diff --git a/.github/workflows/CI_github_ESP32.yml b/.github/workflows/CI_github_ESP32.yml index 849316beb..2a576e40d 100644 --- a/.github/workflows/CI_github_ESP32.yml +++ b/.github/workflows/CI_github_ESP32.yml @@ -104,46 +104,6 @@ jobs: name: firmware path: ./build_output - tasmota32-knx: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - name: Set up Python - uses: actions/setup-python@v1 - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -U platformio - platformio upgrade --dev - platformio update - - name: Run PlatformIO - run: | - platformio run -e tasmota32-knx - - uses: actions/upload-artifact@v2 - with: - name: firmware - path: ./build_output - - tasmota32-sensors: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v1 - - name: Set up Python - uses: actions/setup-python@v1 - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -U platformio - platformio upgrade --dev - platformio update - - name: Run PlatformIO - run: | - platformio run -e tasmota32-sensors - - uses: actions/upload-artifact@v2 - with: - name: firmware - path: ./build_output - tasmota32-display: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/Tasmota_build.yml b/.github/workflows/Tasmota_build.yml index dc595d978..40fd060ba 100644 --- a/.github/workflows/Tasmota_build.yml +++ b/.github/workflows/Tasmota_build.yml @@ -804,46 +804,6 @@ jobs: path: ./build_output - tasmota32-knx: - needs: tasmota_pull - runs-on: ubuntu-latest - continue-on-error: true - steps: - - uses: actions/checkout@v1 - - name: Set up Python - uses: actions/setup-python@v1 - - name: Install dependencies - run: | - pip install -U platformio - - name: Run PlatformIO - run: | - platformio run -e tasmota32-knx - - uses: actions/upload-artifact@v2 - with: - name: firmware - path: ./build_output - - - tasmota32-sensors: - needs: tasmota_pull - runs-on: ubuntu-latest - continue-on-error: true - steps: - - uses: actions/checkout@v1 - - name: Set up Python - uses: actions/setup-python@v1 - - name: Install dependencies - run: | - pip install -U platformio - - name: Run PlatformIO - run: | - platformio run -e tasmota32-sensors - - uses: actions/upload-artifact@v2 - with: - name: firmware - path: ./build_output - - tasmota32-display: needs: tasmota_pull runs-on: ubuntu-latest @@ -1434,14 +1394,12 @@ jobs: [ ! -f ./mv_firmware/firmware/tasmota-knx.* ] || mv ./mv_firmware/firmware/tasmota-knx.* ./firmware/tasmota/ [ ! -f ./mv_firmware/firmware/tasmota-zbbridge.* ] || mv ./mv_firmware/firmware/tasmota-zbbridge.* ./firmware/tasmota/ [ ! -f ./mv_firmware/firmware/tasmota32.* ] || mv ./mv_firmware/firmware/tasmota32.* ./firmware/tasmota32/ - [ ! -f ./mv_firmware/firmware/tasmota32-sensors.* ] || mv ./mv_firmware/firmware/tasmota32-sensors.* ./firmware/tasmota32/ [ ! -f ./mv_firmware/firmware/tasmota32-ir*.* ] || mv ./mv_firmware/firmware/tasmota32-ir*.* ./firmware/tasmota32/ [ ! -f ./mv_firmware/firmware/tasmota32-display.* ] || mv ./mv_firmware/firmware/tasmota32-display.* ./firmware/tasmota32/ [ ! -f ./mv_firmware/firmware/tasmota32-web*.* ] || mv ./mv_firmware/firmware/tasmota32-web*.* ./firmware/tasmota32/ [ ! -f ./mv_firmware/firmware/tasmota32-odroidgo.* ] || mv ./mv_firmware/firmware/tasmota32-odroidgo.* ./firmware/tasmota32/ [ ! -f ./mv_firmware/firmware/tasmota32-core2.* ] || mv ./mv_firmware/firmware/tasmota32-core2.* ./firmware/tasmota32/ [ ! -f ./mv_firmware/firmware/tasmota32-bluetooth.* ] || mv ./mv_firmware/firmware/tasmota32-bluetooth.* ./firmware/tasmota32/ - [ ! -f ./mv_firmware/firmware/tasmota32-knx.* ] || mv ./mv_firmware/firmware/tasmota32-knx.* ./firmware/tasmota32/ [ ! -f ./mv_firmware/firmware/tasmota32* ] || mv ./mv_firmware/firmware/tasmota32* ./firmware/tasmota32/languages/ [ ! -f ./mv_firmware/firmware/* ] || mv ./mv_firmware/firmware/* ./firmware/tasmota/languages/ [ ! -f ./tools/Esptool/ESP32/*.* ] || mv ./tools/Esptool/ESP32/*.* ./firmware/tasmota32/ESP32_needed_files/ diff --git a/.github/workflows/Tasmota_build_master.yml b/.github/workflows/Tasmota_build_master.yml index 4735d702e..4bef7a371 100644 --- a/.github/workflows/Tasmota_build_master.yml +++ b/.github/workflows/Tasmota_build_master.yml @@ -804,46 +804,6 @@ jobs: path: ./build_output - tasmota32-knx: - needs: tasmota_pull - runs-on: ubuntu-latest - continue-on-error: true - steps: - - uses: actions/checkout@v1 - - name: Set up Python - uses: actions/setup-python@v1 - - name: Install dependencies - run: | - pip install -U platformio - - name: Run PlatformIO - run: | - platformio run -e tasmota32-knx - - uses: actions/upload-artifact@v2 - with: - name: firmware - path: ./build_output - - - tasmota32-sensors: - needs: tasmota_pull - runs-on: ubuntu-latest - continue-on-error: true - steps: - - uses: actions/checkout@v1 - - name: Set up Python - uses: actions/setup-python@v1 - - name: Install dependencies - run: | - pip install -U platformio - - name: Run PlatformIO - run: | - platformio run -e tasmota32-sensors - - uses: actions/upload-artifact@v2 - with: - name: firmware - path: ./build_output - - tasmota32-display: needs: tasmota_pull runs-on: ubuntu-latest @@ -1434,14 +1394,12 @@ jobs: [ ! -f ./mv_firmware/firmware/tasmota-knx.* ] || mv ./mv_firmware/firmware/tasmota-knx.* ./firmware/tasmota/ [ ! -f ./mv_firmware/firmware/tasmota-zbbridge.* ] || mv ./mv_firmware/firmware/tasmota-zbbridge.* ./firmware/tasmota/ [ ! -f ./mv_firmware/firmware/tasmota32.* ] || mv ./mv_firmware/firmware/tasmota32.* ./firmware/tasmota32/ - [ ! -f ./mv_firmware/firmware/tasmota32-sensors.* ] || mv ./mv_firmware/firmware/tasmota32-sensors.* ./firmware/tasmota32/ [ ! -f ./mv_firmware/firmware/tasmota32-ir*.* ] || mv ./mv_firmware/firmware/tasmota32-ir*.* ./firmware/tasmota32/ [ ! -f ./mv_firmware/firmware/tasmota32-display.* ] || mv ./mv_firmware/firmware/tasmota32-display.* ./firmware/tasmota32/ [ ! -f ./mv_firmware/firmware/tasmota32-web*.* ] || mv ./mv_firmware/firmware/tasmota32-web*.* ./firmware/tasmota32/ [ ! -f ./mv_firmware/firmware/tasmota32-odroidgo.* ] || mv ./mv_firmware/firmware/tasmota32-odroidgo.* ./firmware/tasmota32/ [ ! -f ./mv_firmware/firmware/tasmota32-core2.* ] || mv ./mv_firmware/firmware/tasmota32-core2.* ./firmware/tasmota32/ [ ! -f ./mv_firmware/firmware/tasmota32-bluetooth.* ] || mv ./mv_firmware/firmware/tasmota32-bluetooth.* ./firmware/tasmota32/ - [ ! -f ./mv_firmware/firmware/tasmota32-knx.* ] || mv ./mv_firmware/firmware/tasmota32-knx.* ./firmware/tasmota32/ [ ! -f ./mv_firmware/firmware/tasmota32* ] || mv ./mv_firmware/firmware/tasmota32* ./firmware/tasmota32/languages/ [ ! -f ./mv_firmware/firmware/* ] || mv ./mv_firmware/firmware/* ./firmware/tasmota/languages/ [ ! -f ./tools/Esptool/ESP32/*.* ] || mv ./tools/Esptool/ESP32/*.* ./firmware/tasmota32/ESP32_needed_files/ diff --git a/CHANGELOG.md b/CHANGELOG.md index f39aea56c..d840a1395 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - Development +## [9.3.1.2] +### Added +- Commands ``MqttKeepAlive 1..100`` to set Mqtt Keep Alive timer (default 30) and ``MqttTimeout 1..100`` to set Mqtt Socket Timeout (default 4) (#5341) +- Support for TM1638 seven segment display by Ajith Vasudevan (#11031) + +### Changed +- PubSubClient library from EspEasy v2.7.12 to Tasmota v2.8.12 + ## [9.3.1.1] ### Added - Support for CSE7761 energy monitor as used in ESP32 based Sonoff Dual R3 Pow (#10793) @@ -16,11 +24,9 @@ All notable changes to this project will be documented in this file. - Crash protection in ext_vnsprintf_P (#11202) - Extent compile time SetOptions support (#11204) - ESP32 Extent BLE (#11212) - - ESP32 support for WS2812 hardware driver via RMT or I2S - - ESP32 support for secondary I2C controller - +- Support for MPU6886 on primary or secondary I2C bus ### Changed - ESP32 core library from v1.0.5-rc6 to v1.0.5 diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 60ee9608b..8d5e34459 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -91,3 +91,4 @@ Index | Define | Driver | Device | Address(es) | Description 55 | USE_EZOPMP | xsns_78 | EZOPMP | 0x61 - 0x70 | Peristaltic Pump 56 | USE_SEESAW_SOIL | xsns_81 | SEESOIL | 0x36 - 0x39 | Adafruit seesaw soil moisture sensor 57 | USE_TOF10120 | xsns_84 | TOF10120 | 0x52 | Time-of-flight (ToF) distance sensor + 58 | USE_MPU6886 | xsns_85 | MPU6886 | 0x68 | MPU6886 M5Stack \ No newline at end of file diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c5ad1ba9e..19e7f50c2 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -78,14 +78,16 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota [Complete list](BUILDS.md) of available feature and sensors. -## Changelog v9.3.1.1 +## Changelog v9.3.1.2 ### Added +- Commands ``MqttKeepAlive 1..100`` to set Mqtt Keep Alive timer (default 30) and ``MqttTimeout 1..100`` to set Mqtt Socket Timeout (default 4) [#5341](https://github.com/arendst/Tasmota/issues/5341) - Command ``Sensor80 1 <0..7>`` to control MFRC522 RFID antenna gain from 18dB (0) to 48dB (7) [#11073](https://github.com/arendst/Tasmota/issues/11073) - Support for SML VBUS [#11125](https://github.com/arendst/Tasmota/issues/11125) - Support for NEC and OPTOMA LCD/DLP Projector serial power control by Jan Bubík [#11145](https://github.com/arendst/Tasmota/issues/11145) - Support for XPT2046 touch screen digitizer on ILI9341 display by nonix [#11159](https://github.com/arendst/Tasmota/issues/11159) - Support for zigbee lumi.sensor_wleak [#11200](https://github.com/arendst/Tasmota/issues/11200) - Support for CSE7761 energy monitor as used in ESP32 based Sonoff Dual R3 Pow [#10793](https://github.com/arendst/Tasmota/issues/10793) +- Support for TM1638 seven segment display by Ajith Vasudevan [#11031](https://github.com/arendst/Tasmota/issues/11031) - Allow MCP230xx pinmode from output to input [#11104](https://github.com/arendst/Tasmota/issues/11104) - Berry improvements [#11163](https://github.com/arendst/Tasmota/issues/11163) - Extent compile time SetOptions support [#11204](https://github.com/arendst/Tasmota/issues/11204) @@ -93,6 +95,7 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota ### Changed - TasmotaSerial library from v3.2.0 to v3.3.0 +- PubSubClient library from EspEasy v2.7.12 to Tasmota v2.8.12 - ESP32 core library from v1.0.5-rc6 to v1.0.5 - TuyaMcu dimmer timeout [#11121](https://github.com/arendst/Tasmota/issues/11121) - Rename epaper 42 commands [#11222](https://github.com/arendst/Tasmota/issues/11222) diff --git a/eMyloEAI90.txt b/eMyloEAI90.txt new file mode 100644 index 000000000..aaa208053 --- /dev/null +++ b/eMyloEAI90.txt @@ -0,0 +1,5 @@ +Template TuyaMCU(54) + +Console: +Backlog SetOption66 1; TuyaMCU 11,16; TuyaMCU 36,6; TuyaMCU 37,1; SetOption59 1; SetOption72 1 +Rule1 on System#Boot do RuleTimer1 10 endon on Rules#Timer=1 do backlog TuyaSend8; RuleTimer1 10 endon \ No newline at end of file diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/.gitignore b/lib/default/PubSubClient-EspEasy-2.7.12/.gitignore deleted file mode 100644 index 1c3ba189b..000000000 --- a/lib/default/PubSubClient-EspEasy-2.7.12/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tests/bin diff --git a/lib/default/pubsubclient-2.8.12/.gitignore b/lib/default/pubsubclient-2.8.12/.gitignore new file mode 100644 index 000000000..a42cc406e --- /dev/null +++ b/lib/default/pubsubclient-2.8.12/.gitignore @@ -0,0 +1,5 @@ +tests/bin +.pioenvs +.piolibdeps +.clang_complete +.gcc-flags.json diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/.travis.yml b/lib/default/pubsubclient-2.8.12/.travis.yml similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/.travis.yml rename to lib/default/pubsubclient-2.8.12/.travis.yml diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/CHANGES.txt b/lib/default/pubsubclient-2.8.12/CHANGES.txt similarity index 86% rename from lib/default/PubSubClient-EspEasy-2.7.12/CHANGES.txt rename to lib/default/pubsubclient-2.8.12/CHANGES.txt index ff4da62ab..e23d5315f 100644 --- a/lib/default/PubSubClient-EspEasy-2.7.12/CHANGES.txt +++ b/lib/default/pubsubclient-2.8.12/CHANGES.txt @@ -1,3 +1,12 @@ +2.8 + * Add setBufferSize() to override MQTT_MAX_PACKET_SIZE + * Add setKeepAlive() to override MQTT_KEEPALIVE + * Add setSocketTimeout() to overide MQTT_SOCKET_TIMEOUT + * Added check to prevent subscribe/unsubscribe to empty topics + * Declare wifi mode prior to connect in ESP example + * Use `strnlen` to avoid overruns + * Support pre-connected Client objects + 2.7 * Fix remaining-length handling to prevent buffer overrun * Add large-payload API - beginPublish/write/publish/endPublish diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/LICENSE.txt b/lib/default/pubsubclient-2.8.12/LICENSE.txt similarity index 96% rename from lib/default/PubSubClient-EspEasy-2.7.12/LICENSE.txt rename to lib/default/pubsubclient-2.8.12/LICENSE.txt index 217df35cc..12c1689e6 100644 --- a/lib/default/PubSubClient-EspEasy-2.7.12/LICENSE.txt +++ b/lib/default/pubsubclient-2.8.12/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2008-2015 Nicholas O'Leary +Copyright (c) 2008-2020 Nicholas O'Leary Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/README.md b/lib/default/pubsubclient-2.8.12/README.md similarity index 87% rename from lib/default/PubSubClient-EspEasy-2.7.12/README.md rename to lib/default/pubsubclient-2.8.12/README.md index 69cbb8f0c..2e1317185 100644 --- a/lib/default/PubSubClient-EspEasy-2.7.12/README.md +++ b/lib/default/pubsubclient-2.8.12/README.md @@ -13,10 +13,12 @@ Full API documentation is available here: https://pubsubclient.knolleary.net ## Limitations - It can only publish QoS 0 messages. It can subscribe at QoS 0 or QoS 1. - - The maximum message size, including header, is **128 bytes** by default. This - is configurable via `MQTT_MAX_PACKET_SIZE` in `PubSubClient.h`. + - The maximum message size, including header, is **256 bytes** by default. This + is configurable via `MQTT_MAX_PACKET_SIZE` in `PubSubClient.h` or can be changed + by calling `PubSubClient::setBufferSize(size)`. - The keepalive interval is set to 15 seconds by default. This is configurable - via `MQTT_KEEPALIVE` in `PubSubClient.h`. + via `MQTT_KEEPALIVE` in `PubSubClient.h` or can be changed by calling + `PubSubClient::setKeepAlive(keepAlive)`. - The client uses MQTT 3.1.1 by default. It can be changed to use MQTT 3.1 by changing value of `MQTT_VERSION` in `PubSubClient.h`. diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/examples/mqtt_auth/mqtt_auth.ino b/lib/default/pubsubclient-2.8.12/examples/mqtt_auth/mqtt_auth.ino similarity index 91% rename from lib/default/PubSubClient-EspEasy-2.7.12/examples/mqtt_auth/mqtt_auth.ino rename to lib/default/pubsubclient-2.8.12/examples/mqtt_auth/mqtt_auth.ino index e9f7b180f..04bd7bb29 100644 --- a/lib/default/PubSubClient-EspEasy-2.7.12/examples/mqtt_auth/mqtt_auth.ino +++ b/lib/default/pubsubclient-2.8.12/examples/mqtt_auth/mqtt_auth.ino @@ -27,9 +27,9 @@ void setup() { Ethernet.begin(mac, ip); // Note - the default maximum packet size is 128 bytes. If the - // combined length of clientId, username and password exceed this, - // you will need to increase the value of MQTT_MAX_PACKET_SIZE in - // PubSubClient.h + // combined length of clientId, username and password exceed this use the + // following to increase the buffer size: + // client.setBufferSize(255); if (client.connect("arduinoClient", "testuser", "testpass")) { client.publish("outTopic","hello world"); diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/examples/mqtt_basic/mqtt_basic.ino b/lib/default/pubsubclient-2.8.12/examples/mqtt_basic/mqtt_basic.ino similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/examples/mqtt_basic/mqtt_basic.ino rename to lib/default/pubsubclient-2.8.12/examples/mqtt_basic/mqtt_basic.ino diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/examples/mqtt_esp8266/mqtt_esp8266.ino b/lib/default/pubsubclient-2.8.12/examples/mqtt_esp8266/mqtt_esp8266.ino similarity index 94% rename from lib/default/PubSubClient-EspEasy-2.7.12/examples/mqtt_esp8266/mqtt_esp8266.ino rename to lib/default/pubsubclient-2.8.12/examples/mqtt_esp8266/mqtt_esp8266.ino index e7357b507..7e6effd24 100644 --- a/lib/default/PubSubClient-EspEasy-2.7.12/examples/mqtt_esp8266/mqtt_esp8266.ino +++ b/lib/default/pubsubclient-2.8.12/examples/mqtt_esp8266/mqtt_esp8266.ino @@ -1,26 +1,21 @@ /* Basic ESP8266 MQTT example - This sketch demonstrates the capabilities of the pubsub library in combination with the ESP8266 board/library. - It connects to an MQTT server then: - publishes "hello world" to the topic "outTopic" every two seconds - subscribes to the topic "inTopic", printing out any messages it receives. NB - it assumes the received payloads are strings not binary - If the first character of the topic "inTopic" is an 1, switch ON the ESP Led, else switch it off - It will reconnect to the server if the connection is lost using a blocking reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to achieve the same result without blocking the main loop. - To install the ESP8266 board, (using Arduino 1.6.4+): - Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs": http://arduino.esp8266.com/stable/package_esp8266com_index.json - Open the "Tools -> Board -> Board Manager" and click install for the ESP8266" - Select your ESP8266 in "Tools -> Board" - */ #include @@ -34,8 +29,9 @@ const char* mqtt_server = "broker.mqtt-dashboard.com"; WiFiClient espClient; PubSubClient client(espClient); -long lastMsg = 0; -char msg[50]; +unsigned long lastMsg = 0; +#define MSG_BUFFER_SIZE (50) +char msg[MSG_BUFFER_SIZE]; int value = 0; void setup_wifi() { @@ -46,6 +42,7 @@ void setup_wifi() { Serial.print("Connecting to "); Serial.println(ssid); + WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { @@ -120,11 +117,11 @@ void loop() { } client.loop(); - long now = millis(); + unsigned long now = millis(); if (now - lastMsg > 2000) { lastMsg = now; ++value; - snprintf (msg, 50, "hello world #%ld", value); + snprintf (msg, MSG_BUFFER_SIZE, "hello world #%ld", value); Serial.print("Publish message: "); Serial.println(msg); client.publish("outTopic", msg); diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/examples/mqtt_large_message/mqtt_large_message.ino b/lib/default/pubsubclient-2.8.12/examples/mqtt_large_message/mqtt_large_message.ino similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/examples/mqtt_large_message/mqtt_large_message.ino rename to lib/default/pubsubclient-2.8.12/examples/mqtt_large_message/mqtt_large_message.ino diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino b/lib/default/pubsubclient-2.8.12/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino rename to lib/default/pubsubclient-2.8.12/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino b/lib/default/pubsubclient-2.8.12/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino rename to lib/default/pubsubclient-2.8.12/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/examples/mqtt_stream/mqtt_stream.ino b/lib/default/pubsubclient-2.8.12/examples/mqtt_stream/mqtt_stream.ino similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/examples/mqtt_stream/mqtt_stream.ino rename to lib/default/pubsubclient-2.8.12/examples/mqtt_stream/mqtt_stream.ino diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/keywords.txt b/lib/default/pubsubclient-2.8.12/keywords.txt similarity index 91% rename from lib/default/PubSubClient-EspEasy-2.7.12/keywords.txt rename to lib/default/pubsubclient-2.8.12/keywords.txt index 1ee23d0fa..960a033f9 100644 --- a/lib/default/PubSubClient-EspEasy-2.7.12/keywords.txt +++ b/lib/default/pubsubclient-2.8.12/keywords.txt @@ -27,6 +27,9 @@ setServer KEYWORD2 setCallback KEYWORD2 setClient KEYWORD2 setStream KEYWORD2 +setKeepAlive KEYWORD2 +setBufferSize KEYWORD2 +setSocketTimeout KEYWORD2 ####################################### # Constants (LITERAL1) diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/library.json b/lib/default/pubsubclient-2.8.12/library.json similarity index 85% rename from lib/default/PubSubClient-EspEasy-2.7.12/library.json rename to lib/default/pubsubclient-2.8.12/library.json index e675ecff3..c0d7bae2d 100644 --- a/lib/default/PubSubClient-EspEasy-2.7.12/library.json +++ b/lib/default/pubsubclient-2.8.12/library.json @@ -6,9 +6,13 @@ "type": "git", "url": "https://github.com/knolleary/pubsubclient.git" }, - "version": "2.7", + "version": "2.8", "exclude": "tests", "examples": "examples/*/*.ino", "frameworks": "arduino", - "platforms": ["espressif8266", "espressif32"] + "platforms": [ + "atmelavr", + "espressif8266", + "espressif32" + ] } diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/library.properties b/lib/default/pubsubclient-2.8.12/library.properties similarity index 98% rename from lib/default/PubSubClient-EspEasy-2.7.12/library.properties rename to lib/default/pubsubclient-2.8.12/library.properties index 7df4daf80..732331bf9 100644 --- a/lib/default/PubSubClient-EspEasy-2.7.12/library.properties +++ b/lib/default/pubsubclient-2.8.12/library.properties @@ -1,5 +1,5 @@ name=PubSubClient -version=2.7 +version=2.8 author=Nick O'Leary maintainer=Nick O'Leary sentence=A client library for MQTT messaging. diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/src/PubSubClient.cpp b/lib/default/pubsubclient-2.8.12/src/PubSubClient.cpp similarity index 61% rename from lib/default/PubSubClient-EspEasy-2.7.12/src/PubSubClient.cpp rename to lib/default/pubsubclient-2.8.12/src/PubSubClient.cpp index 0748fdc4a..acd0fab9b 100644 --- a/lib/default/PubSubClient-EspEasy-2.7.12/src/PubSubClient.cpp +++ b/lib/default/pubsubclient-2.8.12/src/PubSubClient.cpp @@ -12,12 +12,20 @@ PubSubClient::PubSubClient() { this->_client = NULL; this->stream = NULL; setCallback(NULL); + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(Client& client) { this->_state = MQTT_DISCONNECTED; setClient(client); this->stream = NULL; + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) { @@ -25,12 +33,20 @@ PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) { setServer(addr, port); setClient(client); this->stream = NULL; + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; setServer(addr,port); setClient(client); setStream(stream); + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { this->_state = MQTT_DISCONNECTED; @@ -38,6 +54,10 @@ PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATUR setCallback(callback); setClient(client); this->stream = NULL; + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; @@ -45,6 +65,10 @@ PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATUR setCallback(callback); setClient(client); setStream(stream); + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client) { @@ -52,12 +76,20 @@ PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client) { setServer(ip, port); setClient(client); this->stream = NULL; + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; setServer(ip,port); setClient(client); setStream(stream); + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { this->_state = MQTT_DISCONNECTED; @@ -65,6 +97,10 @@ PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, setCallback(callback); setClient(client); this->stream = NULL; + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; @@ -72,6 +108,10 @@ PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, setCallback(callback); setClient(client); setStream(stream); + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) { @@ -79,12 +119,20 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) { setServer(domain,port); setClient(client); this->stream = NULL; + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; setServer(domain,port); setClient(client); setStream(stream); + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { this->_state = MQTT_DISCONNECTED; @@ -92,6 +140,10 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGN setCallback(callback); setClient(client); this->stream = NULL; + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); } PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { this->_state = MQTT_DISCONNECTED; @@ -99,6 +151,14 @@ PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGN setCallback(callback); setClient(client); setStream(stream); + this->bufferSize = 0; + setBufferSize(MQTT_MAX_PACKET_SIZE); + setKeepAlive(MQTT_KEEPALIVE); + setSocketTimeout(MQTT_SOCKET_TIMEOUT); +} + +PubSubClient::~PubSubClient() { + free(this->buffer); } boolean PubSubClient::connect(const char *id) { @@ -121,18 +181,29 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass if (!connected()) { int result = 0; +// Start Tasmota patch if (_client == nullptr) { return false; } - if (_client->connected()) { +// End Tasmota patch + + if(_client->connected()) { result = 1; } else { + +// Start Tasmota patch +// if (domain != NULL) { +// result = _client->connect(this->domain, this->port); + if (domain.length() != 0) { result = _client->connect(this->domain.c_str(), this->port); +// End Tasmota patch + } else { result = _client->connect(this->ip, this->port); } } + if (result == 1) { nextMsgId = 1; // Leave room in the buffer for header and variable length field @@ -147,7 +218,7 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass #define MQTT_HEADER_VERSION_LENGTH 7 #endif for (j = 0;jbuffer[length++] = d[j]; } uint8_t v; @@ -167,45 +238,48 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass v = v|(0x80>>1); } } + this->buffer[length++] = v; - buffer[length++] = v; - - buffer[length++] = ((MQTT_KEEPALIVE) >> 8); - buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF); + this->buffer[length++] = ((this->keepAlive) >> 8); + this->buffer[length++] = ((this->keepAlive) & 0xFF); CHECK_STRING_LENGTH(length,id) - length = writeString(id,buffer,length); + length = writeString(id,this->buffer,length); if (willTopic) { CHECK_STRING_LENGTH(length,willTopic) - length = writeString(willTopic,buffer,length); + length = writeString(willTopic,this->buffer,length); CHECK_STRING_LENGTH(length,willMessage) - length = writeString(willMessage,buffer,length); + length = writeString(willMessage,this->buffer,length); } if(user != NULL) { CHECK_STRING_LENGTH(length,user) - length = writeString(user,buffer,length); + length = writeString(user,this->buffer,length); if(pass != NULL) { CHECK_STRING_LENGTH(length,pass) - length = writeString(pass,buffer,length); + length = writeString(pass,this->buffer,length); } } - write(MQTTCONNECT,buffer,length-MQTT_MAX_HEADER_SIZE); + write(MQTTCONNECT,this->buffer,length-MQTT_MAX_HEADER_SIZE); lastInActivity = lastOutActivity = millis(); while (!_client->available()) { + +// Start Tasmota patch delay(0); // Prevent watchdog crashes +// End Tasmota patch + unsigned long t = millis(); - if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) { + if (t-lastInActivity >= ((int32_t) this->socketTimeout*1000UL)) { _state = MQTT_CONNECTION_TIMEOUT; _client->stop(); return false; } } uint8_t llen; - uint16_t len = readPacket(&llen); + uint32_t len = readPacket(&llen); if (len == 4) { if (buffer[3] == 0) { @@ -228,14 +302,24 @@ boolean PubSubClient::connect(const char *id, const char *user, const char *pass // reads a byte into result boolean PubSubClient::readByte(uint8_t * result) { + +// Start Tasmota patch if (_client == nullptr) { return false; } +// End Tasmota patch + uint32_t previousMillis = millis(); while(!_client->available()) { + +// Start Tasmota patch +// yield(); + delay(1); // Prevent watchdog crashes +// End Tasmota patch + uint32_t currentMillis = millis(); - if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){ + if(currentMillis - previousMillis >= ((int32_t) this->socketTimeout * 1000)){ return false; } } @@ -254,15 +338,15 @@ boolean PubSubClient::readByte(uint8_t * result, uint16_t * index){ return false; } -uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { +uint32_t PubSubClient::readPacket(uint8_t* lengthLength) { uint16_t len = 0; - if(!readByte(buffer, &len)) return 0; - bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH; + if(!readByte(this->buffer, &len)) return 0; + bool isPublish = (this->buffer[0]&0xF0) == MQTTPUBLISH; uint32_t multiplier = 1; - uint16_t length = 0; + uint32_t length = 0; uint8_t digit = 0; uint16_t skip = 0; - uint8_t start = 0; + uint32_t start = 0; do { if (len == 5) { @@ -272,59 +356,75 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { return 0; } if(!readByte(&digit)) return 0; - buffer[len++] = digit; + this->buffer[len++] = digit; length += (digit & 127) * multiplier; - multiplier *= 128; - } while ((digit & 128) != 0 && len < (MQTT_MAX_PACKET_SIZE -2)); + multiplier <<=7; //multiplier *= 128 + +// Start Tasmota patch +// } while ((digit & 128) != 0); + + } while ((digit & 128) != 0 && len < (this->bufferSize -2)); +// End Tasmota patch + *lengthLength = len-1; if (isPublish) { // Read in topic length to calculate bytes to skip over for Stream writing - if(!readByte(buffer, &len)) return 0; - if(!readByte(buffer, &len)) return 0; - skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2]; + if(!readByte(this->buffer, &len)) return 0; + if(!readByte(this->buffer, &len)) return 0; + skip = (this->buffer[*lengthLength+1]<<8)+this->buffer[*lengthLength+2]; start = 2; - if (buffer[0]&MQTTQOS1) { + if (this->buffer[0]&MQTTQOS1) { // skip message id skip += 2; } } + uint32_t idx = len; - for (uint16_t i = start;istream) { - if (isPublish && len-*lengthLength-2>skip) { + if (isPublish && idx-*lengthLength-2>skip) { this->stream->write(digit); } } - if (len < MQTT_MAX_PACKET_SIZE) { - buffer[len] = digit; + + if (len < this->bufferSize) { + this->buffer[len] = digit; + len++; } - len++; + idx++; } - if (!this->stream && len > MQTT_MAX_PACKET_SIZE) { + if (!this->stream && idx > this->bufferSize) { len = 0; // This will cause the packet to be ignored. } - return len; } boolean PubSubClient::loop() { if (connected()) { unsigned long t = millis(); - if ((t - lastInActivity > MQTT_KEEPALIVE*1000UL) || (t - lastOutActivity > MQTT_KEEPALIVE*1000UL)) { + if ((t - lastInActivity > this->keepAlive*1000UL) || (t - lastOutActivity > this->keepAlive*1000UL)) { if (pingOutstanding) { this->_state = MQTT_CONNECTION_TIMEOUT; _client->stop(); return false; } else { - buffer[0] = MQTTPINGREQ; - buffer[1] = 0; - if (_client->write(buffer,2) != 0) { + this->buffer[0] = MQTTPINGREQ; + this->buffer[1] = 0; + +// Start Tasmota patch +// _client->write(this->buffer,2); +// lastOutActivity = t; +// lastInActivity = t; + + if (_client->write(this->buffer,2) != 0) { lastOutActivity = t; lastInActivity = t; } +// End Tasmota patch + pingOutstanding = true; } } @@ -335,35 +435,42 @@ boolean PubSubClient::loop() { uint8_t *payload; if (len > 0) { lastInActivity = t; - uint8_t type = buffer[0]&0xF0; + uint8_t type = this->buffer[0]&0xF0; if (type == MQTTPUBLISH) { if (callback) { - uint16_t tl = (buffer[llen+1]<<8)+buffer[llen+2]; /* topic length in bytes */ - memmove(buffer+llen+2,buffer+llen+3,tl); /* move topic inside buffer 1 byte to front */ - buffer[llen+2+tl] = 0; /* end the topic as a 'C' string with \x00 */ - char *topic = (char*) buffer+llen+2; + uint16_t tl = (this->buffer[llen+1]<<8)+this->buffer[llen+2]; /* topic length in bytes */ + memmove(this->buffer+llen+2,this->buffer+llen+3,tl); /* move topic inside buffer 1 byte to front */ + this->buffer[llen+2+tl] = 0; /* end the topic as a 'C' string with \x00 */ + char *topic = (char*) this->buffer+llen+2; // msgId only present for QOS>0 - if ((buffer[0]&0x06) == MQTTQOS1) { - msgId = (buffer[llen+3+tl]<<8)+buffer[llen+3+tl+1]; - payload = buffer+llen+3+tl+2; + if ((this->buffer[0]&0x06) == MQTTQOS1) { + msgId = (this->buffer[llen+3+tl]<<8)+this->buffer[llen+3+tl+1]; + payload = this->buffer+llen+3+tl+2; callback(topic,payload,len-llen-3-tl-2); - buffer[0] = MQTTPUBACK; - buffer[1] = 2; - buffer[2] = (msgId >> 8); - buffer[3] = (msgId & 0xFF); - if (_client->write(buffer,4) != 0) { + this->buffer[0] = MQTTPUBACK; + this->buffer[1] = 2; + this->buffer[2] = (msgId >> 8); + this->buffer[3] = (msgId & 0xFF); + +// Start Tasmota patch +// _client->write(this->buffer,4); +// lastOutActivity = t; + + if (_client->write(this->buffer,4) != 0) { lastOutActivity = t; } +// End Tasmota patch + } else { - payload = buffer+llen+3+tl; + payload = this->buffer+llen+3+tl; callback(topic,payload,len-llen-3-tl); } } } else if (type == MQTTPINGREQ) { - buffer[0] = MQTTPINGRESP; - buffer[1] = 0; - _client->write(buffer,2); + this->buffer[0] = MQTTPINGRESP; + this->buffer[1] = 0; + _client->write(this->buffer,2); } else if (type == MQTTPINGRESP) { pingOutstanding = false; } @@ -378,13 +485,11 @@ boolean PubSubClient::loop() { } boolean PubSubClient::publish(const char* topic, const char* payload) { - size_t plength = (payload != nullptr) ? strlen(payload) : 0; - return publish(topic,(const uint8_t*)payload,plength,false); + return publish(topic,(const uint8_t*)payload, payload ? strnlen(payload, this->bufferSize) : 0,false); } boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) { - size_t plength = (payload != nullptr) ? strlen(payload) : 0; - return publish(topic,(const uint8_t*)payload,plength,retained); + return publish(topic,(const uint8_t*)payload, payload ? strnlen(payload, this->bufferSize) : 0,retained); } boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) { @@ -393,29 +498,32 @@ boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigne boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) { if (connected()) { - if (MQTT_MAX_PACKET_SIZE < MQTT_MAX_HEADER_SIZE + 2+strlen(topic) + plength) { + if (this->bufferSize < MQTT_MAX_HEADER_SIZE + 2+strnlen(topic, this->bufferSize) + plength) { // Too long return false; } // Leave room in the buffer for header and variable length field uint16_t length = MQTT_MAX_HEADER_SIZE; - length = writeString(topic,buffer,length); + length = writeString(topic,this->buffer,length); + + // Add payload uint16_t i; for (i=0;ibuffer[length++] = payload[i]; } + + // Write the header uint8_t header = MQTTPUBLISH; if (retained) { header |= 1; } - return write(header,buffer,length-MQTT_MAX_HEADER_SIZE); + return write(header,this->buffer,length-MQTT_MAX_HEADER_SIZE); } return false; } boolean PubSubClient::publish_P(const char* topic, const char* payload, boolean retained) { - size_t plength = (payload != nullptr) ? strlen(payload) : 0; - return publish_P(topic, (const uint8_t*)payload, plength, retained); + return publish_P(topic, (const uint8_t*)payload, payload ? strnlen(payload, this->bufferSize) : 0, retained); } boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) { @@ -427,42 +535,48 @@ boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsig unsigned int i; uint8_t header; unsigned int len; + int expectedLength; if (!connected()) { return false; } - tlen = strlen(topic); + tlen = strnlen(topic, this->bufferSize); header = MQTTPUBLISH; if (retained) { header |= 1; } - buffer[pos++] = header; + this->buffer[pos++] = header; len = plength + 2 + tlen; do { - digit = len % 128; - len = len / 128; + digit = len & 127; //digit = len %128 + len >>= 7; //len = len / 128 if (len > 0) { digit |= 0x80; } - buffer[pos++] = digit; + this->buffer[pos++] = digit; llen++; } while(len>0); - pos = writeString(topic,buffer,pos); + pos = writeString(topic,this->buffer,pos); - rc += _client->write(buffer,pos); + rc += _client->write(this->buffer,pos); for (i=0;iwrite((char)pgm_read_byte_near(payload + i)); } + +// Start Tasmota patch +// lastOutActivity = millis(); + if (rc > 0) { lastOutActivity = millis(); } +// End Tasmota patch + + expectedLength = 1 + llen + 2 + tlen + plength; - // Header (1 byte) + llen + identifier (2 bytes) + topic len + payload len - const unsigned int expectedLength = 1 + llen + 2 + tlen + plength; return (rc == expectedLength); } @@ -470,16 +584,22 @@ boolean PubSubClient::beginPublish(const char* topic, unsigned int plength, bool if (connected()) { // Send the header and variable length field uint16_t length = MQTT_MAX_HEADER_SIZE; - length = writeString(topic,buffer,length); + length = writeString(topic,this->buffer,length); uint8_t header = MQTTPUBLISH; if (retained) { header |= 1; } - size_t hlen = buildHeader(header, buffer, plength+length-MQTT_MAX_HEADER_SIZE); - uint16_t rc = _client->write(buffer+(MQTT_MAX_HEADER_SIZE-hlen),length-(MQTT_MAX_HEADER_SIZE-hlen)); + size_t hlen = buildHeader(header, this->buffer, plength+length-MQTT_MAX_HEADER_SIZE); + uint16_t rc = _client->write(this->buffer+(MQTT_MAX_HEADER_SIZE-hlen),length-(MQTT_MAX_HEADER_SIZE-hlen)); + +// Start Tasmota patch +// lastOutActivity = millis(); + if (rc > 0) { lastOutActivity = millis(); } +// End Tasmota patch + return (rc == (length-(MQTT_MAX_HEADER_SIZE-hlen))); } return false; @@ -490,6 +610,11 @@ int PubSubClient::endPublish() { } size_t PubSubClient::write(uint8_t data) { + +// Start Tasmota patch +// lastOutActivity = millis(); +// return _client->write(data); + if (_client == nullptr) { lastOutActivity = millis(); return 0; @@ -499,9 +624,16 @@ size_t PubSubClient::write(uint8_t data) { lastOutActivity = millis(); } return rc; +// End Tasmota patch + } size_t PubSubClient::write(const uint8_t *buffer, size_t size) { + +// Start Tasmota patch +// lastOutActivity = millis(); +// return _client->write(buffer,size); + if (_client == nullptr) { lastOutActivity = millis(); return 0; @@ -511,6 +643,8 @@ size_t PubSubClient::write(const uint8_t *buffer, size_t size) { lastOutActivity = millis(); } return rc; +// End Tasmota patch + } size_t PubSubClient::buildHeader(uint8_t header, uint8_t* buf, uint16_t length) { @@ -520,8 +654,9 @@ size_t PubSubClient::buildHeader(uint8_t header, uint8_t* buf, uint16_t length) uint8_t pos = 0; uint16_t len = length; do { - digit = len % 128; - len = len / 128; + + digit = len & 127; //digit = len %128 + len >>= 7; //len = len / 128 if (len > 0) { digit |= 0x80; } @@ -546,7 +681,6 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { uint8_t bytesToWrite; boolean result = true; while((bytesRemaining > 0) && result) { - delay(0); // Prevent watchdog crashes bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE)?MQTT_MAX_TRANSFER_SIZE:bytesRemaining; rc = _client->write(writeBuf,bytesToWrite); result = (rc == bytesToWrite); @@ -556,9 +690,15 @@ boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { return result; #else rc = _client->write(buf+(MQTT_MAX_HEADER_SIZE-hlen),length+hlen); + +// Start Tasmota patch +// lastOutActivity = millis(); + if (rc != 0) { lastOutActivity = millis(); } +// End Tasmota patch + return (rc == hlen+length); #endif } @@ -568,10 +708,14 @@ boolean PubSubClient::subscribe(const char* topic) { } boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { + size_t topicLength = strnlen(topic, this->bufferSize); + if (topic == 0) { + return false; + } if (qos > 1) { return false; } - if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { + if (this->bufferSize < 9 + topicLength) { // Too long return false; } @@ -582,17 +726,21 @@ boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { if (nextMsgId == 0) { nextMsgId = 1; } - buffer[length++] = (nextMsgId >> 8); - buffer[length++] = (nextMsgId & 0xFF); - length = writeString((char*)topic, buffer,length); - buffer[length++] = qos; - return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE); + this->buffer[length++] = (nextMsgId >> 8); + this->buffer[length++] = (nextMsgId & 0xFF); + length = writeString((char*)topic, this->buffer,length); + this->buffer[length++] = qos; + return write(MQTTSUBSCRIBE|MQTTQOS1,this->buffer,length-MQTT_MAX_HEADER_SIZE); } return false; } boolean PubSubClient::unsubscribe(const char* topic) { - if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { + size_t topicLength = strnlen(topic, this->bufferSize); + if (topic == 0) { + return false; + } + if (this->bufferSize < 9 + topicLength) { // Too long return false; } @@ -602,25 +750,34 @@ boolean PubSubClient::unsubscribe(const char* topic) { if (nextMsgId == 0) { nextMsgId = 1; } - buffer[length++] = (nextMsgId >> 8); - buffer[length++] = (nextMsgId & 0xFF); - length = writeString(topic, buffer,length); - return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE); + this->buffer[length++] = (nextMsgId >> 8); + this->buffer[length++] = (nextMsgId & 0xFF); + length = writeString(topic, this->buffer,length); + return write(MQTTUNSUBSCRIBE|MQTTQOS1,this->buffer,length-MQTT_MAX_HEADER_SIZE); } return false; } void PubSubClient::disconnect(bool disconnect_package) { - buffer[0] = MQTTDISCONNECT; - buffer[1] = 0; + this->buffer[0] = MQTTDISCONNECT; + this->buffer[1] = 0; + +// Start Tasmota patch +// _client->write(this->buffer,2); +// _state = MQTT_DISCONNECTED; +// _client->flush(); +// _client->stop(); + if (_client != nullptr) { if (disconnect_package) { - _client->write(buffer,2); + _client->write(this->buffer,2); } _client->flush(); _client->stop(); } _state = MQTT_DISCONNECTED; +// End Tasmota patch + lastInActivity = lastOutActivity = millis(); } @@ -628,7 +785,7 @@ uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t po const char* idp = string; uint16_t i = 0; pos += 2; - while (*idp && pos < (MQTT_MAX_PACKET_SIZE - 2)) { + while (*idp) { buf[pos++] = *idp++; i++; } @@ -639,19 +796,27 @@ uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t po boolean PubSubClient::connected() { + boolean rc; if (_client == NULL ) { + +// Start Tasmota patch this->_state = MQTT_DISCONNECTED; - return false; - } - if (_client->connected() == 0) { - bool lastStateConnected = this->_state == MQTT_CONNECTED; - this->disconnect(); - if (lastStateConnected) { - this->_state = MQTT_CONNECTION_LOST; +// End Tasmota patch + + rc = false; + } else { + rc = (int)_client->connected(); + if (!rc) { + if (this->_state == MQTT_CONNECTED) { + this->_state = MQTT_CONNECTION_LOST; + _client->flush(); + _client->stop(); + } + } else { + return this->_state == MQTT_CONNECTED; } - return false; } - return this->_state == MQTT_CONNECTED; + return rc; } PubSubClient& PubSubClient::setServer(uint8_t * ip, uint16_t port) { @@ -662,7 +827,13 @@ PubSubClient& PubSubClient::setServer(uint8_t * ip, uint16_t port) { PubSubClient& PubSubClient::setServer(IPAddress ip, uint16_t port) { this->ip = ip; this->port = port; + +// Start Tasmota patch +// this->domain = NULL; + this->domain = ""; +// End Tasmota patch + return *this; } @@ -690,3 +861,34 @@ PubSubClient& PubSubClient::setStream(Stream& stream){ int PubSubClient::state() { return this->_state; } + +boolean PubSubClient::setBufferSize(uint16_t size) { + if (size == 0) { + // Cannot set it back to 0 + return false; + } + if (this->bufferSize == 0) { + this->buffer = (uint8_t*)malloc(size); + } else { + uint8_t* newBuffer = (uint8_t*)realloc(this->buffer, size); + if (newBuffer != NULL) { + this->buffer = newBuffer; + } else { + return false; + } + } + this->bufferSize = size; + return (this->buffer != NULL); +} + +uint16_t PubSubClient::getBufferSize() { + return this->bufferSize; +} +PubSubClient& PubSubClient::setKeepAlive(uint16_t keepAlive) { + this->keepAlive = keepAlive; + return *this; +} +PubSubClient& PubSubClient::setSocketTimeout(uint16_t timeout) { + this->socketTimeout = timeout; + return *this; +} diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/src/PubSubClient.h b/lib/default/pubsubclient-2.8.12/src/PubSubClient.h similarity index 88% rename from lib/default/PubSubClient-EspEasy-2.7.12/src/PubSubClient.h rename to lib/default/pubsubclient-2.8.12/src/PubSubClient.h index 19b35160a..4edf5ec57 100644 --- a/lib/default/PubSubClient-EspEasy-2.7.12/src/PubSubClient.h +++ b/lib/default/pubsubclient-2.8.12/src/PubSubClient.h @@ -21,24 +21,20 @@ #define MQTT_VERSION MQTT_VERSION_3_1_1 #endif -// MQTT_MAX_PACKET_SIZE : Maximum packet size +// MQTT_MAX_PACKET_SIZE : Maximum packet size. Override with setBufferSize(). #ifndef MQTT_MAX_PACKET_SIZE -//#define MQTT_MAX_PACKET_SIZE 128 -//#define MQTT_MAX_PACKET_SIZE 1000 // Tasmota v5.11.1c +//#define MQTT_MAX_PACKET_SIZE 256 #define MQTT_MAX_PACKET_SIZE 1200 // Tasmota v8.1.0.8 #endif -// MQTT_KEEPALIVE : keepAlive interval in Seconds -// Keepalive timeout for default MQTT Broker is 10s +// MQTT_KEEPALIVE : keepAlive interval in Seconds. Override with setKeepAlive() #ifndef MQTT_KEEPALIVE -//#define MQTT_KEEPALIVE 10 -#define MQTT_KEEPALIVE 30 // Tasmota v6.5.0.14 enabling AWS-iot +#define MQTT_KEEPALIVE 15 #endif -// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds +// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds. Override with setSocketTimeout() #ifndef MQTT_SOCKET_TIMEOUT -//#define MQTT_SOCKET_TIMEOUT 15 -#define MQTT_SOCKET_TIMEOUT 4 // Tasmota 20210120 +#define MQTT_SOCKET_TIMEOUT 15 #endif // MQTT_MAX_TRANSFER_SIZE : limit how much data is passed to the network client @@ -88,18 +84,21 @@ #define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int) #endif -#define CHECK_STRING_LENGTH(l,s) if (l+2+strlen(s) > MQTT_MAX_PACKET_SIZE) {_client->stop();return false;} +#define CHECK_STRING_LENGTH(l,s) if (l+2+strnlen(s, this->bufferSize) > this->bufferSize) {_client->stop();return false;} class PubSubClient : public Print { private: Client* _client; - uint8_t buffer[MQTT_MAX_PACKET_SIZE]; + uint8_t* buffer; + uint16_t bufferSize; + uint16_t keepAlive; + uint16_t socketTimeout; uint16_t nextMsgId; unsigned long lastOutActivity; unsigned long lastInActivity; bool pingOutstanding; MQTT_CALLBACK_SIGNATURE; - uint16_t readPacket(uint8_t*); + uint32_t readPacket(uint8_t*); boolean readByte(uint8_t * result); boolean readByte(uint8_t * result, uint16_t * index); boolean write(uint8_t header, uint8_t* buf, uint16_t length); @@ -110,7 +109,13 @@ private: // (MQTT_MAX_HEADER_SIZE - ) bytes into the buffer size_t buildHeader(uint8_t header, uint8_t* buf, uint16_t length); IPAddress ip; + +// Start Tasmota patch +// const char* domain; + String domain; +// End Tasmota patch + uint16_t port; Stream* stream; int _state; @@ -129,7 +134,8 @@ public: PubSubClient(const char*, uint16_t, Client& client, Stream&); PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); - virtual ~PubSubClient() {} + + ~PubSubClient(); PubSubClient& setServer(IPAddress ip, uint16_t port); PubSubClient& setServer(uint8_t * ip, uint16_t port); @@ -137,13 +143,24 @@ public: PubSubClient& setCallback(MQTT_CALLBACK_SIGNATURE); PubSubClient& setClient(Client& client); PubSubClient& setStream(Stream& stream); + PubSubClient& setKeepAlive(uint16_t keepAlive); + PubSubClient& setSocketTimeout(uint16_t timeout); + + boolean setBufferSize(uint16_t size); + uint16_t getBufferSize(); boolean connect(const char* id); boolean connect(const char* id, const char* user, const char* pass); boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession); + +// Start Tasmota patch +// void disconnect(); + void disconnect(bool disconnect_package = false); +// End Tasmota patch + boolean publish(const char* topic, const char* payload); boolean publish(const char* topic, const char* payload, boolean retained); boolean publish(const char* topic, const uint8_t * payload, unsigned int plength); @@ -173,6 +190,7 @@ public: boolean loop(); boolean connected(); int state(); + }; diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/.gitignore b/lib/default/pubsubclient-2.8.12/tests/.gitignore similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/.gitignore rename to lib/default/pubsubclient-2.8.12/tests/.gitignore diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/Makefile b/lib/default/pubsubclient-2.8.12/tests/Makefile similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/Makefile rename to lib/default/pubsubclient-2.8.12/tests/Makefile diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/README.md b/lib/default/pubsubclient-2.8.12/tests/README.md similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/README.md rename to lib/default/pubsubclient-2.8.12/tests/README.md diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/connect_spec.cpp b/lib/default/pubsubclient-2.8.12/tests/src/connect_spec.cpp similarity index 90% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/connect_spec.cpp rename to lib/default/pubsubclient-2.8.12/tests/src/connect_spec.cpp index e27a1f59f..e8545c49d 100644 --- a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/connect_spec.cpp +++ b/lib/default/pubsubclient-2.8.12/tests/src/connect_spec.cpp @@ -280,6 +280,38 @@ int test_connect_disconnect_connect() { END_IT } +int test_connect_custom_keepalive() { + IT("sends a properly formatted connect packet with custom keepalive value"); + ShimClient shimClient; + + shimClient.setAllowConnect(true); + byte expectServer[] = { 172, 16, 0, 2 }; + shimClient.expectConnect(expectServer,1883); + + // Set keepalive to 300secs == 0x01 0x2c + byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x2,0x01,0x2c,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31}; + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; + + shimClient.expect(connect,26); + shimClient.respond(connack,4); + + PubSubClient client(server, 1883, callback, shimClient); + int state = client.state(); + IS_TRUE(state == MQTT_DISCONNECTED); + + client.setKeepAlive(300); + + int rc = client.connect((char*)"client_test1"); + IS_TRUE(rc); + IS_FALSE(shimClient.error()); + + state = client.state(); + IS_TRUE(state == MQTT_CONNECTED); + + END_IT +} + + int main() { SUITE("Connect"); @@ -298,5 +330,7 @@ int main() test_connect_with_will(); test_connect_with_will_username_password(); test_connect_disconnect_connect(); + + test_connect_custom_keepalive(); FINISH } diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/keepalive_spec.cpp b/lib/default/pubsubclient-2.8.12/tests/src/keepalive_spec.cpp similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/keepalive_spec.cpp rename to lib/default/pubsubclient-2.8.12/tests/src/keepalive_spec.cpp diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/Arduino.h b/lib/default/pubsubclient-2.8.12/tests/src/lib/Arduino.h similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/Arduino.h rename to lib/default/pubsubclient-2.8.12/tests/src/lib/Arduino.h diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/BDDTest.cpp b/lib/default/pubsubclient-2.8.12/tests/src/lib/BDDTest.cpp similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/BDDTest.cpp rename to lib/default/pubsubclient-2.8.12/tests/src/lib/BDDTest.cpp diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/BDDTest.h b/lib/default/pubsubclient-2.8.12/tests/src/lib/BDDTest.h similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/BDDTest.h rename to lib/default/pubsubclient-2.8.12/tests/src/lib/BDDTest.h diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/Buffer.cpp b/lib/default/pubsubclient-2.8.12/tests/src/lib/Buffer.cpp similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/Buffer.cpp rename to lib/default/pubsubclient-2.8.12/tests/src/lib/Buffer.cpp diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/Buffer.h b/lib/default/pubsubclient-2.8.12/tests/src/lib/Buffer.h similarity index 88% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/Buffer.h rename to lib/default/pubsubclient-2.8.12/tests/src/lib/Buffer.h index f448cade8..c6a2cb584 100644 --- a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/Buffer.h +++ b/lib/default/pubsubclient-2.8.12/tests/src/lib/Buffer.h @@ -5,18 +5,18 @@ class Buffer { private: - uint8_t buffer[1024]; + uint8_t buffer[2048]; uint16_t pos; uint16_t length; - + public: Buffer(); Buffer(uint8_t* buf, size_t size); - + virtual bool available(); virtual uint8_t next(); virtual void reset(); - + virtual void add(uint8_t* buf, size_t size); }; diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/Client.h b/lib/default/pubsubclient-2.8.12/tests/src/lib/Client.h similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/Client.h rename to lib/default/pubsubclient-2.8.12/tests/src/lib/Client.h diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/IPAddress.cpp b/lib/default/pubsubclient-2.8.12/tests/src/lib/IPAddress.cpp similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/IPAddress.cpp rename to lib/default/pubsubclient-2.8.12/tests/src/lib/IPAddress.cpp diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/IPAddress.h b/lib/default/pubsubclient-2.8.12/tests/src/lib/IPAddress.h similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/IPAddress.h rename to lib/default/pubsubclient-2.8.12/tests/src/lib/IPAddress.h diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/Print.h b/lib/default/pubsubclient-2.8.12/tests/src/lib/Print.h similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/Print.h rename to lib/default/pubsubclient-2.8.12/tests/src/lib/Print.h diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/ShimClient.cpp b/lib/default/pubsubclient-2.8.12/tests/src/lib/ShimClient.cpp similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/ShimClient.cpp rename to lib/default/pubsubclient-2.8.12/tests/src/lib/ShimClient.cpp diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/ShimClient.h b/lib/default/pubsubclient-2.8.12/tests/src/lib/ShimClient.h similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/ShimClient.h rename to lib/default/pubsubclient-2.8.12/tests/src/lib/ShimClient.h diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/Stream.cpp b/lib/default/pubsubclient-2.8.12/tests/src/lib/Stream.cpp similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/Stream.cpp rename to lib/default/pubsubclient-2.8.12/tests/src/lib/Stream.cpp diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/Stream.h b/lib/default/pubsubclient-2.8.12/tests/src/lib/Stream.h similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/Stream.h rename to lib/default/pubsubclient-2.8.12/tests/src/lib/Stream.h diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/trace.h b/lib/default/pubsubclient-2.8.12/tests/src/lib/trace.h similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/lib/trace.h rename to lib/default/pubsubclient-2.8.12/tests/src/lib/trace.h diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/publish_spec.cpp b/lib/default/pubsubclient-2.8.12/tests/src/publish_spec.cpp similarity index 99% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/publish_spec.cpp rename to lib/default/pubsubclient-2.8.12/tests/src/publish_spec.cpp index 232df0d37..ee3d3bedb 100644 --- a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/publish_spec.cpp +++ b/lib/default/pubsubclient-2.8.12/tests/src/publish_spec.cpp @@ -134,6 +134,7 @@ int test_publish_too_long() { shimClient.respond(connack,4); PubSubClient client(server, 1883, callback, shimClient); + client.setBufferSize(128); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/receive_spec.cpp b/lib/default/pubsubclient-2.8.12/tests/src/receive_spec.cpp similarity index 75% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/receive_spec.cpp rename to lib/default/pubsubclient-2.8.12/tests/src/receive_spec.cpp index 9a18af042..93e909aeb 100644 --- a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/receive_spec.cpp +++ b/lib/default/pubsubclient-2.8.12/tests/src/receive_spec.cpp @@ -20,6 +20,7 @@ void reset_callback() { } void callback(char* topic, byte* payload, unsigned int length) { + TRACE("Callback received topic=[" << topic << "] length=" << length << "\n") callback_called = true; strcpy(lastTopic,topic); memcpy(lastPayload,payload,length); @@ -102,10 +103,15 @@ int test_receive_max_sized_message() { shimClient.respond(connack,4); PubSubClient client(server, 1883, callback, shimClient); + int length = 80; // If this is changed to > 128 then the publish packet below + // is no longer valid as it assumes the remaining length + // is a single-byte. Don't make that mistake like I just + // did and lose a whole evening tracking down the issue. + client.setBufferSize(length); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - int length = MQTT_MAX_PACKET_SIZE; + byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; byte bigPublish[length]; memset(bigPublish,'A',length); @@ -137,11 +143,13 @@ int test_receive_oversized_message() { byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); + int length = 80; // See comment in test_receive_max_sized_message before changing this value + PubSubClient client(server, 1883, callback, shimClient); + client.setBufferSize(length-1); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - int length = MQTT_MAX_PACKET_SIZE+1; byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; byte bigPublish[length]; memset(bigPublish,'A',length); @@ -188,9 +196,58 @@ int test_drop_invalid_remaining_length_message() { END_IT } +int test_resize_buffer() { + IT("receives a message larger than the default maximum"); + reset_callback(); + + ShimClient shimClient; + shimClient.setAllowConnect(true); + + byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; + shimClient.respond(connack,4); + + int length = 80; // See comment in test_receive_max_sized_message before changing this value + + PubSubClient client(server, 1883, callback, shimClient); + client.setBufferSize(length-1); + int rc = client.connect((char*)"client_test1"); + IS_TRUE(rc); + + byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; + byte bigPublish[length]; + memset(bigPublish,'A',length); + bigPublish[length] = 'B'; + memcpy(bigPublish,publish,16); + // Send it twice + shimClient.respond(bigPublish,length); + shimClient.respond(bigPublish,length); + + rc = client.loop(); + IS_TRUE(rc); + + // First message fails as it is too big + IS_FALSE(callback_called); + + // Resize the buffer + client.setBufferSize(length); + + rc = client.loop(); + IS_TRUE(rc); + + IS_TRUE(callback_called); + + IS_TRUE(strcmp(lastTopic,"topic")==0); + IS_TRUE(lastLength == length-9); + IS_TRUE(memcmp(lastPayload,bigPublish+9,lastLength)==0); + + IS_FALSE(shimClient.error()); + + END_IT +} + int test_receive_oversized_stream_message() { - IT("drops an oversized message"); + IT("receive an oversized streamed message"); reset_callback(); Stream stream; @@ -201,11 +258,13 @@ int test_receive_oversized_stream_message() { byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; shimClient.respond(connack,4); + int length = 80; // See comment in test_receive_max_sized_message before changing this value + PubSubClient client(server, 1883, callback, shimClient, stream); + client.setBufferSize(length-1); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); - int length = MQTT_MAX_PACKET_SIZE+1; byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; byte bigPublish[length]; @@ -222,7 +281,8 @@ int test_receive_oversized_stream_message() { IS_TRUE(callback_called); IS_TRUE(strcmp(lastTopic,"topic")==0); - IS_TRUE(lastLength == length-9); + + IS_TRUE(lastLength == length-10); IS_FALSE(stream.error()); IS_FALSE(shimClient.error()); @@ -272,6 +332,7 @@ int main() test_receive_max_sized_message(); test_drop_invalid_remaining_length_message(); test_receive_oversized_message(); + test_resize_buffer(); test_receive_oversized_stream_message(); test_receive_qos1(); diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/subscribe_spec.cpp b/lib/default/pubsubclient-2.8.12/tests/src/subscribe_spec.cpp similarity index 99% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/src/subscribe_spec.cpp rename to lib/default/pubsubclient-2.8.12/tests/src/subscribe_spec.cpp index a41982355..22dc8a443 100644 --- a/lib/default/PubSubClient-EspEasy-2.7.12/tests/src/subscribe_spec.cpp +++ b/lib/default/pubsubclient-2.8.12/tests/src/subscribe_spec.cpp @@ -106,6 +106,7 @@ int test_subscribe_too_long() { shimClient.respond(connack,4); PubSubClient client(server, 1883, callback, shimClient); + client.setBufferSize(128); int rc = client.connect((char*)"client_test1"); IS_TRUE(rc); diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/testcases/__init__.py b/lib/default/pubsubclient-2.8.12/tests/testcases/__init__.py similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/testcases/__init__.py rename to lib/default/pubsubclient-2.8.12/tests/testcases/__init__.py diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/testcases/mqtt_basic.py b/lib/default/pubsubclient-2.8.12/tests/testcases/mqtt_basic.py similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/testcases/mqtt_basic.py rename to lib/default/pubsubclient-2.8.12/tests/testcases/mqtt_basic.py diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/testcases/mqtt_publish_in_callback.py b/lib/default/pubsubclient-2.8.12/tests/testcases/mqtt_publish_in_callback.py similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/testcases/mqtt_publish_in_callback.py rename to lib/default/pubsubclient-2.8.12/tests/testcases/mqtt_publish_in_callback.py diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/testcases/settings.py b/lib/default/pubsubclient-2.8.12/tests/testcases/settings.py similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/testcases/settings.py rename to lib/default/pubsubclient-2.8.12/tests/testcases/settings.py diff --git a/lib/default/PubSubClient-EspEasy-2.7.12/tests/testsuite.py b/lib/default/pubsubclient-2.8.12/tests/testsuite.py similarity index 100% rename from lib/default/PubSubClient-EspEasy-2.7.12/tests/testsuite.py rename to lib/default/pubsubclient-2.8.12/tests/testsuite.py diff --git a/lib/lib_display/TM1638plus/README.md b/lib/lib_display/TM1638plus/README.md new file mode 100644 index 000000000..f23624b11 --- /dev/null +++ b/lib/lib_display/TM1638plus/README.md @@ -0,0 +1,276 @@ +![ module pics ](https://github.com/gavinlyonsrepo/TM1638plus/blob/master/extra/images/tm16383.jpg) + +Table of contents +--------------------------- + + * [Overview](#overview) + * [Installation](#installation) + * [Features](#features) + * [Model One](#model-one) + * [Model Two](#model-two) + * [Model Three](#model-three) + * [Notes](#notes) + * [Memory](#memory) + * [Pic Ports](#pic-port) + + +Overview +-------------------------------------------- +* Name: TM1638plus +* Description: +An Arduino library to display data on a 8-digit TM1638 seven segment module. +This library supports 3 different models, pictured above from left to right. + +1. Model 1, The (8 KEY & 8 LED) variant which has 8 LED's and 8 Push buttons. +2. Model 2, The (QYF 16 KEY) variant which has 16 pushbuttons. +3. Model 3, The (LKM1638) variant which has 8 bi-colour LED's and 8 Push buttons. + + +* Main Author: Gavin Lyons. + +* Tested on Development platforms: + +1. Arduino UNO & NANO v3 . +2. ATtiny85 . +3. ESP32. +4. STM32 STM32F103C8T6 "the blue pill". +5. ESP8266. +6. Teensy 4.0. (may not work at highest frequency see notes section) + +* History: see CHANGELOG.md in extra folder +* Contributors: [gabormay](https://github.com/gabormay) [centic9](https://github.com/centic9) [wunderbaum](https://github.com/wunderbaum) + + +Installation +------------------------------ + +The library is included in the official Arduino library manger and the optimum way to install it +is using the library manager which can be opened by the *manage libraries* option in Arduino IDE. +Search "tm1638" in search bar of library manager to find it. + +See link below for instruction for this and for the other methods too. + +[Installing Additional Arduino Libraries guide](https://www.arduino.cc/en/Guide/Libraries) + + +Features +---------------------- + +Connections to MCU: + +1. GPIO = STB = Strobe +2. GPIO = CLK = Clock +3. GPIO = DIO = Data input / output +4. GND +5. VCC 5V. + +This device is 5V if using 3.3V MCU, level shift. + +This library supports three variants of the TM1638, which for purposes of this documentation, +will be named Model 1 ,Model 2 and Model 3. + +| Model No | Module Name | LEDS | Push buttons | +| ------ | ------ | ------ | ------ | +| 1 | TM1638 LED & KEY | 8 red only | 8 | +| 2 | TM1638 KEYS, QYF | 0 | 16 | +| 3 | TM1638 V1.3 or LKM1638 | 8 bi color, red and green | 8 | + +There are two sets of files to support model 1 & 2 . I kept them separate as the models are wired quite different, Model 1 address by digit, while Model 2 address by segment. So the code is quite different for most functions. Model 3 uses same code as Model 1, just different example file and different use of LED functions. Common settings, data and functions are in the TM1638plus_common.x files. + +| Model | Header | Code file | TEST files | +| ------ | ------ | ------ | ------ | +| 1 | TM1638plus.h | TM1638plus.cpp | TM1638plus_HELLOWORLD_Model1.ino TM1638plus_TEST_Model1.ino | +| 3 | Same as model 1 | Same as model 1 | TM1638plus_TEST_Model3.ino | +| 2 | TM1638plus_Model2.h | TM1638plus_Model2.cpp | TM1638plus_HELLOWORLD_Model2 TM1638plus_TEST_Model2.ino | + +Model One +-------------------------------------- + +TM1638 Module 8 Push buttons 8 LEDS (LED & KEY) + +![ module ](https://github.com/gavinlyonsrepo/pic_16F18446_projects/blob/master/images/TM1638.jpg) + +![ sch ](https://github.com/gavinlyonsrepo/pic_16F18446_projects/blob/master/images/TM1638_2.jpg) + +This variant consist of an 8-digit seven segment display with decimal points, +8 Leds and 8 Push buttons. Two 4 digit 3461AS-1 (.34 inch, 4 digit ,common Cathode, decimal point, RED) are used in this module giving a total of 8 digits. A TM1638 controller chip drives the unit. +The unit is marked (LED & KEY). + +**Model 1 Library Functions** + +The commented functions can be found in library header file TM1638plus.h. +The library support ASCII ,text ,Hex and allows for setting individual segments, +and the decimal point of segment. +The TM1638plus_TEST.ino contains a set of tests demonstrating library functions. +For more information see the commented headers in header file. + +1. Print an ASCII character. +2. Print an ASCII character with a dot/decimal point. +3. Print a Hexadecimal digit(0-15). +4. Print a long integer number with or without leading zeros. +5. Print two integer numbers (0-9999) to each nibble with or without leading zeros. +6. Print a text string(dots are replaced and dot is turned on preceding digit), +"abc.def" becomes "abcdef" with c decimal point segment switched on. +7. Read buttons status. User may have to debounce buttons depending on application. +debouncing left out to minimise library size. +See [URL LINK](https://github.com/gavinlyonsrepo/Arduino_Clock_3) +for a practical real world example of using this library, +including a example of debouncing the key presses. It is also possible to read multiple key presses. +8. Reset and init module functions. +9. Adjust brightness of module. Support 8 degree brightness adjustment. +If user wishes to change the default brightness at start-up change, +The DEFAULT_BRIGHTNESS define in header file. +10. Manually set segments to create custom patterns. +11. Switch the 8 LEDS on and off, both a set one LED and set all LEDS methods available. + + +Model Two +----------------------------------------- + +TM1638 Module 16 Push buttons (16 KEY) (QYF). + +![ module ](https://github.com/gavinlyonsrepo/TM1638plus/blob/master/extra/images/tm16381.jpg) + +![ sch ](https://github.com/gavinlyonsrepo/TM1638plus/blob/master/extra/images/tm16382.jpg) + +They consist of an 8-digit seven segment display with decimal points, +and 16 Push buttons.Two 4 digit 3461BS-1 (.34 inch, 4 digit ,common Anode, decimal point, RED)are used in this module giving a total of 8 digits. A TM1638 controller chip drives the unit. +NB : If your display shows "56781234" for "12345678" see Notes section. Note A. + +**Model 2 Library Functions** + +The commented functions can be found in library header file TM1638plus_Model2.h. +The library support Strings,decimal ,Hex ,raw ASCII data, setting individual segments, +and the decimal point. For more detailed information on functions see commented headers in header file(.h). + +1. Print a Hexadecimal number with or without leading zeros +2. Print a decimal number with or without leading zeros +3. Manually set segments to create custom patterns. +4. Print two 4 digit decimal number(0-9999) to each nibble with or without leading zeros. +5. Print a text string, dot function supported. +6. Read buttons status. User may want to debounce buttons depending on application. +See TM1638plus_ADC_TEST_Model2.ino for debounce button example. +Two different functions to read buttons. +7. Reset and init module functions. +8. Adjust brightness of module. Support 8 degree brightness adjustment. +If user wishes to change the default brightness at start-up change, +The "DEFAULT_BRIGHTNESS" define in header file. +9. Print raw ASCII data without reference to font file. + +Model Three +----------------------------------------- + +There are different PCB's of these modules on market, +This library was tested on no 3 below. I think this software will work for all of them +and the differences in PCB are related to connectors, layout and component placement. +This module is a variant of Model 1. The differences are the LEDs are bigger and bi-color +both red and green, The seven segment display is larger and extra connectors are added for Daisy chaining. +Two 4 digit KYX-5461AS-7.3 (.54 inch, 4 digit ,common cathode, decimal point, RED)are used in this module +giving a total of 8 digits. + +1. LKM1638 v1.1 +2. LKM1638 v1.2 +3. TM1638 V1.3 + +![ module ](https://github.com/gavinlyonsrepo/TM1638plus/blob/master/extra/images/tm16384.jpg) + +**Model 3 Library Functions** + +The code is the same as model 1 and there is one unique model 3 example file. +setLED and setLEDs functions behaviour is the only difference in code base between 1 and 3. +SetLED: The difference is when you call the setLED function you pass the following to get LEDs to change colour. For more detailed information on functions see commented headers in header file(.h). + +| Model | setLED Value | result | +| ---- | ---- | ---- | +| 1 & 3 | 0 | LED off | +| 3 | 1 | Led green on | +| 3 | 2 | LED red on | +| 1 | 1 | LED on | + +SetLEDs: When you pass call the setLEDs function you can pass a word pattern where upper byte is turns LEDs green on and lower byte turns LEDs red on . Model one ignores lower byte, Set to 0x00 always. + +1. Model 3 setLEDs(word) = 0xGGRR +3. Model 1 setLEDs(word) = 0xRR00 + +Notes +-------------------------- + +1. Swapped data on Display issue on some Model 2 modules +2. Anomaly's on High frequency micro-controllers. +3. Driving multiple displays. +4. Detecting multiple buttons pressed together. + +*Note A* : Swapped display Issue: Model 2 only + +For Some users using this library the nibbles in information display byte +where swapped around. This is because there are different versions of modules on market with different wiring. See issue #3 on github called Swapped display :: "12345678" becomes "56781234". +If you test library and you see this issue, in order to fix this when you declare the +Object, set the fourth parameter "swap_nibbles" to True, The default is false. + +| PCB Model noted Label | Operation | Object constructor 4th parameter | +| ------ | ------ | ------ | +| QYF-TM1638 | default operation | false | +| QYF-TM1638 -Ver 1.0 | Swapped display Fix | true | + +*Note B* : High frequency micro-controllers. + +This library uses a software SPI-like protocol and may not work fully on +micro-controllers running at a very high frequency, without some adjustments to timing. +Its a SPI-like interface with a single bidirectional data wire DIO. +The TM1638 is basically a slow SPI device (< 500kHz) in DIO mode. The clock uses the equivalent of SPI mode 3 (normally high, clocks data on the rising edge). The problem is that the native Arduino shiftIn()/shiftOut() wire functions are simply too fast for this device (technically the clock signalling for the TM1638 is inverted but as it triggers on a rising edge still it is tolerant of that). +To make this work with fast devices, the shift clocking is slowed with a small delay (on the order of a microsecond). As of version 1.6 a new parameter *(_HIGH_FREQ)* has been introduced to constructor it is false by default. Set to true for high frequency MCU ~> 100Mhz. This will fix the issue of HF MCU not reading buttons correctly(ESP-Xs). The High_Freq parameter causes a custom shift-in function to be used. +The Teensy results have been sent to me, I don't have these MCU's them at time of writing. + +| IC | frequency | Status | +| ------ | ------ | ------ | +| ATtiny85 | 1Mhz internal | Working | +| Arduino UNO | 16 MHz | Working | +| Arduino Nano | 16 MHz | Working | +| STM32 "blue pill" STM32F103C8T6 | 72Mhz | Working | +| ESP8266 | 160Mhz | Working | +| ESP 32 | 240 MHz | Working, with high_freq set to true | +| Teensy 4.0| 150Mhz | Working model 1, no Data rest of models | +| Teensy 4.0| 396Mhz | Not working on model1 , no Data rest of models | + +*Note C* : Driving multiple displays. + +It is possible to drive multiple modules. Share the DIO and CLK lines and use a unique +STB line for each device. see issue number 10 at github for example code. + +*Note D* : Detecting multiple buttons pressed together. + +Model 1 and Model 3 CAN detect multiple buttons pressed. + +Model 3 has two different functions: + +1. ReadKey16 returns a byte with decimal value 1-16 this function cannot +detect multiple buttons pressed. + +2. ReadKey16Two returns a 16 bit integer where each bit corresponds to the 16 switch's. +However due to the wiring of the module, see SG-X lines on schematic, +Pressing Certain combinations of buttons will cause the data on Seven Segments to +change. So the simultaneous use of multiple key presses and the seven segments display +is problematic. See issue 12 on github for more details. + +Memory +------------------------------- + +Version 1.4. + +1. Model 1 memory usage NANO, basic hello world sketch. + +Sketch uses 1488 bytes (4%) of program storage space. +Global variables use 22 bytes (1%) of dynamic memory. + +2. Model 2 memory usage NANO, basic hello world sketch. + +Sketch uses 1536 bytes (5%) of program storage space. +Global variables use 23 bytes (1%) of dynamic memory. + + +Pic Port +------------------- + +MicroChip PIC XC8 port. +I have ported this library to the PIC for the XC8 compiler: +[ Link ](https://github.com/gavinlyonsrepo/pic_16F18446_projects) diff --git a/lib/lib_display/TM1638plus/keywords.txt b/lib/lib_display/TM1638plus/keywords.txt new file mode 100644 index 000000000..ae7e9bb67 --- /dev/null +++ b/lib/lib_display/TM1638plus/keywords.txt @@ -0,0 +1,35 @@ +# ----------------------------------------- +# Syntax coloring for TM1638plus library +# ----------------------------------------- + +# Datatypes (such as objects) +TM1638plus KEYWORD1 +TM1638plus_Model2 KEYWORD1 + +# Methods / functions +displayBegin KEYWORD2 +reset KEYWORD2 +brightness KEYWORD2 +DisplayDecNumNibble KEYWORD2 + +readButtons KEYWORD2 +setLED KEYWORD2 +setLEDs KEYWORD2 +displayText KEYWORD2 +displayASCIIwDot KEYWORD2 +displayASCII KEYWORD2 +display7Seg KEYWORD2 +displayHex KEYWORD2 +displayIntNum KEYWORD2 + +DisplaySegments KEYWORD2 +DisplayHexNum KEYWORD2 +DisplayDecNum KEYWORD2 +DisplayStr KEYWORD2 +ASCIItoSegment KEYWORD2 +ReadKey16 KEYWORD2 +ReadKey16Two KEYWORD2 + +# Constants + + diff --git a/lib/lib_display/TM1638plus/library.properties b/lib/lib_display/TM1638plus/library.properties new file mode 100644 index 000000000..8635f3eaf --- /dev/null +++ b/lib/lib_display/TM1638plus/library.properties @@ -0,0 +1,9 @@ +name=TM1638plus +version=1.7.0 +author=Gavin Lyons +maintainer=Gavin Lyons +sentence=TM1638plus is an Arduino library to control TM1638 seven segment modules. +paragraph=It supports Push Buttons, LEDs, ASCII, Decimal, Hexadecimal,text strings and the decimal point. Small Memory footprint. +category=Display +url=https://github.com/gavinlyonsrepo/TM1638plus +architectures=* diff --git a/lib/lib_display/TM1638plus/src/TM1638plus.cpp b/lib/lib_display/TM1638plus/src/TM1638plus.cpp new file mode 100644 index 000000000..c4076ab3a --- /dev/null +++ b/lib/lib_display/TM1638plus/src/TM1638plus.cpp @@ -0,0 +1,191 @@ +/* +* Project Name: TM1638 +* File: TM1638plus.cpp +* Description: source file arduino library for TM1638 module(LED & KEY). Model 1 & Model 3 +* Author: Gavin Lyons. +* Created May 2019 +* URL: https://github.com/gavinlyonsrepo/TM1638plus +*/ + +#include "TM1638plus.h" + + +TM1638plus::TM1638plus(uint8_t strobe, uint8_t clock, uint8_t data, bool highfreq) { + _STROBE_IO = strobe; + _DATA_IO = data; + _CLOCK_IO = clock; + _HIGH_FREQ = highfreq; +} + +void TM1638plus::displayBegin() { + pinMode(_STROBE_IO , OUTPUT); + pinMode(_DATA_IO, OUTPUT); + pinMode(_CLOCK_IO , OUTPUT); + sendCommand(TM_ACTIVATE); + brightness(TM_DEFAULT_BRIGHTNESS); + reset(); +} + + +void TM1638plus::sendCommand(uint8_t value) +{ + digitalWrite(_STROBE_IO, LOW); + sendData(value); + digitalWrite(_STROBE_IO, HIGH); +} + +void TM1638plus::sendData(uint8_t data) +{ + if (_HIGH_FREQ == false) + shiftOut(_DATA_IO, _CLOCK_IO, LSBFIRST, data); + else + TM_common.HighFreqshiftOut(_DATA_IO, _CLOCK_IO, LSBFIRST, data); +} + +void TM1638plus::reset() { + sendCommand(TM_WRITE_INC); // set auto increment mode + digitalWrite(_STROBE_IO, LOW); + sendData(TM_SEG_ADR); // set starting address to + for (uint8_t i = 0; i < 16; i++) + { + sendData(0x00); + } + digitalWrite(_STROBE_IO, HIGH); +} + +void TM1638plus::setLED(uint8_t position, uint8_t value) +{ + pinMode(_DATA_IO, OUTPUT); + sendCommand(TM_WRITE_LOC); + digitalWrite(_STROBE_IO, LOW); + sendData(TM_LEDS_ADR + (position << 1)); + sendData(value); + digitalWrite(_STROBE_IO, HIGH); +} + +void TM1638plus::setLEDs(uint16_t ledvalues) +{ + for (uint8_t LEDposition = 0; LEDposition < 8; LEDposition++) { + uint8_t colour = 0; + + if ((ledvalues & (1 << LEDposition)) != 0) { + colour |= TM_RED_LED; //scan lower byte, set Red if one + } + + if ((ledvalues & (1 << (LEDposition + 8))) != 0) { + colour |= TM_GREEN_LED; //scan upper byte, set green if one + } + + setLED(LEDposition, colour); + } +} + + +void TM1638plus::displayIntNum(unsigned long number, boolean leadingZeros) +{ + char values[TM_DISPLAY_SIZE + 1]; + snprintf(values, TM_DISPLAY_SIZE + 1, leadingZeros ? "%08ld" : "%ld", number); + displayText(values); +} + + +void TM1638plus::DisplayDecNumNibble(uint16_t numberUpper, uint16_t numberLower, boolean leadingZeros) +{ + char valuesUpper[TM_DISPLAY_SIZE + 1]; + char valuesLower[TM_DISPLAY_SIZE/2 + 1]; + snprintf(valuesUpper, TM_DISPLAY_SIZE/2 + 1, leadingZeros ? "%04d" : "%d", numberUpper); + snprintf(valuesLower, TM_DISPLAY_SIZE/2 + 1, leadingZeros ? "%04d" : "%d", numberLower); + strcat(valuesUpper ,valuesLower); + displayText(valuesUpper); +} + +void TM1638plus::displayText(const char *text) { + char c, pos; + pos = 0; + while ((c = (*text++)) && pos < TM_DISPLAY_SIZE) { + if (*text == '.' && c != '.') { + displayASCIIwDot(pos++, c); + + text++; + } else { + displayASCII(pos++, c); + } + } +} + + +void TM1638plus::displayASCIIwDot(uint8_t position, uint8_t ascii) { + // add 128 or 0x080 0b1000000 to turn on decimal point/dot in seven seg + display7Seg(position, pgm_read_byte(&SevenSeg[ascii- TM_ASCII_OFFSET]) + TM_DOT_MASK_DEC); +} + +void TM1638plus::display7Seg(uint8_t position, uint8_t value) { // call 7-segment + sendCommand(TM_WRITE_LOC); + digitalWrite(_STROBE_IO, LOW); + sendData(TM_SEG_ADR + (position << 1)); + sendData(value); + digitalWrite(_STROBE_IO, HIGH); +} + + +void TM1638plus::displayASCII(uint8_t position, uint8_t ascii) { + display7Seg(position, pgm_read_byte(&SevenSeg[ascii - TM_ASCII_OFFSET])); +} + +void TM1638plus::displayHex(uint8_t position, uint8_t hex) +{ + uint8_t offset = 0; + if (hex <= 9) + { + display7Seg(position, pgm_read_byte(&SevenSeg[hex + TM_HEX_OFFSET])); + // 16 is offset in reduced ASCII table for 0 + }else if ((hex >= 10) && (hex <=15)) + { + // Calculate offset in reduced ASCII table for AbCDeF + switch(hex) + { + case 10: offset = 'A'; break; + case 11: offset = 'b'; break; + case 12: offset = 'C'; break; + case 13: offset = 'd'; break; + case 14: offset = 'E'; break; + case 15: offset = 'F'; break; + } + display7Seg(position, pgm_read_byte(&SevenSeg[offset-TM_ASCII_OFFSET])); + } + +} + + +uint8_t TM1638plus::readButtons() +{ + uint8_t buttons = 0; + uint8_t v =0; + + digitalWrite(_STROBE_IO, LOW); + sendData(TM_BUTTONS_MODE); + pinMode(_DATA_IO, INPUT); + + for (uint8_t i = 0; i < 4; i++) + { + + if (_HIGH_FREQ == false) + v = shiftIn(_DATA_IO, _CLOCK_IO, LSBFIRST) << i; + else + v = TM_common.HighFreqshiftin(_DATA_IO, _CLOCK_IO, LSBFIRST) << i; + + buttons |= v; + } + + pinMode(_DATA_IO, OUTPUT); + digitalWrite(_STROBE_IO, HIGH); + return buttons; +} + + +void TM1638plus::brightness(uint8_t brightness) +{ + uint8_t value = 0; + value = TM_BRIGHT_ADR + (TM_BRIGHT_MASK & brightness); + sendCommand(value); +} diff --git a/lib/lib_display/TM1638plus/src/TM1638plus.h b/lib/lib_display/TM1638plus/src/TM1638plus.h new file mode 100644 index 000000000..6809a117b --- /dev/null +++ b/lib/lib_display/TM1638plus/src/TM1638plus.h @@ -0,0 +1,104 @@ +/* +* Project Name: TM1638plus +* File: TM1638plus.h +* Description: TM1638plus.h header file arduino library for TM1638 module(LED & KEY). Model 1 & Model 3 +* Author: Gavin Lyons. +* Created May 2019 +* URL: https://github.com/gavinlyonsrepo/TM1638plus +*/ + + +#ifndef TM1638PLUS_H +#define TM1638PLUS_H + +#if (ARDUINO >=100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#include "TM1638plus_common.h" + +class TM1638plus { + +public: + // Constructor + //Parameters + // 1. strobe = GPIO STB pin + // 2. clock = GPIO CLK pin + // 3. data = GPIO DIO pin + // 4. higfreq Changes the value of parameter _HIGH_FREQ which is default false + // This is used when running high freq MCU CPU (~>100Mhz) because of issues with button function. + // Pass true when running high freq MCU CPU (~>100Mhz). + TM1638plus(uint8_t strobe, uint8_t clock, uint8_t data, bool highfreq = false); + + // Methods + + void displayBegin(); // Begin method , sets pinmodes , Call in setup + + void reset(void); // Reset / Clear module + + //Sets the brightness level on a scale of brightness = 0 to 7. + //0 is not turned off, it's just the lowest brightness. + //If user wishes to change the default brightness at start-up change. + //The DEFAULT_BRIGHTNESS define in header file. + void brightness(uint8_t brightness); + + //Read buttons returns a byte with value of buttons 1-8 b7b6b5b4b3b2b1b0 + // 1 pressed, zero not pressed. + //User may have to debounce buttons depending on application. + //See [URL LINK](https://github.com/gavinlyonsrepo/Arduino_Clock_3) + // for de-bonce example. + uint8_t readButtons(void); + + // Send Text to Seven segments, passed char array pointer + // dots are removed from string and dot on preceding digit switched on + // "abc.def" will be shown as "abcdef" with c decimal point turned on. + void displayText(const char *text); + + // Send ASCII value to seven segment, pass position 0-7 and ASCII value byte + void displayASCII(uint8_t position, uint8_t ascii); + + // Same as displayASCII function but turns on dot/decimal point as well + void displayASCIIwDot(uint8_t position, uint8_t ascii) ; + + // Send HEX value to seven segment, pass position 0-7 and hex value(DEC) 0-15 + void displayHex(uint8_t position, uint8_t hex); + + // Send seven segment value to seven segment + // pass position 0-7 byte of data corresponding to segments (dp)gfedcba + // i.e 0b01000001 will set g and a on. + void display7Seg(uint8_t position, uint8_t value); + + //Display an integer and leading zeros optional + void displayIntNum(unsigned long number, boolean leadingZeros = true); + + //Divides the display into two nibbles and displays a Decimal number in each. + //takes in two numbers 0-9999 for each nibble , and byte for decimal point display, + //and leading zeros optional + void DisplayDecNumNibble(uint16_t numberUpper, uint16_t numberLower, boolean leadingZeros = true); + + // Set the LEDs. passed one 16bit integer. + // MODEL 3: + //MSB byte for the green LEDs, LS byte for the red LEDs (0xgreenred) + //ie. 0xE007 1110 0000 0000 0111 results in L8-L0 GGGX XRRR, NOTE L8 is RHS on display + // MODEL 1: + // MSB byte 1 for red LED , LSB byte n/a set to 0x00 (0xleds, 0xXX) + //i.e 0xF100 1111 0000 L8-L0 RRRRXXX0 NOTE L8 is RHS on display + void setLEDs(uint16_t greenred); + + // Set an LED, pass it LED position 0-7 and value 0 or 1 , L1-L8 + void setLED(uint8_t position, uint8_t value); + +private: + uint8_t _STROBE_IO; + uint8_t _DATA_IO; + uint8_t _CLOCK_IO; + void sendCommand(uint8_t value); + void sendData(uint8_t data); + //This is used when running high freq CPU + bool _HIGH_FREQ = false; + TM1638plus_common TM_common; +}; + +#endif diff --git a/lib/lib_display/TM1638plus/src/TM1638plus_common.cpp b/lib/lib_display/TM1638plus/src/TM1638plus_common.cpp new file mode 100644 index 000000000..f0accc1fc --- /dev/null +++ b/lib/lib_display/TM1638plus/src/TM1638plus_common.cpp @@ -0,0 +1,52 @@ +/* +* Project Name: TM1638plus +* File: TM1638plus_common +* Description: cpp file for common data and functions between model 1 and 2 classes +* Arduino library TM1638plus +* Author: Gavin Lyons. +* URL: https://github.com/gavinlyonsrepo/TM1638plus +*/ + +#include "TM1638plus_common.h" + + +TM1638plus_common::TM1638plus_common() +{ + // Blank constructor +} + +uint8_t TM1638plus_common::HighFreqshiftin(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) +{ + uint8_t value = 0; + uint8_t i = 0; + + for(i = 0; i < 8; ++i) { + if(bitOrder == LSBFIRST) + value |= digitalRead(dataPin) << i; + else + value |= digitalRead(dataPin) << (7 - i); + + digitalWrite(clockPin, HIGH); + delayMicroseconds(1); + digitalWrite(clockPin, LOW); + delayMicroseconds(1); + } + return value; +} + +void TM1638plus_common::HighFreqshiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) +{ + uint8_t i; + + for (i = 0; i < 8; i++) { + if (bitOrder == LSBFIRST) + digitalWrite(dataPin, !!(val & (1 << i))); + else + digitalWrite(dataPin, !!(val & (1 << (7 - i)))); + + digitalWrite(clockPin, HIGH); + delayMicroseconds(1); + digitalWrite(clockPin, LOW); + delayMicroseconds(1); + } +} diff --git a/lib/lib_display/TM1638plus/src/TM1638plus_common.h b/lib/lib_display/TM1638plus/src/TM1638plus_common.h new file mode 100644 index 000000000..36a7d5408 --- /dev/null +++ b/lib/lib_display/TM1638plus/src/TM1638plus_common.h @@ -0,0 +1,152 @@ +/* +* Project Name: TM1638plus +* File: TM1638plus_common.h +* Description: header file for common data and functions between model 1 and 2 classes +* Arduino library TM1638plus +* Author: Gavin Lyons. +* URL: https://github.com/gavinlyonsrepo/TM1638plus +*/ + +#ifndef TM1638PLUS_COMMON_H +#define TM1638PLUS_COMMON_H + +#if (ARDUINO >=100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#define TM_ACTIVATE 0x8F // Start up +#define TM_BUTTONS_MODE 0x42 // Buttons mode +#define TM_WRITE_LOC 0x44 // Write to a location +#define TM_WRITE_INC 0x40 // Incremental write +#define TM_SEG_ADR 0xC0 // leftmost segment Address C0 C2 C4 C6 C8 CA CC CE +#define TM_LEDS_ADR 0xC1 // Leftmost LED address C1 C3 C5 C7 C9 CB CD CF +#define TM_BRIGHT_ADR 0x88 // Brightness address +#define TM_BRIGHT_MASK 0x07 // Brightness mask +#define TM_DEFAULT_BRIGHTNESS 0x02 //can be 0x00 to 0x07 +#define TM_DISPLAY_SIZE 8 //size of display + +#define TM_ASCII_OFFSET 32 // Ascii table offset to jump over first missing 32 chars +#define TM_HEX_OFFSET 16 // Ascii table offset to reach number position +#define TM_DOT_MASK_DEC 128 // 0x80 Mask to switch on decimal point in seven seg. + +#define TM_RED_LED 0x02 // Model 3 +#define TM_GREEN_LED 0x01 // Model 3 +#define TM_OFF_LED 0x00 + +// font , map of ASCII values/table to 7-segment, offset to position 32. +const PROGMEM unsigned char SevenSeg[] = { + 0x00, /* (space) */ + 0x86, /* ! */ + 0x22, /* " */ + 0x7E, /* # */ + 0x6D, /* $ */ + 0xD2, /* % */ + 0x46, /* & */ + 0x20, /* ' */ + 0x29, /* ( */ + 0x0B, /* ) */ + 0x21, /* * */ + 0x70, /* + */ + 0x10, /* , */ + 0x40, /* - */ + 0x80, /* . */ + 0x52, /* / */ + 0x3F, /* 0 */ + 0x06, /* 1 */ + 0x5B, /* 2 */ + 0x4F, /* 3 */ + 0x66, /* 4 */ + 0x6D, /* 5 */ + 0x7D, /* 6 */ + 0x07, /* 7 */ + 0x7F, /* 8 */ + 0x6F, /* 9 */ + 0x09, /* : */ + 0x0D, /* ; */ + 0x61, /* < */ + 0x48, /* = */ + 0x43, /* > */ + 0xD3, /* ? */ + 0x5F, /* @ */ + 0x77, /* A */ + 0x7C, /* B */ + 0x39, /* C */ + 0x5E, /* D */ + 0x79, /* E */ + 0x71, /* F */ + 0x3D, /* G */ + 0x76, /* H */ + 0x30, /* I */ + 0x1E, /* J */ + 0x75, /* K */ + 0x38, /* L */ + 0x15, /* M */ + 0x37, /* N */ + 0x3F, /* O */ + 0x73, /* P */ + 0x6B, /* Q */ + 0x33, /* R */ + 0x6D, /* S */ + 0x78, /* T */ + 0x3E, /* U */ + 0x3E, /* V */ + 0x2A, /* W */ + 0x76, /* X */ + 0x6E, /* Y */ + 0x5B, /* Z */ + 0x39, /* [ */ + 0x64, /* \ */ + 0x0F, /* ] */ + 0x23, /* ^ */ + 0x08, /* _ */ + 0x02, /* ` */ + 0x5F, /* a */ + 0x7C, /* b */ + 0x58, /* c */ + 0x5E, /* d */ + 0x7B, /* e */ + 0x71, /* f */ + 0x6F, /* g */ + 0x74, /* h */ + 0x10, /* i */ + 0x0C, /* j */ + 0x75, /* k */ + 0x30, /* l */ + 0x14, /* m */ + 0x54, /* n */ + 0x5C, /* o */ + 0x73, /* p */ + 0x67, /* q */ + 0x50, /* r */ + 0x6D, /* s */ + 0x78, /* t */ + 0x1C, /* u */ + 0x1C, /* v */ + 0x14, /* w */ + 0x76, /* x */ + 0x6E, /* y */ + 0x5B, /* z */ + // Note : Removed last 4 characters to reduce program size as of v 1.3.0 +// 0x46, /* { */ +// 0x30, /* | */ +// 0x70, /* } */ +// 0x01, /* ~ */ +}; + +// Class for some common functions +class TM1638plus_common{ + +public: + // Constructor + TM1638plus_common(); + + // Used instead of arduino function "shiftin" when _HIGH_FREQ is set to true + uint8_t HighFreqshiftin(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) ; + // Used instead of arduino function "shiftOut" when _HIGH_FREQ is set to true + void HighFreqshiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); + +}; + +#endif diff --git a/lib/lib_i2c/MPU6886/library.properties b/lib/lib_i2c/MPU6886/library.properties new file mode 100644 index 000000000..1a08c8516 --- /dev/null +++ b/lib/lib_i2c/MPU6886/library.properties @@ -0,0 +1,9 @@ +name=MPU6886 +version= +author=M5StickC +maintainer=Stephan Hadinger +sentence=Support for MPU6886 +paragraph=Support for MPU6886 +category= +url=https://github.com/m5stack/M5StickC/blob/master/src/utility/ +architectures=esp32,esp8266 diff --git a/lib/libesp32/CORE2_Library/MPU6886.cpp b/lib/lib_i2c/MPU6886/src/MPU6886.cpp similarity index 68% rename from lib/libesp32/CORE2_Library/MPU6886.cpp rename to lib/lib_i2c/MPU6886/src/MPU6886.cpp index 418c94b39..9ae45461d 100755 --- a/lib/libesp32/CORE2_Library/MPU6886.cpp +++ b/lib/lib_i2c/MPU6886/src/MPU6886.cpp @@ -2,39 +2,33 @@ #include #include -MPU6886::MPU6886(){ - -} - void MPU6886::I2C_Read_NBytes(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *read_Buffer){ - Wire1.beginTransmission(driver_Addr); - Wire1.write(start_Addr); - Wire1.endTransmission(false); + myWire.beginTransmission(driver_Addr); + myWire.write(start_Addr); + myWire.endTransmission(false); uint8_t i = 0; - Wire1.requestFrom(driver_Addr,number_Bytes); + myWire.requestFrom(driver_Addr,number_Bytes); //! Put read results in the Rx buffer - while (Wire1.available()) { - read_Buffer[i++] = Wire1.read(); + while (myWire.available()) { + read_Buffer[i++] = myWire.read(); } } void MPU6886::I2C_Write_NBytes(uint8_t driver_Addr, uint8_t start_Addr, uint8_t number_Bytes, uint8_t *write_Buffer){ - Wire1.beginTransmission(driver_Addr); - Wire1.write(start_Addr); - Wire1.write(*write_Buffer); - Wire1.endTransmission(); + myWire.beginTransmission(driver_Addr); + myWire.write(start_Addr); + myWire.write(*write_Buffer); + myWire.endTransmission(); } int MPU6886::Init(void){ unsigned char tempdata[1]; unsigned char regdata; - - Wire1.begin(21,22); - + I2C_Read_NBytes(MPU6886_ADDRESS, MPU6886_WHOAMI, 1, tempdata); if(tempdata[0] != 0x19) return -1; @@ -52,11 +46,11 @@ int MPU6886::Init(void){ I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_PWR_MGMT_1, 1, ®data); delay(10); - regdata = 0x10; + regdata = 0x10; // AFS_8G I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_ACCEL_CONFIG, 1, ®data); delay(1); - regdata = 0x18; + regdata = 0x18; // GFS_2000DPS I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_GYRO_CONFIG, 1, ®data); delay(1); @@ -128,24 +122,24 @@ void MPU6886::getTempAdc(int16_t *t){ -//!俯仰,航向,横滚:pitch,yaw,roll,指三维空间中飞行器的旋转状态。 -void MPU6886::getAhrsData(float *pitch,float *roll,float *yaw){ +// //!俯仰,航向,横滚:pitch,yaw,roll,指三维空间中飞行器的旋转状态。 +// void MPU6886::getAhrsData(float *pitch,float *roll,float *yaw){ - float accX = 0; - float accY = 0; - float accZ = 0; +// float accX = 0; +// float accY = 0; +// float accZ = 0; - float gyroX = 0; - float gyroY = 0; - float gyroZ = 0; +// float gyroX = 0; +// float gyroY = 0; +// float gyroZ = 0; - getGyroData(&gyroX,&gyroY,&gyroZ); - getAccelData(&accX,&accY,&accZ); +// getGyroData(&gyroX,&gyroY,&gyroZ); +// getAccelData(&accX,&accY,&accZ); - MahonyAHRSupdateIMU(gyroX * DEG_TO_RAD, gyroY * DEG_TO_RAD, gyroZ * DEG_TO_RAD, accX, accY, accZ,pitch,roll,yaw); +// MahonyAHRSupdateIMU(gyroX * DEG_TO_RAD, gyroY * DEG_TO_RAD, gyroZ * DEG_TO_RAD, accX, accY, accZ,pitch,roll,yaw); -} +// } void MPU6886::getGres(){ @@ -153,16 +147,20 @@ void MPU6886::getGres(){ { // Possible gyro scales (and their register bit settings) are: case GFS_250DPS: - gRes = 250.0/32768.0; + gRes = 250.0f/32768.0f; + gyRange = 250; break; case GFS_500DPS: - gRes = 500.0/32768.0; + gRes = 500.0f/32768.0f; + gyRange = 500; break; case GFS_1000DPS: - gRes = 1000.0/32768.0; + gRes = 1000.0f/32768.0f; + gyRange = 1000; break; case GFS_2000DPS: - gRes = 2000.0/32768.0; + gRes = 2000.0f/32768.0f; + gyRange = 2000; break; } @@ -177,15 +175,19 @@ void MPU6886::getAres(){ // Here's a bit of an algorith to calculate DPS/(ADC tick) based on that 2-bit value: case AFS_2G: aRes = 2.0/32768.0; + acRange = 2000; break; case AFS_4G: aRes = 4.0/32768.0; + acRange = 4000; break; case AFS_8G: aRes = 8.0/32768.0; + acRange = 8000; break; case AFS_16G: aRes = 16.0/32768.0; + acRange = 16000; break; } @@ -215,7 +217,19 @@ void MPU6886::SetAccelFsr(Ascale scale) } +// x/y/z are in 1/1000 if g +// avoiding costly float calculations +void MPU6886::getAccelDataInt(int16_t* ax, int16_t* ay, int16_t* az) { + int16_t accX = 0; + int16_t accY = 0; + int16_t accZ = 0; + getAccelAdc(&accX, &accY, &accZ); + if (ax != nullptr) { *ax = ((int32_t)accX * acRange) / 0x7FFFL; } + if (ay != nullptr) { *ay = ((int32_t)accY * acRange) / 0x7FFFL; } + if (az != nullptr) { *az = ((int32_t)accZ * acRange) / 0x7FFFL; } + +} void MPU6886::getAccelData(float* ax, float* ay, float* az){ @@ -232,6 +246,20 @@ void MPU6886::getAccelData(float* ax, float* ay, float* az){ } +// x/y/z are in dps - degrees per second +// avoiding costly float calculations +void MPU6886::getGyroDataInt(int16_t* ax, int16_t* ay, int16_t* az) { + int16_t gyX = 0; + int16_t gyY = 0; + int16_t gyZ = 0; + getGyroAdc(&gyX, &gyY, &gyZ); + + if (ax != nullptr) { *ax = ((int32_t)gyX * gyRange) / 0x7FFFL; } + if (ay != nullptr) { *ay = ((int32_t)gyY * gyRange) / 0x7FFFL; } + if (az != nullptr) { *az = ((int32_t)gyZ * gyRange) / 0x7FFFL; } + +} + void MPU6886::getGyroData(float* gx, float* gy, float* gz){ int16_t gyroX = 0; int16_t gyroY = 0; diff --git a/lib/libesp32/CORE2_Library/MPU6886.h b/lib/lib_i2c/MPU6886/src/MPU6886.h similarity index 82% rename from lib/libesp32/CORE2_Library/MPU6886.h rename to lib/lib_i2c/MPU6886/src/MPU6886.h index b1a0fb16b..025f71587 100755 --- a/lib/libesp32/CORE2_Library/MPU6886.h +++ b/lib/lib_i2c/MPU6886/src/MPU6886.h @@ -10,7 +10,6 @@ #include #include -#include "MahonyAHRS.h" #define MPU6886_ADDRESS 0x68 #define MPU6886_WHOAMI 0x75 @@ -67,8 +66,15 @@ class MPU6886 { Gscale Gyscale = GFS_2000DPS; Ascale Acscale = AFS_8G; + int16_t acRange = 8000; // 1/1000 of g + int16_t gyRange = 2000; // dps - degree per second public: - MPU6886(); + MPU6886(void) {}; + #ifdef ESP32 + void setBus(uint32_t _bus) { myWire = _bus ? Wire1 : Wire; }; + #else + void setBus(uint32_t _bus) { myWire = Wire; }; + #endif int Init(void); void getAccelAdc(int16_t* ax, int16_t* ay, int16_t* az); void getGyroAdc(int16_t* gx, int16_t* gy, int16_t* gz); @@ -77,13 +83,17 @@ class MPU6886 { void getAccelData(float* ax, float* ay, float* az); void getGyroData(float* gx, float* gy, float* gz); void getTempData(float *t); + // int variants + void getAccelDataInt(int16_t* ax, int16_t* ay, int16_t* az); + void getGyroDataInt(int16_t* gx, int16_t* gy, int16_t* gz); void SetGyroFsr(Gscale scale); void SetAccelFsr(Ascale scale); - void getAhrsData(float *pitch,float *roll,float *yaw); + // void getAhrsData(float *pitch,float *roll,float *yaw); public: + TwoWire & myWire = Wire; // default to Wire (bus 0) float aRes, gRes; private: diff --git a/lib/libesp32/Berry-0.1.10/generate/be_const_strtab.h b/lib/libesp32/Berry-0.1.10/generate/be_const_strtab.h index d3ad809d7..2d1b7e9e0 100644 --- a/lib/libesp32/Berry-0.1.10/generate/be_const_strtab.h +++ b/lib/libesp32/Berry-0.1.10/generate/be_const_strtab.h @@ -1,111 +1,116 @@ +extern const bcstring be_const_str_remove; +extern const bcstring be_const_str_false; +extern const bcstring be_const_str_raise; +extern const bcstring be_const_str_opt_connect; +extern const bcstring be_const_str_dot_p; +extern const bcstring be_const_str_calldepth; +extern const bcstring be_const_str_toupper; +extern const bcstring be_const_str_break; +extern const bcstring be_const_str_map; +extern const bcstring be_const_str_bytes; +extern const bcstring be_const_str_tanh; +extern const bcstring be_const_str_real; +extern const bcstring be_const_str_count; +extern const bcstring be_const_str_setitem; +extern const bcstring be_const_str_split; +extern const bcstring be_const_str_if; +extern const bcstring be_const_str_format; +extern const bcstring be_const_str_pow; +extern const bcstring be_const_str_tostring; +extern const bcstring be_const_str_load; +extern const bcstring be_const_str_setrange; +extern const bcstring be_const_str_char; extern const bcstring be_const_str_acos; +extern const bcstring be_const_str_deinit; +extern const bcstring be_const_str_dump; +extern const bcstring be_const_str_sqrt; +extern const bcstring be_const_str_fromstring; +extern const bcstring be_const_str_opt_eq; extern const bcstring be_const_str_asin; +extern const bcstring be_const_str_byte; +extern const bcstring be_const_str_copy; +extern const bcstring be_const_str_floor; +extern const bcstring be_const_str_find; +extern const bcstring be_const_str_var; +extern const bcstring be_const_str_opt_add; +extern const bcstring be_const_str___lower__; +extern const bcstring be_const_str_rand; +extern const bcstring be_const_str_sin; +extern const bcstring be_const_str_deg; +extern const bcstring be_const_str_imin; +extern const bcstring be_const_str_class; +extern const bcstring be_const_str_try; +extern const bcstring be_const_str_allocated; +extern const bcstring be_const_str_asstring; +extern const bcstring be_const_str_classname; +extern const bcstring be_const_str_reverse; +extern const bcstring be_const_str_assert; +extern const bcstring be_const_str_str; +extern const bcstring be_const_str_imax; +extern const bcstring be_const_str_init; +extern const bcstring be_const_str_except; +extern const bcstring be_const_str_return; +extern const bcstring be_const_str_opt_neq; +extern const bcstring be_const_str_hex; +extern const bcstring be_const_str_resize; +extern const bcstring be_const_str_as; +extern const bcstring be_const_str___upper__; +extern const bcstring be_const_str_codedump; +extern const bcstring be_const_str_cosh; +extern const bcstring be_const_str_abs; +extern const bcstring be_const_str_collect; +extern const bcstring be_const_str_atan; +extern const bcstring be_const_str_attrdump; +extern const bcstring be_const_str_input; +extern const bcstring be_const_str_; +extern const bcstring be_const_str_compile; +extern const bcstring be_const_str_iter; +extern const bcstring be_const_str_lower; +extern const bcstring be_const_str_number; +extern const bcstring be_const_str_print; +extern const bcstring be_const_str_exp; +extern const bcstring be_const_str_pi; +extern const bcstring be_const_str___iterator__; +extern const bcstring be_const_str_log; +extern const bcstring be_const_str_log10; +extern const bcstring be_const_str_ceil; +extern const bcstring be_const_str_get; +extern const bcstring be_const_str_tolower; +extern const bcstring be_const_str_while; +extern const bcstring be_const_str_import; +extern const bcstring be_const_str_size; extern const bcstring be_const_str_list; +extern const bcstring be_const_str_rad; +extern const bcstring be_const_str_tan; +extern const bcstring be_const_str_type; +extern const bcstring be_const_str_insert; extern const bcstring be_const_str_module; +extern const bcstring be_const_str_range; +extern const bcstring be_const_str_super; +extern const bcstring be_const_str_issubclass; +extern const bcstring be_const_str_def; +extern const bcstring be_const_str_classof; +extern const bcstring be_const_str_sinh; +extern const bcstring be_const_str_srand; +extern const bcstring be_const_str_end; +extern const bcstring be_const_str_clear; +extern const bcstring be_const_str_top; +extern const bcstring be_const_str_nil; +extern const bcstring be_const_str_open; +extern const bcstring be_const_str_do; +extern const bcstring be_const_str_add; +extern const bcstring be_const_str_isinstance; extern const bcstring be_const_str_pop; extern const bcstring be_const_str_int; -extern const bcstring be_const_str_push; -extern const bcstring be_const_str_setrange; -extern const bcstring be_const_str_sinh; -extern const bcstring be_const_str_elif; -extern const bcstring be_const_str_iter; -extern const bcstring be_const_str_load; -extern const bcstring be_const_str_class; -extern const bcstring be_const_str_if; -extern const bcstring be_const_str_opt_eq; -extern const bcstring be_const_str_ceil; -extern const bcstring be_const_str_floor; -extern const bcstring be_const_str_map; -extern const bcstring be_const_str_print; -extern const bcstring be_const_str_else; -extern const bcstring be_const_str_find; -extern const bcstring be_const_str_str; -extern const bcstring be_const_str___upper__; -extern const bcstring be_const_str_dump; -extern const bcstring be_const_str_atan; -extern const bcstring be_const_str_size; -extern const bcstring be_const_str_tolower; -extern const bcstring be_const_str_opt_add; -extern const bcstring be_const_str_abs; -extern const bcstring be_const_str_lower; -extern const bcstring be_const_str_end; -extern const bcstring be_const_str_import; -extern const bcstring be_const_str_classof; -extern const bcstring be_const_str_concat; -extern const bcstring be_const_str_byte; -extern const bcstring be_const_str_top; -extern const bcstring be_const_str_clear; -extern const bcstring be_const_str_opt_connect; -extern const bcstring be_const_str_collect; -extern const bcstring be_const_str_init; -extern const bcstring be_const_str_log10; -extern const bcstring be_const_str_nil; -extern const bcstring be_const_str_; -extern const bcstring be_const_str_real; -extern const bcstring be_const_str_calldepth; -extern const bcstring be_const_str_format; -extern const bcstring be_const_str_pi; -extern const bcstring be_const_str_do; -extern const bcstring be_const_str___iterator__; -extern const bcstring be_const_str_number; -extern const bcstring be_const_str_type; -extern const bcstring be_const_str_dot_p; -extern const bcstring be_const_str_traceback; -extern const bcstring be_const_str_as; -extern const bcstring be_const_str___lower__; -extern const bcstring be_const_str_exp; -extern const bcstring be_const_str_hex; -extern const bcstring be_const_str_char; -extern const bcstring be_const_str_split; -extern const bcstring be_const_str_toupper; -extern const bcstring be_const_str_deinit; -extern const bcstring be_const_str_tan; -extern const bcstring be_const_str_srand; -extern const bcstring be_const_str_imin; -extern const bcstring be_const_str_input; -extern const bcstring be_const_str_issubclass; -extern const bcstring be_const_str_tostring; -extern const bcstring be_const_str_break; -extern const bcstring be_const_str_insert; -extern const bcstring be_const_str_var; -extern const bcstring be_const_str_open; -extern const bcstring be_const_str_tanh; -extern const bcstring be_const_str_upper; -extern const bcstring be_const_str_allocated; -extern const bcstring be_const_str_rad; -extern const bcstring be_const_str_attrdump; -extern const bcstring be_const_str_copy; -extern const bcstring be_const_str_sqrt; -extern const bcstring be_const_str_for; -extern const bcstring be_const_str_raise; -extern const bcstring be_const_str_opt_neq; -extern const bcstring be_const_str_assert; -extern const bcstring be_const_str_item; -extern const bcstring be_const_str_reverse; -extern const bcstring be_const_str_sin; -extern const bcstring be_const_str_super; -extern const bcstring be_const_str_try; -extern const bcstring be_const_str_range; -extern const bcstring be_const_str_return; -extern const bcstring be_const_str_compile; -extern const bcstring be_const_str_false; -extern const bcstring be_const_str_resize; -extern const bcstring be_const_str_continue; -extern const bcstring be_const_str_log; -extern const bcstring be_const_str_true; -extern const bcstring be_const_str_while; -extern const bcstring be_const_str_pow; -extern const bcstring be_const_str_cos; -extern const bcstring be_const_str_count; -extern const bcstring be_const_str_remove; -extern const bcstring be_const_str_imax; -extern const bcstring be_const_str_rand; -extern const bcstring be_const_str_codedump; -extern const bcstring be_const_str_deg; extern const bcstring be_const_str_keys; -extern const bcstring be_const_str_setitem; -extern const bcstring be_const_str_def; -extern const bcstring be_const_str_except; -extern const bcstring be_const_str_classname; -extern const bcstring be_const_str_isinstance; -extern const bcstring be_const_str_cosh; +extern const bcstring be_const_str_elif; +extern const bcstring be_const_str_item; +extern const bcstring be_const_str_push; +extern const bcstring be_const_str_concat; +extern const bcstring be_const_str_traceback; +extern const bcstring be_const_str_upper; +extern const bcstring be_const_str_true; +extern const bcstring be_const_str_continue; +extern const bcstring be_const_str_else; +extern const bcstring be_const_str_cos; +extern const bcstring be_const_str_for; diff --git a/lib/libesp32/Berry-0.1.10/generate/be_const_strtab_def.h b/lib/libesp32/Berry-0.1.10/generate/be_const_strtab_def.h index b967bc818..bce08392c 100644 --- a/lib/libesp32/Berry-0.1.10/generate/be_const_strtab_def.h +++ b/lib/libesp32/Berry-0.1.10/generate/be_const_strtab_def.h @@ -1,165 +1,172 @@ -be_define_const_str(acos, "acos", 1006755615u, 0, 4, &be_const_str_asin); -be_define_const_str(asin, "asin", 4272848550u, 0, 4, &be_const_str_list); -be_define_const_str(list, "list", 217798785u, 0, 4, &be_const_str_module); -be_define_const_str(module, "module", 3617558685u, 0, 6, &be_const_str_pop); -be_define_const_str(pop, "pop", 1362321360u, 0, 3, NULL); -be_define_const_str(int, "int", 2515107422u, 0, 3, &be_const_str_push); -be_define_const_str(push, "push", 2272264157u, 0, 4, &be_const_str_setrange); -be_define_const_str(setrange, "setrange", 3794019032u, 0, 8, &be_const_str_sinh); -be_define_const_str(sinh, "sinh", 282220607u, 0, 4, &be_const_str_elif); -be_define_const_str(elif, "elif", 3232090307u, 51, 4, NULL); -be_define_const_str(iter, "iter", 3124256359u, 0, 4, &be_const_str_load); -be_define_const_str(load, "load", 3859241449u, 0, 4, &be_const_str_class); -be_define_const_str(class, "class", 2872970239u, 57, 5, &be_const_str_if); -be_define_const_str(if, "if", 959999494u, 50, 2, NULL); -be_define_const_str(opt_eq, "==", 2431966415u, 0, 2, &be_const_str_ceil); -be_define_const_str(ceil, "ceil", 1659167240u, 0, 4, NULL); -be_define_const_str(floor, "floor", 3102149661u, 0, 5, &be_const_str_map); -be_define_const_str(map, "map", 3751997361u, 0, 3, &be_const_str_print); -be_define_const_str(print, "print", 372738696u, 0, 5, &be_const_str_else); -be_define_const_str(else, "else", 3183434736u, 52, 4, NULL); -be_define_const_str(find, "find", 3186656602u, 0, 4, &be_const_str_str); -be_define_const_str(str, "str", 3259748752u, 0, 3, NULL); -be_define_const_str(__upper__, "__upper__", 3612202883u, 0, 9, &be_const_str_dump); -be_define_const_str(dump, "dump", 3663001223u, 0, 4, NULL); -be_define_const_str(atan, "atan", 108579519u, 0, 4, &be_const_str_size); -be_define_const_str(size, "size", 597743964u, 0, 4, &be_const_str_tolower); -be_define_const_str(tolower, "tolower", 1042520049u, 0, 7, NULL); -be_define_const_str(opt_add, "+", 772578730u, 0, 1, &be_const_str_abs); -be_define_const_str(abs, "abs", 709362235u, 0, 3, &be_const_str_lower); -be_define_const_str(lower, "lower", 3038577850u, 0, 5, &be_const_str_end); -be_define_const_str(end, "end", 1787721130u, 56, 3, &be_const_str_import); -be_define_const_str(import, "import", 288002260u, 66, 6, NULL); -be_define_const_str(classof, "classof", 1796577762u, 0, 7, &be_const_str_concat); -be_define_const_str(concat, "concat", 4124019837u, 0, 6, NULL); -be_define_const_str(byte, "byte", 1683620383u, 0, 4, &be_const_str_top); -be_define_const_str(top, "top", 2802900028u, 0, 3, NULL); -be_define_const_str(clear, "clear", 1550717474u, 0, 5, NULL); -be_define_const_str(opt_connect, "..", 2748622605u, 0, 2, &be_const_str_collect); -be_define_const_str(collect, "collect", 2399039025u, 0, 7, &be_const_str_init); -be_define_const_str(init, "init", 380752755u, 0, 4, &be_const_str_log10); -be_define_const_str(log10, "log10", 2346846000u, 0, 5, &be_const_str_nil); -be_define_const_str(nil, "nil", 228849900u, 63, 3, NULL); -be_define_const_str(, "", 2166136261u, 0, 0, &be_const_str_real); -be_define_const_str(real, "real", 3604983901u, 0, 4, NULL); -be_define_const_str(calldepth, "calldepth", 3122364302u, 0, 9, &be_const_str_format); -be_define_const_str(format, "format", 3114108242u, 0, 6, &be_const_str_pi); -be_define_const_str(pi, "pi", 1213090802u, 0, 2, &be_const_str_do); -be_define_const_str(do, "do", 1646057492u, 65, 2, NULL); -be_define_const_str(__iterator__, "__iterator__", 3884039703u, 0, 12, &be_const_str_number); -be_define_const_str(number, "number", 467038368u, 0, 6, &be_const_str_type); -be_define_const_str(type, "type", 1361572173u, 0, 4, NULL); -be_define_const_str(dot_p, ".p", 1171526419u, 0, 2, &be_const_str_traceback); -be_define_const_str(traceback, "traceback", 3385188109u, 0, 9, &be_const_str_as); -be_define_const_str(as, "as", 1579491469u, 67, 2, NULL); -be_define_const_str(__lower__, "__lower__", 123855590u, 0, 9, &be_const_str_exp); -be_define_const_str(exp, "exp", 1923516200u, 0, 3, &be_const_str_hex); -be_define_const_str(hex, "hex", 4273249610u, 0, 3, NULL); -be_define_const_str(char, "char", 2823553821u, 0, 4, &be_const_str_split); -be_define_const_str(split, "split", 2276994531u, 0, 5, &be_const_str_toupper); -be_define_const_str(toupper, "toupper", 3691983576u, 0, 7, NULL); -be_define_const_str(deinit, "deinit", 2345559592u, 0, 6, &be_const_str_tan); -be_define_const_str(tan, "tan", 2633446552u, 0, 3, NULL); -be_define_const_str(srand, "srand", 465518633u, 0, 5, NULL); -be_define_const_str(imin, "imin", 2714127864u, 0, 4, &be_const_str_input); -be_define_const_str(input, "input", 4191711099u, 0, 5, &be_const_str_issubclass); -be_define_const_str(issubclass, "issubclass", 4078395519u, 0, 10, NULL); -be_define_const_str(tostring, "tostring", 2299708645u, 0, 8, &be_const_str_break); -be_define_const_str(break, "break", 3378807160u, 58, 5, NULL); -be_define_const_str(insert, "insert", 3332609576u, 0, 6, &be_const_str_var); -be_define_const_str(var, "var", 2317739966u, 64, 3, NULL); -be_define_const_str(open, "open", 3546203337u, 0, 4, &be_const_str_tanh); -be_define_const_str(tanh, "tanh", 153638352u, 0, 4, &be_const_str_upper); -be_define_const_str(upper, "upper", 176974407u, 0, 5, NULL); -be_define_const_str(allocated, "allocated", 429986098u, 0, 9, &be_const_str_rad); -be_define_const_str(rad, "rad", 1358899048u, 0, 3, NULL); -be_define_const_str(attrdump, "attrdump", 1521571304u, 0, 8, &be_const_str_copy); -be_define_const_str(copy, "copy", 3848464964u, 0, 4, &be_const_str_sqrt); -be_define_const_str(sqrt, "sqrt", 2112764879u, 0, 4, NULL); -be_define_const_str(for, "for", 2901640080u, 54, 3, &be_const_str_raise); +be_define_const_str(remove, "remove", 3683784189u, 0, 6, &be_const_str_false); +be_define_const_str(false, "false", 184981848u, 62, 5, &be_const_str_raise); be_define_const_str(raise, "raise", 1593437475u, 70, 5, NULL); -be_define_const_str(opt_neq, "!=", 2428715011u, 0, 2, &be_const_str_assert); -be_define_const_str(assert, "assert", 2774883451u, 0, 6, &be_const_str_item); -be_define_const_str(item, "item", 2671260646u, 0, 4, &be_const_str_reverse); -be_define_const_str(reverse, "reverse", 558918661u, 0, 7, &be_const_str_sin); -be_define_const_str(sin, "sin", 3761252941u, 0, 3, &be_const_str_super); -be_define_const_str(super, "super", 4152230356u, 0, 5, &be_const_str_try); +be_define_const_str(opt_connect, "..", 2748622605u, 0, 2, &be_const_str_dot_p); +be_define_const_str(dot_p, ".p", 1171526419u, 0, 2, &be_const_str_calldepth); +be_define_const_str(calldepth, "calldepth", 3122364302u, 0, 9, NULL); +be_define_const_str(toupper, "toupper", 3691983576u, 0, 7, &be_const_str_break); +be_define_const_str(break, "break", 3378807160u, 58, 5, NULL); +be_define_const_str(map, "map", 3751997361u, 0, 3, NULL); +be_define_const_str(bytes, "bytes", 1706151940u, 0, 5, &be_const_str_tanh); +be_define_const_str(tanh, "tanh", 153638352u, 0, 4, NULL); +be_define_const_str(real, "real", 3604983901u, 0, 4, NULL); +be_define_const_str(count, "count", 967958004u, 0, 5, &be_const_str_setitem); +be_define_const_str(setitem, "setitem", 1554834596u, 0, 7, &be_const_str_split); +be_define_const_str(split, "split", 2276994531u, 0, 5, &be_const_str_if); +be_define_const_str(if, "if", 959999494u, 50, 2, NULL); +be_define_const_str(format, "format", 3114108242u, 0, 6, &be_const_str_pow); +be_define_const_str(pow, "pow", 1479764693u, 0, 3, &be_const_str_tostring); +be_define_const_str(tostring, "tostring", 2299708645u, 0, 8, NULL); +be_define_const_str(load, "load", 3859241449u, 0, 4, &be_const_str_setrange); +be_define_const_str(setrange, "setrange", 3794019032u, 0, 8, NULL); +be_define_const_str(char, "char", 2823553821u, 0, 4, NULL); +be_define_const_str(acos, "acos", 1006755615u, 0, 4, &be_const_str_deinit); +be_define_const_str(deinit, "deinit", 2345559592u, 0, 6, &be_const_str_dump); +be_define_const_str(dump, "dump", 3663001223u, 0, 4, &be_const_str_sqrt); +be_define_const_str(sqrt, "sqrt", 2112764879u, 0, 4, NULL); +be_define_const_str(fromstring, "fromstring", 610302344u, 0, 10, NULL); +be_define_const_str(opt_eq, "==", 2431966415u, 0, 2, &be_const_str_asin); +be_define_const_str(asin, "asin", 4272848550u, 0, 4, &be_const_str_byte); +be_define_const_str(byte, "byte", 1683620383u, 0, 4, &be_const_str_copy); +be_define_const_str(copy, "copy", 3848464964u, 0, 4, &be_const_str_floor); +be_define_const_str(floor, "floor", 3102149661u, 0, 5, NULL); +be_define_const_str(find, "find", 3186656602u, 0, 4, &be_const_str_var); +be_define_const_str(var, "var", 2317739966u, 64, 3, NULL); +be_define_const_str(opt_add, "+", 772578730u, 0, 1, &be_const_str___lower__); +be_define_const_str(__lower__, "__lower__", 123855590u, 0, 9, &be_const_str_rand); +be_define_const_str(rand, "rand", 2711325910u, 0, 4, &be_const_str_sin); +be_define_const_str(sin, "sin", 3761252941u, 0, 3, NULL); +be_define_const_str(deg, "deg", 3327754271u, 0, 3, &be_const_str_imin); +be_define_const_str(imin, "imin", 2714127864u, 0, 4, &be_const_str_class); +be_define_const_str(class, "class", 2872970239u, 57, 5, &be_const_str_try); be_define_const_str(try, "try", 2887626766u, 68, 3, NULL); -be_define_const_str(range, "range", 4208725202u, 0, 5, &be_const_str_return); +be_define_const_str(allocated, "allocated", 429986098u, 0, 9, &be_const_str_asstring); +be_define_const_str(asstring, "asstring", 1298225088u, 0, 8, &be_const_str_classname); +be_define_const_str(classname, "classname", 1998589948u, 0, 9, NULL); +be_define_const_str(reverse, "reverse", 558918661u, 0, 7, NULL); +be_define_const_str(assert, "assert", 2774883451u, 0, 6, &be_const_str_str); +be_define_const_str(str, "str", 3259748752u, 0, 3, NULL); +be_define_const_str(imax, "imax", 3084515410u, 0, 4, &be_const_str_init); +be_define_const_str(init, "init", 380752755u, 0, 4, &be_const_str_except); +be_define_const_str(except, "except", 950914032u, 69, 6, &be_const_str_return); be_define_const_str(return, "return", 2246981567u, 60, 6, NULL); -be_define_const_str(compile, "compile", 1000265118u, 0, 7, &be_const_str_false); -be_define_const_str(false, "false", 184981848u, 62, 5, NULL); -be_define_const_str(resize, "resize", 3514612129u, 0, 6, NULL); -be_define_const_str(continue, "continue", 2977070660u, 59, 8, NULL); -be_define_const_str(log, "log", 1062293841u, 0, 3, &be_const_str_true); -be_define_const_str(true, "true", 1303515621u, 61, 4, NULL); -be_define_const_str(while, "while", 231090382u, 53, 5, NULL); -be_define_const_str(pow, "pow", 1479764693u, 0, 3, NULL); -be_define_const_str(cos, "cos", 4220379804u, 0, 3, &be_const_str_count); -be_define_const_str(count, "count", 967958004u, 0, 5, &be_const_str_remove); -be_define_const_str(remove, "remove", 3683784189u, 0, 6, NULL); -be_define_const_str(imax, "imax", 3084515410u, 0, 4, &be_const_str_rand); -be_define_const_str(rand, "rand", 2711325910u, 0, 4, NULL); -be_define_const_str(codedump, "codedump", 1786337906u, 0, 8, &be_const_str_deg); -be_define_const_str(deg, "deg", 3327754271u, 0, 3, &be_const_str_keys); -be_define_const_str(keys, "keys", 4182378701u, 0, 4, &be_const_str_setitem); -be_define_const_str(setitem, "setitem", 1554834596u, 0, 7, NULL); -be_define_const_str(def, "def", 3310976652u, 55, 3, &be_const_str_except); -be_define_const_str(except, "except", 950914032u, 69, 6, NULL); -be_define_const_str(classname, "classname", 1998589948u, 0, 9, &be_const_str_isinstance); -be_define_const_str(isinstance, "isinstance", 3669352738u, 0, 10, NULL); +be_define_const_str(opt_neq, "!=", 2428715011u, 0, 2, &be_const_str_hex); +be_define_const_str(hex, "hex", 4273249610u, 0, 3, &be_const_str_resize); +be_define_const_str(resize, "resize", 3514612129u, 0, 6, &be_const_str_as); +be_define_const_str(as, "as", 1579491469u, 67, 2, NULL); +be_define_const_str(__upper__, "__upper__", 3612202883u, 0, 9, &be_const_str_codedump); +be_define_const_str(codedump, "codedump", 1786337906u, 0, 8, &be_const_str_cosh); be_define_const_str(cosh, "cosh", 4099687964u, 0, 4, NULL); +be_define_const_str(abs, "abs", 709362235u, 0, 3, &be_const_str_collect); +be_define_const_str(collect, "collect", 2399039025u, 0, 7, NULL); +be_define_const_str(atan, "atan", 108579519u, 0, 4, &be_const_str_attrdump); +be_define_const_str(attrdump, "attrdump", 1521571304u, 0, 8, &be_const_str_input); +be_define_const_str(input, "input", 4191711099u, 0, 5, NULL); +be_define_const_str(, "", 2166136261u, 0, 0, &be_const_str_compile); +be_define_const_str(compile, "compile", 1000265118u, 0, 7, &be_const_str_iter); +be_define_const_str(iter, "iter", 3124256359u, 0, 4, &be_const_str_lower); +be_define_const_str(lower, "lower", 3038577850u, 0, 5, &be_const_str_number); +be_define_const_str(number, "number", 467038368u, 0, 6, &be_const_str_print); +be_define_const_str(print, "print", 372738696u, 0, 5, NULL); +be_define_const_str(exp, "exp", 1923516200u, 0, 3, &be_const_str_pi); +be_define_const_str(pi, "pi", 1213090802u, 0, 2, NULL); +be_define_const_str(__iterator__, "__iterator__", 3884039703u, 0, 12, &be_const_str_log); +be_define_const_str(log, "log", 1062293841u, 0, 3, &be_const_str_log10); +be_define_const_str(log10, "log10", 2346846000u, 0, 5, NULL); +be_define_const_str(ceil, "ceil", 1659167240u, 0, 4, &be_const_str_get); +be_define_const_str(get, "get", 1410115415u, 0, 3, &be_const_str_tolower); +be_define_const_str(tolower, "tolower", 1042520049u, 0, 7, &be_const_str_while); +be_define_const_str(while, "while", 231090382u, 53, 5, NULL); +be_define_const_str(import, "import", 288002260u, 66, 6, NULL); +be_define_const_str(size, "size", 597743964u, 0, 4, NULL); +be_define_const_str(list, "list", 217798785u, 0, 4, &be_const_str_rad); +be_define_const_str(rad, "rad", 1358899048u, 0, 3, &be_const_str_tan); +be_define_const_str(tan, "tan", 2633446552u, 0, 3, &be_const_str_type); +be_define_const_str(type, "type", 1361572173u, 0, 4, NULL); +be_define_const_str(insert, "insert", 3332609576u, 0, 6, &be_const_str_module); +be_define_const_str(module, "module", 3617558685u, 0, 6, &be_const_str_range); +be_define_const_str(range, "range", 4208725202u, 0, 5, &be_const_str_super); +be_define_const_str(super, "super", 4152230356u, 0, 5, NULL); +be_define_const_str(issubclass, "issubclass", 4078395519u, 0, 10, &be_const_str_def); +be_define_const_str(def, "def", 3310976652u, 55, 3, NULL); +be_define_const_str(classof, "classof", 1796577762u, 0, 7, &be_const_str_sinh); +be_define_const_str(sinh, "sinh", 282220607u, 0, 4, &be_const_str_srand); +be_define_const_str(srand, "srand", 465518633u, 0, 5, NULL); +be_define_const_str(end, "end", 1787721130u, 56, 3, NULL); +be_define_const_str(clear, "clear", 1550717474u, 0, 5, &be_const_str_top); +be_define_const_str(top, "top", 2802900028u, 0, 3, &be_const_str_nil); +be_define_const_str(nil, "nil", 228849900u, 63, 3, NULL); +be_define_const_str(open, "open", 3546203337u, 0, 4, &be_const_str_do); +be_define_const_str(do, "do", 1646057492u, 65, 2, NULL); +be_define_const_str(add, "add", 993596020u, 0, 3, &be_const_str_isinstance); +be_define_const_str(isinstance, "isinstance", 3669352738u, 0, 10, &be_const_str_pop); +be_define_const_str(pop, "pop", 1362321360u, 0, 3, NULL); +be_define_const_str(int, "int", 2515107422u, 0, 3, &be_const_str_keys); +be_define_const_str(keys, "keys", 4182378701u, 0, 4, &be_const_str_elif); +be_define_const_str(elif, "elif", 3232090307u, 51, 4, NULL); +be_define_const_str(item, "item", 2671260646u, 0, 4, &be_const_str_push); +be_define_const_str(push, "push", 2272264157u, 0, 4, NULL); +be_define_const_str(concat, "concat", 4124019837u, 0, 6, &be_const_str_traceback); +be_define_const_str(traceback, "traceback", 3385188109u, 0, 9, &be_const_str_upper); +be_define_const_str(upper, "upper", 176974407u, 0, 5, &be_const_str_true); +be_define_const_str(true, "true", 1303515621u, 61, 4, NULL); +be_define_const_str(continue, "continue", 2977070660u, 59, 8, NULL); +be_define_const_str(else, "else", 3183434736u, 52, 4, NULL); +be_define_const_str(cos, "cos", 4220379804u, 0, 3, &be_const_str_for); +be_define_const_str(for, "for", 2901640080u, 54, 3, NULL); static const bstring* const m_string_table[] = { + (const bstring *)&be_const_str_remove, + (const bstring *)&be_const_str_opt_connect, + (const bstring *)&be_const_str_toupper, + NULL, + (const bstring *)&be_const_str_map, + (const bstring *)&be_const_str_bytes, + (const bstring *)&be_const_str_real, + (const bstring *)&be_const_str_count, + (const bstring *)&be_const_str_format, + (const bstring *)&be_const_str_load, + (const bstring *)&be_const_str_char, (const bstring *)&be_const_str_acos, - NULL, - (const bstring *)&be_const_str_int, - NULL, - (const bstring *)&be_const_str_iter, + (const bstring *)&be_const_str_fromstring, (const bstring *)&be_const_str_opt_eq, - (const bstring *)&be_const_str_floor, (const bstring *)&be_const_str_find, - (const bstring *)&be_const_str___upper__, - (const bstring *)&be_const_str_atan, (const bstring *)&be_const_str_opt_add, NULL, - (const bstring *)&be_const_str_classof, - (const bstring *)&be_const_str_byte, - (const bstring *)&be_const_str_clear, - (const bstring *)&be_const_str_opt_connect, - (const bstring *)&be_const_str_, - (const bstring *)&be_const_str_calldepth, - (const bstring *)&be_const_str___iterator__, - (const bstring *)&be_const_str_dot_p, - (const bstring *)&be_const_str___lower__, - (const bstring *)&be_const_str_char, - (const bstring *)&be_const_str_deinit, - (const bstring *)&be_const_str_srand, - (const bstring *)&be_const_str_imin, - (const bstring *)&be_const_str_tostring, - (const bstring *)&be_const_str_insert, - (const bstring *)&be_const_str_open, + (const bstring *)&be_const_str_deg, (const bstring *)&be_const_str_allocated, - (const bstring *)&be_const_str_attrdump, - (const bstring *)&be_const_str_for, - (const bstring *)&be_const_str_opt_neq, - (const bstring *)&be_const_str_range, - (const bstring *)&be_const_str_compile, - (const bstring *)&be_const_str_resize, - (const bstring *)&be_const_str_continue, - (const bstring *)&be_const_str_log, - (const bstring *)&be_const_str_while, - (const bstring *)&be_const_str_pow, - (const bstring *)&be_const_str_cos, + (const bstring *)&be_const_str_reverse, + (const bstring *)&be_const_str_assert, (const bstring *)&be_const_str_imax, - (const bstring *)&be_const_str_codedump, - (const bstring *)&be_const_str_def, - (const bstring *)&be_const_str_classname, - (const bstring *)&be_const_str_cosh + (const bstring *)&be_const_str_opt_neq, + (const bstring *)&be_const_str___upper__, + (const bstring *)&be_const_str_abs, + (const bstring *)&be_const_str_atan, + (const bstring *)&be_const_str_, + NULL, + (const bstring *)&be_const_str_exp, + (const bstring *)&be_const_str___iterator__, + (const bstring *)&be_const_str_ceil, + (const bstring *)&be_const_str_import, + (const bstring *)&be_const_str_size, + (const bstring *)&be_const_str_list, + (const bstring *)&be_const_str_insert, + (const bstring *)&be_const_str_issubclass, + (const bstring *)&be_const_str_classof, + (const bstring *)&be_const_str_end, + (const bstring *)&be_const_str_clear, + (const bstring *)&be_const_str_open, + (const bstring *)&be_const_str_add, + (const bstring *)&be_const_str_int, + (const bstring *)&be_const_str_item, + (const bstring *)&be_const_str_concat, + (const bstring *)&be_const_str_continue, + (const bstring *)&be_const_str_else, + (const bstring *)&be_const_str_cos }; static const struct bconststrtab m_const_string_table = { - .size = 45, - .count = 90, + .size = 47, + .count = 95, .table = m_string_table }; diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_be_class_bytes.h b/lib/libesp32/Berry-0.1.10/generate/be_fixed_be_class_bytes.h new file mode 100644 index 000000000..44f8eff3e --- /dev/null +++ b/lib/libesp32/Berry-0.1.10/generate/be_fixed_be_class_bytes.h @@ -0,0 +1,33 @@ +#include "be_constobj.h" + +static be_define_const_map_slots(be_class_bytes_map) { + { be_const_key(copy, -1), be_const_func(m_copy) }, + { be_const_key(setitem, -1), be_const_func(m_setitem) }, + { be_const_key(tostring, -1), be_const_func(m_tostring) }, + { be_const_key(item, -1), be_const_func(m_item) }, + { be_const_key(init, 8), be_const_func(m_init) }, + { be_const_key(size, 6), be_const_func(m_size) }, + { be_const_key(opt_connect, 7), be_const_func(m_connect) }, + { be_const_key(opt_add, -1), be_const_func(m_merge) }, + { be_const_key(fromstring, -1), be_const_func(m_fromstring) }, + { be_const_key(opt_eq, 14), be_const_func(m_equal) }, + { be_const_key(get, 1), be_const_func(m_get) }, + { be_const_key(asstring, 5), be_const_func(m_asstring) }, + { be_const_key(add, -1), be_const_func(m_add) }, + { be_const_key(dot_p, -1), be_const_int(0) }, + { be_const_key(clear, -1), be_const_func(m_clear) }, + { be_const_key(opt_neq, 4), be_const_func(m_nequal) }, + { be_const_key(resize, 9), be_const_func(m_resize) }, +}; + +static be_define_const_map( + be_class_bytes_map, + 17 +); + +BE_EXPORT_VARIABLE be_define_const_class( + be_class_bytes, + 1, + NULL, + bytes +); diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_be_class_list.h b/lib/libesp32/Berry-0.1.10/generate/be_fixed_be_class_list.h index 64eaac2ac..98a52b494 100644 --- a/lib/libesp32/Berry-0.1.10/generate/be_fixed_be_class_list.h +++ b/lib/libesp32/Berry-0.1.10/generate/be_fixed_be_class_list.h @@ -1,31 +1,32 @@ #include "be_constobj.h" static be_define_const_map_slots(be_class_list_map) { - { be_const_key(pop, -1), be_const_func(m_pop) }, - { be_const_key(reverse, -1), be_const_func(m_reverse) }, + { be_const_key(concat, -1), be_const_func(m_concat) }, { be_const_key(push, -1), be_const_func(m_push) }, - { be_const_key(init, -1), be_const_func(m_init) }, - { be_const_key(copy, 8), be_const_func(m_copy) }, - { be_const_key(opt_connect, 13), be_const_func(m_connect) }, - { be_const_key(item, -1), be_const_func(m_item) }, - { be_const_key(remove, -1), be_const_func(m_remove) }, - { be_const_key(size, -1), be_const_func(m_size) }, - { be_const_key(resize, 7), be_const_func(m_resize) }, - { be_const_key(opt_add, -1), be_const_func(m_merge) }, - { be_const_key(opt_neq, -1), be_const_func(m_nequal) }, - { be_const_key(setitem, -1), be_const_func(m_setitem) }, - { be_const_key(tostring, -1), be_const_func(m_tostring) }, + { be_const_key(insert, 1), be_const_func(m_insert) }, + { be_const_key(find, -1), be_const_func(m_find) }, + { be_const_key(remove, 9), be_const_func(m_remove) }, { be_const_key(clear, -1), be_const_func(m_clear) }, - { be_const_key(opt_eq, 3), be_const_func(m_equal) }, - { be_const_key(insert, 12), be_const_func(m_insert) }, - { be_const_key(concat, 2), be_const_func(m_concat) }, - { be_const_key(dot_p, -1), be_const_int(0) }, - { be_const_key(iter, 18), be_const_func(m_iter) }, + { be_const_key(size, -1), be_const_func(m_size) }, + { be_const_key(resize, 13), be_const_func(m_resize) }, + { be_const_key(copy, -1), be_const_func(m_copy) }, + { be_const_key(pop, -1), be_const_func(m_pop) }, + { be_const_key(tostring, 3), be_const_func(m_tostring) }, + { be_const_key(opt_eq, -1), be_const_func(m_equal) }, + { be_const_key(init, -1), be_const_func(m_init) }, + { be_const_key(dot_p, 17), be_const_int(0) }, + { be_const_key(setitem, -1), be_const_func(m_setitem) }, + { be_const_key(opt_connect, 4), be_const_func(m_connect) }, + { be_const_key(opt_neq, -1), be_const_func(m_nequal) }, + { be_const_key(opt_add, 18), be_const_func(m_merge) }, + { be_const_key(iter, 20), be_const_func(m_iter) }, + { be_const_key(item, -1), be_const_func(m_item) }, + { be_const_key(reverse, -1), be_const_func(m_reverse) }, }; static be_define_const_map( be_class_list_map, - 20 + 21 ); BE_EXPORT_VARIABLE be_define_const_class( diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_m_builtin.h b/lib/libesp32/Berry-0.1.10/generate/be_fixed_m_builtin.h index 4b6d13344..423be6100 100644 --- a/lib/libesp32/Berry-0.1.10/generate/be_fixed_m_builtin.h +++ b/lib/libesp32/Berry-0.1.10/generate/be_fixed_m_builtin.h @@ -1,37 +1,39 @@ #include "be_constobj.h" static be_define_const_map_slots(m_builtin_map) { - { be_const_key(map, 11), be_const_int(10) }, - { be_const_key(str, 14), be_const_int(18) }, - { be_const_key(int, -1), be_const_int(6) }, - { be_const_key(type, -1), be_const_int(20) }, - { be_const_key(assert, -1), be_const_int(1) }, - { be_const_key(issubclass, -1), be_const_int(8) }, - { be_const_key(number, 7), be_const_int(12) }, - { be_const_key(compile, 8), be_const_int(4) }, - { be_const_key(module, 18), be_const_int(11) }, - { be_const_key(input, 5), be_const_int(5) }, - { be_const_key(super, -1), be_const_int(19) }, - { be_const_key(classof, -1), be_const_int(3) }, - { be_const_key(open, 13), be_const_int(13) }, + { be_const_key(print, 19), be_const_int(15) }, + { be_const_key(isinstance, -1), be_const_int(8) }, + { be_const_key(classname, -1), be_const_int(3) }, + { be_const_key(module, -1), be_const_int(12) }, + { be_const_key(size, -1), be_const_int(18) }, + { be_const_key(type, 9), be_const_int(21) }, + { be_const_key(compile, -1), be_const_int(5) }, + { be_const_key(open, -1), be_const_int(14) }, + { be_const_key(real, -1), be_const_int(17) }, { be_const_key(__iterator__, -1), be_const_int(0) }, - { be_const_key(real, 10), be_const_int(16) }, - { be_const_key(list, 20), be_const_int(9) }, - { be_const_key(isinstance, -1), be_const_int(7) }, - { be_const_key(range, -1), be_const_int(15) }, - { be_const_key(size, -1), be_const_int(17) }, - { be_const_key(classname, -1), be_const_int(2) }, - { be_const_key(print, -1), be_const_int(14) }, + { be_const_key(super, -1), be_const_int(20) }, + { be_const_key(issubclass, -1), be_const_int(9) }, + { be_const_key(classof, -1), be_const_int(4) }, + { be_const_key(map, 8), be_const_int(11) }, + { be_const_key(int, 2), be_const_int(7) }, + { be_const_key(input, 3), be_const_int(6) }, + { be_const_key(number, -1), be_const_int(13) }, + { be_const_key(list, 7), be_const_int(10) }, + { be_const_key(str, 1), be_const_int(19) }, + { be_const_key(range, -1), be_const_int(16) }, + { be_const_key(bytes, -1), be_const_int(2) }, + { be_const_key(assert, -1), be_const_int(1) }, }; static be_define_const_map( m_builtin_map, - 21 + 22 ); static const bvalue __vlist_array[] = { be_const_func(l_iterator), be_const_func(l_assert), + be_const_class(be_class_bytes), be_const_func(l_classname), be_const_func(l_classof), be_const_func(l_compile), @@ -56,5 +58,5 @@ static const bvalue __vlist_array[] = { static be_define_const_vector( m_builtin_vector, __vlist_array, - 21 + 22 ); diff --git a/lib/libesp32/Berry-0.1.10/generate/be_fixed_os_path.h b/lib/libesp32/Berry-0.1.10/generate/be_fixed_os_path.h deleted file mode 100644 index fc4f5edbc..000000000 --- a/lib/libesp32/Berry-0.1.10/generate/be_fixed_os_path.h +++ /dev/null @@ -1,20 +0,0 @@ -#include "be_constobj.h" - -static be_define_const_map_slots(m_libpath_map) { - { be_const_key(isdir, -1), be_const_func(m_path_isdir) }, - { be_const_key(join, 2), be_const_func(m_path_join) }, - { be_const_key(exists, -1), be_const_func(m_path_exists) }, - { be_const_key(split, -1), be_const_func(m_path_split) }, - { be_const_key(splitext, -1), be_const_func(m_path_splitext) }, - { be_const_key(isfile, -1), be_const_func(m_path_isfile) }, -}; - -static be_define_const_map( - m_libpath_map, - 6 -); - -static be_define_const_module( - m_libpath, - "path" -); diff --git a/lib/libesp32/Berry-0.1.10/src/be_baselib.c b/lib/libesp32/Berry-0.1.10/src/be_baselib.c index f0d7e0147..d1bfd83b1 100644 --- a/lib/libesp32/Berry-0.1.10/src/be_baselib.c +++ b/lib/libesp32/Berry-0.1.10/src/be_baselib.c @@ -313,6 +313,7 @@ void be_load_baselib(bvm *vm) extern const bclass be_class_list; extern const bclass be_class_map; extern const bclass be_class_range; +extern const bclass be_class_bytes; extern int be_nfunc_open(bvm *vm); /* @const_object_info_begin vartab m_builtin (scope: local) { @@ -337,6 +338,7 @@ vartab m_builtin (scope: local) { list, class(be_class_list) map, class(be_class_map) range, class(be_class_range) + bytes, class(be_class_bytes) } @const_object_info_end */ #include "../generate/be_fixed_m_builtin.h" diff --git a/lib/libesp32/Berry-0.1.10/src/be_byteslib.c b/lib/libesp32/Berry-0.1.10/src/be_byteslib.c new file mode 100644 index 000000000..7217c7d75 --- /dev/null +++ b/lib/libesp32/Berry-0.1.10/src/be_byteslib.c @@ -0,0 +1,668 @@ +/******************************************************************** +** Copyright (c) 2018-2020 Guan Wenliang - Stephan Hadinger +** This file is part of the Berry default interpreter. +** skiars@qq.com, https://github.com/Skiars/berry +** See Copyright Notice in the LICENSE file or at +** https://github.com/Skiars/berry/blob/master/LICENSE +********************************************************************/ +#include "be_object.h" +#include "be_string.h" +#include "be_strlib.h" +#include "be_list.h" +#include "be_func.h" +#include "be_exec.h" +#include "be_vm.h" +#include "be_mem.h" +#include +#include + +#define BYTES_DEFAULT_SIZE 28 // default pre-reserved size for buffer (keep 4 bytes for len/size) +#define BYTES_MAX_SIZE (32*1024) // max 32Kb +#define BYTES_OVERHEAD 4 // bytes overhead to be added when allocating (used to store len and size) +#define BYTES_HEADROOM 8 // keep a natural headroom of 8 bytes when resizing + +typedef struct buf_impl { + uint16_t size; // size in bytes of the buffer + uint16_t len; // current size of the data in buffer. Invariant: len <= size + uint8_t buf[]; // the actual data +} buf_impl; + +/******************************************************************** +** Buffer low-level implementation +** +** Extracted from Tasmota SBuffer lib +********************************************************************/ +static inline uint8_t* buf_get_buf(buf_impl* buf) { + return &buf->buf[0]; +} + +// shrink or increase. If increase, fill with zeores. Cannot go beyond `size` +static void buf_set_len(buf_impl* buf, const size_t len) { + uint16_t old_len = buf->len; + buf->len = (len <= buf->size) ? len : buf->size; + if (old_len < buf->len) { + memset((void*) &buf->buf[old_len], 0, buf->len - old_len); + } +} + + +static void buf_set1(buf_impl* buf, const size_t offset, const uint8_t data) { + if (offset < buf->len) { + buf->buf[offset] = data; + } +} +static size_t buf_add1(buf_impl* buf, const uint8_t data) { // append 8 bits value + if (buf->len < buf->size) { // do we have room for 1 byte + buf->buf[buf->len++] = data; + } + return buf->len; +} +static size_t buf_add2_le(buf_impl* buf, const uint16_t data) { // append 16 bits value + if (buf->len < buf->size - 1) { // do we have room for 2 bytes + buf->buf[buf->len++] = data; + buf->buf[buf->len++] = data >> 8; + } + return buf->len; +} +static size_t buf_add2_be(buf_impl* buf, const uint16_t data) { // append 16 bits value + if (buf->len < buf->size - 1) { // do we have room for 2 bytes + buf->buf[buf->len++] = data >> 8; + buf->buf[buf->len++] = data; + } + return buf->len; +} +static size_t buf_add4_le(buf_impl* buf, const uint32_t data) { // append 32 bits value + if (buf->len < buf->size - 3) { // do we have room for 4 bytes + buf->buf[buf->len++] = data; + buf->buf[buf->len++] = data >> 8; + buf->buf[buf->len++] = data >> 16; + buf->buf[buf->len++] = data >> 24; + } + return buf->len; +} +size_t buf_add4_be(buf_impl* buf, const uint32_t data) { // append 32 bits value + if (buf->len < buf->size - 3) { // do we have room for 4 bytes + buf->buf[buf->len++] = data >> 24; + buf->buf[buf->len++] = data >> 16; + buf->buf[buf->len++] = data >> 8; + buf->buf[buf->len++] = data; + } + return buf->len; +} + +static size_t buf_add_buf(buf_impl* buf, buf_impl* buf2) { + if (buf->len + buf2->len <= buf->size) { + for (uint32_t i = 0; i < buf2->len; i++) { + buf->buf[buf->len++] = buf2->buf[i]; + } + } + return buf->len; +} + +static uint8_t buf_get1(buf_impl* buf, int offset) { + if ((offset >= 0) && (offset < buf->len)) { + return buf->buf[offset]; + } + return 0; +} +static uint16_t buf_get2_le(buf_impl* buf, int offset) { + if ((offset >= 0) && (offset < buf->len - 1)) { + return buf->buf[offset] | (buf->buf[offset+1] << 8); + } + return 0; +} +static uint16_t buf_get2_be(buf_impl* buf, int offset) { + if (offset < buf->len - 1) { + return buf->buf[offset+1] | (buf->buf[offset] << 8); + } + return 0; +} +static uint32_t buf_get4_le(buf_impl* buf, int offset) { + if ((offset >= 0) && (offset < buf->len - 3)) { + return buf->buf[offset] | (buf->buf[offset+1] << 8) | + (buf->buf[offset+2] << 16) | (buf->buf[offset+3] << 24); + } + return 0; +} +static uint32_t buf_get4_be(buf_impl* buf, int offset) { + if (offset < buf->len - 3) { + return buf->buf[offset+3] | (buf->buf[offset+2] << 8) | + (buf->buf[offset+1] << 16) | (buf->buf[offset] << 24); + } + return 0; +} + +// nullptr accepted +static bbool buf_equals(buf_impl* buf1, buf_impl* buf2) { + if (buf1 == buf2) { return btrue; } + if (!buf1 || !buf2) { return bfalse; } // at least one buf is not empty + // we know that both buf1 and buf2 are non-null + if (buf1->len != buf2->len) { return bfalse; } + size_t len = buf1->len; + for (uint32_t i=0; i= 'A' && chr <= 'F') { rVal = chr + 10 - 'A'; } + else if (chr >= 'a' && chr <= 'f') { rVal = chr + 10 - 'a'; } + return rVal; +} +// does not check if there is enough room before hand, truncated if buffer too small +static void buf_add_hex(buf_impl* buf, const char *hex, size_t len) { + uint8_t val; + for (; len > 1; len -= 2) { + val = asc2byte(*hex++) << 4; + val |= asc2byte(*hex++); + buf_add1(buf, val); + } +} + +/******************************************************************** +** Wrapping into lib +********************************************************************/ +// typedef int (*bntvfunc)(bvm*); /* native function pointer */ +int free_bytes_buf(bvm* vm) { + int argc = be_top(vm); + if (argc > 0) { + buf_impl * buf = (buf_impl*) be_tocomptr(vm, 1); + if (buf != NULL) { + be_os_free(buf); + } + } + be_return_nil(vm); +} + +buf_impl * bytes_alloc(int32_t size) +{ + if (size < 4) { size = 4; } + if (size > BYTES_MAX_SIZE) { size = BYTES_MAX_SIZE; } + buf_impl * next = (buf_impl*) be_os_malloc(size + BYTES_OVERHEAD); + next->size = size; + next->len = 0; + return next; +} + +/* allocate a new `bytes` object with pre-allocated size */ +static void bytes_new_object(bvm *vm, size_t size) +{ + be_getglobal(vm, "bytes"); /* eventually change with be_getbuiltin */ + be_call(vm, 0); /* stack has only instance */ + be_getmember(vm, -1, "init"); + be_pushvalue(vm, -2); + be_pushint(vm, size); /* stack: instance, init func, instance, size */ + be_call(vm, 2); /* stack: instance, ret, instance, size */ + be_pop(vm, 3); /* remove ret, instance, size */ +} + +static int m_init(bvm *vm) +{ + int argc = be_top(vm); + int size = BYTES_DEFAULT_SIZE; + const char * hex_in = NULL; + if (argc > 1 && be_isint(vm, 2)) { + int new_size = be_toint(vm, 2) + BYTES_HEADROOM; + if (new_size > size) { + size = new_size; + } + } else if (argc > 1 && be_isstring(vm, 2)) { + hex_in = be_tostring(vm, 2); + if (hex_in) { + size = strlen(hex_in) / 2 + BYTES_HEADROOM; // allocate headroom + } + } + buf_impl * buf = bytes_alloc(size); + if (!buf) { + be_throw(vm, BE_MALLOC_FAIL); + } + + if (hex_in) { + buf_add_hex(buf, hex_in, strlen(hex_in)); + } + be_newcomobj(vm, buf, &free_bytes_buf); + be_setmember(vm, 1, ".p"); + be_return_nil(vm); +} + +/* grow or shrink to the exact value */ +/* stack item 1 must contain the instance */ +static buf_impl * _bytes_resize(bvm *vm, buf_impl * buf, size_t new_size) { + buf_impl * new_buf = bytes_alloc(new_size); + if (!new_buf) { + be_throw(vm, BE_MALLOC_FAIL); + } + memmove(buf_get_buf(new_buf), buf_get_buf(buf), buf->len); + new_buf->len = buf->len; + /* replace the .p attribute */ + be_newcomobj(vm, new_buf, &free_bytes_buf); + be_setmember(vm, 1, ".p"); + be_pop(vm, 1); /* remove comobj from stack */ + /* the old buffer will be garbage collected later */ + return new_buf; +} + +/* grow if needed but don't shrink */ +/* if grow, then add some headroom */ +/* stack item 1 must contain the instance */ +static buf_impl * bytes_resize(bvm *vm, buf_impl * buf, size_t new_size) { + if (buf->size >= new_size) { return buf; } /* no resize needed */ + return _bytes_resize(vm, buf, new_size + BYTES_HEADROOM); +} + +static buf_impl * bytes_check_data(bvm *vm, size_t add_size) { + be_getmember(vm, 1, ".p"); + buf_impl * buf = be_tocomptr(vm, -1); + be_pop(vm, 1); /* remove member from stack */ + /* check if the `size` is big enough */ + if (buf->len + add_size > buf->size) { + /* it does not fit so we need to realocate the buffer */ + buf = bytes_resize(vm, buf, buf->len + add_size); + } + return buf; +} + +static size_t tohex(char * out, size_t outsz, const uint8_t * in, size_t insz) { + static const char * hex = "0123456789ABCDEF"; + const uint8_t * pin = in; + char * pout = out; + for (; pin < in + insz; pout += 2, pin++) { + pout[0] = hex[((*pin)>>4) & 0xF]; + pout[1] = hex[ (*pin) & 0xF]; + if (pout + 3 > out + outsz) { break; } /* check overflow */ + } + pout[0] = 0; /* terminating Nul char */ + return pout - out; +} + +static int m_tostring(bvm *vm) +{ + buf_impl * buf = bytes_check_data(vm, 0); + size_t len = buf->len; + size_t hex_len = len * 2 + 5 + 2 + 2 + 1; /* reserve size for `bytes("")\0` - 9 chars */ + + char * hex_out = be_pushbuffer(vm, hex_len); + size_t l = strlcpy(hex_out, "bytes('", hex_len); + l += tohex(&hex_out[l], hex_len - l, buf_get_buf(buf), buf->len); + l += strlcpy(&hex_out[l], "')", hex_len - l); + + be_pushnstring(vm, hex_out, l); /* make escape string from buffer */ + be_remove(vm, -2); /* remove buffer */ + be_return(vm); +} + +/* + * Copy the buffer into a string without any changes + */ +static int m_asstring(bvm *vm) +{ + buf_impl * buf = bytes_check_data(vm, 0); + be_pushnstring(vm, (const char*) buf_get_buf(buf), buf->len); + be_return(vm); +} +static int m_fromstring(bvm *vm) +{ + int argc = be_top(vm); + if (argc >= 2 && be_isstring(vm, 2)) { + const char *s = be_tostring(vm, 2); + size_t len = strlen(s); + buf_impl * buf = bytes_check_data(vm, 0); + buf = bytes_resize(vm, buf, len); /* resize if needed */ + if (len > buf->size) { len = buf->size; } /* avoid overflow */ + memmove(buf_get_buf(buf), s, len); + buf->len = len; + be_pop(vm, 1); /* remove arg to leave instance */ + be_return(vm); + } + be_raise(vm, "type_error", "operand must be a string"); + be_return_nil(vm); +} + +/* + * Add an int made of 1, 2 or 4 bytes, in little or big endian + * `add(value:int[, size:int = 1]) -> instance` + * + * size: may be 1, 2, 4 (little endian), or -1, -2, -4 (big endian) + * obvisouly -1 is idntical to 1 + * size==0 does nothing + */ +static int m_add(bvm *vm) +{ + int argc = be_top(vm); + buf_impl * buf = bytes_check_data(vm, 4); /* we reserve 4 bytes anyways */ + if (argc >= 2 && be_isint(vm, 2)) { + int32_t v = be_toint(vm, 2); + int vsize = 1; + if (argc >= 3 && be_isint(vm, 3)) { + vsize = be_toint(vm, 3); + } + switch (vsize) { + case 0: break; + case -1: /* fallback below */ + case 1: buf_add1(buf, v); break; + case 2: buf_add2_le(buf, v); break; + case 4: buf_add4_le(buf, v); break; + case -2: buf_add2_be(buf, v); break; + case -4: buf_add4_be(buf, v); break; + default: be_raise(vm, "type_error", "size must be -4, -2, -1, 0, 1, 2 or 4."); + } + be_pop(vm, argc - 1); + be_return(vm); + } + be_return_nil(vm); +} + +/* + * Get an int made of 1, 2 or 4 bytes, in little or big endian + * `get(index:int[, size:int = 1]) -> instance` + * + * size: may be 1, 2, 4 (little endian), or -1, -2, -4 (big endian) + * obvisouly -1 is idntical to 1 + * 0 returns nil + */ +static int m_get(bvm *vm) +{ + int argc = be_top(vm); + buf_impl * buf = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */ + if (argc >=2 && be_isint(vm, 2)) { + int32_t idx = be_toint(vm, 2); + int vsize = 1; + if (argc >= 3 && be_isint(vm, 3)) { + vsize = be_toint(vm, 3); + } + int ret = 0; + switch (vsize) { + case 0: break; + case -1: /* fallback below */ + case 1: ret = buf_get1(buf, idx); break; + case 2: ret = buf_get2_le(buf, idx); break; + case 4: ret = buf_get4_le(buf, idx); break; + case -2: ret = buf_get2_be(buf, idx); break; + case -4: ret = buf_get4_be(buf, idx); break; + default: be_raise(vm, "type_error", "size must be -4, -2, -1, 0, 1, 2 or 4."); + } + be_pop(vm, argc - 1); + if (vsize != 0) { + be_pushint(vm, ret); + } else { + be_pushnil(vm); + } + be_return(vm); + } + be_return_nil(vm); +} + + +static int m_setitem(bvm *vm) +{ + int argc = be_top(vm); + buf_impl * buf = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */ + if (argc >=3 && be_isint(vm, 2) && be_isint(vm, 3)) { + int index = be_toint(vm, 2); + int val = be_toint(vm, 3); + if (index >= 0 && index < buf->len) { + buf_set1(buf, index, val); + be_return_nil(vm); + } + } + be_raise(vm, "index_error", "bytes index out of range or value non int"); + be_return_nil(vm); +} + +static int m_item(bvm *vm) +{ + int argc = be_top(vm); + buf_impl * buf = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */ + if (argc >=2 && be_isint(vm, 2)) { + int index = be_toint(vm,2); + if (index >= 0 && index < buf->len) { + be_pushint(vm, buf_get1(buf, index)); + be_return(vm); + } + } + if (argc >= 2 && be_isinstance(vm, 2)) { + const char *cname = be_classname(vm, 2); + if (!strcmp(cname, "range")) { + bint lower, upper; + bint size = buf->len; + /* get index range */ + be_getmember(vm, 2, "__lower__"); + lower = be_toint(vm, -1); + be_pop(vm, 1); + be_getmember(vm, 2, "__upper__"); + upper = be_toint(vm, -1); + be_pop(vm, 1); + /* protection scope */ + upper = upper < size ? upper : size - 1; + lower = lower < 0 ? 0 : lower; + /* construction result list instance */ + bytes_new_object(vm, upper > lower ? upper-lower : 0); + be_getmember(vm, -1, ".p"); + buf_impl * buf2 = be_tocomptr(vm, -1); + be_pop(vm, 1); /* remove .p and leave bytes instance */ + for (; lower <= upper; ++lower) { + buf_add1(buf2, buf->buf[lower]); + } + be_return(vm); + } + } + be_raise(vm, "index_error", "bytes index out of range"); + be_return_nil(vm); +} + +static int m_size(bvm *vm) +{ + buf_impl * buf = bytes_check_data(vm, 0); + be_pushint(vm, buf->len); + be_return(vm); +} + +static int m_resize(bvm *vm) +{ + int argc = be_top(vm); + be_getmember(vm, 1, ".p"); + buf_impl * buf = be_tocomptr(vm, -1); + be_pop(vm, 1); + + if (argc <= 1 || !be_isint(vm, 2)) { + be_raise(vm, "type_error", "size must be of type 'int'"); + } + int new_len = be_toint(vm, 2); + if (new_len < 0) { + new_len = 0; + } + + buf = bytes_resize(vm, buf, new_len); + buf_set_len(buf, new_len); + be_pop(vm, 1); + be_return(vm); +} + +static int m_clear(bvm *vm) +{ + buf_impl * buf = bytes_check_data(vm, 0); + buf->len = 0; + be_return_nil(vm); +} + +static int m_merge(bvm *vm) +{ + int argc = be_top(vm); + buf_impl * buf1 = bytes_check_data(vm, 0); /* no resize yet */ + if (argc >= 2 && be_isinstance(vm, 2)) { + be_getglobal(vm, "bytes"); /* get the bytes class */ /* TODO eventually replace with be_getbuiltin */ + if (be_isderived(vm, 2)) { + be_getmember(vm, 2, ".p"); + buf_impl * buf2 = be_tocomptr(vm, -1); + be_pop(vm, 4); /* remove class, member, and 2 operands */ + + /* allocate new object */ + bytes_new_object(vm, buf1->len + buf2->len); + be_getmember(vm, -1, ".p"); + /* .p is on top of stack, then instance */ + buf_impl * buf3 = be_tocomptr(vm, -1); + be_pop(vm, 1); + buf_add_buf(buf3, buf1); + buf_add_buf(buf3, buf2); + + be_return(vm); /* return self */ + } + } + be_raise(vm, "type_error", "operand must be bytes"); + be_return_nil(vm); /* return self */ +} + +static int m_copy(bvm *vm) +{ + buf_impl * buf1 = bytes_check_data(vm, 0); /* no resize */ + bytes_new_object(vm, buf1->len); + be_getmember(vm, -1, ".p"); + buf_impl * buf2 = be_tocomptr(vm, -1); + be_pop(vm, 1); + buf_add_buf(buf2, buf1); + be_return(vm); /* return self */ +} + +/* accept bytes or int as operand */ +static int m_connect(bvm *vm) +{ + int argc = be_top(vm); + buf_impl * buf1 = bytes_check_data(vm, 0); /* don't resize yet */ + if (argc >= 2 && (be_isinstance(vm, 2) || be_isint(vm, 2))) { + if (be_isint(vm, 2)) { + buf1 = bytes_resize(vm, buf1, buf1->len + 1); /* resize */ + buf_add1(buf1, be_toint(vm, 2)); + be_pop(vm, 1); /* remove operand */ + be_return(vm); /* return self */ + } else { + be_getglobal(vm, "bytes"); /* get the bytes class */ /* TODO eventually replace with be_getbuiltin */ + if (be_isderived(vm, 2)) { + be_getmember(vm, 2, ".p"); + buf_impl * buf2 = be_tocomptr(vm, -1); + buf1 = bytes_resize(vm, buf1, buf1->len + buf2->len); /* resize buf1 for total size */ + buf_add_buf(buf1, buf2); + be_pop(vm, 3); /* remove class, member, and last operand */ + be_return(vm); /* return self */ + } + } + } + be_raise(vm, "type_error", "operand must be bytes or int"); + be_return_nil(vm); /* return self */ +} + +static int bytes_equal(bvm *vm, bbool iseq) +{ + be_getmember(vm, 1, ".p"); + buf_impl * buf1 = be_tocomptr(vm, -1); + be_pop(vm, 1); + + be_getmember(vm, 2, ".p"); + buf_impl * buf2 = be_tocomptr(vm, -1); + be_pop(vm, 1); + + bbool ret; + if (buf_equals(buf1, buf2)) { + ret = iseq; + } else { + ret = !iseq; + } + be_pushbool(vm, ret); + be_return(vm); +} + +static int m_equal(bvm *vm) +{ + return bytes_equal(vm, btrue); +} + +static int m_nequal(bvm *vm) +{ + return bytes_equal(vm, bfalse); +} + +/* + * External API + */ +BERRY_API void be_pushbytes(bvm *vm, const void * bytes, size_t len) +{ + bytes_new_object(vm, len); + be_getmember(vm, -1, ".p"); + buf_impl * buf = be_tocomptr(vm, -1); + be_pop(vm, 1); /* remove .p1 and leave instance */ + if (len > buf->size) { len = buf->size; } /* double check if the buffer allocated was smaller */ + memmove((void*)buf_get_buf(buf), bytes, len); + buf->len = len; + /* bytes instance is on top of stack */ +} + +BERRY_API const void *be_tobytes(bvm *vm, int rel_index, size_t *len) +{ + int index = be_absindex(vm, rel_index); + if (be_isinstance(vm, index)) { + be_getglobal(vm, "bytes"); /* get the bytes class */ /* TODO eventually replace with be_getbuiltin */ + if (be_isderived(vm, index)) { + be_getmember(vm, index, ".p"); + buf_impl * buf = be_tocomptr(vm, -1); + be_pop(vm, 2); /* class and .p */ + if (len) { *len = buf->len; } + return (void*) buf_get_buf(buf); + } else { + be_pop(vm, 1); /* remove class */ + } + } + if (len) { *len = 0; } + return NULL; +} + +#if !BE_USE_PRECOMPILED_OBJECT +void be_load_byteslib(bvm *vm) +{ + static const bnfuncinfo members[] = { + { ".p", NULL }, + { "init", m_init }, + { "tostring", m_tostring }, + { "asstring", m_asstring }, + { "fromstring", m_fromstring }, + { "add", m_add }, + { "get", m_get }, + { "item", m_item }, + { "setitem", m_setitem }, + { "size", m_size }, + { "resize", m_resize }, + { "clear", m_clear }, + { "copy", m_copy }, + { "+", m_merge }, + { "..", m_connect }, + { "==", m_equal }, + { "!=", m_nequal }, + { NULL, NULL } + }; + be_regclass(vm, "bytes", members); +} +#else +/* @const_object_info_begin +class be_class_bytes (scope: global, name: bytes) { + .p, var + init, func(m_init) + tostring, func(m_tostring) + asstring, func(m_asstring) + fromstring, func(m_fromstring) + add, func(m_add) + get, func(m_get) + item, func(m_item) + setitem, func(m_setitem) + size, func(m_size) + resize, func(m_resize) + clear, func(m_clear) + copy, func(m_copy) + +, func(m_merge) + .., func(m_connect) + ==, func(m_equal) + !=, func(m_nequal) +} +@const_object_info_end */ +#include "../generate/be_fixed_be_class_bytes.h" +#endif diff --git a/lib/libesp32/Berry-0.1.10/src/be_libs.c b/lib/libesp32/Berry-0.1.10/src/be_libs.c index bf95f5dad..5dc77ea85 100644 --- a/lib/libesp32/Berry-0.1.10/src/be_libs.c +++ b/lib/libesp32/Berry-0.1.10/src/be_libs.c @@ -13,6 +13,9 @@ extern void be_load_maplib(bvm *vm); extern void be_load_rangelib(bvm *vm); extern void be_load_filelib(bvm *vm); +extern void be_load_tasmota_ntvlib(bvm *vm); +extern void be_load_wirelib(bvm *vm); + void be_loadlibs(bvm *vm) { be_load_baselib(vm); @@ -21,5 +24,8 @@ void be_loadlibs(bvm *vm) be_load_maplib(vm); be_load_rangelib(vm); be_load_filelib(vm); + be_load_byteslib(vm); #endif + be_load_tasmota_ntvlib(vm); + be_load_wirelib(vm); } diff --git a/lib/libesp32/Berry-0.1.10/src/be_listlib.c b/lib/libesp32/Berry-0.1.10/src/be_listlib.c index a46c89e21..3733c78c0 100644 --- a/lib/libesp32/Berry-0.1.10/src/be_listlib.c +++ b/lib/libesp32/Berry-0.1.10/src/be_listlib.c @@ -207,6 +207,19 @@ static int m_item(bvm *vm) be_return_nil(vm); } +static int m_find(bvm *vm) +{ + be_getmember(vm, 1, ".p"); + list_check_data(vm, 2); + if (be_isint(vm, 2)) { + be_pushvalue(vm, 2); + if (be_getindex(vm, -2)) { + be_return(vm); + } + } + be_return_nil(vm); +} + static int m_setitem(bvm *vm) { be_getmember(vm, 1, ".p"); @@ -291,13 +304,15 @@ static int m_merge(bvm *vm) { int argc = be_top(vm); if (argc >= 2) { + be_newobject(vm, "list"); /* stack contains instance and .p */ be_getmember(vm, 1, ".p"); + be_data_merge(vm, -2); be_getmember(vm, 2, ".p"); if (!be_islist(vm, -1)) { be_raise(vm, "type_error", "operand must be a list"); } - be_data_merge(vm, -2); - be_pop(vm, argc + 1); + be_data_merge(vm, -3); + be_pop(vm, 3); } be_return(vm); /* return self */ } @@ -423,6 +438,7 @@ void be_load_listlib(bvm *vm) { "insert", m_insert }, { "remove", m_remove }, { "item", m_item }, + { "find", m_find }, { "setitem", m_setitem }, { "size", m_size }, { "resize", m_resize }, @@ -450,6 +466,7 @@ class be_class_list (scope: global, name: list) { insert, func(m_insert) remove, func(m_remove) item, func(m_item) + find, func(m_find) setitem, func(m_setitem) size, func(m_size) resize, func(m_resize) diff --git a/lib/libesp32/Berry-0.1.10/src/be_vm.c b/lib/libesp32/Berry-0.1.10/src/be_vm.c index fd45cabfb..ec786aa09 100644 --- a/lib/libesp32/Berry-0.1.10/src/be_vm.c +++ b/lib/libesp32/Berry-0.1.10/src/be_vm.c @@ -1060,4 +1060,4 @@ BERRY_API void be_set_obs_hook(bvm *vm, beobshook hook) #if BE_USE_OBSERVABILITY_HOOK vm->obshook = hook; #endif -} \ No newline at end of file +} diff --git a/lib/libesp32/Berry-0.1.10/src/berry.h b/lib/libesp32/Berry-0.1.10/src/berry.h index 91bc652a4..6bcdbc556 100644 --- a/lib/libesp32/Berry-0.1.10/src/berry.h +++ b/lib/libesp32/Berry-0.1.10/src/berry.h @@ -429,6 +429,10 @@ BERRY_API int be_savecode(bvm *vm, const char *name); BERRY_API void be_module_path(bvm *vm); BERRY_API void be_module_path_set(bvm *vm, const char *path); +/* bytes operations */ +BERRY_API void be_pushbytes(bvm *vm, const void *buf, size_t len); +BERRY_API const void *be_tobytes(bvm *vm, int index, size_t *len); + /* registry operation */ BERRY_API int be_register(bvm *vm, int index); BERRY_API void be_unregister(bvm *vm, int id); diff --git a/lib/libesp32/Berry-0.1.10/src/port/be_energylib.c b/lib/libesp32/Berry-0.1.10/src/port/be_energylib.c new file mode 100644 index 000000000..444133852 --- /dev/null +++ b/lib/libesp32/Berry-0.1.10/src/port/be_energylib.c @@ -0,0 +1,26 @@ +/******************************************************************** + * Tasmota lib + * + * To use: `import power` + * + * read power values + *******************************************************************/ +#include "be_object.h" + +extern int b_nrg_read(bvm *vm); + +// #if !BE_USE_PRECOMPILED_OBJECT +#if 1 // TODO we will do pre-compiled later +be_native_module_attr_table(energy) { + be_native_module_function("read", b_nrg_read), +}; + +be_define_native_module(energy, NULL); +#else +/* @const_object_info_begin +module tasmota (scope: global, depend: 1) { + getfreeheap, func(l_getFreeHeap) +} +@const_object_info_end */ +#include "../generate/be_fixed_tasmota.h" +#endif diff --git a/lib/libesp32/Berry-0.1.10/src/port/be_modtab.c b/lib/libesp32/Berry-0.1.10/src/port/be_modtab.c index b3e763fec..fa3f09479 100644 --- a/lib/libesp32/Berry-0.1.10/src/port/be_modtab.c +++ b/lib/libesp32/Berry-0.1.10/src/port/be_modtab.c @@ -20,8 +20,9 @@ be_extern_native_module(debug); be_extern_native_module(gc); /* Tasmota specific */ -be_extern_native_module(tasmota_ntv); +// be_extern_native_module(tasmota_ntv); be_extern_native_module(wire); +be_extern_native_module(energy); /* user-defined modules declare start */ @@ -56,8 +57,7 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = { #endif /* user-defined modules register start */ - &be_native_module(tasmota_ntv), - &be_native_module(wire), + &be_native_module(energy), /* user-defined modules register end */ NULL /* do not remove */ diff --git a/lib/libesp32/Berry-0.1.10/src/port/be_tasmotalib.c b/lib/libesp32/Berry-0.1.10/src/port/be_tasmotalib.c index bd484a9da..17b09a219 100644 --- a/lib/libesp32/Berry-0.1.10/src/port/be_tasmotalib.c +++ b/lib/libesp32/Berry-0.1.10/src/port/be_tasmotalib.c @@ -13,6 +13,7 @@ extern int l_millis(bvm *vm); extern int l_timereached(bvm *vm); extern int l_yield(bvm *vm); extern int l_delay(bvm *vm); +extern int l_scaleuint(bvm *vm); extern int l_respCmnd(bvm *vm); extern int l_respCmndStr(bvm *vm); @@ -22,33 +23,49 @@ extern int l_respCmndFailed(bvm *vm); extern int l_resolveCmnd(bvm *vm); extern int l_getlight(bvm *vm); +extern int l_getpower(bvm *vm); +extern int l_setlight(bvm *vm); +extern int l_setpower(bvm *vm); // #if !BE_USE_PRECOMPILED_OBJECT #if 1 // TODO we will do pre-compiled later +// Class definition +void be_load_tasmota_ntvlib(bvm *vm) +{ + static const bnfuncinfo members[] = { + { "_op", NULL }, + { "_opf", NULL }, + { "_operators", NULL }, + { "_rules", NULL }, + { "_timers", NULL }, + { "_cmd", NULL }, + { "getfreeheap", l_getFreeHeap }, + { "publish", l_publish }, + { "cmd", l_cmd }, + { "getoption", l_getoption }, + { "millis", l_millis }, + { "timereached", l_timereached }, + { "yield", l_yield }, + { "delay", l_delay }, + { "scaleuint", l_scaleuint }, -be_native_module_attr_table(tasmota_ntv) { - be_native_module_function("getfreeheap", l_getFreeHeap), - be_native_module_function("publish", l_publish), - be_native_module_function("cmd", l_cmd), - be_native_module_function("getoption", l_getoption), - be_native_module_function("millis", l_millis), - be_native_module_function("timereached", l_timereached), - be_native_module_function("yield", l_yield), - be_native_module_function("delay", l_delay), + { "respcmnd", l_respCmnd }, + { "respcmndstr", l_respCmndStr }, + { "respcmnd_done", l_respCmndDone }, + { "respcmnd_error", l_respCmndError }, + { "respcmnd_failed", l_respCmndFailed }, + { "resolvecmnd", l_resolveCmnd }, - be_native_module_function("respcmnd", l_respCmnd), - be_native_module_function("respcmndstr", l_respCmndStr), - be_native_module_function("respcmnd_done", l_respCmndDone), - be_native_module_function("respcmnd_error", l_respCmndError), - be_native_module_function("respcmnd_failed", l_respCmndFailed), - be_native_module_function("resolvecmnd", l_resolveCmnd), + { "getlight", l_getlight }, + { "getpower", l_getpower }, + { "setlight", l_setlight }, + { "setpower", l_setpower }, + + { NULL, NULL } + }; + be_regclass(vm, "Tasmota_ntv", members); +} - be_native_module_function("getlight", l_getlight), - - be_native_module_str("_operators", "=<>!|"), -}; - -be_define_native_module(tasmota_ntv, NULL); #else /* @const_object_info_begin module tasmota (scope: global, depend: 1) { diff --git a/lib/libesp32/Berry-0.1.10/src/port/be_wirelib.c b/lib/libesp32/Berry-0.1.10/src/port/be_wirelib.c index 948ccddef..07581b2a4 100644 --- a/lib/libesp32/Berry-0.1.10/src/port/be_wirelib.c +++ b/lib/libesp32/Berry-0.1.10/src/port/be_wirelib.c @@ -7,6 +7,8 @@ *******************************************************************/ #include "be_object.h" +extern int b_wire_init(bvm *vm); + extern int b_wire_begintransmission(bvm *vm); extern int b_wire_endtransmission(bvm *vm); extern int b_wire_requestfrom(bvm *vm); @@ -21,19 +23,25 @@ extern int b_wire_validread(bvm *vm); // #if !BE_USE_PRECOMPILED_OBJECT #if 1 // TODO we will do pre-compiled later -be_native_module_attr_table(wire) { - be_native_module_function("_begintransmission", b_wire_begintransmission), - be_native_module_function("_endtransmission", b_wire_endtransmission), - be_native_module_function("_requestfrom", b_wire_requestfrom), - be_native_module_function("_available", b_wire_available), - be_native_module_function("_write", b_wire_write), - be_native_module_function("_read", b_wire_read), - be_native_module_function("scan", b_wire_scan), - be_native_module_function("write", b_wire_validwrite), - be_native_module_function("read", b_wire_validread), -}; - -be_define_native_module(wire, NULL); +void be_load_wirelib(bvm *vm) +{ + static const bnfuncinfo members[] = { + { "_bus", NULL }, // bus number + { "init", b_wire_init }, + { "_begintransmission", b_wire_begintransmission }, + { "_endtransmission", b_wire_endtransmission }, + { "_requestfrom", b_wire_requestfrom }, + { "_available", b_wire_available }, + { "_write", b_wire_write }, + { "_read", b_wire_read }, + { "scan", b_wire_scan }, + { "write", b_wire_validwrite }, + { "read", b_wire_validread }, + + { NULL, NULL } + }; + be_regclass(vm, "Wire", members); +} #else /* @const_object_info_begin module tasmota (scope: global, depend: 1) { diff --git a/lib/libesp32/CORE2_Library/MahonyAHRS.cpp b/lib/libesp32/CORE2_Library/MahonyAHRS.cpp deleted file mode 100755 index cae005075..000000000 --- a/lib/libesp32/CORE2_Library/MahonyAHRS.cpp +++ /dev/null @@ -1,254 +0,0 @@ -//===================================================================================================== -// MahonyAHRS.c -//===================================================================================================== -// -// Madgwick's implementation of Mayhony's AHRS algorithm. -// See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms -// -// Date Author Notes -// 29/09/2011 SOH Madgwick Initial release -// 02/10/2011 SOH Madgwick Optimised for reduced CPU load -// -//===================================================================================================== - -//--------------------------------------------------------------------------------------------------- -// Header files - -#include "MahonyAHRS.h" -#include "Arduino.h" -#include -//--------------------------------------------------------------------------------------------------- -// Definitions - -#define sampleFreq 25.0f // sample frequency in Hz -#define twoKpDef (2.0f * 1.0f) // 2 * proportional gain -#define twoKiDef (2.0f * 0.0f) // 2 * integral gain - -//#define twoKiDef (0.0f * 0.0f) - -//--------------------------------------------------------------------------------------------------- -// Variable definitions - -volatile float twoKp = twoKpDef; // 2 * proportional gain (Kp) -volatile float twoKi = twoKiDef; // 2 * integral gain (Ki) -volatile float q0 = 1.0, q1 = 0.0, q2 = 0.0, q3 = 0.0; // quaternion of sensor frame relative to auxiliary frame -volatile float integralFBx = 0.0f, integralFBy = 0.0f, integralFBz = 0.0f; // integral error terms scaled by Ki - -//--------------------------------------------------------------------------------------------------- -// Function declarations - -//float invSqrt(float x); - -//==================================================================================================== -// Functions - -//--------------------------------------------------------------------------------------------------- -// AHRS algorithm update - -void MahonyAHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz) { - float recipNorm; - float q0q0, q0q1, q0q2, q0q3, q1q1, q1q2, q1q3, q2q2, q2q3, q3q3; - float hx, hy, bx, bz; - float halfvx, halfvy, halfvz, halfwx, halfwy, halfwz; - float halfex, halfey, halfez; - float qa, qb, qc; - - // Use IMU algorithm if magnetometer measurement invalid (avoids NaN in magnetometer normalisation) - if((mx == 0.0f) && (my == 0.0f) && (mz == 0.0f)) { - //MahonyAHRSupdateIMU(gx, gy, gz, ax, ay, az); - return; - } - - // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) - if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) { - - // Normalise accelerometer measurement - recipNorm = sqrt(ax * ax + ay * ay + az * az); - ax *= recipNorm; - ay *= recipNorm; - az *= recipNorm; - - // Normalise magnetometer measurement - recipNorm = sqrt(mx * mx + my * my + mz * mz); - mx *= recipNorm; - my *= recipNorm; - mz *= recipNorm; - - // Auxiliary variables to avoid repeated arithmetic - q0q0 = q0 * q0; - q0q1 = q0 * q1; - q0q2 = q0 * q2; - q0q3 = q0 * q3; - q1q1 = q1 * q1; - q1q2 = q1 * q2; - q1q3 = q1 * q3; - q2q2 = q2 * q2; - q2q3 = q2 * q3; - q3q3 = q3 * q3; - - // Reference direction of Earth's magnetic field - hx = 2.0f * (mx * (0.5f - q2q2 - q3q3) + my * (q1q2 - q0q3) + mz * (q1q3 + q0q2)); - hy = 2.0f * (mx * (q1q2 + q0q3) + my * (0.5f - q1q1 - q3q3) + mz * (q2q3 - q0q1)); - bx = sqrt(hx * hx + hy * hy); - bz = 2.0f * (mx * (q1q3 - q0q2) + my * (q2q3 + q0q1) + mz * (0.5f - q1q1 - q2q2)); - - // Estimated direction of gravity and magnetic field - halfvx = q1q3 - q0q2; - halfvy = q0q1 + q2q3; - halfvz = q0q0 - 0.5f + q3q3; - halfwx = bx * (0.5f - q2q2 - q3q3) + bz * (q1q3 - q0q2); - halfwy = bx * (q1q2 - q0q3) + bz * (q0q1 + q2q3); - halfwz = bx * (q0q2 + q1q3) + bz * (0.5f - q1q1 - q2q2); - - // Error is sum of cross product between estimated direction and measured direction of field vectors - halfex = (ay * halfvz - az * halfvy) + (my * halfwz - mz * halfwy); - halfey = (az * halfvx - ax * halfvz) + (mz * halfwx - mx * halfwz); - halfez = (ax * halfvy - ay * halfvx) + (mx * halfwy - my * halfwx); - - // Compute and apply integral feedback if enabled - if(twoKi > 0.0f) { - integralFBx += twoKi * halfex * (1.0f / sampleFreq); // integral error scaled by Ki - integralFBy += twoKi * halfey * (1.0f / sampleFreq); - integralFBz += twoKi * halfez * (1.0f / sampleFreq); - gx += integralFBx; // apply integral feedback - gy += integralFBy; - gz += integralFBz; - } - else { - integralFBx = 0.0f; // prevent integral windup - integralFBy = 0.0f; - integralFBz = 0.0f; - } - - // Apply proportional feedback - gx += twoKp * halfex; - gy += twoKp * halfey; - gz += twoKp * halfez; - } - - // Integrate rate of change of quaternion - gx *= (0.5f * (1.0f / sampleFreq)); // pre-multiply common factors - gy *= (0.5f * (1.0f / sampleFreq)); - gz *= (0.5f * (1.0f / sampleFreq)); - qa = q0; - qb = q1; - qc = q2; - q0 += (-qb * gx - qc * gy - q3 * gz); - q1 += (qa * gx + qc * gz - q3 * gy); - q2 += (qa * gy - qb * gz + q3 * gx); - q3 += (qa * gz + qb * gy - qc * gx); - - // Normalise quaternion - recipNorm = sqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); - q0 *= recipNorm; - q1 *= recipNorm; - q2 *= recipNorm; - q3 *= recipNorm; -} - -//--------------------------------------------------------------------------------------------------- -// IMU algorithm update - -void MahonyAHRSupdateIMU(float gx, float gy, float gz, float ax, float ay, float az,float *pitch,float *roll,float *yaw) { - float recipNorm; - float halfvx, halfvy, halfvz; - float halfex, halfey, halfez; - float qa, qb, qc; - - - // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) - if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) { - - // Normalise accelerometer measurement - recipNorm = invSqrt(ax * ax + ay * ay + az * az); - ax *= recipNorm; - ay *= recipNorm; - az *= recipNorm; - - // Estimated direction of gravity and vector perpendicular to magnetic flux - halfvx = q1 * q3 - q0 * q2; - halfvy = q0 * q1 + q2 * q3; - halfvz = q0 * q0 - 0.5f + q3 * q3; - - - - // Error is sum of cross product between estimated and measured direction of gravity - halfex = (ay * halfvz - az * halfvy); - halfey = (az * halfvx - ax * halfvz); - halfez = (ax * halfvy - ay * halfvx); - - // Compute and apply integral feedback if enabled - if(twoKi > 0.0f) { - integralFBx += twoKi * halfex * (1.0f / sampleFreq); // integral error scaled by Ki - integralFBy += twoKi * halfey * (1.0f / sampleFreq); - integralFBz += twoKi * halfez * (1.0f / sampleFreq); - gx += integralFBx; // apply integral feedback - gy += integralFBy; - gz += integralFBz; - } - else { - integralFBx = 0.0f; // prevent integral windup - integralFBy = 0.0f; - integralFBz = 0.0f; - } - - // Apply proportional feedback - gx += twoKp * halfex; - gy += twoKp * halfey; - gz += twoKp * halfez; - } - - // Integrate rate of change of quaternion - gx *= (0.5f * (1.0f / sampleFreq)); // pre-multiply common factors - gy *= (0.5f * (1.0f / sampleFreq)); - gz *= (0.5f * (1.0f / sampleFreq)); - qa = q0; - qb = q1; - qc = q2; - q0 += (-qb * gx - qc * gy - q3 * gz); - q1 += (qa * gx + qc * gz - q3 * gy); - q2 += (qa * gy - qb * gz + q3 * gx); - q3 += (qa * gz + qb * gy - qc * gx); - - // Normalise quaternion - recipNorm = invSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); - q0 *= recipNorm; - q1 *= recipNorm; - q2 *= recipNorm; - q3 *= recipNorm; - - - *pitch = asin(-2 * q1 * q3 + 2 * q0* q2); // pitch - *roll = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1); // roll - *yaw = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3); //yaw - - *pitch *= RAD_TO_DEG; - *yaw *= RAD_TO_DEG; - // Declination of SparkFun Electronics (40°05'26.6"N 105°11'05.9"W) is - // 8° 30' E ± 0° 21' (or 8.5°) on 2016-07-19 - // - http://www.ngdc.noaa.gov/geomag-web/#declination - *yaw -= 8.5; - *roll *= RAD_TO_DEG; - - ///Serial.printf("%f %f %f \r\n", pitch, roll, yaw); -} - -//--------------------------------------------------------------------------------------------------- -// Fast inverse square-root -// See: http://en.wikipedia.org/wiki/Fast_inverse_square_root - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstrict-aliasing" -float invSqrt(float x) { - float halfx = 0.5f * x; - float y = x; - long i = *(long*)&y; - i = 0x5f3759df - (i>>1); - y = *(float*)&i; - y = y * (1.5f - (halfx * y * y)); - return y; -} -#pragma GCC diagnostic pop -//==================================================================================================== -// END OF CODE -//==================================================================================================== diff --git a/lib/libesp32/CORE2_Library/MahonyAHRS.h b/lib/libesp32/CORE2_Library/MahonyAHRS.h deleted file mode 100755 index bae082d24..000000000 --- a/lib/libesp32/CORE2_Library/MahonyAHRS.h +++ /dev/null @@ -1,33 +0,0 @@ -//===================================================================================================== -// MahonyAHRS.h -//===================================================================================================== -// -// Madgwick's implementation of Mayhony's AHRS algorithm. -// See: http://www.x-io.co.uk/node/8#open_source_ahrs_and_imu_algorithms -// -// Date Author Notes -// 29/09/2011 SOH Madgwick Initial release -// 02/10/2011 SOH Madgwick Optimised for reduced CPU load -// -//===================================================================================================== -#ifndef MahonyAHRS_h -#define MahonyAHRS_h - -//---------------------------------------------------------------------------------------------------- -// Variable declaration - -extern volatile float twoKp; // 2 * proportional gain (Kp) -extern volatile float twoKi; // 2 * integral gain (Ki) -//volatile float q0, q1, q2, q3; // quaternion of sensor frame relative to auxiliary frame - -//--------------------------------------------------------------------------------------------------- -// Function declarations - -void MahonyAHRSupdate(float gx, float gy, float gz, float ax, float ay, float az, float mx, float my, float mz); -//void MahonyAHRSupdateIMU(float gx, float gy, float gz, float ax, float ay, float az); -void MahonyAHRSupdateIMU(float gx, float gy, float gz, float ax, float ay, float az,float *pitch,float *roll,float *yaw); -float invSqrt(float x); -#endif -//===================================================================================================== -// End of file -//===================================================================================================== diff --git a/lib/libesp32_div/ESP32-HomeKit/src/_esp_hap_config.h b/lib/libesp32_div/ESP32-HomeKit/src/_esp_hap_config.h old mode 100644 new mode 100755 index e848049b8..ea5421b62 --- a/lib/libesp32_div/ESP32-HomeKit/src/_esp_hap_config.h +++ b/lib/libesp32_div/ESP32-HomeKit/src/_esp_hap_config.h @@ -14,7 +14,7 @@ #define CONFIG_HAP_HTTP_STACK_SIZE 12288 #define CONFIG_HAP_HTTP_SERVER_PORT 5556 // 80 for normal webserver #define CONFIG_HAP_HTTP_CONTROL_PORT 32859 -#define CONFIG_HAP_HTTP_MAX_OPEN_SOCKETS 6 +#define CONFIG_HAP_HTTP_MAX_OPEN_SOCKETS 5 // 6 #define CONFIG_HAP_HTTP_MAX_URI_HANDLERS 16 #endif /* ESP_HAP_CONFIG_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap.h b/lib/libesp32_div/ESP32-HomeKit/src/hap.h old mode 100644 new mode 100755 diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.c b/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.c old mode 100644 new mode 100755 index 773cf31fd..de079b4dd --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.c @@ -39,6 +39,21 @@ hap_char_t *hap_char_brightness_create(int brightness) return hc; } +/* Char: Brightness */ +hap_char_t *hap_char_wattage_create(float watts) +{ + hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_CURRENT_AMBIENT_LIGHT_LEVEL, + HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, watts); + if (!hc) { + return NULL; + } + + hap_char_float_set_constraints(hc, -10000.0, 10000.0, 1); + hap_char_add_unit(hc, HAP_CHAR_UNIT_LUX); + + return hc; +} + /* Char: Cooling Threshold Temperature */ hap_char_t *hap_char_cooling_threshold_temperature_create(float cooling_threshold_temp) { @@ -1284,7 +1299,7 @@ hap_char_t *hap_char_relative_humidity_humidifier_threshold_create(float rel_hum } hap_char_float_set_constraints(hc, 0.0, 100.0, 1.0); - hap_char_add_unit(hc, HAP_CHAR_UNIT_PERCENTAGE); + hap_char_add_unit(hc, HAP_CHAR_UNIT_LUX); return hc; } @@ -1391,7 +1406,7 @@ hap_char_t *hap_char_status_jammed_create(uint8_t status_jammed) hap_char_t *hap_char_administrator_only_access_create(bool administrator_only_access) { hap_char_t *hc = hap_char_bool_create(HAP_CHAR_UUID_ADMINISTRATOR_ONLY_ACCESS, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, + HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, administrator_only_access); if (!hc) { return NULL; @@ -1430,7 +1445,7 @@ hap_char_t *hap_char_lock_last_known_action_create(uint8_t lock_last_known_actio hap_char_t *hap_char_lock_management_auto_security_timeout_create(uint32_t lock_management_auto_security_timeout) { hap_char_t *hc = hap_char_uint32_create(HAP_CHAR_UUID_LOCK_MANAGEMENT_AUTO_SECURITY_TIMEOUT, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, + HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, lock_management_auto_security_timeout); if (!hc) { return NULL; diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.h b/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.h old mode 100644 new mode 100755 index e734a6e57..90aa12e08 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.h +++ b/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.h @@ -142,6 +142,7 @@ extern "C" { #define HAP_CHAR_UUID_REMAINING_DURATION "D4" #define HAP_CHAR_UUID_VALVE_TYPE "D5" #define HAP_CHAR_UUID_IS_CONFIGURED "D6" +#define HAP_CHAR_UUID_WATTAGE "DC" #define HAP_CHAR_UUID_PRODUCT_DATA "220" /** Create Brightness Characteristic @@ -1415,6 +1416,8 @@ hap_char_t *hap_char_air_particulate_density_create(float air_particulate_densit */ hap_char_t *hap_char_air_particulate_size_create(uint8_t air_particulate_size); +hap_char_t *hap_char_wattage_create(float watts); + #ifdef __cplusplus } #endif diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_servs.c b/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_servs.c old mode 100644 new mode 100755 index b8783695f..fec046ffc --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_servs.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_servs.c @@ -419,6 +419,22 @@ err: return NULL; } +hap_serv_t *hap_serv_wattage_create(float curr_watts) +{ + hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_LIGHT_SENSOR); + if (!hs) { + return NULL; + } + if (hap_serv_add_char(hs, hap_char_wattage_create(curr_watts)) != HAP_SUCCESS) { + goto err; + } + return hs; +err: + hap_serv_delete(hs); + return NULL; +} + + hap_serv_t *hap_serv_temperature_sensor_create(float curr_temp) { hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_TEMPERATURE_SENSOR); @@ -703,4 +719,3 @@ err: hap_serv_delete(hs); return NULL; } - diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_servs.h b/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_servs.h old mode 100644 new mode 100755 index e3f6101f9..f1e65e441 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_servs.h +++ b/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_servs.h @@ -75,6 +75,7 @@ extern "C" { #define HAP_SERV_UUID_VALVE "D0" #define HAP_SERV_UUID_FAUCET "D7" + /** Create Accessory Information Service * * This API will create the Accessory Information Service with the mandatory @@ -553,6 +554,9 @@ hap_serv_t *hap_serv_valve_create(uint8_t active, uint8_t in_use, uint8_t valve_ */ hap_serv_t *hap_serv_faucet_create(uint8_t active); + +hap_serv_t *hap_serv_wattage_create(float curr_watts); + #ifdef __cplusplus } #endif diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_keystore.c b/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_keystore.cpp old mode 100644 new mode 100755 similarity index 65% rename from lib/libesp32_div/ESP32-HomeKit/src/hap_platform_keystore.c rename to lib/libesp32_div/ESP32-HomeKit/src/hap_platform_keystore.cpp index b82457ca5..ec27c90c5 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_keystore.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_keystore.cpp @@ -21,25 +21,172 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ + + #include #include #include +#include #define HAP_PLATFORM_DEF_NVS_PARTITION "nvs" #define HAP_PLATFORM_DEF_FACTORY_NVS_PARTITION "factory_nvs" +extern "C" { + static const char *TAG = "hap_platform_keystore"; -char * hap_platform_keystore_get_nvs_partition_name() -{ +const char * hap_platform_keystore_get_nvs_partition_name() { return HAP_PLATFORM_DEF_NVS_PARTITION; } -char * hap_platform_keystore_get_factory_nvs_partition_name() -{ +const char * hap_platform_keystore_get_factory_nvs_partition_name() { return HAP_PLATFORM_DEF_FACTORY_NVS_PARTITION; } +#define HAP_USE_LITTLEFS + +#ifdef HAP_USE_LITTLEFS + +#include + +extern FS *ffsp; + +int hap_platform_keystore_init_partition(const char *part_name, bool read_only) { + return 0; +} + +int hap_platform_keystore_get(const char *part_name, const char *name_space, const char *key, uint8_t *val, size_t *val_size) { + char path[48]; + strcpy(path, "/"); + strcat(path, part_name); + + File fp = ffsp->open(path, "r"); + if (!fp) { + ffsp->mkdir(path); + return -1; + } + fp.close(); + + strcat(path, "/"); + strcat(path, name_space); + fp = ffsp->open(path, "r"); + if (!fp) { + ffsp->mkdir(path); + return -1; + } + fp.close(); + + strcat(path, "/"); + strcat(path, key); + fp = ffsp->open(path, "r"); + if (fp) { + fp.read(val, *val_size); + fp.close(); + } else { + *val_size = 0; + return -1; + } + return 0; +} + +int hap_platform_keystore_set(const char *part_name, const char *name_space, const char *key, const uint8_t *val, const size_t val_len) { + char path[48]; + strcpy(path, "/"); + strcat(path, part_name); + + File fp = ffsp->open(path, "r"); + if (!fp) { + ffsp->mkdir(path); + } + fp.close(); + + strcat(path, "/"); + strcat(path, name_space); + fp = ffsp->open(path, "r"); + if (!fp) { + ffsp->mkdir(path); + } + fp.close(); + + strcat(path, "/"); + strcat(path, key); + fp = ffsp->open(path, "w"); + if (fp) { + fp.write(val, val_len); + fp.close(); + } else { + return -1; + } + return 0; +} + +int hap_platform_keystore_delete(const char *part_name, const char *name_space, const char *key) { + char path[48]; + strcpy(path, "/"); + strcat(path, part_name); + strcat(path, "/"); + strcat(path, name_space); + strcat(path, "/"); + strcat(path, key); + ffsp->remove(path); + return 0; +} + +// should +int hap_platform_keystore_delete_namespace(const char *part_name, const char *name_space) { + char path[48]; + strcpy(path, "/"); + strcat(path, part_name); + strcat(path, "/"); + strcat(path, name_space); + File fp = ffsp->open(path, "r"); + if (fp.isDirectory()) { + while (true) { + File entry = fp.openNextFile(); + if (!entry) break; + char p[48]; + strcpy(p,entry.name()); + entry.close(); + ffsp->remove(p); + } + } + return 0; +} + +// last resort only +int hap_platfrom_keystore_erase_partition(const char *part_name) { +char path[48]; +strcpy(path, "/"); +strcat(path, part_name); +File fp = ffsp->open(path, "r"); +if (fp.isDirectory()) { + while (true) { + File entry = fp.openNextFile(); + if (!entry) break; + const char *ep = entry.name(); + if (*ep=='/') ep++; + char *lcp = strrchr(ep,'/'); + if (lcp) { + ep = lcp + 1; + } + char p[48]; + strcpy(p,entry.name()); + if (entry.isDirectory()) { + hap_platform_keystore_delete_namespace(part_name, ep); + entry.close(); + ffsp->rmdir(p); + } else { + entry.close(); + ffsp->remove(p); + } + + } +} + return 0; +} + +#else + #ifdef CONFIG_NVS_ENCRYPTION int hap_platform_keystore_init_partition(const char *part_name, bool read_only) { @@ -185,3 +332,6 @@ int hap_platfrom_keystore_erase_partition(const char *part_name) } return -1; } +#endif // USE_LITTLEFS + +} diff --git a/platformio.ini b/platformio.ini index 37cf9a174..2bd850f94 100644 --- a/platformio.ini +++ b/platformio.ini @@ -80,7 +80,7 @@ build_flags = ${core.build_flags} board_build.f_cpu = 80000000L board_build.f_flash = 40000000L -monitor_speed = 74880 +monitor_speed = 115200 monitor_port = COM5 upload_speed = 115200 ; *** Upload Serial reset method for Wemos and NodeMCU diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 380145cd6..283c4405f 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -161,7 +161,7 @@ lib_extra_dirs = ; *** EXPERIMENTAL Tasmota version for ESP32solo1 (used in some Xiaomi devices) [env:tasmota32solo1] -extends = env:tasmota32 +extends = env:tasmota32_base platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/raw/framework-arduinoespressif32/framework-arduinoespressif32-release_v3.3-solo1-bd65eb8d1.tar.gz platformio/tool-mklittlefs @ ~1.203.200522 platformio/tool-esptoolpy @ ~1.30000.0 @@ -170,7 +170,7 @@ build_flags = ${common32.build_flags} ; *** EXPERIMENTAL Tasmota version for ESP32-S2 [env:tasmota32s2] -extends = env:tasmota32 +extends = env:tasmota32_base board = esp32s2 board_build.flash_mode = qio platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/arduino-esp32/releases/download/s2-1.0.5-rc6/esp32-s2-1.0.5-rc6.zip @@ -191,7 +191,7 @@ build_flags = ${esp82xx_defaults.build_flags} ; -Wstack-usage=300 [env:tasmota32-debug] -extends = env:tasmota32 +extends = env:tasmota32_base build_type = debug build_unflags = ${esp32_defaults.build_unflags} build_flags = ${esp32_defaults.build_flags} diff --git a/platformio_tasmota32.ini b/platformio_tasmota32.ini index 3eb8047da..1a69eec5d 100644 --- a/platformio_tasmota32.ini +++ b/platformio_tasmota32.ini @@ -11,8 +11,6 @@ default_envs = ${build_envs.default_envs} ; tasmota32-webcam ; tasmota32-odroidgo ; tasmota32-core2 -; tasmota32-knx -; tasmota32-sensors ; tasmota32-display ; tasmota32-ir ; tasmota32-ircustom diff --git a/platformio_tasmota_env32.ini b/platformio_tasmota_env32.ini index bcd391b62..f0b85e60b 100644 --- a/platformio_tasmota_env32.ini +++ b/platformio_tasmota_env32.ini @@ -1,4 +1,4 @@ -[env:tasmota32] +[env:tasmota32_base] framework = ${common.framework} platform = ${common32.platform} platform_packages = ${common32.platform_packages} @@ -30,8 +30,12 @@ lib_ignore = ; Disable next if you want to use ArduinoOTA in Tasmota32 (default disabled) ArduinoOTA +[env:tasmota32] +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DFIRMWARE_TASMOTA32 + [env:tasmota32-webcam] -extends = env:tasmota32 +extends = env:tasmota32_base board = esp32cam board_build.f_cpu = 240000000L board_build.flash_mode = qio @@ -40,7 +44,7 @@ build_flags = ${common32.build_flags} -DBOARD_HAS_PSRAM -mfix-esp32- lib_extra_dirs = lib/libesp32, lib/lib_basic [env:tasmota32-odroidgo] -extends = env:tasmota32 +extends = env:tasmota32_base board = odroid_esp32 board_build.f_cpu = 240000000L board_build.flash_mode = qio @@ -51,7 +55,7 @@ build_flags = ${common32.build_flags} -DBOARD_HAS_PSRAM -mfix-esp32- lib_extra_dirs = lib/libesp32, lib/lib_basic, lib/lib_i2c, lib/lib_rf, lib/lib_div, lib/lib_ssl, lib/lib_display [env:tasmota32-core2] -extends = env:tasmota32 +extends = env:tasmota32_base board = odroid_esp32 board_build.f_cpu = 240000000L board_build.flash_mode = qio @@ -62,130 +66,120 @@ build_flags = ${common32.build_flags} -DBOARD_HAS_PSRAM -mfix-esp32- lib_extra_dirs = lib/libesp32, lib/lib_basic, lib/lib_i2c, lib/lib_rf, lib/lib_div, lib/lib_ssl, lib/lib_display, lib/lib_audio [env:tasmota32-bluetooth] -extends = env:tasmota32 +extends = env:tasmota32_base build_flags = ${common32.build_flags} -DFIRMWARE_BLUETOOTH lib_extra_dirs = lib/libesp32, lib/libesp32_div, lib/lib_basic, lib/lib_i2c, lib/lib_ssl -[env:tasmota32-knx] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DFIRMWARE_KNX_NO_EMULATION -lib_extra_dirs = lib/libesp32, lib/lib_basic, lib/lib_div - -[env:tasmota32-sensors] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DFIRMWARE_SENSORS -lib_extra_dirs = lib/libesp32, lib/lib_basic, lib/lib_i2c, lib/lib_rf, lib/lib_div, lib/lib_ssl - [env:tasmota32-display] -extends = env:tasmota32 +extends = env:tasmota32_base build_flags = ${common32.build_flags} -DFIRMWARE_DISPLAYS lib_extra_dirs = lib/libesp32, lib/lib_basic, lib/lib_display [env:tasmota32-ir] -extends = env:tasmota32 +extends = env:tasmota32_base build_flags = ${common32.build_flags} ${irremoteesp_full.build_flags} -DFIRMWARE_IR lib_extra_dirs = lib/libesp32, lib/lib_basic [env:tasmota32-ircustom] -extends = env:tasmota32 +extends = env:tasmota32_base build_flags = ${common32.build_flags} ${irremoteesp_full.build_flags} -DFIRMWARE_IR_CUSTOM [env:tasmota32-AF] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=af_AF +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=af_AF -DFIRMWARE_TASMOTA32 [env:tasmota32-BG] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=bg_BG +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=bg_BG -DFIRMWARE_TASMOTA32 [env:tasmota32-BR] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=pt_BR +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=pt_BR -DFIRMWARE_TASMOTA32 [env:tasmota32-CN] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=zh_CN +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=zh_CN -DFIRMWARE_TASMOTA32 [env:tasmota32-CZ] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=cs_CZ +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=cs_CZ -DFIRMWARE_TASMOTA32 [env:tasmota32-DE] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=de_DE +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=de_DE -DFIRMWARE_TASMOTA32 [env:tasmota32-ES] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=es_ES +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=es_ES -DFIRMWARE_TASMOTA32 [env:tasmota32-FR] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=fr_FR +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=fr_FR -DFIRMWARE_TASMOTA32 [env:tasmota32-FY] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=fy_NL +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=fy_NL -DFIRMWARE_TASMOTA32 [env:tasmota32-GR] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=el_GR +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=el_GR -DFIRMWARE_TASMOTA32 [env:tasmota32-HE] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=he_HE +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=he_HE -DFIRMWARE_TASMOTA32 [env:tasmota32-HU] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=hu_HU +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=hu_HU -DFIRMWARE_TASMOTA32 [env:tasmota32-IT] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=it_IT +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=it_IT -DFIRMWARE_TASMOTA32 [env:tasmota32-KO] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=ko_KO +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=ko_KO -DFIRMWARE_TASMOTA32 [env:tasmota32-NL] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=nl_NL +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=nl_NL -DFIRMWARE_TASMOTA32 [env:tasmota32-PL] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=pl_PL +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=pl_PL -DFIRMWARE_TASMOTA32 [env:tasmota32-PT] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=pt_PT +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=pt_PT -DFIRMWARE_TASMOTA32 [env:tasmota32-RO] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=ro_RO +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=ro_RO -DFIRMWARE_TASMOTA32 [env:tasmota32-RU] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=ru_RU +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=ru_RU -DFIRMWARE_TASMOTA32 [env:tasmota32-SE] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=sv_SE +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=sv_SE -DFIRMWARE_TASMOTA32 [env:tasmota32-SK] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=sk_SK +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=sk_SK -DFIRMWARE_TASMOTA32 [env:tasmota32-TR] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=tr_TR +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=tr_TR -DFIRMWARE_TASMOTA32 [env:tasmota32-TW] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=zh_TW +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=zh_TW -DFIRMWARE_TASMOTA32 [env:tasmota32-UK] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=uk_UA +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=uk_UA -DFIRMWARE_TASMOTA32 [env:tasmota32-VN] -extends = env:tasmota32 -build_flags = ${common32.build_flags} -DMY_LANGUAGE=vi_VN +extends = env:tasmota32_base +build_flags = ${common32.build_flags} -DMY_LANGUAGE=vi_VN -DFIRMWARE_TASMOTA32 diff --git a/tasmota/berry/autoexec.be b/tasmota/berry/autoexec.be new file mode 100644 index 000000000..60f18e5fc --- /dev/null +++ b/tasmota/berry/autoexec.be @@ -0,0 +1 @@ +load('denky.be') diff --git a/tasmota/berry/denky.be b/tasmota/berry/denky.be new file mode 100644 index 000000000..bcec51407 --- /dev/null +++ b/tasmota/berry/denky.be @@ -0,0 +1,21 @@ +#- +# example of using Berry script to change the led color +# accordingly to power consumption +# using Denky (French Teleinfo reader) +-# + +#- define the global symbol for reference -# +runcolor = nil + +def runcolor() + var pwr = energy.read().find('activepower',0) + print(pwr) + var red = tasmota.scaleuint(int(pwr), 0, 2500, 0, 255) + var green = 255 - red + var channels = [red, green, 0] + tasmota.setlight({"channels":channels, "bri":64, "power":true}) + tasmota.settimer(2000, runcolor) +end + +#- run animation -# +runcolor() diff --git a/tasmota/homekit.c b/tasmota/homekit.c index f8bb77e22..5bd539ddb 100755 --- a/tasmota/homekit.c +++ b/tasmota/homekit.c @@ -24,6 +24,9 @@ /* HomeKit Smart Outlet Example */ +//#define USE_HOMEKIT + + #ifdef USE_HOMEKIT #ifdef ESP32 @@ -49,17 +52,18 @@ static const char *TAG = "HAP outlet"; char *hk_desc; char hk_code[12]; +uint8_t hk_services; extern void Ext_Replace_Cmd_Vars(char *srcbuf, uint32_t srcsize, char *dstbuf, uint32_t dstsize); extern uint32_t Ext_UpdVar(char *vname, float *fvar, uint32_t mode); #define MAX_HAP_DEFS 16 struct HAP_DESC { - char hap_name[16]; - char var_name[16]; - char var2_name[16]; - char var3_name[16]; - char var4_name[16]; + char hap_name[24]; + char var_name[12]; + char var2_name[12]; + char var3_name[12]; + char var4_name[12]; uint8_t hap_cid; uint8_t type; hap_acc_t *accessory; @@ -144,45 +148,66 @@ static int accessory_identify(hap_acc_t *ha) return HAP_SUCCESS; } +const struct HAP_CHAR_TABLE { + char stype[4]; + char ntype; + int8_t index; +} hap_rtab[] = { + {HAP_CHAR_UUID_CURRENT_TEMPERATURE,'f',0}, + {HAP_CHAR_UUID_CURRENT_RELATIVE_HUMIDITY,'f',0}, + {HAP_CHAR_UUID_CURRENT_AMBIENT_LIGHT_LEVEL,'f',0}, + {HAP_CHAR_UUID_BATTERY_LEVEL,'u',0}, + {HAP_CHAR_UUID_STATUS_LOW_BATTERY,'b',1}, + {HAP_CHAR_UUID_CHARGING_STATE,'b',2}, + {HAP_CHAR_UUID_ON,'b',0}, + {HAP_CHAR_UUID_HUE,'f',1}, + {HAP_CHAR_UUID_SATURATION,'f',2}, + {HAP_CHAR_UUID_BRIGHTNESS,'u',3}, + {HAP_CHAR_UUID_COLOR_TEMPERATURE,'u',0}, + {HAP_CHAR_UUID_CONTACT_SENSOR_STATE,'u',0}, + {HAP_CHAR_UUID_WATTAGE,'f',0} +}; + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + /* A dummy callback for handling a write on the "On" characteristic of Outlet. * In an actual accessory, this should control the hardware */ static int sensor_write(hap_write_data_t write_data[], int count, void *serv_priv, void *write_priv, uint32_t index) { int i, ret = HAP_SUCCESS; + float fvar; hap_write_data_t *write; for (i = 0; i < count; i++) { write = &write_data[i]; + bool found = false; const char *hcp = hap_char_get_type_uuid(write->hc); - if (!strcmp(hcp, HAP_CHAR_UUID_ON)) { - //ESP_LOGI(TAG, "Received Write. Outlet %s", write->val.b ? "On" : "Off"); - ESP_LOG_LEVEL(ESP_LOG_INFO, TAG, "Received Write. Outlet %s", write->val.b ? "On" : "Off"); - hap_char_update_val(write->hc, &(write->val)); - float fvar = write->val.b; - Ext_UpdVar(hap_devs[index].var_name, &fvar, 1); - *(write->status) = HAP_STATUS_SUCCESS; - } else if (!strcmp(hcp, HAP_CHAR_UUID_HUE)) { - hap_char_update_val(write->hc, &(write->val)); - float fvar = write->val.f; - Ext_UpdVar(hap_devs[index].var2_name, &fvar, 1); - *(write->status) = HAP_STATUS_SUCCESS; - } else if (!strcmp(hcp, HAP_CHAR_UUID_SATURATION)) { - hap_char_update_val(write->hc, &(write->val)); - float fvar = write->val.f; - Ext_UpdVar(hap_devs[index].var3_name, &fvar, 1); - *(write->status) = HAP_STATUS_SUCCESS; - } else if (!strcmp(hcp, HAP_CHAR_UUID_BRIGHTNESS)) { - hap_char_update_val(write->hc, &(write->val)); - float fvar = write->val.u; - Ext_UpdVar(hap_devs[index].var4_name, &fvar, 1); - *(write->status) = HAP_STATUS_SUCCESS; - } else { + for (uint32_t cnt = 0; cnt < ARRAY_SIZE(hap_rtab); cnt++ ) { + if (!strcmp(hcp, hap_rtab[cnt].stype)) { + hap_char_update_val(write->hc, &(write->val)); + switch (hap_rtab[cnt].ntype) { + case 'f': fvar = write->val.f; break; + case 'u': fvar = write->val.u; break; + case 'b': fvar = write->val.b; break; + } + switch (hap_rtab[cnt].index) { + case 0: Ext_UpdVar(hap_devs[index].var_name, &fvar, 1);break; + case 1: Ext_UpdVar(hap_devs[index].var2_name, &fvar, 1);break; + case 2: Ext_UpdVar(hap_devs[index].var3_name, &fvar, 1);break; + case 3: Ext_UpdVar(hap_devs[index].var4_name, &fvar, 1);break; + } + *(write->status) = HAP_STATUS_SUCCESS; + found = true; + break; + } + } + if (!found) { *(write->status) = HAP_STATUS_RES_ABSENT; } + } return ret; } - // common read routine static int sensor_read(hap_char_t *hc, hap_status_t *status_code, void *serv_priv, void *read_priv, uint32_t index) { hap_val_t new_val; @@ -194,43 +219,125 @@ static int sensor_read(hap_char_t *hc, hap_status_t *status_code, void *serv_pri const char *hcp = hap_char_get_type_uuid(hc); - if (!strcmp(hcp, HAP_CHAR_UUID_CURRENT_TEMPERATURE) - || !strcmp(hcp, HAP_CHAR_UUID_CURRENT_RELATIVE_HUMIDITY) - || !strcmp(hcp, HAP_CHAR_UUID_CURRENT_AMBIENT_LIGHT_LEVEL) - ) { + printf("read values %s\n", hcp ); - Ext_UpdVar(hap_devs[index].var_name, &fvar, 0); - new_val.f = fvar; + for (uint32_t cnt = 0; cnt < ARRAY_SIZE(hap_rtab); cnt++ ) { + if (!strcmp(hcp, hap_rtab[cnt].stype)) { + switch (hap_rtab[cnt].index) { + case 0: Ext_UpdVar(hap_devs[index].var_name, &fvar, 0);break; + case 1: Ext_UpdVar(hap_devs[index].var2_name, &fvar, 0);break; + case 2: Ext_UpdVar(hap_devs[index].var3_name, &fvar, 0);break; + case 3: Ext_UpdVar(hap_devs[index].var4_name, &fvar, 0);break; + } + switch (hap_rtab[cnt].ntype) { + case 'f': new_val.f = fvar; break; + case 'u': new_val.u = fvar; break; + case 'b': new_val.b = fvar; break; + } hap_char_update_val(hc, &new_val); *status_code = HAP_STATUS_SUCCESS; - } - if (!strcmp(hcp, HAP_CHAR_UUID_ON)) { - Ext_UpdVar(hap_devs[index].var_name, &fvar, 0); - new_val.b = fvar; - hap_char_update_val(hc, &new_val); - *status_code = HAP_STATUS_SUCCESS; - } - if (!strcmp(hcp, HAP_CHAR_UUID_HUE)) { - Ext_UpdVar(hap_devs[index].var2_name, &fvar, 0); - new_val.f = fvar; - hap_char_update_val(hc, &new_val); - *status_code = HAP_STATUS_SUCCESS; - } - if (!strcmp(hcp, HAP_CHAR_UUID_SATURATION)) { - Ext_UpdVar(hap_devs[index].var3_name, &fvar, 0); - new_val.f = fvar; - hap_char_update_val(hc, &new_val); - *status_code = HAP_STATUS_SUCCESS; - } - if (!strcmp(hcp, HAP_CHAR_UUID_BRIGHTNESS)) { - Ext_UpdVar(hap_devs[index].var4_name, &fvar, 0); - new_val.u = fvar; - hap_char_update_val(hc, &new_val); - *status_code = HAP_STATUS_SUCCESS; + } } return HAP_SUCCESS; } +// update values every 500 ms +void hap_update_from_vars(void) { + float fvar; + hap_char_t *hc; + hap_val_t new_val; + for (uint32_t cnt = 0; cnt < hk_services; cnt++) { + switch (hap_devs[cnt].hap_cid) { + case HAP_CID_SENSOR: + switch (hap_devs[cnt].type) { + case 0: + hc = hap_serv_get_char_by_uuid(hap_devs[cnt].service, HAP_CHAR_UUID_CURRENT_TEMPERATURE); + if (Ext_UpdVar(hap_devs[cnt].var_name, &fvar, 0)) { + new_val.f = fvar; + hap_char_update_val(hc, &new_val); + } + break; + case 1: + hc = hap_serv_get_char_by_uuid(hap_devs[cnt].service, HAP_CHAR_UUID_CURRENT_RELATIVE_HUMIDITY); + if (Ext_UpdVar(hap_devs[cnt].var_name, &fvar, 0)) { + new_val.f = fvar; + hap_char_update_val(hc, &new_val); + } + break; + case 2: + hc = hap_serv_get_char_by_uuid(hap_devs[cnt].service, HAP_CHAR_UUID_CURRENT_AMBIENT_LIGHT_LEVEL); + if (Ext_UpdVar(hap_devs[cnt].var_name, &fvar, 0)) { + new_val.f = fvar; + hap_char_update_val(hc, &new_val); + } + break; + case 3: + hc = hap_serv_get_char_by_uuid(hap_devs[cnt].service, HAP_CHAR_UUID_BATTERY_LEVEL); + if (Ext_UpdVar(hap_devs[cnt].var_name, &fvar, 0)) { + new_val.u = fvar; + hap_char_update_val(hc, &new_val); + } + hc = hap_serv_get_char_by_uuid(hap_devs[cnt].service, HAP_CHAR_UUID_STATUS_LOW_BATTERY); + if (Ext_UpdVar(hap_devs[cnt].var2_name, &fvar, 0)) { + new_val.u = fvar; + hap_char_update_val(hc, &new_val); + } + hc = hap_serv_get_char_by_uuid(hap_devs[cnt].service, HAP_CHAR_UUID_STATUS_LOW_BATTERY); + if (Ext_UpdVar(hap_devs[cnt].var3_name, &fvar, 0)) { + new_val.u = fvar; + hap_char_update_val(hc, &new_val); + } + break; + case 4: + hc = hap_serv_get_char_by_uuid(hap_devs[cnt].service, HAP_CHAR_UUID_CURRENT_AMBIENT_LIGHT_LEVEL); + if (Ext_UpdVar(hap_devs[cnt].var_name, &fvar, 0)) { + new_val.f = fvar; + hap_char_update_val(hc, &new_val); + } + break; + case 5: + hc = hap_serv_get_char_by_uuid(hap_devs[cnt].service, HAP_CHAR_UUID_CONTACT_SENSOR_STATE); + if (Ext_UpdVar(hap_devs[cnt].var_name, &fvar, 0)) { + new_val.u = fvar; + hap_char_update_val(hc, &new_val); + } + break; + } + break; + case HAP_CID_OUTLET: + hc = hap_serv_get_char_by_uuid(hap_devs[cnt].service, HAP_CHAR_UUID_ON); + if (Ext_UpdVar(hap_devs[cnt].var_name, &fvar, 0)) { + new_val.b = fvar; + hap_char_update_val(hc, &new_val); + } + break; + case HAP_CID_LIGHTING: + hc = hap_serv_get_char_by_uuid(hap_devs[cnt].service, HAP_CHAR_UUID_ON); + if (Ext_UpdVar(hap_devs[cnt].var_name, &fvar, 0)) { + new_val.b = fvar; + hap_char_update_val(hc, &new_val); + } + hc = hap_serv_get_char_by_uuid(hap_devs[cnt].service, HAP_CHAR_UUID_HUE); + if (Ext_UpdVar(hap_devs[cnt].var2_name, &fvar, 0)) { + new_val.f = fvar; + hap_char_update_val(hc, &new_val); + } + hc = hap_serv_get_char_by_uuid(hap_devs[cnt].service, HAP_CHAR_UUID_SATURATION); + if (Ext_UpdVar(hap_devs[cnt].var3_name, &fvar, 0)) { + new_val.f = fvar; + hap_char_update_val(hc, &new_val); + } + hc = hap_serv_get_char_by_uuid(hap_devs[cnt].service, HAP_CHAR_UUID_BRIGHTNESS); + if (Ext_UpdVar(hap_devs[cnt].var4_name, &fvar, 0)) { + new_val.u = fvar; + hap_char_update_val(hc, &new_val); + } + break; + } + } + +} + #define HAP_READ hap_char_t *hc, hap_status_t *status_code, void *serv_priv, void *read_priv) { return sensor_read(hc, status_code, serv_priv, read_priv static int sensor_read1(HAP_READ, 0);} @@ -324,6 +431,7 @@ uint32_t cnt; return cnt; } +float tsim = 20; uint32_t str2c(char **sp, char *vp, uint32_t len) { char *lp = *sp; @@ -352,6 +460,8 @@ uint32_t str2c(char **sp, char *vp, uint32_t len) { return 1; } +extern char *GetFName(); + /*The main thread for handling the Smart Outlet Accessory */ static void smart_outlet_thread_entry(void *p) { /* Initialize the HAP core */ @@ -360,7 +470,8 @@ static void smart_outlet_thread_entry(void *p) { hap_acc_t *accessory; hap_acc_cfg_t cfg = { - .name = "Tasmota-Bridge", + //.name = "Tasmota-Bridge", + .name = GetFName(), .manufacturer = "Tasmota", .model = "Bridge", .serial_num = "001122334455", @@ -437,10 +548,10 @@ static void smart_outlet_thread_entry(void *p) { /* Create accessory object */ hap_devs[index].accessory = hap_acc_create(&hap_cfg); /* Add a dummy Product Data */ - uint8_t product_data[] = {'E','S','P','3','2','H','A','P'}; hap_acc_add_product_data(hap_devs[index].accessory, product_data, sizeof(product_data)); - int ret = hap_serv_add_char(hap_devs[index].service, hap_char_name_create(hap_devs[index].hap_name)); + int ret; + switch (hap_cfg.cid) { case HAP_CID_LIGHTING: { float fvar = 0; @@ -467,18 +578,29 @@ static void smart_outlet_thread_entry(void *p) { case 0: hap_devs[index].service = hap_serv_temperature_sensor_create(fvar); break; case 1: hap_devs[index].service = hap_serv_humidity_sensor_create(fvar); break; case 2: hap_devs[index].service = hap_serv_light_sensor_create(fvar); break; + case 3: + { float fvar1 = 0, fvar2 = 0; + Ext_UpdVar(hap_devs[index].var2_name, &fvar1, 0); + Ext_UpdVar(hap_devs[index].var3_name, &fvar2, 0); + hap_devs[index].service = hap_serv_battery_service_create(fvar, fvar1, fvar2); + } + break; + case 4: hap_devs[index].service = hap_serv_wattage_create(fvar); break; + case 5: hap_devs[index].service = hap_serv_contact_sensor_create(fvar); break; } } break; + + default: hap_devs[index].service = hap_serv_outlet_create(true, true); } - + hap_serv_add_char(hap_devs[index].service, hap_char_name_create(hap_devs[index].hap_name)); hap_set_read(hap_devs[index].service, index); hap_set_write(hap_devs[index].service, index); /* Get pointer to the outlet in use characteristic which we need to monitor for state changes */ - hap_char_t *outlet_in_use = hap_serv_get_char_by_uuid(hap_devs[index].service, HAP_CHAR_UUID_OUTLET_IN_USE); + outlet_in_use = hap_serv_get_char_by_uuid(hap_devs[index].service, HAP_CHAR_UUID_OUTLET_IN_USE); /* Add the Outlet Service to the Accessory Object */ hap_acc_add_serv(hap_devs[index].accessory, hap_devs[index].service); @@ -497,7 +619,7 @@ nextline: lp++; } } - + hk_services = index; /* Initialize the appliance specific hardware. This enables out-in-use detection */ smart_outlet_hardware_init(OUTLET_IN_USE_GPIO); @@ -530,15 +652,10 @@ nextline: /* Enable Hardware MFi authentication (applicable only for MFi variant of SDK) */ hap_enable_mfi_auth(HAP_MFI_AUTH_HW); - /* Initialize Wi-Fi */ - //app_wifi_init(); - /* After all the initializations are done, start the HAP core */ hap_start(); - /* Start Wi-Fi */ - //app_wifi_start(portMAX_DELAY); - uint32_t io_num = OUTLET_IN_USE_GPIO; + int32_t io_num = OUTLET_IN_USE_GPIO; if (io_num >= 0) { hap_val_t appliance_value = { .b = true, @@ -561,25 +678,35 @@ nextline: } } } else { - while (1) { - } + // vTaskDelete(NULL); + while (1) { + delay(500); + // hap_update_from_vars(); + } } } +#define HK_PASSCODE "111-11-111" +int hap_loop_stop(void); +extern void Ext_toLog(char *str); -#define HK_MAXSIZE 1024 - -void homekit_main(char *desc) { +void homekit_main(char *desc, uint32_t flag ) { if (desc) { char *cp = desc; cp += 2; while (*cp == ' ') cp++; // "111-11-111" - uint32_t cnt; - for (cnt = 0; cnt < 10; cnt++) { - hk_code[cnt] = *cp++; + + if (*cp == '*') { + strlcpy(hk_code, HK_PASSCODE, 10); + cp++; + } else { + uint32_t cnt; + for (cnt = 0; cnt < 10; cnt++) { + hk_code[cnt] = *cp++; + } + hk_code[cnt] = 0; } - hk_code[cnt] = 0; if (*cp != '\n') { printf("init error\n"); return; @@ -587,7 +714,16 @@ void homekit_main(char *desc) { cp++; hk_desc = cp; } else { - hap_platfrom_keystore_erase_partition("nvs"); + if (flag == 99) { + hap_loop_stop(); + hap_reset_to_factory(); + } else if (flag == 98) { + hap_loop_stop(); + // is just the folder in wrapper + hap_platfrom_keystore_erase_partition(hap_platform_keystore_get_nvs_partition_name()); + } else { + hap_loop_stop(); + } return; } @@ -595,7 +731,8 @@ void homekit_main(char *desc) { /* Create the application thread */ xTaskCreate(smart_outlet_thread_entry, SMART_OUTLET_TASK_NAME, SMART_OUTLET_TASK_STACKSIZE, NULL, SMART_OUTLET_TASK_PRIORITY, NULL); + } #endif // ESP32 -#endif // USE_HOMEKIT \ No newline at end of file +#endif // USE_HOMEKIT diff --git a/tasmota/i18n.h b/tasmota/i18n.h index 061b240b4..accb88938 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -366,6 +366,8 @@ #define D_CMND_MQTTCLIENT "MqttClient" #define D_CMND_MQTTUSER "MqttUser" #define D_CMND_MQTTPASSWORD "MqttPassword" +#define D_CMND_MQTTKEEPALIVE "MqttKeepAlive" +#define D_CMND_MQTTTIMEOUT "MqttTimeout" #define D_CMND_TLSKEY "TLSKey" #define D_CMND_FULLTOPIC "FullTopic" #define D_CMND_PREFIX "Prefix" @@ -782,6 +784,7 @@ const char JSON_SNS_RANGE[] PROGMEM = ",\"%s\":{\"" D_JSON_RANGE "\":%d}"; const char JSON_SNS_GNGPM[] PROGMEM = ",\"%s\":{\"" D_JSON_TOTAL_USAGE "\":%s,\"" D_JSON_FLOWRATE "\":%s}"; const char S_LOG_I2C_FOUND_AT[] PROGMEM = D_LOG_I2C "%s " D_FOUND_AT " 0x%x"; +const char S_LOG_I2C_FOUND_AT_PORT[] PROGMEM = D_LOG_I2C "%s " D_FOUND_AT " 0x%x (" D_PORT " %d)"; const char S_RSLT_POWER[] PROGMEM = D_RSLT_POWER; const char S_RSLT_RESULT[] PROGMEM = D_RSLT_RESULT; diff --git a/tasmota/language/af_AF.h b/tasmota/language/af_AF.h index b445d8dcd..b61c82c6e 100644 --- a/tasmota/language/af_AF.h +++ b/tasmota/language/af_AF.h @@ -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 v9.2.0.4 + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index c9ddf4cbf..2061eb460 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -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 v8.2.0.6 + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -796,7 +796,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index 6bd44919c..be329c3e2 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -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.5.0.9 + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index c7221243b..9eaff2441 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -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 v9.2.0.3 + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index e11ae5194..ca14da7c1 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -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.5.0 + * Updated until v9.3.1.1 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index df99b6504..12a476a32 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -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 v8.0.0.0 + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index b05540083..93967a818 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -1,5 +1,5 @@ /* - es-ES.h - localization for Spanish - Spain for Tasmota + es-ES.h - localization for Spanish - Spain for Tasmota (translation also valid for all latinamerica) Copyright (C) 2021 Adrian Scillato @@ -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 v9.2.0.3 + * Updated until v9.3.1.1 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Cambiando dirección a" +#define D_OUT_OF_RANGE "Fuera de Rango" +#define D_SENSOR_DETECTED "detectado" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index a5c8ab250..980b380f7 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -1,14 +1,18 @@ /* fr-FR.h - localization for French - France for Tasmota + Copyright (C) 2021 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 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 . */ @@ -24,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 v9.2.0.3 + * Updated until v9.3.1.1 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -793,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/fy_NL.h b/tasmota/language/fy_NL.h index bb33ebc2d..8b166dd94 100644 --- a/tasmota/language/fy_NL.h +++ b/tasmota/language/fy_NL.h @@ -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 v9.2.0.4 + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index 1d5785433..8bf5e5e97 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -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 v5.14.0b + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index 6baf1960f..239239348 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -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 v5.12.0e + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index 3540c0cb0..b8a7d828b 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -1,7 +1,7 @@ /* it-IT.h - localization for Italian - Italy for Tasmota - Copyright (C) 2021 Gennaro Tortone - some mods by Antonio Fragola - Updated by bovirus - rev. 03.03.2021 + Copyright (C) 2021 Gennaro Tortone, Antonio Fragola, Bovirus and 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 @@ -28,11 +28,11 @@ * Use online command StateText to translate ON, OFF, HOLD and TOGGLE. * Use online command Prefix to translate cmnd, stat and tele. * - * Updated until v6.0.0a + * Last update - 9.3.1.1 (17.03.2021) \*********************************************************************/ #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 1040 // HTML (ISO 639-1) Language Code #define D_HTML_LANGUAGE "it" @@ -797,6 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand - D1" #define D_SENSOR_NEOPOOL_TX "NeoPool - TX" #define D_SENSOR_NEOPOOL_RX "NeoPool - RX" +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Imposta indirizzo a" +#define D_OUT_OF_RANGE "Fuori limite" +#define D_SENSOR_DETECTED "rilevato" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index 907f840e5..964ab46a7 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -1,7 +1,7 @@ /* ko-KO.h - localization for Korean - Korean for Tasmota - Copyright (C) 2021 Theo Arends (translated by NyaamZ) + Copyright (C) 2021 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 @@ -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.2.1.11 + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index 96991391f..bc855e4a8 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -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 v9.2.0.4 + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index 818aba4cb..78710996f 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -1,7 +1,7 @@ /* pl-PL-d.h - localization for Polish with diacritics - Poland for Tasmota - Copyright (C) 2021 Theo Arends (translated by roblad - Robert L., upgraded by R. Turala) + Copyright (C) 2021 Roblad (Robert L.) and 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 @@ -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 v5.12.0d + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index c9ba30c50..a2929b529 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -1,7 +1,7 @@ /* pt-BR.h - localization for Portuguese - Brazil for Tasmota - Copyright (C) 2021 Fabiano Bovo + Copyright (C) 2021 Fabiano Bovo and 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 @@ -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 v7.0.0.1 + * Updated until v9.3.1.1 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Mudança de endereço para" +#define D_OUT_OF_RANGE "Fora de Alcance" +#define D_SENSOR_DETECTED "detectou" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index 0687aedcd..c5b524875 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -1,7 +1,7 @@ /* pt-PT.h - localization for Portuguese - Portugal for Tasmota - Copyright (C) 2021 Paulo Paiva + Copyright (C) 2021 Paulo Paiva and 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 @@ -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 v7.0.0.1 + * Updated until v9.3.1.1 \*********************************************************************/ #define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Mudança de endereço para" +#define D_OUT_OF_RANGE "Fora de Alcance" +#define D_SENSOR_DETECTED "detectou" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index d9d779948..c8182eb75 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -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 v8.1.0.10 + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index ab546c0f1..6d8d0b932 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -1,7 +1,7 @@ /* - ru-RU.h - localization for Russian - Rissia for Tasmota + ru-RU.h - localization for Russian - Russia for Tasmota - Copyright (C) 2021 Theo Arends / roman-vn + Copyright (C) 2021 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 @@ -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 v5.12.0b + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "А" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index 9310a6d24..b0fbc5c3f 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -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.2.1.14 + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index 67de1e2aa..5ccbc77fe 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -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.2.1.11 + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index b21b0574a..e6429fed1 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -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.1.1 + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index b1baca8dd..286b851dc 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -1,7 +1,7 @@ /* uk-UA.h - localization for Ukrainian - Ukraine for Tasmota - Copyright (C) 2021 Theo Arends / vadym-adik + Copyright (C) 2021 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 @@ -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 v5.14.0a + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "А" diff --git a/tasmota/language/vi_VN.h b/tasmota/language/vi_VN.h index 40ea941d0..c04e43010 100644 --- a/tasmota/language/vi_VN.h +++ b/tasmota/language/vi_VN.h @@ -1,7 +1,7 @@ /* vi-VN.h - localization for Vietnam for Tasmota - Copyright (C) 2021 translateb by Tâm.NT + Copyright (C) 2021 Tâm.NT 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 v9.0.0.1 + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "A" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index 73f9424ed..a7e1847ca 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -1,7 +1,7 @@ /* zh-CN.h - localization for Chinese (Simplified) - China for Tasmota - Copyright (C) 2021 Theo Arends (translated by killadm) + Copyright (C) 2021 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 @@ -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 v5.14.0b + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "安" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index 8a759f0eb..13cc6e858 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -1,7 +1,7 @@ /* zh-TW.h - localization for Chinese (Traditional) - Taiwan for Tasmota - Copyright (C) 2021 Theo Arends (translated by dannydu) + Copyright (C) 2021 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 @@ -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 v5.12.0d + * Updated until v9.3.1.1 \*********************************************************************/ //#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English) @@ -797,7 +797,10 @@ #define D_SENSOR_WIEGAND_D1 "Wiegand D1" #define D_SENSOR_NEOPOOL_TX "NeoPool Tx" #define D_SENSOR_NEOPOOL_RX "NeoPool Rx" - +#define D_SENSOR_VL53L0X_XSHUT "VL53L0X XSHUT" +#define D_NEW_ADDRESS "Setting address to" +#define D_OUT_OF_RANGE "Out of Range" +#define D_SENSOR_DETECTED "detected" // Units #define D_UNIT_AMPERE "安培" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index b4bd5dfae..1d13bedda 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -101,6 +101,9 @@ // -- MQTT ---------------------------------------- #define MQTT_USE true // [SetOption3] Select default MQTT use (false = Off, true = On) +#define MQTT_KEEPALIVE 30 // [MqttKeepAlive] +#define MQTT_SOCKET_TIMEOUT 4 // [MqttTimeout] + #define MQTT_HOST "" // [MqttHost] #define MQTT_FINGERPRINT1 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 // [MqttFingerprint1] (auto-learn) #define MQTT_FINGERPRINT2 0xDA,0x39,0xA3,0xEE,0x5E,0x6B,0x4B,0x0D,0x32,0x55,0xBF,0xEF,0x95,0x60,0x18,0x90,0xAF,0xD8,0x07,0x09 // [MqttFingerprint2] (invalid) @@ -607,6 +610,7 @@ // #define USE_EZORGB // [I2cDriver55] Enable support for EZO's RGB sensor (+0k5 code) - Shared EZO code required for any EZO device (+1k2 code) // #define USE_EZOPMP // [I2cDriver55] Enable support for EZO's PMP sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code) // #define USE_SEESAW_SOIL // [I2cDriver56] Enable Capacitice Soil Moisture & Temperature Sensor (I2C addresses 0x36 - 0x39) (+1k3 code) +// #define USE_MPU6886 // [I2cDriver58] Enable MPU6886 - found in M5Stack - support 2 I2C buses on ESP32 (I2C address 0x68) (+2k 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 @@ -669,6 +673,7 @@ #define STARTING_OFFSET 30 // Turn on NovaSDS XX-seconds before tele_period is reached //#define USE_HPMA // Add support for Honeywell HPMA115S0 particle concentration sensor (+1k4) //#define USE_SR04 // Add support for HC-SR04 ultrasonic devices (+1k code) + #define SR04_MAX_SENSOR_DISTANCE 500 // Set sensor max detection distance //#define USE_DYP // Add support for DYP ME-007 ultrasonic distance sensor, serial port version (+0k5 code) #define USE_SERIAL_BRIDGE // Add support for software Serial Bridge (+0k8 code) //#define USE_TCP_BRIDGE // Add support for Serial to TCP bridge (+1.3k code) diff --git a/tasmota/settings.h b/tasmota/settings.h index 347aca523..d8c5ce2da 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -149,8 +149,8 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t mqtt_state_retain : 1; // bit 7 (v9.3.0.1) - CMND_STATERETAIN uint32_t mqtt_info_retain : 1; // bit 8 (v9.3.0.1) - CMND_INFORETAIN uint32_t wiegand_hex_output : 1; // bit 9 (v9.3.1.1) - SetOption123 - (Wiegand) switch tag number output to hex format (1) - uint32_t zigbee_hide_bridge_topic : 1; // bit 10 (v9.3.xxx) - SetOption124 - (Zigbee) Hide bridge topic from zigbee topic (use with SetOption89) (1) - uint32_t spare11 : 1; // bit 11 + uint32_t wiegand_keypad_to_tag : 1; // bit 10 (v9.3.1.1) - SetOption124 - (Wiegand) send key pad stroke as single char (0) or one tag (ending char #) (1) + uint32_t zigbee_hide_bridge_topic : 1; // bit 11 (v9.3.1.1) - SetOption125 - (Zigbee) Hide bridge topic from zigbee topic (use with SetOption89) (1) uint32_t spare12 : 1; // bit 12 uint32_t spare13 : 1; // bit 13 uint32_t spare14 : 1; // bit 14 @@ -488,7 +488,12 @@ struct { power_t interlock[MAX_INTERLOCKS_SET]; // 4D0 MAX_INTERLOCKS = MAX_RELAYS / 2 - uint8_t free_508[41]; // 508 + uint8_t free_508[36]; // 508 + + uint16_t mqtt_keepalive; // 52C + uint16_t mqtt_socket_timeout; // 52E + + uint8_t free_530[1]; // 530 uint8_t ina219_mode; // 531 uint16_t pulse_timer[MAX_PULSETIMERS]; // 532 diff --git a/tasmota/settings.ino b/tasmota/settings.ino index c1996da99..11f835592 100644 --- a/tasmota/settings.ino +++ b/tasmota/settings.ino @@ -864,6 +864,8 @@ void SettingsDefaultSet2(void) { memcpy_P(Settings.mqtt_fingerprint[1], default_fingerprint2, sizeof(default_fingerprint2)); Settings.tele_period = TELE_PERIOD; Settings.mqttlog_level = MQTT_LOG_LEVEL; + Settings.mqtt_keepalive = MQTT_KEEPALIVE; + Settings.mqtt_socket_timeout = MQTT_SOCKET_TIMEOUT; // Energy flag.no_power_on_check |= ENERGY_VOLTAGE_ALWAYS; @@ -1244,6 +1246,10 @@ void SettingsDelta(void) { if (Settings.version < 0x09020007) { *(uint32_t *)&Settings.device_group_tie = 0x04030201; } + if (Settings.version < 0x09030102) { + Settings.mqtt_keepalive = MQTT_KEEPALIVE; + Settings.mqtt_socket_timeout = MQTT_SOCKET_TIMEOUT; + } Settings.version = VERSION; SettingsSave(1); diff --git a/tasmota/support.ino b/tasmota/support.ino index 85e1a7341..63ebc371e 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -1812,27 +1812,37 @@ const uint8_t I2C_RETRY_COUNTER = 3; uint32_t i2c_active[4] = { 0 }; uint32_t i2c_buffer = 0; +#ifdef ESP32 +bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size, uint32_t bus = 0); +bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size, uint32_t bus) +#else bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size) +#endif { uint8_t retry = I2C_RETRY_COUNTER; bool status = false; +#ifdef ESP32 + TwoWire & myWire = (bus == 0) ? Wire : Wire1; +#else + TwoWire & myWire = Wire; +#endif i2c_buffer = 0; while (!status && retry) { - Wire.beginTransmission(addr); // start transmission to device - Wire.write(reg); // sends register address to read from - 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) { + myWire.beginTransmission(addr); // start transmission to device + myWire.write(reg); // sends register address to read from + if (0 == myWire.endTransmission(false)) { // Try to become I2C Master, send data and collect bytes, keep master status for next request... + myWire.requestFrom((int)addr, (int)size); // send data n-bytes read + if (myWire.available() == size) { for (uint32_t i = 0; i < size; i++) { - i2c_buffer = i2c_buffer << 8 | Wire.read(); // receive DATA + i2c_buffer = i2c_buffer << 8 | myWire.read(); // receive DATA } status = true; } } retry--; } - if (!retry) Wire.endTransmission(); + if (!retry) myWire.endTransmission(); return status; } @@ -1916,19 +1926,30 @@ int32_t I2cRead24(uint8_t addr, uint8_t reg) return i2c_buffer; } +#ifdef ESP32 +bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size, uint32_t bus = 0); +bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size, uint32_t bus) +#else bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size) +#endif { uint8_t x = I2C_RETRY_COUNTER; +#ifdef ESP32 + TwoWire & myWire = (bus == 0) ? Wire : Wire1; +#else + TwoWire & myWire = Wire; +#endif + do { - Wire.beginTransmission((uint8_t)addr); // start transmission to device - Wire.write(reg); // sends register address to write to + myWire.beginTransmission((uint8_t)addr); // start transmission to device + myWire.write(reg); // sends register address to write to uint8_t bytes = size; while (bytes--) { - Wire.write((val >> (8 * bytes)) & 0xFF); // write data + myWire.write((val >> (8 * bytes)) & 0xFF); // write data } x--; - } while (Wire.endTransmission(true) != 0 && x != 0); // end transmission + } while (myWire.endTransmission(true) != 0 && x != 0); // end transmission return (x); } @@ -2032,10 +2053,19 @@ void I2cSetActive(uint32_t addr, uint32_t count = 1) // AddLog(LOG_LEVEL_DEBUG, PSTR("I2C: Active %08X,%08X,%08X,%08X"), i2c_active[0], i2c_active[1], i2c_active[2], i2c_active[3]); } -void I2cSetActiveFound(uint32_t addr, const char *types) +void I2cSetActiveFound(uint32_t addr, const char *types, uint32_t bus = 0); +void I2cSetActiveFound(uint32_t addr, const char *types, uint32_t bus) { I2cSetActive(addr); +#ifdef ESP32 + if (0 == bus) { + AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT, types, addr); + } else { + AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT_PORT, types, addr, bus); + } +#else AddLog(LOG_LEVEL_INFO, S_LOG_I2C_FOUND_AT, types, addr); +#endif // ESP32 } bool I2cActive(uint32_t addr) @@ -2047,14 +2077,24 @@ bool I2cActive(uint32_t addr) return false; } +#ifdef ESP32 +bool I2cSetDevice(uint32_t addr, uint32_t bus = 0); +bool I2cSetDevice(uint32_t addr, uint32_t bus) +#else bool I2cSetDevice(uint32_t addr) +#endif { +#ifdef ESP32 + TwoWire & myWire = (bus == 0) ? Wire : Wire1; +#else + TwoWire & myWire = Wire; +#endif addr &= 0x7F; // Max I2C address is 127 if (I2cActive(addr)) { return false; // If already active report as not present; } - Wire.beginTransmission((uint8_t)addr); - return (0 == Wire.endTransmission()); + myWire.beginTransmission((uint8_t)addr); + return (0 == myWire.endTransmission()); } #endif // USE_I2C @@ -2085,7 +2125,7 @@ void SyslogAsync(bool refresh) { static uint32_t syslog_host_hash = 0; // Syslog host name hash static uint32_t index = 1; - if (!TasmotaGlobal.syslog_level) { return; } + if (!TasmotaGlobal.syslog_level || TasmotaGlobal.global_state.network_down) { return; } if (refresh && !NeedLogRefresh(TasmotaGlobal.syslog_level, index)) { return; } char* line; @@ -2097,8 +2137,16 @@ void SyslogAsync(bool refresh) { if (mxtime > 0) { uint32_t current_hash = GetHash(SettingsText(SET_SYSLOG_HOST), strlen(SettingsText(SET_SYSLOG_HOST))); if (syslog_host_hash != current_hash) { + IPAddress temp_syslog_host_addr; + int ok = WiFi.hostByName(SettingsText(SET_SYSLOG_HOST), temp_syslog_host_addr); // If sleep enabled this might result in exception so try to do it once using hash + if (!ok || (0xFFFFFFFF == (uint32_t)temp_syslog_host_addr)) { // 255.255.255.255 is assumed a DNS problem + TasmotaGlobal.syslog_level = 0; + TasmotaGlobal.syslog_timer = SYSLOG_TIMER; + AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION "Loghost DNS resolve failed (%s). " D_RETRY_IN " %d " D_UNIT_SECOND), SettingsText(SET_SYSLOG_HOST), SYSLOG_TIMER); + return; + } syslog_host_hash = current_hash; - WiFi.hostByName(SettingsText(SET_SYSLOG_HOST), syslog_host_addr); // If sleep enabled this might result in exception so try to do it once using hash + syslog_host_addr = temp_syslog_host_addr; } if (!PortUdp.beginPacket(syslog_host_addr, Settings.syslog_port)) { TasmotaGlobal.syslog_level = 0; diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino index de6879f16..d782f385f 100644 --- a/tasmota/support_command.ino +++ b/tasmota/support_command.ino @@ -529,9 +529,9 @@ void CmndStatus(void) if (((0 == payload) || (6 == payload)) && Settings.flag.mqtt_enabled) { // SetOption3 - Enable MQTT Response_P(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\",\"" D_JSON_MQTT_COUNT "\":%d,\"MAX_PACKET_SIZE\":%d,\"KEEPALIVE\":%d}}"), + D_CMND_MQTTCLIENT "\":\"%s\",\"" D_CMND_MQTTUSER "\":\"%s\",\"" D_JSON_MQTT_COUNT "\":%d,\"MAX_PACKET_SIZE\":%d,\"KEEPALIVE\":%d,\"SOCKET_TIMEOUT\":%d}}"), SettingsText(SET_MQTT_HOST), Settings.mqtt_port, EscapeJSONString(SettingsText(SET_MQTT_CLIENT)).c_str(), - TasmotaGlobal.mqtt_client, EscapeJSONString(SettingsText(SET_MQTT_USER)).c_str(), MqttConnectCount(), MQTT_MAX_PACKET_SIZE, MQTT_KEEPALIVE); + TasmotaGlobal.mqtt_client, EscapeJSONString(SettingsText(SET_MQTT_USER)).c_str(), MqttConnectCount(), MQTT_MAX_PACKET_SIZE, Settings.mqtt_keepalive, Settings.mqtt_socket_timeout); MqttPublishPrefixTopic_P(STAT, PSTR(D_CMND_STATUS "6")); } diff --git a/tasmota/support_device_groups.ino b/tasmota/support_device_groups.ino index f85b801a5..19112567a 100644 --- a/tasmota/support_device_groups.ino +++ b/tasmota/support_device_groups.ino @@ -344,18 +344,18 @@ void SendReceiveDeviceGroupMessage(struct device_group * device_group, struct de value |= *message_ptr++ << 16; value |= *message_ptr++ << 24; #ifdef USE_DEVICE_GROUPS_SEND - device_group->values_32bit[item - DGR_ITEM_MAX_16BIT - 1] = (item == DGR_ITEM_POWER ? value & 0xffffff : value); + if (item < DGR_ITEM_LAST_32BIT) device_group->values_32bit[item - DGR_ITEM_MAX_16BIT - 1] = (item == DGR_ITEM_POWER ? value & 0xffffff : value); #endif // USE_DEVICE_GROUPS_SEND } #ifdef USE_DEVICE_GROUPS_SEND else { - device_group->values_16bit[item - DGR_ITEM_MAX_8BIT - 1] = value; + if (item < DGR_ITEM_LAST_16BIT) device_group->values_16bit[item - DGR_ITEM_MAX_8BIT - 1] = value; } #endif // USE_DEVICE_GROUPS_SEND } #ifdef USE_DEVICE_GROUPS_SEND else { - device_group->values_8bit[item] = value; + if (item < DGR_ITEM_LAST_8BIT) device_group->values_8bit[item] = value; } #endif // USE_DEVICE_GROUPS_SEND log_length = snprintf(log_ptr, log_remaining, PSTR("%u"), value); diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 4c20486b2..9ad44d32e 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -769,7 +769,7 @@ bool MqttShowSensor(void) int json_data_start = strlen(TasmotaGlobal.mqtt_data); for (uint32_t i = 0; i < MAX_SWITCHES; i++) { #ifdef USE_TM1638 - if (PinUsed(GPIO_SWT1, i) || (PinUsed(GPIO_TM16CLK) && PinUsed(GPIO_TM16DIO) && PinUsed(GPIO_TM16STB))) { + if (PinUsed(GPIO_SWT1, i) || (PinUsed(GPIO_TM1638CLK) && PinUsed(GPIO_TM1638DIO) && PinUsed(GPIO_TM1638STB))) { #else if (PinUsed(GPIO_SWT1, i)) { #endif // USE_TM1638 diff --git a/tasmota/tasmota.h b/tasmota/tasmota.h index 87e5f01b3..85784956f 100644 --- a/tasmota/tasmota.h +++ b/tasmota/tasmota.h @@ -83,6 +83,7 @@ const uint8_t MAX_SHUTTER_KEYS = 4; // Max number of shutter keys or but const uint8_t MAX_PCF8574 = 4; // Max number of PCF8574 devices const uint8_t MAX_RULE_SETS = 3; // Max number of rule sets of size 512 characters const uint16_t MAX_RULE_SIZE = 512; // Max number of characters in rules +const uint16_t VL53L0X_MAX_SENSORS = 8; // Max number of VL53L0X sensors #ifdef ESP32 const uint8_t MAX_I2C = 2; // Max number of I2C controllers (ESP32 = 2) @@ -423,7 +424,7 @@ enum TuyaSupportedFunctions { TUYA_MCU_FUNC_NONE, TUYA_MCU_FUNC_REL6, TUYA_MCU_FUNC_REL7, TUYA_MCU_FUNC_REL8, TUYA_MCU_FUNC_DIMMER = 21, TUYA_MCU_FUNC_DIMMER2, TUYA_MCU_FUNC_CT, TUYA_MCU_FUNC_RGB, TUYA_MCU_FUNC_WHITE, TUYA_MCU_FUNC_MODESET, TUYA_MCU_FUNC_REPORT1, TUYA_MCU_FUNC_REPORT2, - TUYA_MCU_FUNC_POWER = 31, TUYA_MCU_FUNC_CURRENT, TUYA_MCU_FUNC_VOLTAGE, TUYA_MCU_FUNC_BATTERY_STATE, TUYA_MCU_FUNC_BATTERY_PERCENTAGE, + TUYA_MCU_FUNC_POWER = 31, TUYA_MCU_FUNC_CURRENT, TUYA_MCU_FUNC_VOLTAGE, TUYA_MCU_FUNC_BATTERY_STATE, TUYA_MCU_FUNC_BATTERY_PERCENTAGE, TUYA_MCU_FUNC_POWER_COMBINED, TUYA_MCU_FUNC_POWER_TOTAL, TUYA_MCU_FUNC_REL1_INV = 41, TUYA_MCU_FUNC_REL2_INV, TUYA_MCU_FUNC_REL3_INV, TUYA_MCU_FUNC_REL4_INV, TUYA_MCU_FUNC_REL5_INV, TUYA_MCU_FUNC_REL6_INV, TUYA_MCU_FUNC_REL7_INV, TUYA_MCU_FUNC_REL8_INV, TUYA_MCU_FUNC_LOWPOWER_MODE = 51, diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 54db9ae17..c24b8733a 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -338,6 +338,8 @@ void setup(void) { snprintf_P(TasmotaGlobal.hostname, sizeof(TasmotaGlobal.hostname)-1, SettingsText(SET_HOSTNAME)); } + RtcInit(); + GpioInit(); WifiConnect(); @@ -350,7 +352,7 @@ void setup(void) { AddLog(LOG_LEVEL_INFO, PSTR(D_WARNING_MINIMAL_VERSION)); #endif // FIRMWARE_MINIMAL - RtcInit(); +// RtcInit(); #ifdef USE_ARDUINO_OTA ArduinoOTAInit(); diff --git a/tasmota/tasmota_configurations_ESP32.h b/tasmota/tasmota_configurations_ESP32.h index 951d63e41..75cfc5572 100644 --- a/tasmota/tasmota_configurations_ESP32.h +++ b/tasmota/tasmota_configurations_ESP32.h @@ -81,12 +81,12 @@ #define USE_M5STACK_CORE2 // Add support for M5Stack Core2 #define USE_I2S_SAY_TIME #define USE_I2S_WEBRADIO - #define USE_MPU6886 #define USE_UFILESYS #define USE_SDCARD #define GUI_TRASH_FILE #define USE_I2C #define USE_BMA423 + #define USE_MPU6886 #define USE_SPI #define USE_DISPLAY #define USE_DISPLAY_ILI9342 @@ -140,6 +140,186 @@ #define USE_MI_ESP32 // (ESP32 only) Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash) #endif // FIRMWARE_BLUETOOTH -#endif // ESP32 +/*********************************************************************************************\ + * [tasmota32.bin] + * Provide an image which includes KNX and Sensors +\*********************************************************************************************/ +#ifdef FIRMWARE_TASMOTA32 + +#define USE_ENHANCED_GUI_WIFI_SCAN + +#define ROTARY_V1 // Add support for Rotary Encoder as used in MI Desk Lamp + +#define USE_TUYA_MCU // Add support for Tuya Serial MCU +#ifndef TUYA_DIMMER_ID + #define TUYA_DIMMER_ID 0 // Default dimmer Id +#endif +#undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code) +//#undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer (+2k code) +#undef USE_SONOFF_IFAN // Disable support for Sonoff iFan02 and iFan03 (+2k code) +#define USE_BUZZER // Add support for a buzzer (+0k6 code) +//#undef USE_ARILUX_RF // Disable support for Arilux RF remote controller (+0k8 code, 252 iram (non 2.3.0)) +#define USE_DEEPSLEEP // Add support for deepsleep (+1k code) +#undef USE_EXS_DIMMER // Disable support for EX-Store WiFi Dimmer +//#define USE_HOTPLUG // Add support for sensor HotPlug +//#undef USE_DEVICE_GROUPS // Disable support for device groups (+5k6 code) +#undef USE_PWM_DIMMER // Disable support for MJ-SD01/acenx/NTONPOWER PWM dimmers (+4k5 code) +#undef USE_KEELOQ // Disable support for Jarolift rollers by Keeloq algorithm (+4k5 code) +#undef USE_SONOFF_D1 // Disable support for Sonoff D1 Dimmer (+0k7 code) +#undef USE_SHELLY_DIMMER // Disable support for Shelly Dimmer (+3k code) + +#define USE_LIGHT_PALETTE // Add support for color palette (+0k9 code) + +#define USE_DS18x20 // Add support for DS18x20 sensors with id sort, single scan and read retry (+1k3 code) + +#define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram) +#define USE_SHT // [I2cDriver8] Enable SHT1X sensor (+1k4 code) +#define USE_HTU // [I2cDriver9] Enable HTU21/SI7013/SI7020/SI7021 sensor (I2C address 0x40) (+1k5 code) +#define USE_BMP // [I2cDriver10] Enable BMP085/BMP180/BMP280/BME280 sensors (I2C addresses 0x76 and 0x77) (+4k4 code) + #define USE_BME680 // Enable support for BME680 sensor using Bosch BME680 library (+4k code) +#define USE_BH1750 // [I2cDriver11] Enable BH1750 sensor (I2C address 0x23 or 0x5C) (+0k5 code) +#define USE_VEML6070 // [I2cDriver12] Enable VEML6070 sensor (I2C addresses 0x38 and 0x39) (+1k5 code) +//#define USE_VEML6075 // [I2cDriver49] Enable VEML6075 UVA/UVB/UVINDEX Sensor (I2C address 0x10) (+2k1 code) +//#define USE_VEML7700 // [I2cDriver50] Enable VEML7700 Ambient Light sensor (I2C addresses 0x10) (+4k5 code) +#define USE_ADS1115 // [I2cDriver13] Enable ADS1115 16 bit A/D converter (I2C address 0x48, 0x49, 0x4A or 0x4B) based on Adafruit ADS1x15 library (no library needed) (+0k7 code) +#define USE_INA219 // [I2cDriver14] Enable INA219 (I2C address 0x40, 0x41 0x44 or 0x45) Low voltage and current sensor (+1k code) +//#define USE_INA226 // [I2cDriver35] Enable INA226 (I2C address 0x40, 0x41 0x44 or 0x45) Low voltage and current sensor (+2k3 code) +#define USE_SHT3X // [I2cDriver15] Enable SHT3x (I2C address 0x44 or 0x45) or SHTC3 (I2C address 0x70) sensor (+0k7 code) +#define USE_TSL2561 // [I2cDriver16] Enable TSL2561 sensor (I2C address 0x29, 0x39 or 0x49) using library Joba_Tsl2561 (+2k3 code) +//#define USE_TSL2591 // [I2cDriver40] Enable TSL2591 sensor (I2C address 0x29) using library Adafruit_TSL2591 (+1k6 code) +#define USE_MGS // [I2cDriver17] Enable Xadow and Grove Mutichannel Gas sensor using library Multichannel_Gas_Sensor (+10k code) +#define USE_SGP30 // [I2cDriver18] Enable SGP30 sensor (I2C address 0x58) (+1k1 code) +//#define USE_SI1145 // [I2cDriver19] Enable SI1145/46/47 sensor (I2C address 0x60) (+1k code) +#define USE_LM75AD // [I2cDriver20] Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code) +//#define USE_APDS9960 // [I2cDriver21] Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code) +//#define USE_MCP230xx // [I2cDriver22] Enable MCP23008/MCP23017 - Must define I2C Address in #define USE_MCP230xx_ADDR below - range 0x20 - 0x27 (+4k7 code) +//#define USE_PCA9685 // [I2cDriver1] Enable PCA9685 I2C HW PWM Driver - Must define I2C Address in #define USE_PCA9685_ADDR below - range 0x40 - 0x47 (+1k4 code) +//#define USE_MPR121 // [I2cDriver23] Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code) +#define USE_CCS811 // [I2cDriver24] Enable CCS811 sensor (I2C address 0x5A) (+2k2 code) +#define USE_MPU6886 // [I2cDriver??] Enable MPU6886 6-axis MotionTracking sensor (I2C address 0x68) +//#define USE_MPU6050 // [I2cDriver25] Enable MPU6050 sensor (I2C address 0x68 AD0 low or 0x69 AD0 high) (+3K3 of code and 188 Bytes of RAM) +//#define USE_DS3231 // [I2cDriver26] Enable DS3231 external RTC in case no Wifi is avaliable. See docs in the source file (+1k2 code) +//#define USE_MGC3130 // [I2cDriver27] Enable MGC3130 Electric Field Effect Sensor (I2C address 0x42) (+2k7 code, 0k3 mem) +//#define USE_MAX44009 // [I2cDriver28] Enable MAX44009 Ambient Light sensor (I2C addresses 0x4A and 0x4B) (+0k8 code) +#define USE_SCD30 // [I2cDriver29] Enable Sensiron SCd30 CO2 sensor (I2C address 0x61) (+3k3 code) +//#define USE_SPS30 // [I2cDriver30] Enable Sensiron SPS30 particle sensor (I2C address 0x69) (+1.7 code) +#define USE_ADE7953 // [I2cDriver7] Enable ADE7953 Energy monitor as used on Shelly 2.5 (I2C address 0x38) (+1k5) +//#define USE_VL53L0X // [I2cDriver31] Enable VL53L0x time of flight sensor (I2C address 0x29) (+4k code) +//#define USE_VL53L1X // [I2cDriver54] Enable VL53L1X time of flight sensor (I2C address 0x29) using Pololu VL53L1X library (+2k9 code) +//#define USE_TOF10120 // [I2cDriver57] Enable TOF10120 time of flight sensor (I2C address 0x52) (+0k6 code) +//#define USE_MLX90614 // [I2cDriver32] Enable MLX90614 ir temp sensor (I2C address 0x5a) (+0.6k code) +//#define USE_CHIRP // [I2cDriver33] Enable CHIRP soil moisture sensor (variable I2C address, default 0x20) +//#define USE_PAJ7620 // [I2cDriver34] Enable PAJ7620 gesture sensor (I2C address 0x73) (+2.5k code) +//#define USE_PCF8574 // [I2cDriver2] Enable PCF8574 I/O Expander (I2C addresses 0x20 - 0x26 and 0x39 - 0x3F) (+1k9 code) +#define USE_HIH6 // [I2cDriver36] Enable Honeywell HIH Humidity and Temperature sensor (I2C address 0x27) (+0k6) +#define USE_DHT12 // [I2cDriver41] Enable DHT12 humidity and temperature sensor (I2C address 0x5C) (+0k7 code) +#define USE_DS1624 // [I2cDriver42] Enable DS1624, DS1621 temperature sensor (I2C addresses 0x48 - 0x4F) (+1k2 code) +//#define USE_AHT1x // [I2cDriver43] Enable AHT10/15 humidity and temperature sensor (I2C address 0x38, 0x39) (+0k8 code) +// #define USE_AHT2x // [I2cDriver43] Enable AHT20 instead of AHT1x humidity and temperature sensor (I2C address 0x38) (+0k8 code) +#define USE_WEMOS_MOTOR_V1 // [I2cDriver44] Enable Wemos motor driver V1 (I2C addresses 0x2D - 0x30) (+0k7 code) + #define WEMOS_MOTOR_V1_ADDR 0x30 // Default I2C address 0x30 + #define WEMOS_MOTOR_V1_FREQ 1000 // Default frequency +//#define USE_HDC1080 // [I2cDriver45] Enable HDC1080 temperature/humidity sensor (I2C address 0x40) (+1k5 code) +#define USE_IAQ // [I2cDriver46] Enable iAQ-core air quality sensor (I2C address 0x5a) (+0k6 code) +#define USE_AS3935 // [I2cDriver48] Enable AS3935 Franklin Lightning Sensor (I2C address 0x03) (+5k4 code) +//#define USE_MCP9808 // [I2cDriver51] Enable MCP9808 temperature sensor (I2C addresses 0x18 - 0x1F) (+0k9 code) +//#define USE_HP303B // [I2cDriver52] Enable HP303B temperature and pressure sensor (I2C address 0x76 or 0x77) (+6k2 code) +//#define USE_MLX90640 // [I2cDriver53] Enable MLX90640 IR array temperature sensor (I2C address 0x33) (+20k code) +//#define USE_EZOPH // [I2cDriver55] Enable support for EZO's pH sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code) +//#define USE_EZOORP // [I2cDriver55] Enable support for EZO's ORP sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code) +//#define USE_EZORTD // [I2cDriver55] Enable support for EZO's RTD sensor (+0k2 code) - Shared EZO code required for any EZO device (+1k2 code) +//#define USE_EZOHUM // [I2cDriver55] Enable support for EZO's HUM sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code) +//#define USE_EZOEC // [I2cDriver55] Enable support for EZO's EC sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code) +//#define USE_EZOCO2 // [I2cDriver55] Enable support for EZO's CO2 sensor (+0k2 code) - Shared EZO code required for any EZO device (+1k2 code) +//#define USE_EZOO2 // [I2cDriver55] Enable support for EZO's O2 sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code) +//#define USE_EZOPRS // [I2cDriver55] Enable support for EZO's PRS sensor (+0k7 code) - Shared EZO code required for any EZO device (+1k2 code) +//#define USE_EZOFLO // [I2cDriver55] Enable support for EZO's FLO sensor (+0k4 code) - Shared EZO code required for any EZO device (+1k2 code) +//#define USE_EZODO // [I2cDriver55] Enable support for EZO's DO sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code) +//#define USE_EZORGB // [I2cDriver55] Enable support for EZO's RGB sensor (+0k5 code) - Shared EZO code required for any EZO device (+1k2 code) +//#define USE_EZOPMP // [I2cDriver55] Enable support for EZO's PMP sensor (+0k3 code) - Shared EZO code required for any EZO device (+1k2 code) +//#define USE_SEESAW_SOIL // [I2cDriver56] Enable Capacitice Soil Moisture & Temperature Sensor (I2C addresses 0x36 - 0x39) (+1k3 code) + +//#define USE_SPI // Hardware SPI using GPIO12(MISO), GPIO13(MOSI) and GPIO14(CLK) in addition to two user selectable GPIOs(CS and DC) +//#define USE_RC522 // Add support for MFRC522 13.56Mhz Rfid reader (+6k 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 + #define CO2_LOW 800 // Below this CO2 value show green light (needs PWM or WS2812 RG(B) led and enable with SetOption18 1) +#endif +#ifndef CO2_HIGH + #define CO2_HIGH 1200 // Above this CO2 value show red light (needs PWM or WS2812 RG(B) led and enable with SetOption18 1) +#endif +#define USE_PMS5003 // Add support for PMS5003 and PMS7003 particle concentration sensor (+1k3 code) + //#define PMS_MODEL_PMS3003 // Enable support of PMS3003 instead of PMS5003/PMS7003 (needs the USE_PMS5003 above) +#define USE_NOVA_SDS // Add support for SDS011 and SDS021 particle concentration sensor (+0k7 code) +#define USE_HPMA // Add support for Honeywell HPMA115S0 particle concentration sensor +#define USE_SR04 // Add support for HC-SR04 ultrasonic devices (+1k code) +//#define USE_DYP // Add support for DYP ME-007 ultrasonic distance sensor, serial port version (+0k5 code) +#define USE_SERIAL_BRIDGE // Add support for software Serial Bridge (+0k8 code) +#define USE_MP3_PLAYER // Use of the DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop + #define MP3_VOLUME 10 // Set the startup volume on init, the range can be 0..30(max) +//#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_ZIGBEE // Enable serial communication with Zigbee CC2530 flashed with ZNP +#define USE_RDM6300 // Add support for RDM6300 125kHz RFID Reader (+0k8) +#define USE_IBEACON // Add support for bluetooth LE passive scan of ibeacon devices (uses HM17 module) +//#define USE_GPS // Add support for GPS and NTP Server for becoming Stratus 1 Time Source (+ 3.1kb flash, +132 bytes RAM) + +//#define USE_BLE_ESP32 // (ESP32 only) Add support for native BLE on ESP32 - use new driver +//#define USE_MI_ESP32 // (ESP32 only) Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash) + +#define USE_HRXL // Add support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7) +//#define USE_TASMOTA_CLIENT // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem) +//#define USE_OPENTHERM // Add support for OpenTherm (+15k code) +//#define USE_MIEL_HVAC // Add support for Mitsubishi Electric HVAC serial interface (+5k code) +//#define USE_PROJECTOR_CTRL // Add support for LCD/DLP Projector serial control interface (+2k code) +// #define USE_PROJECTOR_CTRL_NEC // Use codes for NEC +// #define USE_PROJECTOR_CTRL_OPTOMA // Use codes for OPTOMA +//#define USE_AS608 // Add support for AS608 optical and R503 capacitive fingerprint sensor (+3k4 code) + +#define USE_ENERGY_SENSOR // Add energy sensors (-14k code) +#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_SDM72 // Add support for Eastron SDM72-Modbus energy monitor (+0k3 code) +#define USE_SDM120 // Add support for Eastron SDM120-Modbus energy monitor (+1k1 code) +#define USE_SDM630 // Add support for Eastron SDM630-Modbus energy monitor (+0k6 code) +#define USE_DDS2382 // Add support for Hiking DDS2382 Modbus energy monitor (+0k6 code) +#define USE_DDSU666 // Add support for Chint DDSU666 Modbus energy monitor (+0k6 code) +//#define USE_SOLAX_X1 // Add support for Solax X1 series Modbus log info (+3k1 code) +//#define USE_LE01MR // Add support for F&F LE-01MR modbus energy meter (+2k code) +//#define USE_TELEINFO // Add support for French Energy Provider metering telemetry (+5k2 code, +168 RAM + SmartMeter LinkedList Values RAM) +//#define USE_WE517 // Add support for Orno WE517-Modbus energy monitor (+1k code) + +#define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor +#define USE_MAX31855 // Add support for MAX31855 K-Type thermocouple sensor using softSPI +//#define USE_MAX31865 // Add support for MAX31865 RTD sensors using softSPI +#define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0k3 mem, 48 iram) + #define USE_IR_RECEIVE // Support for IR receiver (+5k5 code, 264 iram) +#define USE_LMT01 // Add support for TI LMT01 temperature sensor, count pulses on single GPIO (+0k5 code) +//#define USE_WIEGAND // Add support for 24/26/32/34 bit RFID Wiegand interface (D0/D1) (+1k7 code) +#define USE_TM1638 // Add support for TM1638 switches copying Switch1 .. Switch8 (+1k code) +#define USE_HX711 // Add support for HX711 load cell (+1k5 code) +//#define USE_HX711_GUI // Add optional web GUI to HX711 as scale (+1k8 code) +//#define USE_TX20_WIND_SENSOR // Add support for La Crosse TX20 anemometer (+2k6/0k8 code) +//#define USE_TX23_WIND_SENSOR // Add support for La Crosse TX23 anemometer (+2k7/1k code) +//#define USE_WINDMETER // Add support for analog anemometer (+2k2 code) +#define USE_RC_SWITCH // Add support for RF transceiver using library RcSwitch (+2k7 code, 460 iram) +#define USE_RF_SENSOR // Add support for RF sensor receiver (434MHz or 868MHz) (+0k8 code) +// #define USE_THEO_V2 // Add support for decoding Theo V2 sensors as documented on https://sidweb.nl using 434MHz RF sensor receiver (+1k4 code) + #define USE_ALECTO_V2 // Add support for decoding Alecto V2 sensors like ACH2010, WS3000 and DKW2012 using 868MHz RF sensor receiver (+1k7 code) +#define USE_HRE // Add support for Badger HR-E Water Meter (+1k4 code) +//#define USE_A4988_STEPPER // Add support for A4988/DRV8825 stepper-motor-driver-circuit (+10k5 code) +//#define USE_THERMOSTAT // Add support for Thermostat + +#ifndef USE_KNX +#define USE_KNX // Enable KNX IP Protocol Support (+23k code, +3k3 mem) +#endif + +#endif // FIRMWARE_TASMOTA32 + +#endif // ESP32 #endif // _TASMOTA_CONFIGURATIONS_ESP32_H_ diff --git a/tasmota/tasmota_globals.h b/tasmota/tasmota_globals.h index 52149943c..110277cc2 100644 --- a/tasmota/tasmota_globals.h +++ b/tasmota/tasmota_globals.h @@ -270,8 +270,8 @@ const uint16_t LOG_BUFFER_SIZE = 4000; // Max number of characters in lo #ifndef MQTT_KEEPALIVE #define MQTT_KEEPALIVE 30 // Seconds #endif -#ifndef MQTT_TIMEOUT -#define MQTT_TIMEOUT 10000 // milli seconds +#ifndef MQTT_SOCKET_TIMEOUT +#define MQTT_SOCKET_TIMEOUT 4 // Seconds #endif #ifndef MQTT_CLEAN_SESSION #define MQTT_CLEAN_SESSION 1 // 0 = No clean session, 1 = Clean session (default) diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index 7b9bac855..197596b7b 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -52,7 +52,7 @@ enum UserSelectablePins { GPIO_SR04_TRIG, GPIO_SR04_ECHO, // SR04 interface GPIO_SDM120_TX, GPIO_SDM120_RX, // SDM120 Serial interface GPIO_SDM630_TX, GPIO_SDM630_RX, // SDM630 Serial interface - GPIO_TM16CLK, GPIO_TM16DIO, GPIO_TM16STB, // TM1638 interface + GPIO_TM1638CLK, GPIO_TM1638DIO, GPIO_TM1638STB, // TM1638 interface GPIO_MP3_DFR562, // RB-DFR-562, DFPlayer Mini MP3 Player GPIO_HX711_SCK, GPIO_HX711_DAT, // HX711 Load Cell interface GPIO_TX2X_TXD_BLACK, // TX20/TX23 Transmission Pin @@ -154,6 +154,7 @@ enum UserSelectablePins { GPIO_SSD1351_DC, GPIO_XPT2046_CS, // XPT2046 SPI Chip Select GPIO_CSE7761_TX, GPIO_CSE7761_RX, // CSE7761 Serial interface (Dual R3) + GPIO_VL53L0X_XSHUT1, // VL53L0X_XSHUT (the max number of sensors is VL53L0X_MAX_SENSORS)- Used when connecting multiple VL53L0X GPIO_SENSOR_END }; enum ProgramSelectablePins { @@ -328,6 +329,7 @@ const char kSensorNames[] PROGMEM = D_SENSOR_SSD1351_DC "|" D_SENSOR_XPT2046_CS "|" D_SENSOR_CSE7761_TX "|" D_SENSOR_CSE7761_RX "|" + D_SENSOR_VL53L0X_XSHUT "|" ; const char kSensorNamesFixed[] PROGMEM = @@ -408,11 +410,13 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_SDCARD_CS), #endif // USE_SDCARD #endif // USE_SPI + AGPIO(GPIO_SSPI_MISO), // Software SPI Master Input Client Output AGPIO(GPIO_SSPI_MOSI), // Software SPI Master Output Client Input AGPIO(GPIO_SSPI_SCLK), // Software SPI Serial Clock AGPIO(GPIO_SSPI_CS), // Software SPI Chip Select AGPIO(GPIO_SSPI_DC), // Software SPI Data or Command + #ifdef USE_DISPLAY #ifdef USE_DISPLAY_ILI9341 AGPIO(GPIO_ILI9341_CS), @@ -420,7 +424,6 @@ const uint16_t kGpioNiceList[] PROGMEM = { #ifdef USE_XPT2046 AGPIO(GPIO_XPT2046_CS), // XPT2046 SPI Chip Select #endif - #endif // USE_DISPLAY_ILI9341 #ifdef USE_DISPLAY_ILI9488 AGPIO(GPIO_ILI9488_CS), @@ -449,6 +452,9 @@ const uint16_t kGpioNiceList[] PROGMEM = { #ifdef USE_DISPLAY_TM1637 AGPIO(GPIO_TM1637CLK), AGPIO(GPIO_TM1637DIO), + AGPIO(GPIO_TM1638CLK), + AGPIO(GPIO_TM1638DIO), + AGPIO(GPIO_TM1638STB), #endif // USE_DISPLAY_TM1637 AGPIO(GPIO_BACKLIGHT), // Display backlight control AGPIO(GPIO_OLED_RESET), // OLED Display Reset @@ -547,9 +553,9 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_SR04_ECHO), // SR04 Ech/RXo pin #endif #ifdef USE_TM1638 - AGPIO(GPIO_TM16CLK), // TM1638 Clock - AGPIO(GPIO_TM16DIO), // TM1638 Data I/O - AGPIO(GPIO_TM16STB), // TM1638 Strobe + AGPIO(GPIO_TM1638CLK), // TM1638 Clock + AGPIO(GPIO_TM1638DIO), // TM1638 Data I/O + AGPIO(GPIO_TM1638STB), // TM1638 Strobe #endif #ifdef USE_HX711 AGPIO(GPIO_HX711_SCK), // HX711 Load Cell clock @@ -781,6 +787,10 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_PROJECTOR_CTRL_TX), // LCD/DLP Projector Serial Control AGPIO(GPIO_PROJECTOR_CTRL_RX), // LCD/DLP Projector Serial Control #endif +#ifdef USE_VL53L0X + AGPIO(GPIO_VL53L0X_XSHUT1) + VL53L0X_MAX_SENSORS, // When using multiple VL53L0X. +#endif + /*-------------------------------------------------------------------------------------------*\ * ESP32 specifics \*-------------------------------------------------------------------------------------------*/ diff --git a/tasmota/tasmota_template_legacy.h b/tasmota/tasmota_template_legacy.h index 4d5f2c507..4583a9783 100644 --- a/tasmota/tasmota_template_legacy.h +++ b/tasmota/tasmota_template_legacy.h @@ -334,9 +334,9 @@ const uint16_t kGpioConvert[] PROGMEM = { AGPIO(GPIO_SDM120_RX), // SDM120 Serial interface AGPIO(GPIO_SDM630_TX), // SDM630 Serial interface AGPIO(GPIO_SDM630_RX), // SDM630 Serial interface - AGPIO(GPIO_TM16CLK), // TM1638 Clock - AGPIO(GPIO_TM16DIO), // TM1638 Data I/O - AGPIO(GPIO_TM16STB), // TM1638 Strobe + AGPIO(GPIO_TM1638CLK), // TM1638 Clock + AGPIO(GPIO_TM1638DIO), // TM1638 Data I/O + AGPIO(GPIO_TM1638STB), // TM1638 Strobe AGPIO(GPIO_SWT1_NP), // Switch no pullup AGPIO(GPIO_SWT1_NP) +1, AGPIO(GPIO_SWT1_NP) +2, diff --git a/tasmota/tasmota_version.h b/tasmota/tasmota_version.h index 26807fb8f..e26ffc875 100644 --- a/tasmota/tasmota_version.h +++ b/tasmota/tasmota_version.h @@ -20,6 +20,6 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x09030101; +const uint32_t VERSION = 0x09030102; #endif // _TASMOTA_VERSION_H_ diff --git a/tasmota/xdrv_02_mqtt.ino b/tasmota/xdrv_02_mqtt.ino index 02fe422f1..c31b2f4a7 100644 --- a/tasmota/xdrv_02_mqtt.ino +++ b/tasmota/xdrv_02_mqtt.ino @@ -23,6 +23,8 @@ #define MQTT_WIFI_CLIENT_TIMEOUT 200 // Wifi TCP connection timeout (default is 5000 mSec) #endif +#define USE_MQTT_NEW_PUBSUBCLIENT + // #define DEBUG_DUMP_TLS // allow dumping of TLS Flash keys #ifdef USE_MQTT_TLS @@ -42,7 +44,7 @@ const char kMqttCommands[] PROGMEM = "|" // No prefix #if defined(USE_MQTT_TLS) && !defined(USE_MQTT_TLS_CA_CERT) D_CMND_MQTTFINGERPRINT "|" #endif - D_CMND_MQTTUSER "|" D_CMND_MQTTPASSWORD "|" + D_CMND_MQTTUSER "|" D_CMND_MQTTPASSWORD "|" D_CMND_MQTTKEEPALIVE "|" D_CMND_MQTTTIMEOUT "|" #if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT) D_CMND_TLSKEY "|" #endif @@ -68,7 +70,7 @@ void (* const MqttCommand[])(void) PROGMEM = { #if defined(USE_MQTT_TLS) && !defined(USE_MQTT_TLS_CA_CERT) &CmndMqttFingerprint, #endif - &CmndMqttUser, &CmndMqttPassword, + &CmndMqttUser, &CmndMqttPassword, &CmndMqttKeepAlive, &CmndMqttTimeout, #if defined(USE_MQTT_TLS) && defined(USE_MQTT_AWS_IOT) &CmndTlsKey, #endif @@ -209,6 +211,9 @@ void MqttInit(void) { #else // USE_MQTT_TLS MqttClient.setClient(EspClient); #endif // USE_MQTT_TLS + + MqttClient.setKeepAlive(Settings.mqtt_keepalive); + MqttClient.setSocketTimeout(Settings.mqtt_socket_timeout); } bool MqttIsConnected(void) { @@ -311,7 +316,7 @@ void MqttUnsubscribe(const char *topic) { void MqttPublishLoggingAsync(bool refresh) { static uint32_t index = 1; - if (!Settings.mqttlog_level || !Settings.flag.mqtt_enabled) { return; } // SetOption3 - Enable MQTT + if (!Settings.mqttlog_level || !Settings.flag.mqtt_enabled || !Mqtt.connected) { return; } // SetOption3 - Enable MQTT if (refresh && !NeedLogRefresh(Settings.mqttlog_level, index)) { return; } char* line; @@ -829,6 +834,26 @@ void CmndMqttPassword(void) { } } +void CmndMqttKeepAlive(void) { + if ((XdrvMailbox.payload >= 1) && (XdrvMailbox.payload <= 100)) { + Settings.mqtt_keepalive = XdrvMailbox.payload; +#ifdef USE_MQTT_NEW_PUBSUBCLIENT + MqttClient.setKeepAlive(Settings.mqtt_keepalive); +#endif + } + ResponseCmndNumber(Settings.mqtt_keepalive); +} + +void CmndMqttTimeout(void) { + if ((XdrvMailbox.payload >= 1) && (XdrvMailbox.payload <= 100)) { + Settings.mqtt_socket_timeout = XdrvMailbox.payload; +#ifdef USE_MQTT_NEW_PUBSUBCLIENT + MqttClient.setSocketTimeout(Settings.mqtt_socket_timeout); +#endif + } + ResponseCmndNumber(Settings.mqtt_socket_timeout); +} + void CmndMqttlog(void) { if ((XdrvMailbox.payload >= LOG_LEVEL_NONE) && (XdrvMailbox.payload <= LOG_LEVEL_DEBUG_MORE)) { Settings.mqttlog_level = XdrvMailbox.payload; diff --git a/tasmota/xdrv_10_rules.ino b/tasmota/xdrv_10_rules.ino index cdf374a27..b4e21e578 100644 --- a/tasmota/xdrv_10_rules.ino +++ b/tasmota/xdrv_10_rules.ino @@ -882,7 +882,7 @@ void RulesEvery50ms(void) // Boot time SWITCHES Status for (uint32_t i = 0; i < MAX_SWITCHES; i++) { #ifdef USE_TM1638 - if (PinUsed(GPIO_SWT1, i) || (PinUsed(GPIO_TM16CLK) && PinUsed(GPIO_TM16DIO) && PinUsed(GPIO_TM16STB))) { + if (PinUsed(GPIO_SWT1, i) || (PinUsed(GPIO_TM1638CLK) && PinUsed(GPIO_TM1638DIO) && PinUsed(GPIO_TM1638STB))) { #else if (PinUsed(GPIO_SWT1, i)) { #endif // USE_TM1638 diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index 3c230c8b1..97ebfad30 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -56,7 +56,9 @@ keywords if then else endif, or, and are better readable for beginners (others m #define MAXFILT 5 #endif #define SCRIPT_SVARSIZE 20 +#ifndef SCRIPT_MAXSSIZE #define SCRIPT_MAXSSIZE 48 +#endif #define SCRIPT_EOL '\n' #define SCRIPT_FLOAT_PRECISION 2 #define PMEM_SIZE sizeof(Settings.script_pram) @@ -221,7 +223,7 @@ extern FS *ufsp; #endif // USE_UFILESYS -extern "C" void homekit_main(char *); +extern "C" void homekit_main(char *, uint32_t); #ifdef SUPPORT_MQTT_EVENT #include // Import LinkedList library @@ -244,7 +246,7 @@ extern VButton *buttons[MAX_TOUCH_BUTTONS]; #endif typedef union { -#ifdef USE_SCRIPT_GLOBVARS +#if defined(USE_SCRIPT_GLOBVARS) || defined(USE_HOMEKIT) uint16_t data; #else uint8_t data; @@ -260,6 +262,9 @@ typedef union { uint8_t constant : 1; #ifdef USE_SCRIPT_GLOBVARS uint8_t global : 1; +#endif +#ifdef USE_SCRIPT_GLOBVARS + uint8_t hchanged : 1; #endif }; } SCRIPT_TYPE; @@ -490,7 +495,7 @@ void ScriptEverySecond(void) { uint8_t homekit_found = Run_Scripter(">h", -2, 0); if (homekit_found == 99) { if (!TasmotaGlobal.global_state.wifi_down) { - homekit_main(glob_script_mem.section_ptr); + homekit_main(glob_script_mem.section_ptr, 0); glob_script_mem.homekit_running = true; } } @@ -504,6 +509,15 @@ void RulesTeleperiod(void) { if (bitRead(Settings.rule_enabled, 0) && TasmotaGlobal.mqtt_data[0]) Run_Scripter(">T", 2, TasmotaGlobal.mqtt_data); } +void SetChanged(uint32_t index) { + glob_script_mem.type[index].bits.changed = 1; +#ifdef USE_HOMEKIT + glob_script_mem.type[index].bits.hchanged = 1; +#endif +//AddLog(LOG_LEVEL_INFO, PSTR("Change: %d"), index); +} + + #define SCRIPT_SKIP_SPACES while (*lp==' ' || *lp=='\t') lp++; #define SCRIPT_SKIP_EOL while (*lp==SCRIPT_EOL) lp++; @@ -1015,7 +1029,7 @@ void Script_PollUdp(void) { if (res) { // mark changed glob_script_mem.last_udp_ip = glob_script_mem.Script_PortUdp.remoteIP(); - glob_script_mem.type[index].bits.changed = 1; + SetChanged(index); if (glob_script_mem.glob_script == 99) { Run_Scripter(">G", 2, 0); } @@ -2497,14 +2511,19 @@ chknext: #endif //USE_LIGHT #ifdef USE_HOMEKIT - if (!strncmp(vname, "hki", 3)) { + if (!strncmp(vname, "hki(", 4)) { if (!TasmotaGlobal.global_state.wifi_down) { // erase nvs - homekit_main(0); - // restart homekit - glob_script_mem.homekit_running = false; + lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); + + homekit_main(0, fvar); + if (fvar >= 98) { + glob_script_mem.homekit_running == false; + } + } - fvar = 0; + lp++; + len = 0; goto exit; } #endif @@ -3568,13 +3587,53 @@ char *ForceStringVar(char *lp, char *dstr) { return lp; } +#ifdef USE_HOMEKIT extern "C" { uint32_t Ext_UpdVar(char *vname, float *fvar, uint32_t mode) { return UpdVar(vname, fvar, mode); } + void Ext_toLog(char *str) { + toLog(str); + } + + char *GetFName(void) { + return SettingsText(SET_FRIENDLYNAME1); + } } -uint32_t UpdVar(char *vname, float *fvar, uint32_t mode) { +int32_t UpdVar(char *vname, float *fvar, uint32_t mode) { + uint8_t type; + uint8_t index; + if (*vname == '@') { + vname++; + type = *vname; + vname++; + index = (*vname & 0x0f); + if (index < 1) index = 1; + if (index > 9) index = 9; + switch (type) { + case 'p': + if (mode) { + // set power + ExecuteCommandPower(index, *fvar, SRC_BUTTON); + return 0; + } else { + // read power + *fvar = bitRead(TasmotaGlobal.power, index - 1); + return 1; + } + break; + case 's': + *fvar = SwitchLastState(index - 1); + return 1; + break; + case 'b': + *fvar = Button.last_state[index - 1]; + return 1; + break; + } + return 0; + } struct T_INDEX ind; uint8_t vtype; float res = *fvar; @@ -3584,16 +3643,22 @@ uint32_t UpdVar(char *vname, float *fvar, uint32_t mode) { if (vtype == NUM_RES || (vtype & STYPE) == 0) { if (mode) { // set var - uint8_t index = glob_script_mem.type[ind.index].index; + index = glob_script_mem.type[ind.index].index; glob_script_mem.fvars[index] = res; - glob_script_mem.type[index].bits.changed = 1; + glob_script_mem.type[ind.index].bits.changed = 1; + return 0; + } else { + // get var + //index = glob_script_mem.type[ind.index].index; + int32_t ret = glob_script_mem.type[ind.index].bits.hchanged; + glob_script_mem.type[ind.index].bits.hchanged = 0; + return ret; } - return 0; } else { // break; } } - return 1; + return -1; } @@ -3602,6 +3667,9 @@ extern "C" { Replace_Cmd_Vars(srcbuf, srcsize, dstbuf, dstsize); } } + +#endif // USE_HOMEKIT + // replace vars in cmd %var% void Replace_Cmd_Vars(char *srcbuf, uint32_t srcsize, char *dstbuf, uint32_t dstsize) { char *cp; @@ -3697,13 +3765,11 @@ void Replace_Cmd_Vars(char *srcbuf, uint32_t srcsize, char *dstbuf, uint32_t dst dstbuf[count] = 0; } - void toLog(const char *str) { if (!str) return; AddLog(LOG_LEVEL_INFO, str); } - void toLogN(const char *cp, uint8_t len) { if (!cp) return; char str[32]; @@ -4575,7 +4641,7 @@ int16_t Run_script_sub(const char *type, int8_t tlen, struct GVARS *gv) { break; } // var was changed - glob_script_mem.type[globvindex].bits.changed = 1; + SetChanged(globvindex); #ifdef USE_SCRIPT_GLOBVARS if (glob_script_mem.type[globvindex].bits.global) { script_udp_sendvar(varname, dfvar, 0); @@ -4633,7 +4699,7 @@ int16_t Run_script_sub(const char *type, int8_t tlen, struct GVARS *gv) { if (!glob_script_mem.var_not_found) { // var was changed - glob_script_mem.type[globvindex].bits.changed = 1; + SetChanged(globvindex); #ifdef USE_SCRIPT_GLOBVARS if (glob_script_mem.type[globvindex].bits.global) { script_udp_sendvar(varname, 0, str); @@ -5631,7 +5697,7 @@ void Script_Handle_Hue(String *path) { glob_script_mem.fvars[hue_script[index].index[0] - 1] = 1; response.replace("{re", "true"); } - glob_script_mem.type[hue_script[index].vindex[0]].bits.changed = 1; + SetChanged(hue_script[index].vindex[0]); resp = true; } @@ -5647,7 +5713,7 @@ void Script_Handle_Hue(String *path) { response.replace("{cm", "bri"); response.replace("{re", String(tmp)); glob_script_mem.fvars[hue_script[index].index[1] - 1] = bri; - glob_script_mem.type[hue_script[index].vindex[1]].bits.changed = 1; + SetChanged(hue_script[index].vindex[1]); resp = true; } @@ -5670,9 +5736,9 @@ void Script_Handle_Hue(String *path) { response.replace("{cm", "xy"); response.replace("{re", "[" + x_str + "," + y_str + "]"); glob_script_mem.fvars[hue_script[index].index[2]-1] = hue; - glob_script_mem.type[hue_script[index].vindex[2]].bits.changed = 1; + SetChanged(hue_script[index].vindex[2]); glob_script_mem.fvars[hue_script[index].index[3]-1] = sat; - glob_script_mem.type[hue_script[index].vindex[3]].bits.changed = 1; + SetChanged(hue_script[index].vindex[3]); resp = true; } @@ -5688,7 +5754,7 @@ void Script_Handle_Hue(String *path) { response.replace("{cm", "hue"); response.replace("{re", String(tmp)); glob_script_mem.fvars[hue_script[index].index[2] - 1] = hue; - glob_script_mem.type[hue_script[index].vindex[2]].bits.changed = 1; + SetChanged(hue_script[index].vindex[2]); resp = true; } @@ -5703,7 +5769,7 @@ void Script_Handle_Hue(String *path) { response.replace("{cm", "sat"); response.replace("{re", String(tmp)); glob_script_mem.fvars[hue_script[index].index[3] - 1] = sat; - glob_script_mem.type[hue_script[index].vindex[3]].bits.changed = 1; + SetChanged(hue_script[index].vindex[3]); resp = true; } @@ -5716,7 +5782,7 @@ void Script_Handle_Hue(String *path) { response.replace("{cm", "ct"); response.replace("{re", String(ct)); glob_script_mem.fvars[hue_script[index].index[4] - 1] = ct; - glob_script_mem.type[hue_script[index].vindex[4]].bits.changed = 1; + SetChanged(hue_script[index].vindex[4]); resp = true; } response += "]"; diff --git a/tasmota/xdrv_12_home_assistant.ino b/tasmota/xdrv_12_home_assistant.ino index 3280c8cb0..617ec2e39 100644 --- a/tasmota/xdrv_12_home_assistant.ino +++ b/tasmota/xdrv_12_home_assistant.ino @@ -270,10 +270,10 @@ void NewHAssDiscovery(void) char stopic[TOPSZ]; char stemp1[TOPSZ]; char stemp2[200]; - char stemp3[TOPSZ]; - char stemp4[TOPSZ]; - char stemp5[TOPSZ]; - char stemp6[TOPSZ]; + char switch_mode[90]; + char switch_name[300]; + char stemp5[90]; + char stemp6[90]; char unique_id[30]; char relays[TOPSZ]; char *state_topic = stemp1; @@ -297,14 +297,14 @@ void NewHAssDiscovery(void) snprintf_P(stemp2, sizeof(stemp2), PSTR("%s%s%s"), stemp2, (i > 0 ? "," : ""), (i < maxfn) ? fname : PSTR("null")); } - stemp3[0] = '\0'; - stemp4[0] = '\0'; + switch_mode[0] = '\0'; + switch_name[0] = '\0'; // Enable Discovery for Switches only if SetOption114 is enabled for (uint32_t i = 0; i < MAX_SWITCHES; i++) { char sname[TOPSZ]; snprintf_P(sname, sizeof(sname), PSTR("\"%s\""), GetSwitchText(i).c_str()); - snprintf_P(stemp3, sizeof(stemp3), PSTR("%s%s%d"), stemp3, (i > 0 ? "," : ""), (PinUsed(GPIO_SWT1, i) & Settings.flag5.mqtt_switches) ? Settings.switchmode[i] : -1); - snprintf_P(stemp4, sizeof(stemp4), PSTR("%s%s%s"), stemp4, (i > 0 ? "," : ""), (PinUsed(GPIO_SWT1, i) & Settings.flag5.mqtt_switches) ? sname : PSTR("null")); + snprintf_P(switch_mode, sizeof(switch_mode), PSTR("%s%s%d"), switch_mode, (i > 0 ? "," : ""), (PinUsed(GPIO_SWT1, i) & Settings.flag5.mqtt_switches) ? Settings.switchmode[i] : -1); + snprintf_P(switch_name, sizeof(switch_name), PSTR("%s%s%s"), switch_name, (i > 0 ? "," : ""), (PinUsed(GPIO_SWT1, i) & Settings.flag5.mqtt_switches) ? sname : PSTR("null")); } stemp5[0] = '\0'; @@ -338,7 +338,7 @@ void NewHAssDiscovery(void) if (!Settings.flag.hass_discovery) { // HassDiscoveryRelays(relays) Response_P(HASS_DISCOVER_DEVICE, (uint32_t)WiFi.localIP(), SettingsText(SET_DEVICENAME), stemp2, TasmotaGlobal.hostname, unique_id, ModuleName().c_str(), TuyaMod, iFanMod, GetStateText(0), GetStateText(1), GetStateText(2), GetStateText(3), - TasmotaGlobal.version, TasmotaGlobal.mqtt_topic, SettingsText(SET_MQTT_FULLTOPIC), PSTR(SUB_PREFIX), PSTR(PUB_PREFIX), PSTR(PUB_PREFIX2), Hass.RelLst, stemp3, stemp4, + TasmotaGlobal.version, TasmotaGlobal.mqtt_topic, SettingsText(SET_MQTT_FULLTOPIC), PSTR(SUB_PREFIX), PSTR(PUB_PREFIX), PSTR(PUB_PREFIX2), Hass.RelLst, switch_mode, switch_name, stemp5, Settings.flag.mqtt_response, Settings.flag.button_swap, Settings.flag.button_single, Settings.flag.decimal_text, Settings.flag.not_power_linked, Settings.flag.hass_light, Settings.flag3.pwm_multi_channels, Settings.flag3.mqtt_buttons, Settings.flag4.alexa_ct_range, Settings.flag5.mqtt_switches, Settings.flag5.fade_fixed_duration, light_controller.isCTRGBLinked(), Light.subtype, stemp6); diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino index 1d319750b..cf5e384eb 100755 --- a/tasmota/xdrv_13_display.ino +++ b/tasmota/xdrv_13_display.ino @@ -17,7 +17,6 @@ along with this program. If not, see . */ -#if defined(USE_I2C) || defined(USE_SPI) #ifdef USE_DISPLAY #define XDRV_13 13 @@ -43,7 +42,7 @@ uint16_t bg_color = 0; uint8_t color_type = COLOR_BW; uint8_t auto_draw = 1; -const uint8_t DISPLAY_MAX_DRIVERS = 16; // Max number of display drivers/models supported by xdsp_interface.ino +const uint8_t DISPLAY_MAX_DRIVERS = 32; // Max number of display drivers/models supported by xdsp_interface.ino const uint8_t DISPLAY_MAX_COLS = 64; // Max number of columns allowed with command DisplayCols const uint8_t DISPLAY_MAX_ROWS = 64; // Max number of lines allowed with command DisplayRows @@ -78,9 +77,6 @@ const uint8_t DISPLAY_LOG_ROWS = 32; // Number of lines in display log #define D_CMND_DISP_SCROLLDELAY "ScrollDelay" #define D_CMND_DISP_CLOCK "Clock" #define D_CMND_DISP_TEXTNC "TextNC" // NC - "No Clear" -#define D_CMND_DISP_SETLEDS "SetLEDs" -#define D_CMND_DISP_SETLED "SetLED" -#define D_CMND_DISP_BUTTONS "Buttons" #define D_CMND_DISP_SCROLLTEXT "ScrollText" #define D_CMND_DISP_ILIMODE "ILIMode" #define D_CMND_DISP_ILIINVERT "Invert" @@ -93,14 +89,13 @@ enum XdspFunctions { FUNC_DISPLAY_INIT_DRIVER, FUNC_DISPLAY_INIT, FUNC_DISPLAY_E FUNC_DISPLAY_DRAW_CIRCLE, FUNC_DISPLAY_FILL_CIRCLE, FUNC_DISPLAY_DRAW_RECTANGLE, FUNC_DISPLAY_FILL_RECTANGLE, FUNC_DISPLAY_TEXT_SIZE, FUNC_DISPLAY_FONT_SIZE, FUNC_DISPLAY_ROTATION, FUNC_DISPLAY_DRAW_STRING, - FUNC_DISPLAY_DIM, FUNC_DISPLAY_BLINKRATE + FUNC_DISPLAY_DIM, FUNC_DISPLAY_BLINKRATE, #ifdef USE_UFILESYS - ,FUNC_DISPLAY_BATCH + FUNC_DISPLAY_BATCH, #endif - , FUNC_DISPLAY_NUMBER, FUNC_DISPLAY_FLOAT, FUNC_DISPLAY_NUMBERNC, FUNC_DISPLAY_FLOATNC, - FUNC_DISPLAY_BRIGHTNESS, FUNC_DISPLAY_RAW, FUNC_DISPLAY_LEVEL, FUNC_DISPLAY_SEVENSEG_TEXT, FUNC_DISPLAY_SEVENSEG_TEXTNC, - FUNC_DISPLAY_SCROLLDELAY, FUNC_DISPLAY_CLOCK, FUNC_DISPLAY_SETLEDS, FUNC_DISPLAY_SETLED, - FUNC_DISPLAY_BUTTONS, FUNC_DISPLAY_SCROLLTEXT + FUNC_DISPLAY_NUMBER, FUNC_DISPLAY_FLOAT, FUNC_DISPLAY_NUMBERNC, FUNC_DISPLAY_FLOATNC, + FUNC_DISPLAY_RAW, FUNC_DISPLAY_LEVEL, FUNC_DISPLAY_SEVENSEG_TEXT, FUNC_DISPLAY_SEVENSEG_TEXTNC, + FUNC_DISPLAY_SCROLLDELAY, FUNC_DISPLAY_CLOCK, FUNC_DISPLAY_SCROLLTEXT }; enum DisplayInitModes { DISPLAY_INIT_MODE, DISPLAY_INIT_PARTIAL, DISPLAY_INIT_FULL }; @@ -108,27 +103,27 @@ enum DisplayInitModes { DISPLAY_INIT_MODE, DISPLAY_INIT_PARTIAL, DISPLAY_INIT_FU const char kDisplayCommands[] PROGMEM = D_PRFX_DISPLAY "|" // Prefix "|" D_CMND_DISP_MODEL "|" D_CMND_DISP_WIDTH "|" D_CMND_DISP_HEIGHT "|" D_CMND_DISP_MODE "|" D_CMND_DISP_REFRESH "|" D_CMND_DISP_DIMMER "|" D_CMND_DISP_COLS "|" D_CMND_DISP_ROWS "|" D_CMND_DISP_SIZE "|" D_CMND_DISP_FONT "|" - D_CMND_DISP_ROTATE "|" D_CMND_DISP_TEXT "|" D_CMND_DISP_ADDRESS "|" D_CMND_DISP_BLINKRATE + D_CMND_DISP_ROTATE "|" D_CMND_DISP_TEXT "|" D_CMND_DISP_ADDRESS "|" D_CMND_DISP_BLINKRATE "|" #ifdef USE_UFILESYS - "|" D_CMND_DISP_BATCH + D_CMND_DISP_BATCH "|" #endif - "|" D_CMND_DISP_CLEAR "|" D_CMND_DISP_NUMBER "|" D_CMND_DISP_FLOAT "|" D_CMND_DISP_NUMBERNC "|" D_CMND_DISP_FLOATNC "|" - D_CMND_DISP_BRIGHTNESS "|" D_CMND_DISP_RAW "|" D_CMND_DISP_LEVEL "|" D_CMND_DISP_SEVENSEG_TEXT "|" D_CMND_DISP_SEVENSEG_TEXTNC "|" - D_CMND_DISP_SCROLLDELAY "|" D_CMND_DISP_CLOCK "|" D_CMND_DISP_TEXTNC "|" D_CMND_DISP_SETLEDS "|" D_CMND_DISP_SETLED "|" - D_CMND_DISP_BUTTONS "|" D_CMND_DISP_SCROLLTEXT "|" D_CMND_DISP_ILIMODE "|" D_CMND_DISP_ILIINVERT + D_CMND_DISP_CLEAR "|" D_CMND_DISP_NUMBER "|" D_CMND_DISP_FLOAT "|" D_CMND_DISP_NUMBERNC "|" D_CMND_DISP_FLOATNC "|" + D_CMND_DISP_RAW "|" D_CMND_DISP_LEVEL "|" D_CMND_DISP_SEVENSEG_TEXT "|" D_CMND_DISP_SEVENSEG_TEXTNC "|" + D_CMND_DISP_SCROLLDELAY "|" D_CMND_DISP_CLOCK "|" D_CMND_DISP_TEXTNC "|" + D_CMND_DISP_SCROLLTEXT "|" D_CMND_DISP_ILIMODE "|" D_CMND_DISP_ILIINVERT ; void (* const DisplayCommand[])(void) PROGMEM = { &CmndDisplay, &CmndDisplayModel, &CmndDisplayWidth, &CmndDisplayHeight, &CmndDisplayMode, &CmndDisplayRefresh, &CmndDisplayDimmer, &CmndDisplayColumns, &CmndDisplayRows, &CmndDisplaySize, &CmndDisplayFont, - &CmndDisplayRotate, &CmndDisplayText, &CmndDisplayAddress, &CmndDisplayBlinkrate + &CmndDisplayRotate, &CmndDisplayText, &CmndDisplayAddress, &CmndDisplayBlinkrate, #ifdef USE_UFILESYS - ,&CmndDisplayBatch + &CmndDisplayBatch, #endif - , &CmndDisplayClear, &CmndDisplayNumber, &CmndDisplayFloat, &CmndDisplayNumberNC, &CmndDisplayFloatNC, - &CmndDisplayBrightness, &CmndDisplayRaw, &CmndDisplayLevel, &CmndDisplaySevensegText, &CmndDisplaySevensegTextNC, - &CmndDisplayScrollDelay, &CmndDisplayClock, &CmndDisplayTextNC, &CmndDisplaySetLEDs, &CmndDisplaySetLED, - &CmndDisplayButtons, &CmndDisplayScrollText, &CmndDisplayILIMOde , &CmndDisplayILIInvert + &CmndDisplayClear, &CmndDisplayNumber, &CmndDisplayFloat, &CmndDisplayNumberNC, &CmndDisplayFloatNC, + &CmndDisplayRaw, &CmndDisplayLevel, &CmndDisplaySevensegText, &CmndDisplaySevensegTextNC, + &CmndDisplayScrollDelay, &CmndDisplayClock, &CmndDisplayTextNC, + &CmndDisplayScrollText, &CmndDisplayILIMOde , &CmndDisplayILIInvert }; char *dsp_str; @@ -1600,7 +1595,9 @@ void DisplayInitDriver(void) Display_Text_From_File("/display.ini"); #endif - +#ifdef USE_GRAPH + for (uint8_t count = 0; count < NUM_GRAPHS; count++) { graph[count] = 0; } +#endif // AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "Display model %d"), Settings.display_model); @@ -1646,7 +1643,7 @@ void CmndDisplay(void) D_CMND_DISP_MODE "\":%d,\"" D_CMND_DISP_DIMMER "\":%d,\"" D_CMND_DISP_SIZE "\":%d,\"" D_CMND_DISP_FONT "\":%d,\"" D_CMND_DISP_ROTATE "\":%d,\"" D_CMND_DISP_REFRESH "\":%d,\"" D_CMND_DISP_COLS "\":[%d,%d],\"" D_CMND_DISP_ROWS "\":%d}}"), Settings.display_model, Settings.display_width, Settings.display_height, - Settings.display_mode, Settings.display_dimmer, Settings.display_size, Settings.display_font, + Settings.display_mode, ((Settings.display_dimmer * 666) / 100) +1, Settings.display_size, Settings.display_font, Settings.display_rotate, Settings.display_refresh, Settings.display_cols[0], Settings.display_cols[1], Settings.display_rows); } @@ -1689,7 +1686,7 @@ void CmndDisplayHeight(void) void CmndDisplayMode(void) { #ifdef USE_DISPLAY_MODES1TO5 -/* Matrix LCD / Oled TFT +/* Matrix / 7-segment LCD / Oled TFT * 1 = Text up and time Time * 2 = Date Local sensors Local sensors * 3 = Day Local sensors and time Local sensors and time @@ -1717,8 +1714,7 @@ void CmndDisplayMode(void) ResponseCmndNumber(Settings.display_mode); } -void CmndDisplayDimmer(void) -{ +void CmndDisplayDimmer(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) { Settings.display_dimmer = ((XdrvMailbox.payload +1) * 100) / 666; // Correction for Domoticz (0 - 15) if (Settings.display_dimmer && !(disp_power)) { @@ -1727,12 +1723,13 @@ void CmndDisplayDimmer(void) else if (!Settings.display_dimmer && disp_power) { ExecuteCommandPower(disp_device, POWER_OFF, SRC_DISPLAY); } - if (renderer) + if (renderer) { renderer->dim(Settings.display_dimmer); - else + } else { XdspCall(FUNC_DISPLAY_DIM); + } } - ResponseCmndNumber(Settings.display_dimmer); + ResponseCmndNumber(((Settings.display_dimmer * 666) / 100) +1); } void CmndDisplayBlinkrate(void) @@ -1797,16 +1794,6 @@ void CmndDisplayFloatNC(void) ResponseCmndChar(XdrvMailbox.data); } -void CmndDisplayBrightness(void) -{ - bool result = false; - if (!renderer) { - result = XdspCall(FUNC_DISPLAY_BRIGHTNESS); - } - if(result) ResponseCmndNumber(XdrvMailbox.payload); - else ResponseCmndChar(XdrvMailbox.data); -} - void CmndDisplayRaw(void) { if (!renderer) { @@ -1822,7 +1809,6 @@ void CmndDisplayLevel(void) result = XdspCall(FUNC_DISPLAY_LEVEL); } if(result) ResponseCmndNumber(XdrvMailbox.payload); - else ResponseCmndChar(XdrvMailbox.data); } void CmndDisplaySevensegText(void) @@ -1865,33 +1851,6 @@ void CmndDisplayClock(void) ResponseCmndNumber(XdrvMailbox.payload); } -void CmndDisplaySetLEDs(void) -{ - bool result = false; - if (!renderer) { - result = XdspCall(FUNC_DISPLAY_SETLEDS); - } - if(result) ResponseCmndNumber(XdrvMailbox.payload); - else ResponseCmndChar(XdrvMailbox.data); -} - - -void CmndDisplaySetLED(void) -{ - if (!renderer) { - XdspCall(FUNC_DISPLAY_SETLED); - } - ResponseCmndChar(XdrvMailbox.data); -} - -void CmndDisplayButtons(void) -{ - if (!renderer) { - XdspCall(FUNC_DISPLAY_BUTTONS); - } - ResponseCmndNumber(XdrvMailbox.payload); -} - void CmndDisplayScrollText(void) { @@ -1899,8 +1858,7 @@ void CmndDisplayScrollText(void) if (!renderer) { result = XdspCall(FUNC_DISPLAY_SCROLLTEXT); } - if(result) ResponseCmndNumber(XdrvMailbox.payload); - else ResponseCmndChar(XdrvMailbox.data); + if(result) ResponseCmndChar(XdrvMailbox.data); } @@ -1931,7 +1889,7 @@ void CmndDisplayFont(void) void CmndDisplayILIMOde(void) { - if ((XdrvMailbox.payload >= 1) && (XdrvMailbox.payload < 16)) { + if ((XdrvMailbox.payload >= 1) && (XdrvMailbox.payload <= 7)) { Settings.display_options.ilimode = XdrvMailbox.payload; TasmotaGlobal.restart_flag = 2; } @@ -2037,8 +1995,9 @@ void CmndDisplayRows(void) } /*********************************************************************************************\ - * optional drivers + * Optional drivers \*********************************************************************************************/ + #ifdef USE_TOUCH_BUTTONS // very limited path size, so, add .jpg void draw_picture(char *path, uint32_t xp, uint32_t yp, uint32_t xs, uint32_t ys, uint32_t ocol, bool inverted) { @@ -2059,7 +2018,7 @@ char ppath[16]; } Draw_RGB_Bitmap(ppath, xp, yp, inverted); } -#endif +#endif // USE_TOUCH_BUTTONS #ifdef ESP32 @@ -2173,6 +2132,10 @@ void Draw_RGB_Bitmap(char *file,uint16_t xp, uint16_t yp, bool inverted ) { } #endif // USE_UFILESYS +/*********************************************************************************************\ + * AWatch +\*********************************************************************************************/ + #ifdef USE_AWATCH #define MINUTE_REDUCT 4 @@ -2210,6 +2173,9 @@ void DrawAClock(uint16_t rad) { } #endif // USE_AWATCH +/*********************************************************************************************\ + * Graphics +\*********************************************************************************************/ #ifdef USE_GRAPH @@ -2250,7 +2216,6 @@ struct GRAPH { GFLAGS flags; }; - struct GRAPH *graph[NUM_GRAPHS]; #define TICKLEN 4 @@ -2447,6 +2412,7 @@ void Save_graph(uint8_t num, char *path) { fp.print("\n"); fp.close(); } + void Restore_graph(uint8_t num, char *path) { if (!renderer) return; uint16_t index=num%NUM_GRAPHS; @@ -2558,7 +2524,6 @@ void AddGraph(uint8_t num,uint8_t val) { } } - // add next value void AddValue(uint8_t num,float fval) { // not yet defined ??? @@ -2593,7 +2558,12 @@ void AddValue(uint8_t num,float fval) { } #endif // USE_GRAPH +/*********************************************************************************************\ + * Touch panel control +\*********************************************************************************************/ + #if defined(USE_FT5206) || defined(USE_XPT2046) + #ifdef USE_FT5206 #include @@ -2630,7 +2600,7 @@ uint32_t Touch_Status(uint32_t sel) { return 0; } } -#endif +#endif // USE_FT5206 #if defined(USE_XPT2046) && defined(USE_DISPLAY_ILI9341) #include @@ -2664,7 +2634,7 @@ uint32_t Touch_Status(uint32_t sel) { } } -#endif +#endif // USE_XPT2046 && USE_DISPLAY_ILI9341 #ifdef USE_TOUCH_BUTTONS void Touch_MQTT(uint8_t index, const char *cp, uint32_t val) { @@ -2672,7 +2642,7 @@ void Touch_MQTT(uint8_t index, const char *cp, uint32_t val) { ResponseTime_P(PSTR(",\"FT5206\":{\"%s%d\":\"%d\"}}"), cp, index+1, val); #elif defined(USE_XPT2046) ResponseTime_P(PSTR(",\"XPT2046\":{\"%s%d\":\"%d\"}}"), cp, index+1, val); -#endif +#endif // USE_XPT2046 MqttPublishTeleSensor(); } @@ -2688,18 +2658,17 @@ uint8_t tbstate[3]; // check digitizer hit void Touch_Check(void(*rotconvert)(int16_t *x, int16_t *y)) { -uint16_t temp; -uint8_t rbutt=0; -uint8_t vbutt=0; + uint16_t temp; + uint8_t rbutt=0; + uint8_t vbutt=0; - - if (touchp->touched()) { + if (touchp->touched()) { // did find a hit #if defined(USE_FT5206) pLoc = touchp->getPoint(0); #elif defined(USE_XPT2046) pLoc = touchp->getPoint(); -#endif +#endif // USE_XPT2046 if (renderer) { #ifdef USE_M5STACK_CORE2 @@ -2720,7 +2689,7 @@ uint8_t vbutt=0; } xcenter += 100; } -#endif +#endif // USE_M5STACK_CORE2 rotconvert(&pLoc.x, &pLoc.y); @@ -2784,7 +2753,7 @@ uint8_t vbutt=0; //AddLog(LOG_LEVEL_INFO, PSTR("tbut: %d released"), tbut); } } -#endif +#endif // USE_M5STACK_CORE2 for (uint8_t count = 0; count < MAX_TOUCH_BUTTONS; count++) { if (buttons[count]) { if (!buttons[count]->vpower.slider) { @@ -2817,7 +2786,7 @@ uint8_t vbutt=0; } #endif // USE_TOUCH_BUTTONS -#endif // USE_FT5206 +#endif // USE_FT5206 || USE_XPT2046 /*********************************************************************************************\ * Interface @@ -2827,13 +2796,10 @@ bool Xdrv13(uint8_t function) { bool result = false; - if ((TasmotaGlobal.i2c_enabled || TasmotaGlobal.spi_enabled || TasmotaGlobal.soft_spi_enabled) && XdspPresent()) { + if (XdspPresent()) { switch (function) { case FUNC_PRE_INIT: DisplayInitDriver(); -#ifdef USE_GRAPH - for (uint8_t count = 0; count < NUM_GRAPHS; count++) { graph[count] = 0; } -#endif break; case FUNC_EVERY_50_MSECOND: if (Settings.display_model) { XdspCall(FUNC_DISPLAY_EVERY_50_MSECOND); } @@ -2875,4 +2841,3 @@ bool Xdrv13(uint8_t function) } #endif // USE_DISPLAY -#endif // USE_I2C or USE_SPI diff --git a/tasmota/xdrv_16_tuyamcu.ino b/tasmota/xdrv_16_tuyamcu.ino index 22eba70f2..476328ef1 100644 --- a/tasmota/xdrv_16_tuyamcu.ino +++ b/tasmota/xdrv_16_tuyamcu.ino @@ -386,7 +386,7 @@ inline bool TuyaFuncIdValid(uint8_t fnId) { return (fnId >= TUYA_MCU_FUNC_SWT1 && fnId <= TUYA_MCU_FUNC_SWT4) || (fnId >= TUYA_MCU_FUNC_REL1 && fnId <= TUYA_MCU_FUNC_REL8) || (fnId >= TUYA_MCU_FUNC_DIMMER && fnId <= TUYA_MCU_FUNC_REPORT2) || - (fnId >= TUYA_MCU_FUNC_POWER && fnId <= TUYA_MCU_FUNC_BATTERY_PERCENTAGE) || + (fnId >= TUYA_MCU_FUNC_POWER && fnId <= TUYA_MCU_FUNC_POWER_TOTAL) || (fnId >= TUYA_MCU_FUNC_REL1_INV && fnId <= TUYA_MCU_FUNC_REL8_INV) || (fnId >= TUYA_MCU_FUNC_ENUM1 && fnId <= TUYA_MCU_FUNC_ENUM4) || (fnId >= TUYA_MCU_FUNC_MOTOR_DIR && fnId <= TUYA_MCU_FUNC_DUMMY) || @@ -697,13 +697,41 @@ void TuyaProcessStatePacket(void) { uint8_t fnId; uint16_t dpDataLen; bool PowerOff = false; + bool tuya_energy_enabled = (XNRG_32 == TasmotaGlobal.energy_driver); while (dpidStart + 4 < Tuya.byte_counter) { dpDataLen = Tuya.buffer[dpidStart + 2] << 8 | Tuya.buffer[dpidStart + 3]; fnId = TuyaGetFuncId(Tuya.buffer[dpidStart]); AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: fnId=%d is set for dpId=%d"), fnId, Tuya.buffer[dpidStart]); - if (Tuya.buffer[dpidStart + 1] == 1) { // Data Type 1 + if (Tuya.buffer[dpidStart + 1] == 0) { +#ifdef USE_ENERGY_SENSOR + if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_POWER_COMBINED) { + if (dpDataLen == 8) { + uint16_t tmpVol = Tuya.buffer[dpidStart + 4] << 8 | Tuya.buffer[dpidStart + 5]; + uint16_t tmpCur = Tuya.buffer[dpidStart + 7] << 8 | Tuya.buffer[dpidStart + 8]; + uint16_t tmpPow = Tuya.buffer[dpidStart + 10] << 8 | Tuya.buffer[dpidStart + 11]; + Energy.voltage[0] = (float)tmpVol / 10; + Energy.current[0] = (float)tmpCur / 1000; + Energy.active_power[0] = (float)tmpPow; + AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Voltage=%d"), Tuya.buffer[dpidStart], tmpVol); + AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Current=%d"), Tuya.buffer[dpidStart], tmpCur); + AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Active_Power=%d"), Tuya.buffer[dpidStart], tmpPow); + + if (RtcTime.valid) { + if (Tuya.lastPowerCheckTime != 0 && Energy.active_power[0] > 0) { + Energy.kWhtoday += (float)Energy.active_power[0] * (Rtc.utc_time - Tuya.lastPowerCheckTime) / 36; + EnergyUpdateToday(); + } + Tuya.lastPowerCheckTime = Rtc.utc_time; + } + } else { + AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d INV_LEN=%d"), Tuya.buffer[dpidStart], dpDataLen); + } + } + #endif // USE_ENERGY_SENSOR + } + else if (Tuya.buffer[dpidStart + 1] == 1) { // Data Type 1 if (fnId >= TUYA_MCU_FUNC_REL1 && fnId <= TUYA_MCU_FUNC_REL8) { AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: RX Relay-%d --> MCU State: %s Current State:%s"), fnId - TUYA_MCU_FUNC_REL1 + 1, Tuya.buffer[dpidStart + 4]?"On":"Off",bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1)?"On":"Off"); @@ -728,7 +756,6 @@ void TuyaProcessStatePacket(void) { if (PowerOff) { Tuya.ignore_dimmer_cmd_timeout = millis() + 250; } } else if (Tuya.buffer[dpidStart + 1] == 2) { // Data Type 2 - bool tuya_energy_enabled = (XNRG_32 == TasmotaGlobal.energy_driver); uint16_t packetValue = Tuya.buffer[dpidStart + 6] << 8 | Tuya.buffer[dpidStart + 7]; uint8_t dimIndex; bool SnsUpdate = false; @@ -824,6 +851,9 @@ void TuyaProcessStatePacket(void) { } Tuya.lastPowerCheckTime = Rtc.utc_time; } + } else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_POWER_TOTAL) { + EnergyUpdateTotal((float)packetValue / 100,true); + AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Total_Power=%d"), Tuya.buffer[dpidStart], packetValue); } #endif // USE_ENERGY_SENSOR } @@ -862,6 +892,7 @@ void TuyaProcessStatePacket(void) { ExecuteCommand(scmnd, SRC_SWITCH); } } + } else if (Tuya.buffer[dpidStart + 1] == 4) { // Data Type 4 const unsigned char *dpData = (unsigned char*)&Tuya.buffer[dpidStart + 4]; @@ -1273,11 +1304,11 @@ bool Xnrg32(uint8_t function) if (TUYA_DIMMER == TasmotaGlobal.module_type) { if (FUNC_PRE_INIT == function) { - if (TuyaGetDpId(TUYA_MCU_FUNC_POWER) != 0) { - if (TuyaGetDpId(TUYA_MCU_FUNC_CURRENT) == 0) { + if (TuyaGetDpId(TUYA_MCU_FUNC_POWER) != 0 || TuyaGetDpId(TUYA_MCU_FUNC_POWER_COMBINED) != 0) { + if (TuyaGetDpId(TUYA_MCU_FUNC_CURRENT) == 0 && TuyaGetDpId(TUYA_MCU_FUNC_POWER_COMBINED) == 0) { Energy.current_available = false; } - if (TuyaGetDpId(TUYA_MCU_FUNC_VOLTAGE) == 0) { + if (TuyaGetDpId(TUYA_MCU_FUNC_VOLTAGE) == 0 && TuyaGetDpId(TUYA_MCU_FUNC_POWER_COMBINED) == 0) { Energy.voltage_available = false; } TasmotaGlobal.energy_driver = XNRG_32; diff --git a/tasmota/xdrv_35_pwm_dimmer.ino b/tasmota/xdrv_35_pwm_dimmer.ino index 555ec1a67..d30e7cba1 100644 --- a/tasmota/xdrv_35_pwm_dimmer.ino +++ b/tasmota/xdrv_35_pwm_dimmer.ino @@ -755,21 +755,8 @@ bool Xdrv35(uint8_t function) // If the button is pressed, ... if (!XdrvMailbox.payload) { - // If the button was just pressed, flag the button as pressed, set the hold time and - // increment the buttons pressed count. + // If the button was just pressed, ... if (!button_pressed[button_index]) { - button_pressed[button_index] = true; - uint32_t hold_delay = 250; - if (button_index == power_button_index) { -#ifdef USE_PWM_DIMMER_REMOTE - if (!(active_remote_pwm_dimmer ? active_remote_pwm_dimmer->power_on : TasmotaGlobal.power)) hold_delay = 500; -#else // USE_PWM_DIMMER_REMOTE - if (!TasmotaGlobal.power) hold_delay = 500; -#endif // USE_PWM_DIMMER_REMOTE - } - button_hold_time[button_index] = now + hold_delay; - buttons_pressed++; - if (buttons_pressed > 1) multibutton_in_progress = true; #ifdef USE_PWM_DIMMER_REMOTE // If there are no other buttons pressed right now and remote mode is enabled, make the @@ -785,7 +772,7 @@ bool Xdrv35(uint8_t function) // Top 0 1 1 0 // Middle 1 2 15 0 // Bottom 15 3 15 1 - if (buttons_pressed == 1 && Settings.flag4.multiple_device_groups) { + if (!buttons_pressed && Settings.flag4.multiple_device_groups) { power_button_index = button_index; down_button_index = (Pin(GPIO_KEY1, power_button_index) == 15 ? TasmotaGlobal.gpio_pin[1] : TasmotaGlobal.gpio_pin[15]) - 32; active_remote_pwm_dimmer = nullptr; @@ -793,9 +780,17 @@ bool Xdrv35(uint8_t function) active_remote_pwm_dimmer = &remote_pwm_dimmers[power_button_index]; } #endif // USE_PWM_DIMMER_REMOTE + + // Flag the button as pressed, increment the buttons pressed count and set the hold time. + button_pressed[button_index] = true; + buttons_pressed++; + if (buttons_pressed > 1) multibutton_in_progress = true; + uint32_t hold_delay = 250; + if (button_index == power_button_index) hold_delay = Settings.param[P_HOLD_TIME] * 10; + button_hold_time[button_index] = now + hold_delay; } - // If hold time has arrived and a rule is enabled that handles the button hold, handle it. + // If hold time has arrived and no rule is enabled that handles the button hold, handle it. else if (button_hold_time[button_index] <= now) { #ifdef USE_RULES sprintf(TasmotaGlobal.mqtt_data, PSTR("{\"Button%u\":{\"State\":3}}"), button_index + 1); diff --git a/tasmota/xdrv_52_2_berry_native.ino b/tasmota/xdrv_52_2_berry_native.ino new file mode 100644 index 000000000..58a4f8ec3 --- /dev/null +++ b/tasmota/xdrv_52_2_berry_native.ino @@ -0,0 +1,119 @@ +/* + xdrv_52_3_berry_native.ino - Berry scripting language, native fucnctions + + Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#ifdef USE_BERRY + +#include +#include + +const char kTypeError[] PROGMEM = "type_error"; + +extern "C" { + void be_dumpstack(bvm *vm) { + int32_t top = be_top(vm); + AddLog(LOG_LEVEL_INFO, "BRY: top=%d", top); + for (uint32_t i = 1; i <= top; i++) { + const char * tname = be_typename(vm, i); + const char * cname = be_classname(vm, i); + AddLog(LOG_LEVEL_INFO, "BRY: stack[%d] = type='%s' (%s)", i, (tname != nullptr) ? tname : "", (cname != nullptr) ? cname : ""); + } + } + + // convert to unsigned 8 bits + static uint8_t to_u8(int32_t v) { + if (v < 0) { return 0; } + if (v > 0xFF) { return 0xFF; } + return v; + } + static void map_insert_int(bvm *vm, const char *key, int value) + { + be_pushstring(vm, key); + be_pushint(vm, value); + be_data_insert(vm, -3); + be_pop(vm, 2); + } + static void map_insert_bool(bvm *vm, const char *key, bool value) + { + be_pushstring(vm, key); + be_pushbool(vm, value); + be_data_insert(vm, -3); + be_pop(vm, 2); + } + // if value == NAN, ignore + static void map_insert_float(bvm *vm, const char *key, float value) + { + if (!isnan(value)) { + be_pushstring(vm, key); + be_pushreal(vm, value); + be_data_insert(vm, -3); + be_pop(vm, 2); + } + } + static void map_insert_str(bvm *vm, const char *key, const char *value) + { + be_pushstring(vm, key); + be_pushstring(vm, value); + be_data_insert(vm, -3); + be_pop(vm, 2); + } + static void map_insert_list_uint8(bvm *vm, const char *key, const uint8_t *value, size_t size) + { + be_pushstring(vm, key); + + be_newobject(vm, "list"); + for (uint32_t i=0; i < size; i++) { + be_pushint(vm, value[i]); + be_data_push(vm, -2); + be_pop(vm, 1); + } + be_pop(vm, 1); // now list is on top + + be_data_insert(vm, -3); // insert into map, key/value + be_pop(vm, 2); // pop both key and value + } + static bool map_find(bvm *vm, const char *key) + { + be_getmethod(vm, -1, "find"); // look for "find" method of "Map" instance + be_pushvalue(vm, -2); // put back instance as first argument (implicit instance) + be_pushstring(vm, key); // push string as second argument + be_call(vm, 2); // call wirn 2 parameters (implicit instance and key) + be_pop(vm, 2); // pop 2 arguments, the function is replaced by result + return !be_isnil(vm, -1); // true if not 'nil' + } + static int32_t get_list_size(bvm *vm) { + be_getmethod(vm, -1, "size"); // look for "size" method of "list" instance + be_pushvalue(vm, -2); // put back instance as first argument (implicit instance) + be_call(vm, 1); // call wirn 2 parameters (implicit instance and key) + int32_t ret = be_toint(vm, -2); + be_pop(vm, 2); // pop 1 argument and return value + return ret; + } + // get item number `index` from list, index must be valid or raises an exception + static void get_list_item(bvm *vm, int32_t index) { + be_getmethod(vm, -1, "item"); // look for "size" method of "list" instance + be_pushvalue(vm, -2); // put back instance as first argument (implicit instance) + be_pushint(vm, index); + // be_dumpstack(vm); + be_call(vm, 2); // call wirn 2 parameters (implicit instance and key) + be_pop(vm, 2); // pop 2 arguments and return value + } +} + +#endif // USE_BERRY diff --git a/tasmota/xdrv_52_3_berry_energy.ino b/tasmota/xdrv_52_3_berry_energy.ino new file mode 100644 index 000000000..75ae27245 --- /dev/null +++ b/tasmota/xdrv_52_3_berry_energy.ino @@ -0,0 +1,70 @@ +/* + xdrv_52_3_berry_native.ino - Berry scripting language, native fucnctions + + Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#ifdef USE_BERRY + +#include + + +/*********************************************************************************************\ + * Native functions mapped to Berry functions + * + * import power + * + * power.read() -> map + * +\*********************************************************************************************/ +extern "C" { +#ifdef USE_ENERGY_SENSOR + // Berry: `begintransmission(address:int) -> nil` + int32_t b_nrg_read(struct bvm *vm); + int32_t b_nrg_read(struct bvm *vm) { + be_newobject(vm, "map"); + map_insert_float(vm, "total", Energy.total); + // Energy.phase_count + map_insert_float(vm, "power", Energy.active_power[0]); + map_insert_float(vm, "yesterday", (float)Settings.energy_kWhyesterday / 100000); + map_insert_float(vm, "today", Energy.daily); + map_insert_float(vm, "activepower", Energy.active_power[0]); + map_insert_float(vm, "apparentpower", Energy.active_power[0]); + map_insert_float(vm, "reactivepower", Energy.reactive_power[0]); + // map_insert_float(vm, "powerfactor", ); + map_insert_float(vm, "frequency", Energy.frequency[0]); + map_insert_float(vm, "voltage", Energy.voltage[0]); + map_insert_float(vm, "current", Energy.current[0]); + + be_pop(vm, 1); + be_return(vm); // Return + } +#else // USE_ENERGY_SENSOR + // + int32_t b_wire_energymissing(struct bvm *vm); + int32_t b_wire_energymissing(struct bvm *vm) { + be_raise(vm, "feature_error", "Energy sensor is not enabled, use '#define USE_ENERGY_SENSOR'"); + } + + // define weak aliases + int32_t b_nrg_read(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_energymissing"))); +#endif // USE_ENERGY_SENSOR +} + + + +#endif // USE_BERRY diff --git a/tasmota/xdrv_52_3_berry_native.ino b/tasmota/xdrv_52_3_berry_native.ino deleted file mode 100644 index 46b869544..000000000 --- a/tasmota/xdrv_52_3_berry_native.ino +++ /dev/null @@ -1,534 +0,0 @@ -/* - xdrv_52_3_berry_native.ino - Berry scripting language, native fucnctions - - Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - - -#ifdef USE_BERRY - -#include -#include - -const char kTypeError[] PROGMEM = "type_error"; -/*********************************************************************************************\ - * Native functions mapped to Berry functions - * - * log(msg:string [,log_level:int]) ->nil - * - * import tasmota - * - * tasmota.getfreeheap() -> int - * tasmota.publish(topic:string, payload:string[, retain:bool]) -> nil - * tasmota.cmd(command:string) -> string - * tasmota.getoption(index:int) -> int - * tasmota.millis([delay:int]) -> int - * tasmota.timereached(timer:int) -> bool - * tasmota.yield() -> nil - * -\*********************************************************************************************/ -extern "C" { - // Berry: `tasmota.publish(topic, payload [,retain]) -> nil`` - // - int32_t l_publish(struct bvm *vm); - int32_t l_publish(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top >= 2 && be_isstring(vm, 1) && be_isstring(vm, 2)) { // 2 mandatory string arguments - if (top == 2 || (top == 3 && be_isbool(vm, 3))) { // 3rd optional argument must be bool - const char * topic = be_tostring(vm, 1); - const char * payload = be_tostring(vm, 2); - bool retain = false; - if (top == 3) { - retain = be_tobool(vm, 3); - } - strlcpy(TasmotaGlobal.mqtt_data, payload, sizeof(TasmotaGlobal.mqtt_data)); - MqttPublish(topic, retain); - be_return(vm); // Return - } - } - be_raise(vm, kTypeError, nullptr); - } - - // Berry: `tasmota.cmd(command:string) -> string` - // - int32_t l_cmd(struct bvm *vm); - int32_t l_cmd(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 1 && be_isstring(vm, 1)) { // only 1 argument of type string accepted - const char * command = be_tostring(vm, 1); - ExecuteCommand(command, SRC_BERRY); - be_pushstring(vm, TasmotaGlobal.mqtt_data); - be_return(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } - - // Berry: tasmota.millis([delay:int]) -> int - // - int32_t l_millis(struct bvm *vm); - int32_t l_millis(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 0 || (top == 1 && be_isint(vm, 1))) { // only 1 argument of type string accepted - uint32_t delay = 0; - if (top == 1) { - delay = be_toint(vm, 1); - } - uint32_t ret_millis = millis() + delay; - be_pushint(vm, ret_millis); - be_return(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } - - // Berry: tasmota.getoption(index:int) -> int - // - int32_t l_getoption(struct bvm *vm); - int32_t l_getoption(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 1 && be_isint(vm, 1)) { - uint32_t opt = GetOption(be_toint(vm, 1)); - be_pushint(vm, opt); - be_return(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } - - // Berry: tasmota.timereached(timer:int) -> bool - // - int32_t l_timereached(struct bvm *vm); - int32_t l_timereached(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 1 && be_isint(vm, 1)) { // only 1 argument of type string accepted - uint32_t timer = be_toint(vm, 1); - bool reached = TimeReached(timer); - be_pushbool(vm, reached); - be_return(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } - - // Berry: tasmota.delay(timer:int) -> nil - // - int32_t l_delay(struct bvm *vm); - int32_t l_delay(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 1 && be_isint(vm, 1)) { // only 1 argument of type string accepted - uint32_t timer = be_toint(vm, 1); - delay(timer); - be_return_nil(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } - - // Berry: `yield() -> nil` - // ESP object - int32_t l_yield(bvm *vm); - int32_t l_yield(bvm *vm) { - optimistic_yield(10); - be_return(vm); - } - - // Berry: `save(file:string, f:closure) -> bool` - int32_t l_save(struct bvm *vm); - int32_t l_save(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top ==2 && be_isstring(vm, 1) && be_isclosure(vm, 2)) { // only 1 argument of type string accepted - const char *fname = be_tostring(vm, 1); - int32_t ret = be_savecode(vm, fname); - be_pushint(vm, ret); - be_return(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } - - int32_t l_respCmnd(bvm *vm); - int32_t l_respCmnd(bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 1) { - const char *msg = be_tostring(vm, 1); - Response_P("%s", msg); - be_return_nil(vm); // Return nil when something goes wrong - } - be_raise(vm, kTypeError, nullptr); - } - - int32_t l_respCmndStr(bvm *vm); - int32_t l_respCmndStr(bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 1) { - const char *msg = be_tostring(vm, 1); - ResponseCmndChar(msg); - be_return_nil(vm); // Return nil when something goes wrong - } - be_raise(vm, kTypeError, nullptr); - } - - int32_t l_respCmndDone(bvm *vm); - int32_t l_respCmndDone(bvm *vm) { - ResponseCmndDone(); - be_return_nil(vm); - } - - int32_t l_respCmndError(bvm *vm); - int32_t l_respCmndError(bvm *vm) { - ResponseCmndError(); - be_return_nil(vm); - } - - int32_t l_respCmndFailed(bvm *vm); - int32_t l_respCmndFailed(bvm *vm) { - ResponseCmndFailed(); - be_return_nil(vm); - } - - // update XdrvMailbox.command with actual command - int32_t l_resolveCmnd(bvm *vm); - int32_t l_resolveCmnd(bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 1 && be_isstring(vm, 1)) { - const char *msg = be_tostring(vm, 1); - strlcpy(XdrvMailbox.command, msg, CMDSZ); - be_return_nil(vm); // Return nil when something goes wrong - } - be_raise(vm, kTypeError, nullptr); - } - - - static void map_insert_int(bvm *vm, const char *key, int value) - { - be_pushstring(vm, key); - be_pushint(vm, value); - be_data_insert(vm, -3); - be_pop(vm, 2); - } - static void map_insert_bool(bvm *vm, const char *key, bool value) - { - be_pushstring(vm, key); - be_pushbool(vm, value); - be_data_insert(vm, -3); - be_pop(vm, 2); - } - static void map_insert_str(bvm *vm, const char *key, const char *value) - { - be_pushstring(vm, key); - be_pushstring(vm, value); - be_data_insert(vm, -3); - be_pop(vm, 2); - } - - // get light - int32_t l_getlight(bvm *vm); - int32_t l_getlight(bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 0 || (top == 1 && be_isint(vm, 1))) { - int32_t light_num = 0; - if (top > 0) { - light_num = be_toint(vm, 1); - } - bool data_present = false; // do we have relevant data - be_newobject(vm, "map"); - // check if the light exist - // TasmotaGlobal.devices_present - // Light.device - // Light.subtype - // Light.pwm_multi_channels - // light_controller.isCTRGBLinked() - - if (Light.device > 0) { - // we have a light - - uint8_t channels[LST_MAX]; - uint8_t channelsb[LST_MAX]; - char rgbcw[12] = {0}; - char rgbcwb[12] = {0}; - light_state.getChannelsRaw(channels); - light_state.getChannels(channelsb); - - // map_insert_int(vm, "_devices_present", TasmotaGlobal.devices_present); - // map_insert_int(vm, "_light_device", Light.device); - // map_insert_int(vm, "_light_subtype", Light.subtype); - // map_insert_int(vm, "_light_multi", Light.pwm_multi_channels); - // map_insert_int(vm, "_light_linked", light_controller.isCTRGBLinked()); - - if (!Light.pwm_multi_channels) { - uint32_t subtype = Light.subtype; // virtual sub-type, for SO37 128 - uint32_t chanidx = 0; // channel offset, for SO37 128 - - - if (light_controller.isCTRGBLinked() && (light_num == 0)) { - data_present = true; // valid combination - } - if (!light_controller.isCTRGBLinked()) { - if (light_num == 0) { - data_present = true; // valid combination - if (subtype > LST_RGB) { subtype = LST_RGB; } // limit to RGB - } - if ((light_num == 1) && subtype > LST_RGB) { - data_present = true; // valid combination - subtype = subtype - LST_RGB; - chanidx = 3; // skip first 3 channels - } - } - - if (data_present) { - // see ResponseLightState() - map_insert_bool(vm, "power", (bool)(Light.power & 1)); - map_insert_int(vm, "bri", light_state.getBri()); - - - if (subtype >= LST_RGB) { - uint16_t hue; - uint8_t sat, bri; - light_state.getHSB(&hue, &sat, &bri); - map_insert_int(vm, "hue", hue); - map_insert_int(vm, "sat", sat); - } - if ((LST_COLDWARM == subtype) || (LST_RGBW <= subtype)) { - map_insert_int(vm, "ct", light_state.getCT()); - } - if (subtype > LST_NONE) { - for (uint32_t i=0; i < subtype; i++) { - snprintf_P(rgbcw, sizeof(rgbcw), PSTR("%s%02X"), rgbcw, channels[i+chanidx]); - snprintf_P(rgbcwb, sizeof(rgbcwb), PSTR("%s%02X"), rgbcwb, channelsb[i+chanidx]); - } - map_insert_str(vm, "channels", rgbcw); - map_insert_str(vm, "channelsb", rgbcwb); - // map_insert_bool(vm, "gamma", Settings.light_correction); - } - } - } else { // Light.pwm_multi_channels - if ((light_num >= 0) && (light_num < LST_MAX)) { - data_present = true; - map_insert_bool(vm, "power", Light.power & (1 << light_num)); - map_insert_int(vm, "bri", Light.current_color[light_num]); - snprintf_P(rgbcw, sizeof(rgbcw), PSTR("%02X"), channels[light_num]); - snprintf_P(rgbcwb, sizeof(rgbcwb), PSTR("%02X"), channelsb[light_num]); - map_insert_str(vm, "channels", rgbcw); - map_insert_str(vm, "channelsb", rgbcwb); - } - } - - be_pop(vm, 1); - if (data_present) { - be_return(vm); // Return - } else { - be_return_nil(vm); // no data, return nil instead of empty map - } - } else { - be_return_nil(vm); - } - } - be_raise(vm, kTypeError, nullptr); - } - -} - -/*********************************************************************************************\ - * Native functions mapped to Berry functions - * - * import wire - * - * wire.getfreeheap() -> int - * -\*********************************************************************************************/ -extern "C" { - // Berry: `begintransmission(address:int) -> nil` - int32_t b_wire_begintransmission(struct bvm *vm); - int32_t b_wire_begintransmission(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 1 && be_isint(vm, 1)) { // only 1 argument of type string accepted - int32_t address = be_toint(vm, 1); - Wire.beginTransmission(address); - be_return(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } - - // Berry: `endtransmission([stop:bool]) -> nil` - int32_t b_wire_endtransmission(struct bvm *vm); - int32_t b_wire_endtransmission(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 0 || (top == 1 && be_isbool(vm, 1))) { // only 1 argument of type string accepted - bool stop = true; - if (top == 1) { - stop = be_tobool(vm, 1); - } - uint32_t ret = Wire.endTransmission(stop); - be_pushint(vm, ret); - be_return(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } - - // Berry: `requestfrom(address:int, quantity:int [stop:bool = true]) -> nil` - int32_t b_wire_requestfrom(struct bvm *vm); - int32_t b_wire_requestfrom(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if ( (top == 2 || (top == 3 && be_isbool(vm, 3))) - && be_isint(vm, 1) && be_isint(vm, 2) ) { - int32_t address = be_toint(vm, 1); - int32_t quantity = be_toint(vm, 2); - bool stop = true; - if (top == 3) { - stop = be_tobool(vm, 3); - } - Wire.requestFrom((uint16_t)address, (uint8_t)quantity, stop); - be_return(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } - - // Berry: `available() -> bool` - int32_t b_wire_available(struct bvm *vm); - int32_t b_wire_available(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 0) { - size_t available = Wire.available(); - be_pushint(vm, available); - be_return(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } - - // Berry: `write(value:int | s:string) -> nil` - int32_t b_wire_write(struct bvm *vm); - int32_t b_wire_write(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 1 && (be_isint(vm, 1) || be_isstring(vm, 1))) { - if (be_isint(vm, 1)) { - int32_t value = be_toint(vm, 1); - Wire.write(value); - } else if (be_isstring(vm, 1)) { - const char * s = be_tostring(vm, 1); - Wire.write(s); - } else { - be_return_nil(vm); - } - be_return(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } - - // Berry: `read() -> int` - int32_t b_wire_read(struct bvm *vm); - int32_t b_wire_read(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 0) { - int32_t value = Wire.read(); - be_pushint(vm, value); - be_return(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } - - int32_t b_wire_scan(struct bvm *vm); - int32_t b_wire_scan(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 0) { - be_newobject(vm, "list"); - for (uint8_t address = 1; address <= 127; address++) { - Wire.beginTransmission(address); - int32_t error = Wire.endTransmission(); - if (0 == error) { - be_pushint(vm, address); - be_data_push(vm, -2); - be_pop(vm, 1); - } - } - be_pop(vm, 1); - be_return(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } - - // Berry: `validwrite(address:int, reg:int, val:int, size:int) -> bool or nil` - int32_t b_wire_validwrite(struct bvm *vm); - int32_t b_wire_validwrite(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 4 && be_isint(vm, 1) && be_isint(vm, 2) && be_isint(vm, 3) && be_isint(vm, 4)) { - uint8_t addr = be_toint(vm, 1); - uint8_t reg = be_toint(vm, 2); - uint8_t val = be_toint(vm, 3); - uint8_t size = be_toint(vm, 4); - bool ok = I2cWrite(addr, reg, val, size); - be_pushbool(vm, ok); - be_return(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } - - // Berry: `validread(address:int, reg:int, size:int) -> int or nil` - int32_t b_wire_validread(struct bvm *vm); - int32_t b_wire_validread(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top == 3 && be_isint(vm, 1) && be_isint(vm, 2) && be_isint(vm, 3)) { - uint8_t addr = be_toint(vm, 1); - uint8_t reg = be_toint(vm, 2); - uint8_t size = be_toint(vm, 3); - bool ok = I2cValidRead(addr, reg, size); - if (ok) { - be_pushint(vm, i2c_buffer); - } else { - be_pushnil(vm); - } - be_return(vm); // Return - } - be_raise(vm, kTypeError, nullptr); - } -} - -/*********************************************************************************************\ - * Native functions mapped to Berry functions - * - * log(msg:string [,log_level:int]) ->nil - * -\*********************************************************************************************/ -extern "C" { - // Berry: `log(msg:string [,log_level:int]) ->nil` - // Logs the string at LOG_LEVEL_INFO (loglevel=2) - int32_t l_logInfo(struct bvm *vm); - int32_t l_logInfo(struct bvm *vm) { - int32_t top = be_top(vm); // Get the number of arguments - if (top >= 1 && be_isstring(vm, 1)) { // only 1 argument of type string accepted - const char * msg = be_tostring(vm, 1); - uint32_t log_level = LOG_LEVEL_INFO; - if (top >= 2 && be_isint(vm, 2)) { - log_level = be_toint(vm, 2); - if (log_level > LOG_LEVEL_DEBUG_MORE) { log_level = LOG_LEVEL_DEBUG_MORE; } - } - AddLog(log_level, PSTR("%s"), msg); - be_return(vm); // Return - } - be_return_nil(vm); // Return nil when something goes wrong - } - - // Berry: `getFreeHeap() -> int` - // ESP object - int32_t l_getFreeHeap(bvm *vm); - int32_t l_getFreeHeap(bvm *vm) { - be_pushint(vm, ESP.getFreeHeap()); - be_return(vm); - } -} - -// called as a replacement to Berry `print()` -void berry_log(const char * berry_buf); -void berry_log(const char * berry_buf) { - AddLog(LOG_LEVEL_INFO, PSTR("%s"), berry_buf); -} - - -#endif // USE_BERRY diff --git a/tasmota/xdrv_52_3_berry_tasmota.ino b/tasmota/xdrv_52_3_berry_tasmota.ino new file mode 100644 index 000000000..f39f3cc1c --- /dev/null +++ b/tasmota/xdrv_52_3_berry_tasmota.ino @@ -0,0 +1,529 @@ +/* + xdrv_52_3_berry_native.ino - Berry scripting language, native fucnctions + + Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#ifdef USE_BERRY + +#include +#include + +/*********************************************************************************************\ + * Native functions mapped to Berry functions + * + * log(msg:string [,log_level:int]) ->nil + * + * import tasmota + * + * tasmota.getfreeheap() -> int + * tasmota.publish(topic:string, payload:string[, retain:bool]) -> nil + * tasmota.cmd(command:string) -> string + * tasmota.getoption(index:int) -> int + * tasmota.millis([delay:int]) -> int + * tasmota.timereached(timer:int) -> bool + * tasmota.yield() -> nil + * + * tasmota.getlight([index:int = 0]) -> map + * tasmota.getpower([index:int = 0]) -> bool + * tasmota.setpower(idx:int, power:bool) -> bool or nil + * tasmota.setlight(idx:int, values:map) -> map + * +\*********************************************************************************************/ +extern "C" { + // Berry: `tasmota.publish(topic, payload [,retain]) -> nil`` + // + int32_t l_publish(struct bvm *vm); + int32_t l_publish(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top >= 3 && be_isstring(vm, 2) && be_isstring(vm, 3)) { // 2 mandatory string arguments + if (top == 3 || (top == 4 && be_isbool(vm, 4))) { // 3rd optional argument must be bool + const char * topic = be_tostring(vm, 2); + const char * payload = be_tostring(vm, 3); + bool retain = false; + if (top == 4) { + retain = be_tobool(vm, 4); + } + strlcpy(TasmotaGlobal.mqtt_data, payload, sizeof(TasmotaGlobal.mqtt_data)); + MqttPublish(topic, retain); + be_return(vm); // Return + } + } + be_raise(vm, kTypeError, nullptr); + } + + // Berry: `tasmota.cmd(command:string) -> string` + // + int32_t l_cmd(struct bvm *vm); + int32_t l_cmd(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top == 2 && be_isstring(vm, 2)) { // only 1 argument of type string accepted + const char * command = be_tostring(vm, 2); + ExecuteCommand(command, SRC_BERRY); + be_pushstring(vm, TasmotaGlobal.mqtt_data); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + // Berry: tasmota.millis([delay:int]) -> int + // + int32_t l_millis(struct bvm *vm); + int32_t l_millis(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top == 1 || (top == 2 && be_isint(vm, 2))) { // only 1 argument of type string accepted + uint32_t delay = 0; + if (top == 2) { + delay = be_toint(vm, 2); + } + uint32_t ret_millis = millis() + delay; + be_pushint(vm, ret_millis); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + // Berry: tasmota.getoption(index:int) -> int + // + int32_t l_getoption(struct bvm *vm); + int32_t l_getoption(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top == 2 && be_isint(vm, 2)) { + uint32_t opt = GetOption(be_toint(vm, 2)); + be_pushint(vm, opt); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + // Berry: tasmota.timereached(timer:int) -> bool + // + int32_t l_timereached(struct bvm *vm); + int32_t l_timereached(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top == 2 && be_isint(vm, 2)) { // only 1 argument of type string accepted + uint32_t timer = be_toint(vm, 2); + bool reached = TimeReached(timer); + be_pushbool(vm, reached); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + // Berry: tasmota.delay(timer:int) -> nil + // + int32_t l_delay(struct bvm *vm); + int32_t l_delay(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top == 2 && be_isint(vm, 2)) { // only 1 argument of type string accepted + uint32_t timer = be_toint(vm, 2); + delay(timer); + be_return_nil(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + // Berry: `yield() -> nil` + // ESP object + int32_t l_yield(bvm *vm); + int32_t l_yield(bvm *vm) { + optimistic_yield(10); + be_return_nil(vm); + } + + // Berry: tasmota.scaleuint(int * 5) -> int + // + int32_t l_scaleuint(struct bvm *vm); + int32_t l_scaleuint(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top == 6 && be_isint(vm, 2) && be_isint(vm, 3) && be_isint(vm, 4) && be_isint(vm, 5) && be_isint(vm, 6)) { // only 1 argument of type string accepted + int32_t v = be_toint(vm, 2); + int32_t from1 = be_toint(vm, 3); + int32_t from2 = be_toint(vm, 4); + int32_t to1 = be_toint(vm, 5); + int32_t to2 = be_toint(vm, 6); + + int32_t ret = changeUIntScale(v, from1, from2, to1, to2); + be_pushint(vm, ret); + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); + } + + int32_t l_respCmnd(bvm *vm); + int32_t l_respCmnd(bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top == 2) { + const char *msg = be_tostring(vm, 2); + Response_P("%s", msg); + be_return_nil(vm); // Return nil when something goes wrong + } + be_raise(vm, kTypeError, nullptr); + } + + int32_t l_respCmndStr(bvm *vm); + int32_t l_respCmndStr(bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top == 2) { + const char *msg = be_tostring(vm, 2); + ResponseCmndChar(msg); + be_return_nil(vm); // Return nil when something goes wrong + } + be_raise(vm, kTypeError, nullptr); + } + + int32_t l_respCmndDone(bvm *vm); + int32_t l_respCmndDone(bvm *vm) { + ResponseCmndDone(); + be_return_nil(vm); + } + + int32_t l_respCmndError(bvm *vm); + int32_t l_respCmndError(bvm *vm) { + ResponseCmndError(); + be_return_nil(vm); + } + + int32_t l_respCmndFailed(bvm *vm); + int32_t l_respCmndFailed(bvm *vm) { + ResponseCmndFailed(); + be_return_nil(vm); + } + + // update XdrvMailbox.command with actual command + int32_t l_resolveCmnd(bvm *vm); + int32_t l_resolveCmnd(bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top == 2 && be_isstring(vm, 2)) { + const char *msg = be_tostring(vm, 2); + strlcpy(XdrvMailbox.command, msg, CMDSZ); + be_return_nil(vm); // Return nil when something goes wrong + } + be_raise(vm, kTypeError, nullptr); + } + + // push the light status object on the vm stack + void push_getlight(bvm *vm, uint32_t light_num) { + bool data_present = false; // do we have relevant data + be_newobject(vm, "map"); + // check if the light exist + // TasmotaGlobal.devices_present + // Light.device + // Light.subtype + // Light.pwm_multi_channels + // light_controller.isCTRGBLinked() + + if (Light.device > 0) { + // we have a light + + uint8_t channels[LST_MAX]; + char s_rgb[8] = {0}; // RGB raw levels + light_controller.calcLevels(channels); + uint8_t bri = light_state.getBri(); + + // map_insert_int(vm, "_devices_present", TasmotaGlobal.devices_present); + // map_insert_int(vm, "_light_device", Light.device); + // map_insert_int(vm, "_light_subtype", Light.subtype); + // map_insert_int(vm, "_light_multi", Light.pwm_multi_channels); + // map_insert_int(vm, "_light_linked", light_controller.isCTRGBLinked()); + + if (!Light.pwm_multi_channels) { + uint32_t subtype = Light.subtype; // virtual sub-type, for SO37 128 + uint32_t chanidx = 0; // channel offset, for SO37 128 + + + if (light_controller.isCTRGBLinked() && (light_num == 0)) { + data_present = true; // valid combination + if (subtype >= LST_RGBW) { + map_insert_str(vm, "colormode", (light_state.getColorMode() & LCM_RGB ? "rgb" : "ct")); + } + } + if (!light_controller.isCTRGBLinked()) { + if (light_num == 0) { + data_present = true; // valid combination + if (subtype > LST_RGB) { subtype = LST_RGB; } // limit to RGB + bri = light_state.getBriRGB(); + } + if ((light_num == 1) && subtype > LST_RGB) { + data_present = true; // valid combination + subtype = subtype - LST_RGB; + chanidx = 3; // skip first 3 channels + bri = light_state.getBriCT(); + } + } + + if (data_present) { + // see ResponseLightState() + map_insert_bool(vm, "power", bitRead(TasmotaGlobal.power, light_num)); + map_insert_int(vm, "bri", bri); + + if (subtype >= LST_RGB) { + uint16_t hue; + uint8_t sat, bri; + light_state.getHSB(&hue, &sat, &bri); + map_insert_int(vm, "hue", hue); + map_insert_int(vm, "sat", sat); + } + if ((LST_COLDWARM == subtype) || (LST_RGBW <= subtype)) { + map_insert_int(vm, "ct", light_state.getCT()); + } + if (subtype >= LST_RGB) { + snprintf(s_rgb, sizeof(s_rgb), PSTR("%02X%02X%02X"), channels[0], channels[1], channels[2]); + map_insert_str(vm, "rgb", s_rgb); + } + if (subtype > LST_NONE) { + map_insert_list_uint8(vm, "channels", &channels[chanidx], subtype); + } + } + } else { // Light.pwm_multi_channels + if ((light_num >= 0) && (light_num < LST_MAX)) { + data_present = true; + map_insert_bool(vm, "power", Light.power & (1 << light_num)); + map_insert_int(vm, "bri", Light.current_color[light_num]); + map_insert_list_uint8(vm, "channels", &channels[light_num], 1); + } + } + + be_pop(vm, 1); + if (!data_present) { + be_pop(vm, 1); + be_pushnil(vm); + } + } else { + be_pop(vm, 1); + be_pushnil(vm); + } + } + + // get light + int32_t l_getlight(bvm *vm); + int32_t l_getlight(bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top == 1 || (top == 2 && be_isint(vm, 2))) { + int32_t light_num = 0; + if (top > 0) { + light_num = be_toint(vm, 2); + } + push_getlight(vm, light_num); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + // set light + int32_t l_setlight(bvm *vm); + int32_t l_setlight(bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top >= 2 && be_isinstance(vm, 2) && (top != 3 || be_isint(vm, 3))) { + int32_t idx = 0; + if (top >= 3) { + idx = be_toint(vm, 3); + be_pop(vm, 1); // remove last argument to have the map at the top of stack + } + + // power + if (map_find(vm, "power")) { + bool power = be_tobool(vm, -1); + bool current_power = bitRead(TasmotaGlobal.power, idx); + if (power != current_power) { // only send command if needed + ExecuteCommandPower(Light.device + idx, (power) ? POWER_ON : POWER_OFF, SRC_BERRY); + } + } + be_pop(vm, 1); + + // ct + if (map_find(vm, "ct")) { + int32_t ct = be_toint(vm, -1); + light_controller.changeCTB(ct, light_state.getBriCT()); + } + be_pop(vm, 1); + + // hue + if (map_find(vm, "hue")) { + int32_t hue = be_toint(vm, -1); + uint8_t sat; + uint8_t bri; + light_state.getHSB(nullptr, &sat, &bri); + light_controller.changeHSB(hue, sat, bri); + } + be_pop(vm, 1); + + // sat + if (map_find(vm, "sat")) { + int32_t sat = be_toint(vm, -1); + uint16_t hue; + uint8_t bri; + light_state.getHSB(&hue, nullptr, &bri); + light_controller.changeHSB(hue, sat, bri); + } + be_pop(vm, 1); + + // rgb + if (map_find(vm, "rgb")) { + const char * rgb_s = be_tostring(vm, -1); + SBuffer buf = SBuffer::SBufferFromHex(rgb_s, strlen(rgb_s)); + uint8_t channels[LST_MAX] = {}; + memcpy(channels, buf.buf(), buf.len() > LST_MAX ? LST_MAX : buf.len()); + bool on = false; // if all are zero, then only set power off + for (uint32_t i = 0; i < LST_MAX; i++) { + if (channels[i] != 0) { on = true; } + } + if (on) { + light_controller.changeChannels(channels); + } else { + ExecuteCommandPower(idx + 1, POWER_OFF, SRC_BERRY); + } + } + be_pop(vm, 1); + + // channels + if (map_find(vm, "channels")) { + if (be_isinstance(vm, -1)) { + be_getbuiltin(vm, "list"); // add "list" class + if (be_isderived(vm, -2)) { + be_pop(vm, 1); // remove "list" class from top + int32_t list_size = get_list_size(vm); + // AddLog(LOG_LEVEL_INFO, "Instance is list size = %d", list_size); + + uint8_t channels[LST_MAX] = {}; // initialized with all zeroes + if (list_size > LST_MAX) { list_size = LST_MAX; } // no more than 5 channels, no need to test for positive, any negative will be discarded by loop + for (uint32_t i = 0; i < list_size; i++) { + // be_dumpstack(vm); + get_list_item(vm, i); + // be_dumpstack(vm); + int32_t val = be_toint(vm, -1); + be_pop(vm, 1); // remove result from stack + channels[i] = to_u8(val); + + bool on = false; // if all are zero, then only set power off + for (uint32_t i = 0; i < LST_MAX; i++) { + if (channels[i] != 0) { on = true; } + } + if (on) { + light_controller.changeChannels(channels); + } else { + ExecuteCommandPower(idx + 1, POWER_OFF, SRC_BERRY); + } + } + } else { + be_pop(vm, 1); // remove "list" class from top + } + } + } + be_pop(vm, 1); + + // bri is done after channels and rgb + // bri + if (map_find(vm, "bri")) { + int32_t bri = be_toint(vm, -1); + light_controller.changeBri(bri); + } + be_pop(vm, 1); + + push_getlight(vm, idx); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } // TODO + + // get power + int32_t l_getpower(bvm *vm); + int32_t l_getpower(bvm *vm) { + be_newobject(vm, "list"); + for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { + be_pushbool(vm, bitRead(TasmotaGlobal.power, i)); + be_data_push(vm, -2); + be_pop(vm, 1); + } + be_pop(vm, 1); + be_return(vm); // Return + } + + int32_t l_setpower(bvm *vm); + int32_t l_setpower(bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top == 3 && be_isint(vm, 2) && be_isbool(vm, 3)) { + int32_t idx = be_toint(vm, 2); + bool power = be_tobool(vm, 3); + if ((idx >= 0) && (idx < TasmotaGlobal.devices_present)) { + ExecuteCommandPower(idx + 1, (power) ? POWER_ON : POWER_OFF, SRC_BERRY); + be_pushbool(vm, power); + be_return(vm); // Return + } else { + be_return_nil(vm); + } + } + be_raise(vm, kTypeError, nullptr); + } + +} + +/*********************************************************************************************\ + * Native functions mapped to Berry functions + * + * log(msg:string [,log_level:int]) ->nil + * +\*********************************************************************************************/ +extern "C" { + // Berry: `log(msg:string [,log_level:int]) ->nil` + // Logs the string at LOG_LEVEL_INFO (loglevel=2) + int32_t l_logInfo(struct bvm *vm); + int32_t l_logInfo(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top >= 1 && be_isstring(vm, 1)) { // only 1 argument of type string accepted + const char * msg = be_tostring(vm, 1); + uint32_t log_level = LOG_LEVEL_INFO; + if (top >= 2 && be_isint(vm, 2)) { + log_level = be_toint(vm, 2); + if (log_level > LOG_LEVEL_DEBUG_MORE) { log_level = LOG_LEVEL_DEBUG_MORE; } + } + AddLog(log_level, PSTR("%s"), msg); + be_return(vm); // Return + } + be_return_nil(vm); // Return nil when something goes wrong + } + + // Berry: `getFreeHeap() -> int` + // ESP object + int32_t l_getFreeHeap(bvm *vm); + int32_t l_getFreeHeap(bvm *vm) { + be_pushint(vm, ESP.getFreeHeap()); + be_return(vm); + } + + // Berry: `save(file:string, f:closure) -> bool` + int32_t l_save(struct bvm *vm); + int32_t l_save(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + if (top == 2 && be_isstring(vm, 1) && be_isclosure(vm, 2)) { // only 1 argument of type string accepted + const char *fname = be_tostring(vm, 1); + int32_t ret = be_savecode(vm, fname); + be_pushint(vm, ret); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } +} + +// called as a replacement to Berry `print()` +void berry_log(const char * berry_buf); +void berry_log(const char * berry_buf) { + AddLog(LOG_LEVEL_INFO, PSTR("%s"), berry_buf); +} + + +#endif // USE_BERRY diff --git a/tasmota/xdrv_52_3_berry_wire.ino b/tasmota/xdrv_52_3_berry_wire.ino new file mode 100644 index 000000000..5959b98b9 --- /dev/null +++ b/tasmota/xdrv_52_3_berry_wire.ino @@ -0,0 +1,245 @@ +/* + xdrv_52_3_berry_native.ino - Berry scripting language, native fucnctions + + Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#ifdef USE_BERRY + +#include +#include + +// read the `_bus` attribute and return `Wire` or `Wire1` +TwoWire & getWire(bvm *vm); +TwoWire & getWire(bvm *vm) { + be_getmember(vm, 1, "_bus"); + int32_t bus = be_toint(vm, -1); + be_pop(vm, 1); + if (0 == bus) { + return Wire; + } else { + return Wire1; + } +} +int32_t getBus(bvm *vm); +int32_t getBus(bvm *vm) { + be_getmember(vm, 1, "_bus"); + int32_t bus = be_toint(vm, -1); + be_pop(vm, 1); + return bus; +} + +/*********************************************************************************************\ + * Native functions mapped to Berry functions + * + * import wire + * + * wire.getfreeheap() -> int + * +\*********************************************************************************************/ +extern "C" { +#ifdef USE_I2C + // Berry: `init([bus:int = 0]) -> nil + int32_t b_wire_init(struct bvm *vm); + int32_t b_wire_init(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + int32_t bus = 0; + if (top > 1 && be_isint(vm, 2)) { + bus = be_toint(vm, 2); + if (bus < 0) { bus = 0; } + if (bus > 1) { bus = 1; } + } + // store bus in instance + be_pushint(vm, bus); + be_setmember(vm, 1, "_bus"); + be_return_nil(vm); + } + + // Berry: `begintransmission(address:int) -> nil` + int32_t b_wire_begintransmission(struct bvm *vm); + int32_t b_wire_begintransmission(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + TwoWire & myWire = getWire(vm); + if (top == 2 && be_isint(vm, 2)) { // only 1 argument of type string accepted + int32_t address = be_toint(vm, 2); + myWire.beginTransmission(address); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + // Berry: `endtransmission([stop:bool]) -> nil` + int32_t b_wire_endtransmission(struct bvm *vm); + int32_t b_wire_endtransmission(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + TwoWire & myWire = getWire(vm); + if (top == 1 || (top == 2 && be_isbool(vm, 2))) { // only 1 argument of type string accepted + bool stop = true; + if (top == 1) { + stop = be_tobool(vm, 2); + } + uint32_t ret = myWire.endTransmission(stop); + be_pushint(vm, ret); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + // Berry: `requestfrom(address:int, quantity:int [stop:bool = true]) -> nil` + int32_t b_wire_requestfrom(struct bvm *vm); + int32_t b_wire_requestfrom(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + TwoWire & myWire = getWire(vm); + if ( (top == 3 || (top == 4 && be_isbool(vm, 4))) + && be_isint(vm, 2) && be_isint(vm, 3) ) { + int32_t address = be_toint(vm, 2); + int32_t quantity = be_toint(vm, 3); + bool stop = true; + if (top == 4) { + stop = be_tobool(vm, 4); + } + myWire.requestFrom((uint16_t)address, (uint8_t)quantity, stop); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + // Berry: `available() -> bool` + int32_t b_wire_available(struct bvm *vm); + int32_t b_wire_available(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + TwoWire & myWire = getWire(vm); + if (top == 1) { + size_t available = myWire.available(); + be_pushint(vm, available); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + // Berry: `write(value:int | s:string) -> nil` + int32_t b_wire_write(struct bvm *vm); + int32_t b_wire_write(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + TwoWire & myWire = getWire(vm); + if (top == 2 && (be_isint(vm, 2) || be_isstring(vm, 2))) { + if (be_isint(vm, 2)) { + int32_t value = be_toint(vm, 2); + myWire.write(value); + } else if (be_isstring(vm, 2)) { + const char * s = be_tostring(vm, 1); + myWire.write(s); + } else { + be_return_nil(vm); + } + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + // Berry: `read() -> int` + int32_t b_wire_read(struct bvm *vm); + int32_t b_wire_read(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + TwoWire & myWire = getWire(vm); + if (top == 1) { + int32_t value = myWire.read(); + be_pushint(vm, value); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + int32_t b_wire_scan(struct bvm *vm); + int32_t b_wire_scan(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + TwoWire & myWire = getWire(vm); + if (top == 1) { + be_newobject(vm, "list"); + for (uint8_t address = 1; address <= 127; address++) { + myWire.beginTransmission(address); + int32_t error = myWire.endTransmission(); + if (0 == error) { + be_pushint(vm, address); + be_data_push(vm, -2); + be_pop(vm, 1); + } + } + be_pop(vm, 1); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + // Berry: `write(address:int, reg:int, val:int, size:int) -> bool or nil` + int32_t b_wire_validwrite(struct bvm *vm); + int32_t b_wire_validwrite(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + int32_t bus = getBus(vm); + if (top == 5 && be_isint(vm, 2) && be_isint(vm, 3) && be_isint(vm, 4) && be_isint(vm, 5)) { + uint8_t addr = be_toint(vm, 2); + uint8_t reg = be_toint(vm, 3); + uint8_t val = be_toint(vm, 4); + uint8_t size = be_toint(vm, 5); + bool ok = I2cWrite(addr, reg, val, size, bus); + be_pushbool(vm, ok); + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } + + // Berry: `read(address:int, reg:int, size:int) -> int or nil` + int32_t b_wire_validread(struct bvm *vm); + int32_t b_wire_validread(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + int32_t bus = getBus(vm); + if (top == 4 && be_isint(vm, 2) && be_isint(vm, 3) && be_isint(vm, 4)) { + uint8_t addr = be_toint(vm, 2); + uint8_t reg = be_toint(vm, 3); + uint8_t size = be_toint(vm, 4); + bool ok = I2cValidRead(addr, reg, size); // TODO + if (ok) { + be_pushint(vm, i2c_buffer); + } else { + be_pushnil(vm); + } + be_return(vm); // Return + } + be_raise(vm, kTypeError, nullptr); + } +#else // USE_I2C + // + int32_t b_wire_i2cmissing(struct bvm *vm); + int32_t b_wire_i2cmissing(struct bvm *vm) { + be_raise(vm, "feature_error", "I2C is not enabled, use '#define USE_I2C'"); + } + + // define weak aliases + int32_t b_wire_init(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing"))); + int32_t b_wire_begintransmission(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing"))); + int32_t b_wire_endtransmission(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing"))); + int32_t b_wire_requestfrom(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing"))); + int32_t b_wire_available(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing"))); + int32_t b_wire_write(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing"))); + int32_t b_wire_read(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing"))); + int32_t b_wire_scan(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing"))); + int32_t b_wire_validwrite(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing"))); + int32_t b_wire_validread(struct bvm *vm) __attribute__ ((weak, alias ("b_wire_i2cmissing"))); +#endif // USE_I2C +} + +#endif // USE_BERRY diff --git a/tasmota/xdrv_52_7_berry_embedded.ino b/tasmota/xdrv_52_7_berry_embedded.ino index b9575da81..83a3895e7 100644 --- a/tasmota/xdrv_52_7_berry_embedded.ino +++ b/tasmota/xdrv_52_7_berry_embedded.ino @@ -32,60 +32,33 @@ const char berry_prog[] = //"def noop() log('noop before'); yield(); log('middle after'); yield(); log('noop after'); end " //"log(\"foobar\") " + // create a 'ntv' module to allow functions to be registered in a safe namespace + "ntv = module('ntv') " + // auto-import modules // // import alias - "import wire " + "import energy " // Phase 1 - // Prepare the super class that will be eventually in Flash - "class Tasmota_ntv " - "var _op, _operators, _rules, _timers, _cmd " - - // Map all native functions to methods - // Again, this will be eventually pre-compiled - "var getfreeheap, publish, cmd, getoption, millis, timereached, yield " - "var respcmnd, respcmndstr, respcmnd_done, respcmnd_error, respcmnd_failed, resolvecmnd " - "var getlight " - "def init_ntv() " - "import tasmota_ntv " - "self.getfreeheap = tasmota_ntv.getfreeheap " - "self.publish = tasmota_ntv.publish " - "self.cmd = tasmota_ntv.cmd " - "self.getoption = tasmota_ntv.getoption " - "self.millis = tasmota_ntv.millis " - "self.timereached = tasmota_ntv.timereached " - "self.yield = tasmota_ntv.yield " - "self._operators = tasmota_ntv._operators " - - "self.respcmnd = tasmota_ntv.respcmnd " - "self.respcmndstr = tasmota_ntv.respcmndstr " - "self.respcmnd_done = tasmota_ntv.respcmnd_done " - "self.respcmnd_error = tasmota_ntv.respcmnd_error " - "self.respcmnd_failed = tasmota_ntv.respcmnd_failed " - "self.resolvecmnd = tasmota_ntv.resolvecmnd " - - "self.getlight = tasmota_ntv.getlight " - "end " - + "class Tasmota: Tasmota_ntv " + // for now the variables are built, need to find a way to push in Flash "def init() " - "self._op = [ " - "['==', /s1,s2-> str(s1) == str(s2)]," - "['!==',/s1,s2-> str(s1) != str(s2)]," - "['=', /f1,f2-> real(f1) == real(f2)]," - "['!=', /f1,f2-> real(f1) != real(f2)]," - "['>=', /f1,f2-> real(f1) >= real(f2)]," - "['<=', /f1,f2-> real(f1) <= real(f2)]," - "['>', /f1,f2-> real(f1) > real(f2)]," - "['<', /f1,f2-> real(f1) < real(f2)]," + "self._op = ['==', '!==', '=', '!=', '>=', '<=', '>', '<'] " + "self._opf = [ " + "/s1,s2-> str(s1) == str(s2)," + "/s1,s2-> str(s1) != str(s2)," + "/f1,f2-> real(f1) == real(f2)," + "/f1,f2-> real(f1) != real(f2)," + "/f1,f2-> real(f1) >= real(f2)," + "/f1,f2-> real(f1) <= real(f2)," + "/f1,f2-> real(f1) > real(f2)," + "/f1,f2-> real(f1) < real(f2)," "] " + "self._operators = \"=<>!|\" " "self._rules = {} " "self._timers = [] " "self._cmd = {} " - "self.init_ntv() " "end " - "end " - - "class Tasmota: Tasmota_ntv " // add `charsinstring(s:string,c:string) -> int`` // looks for any char in c, and return the position of the first chat // or -1 if not found @@ -125,10 +98,11 @@ const char berry_prog[] = "var op_left = op_split[0] " "var op_rest = op_split[1] " // # iterate through operators - "for op: self._op " - "if string.find(op_rest,op[0]) == 0 " - "var op_func = op[1] " - "var op_right = string.split(op_rest,size(op[0]))[1] " + "for i: 0..size(self._op)-1 " + "var op = self._op[i] " + "if string.find(op_rest,op) == 0 " + "var op_func = self._opf[i] " + "var op_right = string.split(op_rest,size(op))[1] " "return [op_left,op_func,op_right] " "end " "end " @@ -137,7 +111,6 @@ const char berry_prog[] = "end " // Rules trigger if match. return true if match, false if not - // Note: condition is not yet managed "def try_rule(ev, rule, f) " "import string " "var rl_list = self.find_op(rule) " @@ -229,6 +202,8 @@ const char berry_prog[] = // Instantiate tasmota object "tasmota = Tasmota() " + "wire = Wire(0) " + "wire1 = Wire(1) " // Not sure how to run call methods from C "def _exec_rules(e) return tasmota.exec_rules(e) end " @@ -253,19 +228,30 @@ const char berry_prog[] = "var c = compile(f,'file') " // save the compiled bytecode "if !native " - "save(f+'c', c) " + "try " + "save(f+'c', c) " + "except .. as e " + "log(string.format('BRY: could not save compiled file %s (%s)',f+'c',e)) " + "end " "end " // call the compiled code "c() " + "log(string.format(\"BRY: sucessfully loaded '%s'\",f)) " "except .. as e " - "log(string.format(\"BRY: could not load file '%s' - %s\",f,e)) " + "raise \"io_error\",string.format(\"Could not load file '%s'\",f) " "end " "end " // try to load "/autoexec.be" // "try compile('/autoexec.be','file')() except .. log('BRY: no /autoexec.bat file') end " - - // Wire ; +const char berry_autoexec[] = + // load "autoexec.be" using import, which loads either .be or .bec file + "try " + "load('autoexec.be') " + "except .. " + "log(\"BRY: No 'autoexec.be' file\") " + "end " + ; #endif // USE_BERRY diff --git a/tasmota/xdrv_52_9_berry.ino b/tasmota/xdrv_52_9_berry.ino index fbbda679e..976e9e601 100644 --- a/tasmota/xdrv_52_9_berry.ino +++ b/tasmota/xdrv_52_9_berry.ino @@ -36,8 +36,7 @@ class BerrySupport { public: bvm *vm = nullptr; // berry vm bool rules_busy = false; // are we already processing rules, avoid infinite loop - const char *fname = nullptr; // name of berry function to call - int32_t fret = 0; + bool autoexec_done = false; // do we still need to load 'autoexec.be' }; BerrySupport berry; @@ -59,10 +58,6 @@ void checkBeTop(void) { * \*********************************************************************************************/ // // call a function (if exists) of type void -> void -// void callBerryFunctionVoid_berry(const char * fname) { -// berry.fret = 0; -// callBerryFunctionVoid(berry.fname); -// } bool callBerryRule(void) { if (berry.rules_busy) { return false; } @@ -244,7 +239,7 @@ void BrReset(void) { ret_code2 = be_pcall(berry.vm, 0); if (ret_code1 != 0) { AddLog(LOG_LEVEL_ERROR, PSTR(D_LOG_BERRY "ERROR: be_pcall [%s] %s"), be_tostring(berry.vm, -2), be_tostring(berry.vm, -1)); - be_pop(berry.vm, 2); + be_pop(berry.vm, 1); break; } // AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry code ran, RAM used=%u"), be_gc_memcount(berry.vm)); @@ -268,6 +263,32 @@ void BrReset(void) { } } + +void BrAutoexec(void) { + if (berry.vm == nullptr) { return; } + + int32_t ret_code1, ret_code2; + bool berry_init_ok = false; + + // load 'autoexec.be' or 'autoexec.bec' + ret_code1 = be_loadstring(berry.vm, berry_autoexec); + // be_dumpstack(berry.vm); + if (ret_code1 != 0) { + be_pop(berry.vm, 2); + return; + } + ret_code2 = be_pcall(berry.vm, 0); + // be_dumpstack(berry.vm); + if (ret_code1 != 0) { + // AddLog(LOG_LEVEL_ERROR, PSTR(D_LOG_BERRY "ERROR: be_pcall [%s] %s"), be_tostring(berry.vm, -2), be_tostring(berry.vm, -1)); + be_pop(berry.vm, 1); + return; + } + // AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "Berry code ran, RAM used=%u"), be_gc_memcount(berry.vm)); + be_pop(berry.vm, 1); + // be_dumpstack(berry.vm); +} + /*********************************************************************************************\ * Tasmota Commands \*********************************************************************************************/ @@ -304,11 +325,11 @@ void CmndBrRun(void) { // AddLog(LOG_LEVEL_INFO, "run: type(2)=%s", be_typename(berry.vm, 2)); // code taken from REPL, look first at top, and if nil, look at return value - if (!be_isnil(berry.vm, 1)) { + // if (!be_isnil(berry.vm, 1)) { ret_val = be_tostring(berry.vm, 1); - } else { - ret_val = be_tostring(berry.vm, 2); - } + // } else { + // ret_val = be_tostring(berry.vm, 2); + // } Response_P("{\"" D_PRFX_BR "\":\"%s\"}", EscapeJSONString(ret_val).c_str()); // can't use XdrvMailbox.command as it may have been overwritten by subcommand be_pop(berry.vm, 1); } else { @@ -340,6 +361,12 @@ bool Xdrv52(uint8_t function) case FUNC_INIT: BrReset(); break; + case FUNC_LOOP: + if (!berry.autoexec_done) { + BrAutoexec(); + berry.autoexec_done = true; + } + break; case FUNC_EVERY_50_MSECOND: callBerryFunctionVoid(PSTR("_run_deferred")); break; @@ -383,8 +410,6 @@ bool Xdrv52(uint8_t function) case FUNC_BUTTON_PRESSED: break; - case FUNC_LOOP: - break; } return result; diff --git a/tasmota/xdrv_84_esp32_core2.ino b/tasmota/xdrv_84_esp32_core2.ino index dc196536c..9f0d3cc60 100644 --- a/tasmota/xdrv_84_esp32_core2.ino +++ b/tasmota/xdrv_84_esp32_core2.ino @@ -32,15 +32,14 @@ rtc better sync #include #include -#include #include #include +#include #define XDRV_84 84 struct CORE2_globs { AXP192 Axp; - MPU6886 Mpu; BM8563_RTC Rtc; bool ready; bool tset; @@ -56,9 +55,6 @@ struct CORE2_ADC { float vbus_c; float batt_c; float temp; - int16_t x; - int16_t y; - int16_t z; } core2_adc; // cause SC card is needed by scripter @@ -75,9 +71,6 @@ void CORE2_Module_Init(void) { // motor voltage core2_globs.Axp.SetLDOVoltage(3,2000); - core2_globs.Mpu.Init(); - I2cSetActiveFound(MPU6886_ADDRESS, "MPU6886"); - core2_globs.Rtc.begin(); I2cSetActiveFound(RTC_ADRESS, "RTC"); @@ -119,12 +112,6 @@ const char HTTP_CORE2[] PROGMEM = "{s}BATT Voltage" "{m}%s V" "{e}" "{s}BATT Current" "{m}%s mA" "{e}" "{s}Chip Temperature" "{m}%s C" "{e}"; -#ifdef USE_MPU6886 -const char HTTP_CORE2_MPU[] PROGMEM = - "{s}MPU x" "{m}%d mg" "{e}" - "{s}MPU y" "{m}%d mg" "{e}" - "{s}MPU z" "{m}%d mg" "{e}"; -#endif // USE_MPU6886 #endif // USE_WEBSERVER @@ -146,18 +133,9 @@ void CORE2_WebShow(uint32_t json) { dtostrfd(core2_adc.temp, 2, tstring); if (json) { - ResponseAppend_P(PSTR(",\"CORE2\":{\"VBV\":%s,\"BV\":%s,\"VBC\":%s,\"BC\":%s,\"CT\":%s"), vstring, cstring, bvstring, bcstring, tstring); - -#ifdef USE_MPU6886 - ResponseAppend_P(PSTR(",\"MPUX\":%d,\"MPUY\":%d,\"MPUZ\":%d"), core2_adc.x, core2_adc.y, core2_adc.z); -#endif - ResponseJsonEnd(); + ResponseAppend_P(PSTR(",\"CORE2\":{\"VBV\":%s,\"BV\":%s,\"VBC\":%s,\"BC\":%s,\"CT\":%s}"), vstring, cstring, bvstring, bcstring, tstring); } else { WSContentSend_PD(HTTP_CORE2, vstring, cstring, bvstring, bcstring, tstring); - -#ifdef USE_MPU6886 - WSContentSend_PD(HTTP_CORE2_MPU, core2_adc.x, core2_adc.y, core2_adc.z); -#endif // USE_MPU6886 } } @@ -342,15 +320,6 @@ void CORE2_GetADC(void) { core2_adc.batt_c = core2_globs.Axp.GetBatCurrent(); core2_adc.temp = core2_globs.Axp.GetTempInAXP192(); -#ifdef USE_MPU6886 - float x; - float y; - float z; - core2_globs.Mpu.getAccelData(&x, &y, &z); - core2_adc.x=x*1000; - core2_adc.y=y*1000; - core2_adc.z=z*1000; -#endif // USE_MPU6886 } /*********************************************************************************************\ diff --git a/tasmota/xdsp_01_lcd.ino b/tasmota/xdsp_01_lcd.ino index 8f3a9a779..efb3b542c 100644 --- a/tasmota/xdsp_01_lcd.ino +++ b/tasmota/xdsp_01_lcd.ino @@ -55,8 +55,9 @@ void LcdInit(uint8_t mode) } } -void LcdInitDriver(void) -{ +void LcdInitDriver(void) { + if (!TasmotaGlobal.i2c_enabled) { return; } + if (!Settings.display_model) { if (I2cSetDevice(LCD_ADDRESS1)) { Settings.display_address[0] = LCD_ADDRESS1; diff --git a/tasmota/xdsp_02_ssd1306.ino b/tasmota/xdsp_02_ssd1306.ino index 1698f00f6..03bea26b6 100644 --- a/tasmota/xdsp_02_ssd1306.ino +++ b/tasmota/xdsp_02_ssd1306.ino @@ -47,8 +47,9 @@ extern uint8_t *buffer; /*********************************************************************************************/ -void SSD1306InitDriver(void) -{ +void SSD1306InitDriver(void) { + if (!TasmotaGlobal.i2c_enabled) { return; } + if (!Settings.display_model) { if (I2cSetDevice(OLED_ADDRESS1)) { Settings.display_address[0] = OLED_ADDRESS1; diff --git a/tasmota/xdsp_03_matrix.ino b/tasmota/xdsp_03_matrix.ino index 3b0155a8f..6d20efeec 100644 --- a/tasmota/xdsp_03_matrix.ino +++ b/tasmota/xdsp_03_matrix.ino @@ -194,8 +194,9 @@ void MatrixInit(uint8_t mode) } } -void MatrixInitDriver(void) -{ +void MatrixInitDriver(void) { + if (!TasmotaGlobal.i2c_enabled) { return; } + mtx_buffer = (char*)(malloc(MTX_MAX_SCREEN_BUFFER)); if (mtx_buffer != nullptr) { if (!Settings.display_model) { diff --git a/tasmota/xdsp_04_ili9341.ino b/tasmota/xdsp_04_ili9341.ino index 599964ab9..737b9376f 100644 --- a/tasmota/xdsp_04_ili9341.ino +++ b/tasmota/xdsp_04_ili9341.ino @@ -23,6 +23,8 @@ #define XDSP_04 4 +enum IliModes { ILIMODE_9341 = 1, ILIMODE_9342, ILIMODE_MAX }; + #include extern uint8_t *buffer; @@ -37,13 +39,10 @@ uint8_t ili9342_ctouch_counter = 0; uint8_t ili9342_ctouch_counter = 0; #endif // USE_FT5206 - bool tft_init_done = false; -#define ILI9341_ID 1 -#define ILI9342_ID 2 -//Settings.display_options.ilimode = ILI9341_ID; +//Settings.display_options.ilimode = ILIMODE_9341; /*********************************************************************************************/ @@ -66,8 +65,8 @@ void ILI9341_InitDriver() // disable screen buffer buffer = NULL; - if (!Settings.display_options.ilimode) { - Settings.display_options.ilimode = ILI9341_ID; + if (!Settings.display_options.ilimode || (Settings.display_options.ilimode >= ILIMODE_MAX)) { + Settings.display_options.ilimode = ILIMODE_9341; } // default colors @@ -102,7 +101,7 @@ void ILI9341_InitDriver() renderer->setTextFont(2); renderer->setTextSize(1); renderer->setTextColor(ILI9341_WHITE, ILI9341_BLACK); - renderer->DrawStringAt(50, (Settings.display_height/2)-12, (Settings.display_options.ilimode & 3)==ILI9341_ID?"ILI9341 TFT!":"ILI9342 TFT!", ILI9341_WHITE, 0); + renderer->DrawStringAt(50, (Settings.display_height/2)-12, (Settings.display_options.ilimode & 3)==ILIMODE_9341?"ILI9341 TFT!":"ILI9342 TFT!", ILI9341_WHITE, 0); delay(1000); #endif // SHOW_SPLASH diff --git a/tasmota/xdsp_07_sh1106.ino b/tasmota/xdsp_07_sh1106.ino index 3ca925932..a4fa94509 100644 --- a/tasmota/xdsp_07_sh1106.ino +++ b/tasmota/xdsp_07_sh1106.ino @@ -48,8 +48,9 @@ Adafruit_SH1106 *oled1106; /*********************************************************************************************/ -void SH1106InitDriver() -{ +void SH1106InitDriver() { + if (!TasmotaGlobal.i2c_enabled) { return; } + if (!Settings.display_model) { if (I2cSetDevice(OLED_ADDRESS1)) { Settings.display_address[0] = OLED_ADDRESS1; diff --git a/tasmota/xdsp_11_sevenseg.ino b/tasmota/xdsp_11_sevenseg.ino index b3bde3149..69342cbbf 100644 --- a/tasmota/xdsp_11_sevenseg.ino +++ b/tasmota/xdsp_11_sevenseg.ino @@ -147,8 +147,9 @@ void SevensegInit(uint8_t mode) } } -void SevensegInitDriver(void) -{ +void SevensegInitDriver(void) { + if (!TasmotaGlobal.i2c_enabled) { return; } + if (!Settings.display_model) { if (I2cSetDevice(Settings.display_address[0])) { Settings.display_model = XDSP_11; diff --git a/tasmota/xdsp_15_tm1637.ino b/tasmota/xdsp_15_tm1637.ino index 82f6c32a5..0b507fce5 100644 --- a/tasmota/xdsp_15_tm1637.ino +++ b/tasmota/xdsp_15_tm1637.ino @@ -1,5 +1,5 @@ /* - xdsp_15_tm1637.ino - Support for TM1637 seven-segment display (upto 6 digits) for Tasmota + xdsp_15_tm1637.ino - Support for TM1637- and TM1638-based seven-segment displays for Tasmota Copyright (C) 2021 Ajith Vasudevan @@ -21,29 +21,38 @@ #ifdef USE_DISPLAY_TM1637 /*********************************************************************************************\ This driver enables the display of numbers (both integers and floats) and basic text - on the inexpensive TM1637-based seven-segment modules (tested on both 4- and 6-digit variants). + on the inexpensive TM1637- and TM1638-based seven-segment modules. + Raw segments can also be displayed. - In addition, it is also possible to set brightness (8 levels), clear the display, scroll text, display - a rudimentary bar graph, and a Clock (12 hr and 24 hr). + + In addition, it is also possible to set brightness (8 levels), clear the display, scroll text, + display a rudimentary bar graph, and a Clock (12 hr and 24 hr). To use, compile Tasmota with USE_DISPLAY and USE_DISPLAY_TM1637, or build the tasmota-display env. - The pins to use are "SSPI MOSI" and "SSPI SCLK". - - Connect the TM1637 display module's DIO and CLK pins to any free GPIOs of the ESP8266 module + For TM1637: + Connect the TM1637 display module's pins to any free GPIOs of the ESP8266 module and assign the pins as follows from Tasmota's GUI: - DIO hardware pin --> "SSPI MOSI" - CLK hardware pin --> "SSPI SCLK" + DIO hardware pin --> "TM1637 DIO" + CLK hardware pin --> "TM1637 CLK" - Once the device restarts the following "Display" commands become available: + For TM1638: + Connect the TM1638 display module's pins to any free GPIOs of the ESP8266 module + and assign the pins as follows from Tasmota's GUI: + + DIO hardware pin --> "TM1638 DIO" + CLK hardware pin --> "TM1638 CLK" + STB hardware pin --> "TM1638 STB" + Once the GPIO configuration is saved and the ESP8266/ESP32 module restarts, set the Display Model to 15 + using the command "DisplayModel 15" - DisplaySize size {1-6} + If your display is a TM1637 with 6 digits, set Display Columns to the number of digits your + display has, using the command "DisplayCols 6" and restart the ESP module. - Sets the number of digits to use. This is typically set to the actual number of digits available - in the display module. command e.g., "DisplaySize 6" + After the ESP8266/ESP32 module restarts again, the following "Display" commands can be used: DisplayClear @@ -51,57 +60,51 @@ Clears the display, command: "DisplayClear" - DisplayNumber num [,position {0-(TM1637Data.num_digits-1))} [,leading_zeros {0|1} [,length {1 to TM1637Data.num_digits}]]] + DisplayNumber num [,position {0-(Settings.display_width-1))} [,leading_zeros {0|1} [,length {1 to Settings.display_width}]]] Clears and then displays number without decimal. command e.g., "DisplayNumber 1234" Control 'leading zeros', 'length' and 'position' with "DisplayNumber 1234, , , " - 'leading zeros' can be 1 or 0 (default), 'length' can be 1 to TM1637Data.num_digits, 'position' can be 0 (left-most) to TM1637Data.num_digits (right-most). + 'leading zeros' can be 1 or 0 (default), 'length' can be 1 to Settings.display_width, 'position' can be 0 (left-most) to Settings.display_width (right-most). See function description below for more details. - DisplayNumberNC num [,position {0-(TM1637Data.num_digits-1))} [,leading_zeros {0|1} [,length {1 to TM1637Data.num_digits}]]] + DisplayNumberNC num [,position {0-(Settings.display_width-1))} [,leading_zeros {0|1} [,length {1 to Settings.display_width}]]] Display integer number as above, but without clearing first. e.g., "DisplayNumberNC 1234". Usage is same as above. - DisplayFloat num [,position {0-(TM1637Data.num_digits-1)} [,precision {0-TM1637Data.num_digits} [,length {1 to TM1637Data.num_digits}]]] + DisplayFloat num [,position {0-(Settings.display_width-1)} [,precision {0-Settings.display_width} [,length {1 to Settings.display_width}]]] Clears and then displays float (with decimal point) command e.g., "DisplayFloat 12.34" See function description below for more details. - DisplayFloatNC num [,position {0-(TM1637Data.num_digits-1)} [,precision {0-TM1637Data.num_digits} [,length {1 to TM1637Data.num_digits}]]] + DisplayFloatNC num [,position {0-(Settings.display_width-1)} [,precision {0-Settings.display_width} [,length {1 to Settings.display_width}]]] Displays float (with decimal point) as above, but without clearing first. command e.g., "DisplayFloatNC 12.34" See function description below for more details. - DisplayBrightness num {0-8} + DisplayRaw position {0-(Settings.display_width-1)},length {1 to Settings.display_width}, num1 [, num2[, num3[, num4[, ...upto Settings.display_width numbers]]]]] - Set brightness (0 (off) to 8) command e.g., "DisplayBrightness 2" - - - - DisplayRaw position {0-(TM1637Data.num_digits-1)},length {1 to TM1637Data.num_digits}, num1 [, num2[, num3[, num4[, ...upto TM1637Data.num_digits numbers]]]]] - - Takes upto TM1637Data.num_digits comma-separated integers (0-255) and displays raw segments. Each number represents a + Takes upto Settings.display_width comma-separated integers (0-255) and displays raw segments. Each number represents a 7-segment digit. Each 8-bit number represents individual segments of a digit. For example, the command "DisplayRaw 0, 4, 255, 255, 255, 255" would display "[8.8.8.8.]" - DisplayText text [, position {0-(TM1637Data.num_digits-1)} [,length {1 to TM1637Data.num_digits}]] + DisplayText text [, position {0-(Settings.display_width-1)} [,length {1 to Settings.display_width}]] Clears and then displays basic text. command e.g., "DisplayText ajith vasudevan" Control 'length' and 'position' with "DisplayText , , " - 'length' can be 1 to TM1637Data.num_digits, 'position' can be 0 (left-most) to TM1637Data.num_digits-1 (right-most) + 'length' can be 1 to Settings.display_width, 'position' can be 0 (left-most) to Settings.display_width-1 (right-most) A caret(^) symbol in the text input is dispayed as the degrees(°) symbol. This is useful for displaying Temperature! For example, the command "DisplayText 22.5^" will display "22.5°". - DisplayTextNC text [, position {0-TM1637Data.num_digits-1} [,length {1 to TM1637Data.num_digits}]] + DisplayTextNC text [, position {0-Settings.display_width-1} [,length {1 to Settings.display_width}]] Clears first, then displays text. Usage is same as above. @@ -132,59 +135,93 @@ "DisplayClock 2" // 24 hr format "DisplayClock 0" // turn off clock + + + \*********************************************************************************************/ #define XDSP_15 15 -#define BRIGHTNESS_MIN 0 // Display OFF -#define BRIGHTNESS_MAX 8 #define CMD_MAX_LEN 55 #define LEVEL_MIN 0 #define LEVEL_MAX 100 #define SCROLL_MAX_LEN 50 +#define POSITION_MIN 0 +#define POSITION_MAX 8 +#define LED_MIN 0 +#define LED_MAX 255 #include "SevenSegmentTM1637.h" +#include + SevenSegmentTM1637 *tm1637display; +TM1638plus *tm1638display; + +enum display_types { TM1637, TM1638 }; struct { char scroll_text[CMD_MAX_LEN]; char msg[60]; - uint8_t num_digits = 4; - uint8_t prev_num_digits = 4; + char model_name[8]; uint8_t scroll_delay = 4; uint8_t scroll_index = 0; uint8_t iteration = 0; - uint8_t brightness = 5; + uint8_t buttons; + uint8_t display_type = TM1637; + uint8_t prev_buttons; + bool init_done = false; bool scroll = false; bool show_clock = false; bool clock_24 = false; + bool LED[8] = {false, false, false, false, false, false, false, false}; } TM1637Data; /*********************************************************************************************\ * Init function \*********************************************************************************************/ -void TM1637Init(void) { - if (PinUsed(GPIO_TM1637CLK) && PinUsed(GPIO_TM1637DIO)) { - tm1637display = new SevenSegmentTM1637(Pin(GPIO_TM1637CLK), Pin(GPIO_TM1637DIO)); - if (tm1637display) { - Settings.display_model = XDSP_15; - TM1637Data.num_digits = Settings.display_size > 3 ? Settings.display_size : 4; - Settings.display_size = TM1637Data.num_digits; - tm1637display->begin(TM1637Data.num_digits, 1); - tm1637display->setBacklight(TM1637Data.brightness * 10); - TM1637ClearDisplay(); - AddLog(LOG_LEVEL_INFO, PSTR("DSP: TM1637")); +void TM1637Init(void) { + if (PinUsed(GPIO_TM1638CLK) && PinUsed(GPIO_TM1638DIO) && PinUsed(GPIO_TM1638STB)) { + TM1637Data.display_type = TM1638; + Settings.display_width = 8; + } + else if (PinUsed(GPIO_TM1637CLK) && PinUsed(GPIO_TM1637DIO)) { + TM1637Data.display_type = TM1637; + if ((!Settings.display_width || Settings.display_width > 6)) { + Settings.display_width = 4; } } + else { + return; + } + + Settings.display_model = XDSP_15; + Settings.display_cols[0] = Settings.display_width; + Settings.display_height = 1; + Settings.display_rows = Settings.display_height; + + if (TM1637 == TM1637Data.display_type) { + strcpy_P(TM1637Data.model_name, PSTR("TM1637")); + tm1637display = new SevenSegmentTM1637(Pin(GPIO_TM1637CLK), Pin(GPIO_TM1637DIO)); + tm1637display->begin(Settings.display_width, 1); + } + else if (TM1638 == TM1637Data.display_type) { + strcpy_P(TM1637Data.model_name, PSTR("TM1638")); + tm1638display = new TM1638plus(Pin(GPIO_TM1638STB), Pin(GPIO_TM1638CLK), Pin(GPIO_TM1638DIO), true ); + tm1638display->displayBegin(); + } + TM1637ClearDisplay(); + TM1637Dim(); + TM1637Data.init_done = true; + AddLog(LOG_LEVEL_INFO, PSTR("DSP: %s with %d digits"), TM1637Data.model_name, Settings.display_width); } /*********************************************************************************************\ * Displays number without decimal, with/without leading zeros, specifying start-position * and length, optionally skipping clearing display before displaying the number. -* commands: DisplayNumber num [,position {0-(TM1637Data.num_digits-1)} [,leading_zeros {0|1} [,length {1 to TM1637Data.num_digits}]]] -* DisplayNumberNC num [,position {0-(TM1637Data.num_digits-1)} [,leading_zeros {0|1} [,length {1 to TM1637Data.num_digits}]]] // "NC" --> "No Clear" +* commands: DisplayNumber num [,position {0-(Settings.display_width-1)} [,leading_zeros {0|1} [,length {1 to Settings.display_width}]]] +* DisplayNumberNC num [,position {0-(Settings.display_width-1)} [,leading_zeros {0|1} [,length {1 to Settings.display_width}]]] // "NC" --> "No Clear" \*********************************************************************************************/ bool CmndTM1637Number(bool clear) { char sNum[CMD_MAX_LEN]; @@ -214,7 +251,7 @@ bool CmndTM1637Number(bool clear) { } - if((position < 0) || (position > (TM1637Data.num_digits-1))) position = 0; + if((position < 0) || (position > (Settings.display_width-1))) position = 0; AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: num %d, pos %d, lead %d, len %d"), num, position, leadingzeros, length); @@ -223,22 +260,23 @@ bool CmndTM1637Number(bool clear) { char txt[30]; snprintf_P(txt, sizeof(txt), PSTR("%d"), num); if(!length) length = strlen(txt); - if((length < 0) || (length > TM1637Data.num_digits)) length = TM1637Data.num_digits; + if((length < 0) || (length > Settings.display_width)) length = Settings.display_width; char pad = (leadingzeros ? '0': ' '); uint32_t i = position; uint8_t rawBytes[1]; - rawBytes[0] = tm1637display->encode(pad); + for(; iTM1637Data.num_digits) break; - tm1637display->printRaw(rawBytes, 1, i); + if(i>Settings.display_width) break; + if(TM1637Data.display_type == TM1637) { rawBytes[0] = tm1637display->encode(pad); tm1637display->printRaw(rawBytes, 1, i); } + else if(TM1637Data.display_type == TM1638) tm1638display->displayASCII(i, pad); } for(uint32_t j = 0; i< position + length; i++, j++) { + if(i>Settings.display_width) break; if(txt[j] == 0) break; - rawBytes[0] = tm1637display->encode(txt[j]); - if(i>TM1637Data.num_digits) break; - tm1637display->printRaw(rawBytes, 1, i); + if(TM1637Data.display_type == TM1637) { rawBytes[0] = tm1637display->encode(txt[j]); tm1637display->printRaw(rawBytes, 1, i); } + else if(TM1637Data.display_type == TM1638) tm1638display->displayASCII(i, txt[j]); } return true; @@ -247,8 +285,8 @@ bool CmndTM1637Number(bool clear) { /*********************************************************************************************\ * Displays number with decimal, specifying position, precision and length, * optionally skipping clearing display before displaying the number. -* commands: DisplayFloat num [,position {0-(TM1637Data.num_digits-1)} [,precision {0-TM1637Data.num_digits} [,length {1 to TM1637Data.num_digits}]]] -* DisplayFloatNC num [,position {0-(TM1637Data.num_digits-1)} [,precision {0-TM1637Data.num_digits} [,length {1 to TM1637Data.num_digits}]]] // "NC" --> "No Clear" +* commands: DisplayFloat num [,position {0-(Settings.display_width-1)} [,precision {0-Settings.display_width} [,length {1 to Settings.display_width}]]] +* DisplayFloatNC num [,position {0-(Settings.display_width-1)} [,precision {0-Settings.display_width} [,length {1 to Settings.display_width}]]] // "NC" --> "No Clear" \*********************************************************************************************/ bool CmndTM1637Float(bool clear) { @@ -257,7 +295,7 @@ bool CmndTM1637Float(bool clear) { char sPosition[CMD_MAX_LEN]; char sLength[CMD_MAX_LEN]; uint8_t length = 0; - uint8_t precision = TM1637Data.num_digits; + uint8_t precision = Settings.display_width; uint8_t position = 0; float fnum = 0.0f; @@ -279,8 +317,8 @@ bool CmndTM1637Float(bool clear) { } - if((position < 0) || (position > (TM1637Data.num_digits-1))) position = 0; - if((precision < 0) || (precision > TM1637Data.num_digits)) precision = TM1637Data.num_digits; + if((position < 0) || (position > (Settings.display_width-1))) position = 0; + if((precision < 0) || (precision > Settings.display_width)) precision = Settings.display_width; if(clear) TM1637ClearDisplay(); @@ -288,22 +326,35 @@ bool CmndTM1637Float(bool clear) { ext_snprintf_P(txt, sizeof(txt), PSTR("%*_f"), precision, &fnum); if(!length) length = strlen(txt); - if((length <= 0) || (length > TM1637Data.num_digits)) length = TM1637Data.num_digits; + if((length <= 0) || (length > Settings.display_width)) length = Settings.display_width; AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: num %4_f, prec %d, len %d"), &fnum, precision, length); - uint8_t rawBytes[1]; - for(uint32_t i=0, j=0; iencode(txt[i]); - if(txt[i+1] == '.') { - rawBytes[0] = rawBytes[0] | 128; - i++; - length++; + if(TM1637Data.display_type == TM1637) { + uint8_t rawBytes[1]; + for(uint32_t i=0, j=0; iencode(txt[i]); + if(txt[i+1] == '.') { + rawBytes[0] = rawBytes[0] | 128; + i++; + length++; + } + if((j+position) > Settings.display_width) break; + tm1637display->printRaw(rawBytes, 1, j+position); } - if((j+position) > TM1637Data.num_digits) break; - tm1637display->printRaw(rawBytes, 1, j+position); - } + } else if(TM1637Data.display_type == TM1638) { + for(uint32_t i=0, j=0; i 7) break; + if(txt[i] == 0) break; + if(txt[i+1] == '.') { + tm1638display->displayASCIIwDot(j+position, txt[i]); + i++; + length++; + } + else tm1638display->displayASCII(j+position, txt[i]); + } + } return true; } @@ -321,16 +372,22 @@ bool CmndTM1637Clear(void) { } +// /*********************************************************************************************\ +// * Clears the display +// \*********************************************************************************************/ void TM1637ClearDisplay (void) { - unsigned char arr[] = {0}; - AddLog(LOG_LEVEL_DEBUG, PSTR("Clearing digit %d"), TM1637Data.num_digits); - for(int i=0; iprintRaw(arr, 1, i); + if(TM1637Data.display_type == TM1637) { + unsigned char arr[] = {0}; + for(int i=0; iprintRaw(arr, 1, i); + } else if(TM1637Data.display_type == TM1638) { + for(int i=0; idisplay7Seg(i, 0); + } } /*********************************************************************************************\ * Display scrolling text -* Command: DisplayScrollText text +* Command: DisplayTM1637Data.scroll_text text \*********************************************************************************************/ bool CmndTM1637ScrollText(void) { @@ -341,6 +398,7 @@ bool CmndTM1637ScrollText(void) { XdrvMailbox.data = TM1637Data.msg; return false; } else { + snprintf(TM1637Data.scroll_text, sizeof(TM1637Data.scroll_text), PSTR(" ")); snprintf(TM1637Data.scroll_text, sizeof(TM1637Data.scroll_text), PSTR("%s"), XdrvMailbox.data); TM1637Data.scroll_text[XdrvMailbox.data_len] = 0; TM1637Data.scroll_index = 0; @@ -354,9 +412,13 @@ bool CmndTM1637ScrollText(void) { /*********************************************************************************************\ * Sets the scroll delay for scrolling text. -* Command: DisplayScrollDelay delay {0-15} // default = 4 +* Command: DisplayTM1637Data.scroll_delay delay {0-15} // default = 4 \*********************************************************************************************/ bool CmndTM1637ScrollDelay(void) { + if(ArgC() == 0) { + XdrvMailbox.payload = TM1637Data.scroll_delay; + return true; + } if(TM1637Data.scroll_delay<0) TM1637Data.scroll_delay=0; TM1637Data.scroll_delay = XdrvMailbox.payload; return true; @@ -368,28 +430,42 @@ bool CmndTM1637ScrollDelay(void) { * Scrolls a given string. Called every 50ms \*********************************************************************************************/ void TM1637ScrollText(void) { - if(TM1637Data.scroll) { - TM1637Data.iteration++; - if(TM1637Data.scroll_delay) TM1637Data.iteration = TM1637Data.iteration % TM1637Data.scroll_delay; - else TM1637Data.iteration = 0; - if(TM1637Data.iteration) return; + TM1637Data.iteration++; + if(TM1637Data.scroll_delay) TM1637Data.iteration = TM1637Data.iteration % TM1637Data.scroll_delay; + else TM1637Data.iteration = 0; + if(TM1637Data.iteration) return; - if(TM1637Data.scroll_index > strlen(TM1637Data.scroll_text)) { - TM1637Data.scroll = false; - TM1637Data.scroll_index = 0; - return; - } - bool clr = false; - uint8_t rawBytes[1]; - for(uint32_t i=0, j=TM1637Data.scroll_index; i< strlen(TM1637Data.scroll_text); i++, j++) { - if(i > (TM1637Data.num_digits-1)) break; - if(TM1637Data.scroll_text[j] == 0) {clr = true;}; - char charToDisp = (clr ? ' ' : TM1637Data.scroll_text[j]); - rawBytes[0] = tm1637display->encode(charToDisp); - tm1637display->printRaw(rawBytes, 1, i); - } - TM1637Data.scroll_index++; + if(TM1637Data.scroll_index > strlen(TM1637Data.scroll_text)) { + TM1637Data.scroll= false; + TM1637Data.scroll_index = 0; + return; } + uint8_t rawBytes[1]; + for(uint32_t i=0, j=TM1637Data.scroll_index; i< 1 + strlen(TM1637Data.scroll_text); i++, j++) { + if(i > (Settings.display_width-1)) { break; } + rawBytes[0] = tm1637display->encode(TM1637Data.scroll_text[j]); + bool dotSkipped = false; + if(TM1637Data.scroll_text[j+1] == '.') { + dotSkipped = true; + rawBytes[0] = rawBytes[0] | 128; + j++; + } else if(TM1637Data.scroll_text[j] == '^') { + rawBytes[0] = 1 | 2 | 32 | 64; + } + if(!dotSkipped && TM1637Data.scroll_text[j] == '.') { + j++; + TM1637Data.scroll_index++; + rawBytes[0] = tm1637display->encode(TM1637Data.scroll_text[j]); + } + if(TM1637Data.scroll_text[j+1] == '.') { rawBytes[0] = rawBytes[0] | 128; } + if(TM1637Data.display_type == TM1637) { + tm1637display->printRaw(rawBytes, 1, i); + } else if(TM1637Data.display_type == TM1638) { + tm1638display->display7Seg(i, rawBytes[0]); + } + + } + TM1637Data.scroll_index++; } /*********************************************************************************************\ @@ -399,17 +475,16 @@ void TM1637ScrollText(void) { bool CmndTM1637Level(void) { uint16_t val = XdrvMailbox.payload; if((val < LEVEL_MIN) || (val > LEVEL_MAX)) { - sprintf(TM1637Data.msg, PSTR("Level should be a number in the range [%d, %d]"), LEVEL_MIN, LEVEL_MAX); - XdrvMailbox.data = TM1637Data.msg; + Response_P(PSTR("{\"Error\":\"Level should be a number in the range [%d, %d]\"}"), LEVEL_MIN, LEVEL_MAX); return false; } - uint8_t totalBars = 2*TM1637Data.num_digits; - AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: CmndTM1637Level totalBars %d"), totalBars); + uint8_t totalBars = 2*Settings.display_width; + AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: TM1637Data.model_name %s CmndTM1637Level totalBars=%d"), TM1637Data.model_name, totalBars); float barsToDisplay = totalBars * val / 100.0f; char txt[5]; ext_snprintf_P(txt, sizeof(txt), PSTR("%*_f"), 1, &barsToDisplay); - AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: CmndTM1637Level barsToDisplay %s"), txt); + AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: TM1637Data.model_name %s CmndTM1637Level barsToDisplay=%s"), TM1637Data.model_name, txt); char s[4]; ext_snprintf_P(s, sizeof(s), PSTR("%0_f"), &barsToDisplay); uint8_t numBars = atoi(s); @@ -419,19 +494,22 @@ bool CmndTM1637Level(void) { uint8_t rawBytes[1]; for(int i=1; i<=numBars; i++) { uint8_t digit = (i-1) / 2; - AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: CmndTM1637Level digit %d"), digit); uint8_t value = (((i%2) == 0) ? 54 : 48); - AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: CmndTM1637Level value %d"), value); - rawBytes[0] = value; - tm1637display->printRaw(rawBytes, 1, digit); + if(TM1637Data.display_type == TM1637) { + rawBytes[0] = value; + tm1637display->printRaw(rawBytes, 1, digit); + } else if(TM1637Data.display_type == TM1638) { + tm1638display->display7Seg(digit, value); + } + } return true; } /*********************************************************************************************\ * Display arbitrary data on the display module -* Command: DisplayRaw position {0-(TM1637Data.num_digits-1)},length {1 to TM1637Data.num_digits}, a [, b[, c[, d[...upto TM1637Data.num_digits]]]] -* where a,b,c,d... are upto TM1637Data.num_digits numbers in the range 0-255, each number (byte) +* Command: DisplayRaw position {0-(Settings.display_width-1)},length {1 to Settings.display_width}, a [, b[, c[, d[...upto Settings.display_width]]]] +* where a,b,c,d... are upto Settings.display_width numbers in the range 0-255, each number (byte) * corresponding to a single 7-segment digit. Within each byte, bit 0 is segment A, * bit 1 is segment B etc. The function may either set the entire display * or any desired part using the length and position parameters. @@ -482,20 +560,27 @@ bool CmndTM1637Raw(void) { } if(!length) length = ArgC() - 2; - if(length < 0 || length > TM1637Data.num_digits) length = TM1637Data.num_digits; - if(position < 0 || position > (TM1637Data.num_digits-1)) position = 0; - + if(length < 0 || length > Settings.display_width) length = Settings.display_width; + if(position < 0 || position > (Settings.display_width-1)) position = 0; AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: a %d, b %d, c %d, d %d, e %d, f %d, len %d, pos %d"), DATA[0], DATA[1], DATA[2], DATA[3], DATA[4], DATA[5], length, position); - uint8_t rawBytes[1]; - for(uint32_t i=position; i(TM1637Data.num_digits-1)) break; - rawBytes[0] = DATA[i-position]; - tm1637display->printRaw(rawBytes, 1, i); + if(TM1637Data.display_type == TM1637) { + uint8_t rawBytes[1]; + for(uint32_t i=position; i(Settings.display_width-1)) break; + rawBytes[0] = DATA[i-position]; + tm1637display->printRaw(rawBytes, 1, i); + } + } else if(TM1637Data.display_type == TM1638) { + for(uint32_t i=position; i7) break; + tm1638display->display7Seg(i, DATA[i-position]); + } } + return true; } @@ -503,7 +588,7 @@ bool CmndTM1637Raw(void) { * Display a given string. * Text can be placed at arbitrary location on the display using the length and * position parameters without affecting the rest of the display. -* Command: DisplayText text [, position {0-(TM1637Data.num_digits-1)} [,length {1 to TM1637Data.num_digits}]] +* Command: DisplayText text [, position {0-(Settings.display_width-1)} [,length {1 to Settings.display_width}]] \*********************************************************************************************/ bool CmndTM1637Text(bool clear) { char sString[CMD_MAX_LEN + 1]; @@ -525,59 +610,50 @@ bool CmndTM1637Text(bool clear) { } - if((position < 0) || (position > (TM1637Data.num_digits-1))) position = 0; + if((position < 0) || (position > (Settings.display_width-1))) position = 0; AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: sString %s, pos %d, len %d"), sString, position, length); if(clear) TM1637ClearDisplay(); if(!length) length = strlen(sString); - if((length < 0) || (length > TM1637Data.num_digits)) length = TM1637Data.num_digits; + if((length < 0) || (length > Settings.display_width)) length = Settings.display_width; uint32_t i = position; - uint8_t rawBytes[1]; - for(uint32_t j = 0; i< position + length; i++, j++) { - if(i > (TM1637Data.num_digits-1)) break; - if(sString[j] == 0) break; - rawBytes[0] = tm1637display->encode(sString[j]); - if(sString[j+1] == '.') { - rawBytes[0] = rawBytes[0] | 128; - j++; - } else if(sString[j] == '^') { - rawBytes[0] = 1 | 2 | 32 | 64; + if(TM1637Data.display_type == TM1637) { + uint8_t rawBytes[1]; + for(uint32_t j = 0; i< position + length; i++, j++) { + if(i > (Settings.display_width-1)) break; + if(sString[j] == 0) break; + rawBytes[0] = tm1637display->encode(sString[j]); + bool dotSkipped = false; + if(sString[j+1] == '.') { + dotSkipped = true; + rawBytes[0] = rawBytes[0] | 128; + j++; + } else if(sString[j] == '^') { + rawBytes[0] = 1 | 2 | 32 | 64; + } + if(!dotSkipped && sString[j] == '.') rawBytes[0] = 128; + tm1637display->printRaw(rawBytes, 1, i); + } + } else if(TM1637Data.display_type == TM1638) { + for(uint32_t j = 0; i< position + length; i++, j++) { + if(i > 7) break; + if(sString[j] == 0) break; + if(sString[j+1] == '.') { + tm1638display->displayASCIIwDot(i, sString[j]); + j++; + } else if(sString[j] == '^') { + tm1638display->display7Seg(i, (1 | 2 | 32 | 64)); + } else tm1638display->displayASCII(i, sString[j]); } - tm1637display->printRaw(rawBytes, 1, i); } return true; } -/*********************************************************************************************\ -* Sets brightness of the display. -* Command: DisplayBrightness {0-8} // 0 => off -\*********************************************************************************************/ -bool CmndTM1637Brightness(void) { - - uint16_t val = XdrvMailbox.payload; - if(ArgC() == 0) { - XdrvMailbox.payload = TM1637Data.brightness; - return true; - } - - if((val < BRIGHTNESS_MIN) || (val > BRIGHTNESS_MAX)) { - sprintf(TM1637Data.msg, PSTR("Brightness should be a number in the range [%d, %d]"), BRIGHTNESS_MIN, BRIGHTNESS_MAX); - XdrvMailbox.data = TM1637Data.msg; - return false; - } - TM1637Data.brightness = val; - - tm1637display->setBacklight(TM1637Data.brightness*10); - return true; -} - - - /*********************************************************************************************\ * Displays a clock. * Command: DisplayClock 1 // 12-hour format @@ -592,12 +668,9 @@ bool CmndTM1637Clock(void) { if(XdrvMailbox.payload > 1) TM1637Data.clock_24 = true; else if(XdrvMailbox.payload == 1) TM1637Data.clock_24 = false; - AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: TM1637Data.show_clock %d, TM1637Data.clock_24 %d"), - TM1637Data.show_clock, TM1637Data.clock_24); + AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: TM1637Data.show_clock %d, TM1637Data.clock_24 %d"), TM1637Data.show_clock, TM1637Data.clock_24); - if(!TM1637Data.show_clock) { - TM1637ClearDisplay(); - } + TM1637ClearDisplay(); return true; } @@ -626,34 +699,32 @@ void TM1637ShowTime() { if(mn < 10) snprintf(tm, sizeof(tm), PSTR("%d0%d"), hr, mn); else snprintf(tm, sizeof(tm), PSTR("%d%d"), hr, mn); } - uint8_t rawBytes[1]; - for(uint32_t i = 0; i< 4; i++) { - rawBytes[0] = tm1637display->encode(tm[i]); - if((millis() % 1000) > 500 && (i == 1)) rawBytes[0] = rawBytes[0] | 128; - tm1637display->printRaw(rawBytes, 1, i); + + if(TM1637Data.display_type == TM1637) { + uint8_t rawBytes[1]; + for(uint32_t i = 0; i< 4; i++) { + rawBytes[0] = tm1637display->encode(tm[i]); + if((millis() % 1000) > 500 && (i == 1)) rawBytes[0] = rawBytes[0] | 128; + tm1637display->printRaw(rawBytes, 1, i); + } + } else if(TM1637Data.display_type == TM1638) { + for(uint32_t i = 0; i< 4; i++) { + if((millis() % 1000) > 500 && (i == 1)) tm1638display->displayASCIIwDot(i, tm[i]); + else tm1638display->displayASCII(i, tm[i]); + } } + } /*********************************************************************************************\ -* This function is called for all TM1637 Display functions. +* This function is called for all Display functions. \*********************************************************************************************/ -bool TM1637Cmd(uint8_t fn) { +bool TM1637MainFunc(uint8_t fn) { bool result = false; - TM1637Data.num_digits = Settings.display_size; - if(TM1637Data.prev_num_digits != TM1637Data.num_digits) { // Cleck for change of display size, and re-init the library - AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: Size changed. Re-initializing library...")); - tm1637display = new SevenSegmentTM1637(Pin(GPIO_TM1637CLK), Pin(GPIO_TM1637DIO)); - tm1637display->begin(TM1637Data.num_digits, 1); - tm1637display->setBacklight(40); - TM1637ClearDisplay(); - TM1637Data.prev_num_digits = TM1637Data.num_digits; - AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: Re-initialized library")); - } if(XdrvMailbox.data_len > CMD_MAX_LEN) { - sprintf(TM1637Data.msg, PSTR("Command text too long. Please limit it to %d characters"), CMD_MAX_LEN); - XdrvMailbox.data = TM1637Data.msg; - return result; + Response_P(PSTR("{\"Error\":\"Command text too long. Please limit it to %d characters\"}"), CMD_MAX_LEN); + return false; } switch (fn) { @@ -672,9 +743,6 @@ bool TM1637Cmd(uint8_t fn) { case FUNC_DISPLAY_FLOATNC : result = CmndTM1637Float(false); break; - case FUNC_DISPLAY_BRIGHTNESS: - result = CmndTM1637Brightness(); - break; case FUNC_DISPLAY_RAW: result = CmndTM1637Raw(); break; @@ -693,7 +761,7 @@ bool TM1637Cmd(uint8_t fn) { case FUNC_DISPLAY_SCROLLDELAY: result = CmndTM1637ScrollDelay(); break; - case FUNC_DISPLAY_CLOCK: + case FUNC_DISPLAY_CLOCK: result = CmndTM1637Clock(); break; } @@ -701,27 +769,168 @@ bool TM1637Cmd(uint8_t fn) { return result; } +void TM1637Dim(void) { + // Settings.display_dimmer = 0 - 15 + uint8_t brightness = Settings.display_dimmer >> 1; // 0 - 7 + + if (TM1637 == TM1637Data.display_type) { + tm1637display->setBacklight(brightness * 12); // 0 - 84 + } + else if (TM1637Data.display_type == TM1638) { + tm1638display->brightness(brightness); // 0 - 7 + } +} + +/*********************************************************************************************/ + +#ifdef USE_DISPLAY_MODES1TO5 + +void TM1637Print(char* txt) { + for (uint32_t i = 0; i < Settings.display_cols[0]; i++) { + if (TM1637 == TM1637Data.display_type) { + uint8_t rawBytes[1]; + rawBytes[0] = tm1637display->encode(txt[i]); +// if ((millis() % 1000) > 500 && (i == 1)) { rawBytes[0] = rawBytes[0] | 128; } + tm1637display->printRaw(rawBytes, 1, i); + } + else if (TM1638 == TM1637Data.display_type) { +// if ((millis() % 1000) > 500 && (i == 1)) { tm1638display->displayASCIIwDot(i, txt[i]); } + tm1638display->displayASCII(i, txt[i]); + } + } +} + +void TM1637Center(char* txt) { + 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; + for (uint32_t i = 0; i < len; i++) { + line[offset +i] = txt[i]; + } + TM1637Print(line); +} + +/* +bool TM1637PrintLog(void) { + bool result = false; + + disp_refresh--; + if (!disp_refresh) { + disp_refresh = Settings.display_refresh; + if (!disp_screen_buffer_cols) { DisplayAllocScreenBuffer(); } + + char* txt = DisplayLogBuffer('\337'); + if (txt != nullptr) { + uint8_t last_row = Settings.display_rows -1; + + strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols); + DisplayFillScreen(last_row); + + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]); + + TM1637Print(disp_screen_buffer[last_row]); + + result = true; + } + } + return result; +} +*/ + +void TM1637Time(void) { + char line[Settings.display_cols[0] +1]; + + if (Settings.display_cols[0] >= 8) { + snprintf_P(line, sizeof(line), PSTR("%02d %02d %02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); + } + else if (Settings.display_cols[0] >= 6) { + snprintf_P(line, sizeof(line), PSTR("%02d%02d%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); + } + else { + snprintf_P(line, sizeof(line), PSTR("%02d%02d"), RtcTime.hour, RtcTime.minute); + } + TM1637Center(line); +} + +void TM1637Date(void) { + char line[Settings.display_cols[0] +1]; + + if (Settings.display_cols[0] >= 8) { + snprintf_P(line, sizeof(line), PSTR("%02d-%02d-%02d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year -2000); + } + else if (Settings.display_cols[0] >= 6) { + snprintf_P(line, sizeof(line), PSTR("%02d%02d%02d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year -2000); + } + else { + snprintf_P(line, sizeof(line), PSTR("%02d%02d"), RtcTime.day_of_month, RtcTime.month); + } + TM1637Center(line); +} + +void TM1637Refresh(void) { // Every second + if (!disp_power || !Settings.display_mode) { return; } // Mode 0 is User text + + switch (Settings.display_mode) { + case 1: // Time + TM1637Time(); + break; + case 2: // Date + TM1637Date(); + break; + case 3: // Time + if (TasmotaGlobal.uptime % Settings.display_refresh) { + TM1637Time(); + } else { + TM1637Date(); + } + break; +/* + case 4: // Mqtt + TM1637PrintLog(); + break; + case 5: { // Mqtt + if (!TM1637PrintLog()) { TM1637Time(); } + break; + } +*/ + } +} + +#endif // USE_DISPLAY_MODES1TO5 /*********************************************************************************************\ * Interface \*********************************************************************************************/ -bool Xdsp15(uint8_t function) -{ +bool Xdsp15(uint8_t function) { bool result = false; if (FUNC_DISPLAY_INIT_DRIVER == function) { - TM1637Init(); // init + TM1637Init(); } - else if (XDSP_15 == Settings.display_model) { + else if (TM1637Data.init_done && (XDSP_15 == Settings.display_model)) { switch (function) { - case FUNC_DISPLAY_MODEL: - AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: FUNC_DISPLAY_MODEL")); - result = true; + case FUNC_DISPLAY_EVERY_50_MSECOND: + if (disp_power && !Settings.display_mode) { + if (TM1637Data.scroll) { TM1637ScrollText(); } + if (TM1637Data.show_clock) { TM1637ShowTime(); } + } break; - case FUNC_DISPLAY_INIT: - CmndTM1637Clear(); - AddLog(LOG_LEVEL_DEBUG, PSTR("TM7: FUNC_DISPLAY_INIT")); +#ifdef USE_DISPLAY_MODES1TO5 + case FUNC_DISPLAY_EVERY_SECOND: + TM1637Refresh(); + break; +#endif // USE_DISPLAY_MODES1TO5 + case FUNC_DISPLAY_MODEL: + result = true; break; case FUNC_DISPLAY_SEVENSEG_TEXT: case FUNC_DISPLAY_CLEAR: @@ -729,21 +938,23 @@ bool Xdsp15(uint8_t function) case FUNC_DISPLAY_FLOAT: case FUNC_DISPLAY_NUMBERNC: case FUNC_DISPLAY_FLOATNC: - case FUNC_DISPLAY_BRIGHTNESS: case FUNC_DISPLAY_RAW: case FUNC_DISPLAY_LEVEL: case FUNC_DISPLAY_SEVENSEG_TEXTNC: case FUNC_DISPLAY_SCROLLTEXT: case FUNC_DISPLAY_SCROLLDELAY: case FUNC_DISPLAY_CLOCK: - result = TM1637Cmd(function); - break; - case FUNC_DISPLAY_EVERY_50_MSECOND: - TM1637ScrollText(); - if(TM1637Data.show_clock) { - TM1637ShowTime(); + if (disp_power && !Settings.display_mode) { + TM1637Data.show_clock = false; + result = TM1637MainFunc(function); } break; + case FUNC_DISPLAY_DIM: + TM1637Dim(); + break; + case FUNC_DISPLAY_POWER: + if (!disp_power) { TM1637ClearDisplay(); } + break; } } return result; diff --git a/tasmota/xdsp_interface.ino b/tasmota/xdsp_interface.ino index 3ca49f3d6..d404e169e 100644 --- a/tasmota/xdsp_interface.ino +++ b/tasmota/xdsp_interface.ino @@ -17,7 +17,6 @@ along with this program. If not, see . */ -#if defined(USE_I2C) || defined(USE_SPI) #ifdef USE_DISPLAY #ifdef XFUNC_PTR_IN_ROM @@ -201,4 +200,3 @@ bool XdspCall(uint8_t Function) } #endif // USE_DISPLAY -#endif // USE_I2C or USE_SPI diff --git a/tasmota/xsns_14_sht3x.ino b/tasmota/xsns_14_sht3x.ino index 4e29742e5..0f791f78a 100644 --- a/tasmota/xsns_14_sht3x.ino +++ b/tasmota/xsns_14_sht3x.ino @@ -99,7 +99,10 @@ void Sht3xShow(bool json) float h; if (Sht3xRead(t, h, sht3x_sensors[i].address)) { char types[11]; - snprintf_P(types, sizeof(types), PSTR("%s%c0x%02X"), sht3x_sensors[i].types, IndexSeparator(), sht3x_sensors[i].address); // "SHT3X-0xXX" + strlcpy(types, sht3x_sensors[i].types, sizeof(types)); + if (sht3x_count > 1) { + snprintf_P(types, sizeof(types), PSTR("%s%c%02X"), sht3x_sensors[i].types, IndexSeparator(), sht3x_sensors[i].address); // "SHT3X-0xXX" + } TempHumDewShow(json, ((0 == TasmotaGlobal.tele_period) && (0 == i)), types, t, h); } } diff --git a/tasmota/xsns_22_sr04.ino b/tasmota/xsns_22_sr04.ino index f2659f294..29876dce4 100644 --- a/tasmota/xsns_22_sr04.ino +++ b/tasmota/xsns_22_sr04.ino @@ -29,7 +29,11 @@ * - https://www.dfrobot.com/wiki/index.php/Weather-proof_Ultrasonic_Sensor_SKU_:_SEN0207 \*********************************************************************************************/ -#define XSNS_22 22 +#define XSNS_22 22 + +#ifndef SR04_MAX_SENSOR_DISTANCE +#define SR04_MAX_SENSOR_DISTANCE 500 +#endif uint8_t sr04_type = 1; real64_t distance; @@ -64,7 +68,7 @@ uint8_t Sr04TModeDetect(void) if (-1 == sr04_trig_pin) { sr04_trig_pin = Pin(GPIO_SR04_ECHO); // if GPIO_SR04_TRIG is not configured use single PIN mode with GPIO_SR04_ECHO only } - sonar = new NewPing(sr04_trig_pin, sr04_echo_pin, 300); + sonar = new NewPing(sr04_trig_pin, sr04_echo_pin, SR04_MAX_SENSOR_DISTANCE); } else { if (sonar_serial->hardwareSerial()) { ClaimSerial(); diff --git a/tasmota/xsns_28_tm1638.ino b/tasmota/xsns_28_tm1638.ino index 0eb0d1744..2c3e32707 100644 --- a/tasmota/xsns_28_tm1638.ino +++ b/tasmota/xsns_28_tm1638.ino @@ -144,10 +144,10 @@ uint8_t Tm1638GetButtons(void) void TmInit(void) { tm1638_type = 0; - if (PinUsed(GPIO_TM16CLK) && PinUsed(GPIO_TM16DIO) && PinUsed(GPIO_TM16STB)) { - tm1638_clock_pin = Pin(GPIO_TM16CLK); - tm1638_data_pin = Pin(GPIO_TM16DIO); - tm1638_strobe_pin = Pin(GPIO_TM16STB); + if (PinUsed(GPIO_TM1638CLK) && PinUsed(GPIO_TM1638DIO) && PinUsed(GPIO_TM1638STB)) { + tm1638_clock_pin = Pin(GPIO_TM1638CLK); + tm1638_data_pin = Pin(GPIO_TM1638DIO); + tm1638_strobe_pin = Pin(GPIO_TM1638STB); pinMode(tm1638_data_pin, OUTPUT); pinMode(tm1638_clock_pin, OUTPUT); diff --git a/tasmota/xsns_29_mcp230xx.ino b/tasmota/xsns_29_mcp230xx.ino index 3e4dd9dee..5c118b6f3 100644 --- a/tasmota/xsns_29_mcp230xx.ino +++ b/tasmota/xsns_29_mcp230xx.ino @@ -45,7 +45,7 @@ uint8_t MCP230xx_GPIO = 0x09; uint8_t mcp230xx_type = 0; uint8_t mcp230xx_pincount = 0; -uint8_t mcp230xx_oldoutpincount = 0; +uint8_t mcp230xx_outpincount = 0; #ifdef USE_MCP230xx_OUTPUT uint8_t mcp230xx_outpinmapping[16]; #endif @@ -146,13 +146,26 @@ uint8_t MCP230xx_readGPIO(uint8_t port) { void MCP230xx_ApplySettings(void) { +#ifdef USE_MCP230xx_OUTPUT + TasmotaGlobal.devices_present -= mcp230xx_outpincount; + mcp230xx_outpincount = 0; + for (uint32_t idx = 0; idx < mcp230xx_pincount; idx++) { + if (Settings.mcp230xx_config[idx].pinmode >= 5) { + mcp230xx_outpinmapping[mcp230xx_outpincount] = idx; + mcp230xx_outpincount++; + } + int_millis[idx]=millis(); + } + TasmotaGlobal.devices_present += mcp230xx_outpincount; +#endif // USE_MCP230xx_OUTPUT uint8_t int_en = 0; + uint8_t reg_portpins[mcp230xx_type]; for (uint32_t mcp230xx_port = 0; mcp230xx_port < mcp230xx_type; mcp230xx_port++) { uint8_t reg_gppu = 0; uint8_t reg_gpinten = 0; uint8_t reg_iodir = 0xFF; #ifdef USE_MCP230xx_OUTPUT - uint8_t reg_portpins = 0x00; + reg_portpins[mcp230xx_port] = 0x00; #endif // USE_MCP230xx_OUTPUT for (uint32_t idx = 0; idx < 8; idx++) { switch (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].pinmode) { @@ -168,10 +181,10 @@ void MCP230xx_ApplySettings(void) case 5 ... 6: reg_iodir &= ~(1 << idx); if (Settings.flag.save_state) { // SetOption0 - Save power state and use after restart - Firmware configuration wants us to use the last pin state - reg_portpins |= (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].saved_state << idx); + reg_portpins[mcp230xx_port] |= (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].saved_state << idx); } else { if (Settings.mcp230xx_config[idx+(mcp230xx_port*8)].pullup) { - reg_portpins |= (1 << idx); + reg_portpins[mcp230xx_port] |= (1 << idx); } } break; @@ -191,22 +204,19 @@ void MCP230xx_ApplySettings(void) } I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_GPPU+mcp230xx_port, reg_gppu); I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_GPINTEN+mcp230xx_port, reg_gpinten); - I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_IODIR+mcp230xx_port, reg_iodir); #ifdef USE_MCP230xx_OUTPUT - I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_GPIO+mcp230xx_port, reg_portpins); + I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_IODIR+mcp230xx_port, reg_iodir); #endif // USE_MCP230xx_OUTPUT } #ifdef USE_MCP230xx_OUTPUT - TasmotaGlobal.devices_present -= mcp230xx_oldoutpincount; - mcp230xx_oldoutpincount = 0; - for (uint32_t idx=0;idx= 5) { - mcp230xx_outpinmapping[mcp230xx_oldoutpincount] = idx; - mcp230xx_oldoutpincount++; + for (uint32_t mcp230xx_port = 0; mcp230xx_port < mcp230xx_type; mcp230xx_port++) { + for (uint32_t idx = 0; idx < mcp230xx_outpincount; idx++) { + if (mcp230xx_port ? mcp230xx_outpinmapping[idx] > 7 : mcp230xx_outpinmapping[idx] < 8) { + uint8_t relay_no = TasmotaGlobal.devices_present - mcp230xx_outpincount + idx + 1; + ExecuteCommandPower(relay_no, (reg_portpins[mcp230xx_port] >> (mcp230xx_outpinmapping[idx] & 7)) & 1, SRC_IGNORE); + } } - int_millis[idx]=millis(); } - TasmotaGlobal.devices_present += mcp230xx_oldoutpincount; #endif // USE_MCP230xx_OUTPUT mcp230xx_int_en = int_en; MCP230xx_CheckForIntCounter(); // update register on whether or not we should be counting interrupts @@ -360,13 +370,15 @@ void MCP230xx_Show(bool json) uint16_t gpiototal = ((uint16_t)gpiob << 8) | gpio; ResponseAppend_P(PSTR(",\"MCP230_OUT\":{")); char stt[7]; + bool first = true; for (uint32_t pinx = 0; pinx < mcp230xx_pincount; pinx++) { if (Settings.mcp230xx_config[pinx].pinmode >= 5) { sprintf(stt, ConvertNumTxt(((gpiototal>>pinx)&1), Settings.mcp230xx_config[pinx].pinmode)); - ResponseAppend_P(PSTR("\"OUT_D%i\":\"%s\","), pinx, stt); + ResponseAppend_P(PSTR("%s\"OUT_D%i\":\"%s\""), (first) ? "" : ",", pinx, stt); + first = false; } } - ResponseAppend_P(PSTR("\"END\":1}")); + ResponseAppend_P(PSTR("}")); } #endif // USE_MCP230xx_OUTPUT ResponseJsonEnd(); @@ -393,8 +405,8 @@ void MCP230xx_SetOutPin(uint8_t pin,uint8_t pinstate) { I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_GPIO + port, portpins); if (Settings.flag.save_state) { // SetOption0 - Save power state and use after restart - Firmware configured to save last known state in settings - Settings.mcp230xx_config[pin].saved_state=portpins>>(pin-(port*8))&1; - Settings.mcp230xx_config[pin+pinadd].saved_state=portpins>>(pin+pinadd-(port*8))&1; + Settings.mcp230xx_config[pin].saved_state=(portpins>>(pin-(port*8))&1)^(pinmo-5); + Settings.mcp230xx_config[pin+pinadd].saved_state=(portpins>>(pin+pinadd-(port*8))&1)^(pinmo-5); } sprintf(cmnd,ConvertNumTxt(pinstate, pinmo)); sprintf(stt,ConvertNumTxt((portpins >> (pin-(port*8))&1), pinmo)); @@ -651,7 +663,7 @@ bool MCP230xx_Command(void) for (relay_no = 0; relay_no < mcp230xx_pincount ; relay_no ++) { if ( mcp230xx_outpinmapping[relay_no] == pin) break; } - relay_no = TasmotaGlobal.devices_present - mcp230xx_oldoutpincount + relay_no +1; + relay_no = TasmotaGlobal.devices_present - mcp230xx_outpincount + relay_no +1; if ((!strcmp(ArgV(argument, 2), "ON")) || (!strcmp(ArgV(argument, 2), "1"))) { ExecuteCommandPower(relay_no, 1, SRC_IGNORE); return serviced; @@ -772,13 +784,15 @@ void MCP230xx_OutputTelemetry(void) void MCP230xx_Interrupt_Counter_Report(void) { ResponseTime_P(PSTR(",\"MCP230_INTTIMER\":{")); + bool first = true; for (uint32_t pinx = 0;pinx < mcp230xx_pincount;pinx++) { if (Settings.mcp230xx_config[pinx].int_count_en) { // Counting is enabled for this pin so we add to report - ResponseAppend_P(PSTR("\"INTCNT_D%i\":%i,"),pinx,mcp230xx_int_counter[pinx]); + ResponseAppend_P(PSTR("%s\"INTCNT_D%i\":%i,"), (first) ? "" : "?", pinx, mcp230xx_int_counter[pinx]); + first = false; mcp230xx_int_counter[pinx]=0; } } - ResponseAppend_P(PSTR("\"END\":1}}")); + ResponseAppend_P(PSTR("}}")); MqttPublishTeleSensor(); mcp230xx_int_sec_counter = 0; } @@ -799,14 +813,13 @@ void MCP230xx_Interrupt_Retain_Report(void) { #ifdef USE_MCP230xx_OUTPUT void MCP230xx_SwitchRelay() { - for (uint32_t i = TasmotaGlobal.devices_present - mcp230xx_oldoutpincount; i < TasmotaGlobal.devices_present; i++) { - uint8_t pin = mcp230xx_outpinmapping[i - (TasmotaGlobal.devices_present - mcp230xx_oldoutpincount)]; + for (uint32_t i = TasmotaGlobal.devices_present - mcp230xx_outpincount; i < TasmotaGlobal.devices_present; i++) { + uint8_t pin = mcp230xx_outpinmapping[i - (TasmotaGlobal.devices_present - mcp230xx_outpincount)]; uint8_t pincmd = Settings.mcp230xx_config[pin].pinmode - 5; uint8_t relay_state = bitRead(XdrvMailbox.index, i); - AddLog(LOG_LEVEL_DEBUG, PSTR("MCP: relay %d pin_no %d state %d"), i,pin, relay_state); switch (relay_state) { case 1: - MCP230xx_SetOutPin(pin,abs(pincmd-1)); + MCP230xx_SetOutPin(pin,1-pincmd); break; case 0: MCP230xx_SetOutPin(pin,pincmd); @@ -826,7 +839,7 @@ bool Xsns29(uint8_t function) bool result = false; - if (FUNC_PRE_INIT == function) { + if (FUNC_INIT == function) { MCP230xx_Detect(); } else if (mcp230xx_type) { diff --git a/tasmota/xsns_45_vl53l0x.ino b/tasmota/xsns_45_vl53l0x.ino index 1d377bd6d..3996f1c8e 100644 --- a/tasmota/xsns_45_vl53l0x.ino +++ b/tasmota/xsns_45_vl53l0x.ino @@ -1,7 +1,7 @@ /* - xsns_45_vl53l0x.ino - VL53L0X time of flight sensor support for Tasmota + xsns_45_vl53l0x.ino - VL53L0X time of flight multiple sensors support for Tasmota - Copyright (C) 2021 Theo Arends and Gerhard Mutz + Copyright (C) 2021 Theo Arends, Gerhard Mutz and 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 @@ -23,105 +23,216 @@ * VL53L0x time of flight sensor * * I2C Addres: 0x29 + ********************************************************************************************* + * + * Note: When using multiple VL53L0X, it is required to also wire the XSHUT pin of all those sensors + * in order to let Tasmota change by software the I2C address of those and give them an unique address + * for operation. The sensor don't save its address, so this procedure of changing its address is needed + * to be performed every restart. The Addresses used for this are 120 (0x78) to 127 (0x7F). In the I2c + * Standard (https://i2cdevices.org/addresses) those addresses are used by the PCA9685, so take into + * account they won't work together. + * + * The default value of VL53L0X_MAX_SENSORS is set in the file tasmota.h + * Changing that is backwards incompatible - Max supported devices by this driver are 8 + * + ********************************************************************************************** + * + * How to install this sensor: https://www.st.com/resource/en/datasheet/vl53l0x.pdf + * + * If you are going to use long I2C wires read this: + * https://hackaday.com/2017/02/08/taking-the-leap-off-board-an-introduction-to-i2c-over-long-wires/ + * \*********************************************************************************************/ #define XSNS_45 45 #define XI2C_31 31 // See I2CDEVICES.md +// Uncomment this line to use long range mode. This +// increases the sensitivity of the sensor and extends its +// potential range, but increases the likelihood of getting +// an inaccurate reading because of reflections from objects +// other than the intended target. It works best in dark +// conditions. + +//#define VL53L0X_LONG_RANGE + +// Uncomment ONE of these two lines to get +// - higher speed at the cost of lower accuracy OR +// - higher accuracy at the cost of lower speed + +//#define VL53L0X_HIGH_SPEED +//#define VL53L0X_HIGH_ACCURACY + #define USE_VL_MEDIAN #define USE_VL_MEDIAN_SIZE 5 // Odd number of samples median detection #include #include "VL53L0X.h" -VL53L0X sensor; +VL53L0X sensor[VL53L0X_MAX_SENSORS]; struct { uint16_t distance; uint16_t distance_prev; uint16_t buffer[5]; uint8_t ready = 0; uint8_t index; -} Vl53l0x; +} Vl53l0x[VL53L0X_MAX_SENSORS]; + +bool xshut = false; +bool VL53L0X_detected = false; /********************************************************************************************/ void Vl53l0Detect(void) { - if (!I2cSetDevice(0x29)) { return; } - if (!sensor.init()) { return; } - I2cSetActiveFound(sensor.getAddress(), "VL53L0X"); + for (uint32_t i = 0; i < VL53L0X_MAX_SENSORS; i++) { + if (PinUsed(GPIO_VL53L0X_XSHUT1, i)) { + pinMode(Pin(GPIO_VL53L0X_XSHUT1, i), OUTPUT); + digitalWrite(Pin(GPIO_VL53L0X_XSHUT1, i), i==0 ? 1 : 0); + xshut = true; + } + } - sensor.setTimeout(500); + for (uint32_t i = 0; i < VL53L0X_MAX_SENSORS; i++) { + if (PinUsed(GPIO_VL53L0X_XSHUT1, i) || (!xshut)) { + if (xshut) { pinMode(Pin(GPIO_VL53L0X_XSHUT1, i), INPUT); delay(1); } + if (!I2cSetDevice(0x29) && !I2cSetDevice((uint8_t)(120+i))) { return; } // Detection for unconfigured OR configured sensor + if (sensor[i].init()) { + if (xshut) { sensor[i].setAddress((uint8_t)(120+i)); } + uint8_t addr = sensor[i].getAddress(); + if (xshut) { + I2cSetActive(addr); + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_I2C D_SENSOR " VL53L0X %d " D_SENSOR_DETECTED " - " D_NEW_ADDRESS " 0x%02X"), i+1, addr); + } else { + I2cSetActiveFound(addr, "VL53L0X"); + } + sensor[i].setTimeout(500); - // Start continuous back-to-back mode (take readings as - // fast as possible). To use continuous timed mode - // instead, provide a desired inter-measurement period in - // ms (e.g. sensor.startContinuous(100)). - sensor.startContinuous(); - Vl53l0x.ready = 1; +#if defined VL53L0X_LONG_RANGE + // lower the return signal rate limit (default is 0.25 MCPS) + sensor[i].setSignalRateLimit(0.1); + // increase laser pulse periods (defaults are 14 and 10 PCLKs) + sensor[i].setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18); + sensor[i].setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14); +#endif +#if defined VL53L0X_HIGH_SPEED + // reduce timing budget to 20 ms (default is about 33 ms) + sensor[i].setMeasurementTimingBudget(20000); +#elif defined VL53L0X_HIGH_ACCURACY + // increase timing budget to 200 ms + sensor[i].setMeasurementTimingBudget(200000); +#endif + // Start continuous back-to-back mode (take readings as + // fast as possible). To use continuous timed mode + // instead, provide a desired inter-measurement period in + // ms (e.g. sensor.startContinuous(100)). + sensor[i].startContinuous(); - Vl53l0x.index = 0; + Vl53l0x[i].ready = 1; + Vl53l0x[i].index = 0; + VL53L0X_detected = true; + if (!xshut) { break; } + } else { + AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_I2C D_SENSOR " VL53L0X %d - " D_FAILED_TO_START), i+1); + } + } + } } void Vl53l0Every_250MSecond(void) { - uint16_t dist = sensor.readRangeContinuousMillimeters(); - if ((0 == dist) || (dist > 2000)) { - dist = 9999; - } + for (uint32_t i = 0; i < VL53L0X_MAX_SENSORS; i++) { + if (PinUsed(GPIO_VL53L0X_XSHUT1, i) || (!xshut)) { + uint16_t dist = sensor[i].readRangeContinuousMillimeters(); + if ((0 == dist) || (dist > 2200)) { + dist = 9999; + } #ifdef USE_VL_MEDIAN - // store in ring buffer - Vl53l0x.buffer[Vl53l0x.index] = dist; - Vl53l0x.index++; - if (Vl53l0x.index >= USE_VL_MEDIAN_SIZE) { - Vl53l0x.index = 0; - } + // store in ring buffer + Vl53l0x[i].buffer[Vl53l0x[i].index] = dist; + Vl53l0x[i].index++; + if (Vl53l0x[i].index >= USE_VL_MEDIAN_SIZE) { + Vl53l0x[i].index = 0; + } - // sort list and take median - uint16_t tbuff[USE_VL_MEDIAN_SIZE]; - memmove(tbuff, Vl53l0x.buffer, sizeof(tbuff)); - uint16_t tmp; - uint8_t flag; - for (uint32_t ocnt = 0; ocnt < USE_VL_MEDIAN_SIZE; ocnt++) { - flag = 0; - for (uint32_t count = 0; count < USE_VL_MEDIAN_SIZE -1; count++) { - if (tbuff[count] > tbuff[count +1]) { - tmp = tbuff[count]; - tbuff[count] = tbuff[count +1]; - tbuff[count +1] = tmp; - flag = 1; - } - } - if (!flag) { break; } - } - Vl53l0x.distance = tbuff[(USE_VL_MEDIAN_SIZE -1) / 2]; + // sort list and take median + uint16_t tbuff[USE_VL_MEDIAN_SIZE]; + memmove(tbuff, Vl53l0x[i].buffer, sizeof(tbuff)); + uint16_t tmp; + uint8_t flag; + for (uint32_t ocnt = 0; ocnt < USE_VL_MEDIAN_SIZE; ocnt++) { + flag = 0; + for (uint32_t count = 0; count < USE_VL_MEDIAN_SIZE -1; count++) { + if (tbuff[count] > tbuff[count +1]) { + tmp = tbuff[count]; + tbuff[count] = tbuff[count +1]; + tbuff[count +1] = tmp; + flag = 1; + } + } + if (!flag) { break; } + } + Vl53l0x[i].distance = tbuff[(USE_VL_MEDIAN_SIZE -1) / 2]; #else - Vl53l0x.distance = dist; + Vl53l0x[i].distance = dist; #endif + } + if (!xshut) { break; } + } } #ifdef USE_DOMOTICZ void Vl53l0Every_Second(void) { - if (abs(Vl53l0x.distance - Vl53l0x.distance_prev) > 8) { - Vl53l0x.distance_prev = Vl53l0x.distance; - DomoticzSensor(DZ_ILLUMINANCE, Vl53l0x.distance); + if (abs(Vl53l0x[0].distance - Vl53l0x[0].distance_prev) > 8) { + Vl53l0x[0].distance_prev = Vl53l0x[0].distance; + DomoticzSensor(DZ_ILLUMINANCE, Vl53l0x[0].distance); } } #endif // USE_DOMOTICZ void Vl53l0Show(boolean json) { - if (json) { - ResponseAppend_P(PSTR(",\"VL53L0X\":{\"" D_JSON_DISTANCE "\":%d}"), Vl53l0x.distance); + for (uint32_t i = 0; i < VL53L0X_MAX_SENSORS; i++) { + if (PinUsed(GPIO_VL53L0X_XSHUT1, i) || (!xshut)) { + if (json) { + if (Vl53l0x[i].distance == 9999) { + if (xshut) { + ResponseAppend_P(PSTR(",\"VL53L0X_%d\":{\"" D_JSON_DISTANCE "\":null}"), i+1); + } else { + ResponseAppend_P(PSTR(",\"VL53L0X\":{\"" D_JSON_DISTANCE "\":null}")); // For backwards compatibility when not using XSHUT GPIOs + } + } else { + if (xshut) { + ResponseAppend_P(PSTR(",\"VL53L0X_%d\":{\"" D_JSON_DISTANCE "\":%d}"), i+1, Vl53l0x[i].distance); + } else { + ResponseAppend_P(PSTR(",\"VL53L0X\":{\"" D_JSON_DISTANCE "\":%d}"), Vl53l0x[i].distance); // For backwards compatibility when not using XSHUT GPIOs + } + } +#ifdef USE_WEBSERVER + } else { + if (Vl53l0x[i].distance == 9999) { + if (xshut) { + WSContentSend_PD("{s}%s_%d " D_DISTANCE "{m}%s {e}", PSTR("VL53L0X"), i+1, PSTR(D_OUT_OF_RANGE)); + } else { + WSContentSend_PD("{s}%s " D_DISTANCE "{m}%s {e}", PSTR("VL53L0X"), PSTR(D_OUT_OF_RANGE)); // For backwards compatibility when not using XSHUT GPIOs + } + } else { + if (xshut) { + WSContentSend_PD("{s}%s_%d " D_DISTANCE "{m}%d " D_UNIT_MILLIMETER "{e}", PSTR("VL53L0X"), i+1, Vl53l0x[i].distance); + } else { + WSContentSend_PD(HTTP_SNS_DISTANCE, PSTR("VL53L0X"), Vl53l0x[i].distance); // For backwards compatibility when not using XSHUT GPIOs + } + } +#endif + } + } + if (sensor[i].timeoutOccurred()) { AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_I2C D_TIMEOUT_WAITING_FOR D_SENSOR " VL53L0X %d"), i+1); } + if (!xshut) { break; } + } #ifdef USE_DOMOTICZ - if (0 == TasmotaGlobal.tele_period) { - DomoticzSensor(DZ_ILLUMINANCE, Vl53l0x.distance); + if ((json) && (0 == TasmotaGlobal.tele_period)){ + DomoticzSensor(DZ_ILLUMINANCE, Vl53l0x[0].distance); } #endif // USE_DOMOTICZ -#ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_DISTANCE, PSTR("VL53L0X"), Vl53l0x.distance); -#endif - } } /*********************************************************************************************\ @@ -136,7 +247,7 @@ bool Xsns45(byte function) { if (FUNC_INIT == function) { Vl53l0Detect(); } - else if (Vl53l0x.ready) { + else if (VL53L0X_detected) { switch (function) { case FUNC_EVERY_250_MSECOND: Vl53l0Every_250MSecond(); diff --git a/tasmota/xsns_63_aht1x.ino b/tasmota/xsns_63_aht1x.ino index 88da71890..bb47873eb 100644 --- a/tasmota/xsns_63_aht1x.ino +++ b/tasmota/xsns_63_aht1x.ino @@ -175,7 +175,10 @@ void AHT1XShow(bool json) { float tem = ConvertTemp(aht1x_sensors[i].temperature); float hum = ConvertHumidity(aht1x_sensors[i].humidity); char types[11]; // AHT1X-0x38 - snprintf_P(types, sizeof(types), PSTR("%s%c0x%02X"), aht1x_sensors[i].types, IndexSeparator(), aht1x_sensors[i].address); // "X-0xXX" + strlcpy(types, aht1x_sensors[i].types, sizeof(types)); + if (aht1x.count > 1) { + snprintf_P(types, sizeof(types), PSTR("%s%c%02X"), aht1x_sensors[i].types, IndexSeparator(), aht1x_sensors[i].address); // "X-0xXX" + } TempHumDewShow(json, ((0 == TasmotaGlobal.tele_period) && (0 == i)), types, tem, hum); } } diff --git a/tasmota/xsns_75_prometheus.ino b/tasmota/xsns_75_prometheus.ino index bbdb303c5..0b0251229 100644 --- a/tasmota/xsns_75_prometheus.ino +++ b/tasmota/xsns_75_prometheus.ino @@ -57,6 +57,7 @@ String FormatMetricName(const char *metric) { // cleanup spaces and uppercases String formatted = metric; formatted.toLowerCase(); formatted.replace(" ", "_"); + formatted.replace(".", "_"); return formatted; } diff --git a/tasmota/xsns_82_wiegand.ino b/tasmota/xsns_82_wiegand.ino index 4fff9c5d1..70f87b9c8 100644 --- a/tasmota/xsns_82_wiegand.ino +++ b/tasmota/xsns_82_wiegand.ino @@ -41,29 +41,47 @@ * - fix for #11047 Wiegand 26/34 missed some key press if they are press at normal speed * - removed testing code for tests without attached hardware * - added SetOption123 0-Wiegand UID decimal (default) 1-Wiegand UID hexadecimal - * - added SetOption124 0-Keypad every key a single tag (default) 1-all keys up to ending char (#) send as one tag + * - added SetOption124 0-all keys up to ending char (# or *) send as one tag by MQTT (default) 1-Keypad every key a single tag + * - added a new realtime testing option emulating a Wiegang reader output on same GPIOs where normally reader is attached. Details below \*********************************************************************************************/ -#warning **** Wiegand interface enabled **** +#pragma message("**** Wiegand interface enabled ****") #define XSNS_82 82 #define WIEGAND_CODE_GAP_FACTOR 3 // Gap between 2 complete RFID codes send by the device. (WIEGAND_CODE_GAP_FACTOR * bitTime) to detect the end of a code -#define WIEGAND_BIT_TIME_DEFAULT 1250 // period time of one bit (impluse + impulse_gap time) 1250µs measured by oscilloscope on my RFID Reader -#define WIEGAND_RFID_ARRAY_SIZE 5 // storage of rfids found between 2 calls of FUNC_EVERY_100_MSECOND +#define WIEGAND_BIT_TIME_DEFAULT 1250 // period time (µs) of one bit (impluse + impulse_gap time) 1250µs measured by oscilloscope on my RFID Reader +#define WIEGAND_RFID_ARRAY_SIZE 11 // storage of rfids found between 2 calls of FUNC_EVERY_100_MSECOND #define WIEGAND_OPTION_HEX 123 // Index of option to switch output between hex (1) an decimal (0) (default) +#define WIEGAND_OPTION_HEX_POSTFIX "h" // will be added after UID output nothing = "" +#define WIEGAND_OPTION_KEYPAD_TO_TAG 124 //Index of option to switch output of key pad strokes between every single stroke one single char (0) (default) + // or all strokes until detecting ending char (WIEGAND_OPTION_KEYPAD_END_CHAR) as one tag (1) -// using #define will save some space in the final code -// DEV_WIEGAND_TEST_MODE 2 : testing with hardware correctly connected. #define DEV_WIEGAND_TEST_MODE 0 +// using #define will save some space in the final code +// DEV_WIEGAND_TEST_MODE 1 : Use only without Wiegand reader device attache. On a second ESP to simulate reader output! +// DEV_WIEGAND_TEST_MODE 2 : testing with hardware correctly connected. #ifdef DEV_WIEGAND_TEST_MODE #if (DEV_WIEGAND_TEST_MODE==0) #elif (DEV_WIEGAND_TEST_MODE==1) - #warning "(no longer available) Wiegand Interface compiled with 'DEV_WIEGAND_TEST_MODE' 1 (Random RFID)" + #pragma message("\nWiegand Interface code generator (testing purpose only!) compiled with 'DEV_WIEGAND_TEST_MODE' 1 \nUse only on esp WITHOUT Wiegand reader hardware attached! GPIOS will be configured as OUTPUT!" ) + // use on own risk for testing purpose only. + // please don't attach your reader to the ESP when you use this option. The GPIOS will be defined as OUTPUT + // the interrupts will be enabled and normally recognize the generated code, that's the idea behind for testing. + // Commands: + // WieBitTime [time] : get or set the bit impuls length + // WieInterBitTime [time]: get or set the length of the gap between 2 bits + // WieTagGap [tagGap]: get or set the current used gap time between 2 tags send in µs minimal WIEGAND_BIT_TIME_DEFAULT µs default WIEGAND_BIT_TIME_DEFAULT * WIEGAND_CODE_GAP_FACTOR + // WieTagSize [tagsize]: get or set the tagsize (4,8,24,26,32,34) default 26. + // WieTag [tag]: get or set the current used tag. For tagsize 4,8 only one char will be used. + // WieSend [tag[:tagsize];tag[:tagsize];...] : Generate the current Tag with current TagSize to GPIOs if the paramters are used + // tags and tagsize from commandline are used as current values. If tagsize is omitted always last value will be used + // WieSend 4:4;5:8; will send 4 in 4 bit mode and 5 in 8 bit mode with a pause of current TagGab between the chars + // WieSend will send the last used tag with last used tagsize #elif (DEV_WIEGAND_TEST_MODE==2) - #warning "Wiegand Interface compiled with 'DEV_WIEGAND_TEST_MODE' 2 (Hardware connected)" + #pragma message("\nWiegand Interface compiled with 'DEV_WIEGAND_TEST_MODE' 2 (Hardware connected)") #else - #warning "Wiegand Interface compiled with unknown mode" + #pragma message("\nWiegand Interface compiled with unknown mode") #endif #endif @@ -71,7 +89,6 @@ typedef struct rfid_store { uint64_t RFID; uint16_t bitCount; } RFID_store; class Wiegand { public: - Wiegand(void); void Init(void); void ScanForTag(void); @@ -81,21 +98,24 @@ class Wiegand { bool isInit = false; - private: - //uint64_t HexStringToDec(uint64_t); + #if (DEV_WIEGAND_TEST_MODE!=1) + private: + #endif //(DEV_WIEGAND_TEST_MODE==1) uint64_t CheckAndConvertRfid(uint64_t,uint16_t); - char translateEnterEscapeKeyPress(char); uint8_t CalculateParities(uint64_t, int); bool WiegandConversion (uint64_t , uint16_t ); void setOutputFormat(void); // fix output HEX format + void HandleKeyPad(void); //handle one tag for multi key strokes static void handleD0Interrupt(void); static void handleD1Interrupt(void); static void handleDxInterrupt(int in); // fix #11047 uint64_t rfid; - uint8_t tagSize; - char outFormat; + uint32_t tagSize; + const char* outFormat; + uint64_t mqttRFIDKeypadBuffer; + uint64_t webRFIDKeypadBuffer; static volatile uint64_t rfidBuffer; static volatile uint16_t bitCount; @@ -107,7 +127,6 @@ class Wiegand { static volatile bool CodeComplete; static volatile RFID_store rfid_found[]; static volatile int currentFoundRFIDcount; - }; Wiegand* oWiegand = new Wiegand(); @@ -141,7 +160,9 @@ Wiegand::Wiegand() { rfid_found[i].RFID=0; rfid_found[i].bitCount=0; } - outFormat='u'; // standard output format decimal + outFormat="u"; // standard output format decimal + mqttRFIDKeypadBuffer = 0; + webRFIDKeypadBuffer = 0; } void ICACHE_RAM_ATTR Wiegand::handleD1Interrupt() { // Receive a 1 bit. (D0=high & D1=low) @@ -202,6 +223,10 @@ void Wiegand::Init() { #endif // DEV_WIEGAND_TEST_MODE>0 pinMode(Pin(GPIO_WIEGAND_D0), INPUT_PULLUP); pinMode(Pin(GPIO_WIEGAND_D1), INPUT_PULLUP); +#if (DEV_WIEGAND_TEST_MODE==1) // overwrite the setting + pinMode(Pin(GPIO_WIEGAND_D0), OUTPUT); + pinMode(Pin(GPIO_WIEGAND_D1), OUTPUT); +#endif //(DEV_WIEGAND_TEST_MODE==1) attachInterrupt(Pin(GPIO_WIEGAND_D0), handleD0Interrupt, FALLING); attachInterrupt(Pin(GPIO_WIEGAND_D1), handleD1Interrupt, FALLING); isInit = true; // Helps to run only if correctly setup @@ -286,27 +311,8 @@ uint8_t Wiegand::CalculateParities(uint64_t tagWithoutParities, int tag_size=26) return retValue; } -char Wiegand::translateEnterEscapeKeyPress(char oKeyPressed) { - switch(oKeyPressed) { - case 0x0b: // 11 or * key - return 0x0d; // 13 or ASCII ENTER - - case 0x0a: // 10 or # key - return 0x1b; // 27 or ASCII ESCAPE - - default: - return oKeyPressed; - } -} - bool Wiegand::WiegandConversion (uint64_t rfidBuffer, uint16_t bitCount) { bool bRet = false; - // unsigned long nowTick = micros(); - // Add a maximum wait time for new bits - // unsigned long diffTicks = nowTick - lastFoundTime; - // unsigned long inter_code_gap = WIEGAND_CODE_GAP_FACTOR * bitTime; - // if ((diffTicks > inter_code_gap) && (diffTicks >= 1000000 )) { // Max. 4-8 secs between 2 bits comming in. depends on micros() resolution - #if (DEV_WIEGAND_TEST_MODE)>0 AddLog(LOG_LEVEL_INFO, PSTR("WIE: Raw tag %llu, Bit count %u"), rfidBuffer, bitCount); #endif // DEV_WIEGAND_TEST_MODE>0 @@ -318,7 +324,7 @@ bool Wiegand::WiegandConversion (uint64_t rfidBuffer, uint16_t bitCount) { } else if (4 == bitCount) { // 4-bit Wiegand codes for keypads - rfid = (int)translateEnterEscapeKeyPress(rfidBuffer & 0x0000000F); + rfid = (int)(rfidBuffer & 0x0000000F); tagSize = bitCount; bRet = true; } @@ -329,16 +335,15 @@ bool Wiegand::WiegandConversion (uint64_t rfidBuffer, uint16_t bitCount) { char highNibble = (rfidBuffer & 0xf0) >>4; char lowNibble = (rfidBuffer & 0x0f); if (lowNibble == (~highNibble & 0x0f)) { // Check if low nibble matches the "NOT" of high nibble. - rfid = (int)translateEnterEscapeKeyPress(lowNibble); + rfid = (int)(lowNibble); bRet = true; } else { - // lastFoundTime = nowTick; bRet = false; } tagSize = bitCount; } else { // Time reached but unknown bitCount, clear and start again - // lastFoundTime = nowTick; + tagSize = 0; bRet = false; } #if (DEV_WIEGAND_TEST_MODE)>0 @@ -349,8 +354,31 @@ bool Wiegand::WiegandConversion (uint64_t rfidBuffer, uint16_t bitCount) { void Wiegand::setOutputFormat(void) { - if (GetOption(WIEGAND_OPTION_HEX) == 0) { outFormat = 'u'; } - else { outFormat = 'X'; } + if (GetOption(WIEGAND_OPTION_HEX) == 0) { outFormat = "u"; } + else { outFormat = "X" WIEGAND_OPTION_HEX_POSTFIX ; } +} + +void Wiegand::HandleKeyPad(void) { // will be called if a valid key pad input was recognized + if (GetOption(WIEGAND_OPTION_KEYPAD_TO_TAG) == 0) { // handle all key pad inputs as ONE Tag until # is recognized + if ( (tagSize == 4) || (tagSize == 8) ) { + //only handle Keypad strokes if it is requested + if (rfid >= 0x0a) { // # * as end of input detected -> all key values which are larger than 9 + rfid = mqttRFIDKeypadBuffer; // original tagsize of 4 or 8 will be kept. + webRFIDKeypadBuffer = 0; // can be resetted, because now rfid > 0 will be used at web interface + mqttRFIDKeypadBuffer = 0; + } + else { + mqttRFIDKeypadBuffer = (mqttRFIDKeypadBuffer*10)+rfid; //left shift + new key + webRFIDKeypadBuffer = mqttRFIDKeypadBuffer; // visualising the current typed keys + rfid = 0; + tagSize = 0; + } + } + else { //it's not a key pad entry, so another key come in, we will reset the buffer, if it is not finished yet + webRFIDKeypadBuffer = 0; + mqttRFIDKeypadBuffer = 0; + } + } } void Wiegand::ScanForTag() { @@ -364,7 +392,7 @@ void Wiegand::ScanForTag() { // format MQTT output setOutputFormat(); char sFormat[50]; - snprintf( sFormat, 50, PSTR(",\"Wiegand\":{\"UID\":%%0ll%c,\"" D_JSON_SIZE "\":%%%c}}"), outFormat, outFormat); + snprintf( sFormat, 50, PSTR(",\"Wiegand\":{\"UID\":%%0ll%s,\"" D_JSON_SIZE "\":%%%s}}"), outFormat, outFormat); for (int i= 0; i < WIEGAND_RFID_ARRAY_SIZE; i++) { @@ -375,11 +403,14 @@ void Wiegand::ScanForTag() { AddLog(LOG_LEVEL_INFO, PSTR("WIE: Previous tag %llu"), oldTag); #endif // DEV_WIEGAND_TEST_MODE>0 if (validKey) { // Only in case of valid key do action. Issue#10585 - if (oldTag == rfid) { - AddLog(LOG_LEVEL_DEBUG, PSTR("WIE: Old tag")); + HandleKeyPad(); //support one tag for multi key input + if (tagSize>0) { //do output only for rfids which are complete + if (oldTag == rfid) { + AddLog(LOG_LEVEL_DEBUG, PSTR("WIE: Old tag")); + } + ResponseTime_P(sFormat, rfid, tagSize); + MqttPublishTeleSensor(); } - ResponseTime_P(sFormat, rfid,tagSize); - MqttPublishTeleSensor(); } rfid_found[i].RFID=0; rfid_found[i].bitCount=0; @@ -399,17 +430,192 @@ void Wiegand::ScanForTag() { #ifdef USE_WEBSERVER void Wiegand::Show(void) { - setOutputFormat(); - char sFormat [30]; - snprintf( sFormat, 30,PSTR("{s}Wiegand UID{m}%%ll%c {e}"), outFormat); - WSContentSend_PD(sFormat, rfid); - //WSContentSend_PD(PSTR("{s}Wiegand UID{m}%llX {e}"), rfid); -#if (DEV_WIEGAND_TEST_MODE)>0 - AddLog(LOG_LEVEL_INFO, PSTR("WIE: Tag %llu, Bits %u"), rfid, bitCount); -#endif // DEV_WIEGAND_TEST_MODE>0 + setOutputFormat(); + char sFormat [30]; + snprintf( sFormat, 30,PSTR("{s}Wiegand UID{m}%%ll%s {e}"), outFormat); + if (tagSize>0) { WSContentSend_PD(sFormat, rfid); } + else { WSContentSend_PD(sFormat, webRFIDKeypadBuffer); } + + #if (DEV_WIEGAND_TEST_MODE)>0 + AddLog(LOG_LEVEL_INFO, PSTR("WIE: Tag %llu, Bits %u"), rfid, bitCount); + #endif // DEV_WIEGAND_TEST_MODE>0 + } #endif // USE_WEBSERVER +#if (DEV_WIEGAND_TEST_MODE==1) + void CmndTag(void); + void CmndTagSize(void); + void CmndTagGap(void); + void CmndTimeReset(void); + void CmndAllReset(void); + void CmndSend(void); + void CmndBitTime(void); + void CmndInterBitTime(void); + unsigned int setTagSize( char *); + unsigned int setTag ( char * ); + void sendBit(unsigned int b); + void sendTag(uint32_t Tag, uint32_t TagSize); + + uint32_t currTag = 0; + uint32_t currTagSize = 26; //default value 26 Wiegand + uint32_t currBitTime=(WIEGAND_BIT_TIME_DEFAULT/10); //length of the bit impluse in µs + uint32_t currInterBitTime = ((WIEGAND_BIT_TIME_DEFAULT/10)*9); //time to wait before next bit is send in µs + uint32_t currTagGabTime = (WIEGAND_BIT_TIME_DEFAULT * WIEGAND_CODE_GAP_FACTOR) ; //time to wait before next tag is send in µs + + + void CmndTag(void){ + if (XdrvMailbox.data_len > 0) { + currTag= strtoul(XdrvMailbox.data, nullptr, 0); + } + ResponseCmndNumber(currTag); + } + void CmndTagSize(void){ + if (XdrvMailbox.data_len > 0) { + currTagSize = setTagSize(XdrvMailbox.data); + } + ResponseCmndNumber(currTagSize); + } + void CmndTagGap(void){ + if (XdrvMailbox.data_len > 0) { + currTagGabTime = strtoul(XdrvMailbox.data, nullptr, 0); + if (currTagGabTime < (currBitTime+currInterBitTime) ) // doesn't make sense + { currTagGabTime = (currBitTime+currInterBitTime) * WIEGAND_CODE_GAP_FACTOR; } + } + ResponseCmndNumber(currTagGabTime); + } + void CmndBitTime(void){ + if (XdrvMailbox.data_len > 0) { + uint32_t newBitTime = strtoul(XdrvMailbox.data, nullptr, 0); + if ( (newBitTime >= 100) && (newBitTime <= 500000) ) // accept only values between 100µs and 5s + { currBitTime = newBitTime; } + } + ResponseCmndNumber(currBitTime); + } + void CmndInterBitTime(void){ + if (XdrvMailbox.data_len > 0) { + uint32_t newInterBitTime = strtoul(XdrvMailbox.data, nullptr, 0); + if ( (newInterBitTime >= currBitTime) && (newInterBitTime <= (100 * currBitTime)) ) // accept only values between 100µs and 5s + { currInterBitTime = newInterBitTime; } + } + ResponseCmndNumber(currInterBitTime); + } + void CmndTimeReset(void){ + currBitTime=(WIEGAND_BIT_TIME_DEFAULT/10); + currInterBitTime = ((WIEGAND_BIT_TIME_DEFAULT/10)*9); + currTagGabTime = (WIEGAND_BIT_TIME_DEFAULT * WIEGAND_CODE_GAP_FACTOR) ; + ResponseCmndChar_P(PSTR("All timings reset to default!")); + } + void CmndAllReset(void){ + CmndTimeReset(); + currTagSize = 26; + ResponseCmndChar_P(PSTR("All timings and tag size reset to default")); + } + void CmndSend(void){ + if (XdrvMailbox.data_len > 0) { // parameter [tag[:tagsize];tag[:tagsize];...] + char *parameter = strtok(XdrvMailbox.data, ";"); + while (parameter != nullptr) { + char* pTagSize = strchr(parameter,':'); // find optional tagsizes + if (pTagSize != 0) { // 2 parameters found tag:tagsize + *pTagSize = 0; //replace separator ':' by \0 string end + currTag = setTag(parameter); // is now ending before tagsize + pTagSize++; //set the starting char of tagsize correctly + currTagSize = setTagSize(pTagSize); + ResponseCmndChar(pTagSize); + } + else {//only one parameter (tag) found + currTag = setTag(parameter); + } + ResponseCmndChar(parameter); + sendTag(currTag, currTagSize); + ResponseCmndNumber(currTag); + parameter = strtok(nullptr, ";"); + } + } + else { // send last used values again + sendTag(currTag, currTagSize); + ResponseCmndNumber(currTag); + } + } + unsigned int setTag ( char * newTag) { + unsigned int retValue = strtoul(newTag, nullptr, 0); + if ( (currTagSize == 4) || (currTagSize == 8) ) //key pad input simulation requested + { retValue &= 0x0F; } + return retValue; + } + unsigned int setTagSize ( char * newTagSize) { + unsigned int retValue = strtoul(newTagSize, nullptr, 0); + // accept only supported TagSize + if ( retValue <= 4) { retValue = 4;} + else if ( retValue <= 8) { retValue = 8;} + else if ( retValue <= 24) { retValue = 24;} + else if ( retValue <= 26) { retValue = 26;} + else if ( retValue <= 32) { retValue = 32;} + else if ( retValue <= 34) { retValue = 34;} + else { retValue = 26;} //default value + return retValue; + } + void sendBit(unsigned int b) { + int sel = (b == 0) ? Pin(GPIO_WIEGAND_D0) : Pin(GPIO_WIEGAND_D1); + digitalWrite(sel, 0); + delayMicroseconds(currBitTime); // bit impuls time + digitalWrite(sel, 1); + delayMicroseconds(currBitTime+currInterBitTime); // bit + inter bit gap time + } + void sendPlainTag( uint32_t pTag, uint32_t pTagSize){ // send tag without parity + for (int i=1; i<=pTagSize; ++i) + { + sendBit((pTag >> (pTagSize-i)) & 1); + } + } + void sendTag(uint32_t Tag, uint32_t TagSize) { + // TagSize is the requested output tagSize. means b.e. 24 bit == 24 Tag without parity 26 bit = 24 bit with parity bits + // supported tag sizes 4/8 for key pad simulation 24/26 and 32/34 for RFID tags + switch (TagSize){ + case 24: + case 32: + case 4: + sendPlainTag( Tag, TagSize); + break; + case 26: + case 34: + uint8_t parity; + parity = oWiegand->CalculateParities(Tag, TagSize); + sendBit(parity & 0x01); //even parity (starting parity) + sendPlainTag( Tag, TagSize-2); + sendBit(parity & 0x80); //odd parity (ending parity) + break; + case 8: // high nibble is ~ low nibble + Tag = Tag & 0x0F; // low nibble in case of more the one char input it will be cut here + Tag = Tag | ((~Tag) << 4); + sendPlainTag ( Tag, TagSize); + break; + } + //delay to simulate end of tag + delayMicroseconds(currTagGabTime); // inter code gap + return; +} +const char kWiegandCommands[] PROGMEM = "Wie|" // No prefix + "Tag|" + "TagSize|" + "TagGap|" + "BitTime|" + "InterBitTime|" + "TimeReset|" + "AllReset|" + "Send"; + + void (* const WiegandCommand[])(void) PROGMEM = { + &CmndTag, + &CmndTagSize, + &CmndTagGap, + &CmndBitTime, + &CmndInterBitTime, + &CmndTimeReset, + &CmndAllReset, + &CmndSend + }; +#endif //(DEV_WIEGAND_TEST_MODE==1) /*********************************************************************************************\ * Interface \*********************************************************************************************/ @@ -430,6 +636,11 @@ bool Xsns82(byte function) { oWiegand->Show(); break; #endif // USE_WEBSERVER +#if (DEV_WIEGAND_TEST_MODE==1) + case FUNC_COMMAND: + result = DecodeCommand(kWiegandCommands, WiegandCommand); + break; +#endif //(DEV_WIEGAND_TEST_MODE==1) } } return result; diff --git a/tasmota/xsns_85_mpu6886.ino b/tasmota/xsns_85_mpu6886.ino new file mode 100644 index 000000000..5a288fd2f --- /dev/null +++ b/tasmota/xsns_85_mpu6886.ino @@ -0,0 +1,128 @@ +/* + xsns_84_tof10120.ino - TOF10120 sensor support for Tasmota + + Copyright (C) 2021 Stephan Hadinger 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_I2C +#ifdef USE_MPU6886 + +#include +/*********************************************************************************************\ + * MPU6886 + * Internal chip found in M5Stack devices, using `Wire1` internal I2C bus + * + * I2C Address: 0x68 + * +\*********************************************************************************************/ + +#define XSNS_85 85 +#define XI2C_58 58 // See I2CDEVICES.md + +#define MPU6886_ADDRESS 0x68 + +struct { + MPU6886 Mpu; + bool ready = false; + int16_t ax=0, ay=0, az=0; // accelerator data + int16_t gyx=0, gyy=0, gyz=0; // accelerator data +} mpu6886_sensor; + +/********************************************************************************************/ + +const char HTTP_MPU6686[] PROGMEM = + "{s}MPU6886 acc_x" "{m}%3_f G" "{e}" + "{s}MPU6886 acc_y" "{m}%3_f G" "{e}" + "{s}MPU6886 acc_z" "{m}%3_f G" "{e}" + "{s}MPU6886 gyr_x" "{m}%i dps" "{e}" + "{s}MPU6886 gyr_y" "{m}%i dps" "{e}" + "{s}MPU6886 gyr_z" "{m}%i dps" "{e}" + ; + +void MPU6686_Show(uint32_t json) { + if (json) { + ResponseAppend_P(PSTR(",\"MPU6886\":{\"AX\":%i,\"AY\":%i,\"AZ\":%i,\"GX\":%i,\"GY\":%i,\"GZ\":%i}"), + mpu6886_sensor.ax, mpu6886_sensor.ay, mpu6886_sensor.az, + mpu6886_sensor.gyx, mpu6886_sensor.gyy, mpu6886_sensor.gyz); + } else { + float ax = mpu6886_sensor.ax / 1000.0f; + float ay = mpu6886_sensor.ay / 1000.0f; + float az = mpu6886_sensor.az / 1000.0f; + WSContentSend_PD(HTTP_MPU6686, &ax, &ay, &az, + mpu6886_sensor.gyx, mpu6886_sensor.gyy, mpu6886_sensor.gyz); + + } +} + +void MPU6686Detect(void) { +#ifdef ESP32 + if (!I2cSetDevice(MPU6886_ADDRESS, 0)) { + if (!I2cSetDevice(MPU6886_ADDRESS, 1)) { return; } // check on bus 1 + mpu6886_sensor.Mpu.setBus(1); // switch to bus 1 + I2cSetActiveFound(MPU6886_ADDRESS, "MPU6886", 1); + } else { + I2cSetActiveFound(MPU6886_ADDRESS, "MPU6886", 0); + } +#else + if (!I2cSetDevice(MPU6886_ADDRESS)) { return; } + I2cSetActiveFound(MPU6886_ADDRESS, "MPU6886"); +#endif + + mpu6886_sensor.Mpu.Init(); + mpu6886_sensor.ready = true; +} + +void MPU6886Every_Second(void) { + mpu6886_sensor.Mpu.getAccelDataInt(&mpu6886_sensor.ax, &mpu6886_sensor.ay, &mpu6886_sensor.az); + mpu6886_sensor.Mpu.getGyroDataInt(&mpu6886_sensor.gyx, &mpu6886_sensor.gyy, &mpu6886_sensor.gyz); + + // AddLog(LOG_LEVEL_DEBUG, PSTR(">> Acc x=%i y=%i z=%i gx=%i gy=%i gz=%i"), mpu6886_sensor.ax, mpu6886_sensor.ay, mpu6886_sensor.az, + // mpu6886_sensor.gyx, mpu6886_sensor.gyy, mpu6886_sensor.gyz); + +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns85(uint8_t function) { + if (!I2cEnabled(XI2C_58)) { return false; } + + bool result = false; + + if (FUNC_INIT == function) { + MPU6686Detect(); + } + else if (mpu6886_sensor.ready) { + switch (function) { + case FUNC_EVERY_SECOND: + MPU6886Every_Second(); + break; + case FUNC_JSON_APPEND: + MPU6686_Show(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + MPU6686_Show(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_MPU6886 +#endif // USE_I2C \ No newline at end of file