diff --git a/.github/workflows/Tasmota_build_devel.yml b/.github/workflows/Tasmota_build_devel.yml
index 2bbc4fc66..30502be32 100644
--- a/.github/workflows/Tasmota_build_devel.yml
+++ b/.github/workflows/Tasmota_build_devel.yml
@@ -1,12 +1,13 @@
+
name: Build_development
on:
- workflow_dispatch: # Manually start a workflow
+ workflow_dispatch: # Manually start a workflow
push:
branches: development
paths-ignore:
- - '.github/**' # Ignore changes towards the .github directory
- - '**.md' # Do no build if *.md files changes
+ - '.github/**' # Ignore changes towards the .github directory
+ - '**.md' # Do no build if *.md files changes
# Ensures that only one deploy task per branch/environment will run at a time.
concurrency:
@@ -14,6 +15,41 @@ concurrency:
cancel-in-progress: true
jobs:
+ safeboot-images:
+ runs-on: ubuntu-latest
+ if: github.repository == 'arendst/Tasmota'
+ continue-on-error: true
+ strategy:
+ matrix:
+ variant:
+ - tasmota32solo1-safeboot
+ - tasmota32-safeboot
+ - tasmota32c3-safeboot
+ - tasmota32c3cdc-safeboot
+ - tasmota32s2-safeboot
+ - tasmota32s2cdc-safeboot
+ - tasmota32s3-safeboot
+ - tasmota32s3cdc-safeboot
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ ref: development
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
+ - name: Install dependencies
+ run: |
+ pip install wheel
+ pip install -U platformio
+ - name: Run PlatformIO
+ run: platformio run -e ${{ matrix.variant }}
+ - name: Upload safeboot firmware artifacts
+ uses: actions/upload-artifact@v3
+ with:
+ name: firmware_safeboot
+ path: ./build_output
+
base-images:
runs-on: ubuntu-latest
if: github.repository == 'arendst/Tasmota'
@@ -31,6 +67,34 @@ jobs:
- tasmota-sensors
- tasmota-zbbridge
- tasmota-zigbee
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ ref: development
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
+ - name: Install dependencies
+ run: |
+ pip install wheel
+ pip install -U platformio
+ - name: Run PlatformIO
+ run: platformio run -e ${{ matrix.variant }}
+ - name: Upload firmware artifacts
+ uses: actions/upload-artifact@v3
+ with:
+ name: firmware
+ path: ./build_output
+
+ base32-images:
+ needs: safeboot-images
+ runs-on: ubuntu-latest
+ if: github.repository == 'arendst/Tasmota'
+ continue-on-error: true
+ strategy:
+ matrix:
+ variant:
- tasmota32
- tasmota32-zbbrdgpro
- tasmota32-webcam
@@ -46,32 +110,36 @@ jobs:
- tasmota32s3
- tasmota32s3cdc
- tasmota32solo1
- - tasmota32solo1-safeboot
- - tasmota32-safeboot
- - tasmota32c3-safeboot
- - tasmota32c3cdc-safeboot
- - tasmota32s2-safeboot
- - tasmota32s2cdc-safeboot
- - tasmota32s3-safeboot
- - tasmota32s3cdc-safeboot
steps:
- uses: actions/checkout@v3
with:
ref: development
- name: Set up Python
- uses: actions/setup-python@v3
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
- name: Install dependencies
run: |
pip install wheel
pip install -U platformio
+ - name: Download safeboot firmwares
+ uses: actions/download-artifact@v3
+ with:
+ name: firmware_safeboot
+ path: ./firmware
+ - name: Display downloaded files
+ run: |
+ ls -R ./firmware/
- name: Run PlatformIO
run: platformio run -e ${{ matrix.variant }}
- - uses: actions/upload-artifact@v3
+ - name: Upload firmware artifacts
+ uses: actions/upload-artifact@v3
with:
name: firmware
path: ./build_output
language-images:
+ needs: safeboot-images
runs-on: ubuntu-latest
if: github.repository == 'arendst/Tasmota'
continue-on-error: true
@@ -84,27 +152,44 @@ jobs:
with:
ref: development
- name: Set up Python
- uses: actions/setup-python@v3
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
- name: Install dependencies
run: |
pip install wheel
pip install -U platformio
+ - name: Download safeboot firmwares
+ uses: actions/download-artifact@v3
+ with:
+ name: firmware_safeboot
+ path: ./firmware
+ - name: Display downloaded files
+ run: |
+ ls -R ./firmware/
- name: Run PlatformIO
run: platformio run -e ${{ matrix.variant }}-${{ matrix.language }}
- - uses: actions/upload-artifact@v3
+ - name: Upload language firmware artifacts
+ uses: actions/upload-artifact@v3
with:
name: firmware
path: ./build_output
Upload:
- needs: [base-images, language-images]
+ needs: [base-images, base32-images, language-images]
runs-on: ubuntu-latest
continue-on-error: true
steps:
- - uses: actions/download-artifact@v3
+ - name: Download firmware
+ uses: actions/download-artifact@v3
with:
name: firmware
path: ./mv_firmware
+ - name: Downlaod safeboot firmware
+ uses: actions/download-artifact@v3
+ with:
+ name: firmware_safeboot
+ path: ./mv_firmware
- name: Display structure of downloaded files
run: ls -R
working-directory: ./mv_firmware
@@ -155,7 +240,6 @@ jobs:
destination_branch: 'firmware'
user_email: 'github-actions@github.com'
user_name: 'github-actions'
-
Start_final_copy:
needs: Upload
runs-on: ubuntu-latest
diff --git a/.github/workflows/Tasmota_build_master.yml b/.github/workflows/Tasmota_build_master.yml
index 9905d287f..7691a725f 100644
--- a/.github/workflows/Tasmota_build_master.yml
+++ b/.github/workflows/Tasmota_build_master.yml
@@ -1,11 +1,12 @@
name: Build_firmware_master
on:
+ workflow_dispatch: # Manually start a workflow
push:
branches: master
paths-ignore:
- - '.github/**' # Ignore changes towards the .github directory
- - '**.md' # Do no build if *.md files changes
+ - '.github/**' # Ignore changes towards the .github directory
+ - '**.md' # Do no build if *.md files changes
# Ensures that only one deploy task per branch/environment will run at a time.
concurrency:
@@ -13,6 +14,41 @@ concurrency:
cancel-in-progress: true
jobs:
+ safeboot-images:
+ runs-on: ubuntu-latest
+ if: github.repository == 'arendst/Tasmota'
+ continue-on-error: true
+ strategy:
+ matrix:
+ variant:
+ - tasmota32solo1-safeboot
+ - tasmota32-safeboot
+ - tasmota32c3-safeboot
+ - tasmota32c3cdc-safeboot
+ - tasmota32s2-safeboot
+ - tasmota32s2cdc-safeboot
+ - tasmota32s3-safeboot
+ - tasmota32s3cdc-safeboot
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ ref: master
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
+ - name: Install dependencies
+ run: |
+ pip install wheel
+ pip install -U platformio
+ - name: Run PlatformIO
+ run: platformio run -e ${{ matrix.variant }}
+ - name: Upload safeboot firmware artifacts
+ uses: actions/upload-artifact@v3
+ with:
+ name: firmware_safeboot
+ path: ./build_output
+
base-images:
runs-on: ubuntu-latest
if: github.repository == 'arendst/Tasmota'
@@ -30,6 +66,34 @@ jobs:
- tasmota-sensors
- tasmota-zbbridge
- tasmota-zigbee
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ ref: master
+ - name: Set up Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
+ - name: Install dependencies
+ run: |
+ pip install wheel
+ pip install -U platformio
+ - name: Run PlatformIO
+ run: platformio run -e ${{ matrix.variant }}
+ - name: Upload firmware artifacts
+ uses: actions/upload-artifact@v3
+ with:
+ name: firmware
+ path: ./build_output
+
+ base32-images:
+ needs: safeboot-images
+ runs-on: ubuntu-latest
+ if: github.repository == 'arendst/Tasmota'
+ continue-on-error: true
+ strategy:
+ matrix:
+ variant:
- tasmota32
- tasmota32-zbbrdgpro
- tasmota32-webcam
@@ -45,32 +109,36 @@ jobs:
- tasmota32s3
- tasmota32s3cdc
- tasmota32solo1
- - tasmota32solo1-safeboot
- - tasmota32-safeboot
- - tasmota32c3-safeboot
- - tasmota32c3cdc-safeboot
- - tasmota32s2-safeboot
- - tasmota32s2cdc-safeboot
- - tasmota32s3-safeboot
- - tasmota32s3cdc-safeboot
steps:
- uses: actions/checkout@v3
with:
ref: master
- name: Set up Python
- uses: actions/setup-python@v3
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
- name: Install dependencies
run: |
pip install wheel
pip install -U platformio
+ - name: Download safeboot firmwares
+ uses: actions/download-artifact@v3
+ with:
+ name: firmware_safeboot
+ path: ./firmware
+ - name: Display downloaded files
+ run: |
+ ls -R ./firmware/
- name: Run PlatformIO
run: platformio run -e ${{ matrix.variant }}
- - uses: actions/upload-artifact@v3
+ - name: Upload firmware artifacts
+ uses: actions/upload-artifact@v3
with:
name: firmware
path: ./build_output
language-images:
+ needs: safeboot-images
runs-on: ubuntu-latest
if: github.repository == 'arendst/Tasmota'
continue-on-error: true
@@ -83,14 +151,25 @@ jobs:
with:
ref: master
- name: Set up Python
- uses: actions/setup-python@v3
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
- name: Install dependencies
run: |
pip install wheel
pip install -U platformio
+ - name: Download safeboot firmwares
+ uses: actions/download-artifact@v3
+ with:
+ name: firmware_safeboot
+ path: ./firmware
+ - name: Display downloaded files
+ run: |
+ ls -R ./firmware/
- name: Run PlatformIO
run: platformio run -e ${{ matrix.variant }}-${{ matrix.language }}
- - uses: actions/upload-artifact@v3
+ - name: Upload language firmware artifacts
+ uses: actions/upload-artifact@v3
with:
name: firmware
path: ./build_output
@@ -108,7 +187,7 @@ jobs:
- name: Display structure of downloaded files
run: ls -R ./mv_firmware/
- name: Release
- uses: softprops/action-gh-release@v1
+ uses: jason2866/action-gh-release@v1.2
#if: startsWith(github.ref, 'refs/tags/')
with:
tag_name: ${{ github.run_number }}
diff --git a/.github/workflows/build_all_the_things.yml b/.github/workflows/build_all_the_things.yml
index ae8e7e1eb..a91217bac 100644
--- a/.github/workflows/build_all_the_things.yml
+++ b/.github/workflows/build_all_the_things.yml
@@ -28,7 +28,9 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Python
- uses: actions/setup-python@v3
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
- name: Install dependencies
run: |
pip install wheel
@@ -44,7 +46,7 @@ jobs:
path: ./build_output
os-check-mac:
- runs-on: macos-latest
+ runs-on: macOS-12
if: github.repository == 'arendst/Tasmota'
strategy:
fail-fast: true
@@ -54,7 +56,9 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Python
- uses: actions/setup-python@v3
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
- name: Install dependencies
run: |
pip install wheel
@@ -109,9 +113,15 @@ jobs:
- tasmota32s3-safeboot
- tasmota32s3cdc-safeboot
steps:
+ - name: Sleep a while, try to start MacOS / Windows CI env first
+ uses: jakejarvis/wait-action@master
+ with:
+ time: '1m'
- uses: actions/checkout@v3
- name: Set up Python
- uses: actions/setup-python@v3
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
- name: Install dependencies
run: |
pip install wheel
@@ -137,7 +147,9 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Python
- uses: actions/setup-python@v3
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.x'
- name: Install dependencies
run: |
pip install wheel
diff --git a/.github/workflows/stale-actions.yml b/.github/workflows/stale-actions.yml
index 75decdd3c..b99f6f555 100644
--- a/.github/workflows/stale-actions.yml
+++ b/.github/workflows/stale-actions.yml
@@ -8,7 +8,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- - uses: actions/stale@v3.0.15
+ - uses: actions/stale@v6.0.1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 25
diff --git a/API.md b/API.md
index b631172ed..9e5d51a5b 100644
--- a/API.md
+++ b/API.md
@@ -14,20 +14,24 @@ Callback Id | Bool | xdrv | xsns | xnrg | xlgt | Description
----------------------------|------|------|------|------|------|----------------------------------
FUNC_SETTINGS_OVERRIDE | | x | | | | Override start-up settings
FUNC_PIN_STATE | x | 1 | 2 | | | At GPIO configuration
+FUNC_I2C_INIT | | x | | | | Immediatly after I2C init
FUNC_MODULE_INIT | x | 3 | 1 | | 2 | Init module specific parameters
FUNC_PRE_INIT | | 1 | 3 | 2 | | Once GPIO have been established
FUNC_INIT | | 1 | 3 | 2 | | At end of initialisation
FUNC_LOOP | | 1 | 2 | | | In main loop
-FUNC_EVERY_50_MSECOND | | 1 | 2 | | |
-FUNC_EVERY_100_MSECOND | | 1 | 2 | | |
-FUNC_EVERY_200_MSECOND | | | | x | |
-FUNC_EVERY_250_MSECOND | | 1 | 3 | 2 | |
-FUNC_EVERY_SECOND | | 1 | 2 | | |
+FUNC_SLEEP_LOOP | | 1 | 2 | | | In main loop during sleep
+FUNC_EVERY_50_MSECOND | | 1 | 2 | | | In main loop
+FUNC_EVERY_100_MSECOND | | 1 | 2 | | | In main loop
+FUNC_EVERY_200_MSECOND | | | | x | | In main loop
+FUNC_EVERY_250_MSECOND | | 1 | 3 | 2 | | In main loop
+FUNC_EVERY_SECOND | | 1 | 2 | | | In main loop
+FUNC_SAVE_SETTINGS | | 2 | 1 | | | Just before saving settings
FUNC_SAVE_AT_MIDNIGHT | | | x | | | At midnight
FUNC_SAVE_BEFORE_RESTART | | 2 | 1 | | | Just before a planned restart
FUNC_AFTER_TELEPERIOD | | 2 | 1 | | | At end of teleperiod
FUNC_JSON_APPEND | | 2 | 1 | 3 | | Extend teleperiod JSON text
FUNC_WEB_SENSOR | | 2 | 1 | 3 | | Add sensor data to web GUI
+FUNC_WEB_COL_SENSOR | | 2 | 1 | 3 | | Add sensor data to web GUI using columns
FUNC_COMMAND | x | 1 | 2 | 3 | 4 | When a command is not recognized
FUNC_COMMAND_DRIVER | x | x | | | | When command Driver\ is executed
FUNC_COMMAND_SENSOR | x | | x | | | When command Sensor\ is executed
@@ -38,19 +42,28 @@ FUNC_SET_POWER | | 1 | 2 | | | Before setting
FUNC_SET_DEVICE_POWER | x | x | | | | Set relay
FUNC_SHOW_SENSOR | | x | | | | When FUNC_JSON_APPEND completes
FUNC_ANY_KEY | | x | | | |
+FUNC_LED_LINK | | x | | | | SetLedLink (On ESP32 only). XdrvMailbox.index holds state
FUNC_ENERGY_EVERY_SECOND | | | | x | |
FUNC_ENERGY_RESET | | | | x | |
FUNC_RULES_PROCESS | x | x | | | | Process specific rule
+FUNC_TELEPERIOD_RULES_PROCESS | x | x | | | | Process specific rule as teleperiod
FUNC_SERIAL | x | 1 | | 2 | 3 | Process serial data
FUNC_FREE_MEM | | x | | | | Show free memory for debugging
FUNC_BUTTON_PRESSED | x | x | | | | When a button is pressed
+FUNC_BUTTON_MULTI_PRESSED | x | x | | | | When a button is pressed multiple times
FUNC_WEB_ADD_BUTTON | | 1 | 2 | | | Add a Configuration Button to GUI
FUNC_WEB_ADD_MAIN_BUTTON | | 1 | 2 | | | Add a main button to GUI
+FUNC_WEB_ADD_CONSOLE_BUTTON | | 1 | 2 | | | Add a Consoles Button to GUI
+FUNC_WEB_ADD_MANAGEMENT_BUTTON | | x | | | | Add a Management Button to GUI
FUNC_WEB_ADD_HANDLER | | 1 | 2 | | | Add a webserver handler
+FUNC_WEB_GET_ARG | | 2 | 1 | | 3 | Get webserver setting arguments
FUNC_SET_CHANNELS | | 2 | | | 1 |
FUNC_SET_SCHEME | | | | | x |
FUNC_HOTPLUG_SCAN | | | x | | |
+FUNC_TIME_SYNCED | | x | | | | Report time is synced
FUNC_DEVICE_GROUP_ITEM | | x | | | |
+FUNC_NETWORK_UP | | 1 | 2 | 3 | 4 | Wifi or ETH network just went up (received even if webserver is not enabled)
+FUNC_NETWORK_DOWN | | 1 | 2 | 3 | 4 | Wifi or ETH network just went down (received even if webserver is not enabled)
The numbers represent the sequence of execution
diff --git a/BUILDS.md b/BUILDS.md
index f10d3359a..f3dbeadab 100644
--- a/BUILDS.md
+++ b/BUILDS.md
@@ -68,6 +68,7 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up
| USE_SM2135 | - | x / - | x | x | - | x |
| USE_SM2335 | - | x / - | x | x | - | x |
| USE_BP5758D | - | x / - | x | x | - | x |
+| USE_BP1658CJ | - | x / - | x | x | - | x |
| USE_SONOFF_L1 | - | x / - | x | x | - | x |
| USE_ELECTRIQ_MOODL | - | x / - | x | x | - | x |
| | | | | | | |
@@ -177,10 +178,13 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up
| USE_DS3502 | - | - / - | - | - | - | - |
| USE_HYT | - | - / - | - | - | - | - |
| USE_LUXV30B | - | - / - | - | - | - | - |
+| USE_HMC5883L | - | - / - | - | - | - | - |
+| USE_QMC5883L | - | - / - | - | - | - | - |
| | | | | | | |
| Feature or Sensor | l | t | k | s | i | d | Remarks
| USE_SPI | - | - / - | - | - | - | x |
| USE_RC522 | - | - / - | - | - | - | - |
+| USE_CANSNIFFER | - | - / - | - | - | - | - |
| USE_MHZ19 | - | - / x | - | x | - | - |
| USE_SENSEAIR | - | - / x | - | x | - | - |
| USE_PMS5003 | - | - / x | - | x | - | - |
@@ -201,6 +205,7 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up
| USE_MIEL_HVAC | - | - / - | - | - | - | - |
| USE_PROJECTOR_CTRL | - | - / - | - | - | - | - |
| USE_AS608 | - | - / - | - | - | - | - |
+| USE_LD2410 | - | - / - | - | - | - | - |
| USE_TCP_BRIDGE | - | - / - | - | - | - | - | zbbridge / zbbrdgpro
| | | | | | | |
| USE_NRF24 | - | - / - | - | - | - | - |
@@ -254,5 +259,9 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up
| USE_I2S_AUDIO | | / - | | | | |
| USE_TTGO_WATCH | | / - | | | | |
| USE_SONOFF_SPM | | / x | | | | |
+| USE_DISPLAY_TM1621_SONOFF | | / x | | | | |
+| USE_SHELLY_PRO | | / x | | | | |
+| USE_DALI | | / - | | | | |
+| USE_DINGTIAN_RELAY | | / - | | | | |
* USE_MQTT_TLS is enabled by default in every ESP32 variants
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 80ee3cd19..4e03507d0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,120 @@ All notable changes to this project will be documented in this file.
## [Released]
+## [12.3.0] 20221215
+- Release Percy
+
+## [12.2.0.6] 20221215
+### Added
+- Serial Modbus transmit enable GPIOs to all modbus energy drivers and modbus bridge (#17247)
+- Berry crypto module, with AES_GCM by default and EC_CC25519 optional
+- IPv6 support for Ethernet (ESP32)
+
+### Changed
+- TasmotaSerial library from v3.5.0 to v3.6.0
+- Removed leading spaces on commands ``(S)SerialSend1 to 6`` but keep on duplicate commands ``(S)SerialSend11 to 16`` (#16723)
+
+### Fixed
+- TasmotaSerial ``read(buffer, size)`` regression from v9.3.0
+- RCSwitch exception 0/6 on some protocols (#17285)
+
+## [12.2.0.5] 20221129
+### Added
+- ESP32 DS18x20 parasitic power usage when defining W1_PARASITE_POWER (#17112)
+- Optional define ``SERIAL_BRIDGE_BUFFER_SIZE`` to set Serial Bridge internal buffer size (Default ESP8266 = 256, ESP32 = 800)
+- Command ``SSerialBuffer 256..SERIAL_BRIDGE_BUFFER_SIZE`` to change serial bridge rx buffer size (#17120)
+- Command ``SetOption35 0..255`` to skip number of received messages in Serial Bridge (default 0) (#17140)
+- Teleinfo TEMPO (BBR) contract (#17160)
+- Support for HLK-LD2410 24GHz smart wave motion sensor
+- Berry ``mdns`` module (#17202)
+- IPv6 preview for ESP32, also working for ESP8266
+
+### Changed
+- Serial Bridge default internal serial rx buffer size from 64 to 256 (#17120)
+- Accept filename extensions to GUI file upload input fields (#16875)
+- AC PWM dimmer lineair power distribution (#17177)
+
+### Fixed
+- ModbusBridge baudrates over 76500 baud (#17106)
+
+### Removed
+- Accept filename extensions to GUI file upload input fields as not functional in some browsers (#16875)
+
+## [12.2.0.4] 20221117
+### Added
+- Support for Plantower PMSx003T AQI models with temperature and humidity (#16971)
+- Support for Dingtian x595/x165 shift register based relay boards by Barbudor (#17032)
+- New ``FUNC_NETWORK_UP`` and ``FUNC_NETWORK_DOWN`` events
+- WS2812 and Light ArtNet DMX control over UDP port 6454 (#17059)
+- Command ``SwitchMode 16`` sending only MQTT message on inverted switch change (#17028)
+- Support for HMC5883L 3-Axis Digital Compass sensor by Andreas Achtzehn (#17069)
+- Berry add ``udp->close()`` method (#17094)
+- Command ``RgxClients`` for range extender clients list (#17048)
+- Command ``RgxPort [tcp|udp], gateway_port, client_mac, client_port`` for range extender port forwardings (#17092)
+
+### Changed
+- Reverted Flash Mode back from ``DIO`` to ``DOUT`` for ESP8266/ESP8285 (#17019)
+- ESP32 Framework (Core) from v2.0.5.2 to v2.0.5.3 (#17034)
+- TuyaMcu rewrite by btsimonh (#17051)
+- WS2812 sends signal to only ``Pixels`` leds instead of sending to 512 leds (#17055)
+- Zigbee improved Aqara plug support and completed cluster 0x0702 (#17073)
+- ESP32 LVGL library from v8.3.2 to v8.3.3 (no functional change)
+
+### Fixed
+- SenseAir S8 module detection (#17033)
+
+## [12.2.0.3] 20221109
+### Added
+- Support for BP1658CJ RGBCW led bulbs like Orein OS0100411267 by Cossid (#17011)
+
+### Breaking Changed
+- Redesign distance sensors VL53LXX, TOF10120, HRXL and DYP to use cm instead of mm (#17021)
+
+### Changed
+- Default Flash Mode changed from ``DOUT`` to ``DIO`` for ESP8266/ESP8285
+
+## [12.2.0.2] 20221107
+### Added
+- Support for Digital Addressable Lighting Interface (DALI) by Andrei Kazmirtsuk (#16938)
+- Support for two phase power calibration using commands ``PowerSet2``, ``VoltageSet2`` and ``CurrentSet2``
+- Support for NTAG2xx tags read and write on PN532 NFC reader (#16939)
+- Berry ``bytes().reverse()`` method (#16977)
+- ESP32 Support for DMX ArtNet Led matrix animations (#16984)
+- Command ``SetOption47 1..255`` to delay power on relay state in seconds reducing power surge. ``SO47 1`` delays until network connected. ``SO47 2`` delays until mqtt connected
+- ESP32 DMX ArtNet optimization to avoid any object allocation and avoid garbage collector pauses
+- Berry add ``dyn`` class
+
+### Changed
+- Move some persistent data (PowerLow)
+- ESP32 Framework (Core) from v2.0.5 to v2.0.5.2
+- ADE7953 monitoring from instant power to accumulated energy (#16941)
+
+### Fixed
+- Deduplicate code and fix %timer n% rule regression from v12.2.0 (#16914)
+- Serial initialization for baudrate and config (#16970)
+- ModbusBridge buffer overflow (#16979)
+- Default serial bridge configuration from 5N1 to 8N1 regression from v10.1.0.3
+
+### Removed
+- Define ``USE_PN532_DATA_RAW`` from NFC reader (#16939)
+
+## [12.2.0.1] 20221026
+### Added
+- DS18x20 support on up to four GPIOs by md5sum-as (#16833)
+- Berry add `bytes().setbytes()` (#16892)
+- Support for Shelly Pro 1/1PM and 2/2PM (#16773)
+- Add Zigbee router firmware for Sonoff ZBBridgePro (#16900)
+- Prepare for DMX ArtNet support on ESP32
+
+### Changed
+- DS18x20 ``DS18Alias`` to ``DS18Sens`` (#16833)
+- Compiling with reduced boards manifests in favour of Autoconfig (#16848)
+- Add NeoPool ``NPFiltration 2`` toggle cmnd (#16859)
+- ESP32 NimBLE library from v1.4.0 to v1.4.1 (#16775)
+
+### Fixed
+- BP5758D red channel corruption regression from v12.1.1.6 (#16850)
+
## [12.2.0] 20221017
- Release Patrick
diff --git a/CODE_OWNERS.md b/CODE_OWNERS.md
index 49a268bb7..0df3e4a1f 100644
--- a/CODE_OWNERS.md
+++ b/CODE_OWNERS.md
@@ -71,17 +71,129 @@ In addition to @arendst the following code is mainly owned by:
| xdrv_60_shift595 | Jacek Ziółkowski
| xdrv_61_ds3502 | f-reiling
| xdrv_62_improv | @arendst
+| xdrv_63_modbus_bridge | @jeroenst
+| |
| xdrv_79_esp32_ble | @staars, @btsimonh
| xdrv_81_esp32_webcam | @gemu, @philrich
| xdrv_82_esp32_ethernet | @arendst
| xdrv_83_esp32_watch | @gemu
| xdrv_85_esp32_ble_eq3_trv | @btsimonh
| xdrv_86_esp32_sonoff_spm | @arendst
+| xdrv_87_esp32_sonoff_tm1621 | @arendst
+| xdrv_88_esp32_shelly_pro | @arendst
+| xdrv_89_esp32_dali | @eeak
+| xdrv_90_esp32_dingtian_relay | @barbudor
+| |
+| xdrv_122_file_settings_demo | @arendst
+| xdrv_127_debug | @arendst
| |
| Tasmota Sensors |
| |
| xsns_01_counter | @arendst, @stefanbode
+| xsns_02_analog | @arendst, @barbudor
+| xsns_03_energy | @arendst
+| xsns_04_snfsc | @arendst
+| xsns_05_ds18x20 | @arendst
+| xsns_06_dht | @arendst
+| xsns_07_sht1x | @arendst
+| xsns_08_htu | Heiko Krupp
+| xsns_09_bmp | @arendst
+| xsns_10_bh1750 | @arendst
+| xsns_11_veml6070 | @mike2nl
+| xsns_12_ads1115 | @syssi, @stefanbode
+| xsns_13_ina219 | @stefanbode
+| xsns_14_sht3x | Stefan Tibus
+| xsns_15_mhz19 | @arendst
+| xsns_16_tsl2561 | Joachim Banzhaf
+| xsns_17_senseair | @arendst
+| xsns_18_pms5003 | @arendst
+| xsns_19_mgs | @palich2000
+| xsns_20_novasds | Norbert Richter
+| xsns_21_sgp30 | Gerhard Mutz
+| xsns_22_sr04 | Nuno Ferreira, @arendst
+| xsns_23 |
+| xsns_24_si1145 |
+| xsns_25 |
+| xsns_26_lm75ad | Andre Thomas
+| xsns_27_apds9960 | Shawn Hymel
+| xsns_28_tm1638 | @arendst
+| xsns_29_mcp230xx | Andre Thomas
+| xsns_30_mpr121 | Rene 'Renne' Bartsch
+| xsns_31_ccs811 | Gerhard Mutz
+| xsns_32_mpu6050 | Oliver Welter
+| xsns_33_qmc5883l | Helge Scheunemann
+| xsns_34_hx711 | @arendst
+| xsns_35_tx20 | Thomas Eckerstorfer, Norbert Richter
+| xsns_36_mgc3130 | Christian Baars
+| xsns_37_rfsensor | @arendst
+| xsns_38_az7798 | @adebeun
+| xsns_39_max31855 | Markus Past
+| xsns_40_pn532 | Andre Thomas, @md5sum-as
+| xsns_41_max44009 | @llagendijk
+| xsns_42_scd30 | @frogmore42
+| xsns_43_hre | Jon Little
+| xsns_44_sps30 | Gerhard Mutz
+| xsns_45_vl53l0x | Gerhard Mutz, Adrian Scillato
+| xsns_46_mlx90614 | Gerhard Mutz
+| xsns_47_max31865 | Alberto Lopez Siemens
+| xsns_48_chirp | Christian Baars
+| xsns_49 |
+| xsns_50_paj7620 | Christian Baars
+| xsns_51_rdm6300 | Gerhard Mutz
+| xsns_52_esp32_ibeacon | Gerhard Mutz, @btsimonh
+| xsns_52_ibeacon | Gerhard Mutz
+| xsns_53_sml | Gerhard Mutz
+| xsns_54_ina226 | Stephen Rodgers
+| xsns_55_hih_series |
+| xsns_56_hpma | David Hunt
+| xsns_57_tsl2591 | Markus Bösling
+| xsns_58_dht12 | Stefan Oskam
+| xsns_59_ds1624 | Leonid Myravje
+| xsns_60_gps | Christian Baars, Adrian Scillato
+| xsns_61_mi_nrf24 | Christian Baars
+| xsns_62_mi_hm10 | Christian Baars
+| xsns_62_esp32_mi | Christian Baars
+| xsns_63_aht1x | Martin Wagner
+| xsns_64_hrxl | Jon Little
+| xsns_65_hdc1080 | Luis Teixeira
+| xsns_66_iaq | Christian Baars
+| xsns_67_as3935 | Martin Wagner
+| xsns_68_windmeter | Matteo Albinola
+| xsns_69_opentherm | Yuriy Sannikov
+| xsns_70_veml6075 | Martin Wagner
+| xsns_71_veml7700 | Martin Wagner
+| xsns_72_mcp9808 | Martin Wagner
+| xsns_73_hp303b | @rjaakke
+| xsns_74_lmt01 | @justifiably
+| xsns_75_prometheus | @marius, @mhansen, @hansmi
+| xsns_76_dyp | Janusz Kostorz
+| xsns_77_vl53l1x | Rui Marinho, @Jason2866
| xsns_78_ezo | Christopher Tremblay
+| xsns_79_as608 | @boaschti
+| xsns_80_mfrc522 | @arendst
+| xsns_81_seesaw_soil | Wayne Ross, Peter Franck
+| xsns_82_wiegand | Sigurd Leuther
+| xsns_83_neopool | Norbert Richter
+| xsns_84_tof10120 | Cyril Pawelko
+| xsns_85_mpu6886 | @s-hadinger
+| xsns_86_tfminiplus | Raphael Breiting
+| xsns_87_can_sniffer | @kwiatek6324, Marius Bezuidenhout
+| xsns_87_mcp2515 | Marius Bezuidenhout
+| xsns_88_am2320 | Lars Wessels
+| xsns_89_t67xx | Alexander Savchenko
+| xsns_90_hrg15 | Wouter Breukink
+| xsns_91_vindriktning | Marcel Ritter
+| xsns_92_scd40 | @frogmore42, @arnold-n
+| xsns_93_hm330x | @barbudor
+| xsns_94_hdc2010 | Luc Boudreau
+| xsns_95_cm1107 | @maksim
+| xsns_96_flowratemeter | Norbert Richter
+| xsns_97_hyt | Thomas Schnittcher, Adjan Kretz
+| xsns_98_sgp40 | Jean-Pierre Deschamps
+| xsns_99_luxv30b | Marius Bezuidenhout
+| xsns_100_ina3221 | @barbudor
+| xsns_101_hmc5883l | Andreas Achtzehn
+| xsns_102_ld2410 | @arendst
| |
| Libraries |
| |
diff --git a/I2CDEVICES.md b/I2CDEVICES.md
index d3b2cd418..3ef236eeb 100644
--- a/I2CDEVICES.md
+++ b/I2CDEVICES.md
@@ -107,3 +107,4 @@ Index | Define | Driver | Device | Address(es) | Description
70 | USE_LUXV30B | xsns_99 | LUXV30B | 0x4A | DFRobot SEN0390 V30B lux sensor
71 | USE_QMC5883L | xsns_33 | QMC5883L | 0x0D | Magnetic Field Sensor
72 | USE_INA3221 | xsns_100 | INA3221 | 0x40-0x43 | 3-channels Voltage and Current sensor
+ 73 | USE_HMC5883L | xsns_101 | HMC5883L | 0x1E | 3-channels Magnetic Field Sensor
diff --git a/MODULES.md b/MODULES.md
index 6058c385d..f82f7b465 100644
--- a/MODULES.md
+++ b/MODULES.md
@@ -94,4 +94,4 @@ Module | LCode | Description
06 TTGO Watch | x | TTGO Watch
07 M5Stack Core2 | x | M5Stack Core2
-Over 2400 additional devices are supported using [templates](TEMPLATES.md).
+Over 2500 additional devices are supported using [templates](TEMPLATES.md).
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 3bad9efce..8603e8aa5 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -33,9 +33,9 @@ While fallback or downgrading is common practice it was never supported due to S
This release will be supported from ESP8266/Arduino library Core version **2.7.4.9** due to reported security and stability issues on previous Core version. This will also support gzipped binaries.
-This release will be supported from ESP32/Arduino library Core version **2.0.5**.
+This release will be supported from ESP32/Arduino library Core version **2.0.5.3**.
-Support of ESP8266 Core versions before 2.7.4.9 and ESP32 Core versions before 2.0.5 have been removed.
+Support of ESP8266 Core versions before 2.7.4.9 and ESP32 Core versions before 2.0.5.3 have been removed.
## Support of TLS
@@ -72,12 +72,12 @@ Latest released binaries can be downloaded from
- http://ota.tasmota.com/tasmota/release
Historical binaries can be downloaded from
-- http://ota.tasmota.com/tasmota/release-12.2.0
+- http://ota.tasmota.com/tasmota/release-12.3.0
The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmota.com/tasmota/release/tasmota.bin.gz``
### ESP32, ESP32-C3, ESP32-S2 and ESP32-S3 based
-The following binary downloads have been compiled with ESP32/Arduino library core version **2.0.5**.
+The following binary downloads have been compiled with ESP32/Arduino library core version **2.0.5.3**.
- **tasmota32.bin** = The Tasmota version with most drivers including additional sensors and KNX for 4M+ flash. **RECOMMENDED RELEASE BINARY**
- **tasmota32xy.bin** = The Tasmota version with most drivers including additional sensors and KNX for ESP32-C3/S2/S3 and 4M+ flash.
@@ -97,7 +97,7 @@ Latest released binaries can be downloaded from
- http://ota.tasmota.com/tasmota32/release
Historical binaries can be downloaded from
-- http://ota.tasmota.com/tasmota32/release-12.2.0
+- http://ota.tasmota.com/tasmota32/release-12.3.0
The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmota.com/tasmota32/release/tasmota32.bin``
@@ -107,58 +107,65 @@ The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmo
[Complete list](BUILDS.md) of available feature and sensors.
-## Changelog v12.2.0 Patrick
+## Changelog v12.3.0 Percy
+
### Added
-- Command ``SetOption46 0..255`` to add 0..255 * 10 milliseconds power on delay before initializing I/O [#15438](https://github.com/arendst/Tasmota/issues/15438)
-- Command ``SetOption146 1`` to enable display of ESP32 internal temperature
-- Command ``DspSpeed 2..127`` to control message rotation speed on display of POWR3xxD and THR3xxD
-- Command ``DspLine<1|2> ,,,,...`` to select message(s) on display of POWR3xxD and THR3xxD
-- Command ``SspmPowerOnState 0|1|2`` to set Sonoff SPM 4Relay module v1.2.0 power on state overruling tasmota global power on state. 0 = Off, 1 = On, 2 = Saved state [#13447](https://github.com/arendst/Tasmota/issues/13447)
-- Command ``StatusRetain 0|1`` [#11109](https://github.com/arendst/Tasmota/issues/11109)
-- Command ``Sunrise 0..3`` to select sunrise dawn angle between Normal, Civil, Nautical or Astronomical [#16795](https://github.com/arendst/Tasmota/issues/16795)
-- Command ``UrlFetch `` to download a file to filesystem
-- Command ``WcClock 10..200`` set webcam clock in MHz. Default is 20
-- Support for Shelly Plus 2PM
-- Support for SGP40 gas and air quality sensor [#16341](https://github.com/arendst/Tasmota/issues/16341)
-- Support for Modbus writing using ModbusBridge by JeroenSt [#16351](https://github.com/arendst/Tasmota/issues/16351)
-- Support for DFRobot SEN0390 V30B ambient light sensor [#16105](https://github.com/arendst/Tasmota/issues/16105)
-- Support for QMC5883L magnetic induction sensor by Helge Scheunemann [#16714](https://github.com/arendst/Tasmota/issues/16714)
-- Support for Modbus Energy Monitoring devices using a rule file. See ``xnrg_29_modbus.ino`` for more information
-- Support for flowrate meter flow amount/duration, show values in table format [#16385](https://github.com/arendst/Tasmota/issues/16385)
-- Support of optional file calib.dat on ADE7953 based energy monitors like Shelly EM [#16486](https://github.com/arendst/Tasmota/issues/16486)
-- Zigbee device plugin mechanism with commands ``ZbLoad``, ``ZbUnload`` and ``ZbLoadDump`` [#16252](https://github.com/arendst/Tasmota/issues/16252)
-- Zigbee basic support for Green Power [#16407](https://github.com/arendst/Tasmota/issues/16407)
-- Zigbee friendly names per endpoint
-- Zigbee Alexa/Hue emulation, support multiple switches on separate endpoints [#16718](https://github.com/arendst/Tasmota/issues/16718)
-- Support for Ethernet in ESP32 safeboot firmware [#16388](https://github.com/arendst/Tasmota/issues/16388)
-- ESP32-S3 support for internal temperature sensor
-- ESP32-S2 and ESP32-S3 touch button support
-- ESP32 Automatically resize FS to max flash size at initial boot [#16838](https://github.com/arendst/Tasmota/issues/16838)
-- Berry has persistent MQTT subscriptions: auto-subscribe at (re)connection
-- Berry automated solidification of code
-- LVGL/HASPmota add tiny "pixel perfect" fonts for small screens [#16758](https://github.com/arendst/Tasmota/issues/16758)
-- HASPmota support for TTF fonts [#16759](https://github.com/arendst/Tasmota/issues/16759)
+- Command ``SetOption35 0..255`` to skip number of received messages in Serial Bridge (default 0) [#17140](https://github.com/arendst/Tasmota/issues/17140)
+- Command ``SetOption47 1..255`` to delay power on relay state in seconds reducing power surge. ``SO47 1`` delays until network connected. ``SO47 2`` delays until mqtt connected
+- Command ``RgxClients`` for range extender clients list [#17048](https://github.com/arendst/Tasmota/issues/17048)
+- Command ``RgxPort [tcp|udp], gateway_port, client_mac, client_port`` for range extender port forwardings [#17092](https://github.com/arendst/Tasmota/issues/17092)
+- Command ``SSerialBuffer 256..SERIAL_BRIDGE_BUFFER_SIZE`` to change serial bridge rx buffer size [#17120](https://github.com/arendst/Tasmota/issues/17120)
+- Command ``SwitchMode 16`` sending only MQTT message on inverted switch change [#17028](https://github.com/arendst/Tasmota/issues/17028)
+- Command NeoPool ``NPFiltration 2`` toggle [#16859](https://github.com/arendst/Tasmota/issues/16859)
+- Optional define ``SERIAL_BRIDGE_BUFFER_SIZE`` to set Serial Bridge internal buffer size (Default ESP8266 = 256, ESP32 = 800)
+- Support for two phase power calibration using commands ``PowerSet2``, ``VoltageSet2`` and ``CurrentSet2``
+- Support for HLK-LD2410 24GHz smart wave motion sensor
+- Support for Shelly Pro 1/1PM and 2/2PM [#16773](https://github.com/arendst/Tasmota/issues/16773)
+- Support for up to four DS18x20 GPIOs by md5sum-as [#16833](https://github.com/arendst/Tasmota/issues/16833)
+- Support for Digital Addressable Lighting Interface (DALI) by Andrei Kazmirtsuk [#16938](https://github.com/arendst/Tasmota/issues/16938)
+- Support for NTAG2xx tags read and write on PN532 NFC reader [#16939](https://github.com/arendst/Tasmota/issues/16939)
+- Support for Plantower PMSx003T AQI models with temperature and humidity [#16971](https://github.com/arendst/Tasmota/issues/16971)
+- Support for BP1658CJ RGBCW led bulbs like Orein OS0100411267 by Cossid [#17011](https://github.com/arendst/Tasmota/issues/17011)
+- Support for Dingtian x595 shift register based relay boards by Barbudor [#17032](https://github.com/arendst/Tasmota/issues/17032)
+- Support for HMC5883L 3-Axis Digital Compass sensor by Andreas Achtzehn [#17069](https://github.com/arendst/Tasmota/issues/17069)
+- WS2812 and Light ArtNet DMX control over UDP port 6454 [#17059](https://github.com/arendst/Tasmota/issues/17059)
+- Teleinfo TEMPO (BBR) contract [#17160](https://github.com/arendst/Tasmota/issues/17160)
+- Serial Modbus transmit enable GPIOs to all modbus energy drivers and modbus bridge [#17247](https://github.com/arendst/Tasmota/issues/17247)
+- Berry ``bytes().setbytes()`` method [#16892](https://github.com/arendst/Tasmota/issues/16892)
+- Berry ``bytes().reverse()`` method [#16977](https://github.com/arendst/Tasmota/issues/16977)
+- Berry ``mdns`` module [#17202](https://github.com/arendst/Tasmota/issues/17202)
+- Zigbee router firmware for Sonoff ZBBridgePro [#16900](https://github.com/arendst/Tasmota/issues/16900)
+- ESP32 Support for DMX ArtNet Led matrix animations [#16984](https://github.com/arendst/Tasmota/issues/16984)
+- ESP32 DS18x20 parasitic power usage when defining W1_PARASITE_POWER [#17112](https://github.com/arendst/Tasmota/issues/17112)
+
+### Breaking Changed
+- Redesign distance sensors VL53LXX, TOF10120, HRXL and DYP to use cm instead of mm [#17021](https://github.com/arendst/Tasmota/issues/17021)
### Changed
-- IRremoteESP8266 library from v2.8.2 to v2.8.4
-- TasmotaModbus library from v3.5.0 to v3.6.0 [#16351](https://github.com/arendst/Tasmota/issues/16351)
-- ESP32 NimBLE library from v1.3.6 to v1.4.0
-- ESP32 LVGL library from v8.3.0 to v8.3.2
-- ESP32 Tasmota Core32 from 2.0.4.1 to 2.0.5
-- Command ``SerialBuffer`` raise max allowed buffer size to 2048 characters [#16374](https://github.com/arendst/Tasmota/issues/16374)
-- Increase serial console input buffer size from 520 to 800
-- Button debouncing V3 by adopting switch debounce code [#16339](https://github.com/arendst/Tasmota/issues/16339)
-- Thermostat max allowed temperature from 100 to 200C [#16363](https://github.com/arendst/Tasmota/issues/16363)
-- Shelly EM swap internal channels A and B to match P1 and P2 [#16486](https://github.com/arendst/Tasmota/issues/16486)
-- Shelly EM phase calibration set to 200 (from 0) [#16486](https://github.com/arendst/Tasmota/issues/16486)
-- Zigbee report unprocessed attributes
-- ESP32 Increase number of button GPIOs from 8 to 28 [#16518](https://github.com/arendst/Tasmota/issues/16518)
-- ESP32 Platformio one Platform for all Tasmota frameworks Core32 2.0.5 [#16644](https://github.com/arendst/Tasmota/issues/16644)
+- TasmotaSerial library from v3.5.0 to v3.6.0
+- ESP32 Framework (Core) from v2.0.5 to v2.0.5.3
+- ESP32 LVGL library from v8.3.2 to v8.3.3 (no functional change)
+- ESP32 NimBLE library from v1.4.0 to v1.4.1 [#16775](https://github.com/arendst/Tasmota/issues/16775)
+- Serial Bridge default internal serial rx buffer size from 64 to 256 [#17120](https://github.com/arendst/Tasmota/issues/17120)
+- DS18x20 ``DS18Alias`` to ``DS18Sens`` [#16833](https://github.com/arendst/Tasmota/issues/16833)
+- Compiling with reduced boards manifests in favour of Autoconfig [#16848](https://github.com/arendst/Tasmota/issues/16848)
+- ADE7953 monitoring from instant power to accumulated energy [#16941](https://github.com/arendst/Tasmota/issues/16941)
+- TuyaMcu rewrite by btsimonh [#17051](https://github.com/arendst/Tasmota/issues/17051)
+- WS2812 sends signal to only ``Pixels`` leds instead of sending to 512 leds [#17055](https://github.com/arendst/Tasmota/issues/17055)
+- AC PWM dimmer lineair power distribution [#17177](https://github.com/arendst/Tasmota/issues/17177)
+- Zigbee improved Aqara plug support and completed cluster 0x0702 [#17073](https://github.com/arendst/Tasmota/issues/17073)
+- Removed leading spaces on commands ``(S)SerialSend1 to 6`` but keep on duplicate commands ``(S)SerialSend11 to 16`` [#16723](https://github.com/arendst/Tasmota/issues/16723
### Fixed
-- RTC not detected when lights are present [#16242](https://github.com/arendst/Tasmota/issues/16242)
-- DNS lookup for .local domains [#16273](https://github.com/arendst/Tasmota/issues/16273)
-- Button response delay regression from v12.0.2.4 [#16319](https://github.com/arendst/Tasmota/issues/16319)
-- Lost module name in GUI regression from v12.0.2.4 - 20220803 [#16324](https://github.com/arendst/Tasmota/issues/16324)
-- Removed whitespace from JSON values with no decimals [#16365](https://github.com/arendst/Tasmota/issues/16365)
-- ESP32 touch button multi-press and hold detection [#16596](https://github.com/arendst/Tasmota/issues/16596)
+- TasmotaSerial ``read(buffer, size)`` regression from v9.3.0
+- Serial bridge default serial configuration from 5N1 to 8N1 regression from v10.1.0.3
+- BP5758D red channel corruption regression from v12.1.1.6 [#16850](https://github.com/arendst/Tasmota/issues/16850)
+- Deduplicate code and fix %timer n% rule regression from v12.2.0 [#16914](https://github.com/arendst/Tasmota/issues/16914)
+- Serial initialization for baudrate and config [#16970](https://github.com/arendst/Tasmota/issues/16970)
+- ModbusBridge buffer overflow [#16979](https://github.com/arendst/Tasmota/issues/16979)
+- ModbusBridge baudrates over 76500 baud [#17106](https://github.com/arendst/Tasmota/issues/17106)
+- SenseAir S8 module detection [#17033](https://github.com/arendst/Tasmota/issues/17033)
+- RCSwitch exception 0/6 on some protocols [#17285](https://github.com/arendst/Tasmota/issues/17285)
+
+### Removed
+- Define ``USE_PN532_DATA_RAW`` from NFC reader [#16939](https://github.com/arendst/Tasmota/issues/16939)
diff --git a/TEMPLATES.md b/TEMPLATES.md
index f5b23c7a6..7d2b90617 100644
--- a/TEMPLATES.md
+++ b/TEMPLATES.md
@@ -2,17 +2,13 @@
# Templates
-Find below the available templates as of October 2022. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates)
+Find below the available templates as of December 2022. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates)
-## Addressable LED
+## Adapter Board
```
-Athom 2812b {"NAME":"LS2812B-TAS","GPIO":[32,0,1376,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
-Athom High Power 16A {"NAME":"LS_4PIN_TAS","GPIO":[32,1376,0,0,0,0,0,0,224,0,0,0,0,0],"FLAG":0,"BASE":18,"CMND":"Rule1 on Power1#State do power2 2 endon|Rule1 1"}
-BlitzWolf IC Smart RGB Magic {"NAME":"BW-LT31","GPIO":[0,0,32,1376,0,0,0,0,0,1088,0,0,0,0],"FLAG":0,"BASE":18,"CMND":"SO37 24"}
-cod.m WLAN Pixel Controller v0.8 {"NAME":"cod.m Pixel Controller V0.8","GPIO":[0,0,0,0,0,544,0,0,0,0,0,32,1376,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1}
-ESP01 NeoPixel Ring {"NAME":"ESP-01S-RGB-LED-v1.0","GPIO":[1,1,1376,1,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
-IOTMCU {"NAME":"IOTMCU_ESP-12S-RGB-LED-v1","GPIO":[1,1,1,1,0,1376,0,0,1,1088,32,0,0,0],"FLAG":0,"BASE":18}
-SP501E WS2812B {"NAME":"SP501E","GPIO":[0,32,0,1376,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
+3DStar ESP-OpenTherm v1.1 {"NAME":"3DS_OpenTherm","GPIO":[0,0,0,0,0,0,0,0,4960,0,4928,0,0,0],"FLAG":0,"BASE":18}
+WifInfo - Teleinfo Server {"NAME":"WifInfo","GPIO":[1376,1,1,5152,640,608,1,1,1,1,1,1,1,1],"FLAG":0,"BASE":18}
+ZiGate-Ethernet {"NAME":"ZIGATE-ETH","GPIO":[1,1,1,1,1,1,0,0,1,0,1,1,3840,576,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0],"FLAG":0,"BASE":18,"CMND":"EthClockMode 3 | EthAddress 1"}
```
## Air Purifier
@@ -51,7 +47,7 @@ GL.iNet POE Ethernet {"NAME":"GL-S10 v1.0","GPIO":[32,0,0,0,0,0,0,0,321,
## CCT
```
AICase 800lm {"NAME":"AICase Smart L","GPIO":[0,0,0,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18}
-AiYaTo 12W {"NAME":"AiYaTo CW","GPIO":[0,0,0,0,416,0,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18}
+AiYaTo 12W {"NAME":"AiYaTo-CW","GPIO":[0,0,0,0,416,0,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18}
Ajax Online 380lm {"NAME":"AjaxOnline","GPIO":[32,0,0,0,0,416,0,0,417,0,0,0,0,0],"FLAG":0,"BASE":38}
Ajax Online 7W Vintage {"NAME":"AjaxOnline-7W","GPIO":[0,0,0,0,0,0,0,0,417,0,416,0,0,0],"FLAG":0,"BASE":18}
Anoopsyche 9W 800lm {"NAME":"Anoop-CW-WW","GPIO":[0,0,0,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18}
@@ -59,6 +55,7 @@ Arlec Smart 1350lm PAR38 {"NAME":"Arlec GLD302HA","GPIO":[0,0,0,0,0,0,0,0,41
Arlec Smart 9.5W 806lm {"NAME":"Arlec GLD110HA","GPIO":[0,0,0,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":48}
Arlec Smart 9.5W 806lm {"NAME":"Arlec CCT","GPIO":[0,0,0,0,0,416,0,0,0,449,0,0,0,0],"FLAG":0,"BASE":48}
Arlec Smart R80 9.5W 806lm {"NAME":"Arlec R80","GPIO":[0,0,0,0,0,416,0,0,0,449,0,0,0,0],"FLAG":0,"BASE":48}
+AZzardo Led Vintage {"NAME":"Azzardo AZ3210 LightBulb Vintage","GPIO":[0,0,0,0,0,0,0,0,417,0,416,0,0,0],"FLAG":0,"BASE":18}
BlitzWolf A70 9W 900lm {"NAME":"BW-LT29","GPIO":[0,0,0,0,0,0,0,0,0,449,0,416,0,0],"FLAG":0,"BASE":18}
BrilliantSmart 20696 9W 900lm {"NAME":"Brilliant20696","GPIO":[0,0,0,0,0,0,0,0,417,0,416,0,0,0],"FLAG":0,"BASE":18}
BrilliantSmart 20697 9W 900lm {"NAME":"Brilliant20696","GPIO":[0,0,0,0,0,0,0,0,417,0,416,0,0,0],"FLAG":0,"BASE":18}
@@ -128,6 +125,7 @@ Nedis G125 5.5W 350lm Twisted Filament {"NAME":"WIFILF10GDG125","GPIO":[0,0,0,0
Nedis PAR16 330lm {"NAME":"Nedis WIFILW30","GPIO":[0,0,0,0,0,416,0,0,417,0,0,0,0,0],"FLAG":0,"BASE":18}
Nedis PAR16 4,5W 380lm {"NAME":"Nedis WIFILW10WTGU10","GPIO":[0,0,0,0,0,416,0,0,417,0,0,0,0,0],"FLAG":0,"BASE":18}
Nedis PAR16 4.5W 330lm 110 {"NAME":"WIFILW30","GPIO":[0,0,0,0,0,416,0,0,417,0,0,0,0,0],"FLAG":0,"BASE":18}
+Nous P2 {"NAME":"NOUS-P2","GPIO":[0,0,0,0,0,416,0,0,417,0,0,0,0,0],"FLAG":0,"BASE":37}
Philips Zhirui Candle 250lm {"NAME":"Xiaomi Philips","GPIO":[0,0,0,0,0,0,0,0,417,0,0,416,0,0],"FLAG":0,"BASE":48}
Phillips Zhirui 450lm {"NAME":"Xiaomi Philips","GPIO":[0,0,0,0,0,0,0,0,417,0,0,416,0,0],"FLAG":0,"BASE":48}
Polux ST64 5.5W 470lm {"NAME":"basic","GPIO":[0,0,0,0,0,0,0,0,417,0,416,0,0,0],"FLAG":0,"BASE":18}
@@ -141,7 +139,9 @@ Spectrum Smart 5W 410lm Candle {"NAME":"lightbulb","GPIO":[0,0,0,0,0,0,0,0,417,
Status 9W 806lm {"NAME":"Status Smart","GPIO":[0,0,0,0,0,0,0,0,417,0,416,0,0,0],"FLAG":0,"BASE":18}
Sulion Dante G100 10W 1055lm {"NAME":"Sulion Bombilla G100","GPIO":[0,0,0,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18}
Sulion Edisson Filament ST64 8W 600lm {"NAME":"Sulion Bombilla ST64","GPIO":[0,0,0,0,0,0,0,0,417,0,416,0,0,0],"FLAG":0,"BASE":18}
+Sulion Morgan C37 5W 470lm {"NAME":"Sulion Bombilla C37","GPIO":[0,0,0,0,0,0,0,0,417,0,416,0,0,0],"FLAG":0,"BASE":18}
Swisstone 806lm {"NAME":"SwisstoneSH330","GPIO":[0,0,0,0,2912,416,0,0,417,2976,2944,0,0,0],"FLAG":0,"BASE":18}
+Swisstone SH 310 {"NAME":"Swisstone SH 310","GPIO":[0,0,0,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18}
Treatlife A19 9W 800lm {"NAME":"Treatlife SL20","GPIO":[0,0,0,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18}
V-Tac PAR16 4.5W 300lm 110 {"NAME":"V-TAC VT-5174","GPIO":[0,0,0,0,0,0,0,0,417,0,416,0,0,0],"FLAG":0,"BASE":18}
Vestaiot BR30 800lm {"NAME":"Vesta BR30 CCT","GPIO":[0,0,0,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18}
@@ -171,7 +171,10 @@ Fcmila 48W RGBCCT {"NAME":"XDD-48W","GPIO":[0,0,0,0,416,419,0,0,417,4
Globe Electric Brushed Nickel 11" Flush Mount {"NAME":"Globe 60839","GPIO":[0,0,0,0,0,0,0,0,4064,0,4032,0,0,0],"FLAG":0,"BASE":18}
Hama Glitter Effect, 27cm Square {"NAME":"Hama LED Ceiling Light","GPIO":[0,0,0,0,0,416,0,0,0,417,0,0,0,1],"FLAG":0,"BASE":18}
HeyLight Plafoniera 30W CCT {"NAME":"HeyLight Ceiling Light","GPIO":[0,0,0,0,0,0,0,0,417,0,416,0,0,0],"FLAG":0,"BASE":18}
+Hykolity 13" RGBCCT Flush Mount {"NAME":"Hykolity","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
+Lamptan 3 Lights in 1 36W {"NAME":"Lamptan Smart Wi-Fi Ceiling Lamp LUMINA 36W","GPIO":[0,0,0,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":54}
LE lampUX 15W RGBCCT {"NAME":"LE lampUX 15W","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
+LightZone MeLiTec {"NAME":"LightZone MeLiTec D114 Light ","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 11,20 | TuyaMCU 21,22 | TuyaMCU 23,23 | DimmerRange 25,1000"}
Lohas ZN026CL10 RGBCCT {"NAME":"Lohas LED Lamp","GPIO":[0,0,0,0,417,416,0,0,419,418,420,0,0,0],"FLAG":0,"BASE":18}
LOLAsmart Uranus White 70 cm {"NAME":"lola smart","GPIO":[0,0,0,1088,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
LSC 20W 1400lm White Ambiance {"NAME":"LSC RGBCW LED","GPIO":[0,0,0,0,0,0,0,0,4064,0,4032,0,0,0],"FLAG":0,"BASE":18}
@@ -248,6 +251,10 @@ Hoch Circuit Breaker 1P {"NAME":"HOCH ZJSB9","GPIO":[32,0,0,0,0,0,0,0,224,3
Ketotek Single Phase Energy Monitor {"NAME":"Ketotek KTEM06","GPIO":[0,2272,0,2304,0,0,0,0,0,0,320,0,32,0],"FLAG":0,"BASE":54}
OpenEnergyMonitor WiFi MQTT Thermostat {"NAME":"MQTT-RELAY","GPIO":[32,0,1,0,0,224,0,0,0,0,0,0,320,0],"FLAG":0,"BASE":18}
RocketController ASTRA Controller {"NAME":"ASTRA R4A4","GPIO":[1,1,1,1,576,1,1,1,480,1,1,1,3232,3200,1,1,0,640,608,1,0,224,225,1152,0,0,0,0,227,226,160,161,162,0,0,163],"FLAG":0,"BASE":1}
+Shelly Pro 1 {"NAME":"Shelly Pro 1","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"}
+Shelly Pro 1PM {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"}
+Shelly Pro 2 {"NAME":"Shelly Pro 2","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350 | AdcParam2 2,10000,10000,3350"}
+Shelly Pro 2PM {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350 | AdcParam2 2,10000,10000,3350"}
Sinotimer {"NAME":"TM608","GPIO":[32,0,0,0,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":18}
Sinotimer {"NAME":"Sinotimer TM60","GPIO":[0,0,0,0,0,288,0,0,224,160,0,0,0,0],"FLAG":0,"BASE":18}
SMTONOFF 63A {"NAME":"SMTONOFF","GPIO":[32,0,0,3104,0,0,0,0,224,544,0,0,0,0],"FLAG":0,"BASE":43}
@@ -262,6 +269,7 @@ Tongou 2P 63A Circuit Breaker {"NAME":"RCD_CONTACTOR","GPIO":[32,224,0,0,0,0,0,
## Dehumidifier
```
+Duux Bora {"NAME":"Duux Bora","GPIO":[0,0,0,0,0,0,0,0,0,2304,0,2272,0,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 11,1 | TuyaMCU 73,3 | TuyaMCU 74,4 | TuyaMCU 12,5 | TuyaMCU 13,7 | TuyaMCU 81,13 | TuyaMCU 14,101 | HumRes 0"}
electriQ 12L Portable {"NAME":"electriQ CD12PW","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
Vacplus 50 Pint {"NAME":"VacPlus Dehumidifier","GPIO":[0,0,0,0,0,0,0,0,0,2304,0,2272,0,0],"FLAG":0,"BASE":54}
```
@@ -274,7 +282,8 @@ Adafruit HUZZAH32 ESP32 Feather {"NAME":"HUZZAH32","GPIO":[0,0,0,0,4709,0,1,1,1
Adafruit QT Py ESP32 Pico {"NAME":"QTPy ESP32 Pico","GPIO":[32,3200,0,3232,1,1376,0,0,1,1,1,1,0,0,0,608,0,0,640,0,0,1,1,1,0,1,3840,0,1,1,0,0,0,0,0,0],"FLAG":0,"BASE":1}
AZ-Envy Environmental Sensor {"NAME":"AZ Envy","GPIO":[32,0,320,0,640,608,0,0,0,0,0,0,0,4704],"FLAG":0,"BASE":18}
Coiaca Tasmota {"NAME":"AWR01t","GPIO":[576,1,1,128,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
-ESP32 Lite V1.0.0 {"NAME":"ESP32 Lite V1.0.0","GPIO":[1,0,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0],"FLAG":0,"BASE":1}
+Coiaca Tasmota Development Board AWR12 {"NAME":"AWR12t","GPIO":[320,1,1,1,1,1,0,0,1,1,1,1,1,1],"FLAG":0,"BASE":18}
+Espoir Rev 1.0.0 PoE+ {"NAME":"Espoir","GPIO":[0,0,1,0,1,1,1,1,1,1,1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,5568,5600,1,7968,1,1,1,1],"FLAG":0,"BASE":1}
LC Technology MicroPython Maker {"NAME":"LC-ESP-Python","GPIO":[1,1,544,1,1,1,1,1,1,1,1,1,1,1],"FLAG":0,"BASE":18}
LilyGO RGB LED Ring Encoder {"NAME":"T-Encoder","GPIO":[0,0,1,0,1,0,0,0,1,1,1,1,0,0,0,480,6212,0,0,0,0,449,450,448,0,0,0,0,0,0,0,0,3296,3264,32,0],"FLAG":0,"BASE":1,"CMND":"BuzzerPwm 1"}
LilyGO T7 v1.5 {"NAME":"LilyGO T7 V1.5","GPIO":[1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,544,0,0,0,1,0,1,1,1,0,0,0,0,0,1,1,4704,1,0,0,1],"FLAG":0,"BASE":1}
@@ -286,11 +295,11 @@ Olimex ESP32-POE Ethernet {"NAME":"Olimex ESP32-PoE","GPIO":[1,1,1,1,1,1,0,0,
QuinLED 2 Channel {"NAME":"QuinLED 2 channel","GPIO":[416,0,417,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
Silicognition wESP32 {"NAME":"wESP32","GPIO":[0,0,1,0,1,1,0,0,1,1,1,1,5568,5600,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1}
TZT ESP8266 Weather Station Kit {"NAME":"TZT Weather Station","GPIO":[32,0,640,0,1,1184,0,0,1,1,608,1,1,1],"FLAG":0,"BASE":18}
-WifInfo - Teleinfo Server {"NAME":"WifInfo","GPIO":[1376,1,1,5152,640,608,1,1,1,1,1,1,1,1],"FLAG":0,"BASE":18}
+Wemos D1 Mini ESP32 {"NAME":"Wemos D1 Mini ESP32","GPIO":[0,0,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0],"FLAG":0,"BASE":1}
+Wemos LOLIN32 Lite V1.0.0 (ESP32) {"NAME":"Wemos LOLIN32 Lite V1.0.0","GPIO":[1,0,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0],"FLAG":0,"BASE":1}
Wireless Tag ESP32 Ethernet {"NAME":"WT32-ETH01","GPIO":[1,1,1,1,1,1,0,0,1,0,1,1,3840,576,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0,1],"FLAG":0,"BASE":1}
Witty Cloud {"NAME":"Witty Cloud","GPIO":[1,1,320,1,32,1,0,0,417,418,1,416,1,4704],"FLAG":0,"BASE":32}
Yison ESP-01/ESP-202 {"NAME":"Yison Dev Board","GPIO":[259,544,258,1,260,261,1,1,416,418,257,417,256,1],"FLAG":0,"BASE":18}
-ZiGate-Ethernet {"NAME":"ZIGATE-ETH","GPIO":[1,1,1,1,1,1,0,0,1,0,1,1,3840,576,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,0,1,1,0,1,1,0,0],"FLAG":0,"BASE":18,"CMND":"EthClockMode 3 | EthAddress 1"}
```
## Dimmable
@@ -391,12 +400,13 @@ Globe 3 Way {"NAME":"Globe Dimmer","GPIO":[0,2272,0,2304,0,0,0,
Gosund SW2 {"NAME":"Gosund Dimmer","GPIO":[1,3200,1,3232,32,0,1,1,320,576,416,1,1,0],"FLAG":0,"BASE":18}
iLintek / Lumary {"NAME":"L-DS100","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
iSwitch Touch Switch {"NAME":"iSwitchOZ Dimmer","GPIO":[0,0,0,0,0,0,0,0,0,0,290,0,0,0],"FLAG":0,"BASE":54}
-Martin Jerry SD01 {"NAME":"MJ-SD01 Dimmer","GPIO":[34,33,0,323,576,322,0,0,321,416,320,96,256],"FLAG":0,"BASE":73}
-Martin Jerry Single Pole {"NAME":"SD01 Dimmer","GPIO":[34,33,0,323,576,322,0,0,321,416,320,96,256],"FLAG":0,"BASE":73}
+Martin Jerry SD01 {"NAME":"MJ-SD01 Dimmer","GPIO":[34,33,0,323,576,322,0,0,321,416,320,96,256,0],"FLAG":0,"BASE":73}
+Martin Jerry Single Pole {"NAME":"SD01 Dimmer","GPIO":[34,33,0,323,576,322,0,0,321,416,320,96,256,0],"FLAG":0,"BASE":73}
Martin Jerry Single Pole {"NAME":"MJ-KN01 Dimmer","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
Maxcio Rotary {"NAME":"EDM-1WAA-EU","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
Minoston 3-Way {"NAME":"MS10W","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
Moes {"NAME":"MOES DS01","GPIO":[1,1,1,1,1,1,0,0,1,2304,1,2272,1,0],"FLAG":0,"BASE":54}
+Moes 3 Way Smart Light {"NAME":"EDM-1WAA-US","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
PS-16-DZ {"NAME":"PS-16-DZ","GPIO":[1,3200,1,3232,1,1,0,0,1,288,1,1,1,0],"FLAG":0,"BASE":58}
Stitch {"NAME":"Stitch 35558","GPIO":[0,0,0,0,0,0,0,0,0,2304,0,2272,0,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 21,3|DimmerRange 21,255"}
Teekar UIW001-1 {"NAME":"Teekar UIW001-","GPIO":[0,3232,416,3200,640,608,0,0,160,0,0,0,0,0],"FLAG":0,"BASE":18}
@@ -422,7 +432,7 @@ BrilliantSmart Jupiter {"NAME":"BrSm Jupiter","GPIO":[0,2272,0,2304,0,0,0,
EX-Store 2 Kanal RS232 V4 {"NAME":"EXS Dimmer","GPIO":[0,3200,0,3232,0,0,0,0,0,4128,0,0,0,0],"FLAG":0,"BASE":72}
Moes 2 Gang {"NAME":"WM-105","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 11,1 | TuyaMCU 21,2 | TuyaMCU 12,7 | TuyaMCU 22,8 | DimmerRange 0,1003"}
Moes MS-105-1 v2 {"NAME":"MS-105","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
-QS-WiFi-D01-TRIAC 150W {"NAME":"QS-WiFi-D01-TRIAC","GPIO":[0,3200,0,3232,0,0,0,0,0,352,416,0,0],"FLAG":0,"BASE":18}
+QS-WiFi-D01-TRIAC 150W {"NAME":"QS-WiFi-D01-TRIAC","GPIO":[0,3200,0,3232,0,0,0,0,0,352,416,0,0,0],"FLAG":0,"BASE":18}
RJWF-02A {"NAME":"RJWF-02A","GPIO":[32,2272,0,2304,0,0,0,0,0,0,288,0,0,0],"FLAG":0,"BASE":54}
Shelly Dimmer {"NAME":"Shelly Dimmer 1","GPIO":[0,3200,0,3232,5568,5600,0,0,192,0,193,288,0,4736],"FLAG":0,"BASE":18}
Shelly Dimmer 2 {"NAME":"Shelly Dimmer 2","GPIO":[0,3200,0,3232,5568,5600,0,0,193,0,192,0,320,4736],"FLAG":0,"BASE":18}
@@ -453,7 +463,7 @@ Wireless Tag 3.5" Touch {"NAME":"WT32-SC01","GPIO":[6210,1,1,1,1,1,0,0,1,70
## Display Switch
```
Lanbon L8 5 in 1 LCD Touch {"NAME":"Lanbon L8","GPIO":[0,0,0,0,0,992,0,0,224,0,225,0,0,0,1024,896,0,6624,6592,864,0,832,416,226,0,0,0,0,417,418,0,352,0,0,0,4736],"FLAG":0,"BASE":1}
-Sonoff NSPanel Touch {"NAME":"NSPanel","GPIO":[0,0,0,0,3872,0,0,0,0,0,32,0,0,0,0,225,0,480,224,1,0,0,0,33,0,0,0,0,0,0,0,0,0,0,4736,0],"FLAG":0,"BASE":1,"CMND":"ADCParam 2,11200,10000,3950 | Sleep 0 | BuzzerPWM 1"}
+Sonoff NSPanel Touch {"NAME":"NSPanel","GPIO":[0,0,0,0,3872,0,0,0,0,0,32,0,0,0,0,225,0,480,224,1,0,0,0,33,0,0,0,0,0,0,0,0,0,0,4736,0],"FLAG":0,"BASE":1,"CMND":"ADCParam1 2,11200,10000,3950 | Sleep 0 | BuzzerPWM 1"}
```
## Downlight
@@ -538,6 +548,7 @@ Sonoff iFan04-L 110V Light and Ceiling {"NAME":"iFan04-L","GPIO":[32,3200,0,323
Avatto Light and {"NAME":"AVATTO SYS-FL01","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
Deta Light and {"NAME":"Deta Fan Speed and Light Controller","GPIO":[33,0,0,576,226,34,0,0,0,225,224,227,32,0],"FLAG":0,"BASE":18}
iSwitch Light and {"NAME":"iSwitchOZ Light Fan","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
+Martin Jerry Fan Controller {"NAME":"US-FC-01","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
Treatlife 1.5A 4 Speed Ceiling {"NAME":"DS02F","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 11,1|SO97 1|SO68 0"}
```
@@ -564,12 +575,14 @@ SmartMi Electric Air {"NAME":"ZNNFJ07ZM","GPIO":[0,0,0,0,0,0,0,0,0,0,0,0
## Humidifier
```
-Duux Beam {"NAME":"Duux Beam","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 11,1 | TuyaMCU 12,5 | TuyaMCU 13,21 | TuyaMCU 71,14 | TuyaMCU 74,15 | TuyaMCU 73,16"}
+Duux Beam Ultrasonic {"NAME":"Duux Beam","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 11,1 | TuyaMCU 12,5 | TuyaMCU 13,21 | TuyaMCU 71,14 | TuyaMCU 74,15 | TuyaMCU 73,16"}
Proscenic {"NAME":"Generic","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
```
## IR Controller
```
+3DStar ESP IR Blaster 8L {"NAME":"3DS_IRblaster_xL","GPIO":[0,0,0,0,0,0,0,0,0,0,0,1056,0,0],"FLAG":0,"BASE":18}
+3DStar ESP IR Blaster xLR {"NAME":"3DS_IR Blaster_xLR","GPIO":[0,0,0,0,0,0,0,0,0,1088,0,1056,0,0],"FLAG":0,"BASE":18}
A1 Universal Remote Control {"NAME":"A1 IR Controller","GPIO":[1,1,1,1,320,1088,0,0,0,32,1056,0,0,0],"FLAG":0,"BASE":62}
AI Universal Remote {"NAME":"YTF IR Controller","GPIO":[1,1,1,1,320,1088,0,0,0,32,1056,0,0,0],"FLAG":0,"BASE":62}
Alfawise KS1 {"NAME":"KS1","GPIO":[1,1792,32,1824,32,1088,0,0,320,0,1056,0,0,4704],"FLAG":0,"BASE":62}
@@ -598,6 +611,7 @@ Orvibo Magic Cube {"NAME":"Orvibo CT10W","GPIO":[0,0,0,0,32,1088,0,0,
Phlipton Universal Remote {"NAME":"Phliptron IR","GPIO":[1,3200,1,3232,576,1088,0,0,320,32,1056,0,0,0],"FLAG":0,"BASE":62}
Remote Control {"NAME":"DC-QRA2","GPIO":[0,0,0,0,320,1088,0,0,0,32,1056,0,0,0],"FLAG":0,"BASE":62}
RM mini {"NAME":"RM mini","GPIO":[1,1,1,1,320,1088,0,0,0,32,1056,0,0,0],"FLAG":0,"BASE":62}
+Smart Remote {"NAME":"IRC","GPIO":[0,0,544,0,0,288,0,0,1088,32,1056,0,0,0],"FLAG":0,"BASE":18}
Smartpoint Smart Remote {"NAME":"Smartpoint SPCNTRL-WM","GPIO":[0,0,0,0,288,1088,0,0,0,0,1056,0,0,0],"FLAG":0,"BASE":18}
STITCH {"NAME":"Stitch 35753","GPIO":[0,0,0,0,288,1088,0,0,0,64,1056,0,0,0],"FLAG":0,"BASE":62}
SZMDLX IR Remote Controller {"NAME":"SZMDLX WiFi IR","GPIO":[0,0,0,0,320,1088,0,0,0,32,1056,0,0,0],"FLAG":0,"BASE":62}
@@ -640,6 +654,7 @@ DD001-MINI(G)-IR-V03 {"NAME":"WIFI-RGB","GPIO":[32,0,0,0,0,0,0,0,417,418
DD001-MINI(G)-IR-V08 {"NAME":"WIFI-RGB","GPIO":[0,0,0,0,416,0,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18}
Electrodragon ESP LED Strip Board, Mosfet Drive {"NAME":"LEDBoard RGBW","GPIO":[0,0,0,0,0,0,0,0,418,417,419,416,288,0],"FLAG":0,"BASE":18}
H801 {"NAME":"H801","GPIO":[1,288,1,1,420,321,0,0,418,417,419,416,0,0],"FLAG":0,"BASE":20}
+Hama Adapter and RGB {"NAME":"HAMA LED-Strip WLAN-Controller","GPIO":[0,0,0,0,417,419,0,0,0,416,418,0,0,0],"FLAG":0,"BASE":18}
Holman Garden Light RGB {"NAME":"Holman RGB","GPIO":[0,0,0,0,0,0,0,0,417,416,418,0,0,0],"FLAG":0,"BASE":18}
Jinvoo SM-WA104 RGB {"NAME":"Jinvoo LED Controller","GPIO":[0,0,0,0,256,418,0,0,416,32,417,0,257,0],"FLAG":0,"BASE":18}
Konesky 12V RGB {"NAME":"RGBwifi","GPIO":[0,0,0,0,416,0,0,0,417,320,418,0,0,0],"FLAG":0,"BASE":18}
@@ -697,13 +712,14 @@ HitLights L1012V-MC1 {"NAME":"HitLights RBG","GPIO":[32,0,0,0,416,419,0,
HomeMate 10m RGB {"NAME":"Homemate Strip","GPIO":[0,0,0,0,0,416,0,0,418,32,417,0,0,0],"FLAG":0,"BASE":18}
Hykker 3m RGB {"NAME":"HYKKER Strip","GPIO":[0,0,0,0,0,416,0,0,418,32,417,0,0,0],"FLAG":0,"BASE":18}
INDARUN RGB String Lights {"NAME":"STAR301","GPIO":[0,0,0,0,1088,416,0,0,417,418,0,0,0,0],"FLAG":0,"BASE":34}
-Kogan RGB + Cool & Warm White 2m {"NAME":"RGB+W+C Strip","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
+Kogan RGB + Cool & Warm White 2m {"NAME":"RGB+W+C Strip","GPIO":[32,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
LE LampUX 16.4ft RGB {"NAME":"LampUX","GPIO":[0,33,32,0,0,417,0,0,418,1088,0,416,0,0],"FLAG":0,"BASE":18}
LE LampUX 2m RGB TV Backlight {"NAME":"LE 904102","GPIO":[0,32,33,0,0,417,0,0,418,34,0,416,0,0],"FLAG":0,"BASE":18}
LE LampUX 5m RGB {"NAME":"LampUX","GPIO":[32,0,0,0,0,417,0,0,418,0,0,416,0,0],"FLAG":0,"BASE":18}
LE LampUX 5m RGB {"NAME":"LE LampUx","GPIO":[0,0,0,0,0,417,0,0,418,0,0,416,0,0],"FLAG":0,"BASE":34}
LE lampUX 5m RGBW {"NAME":"LampUX","GPIO":[0,0,0,0,416,419,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18}
Lednify WiZ Connected 5m RGB+W {"NAME":"Lednify 429336","GPIO":[0,0,420,0,419,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,416,417,418,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1}
+Lenovo 2m RGB {"NAME":"Lenovo LED Strip 2m","GPIO":[32,0,0,0,416,0,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18}
Lenovo 5m RGBW {"NAME":"Lenovo LED Strip 5m","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
LePower 32.8ft RGB {"NAME":"LePower","GPIO":[0,0,0,0,0,417,0,0,418,0,0,416,0,0],"FLAG":0,"BASE":18}
Lohas ZN022 5m RGBW {"NAME":"LOHAS M5-022","GPIO":[0,0,0,0,417,416,0,0,32,418,0,0,0,0],"FLAG":0,"BASE":18}
@@ -712,6 +728,7 @@ Lumary RGBCCT {"NAME":"Lumary LED","GPIO":[32,0,0,0,416,419,0,0,4
Lumary RGBCCT {"NAME":"Lumary LED","GPIO":[32,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
Maxonar Lightstrip Pro XS-SLD001 {"NAME":"Maxonar LED","GPIO":[0,0,0,0,0,416,0,0,418,32,417,0,0,0],"FLAG":0,"BASE":18}
MegaLight Smart RGB {"NAME":"MegaLight Smart LED-Stripe","GPIO":[0,0,0,0,417,1088,0,0,418,416,0,0,32,0],"FLAG":0,"BASE":18}
+Merkury 6-1/2 ft {"NAME":"Mercury RGBWWCW String","GPIO":[32,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
Merkury Innovations MI-EW003-999W {"NAME":"MI-EW003-999W ","GPIO":[32,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
Mirabella Genio RGB+CW {"NAME":"MirabellaStrip","GPIO":[32,0,0,0,416,419,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18}
Monster Smart IlluminEssence {"NAME":"MI-EW003-999W ","GPIO":[32,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
@@ -781,7 +798,7 @@ Sonoff {"NAME":"Sonoff BN-SZ","GPIO":[0,0,0,0,0,0,0,0,416,
Spotlight 9cm RGB+W 7W {"NAME":"Spotlight RGBW","GPIO":[0,0,0,0,0,0,0,0,0,3008,0,3040,0,0],"FLAG":0,"BASE":27}
TCP WPAN Square 600X600mm 36W CCT Panel {"NAME":"TCPsmart LED Panel","GPIO":[0,0,0,0,0,416,0,0,0,449,0,0,0,0],"FLAG":0,"BASE":18,"CMND":"SO92 1|DimmerRange 30,100"}
Teckin FL41 {"NAME":"Teckin FL41","GPIO":[0,0,0,0,0,32,0,0,0,0,416,0,0,0],"FLAG":0,"BASE":18}
-Wipro 20W LED RGB Batten {"NAME":"Wipro RGBW Tubelight","GPIO":[0,0,0,0,416,420,0,0,417,419,418,0,0,1],"FLAG":0,"BASE":18}
+Wipro 20W LED RGB Batten {"NAME":"Wipro RGBW Tubelight","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,1],"FLAG":0,"BASE":18}
Wipro Next Smart Batten 20W CCT {"NAME":"WIPROBatten","GPIO":[0,0,0,0,0,416,0,0,0,449,0,0,0,0],"FLAG":0,"BASE":18}
Xiaomi Mi Computer Monitor Light Bar 1S {"NAME":"Mijia Desk Lamp 1S (MJGJD02YL)","GPIO":[0,0,0,0,3840,0,1,1,0,0,0,0,0,0,0,416,0,417,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1,"CMND":"DimmerRange 45,255"}
Xiaomi Mi Desk Lamp Pro {"NAME":"Mi Desk Lamp Pro","GPIO":[6212,0,416,0,417,0,0,0,3840,0,0,0,160,640,608,0,0,0,0,0,0,0,3296,3264,0,0,0,0,0,32,0,0,0,0,0,0],"FLAG":0,"BASE":1,"CMND":"DimmerRange 30,100"}
@@ -809,6 +826,7 @@ Liectroux C30B Robot Vacuum {"NAME":"Liectroux C30B","GPIO":[1,1,1,1,1,1,0,0,1,
Mosquito Killer Lamp {"NAME":"MosquitoKiller","GPIO":[32,0,0,0,0,0,0,0,416,320,0,0,0,0],"FLAG":0,"BASE":18}
NEO Coolcam Mouse Trap {"NAME":"Neo Mouse Trap","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
PCI-e Desktop PC Remote Control {"NAME":"PC-Switch-01","GPIO":[32,0,0,0,0,0,0,0,224,544,0,0,0,0],"FLAG":0,"BASE":18}
+Petoneer Smart Dot Cat Toy {"NAME":"Petoneer Smart Dot","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
Proscenic T21 Air Fryer {"NAME":"Proscenic T21","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
RainPoint Indoor Water Pump {"NAME":"RainPoint","GPIO":[0,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 81,107|TuyaMCU 12,109|TuyaMCU 11,1|TuyaMCU 82,104"}
Sinilink PCIe Computer Remote {"NAME":"XY-WPCE","GPIO":[1,1,320,1,32,224,0,0,160,0,0,0,0,0],"FLAG":0,"BASE":18,"CMND":"SO114 1 | SwitchMode1 2"}
@@ -835,6 +853,11 @@ Sinilink MODBUS Interface {"NAME":"XY-WFPOW","GPIO":[0,8768,544,8800,32,0,0,0
TYWE2S Replacement {"NAME":"ESP-02S","GPIO":[1,1,1,1,1,1,0,0,1,1,1,0,0,1],"FLAG":0,"BASE":18}
```
+## Module Switch
+```
+Moes Mini 3 Gang 1/2 Way {"NAME":"Moes MS-104C","GPIO":[0,0,0,34,32,33,0,0,224,225,226,0,0,0],"FLAG":0,"BASE":18}
+```
+
## Motion Sensor
```
DP-WP001 PIR {"NAME":"TUYA PIR","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
@@ -847,7 +870,7 @@ Tuya Alarm PIR {"NAME":"CT61W","GPIO":[0,0,0,0,0,0,0,0,0,160,480,2
```
Steren Curtain {"NAME":"Steren_SHOME-155","GPIO":[0,0,0,0,0,0,0,0,0,2304,0,2272,0,0],"FLAG":0,"BASE":54,"CMND":"SO54 1|SO20 1|TuyaMCU 61,1|TuyaMCU 21,2|TuyaMCU 27,3|TuyaMCU 97,5|TuyaMCU 11,6|TuyaMCU 62,7|TuyaMCU 63,8|TuyaMCU 81,9|TuyaMCU 98,10|TuyaMCU 82,11"}
Zemismart BCM300D-TY {"NAME":"Zemistart_Curt","GPIO":[0,0,0,0,0,0,0,0,0,2304,0,2272,0,0],"FLAG":0,"BASE":54}
-Zemismart Blinds Controller {"NAME":"Zemismart Blind","GPIO":[1,1,1,1,1,1,0,0,1,2304,1,2272,1],"FLAG":0,"BASE":54}
+Zemismart Blinds Controller {"NAME":"Zemismart Blind","GPIO":[1,1,1,1,1,1,0,0,1,2304,1,2272,1,0],"FLAG":0,"BASE":54}
Zemismart Curtain {"NAME":"Zemismart_Curt","GPIO":[0,0,0,0,0,0,0,0,0,2304,0,2272,0,0],"FLAG":0,"BASE":54}
Zemismart Rechargeable Roller Shade {"NAME":"Zemismart Remote","GPIO":[544,0,288,33,225,32,0,0,34,226,289,224,290,0],"FLAG":0,"BASE":18}
Zemismart Roller Shade {"NAME":"M2805EIGB","GPIO":[1,2272,1,2304,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
@@ -936,6 +959,7 @@ Wyze {"NAME":"Wyze Plug Outdoor","GPIO":[0,0,0,0,0,576,0
## Plug
```
+16A {"NAME":"AWP16L","GPIO":[0,0,320,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":45}
1AC 2USB {"NAME":"BSD31","GPIO":[0,0,0,0,0,225,0,0,224,32,320,0,0,0],"FLAG":0,"BASE":18}
2nice {"NAME":"2NICE SP111","GPIO":[320,0,321,0,0,0,0,0,0,32,0,224,0,4736],"FLAG":0,"BASE":18}
3Stone Mini {"NAME":"3Stone Smart Plug","GPIO":[0,32,0,0,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18}
@@ -949,6 +973,7 @@ Aisirer AWP07L {"NAME":"AISIRER AWP07L","GPIO":[320,0,321,0,0,2688
Aisirer JH-G018 {"NAME":"AISIRER JH-G01","GPIO":[0,0,0,0,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
Aisirer SWA11 {"NAME":"SWA11","GPIO":[0,0,0,0,288,224,0,0,0,32,0,0,0,0],"FLAG":0,"BASE":18}
Aisirer UK-1 {"NAME":"AISIRER","GPIO":[0,32,0,0,0,0,0,0,0,288,224,0,0,4704],"FLAG":0,"BASE":18}
+AiYaTo 12W {"NAME":"AiYaTo-SWITCH","GPIO":[0,0,0,0,32,544,0,0,224,0,0,0,0,0],"FLAG":0,"BASE":18}
Alecto SMART-PLUG20 {"NAME":"Alecto SP20","GPIO":[0,0,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":18}
Alexfirst TV-ASP801EU {"NAME":"Alexfirst","GPIO":[32,0,0,0,290,320,0,0,224,0,0,0,0,0],"FLAG":0,"BASE":18}
Alfawise {"NAME":"PE1606","GPIO":[0,0,0,32,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18}
@@ -1026,7 +1051,7 @@ Bardi 16A {"NAME":"BARDI","GPIO":[320,0,0,0,0,2720,0,0,224,32
Bauhn ASPU-1019 {"NAME":"Bauhn Smart Pl","GPIO":[0,0,0,0,224,225,0,0,0,320,32,0,0,0],"FLAG":0,"BASE":18}
BAW {"NAME":"BAW TPSWIFI-10","GPIO":[0,0,0,0,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
Bawoo {"NAME":"Bawoo S120","GPIO":[0,0,0,0,288,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
-Be HiTech 16A {"NAME":"Be HiTech","GPIO":[0,0,0,288,0,2720,0,0,2624,32,2656,224,0],"FLAG":0,"BASE":18}
+Be HiTech 16A {"NAME":"Be HiTech","GPIO":[0,0,0,288,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18}
Bearware 303492 3AC+2USB {"NAME":"Bearware 30349","GPIO":[0,320,0,32,225,226,0,0,227,224,544,0,0,0],"FLAG":0,"BASE":18}
Bestek MRJ1011 {"NAME":"BestekMRJ1011","GPIO":[0,0,0,0,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":1}
BlitzWolf 1200W Dual {"NAME":"BlitzWolf SHP3","GPIO":[320,0,321,0,225,2720,0,0,2624,33,2656,224,32,0],"FLAG":0,"BASE":45}
@@ -1112,10 +1137,9 @@ ednet 84334 {"NAME":"84334","GPIO":[0,0,0,0,320,321,0,0,224,32,
eFamilyCloud ASDFEE174 {"NAME":"eFamily Plug","GPIO":[0,0,0,0,288,224,0,0,0,32,0,0,0,0],"FLAG":0,"BASE":18}
EFUN SH330W {"NAME":"EFUNPlug","GPIO":[320,1,1,1,1,1,1,1,1,32,1,224,1,1],"FLAG":0,"BASE":18}
EFUN SH331W {"NAME":"Efun-Plug","GPIO":[320,0,576,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18}
-Elehot 16A {"NAME":"ELEHOT AWP16L","GPIO":[0,0,320,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":45}
EleLight {"NAME":"EleLight PE1004T","GPIO":[0,0,0,0,288,289,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
EletecPro 2 {"NAME":"EletecPro-2","GPIO":[1,1,1,1,32,1,0,0,289,288,224,1,1,4704],"FLAG":0,"BASE":18}
-Emil Lux Wifi-Stecker IP20 {"NAME":"Emil Lux Wifi-Steckdose","GPIO":[0,0,0,0,321,0,0,0,224,320,32,0,0,0],"FLAG":0,"BASE":18}
+Emil Lux Wifi-Stecker IP20 {"NAME":"Obi CH Plug","GPIO":[0,0,0,0,320,0,0,0,224,576,32,0,0,0],"FLAG":0,"BASE":18}
Emporia {"NAME":"Emporia EMS01","GPIO":[0,0,0,289,224,2720,0,0,2624,32,2656,288,0,0],"FLAG":0,"BASE":18}
Emporia 15A {"NAME":"Emporia EMS02","GPIO":[320,0,321,0,224,2720,0,0,2624,32,2656,0,0,0],"FLAG":0,"BASE":18}
Ener-J {"NAME":"ENER-J SHA5264","GPIO":[32,0,0,0,2720,2656,0,0,2624,288,224,0,0,0],"FLAG":0,"BASE":18}
@@ -1195,10 +1219,10 @@ HBN 13A {"NAME":"BNC-50/E75T","GPIO":[0,0,0,0,576,320,0,0,2
HBN BNC-60/U152T {"NAME":"BNC-60/U152T","GPIO":[0,0,0,0,320,0,1,1,224,32,0,0,0,0],"FLAG":0,"BASE":18}
HerePow {"NAME":"HerePow ZHX-ZNOC","GPIO":[0,544,0,2624,2720,2656,0,0,224,32,320,0,0,0],"FLAG":0,"BASE":68}
Heygo 02 {"NAME":"Heygo 02","GPIO":[0,0,0,0,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
-HiHome WPP-10S1 {"NAME":"HIhome WPP-10S","GPIO":[320,0,576,1,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":49}
-HiHome WPP-10S2 {"NAME":"HiHome WPP-10S","GPIO":[32,0,0,0,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":49}
-HiHome WPP-16S {"NAME":"HIhome WPP-16S","GPIO":[32,0,0,0,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":49}
-HiHome WPP-16T {"NAME":"HiHome WPP-16T","GPIO":[32,320,1,1,2720,2656,0,0,33,1,225,2592,224,4704],"FLAG":0,"BASE":18}
+HiHome {"NAME":"HIhome WPP-16S","GPIO":[32,0,0,0,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":49}
+HiHome {"NAME":"HiHome WPP-10S","GPIO":[32,0,0,0,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":49}
+HiHome {"NAME":"HIhome WPP-10S","GPIO":[320,0,576,1,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":49}
+HiHome {"NAME":"HiHome WPP-16T","GPIO":[32,320,1,1,2720,2656,0,0,33,1,225,2592,224,4704],"FLAG":0,"BASE":18}
HIPER IoT P01 {"NAME":"HIPER IoT P01","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
hiwild W-US002 {"NAME":"W-US002","GPIO":[0,32,0,0,0,0,0,0,0,288,224,0,576,0],"FLAG":0,"BASE":18}
HLT-309 {"NAME":"HLT-309","GPIO":[0,0,0,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18}
@@ -1273,7 +1297,7 @@ Ledvance Smart+ {"NAME":"Ledvance Plug","GPIO":[0,0,0,320,2688,2656
Ledvance Smart+ CH {"NAME":"Ledvance Plug CH","GPIO":[0,0,0,288,32,0,0,0,2656,224,2720,0,0,0],"FLAG":0,"BASE":18}
Lenovo SE-341A {"NAME":"Lenovo SE-341A","GPIO":[0,0,0,0,32,224,0,0,576,0,320,0,0,0],"FLAG":0,"BASE":18}
Lenovo SE-341AA {"NAME":"Lenovo SE-341AC","GPIO":[0,0,0,0,32,224,0,0,576,0,320,0,0,0],"FLAG":0,"BASE":18}
-Lenovo SE-341AC {"NAME":"Lenovo SE-341AC","GPIO":[0,0,0,32,0,0,0,0,320,224,0,0,0,0],"FLAG":0,"BASE":18}
+Lenovo SE-341AC {"NAME":"Lenovo SE-341AC","GPIO":[0,321,0,32,2720,2656,0,0,320,224,2624,0,0,0],"FLAG":0,"BASE":18}
LESHP KS-501 {"NAME":"LESHP KS-501","GPIO":[32,0,0,0,0,0,0,0,224,320,0,0,0,0],"FLAG":0,"BASE":1}
Lighting Arena {"NAME":"Lighting Arena Smart Plug","GPIO":[0,0,320,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18}
Lloyd's {"NAME":"Lloyds LC-1193","GPIO":[0,0,0,0,320,0,0,0,224,0,32,0,0,0],"FLAG":0,"BASE":18}
@@ -1284,7 +1308,7 @@ Lohas Nightlight + USB {"NAME":"Lohas LED Mini Plug","GPIO":[0,321,0,288,3
Lombex Actis Pro {"NAME":"U11-Socket","GPIO":[0,0,0,0,289,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
Lonsonho 10A Type E {"NAME":"Lonsonho10ALed","GPIO":[0,0,0,0,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
LoraTap SP400W-IT {"NAME":"LoraTap SP400W","GPIO":[0,0,0,0,544,320,0,0,224,32,0,0,0,1],"FLAG":0,"BASE":18}
-LSC Power {"NAME":"LSC Smart Plug","GPIO":[0,0,0,0,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
+LSC Power {"NAME":"LSC Smart Plug (CB2S)","GPIO":[0,0,0,0,32,224,0,0,0,288,289,0,0,0],"FLAG":0,"BASE":18}
LSC Smart Connect {"NAME":"LSC Smart Plug FR","GPIO":[0,0,0,0,320,0,0,0,224,0,32,0,0,0],"FLAG":0,"BASE":18}
Lumiman LM650 {"NAME":"Lumiman LM650","GPIO":[0,0,0,0,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
Luminea {"NAME":"CH-1556","GPIO":[0,0,0,32,2720,2656,1,1,2624,320,224,0,0,0],"FLAG":0,"BASE":18}
@@ -1296,6 +1320,7 @@ Lunvon 2000W {"NAME":"Lunvon Smart Plug","GPIO":[32,0,0,0,0,0,28
Lunvon 3000W {"NAME":"Lunvon Smart Plug","GPIO":[32,0,0,0,0,0,288,224,0,0,0,0,0,0],"FLAG":0,"BASE":18}
Martin Jerry V01 {"NAME":"MJ V01","GPIO":[0,0,0,0,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
Martin Jerry XS-SSA01 {"NAME":"MJ_XS-SSA01","GPIO":[0,32,0,0,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18}
+Maxcio 16A Mini {"NAME":"MAXCIO RMC021","GPIO":[0,0,0,32,2720,2656,0,0,2624,544,224,0,0,0],"FLAG":0,"BASE":1}
Maxcio W-UK007S {"NAME":"Maxcio","GPIO":[320,0,1,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":45}
Maxcio W-US002S {"NAME":"W-US002S","GPIO":[321,0,320,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":45}
Maxcio W-US003 {"NAME":"W-US003","GPIO":[1,32,1,1,1,1,0,0,1,225,224,1,1,0],"FLAG":0,"BASE":18}
@@ -1341,13 +1366,14 @@ NGS Loop Track 16A {"NAME":"LOOP","GPIO":[0,0,320,0,0,0,0,0,0,32,0,224
Nightlight and AC Outlet {"NAME":"SWN03","GPIO":[32,0,0,0,0,0,1,1,416,0,0,224,0,0],"FLAG":0,"BASE":18}
Nishica SM-PW701I {"NAME":"SM-PW701I","GPIO":[1,1,1,1,1,1,1,1,224,288,32,1,1,1],"FLAG":0,"BASE":18}
Nivian {"NAME":"Nivian Smart Socket","GPIO":[0,0,320,0,0,2688,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18}
-Nous 16A {"NAME":"NOUS A1T","GPIO":[32,0,0,0,2720,2656,0,0,2624,320,224,0,0],"FLAG":0,"BASE":49}
+Nous 16A {"NAME":"NOUS A1T","GPIO":[32,0,0,0,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":49}
Nous A1 {"NAME":"NOUS A1","GPIO":[320,0,576,0,2656,2720,0,0,2624,32,0,224,0,0],"FLAG":0,"BASE":45}
NX-SM112 {"NAME":"NX-SM112v3","GPIO":[0,0,0,0,2720,2656,0,0,576,32,2592,224,0,0],"FLAG":0,"BASE":45}
NX-SM200 {"NAME":"NX-SM200","GPIO":[320,0,0,0,0,2720,0,0,224,32,2656,321,2624,0],"FLAG":0,"BASE":18}
NX-SM210 {"NAME":"NX-SM210","GPIO":[0,32,0,0,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18}
NX-SM223 {"NAME":"Smart Thurmm","GPIO":[0,32,0,0,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18}
Oakter Oak Plug Plus 16A {"NAME":"Oakter OakPlug Plus","GPIO":[0,0,0,0,224,0,0,0,544,320,0,0,0,0],"FLAG":0,"BASE":18}
+Oakter OakPlug Mini 10A {"NAME":"Oakter OakPlug Mini","GPIO":[0,0,0,0,224,0,0,0,544,320,0,0,0,0],"FLAG":0,"BASE":18}
Oakter OakPlug Plus (old) {"NAME":"Oakter OakPlug Plus (old)","GPIO":[0,0,0,0,224,0,0,0,0,320,0,0,544,0],"FLAG":0,"BASE":18}
Obi Stecker {"NAME":"OBI Socket","GPIO":[1,1,0,1,288,224,0,0,290,1,32,0,1,4704],"FLAG":0,"BASE":51}
Obi Stecker 2 {"NAME":"OBI Socket 2","GPIO":[0,0,0,0,224,32,0,0,320,289,0,0,0,0],"FLAG":0,"BASE":61}
@@ -1559,7 +1585,7 @@ ZSP-001 {"NAME":"ZSP-001","GPIO":[32,1,1,1,2688,2656,0,0,25
## Power Strip
```
3AC 4USB {"NAME":"C723","GPIO":[0,0,320,0,0,224,0,0,226,320,32,227,225,0],"FLAG":0,"BASE":18}
-4 AC Outlets 10A and 4 USB Ports {"NAME":"SA-P802 Power Strip","GPIO":[544,0,0,0,227,228,0,0,225,224,226,0,35,1],"FLAG":0,"BASE":18}
+4 AC Outlets 10A and 4 USB Ports {"NAME":"SA-P802 Power Strip","GPIO":[544,0,0,0,227,228,0,0,225,224,226,0,32,0],"FLAG":0,"BASE":18}
A0F0 ZLD-44EU-W {"NAME":"AOFO-4AC-4USB","GPIO":[0,320,0,32,225,224,0,0,226,227,260,0,0,4704],"FLAG":0,"BASE":18}
Acenx 3AC+3USB {"NAME":"ACENX 3-Outlet","GPIO":[320,291,290,289,0,224,0,0,226,227,225,0,32,0],"FLAG":0,"BASE":18}
AHRise 4+4AC+4USB {"NAME":"AHRise-083","GPIO":[0,0,0,0,320,32,0,0,225,224,226,227,0,0],"FLAG":0,"BASE":18}
@@ -1585,6 +1611,7 @@ Brennenstuhl Connect Eco-Line {"NAME":"WS EL01 DE","GPIO":[34,33,0,32,224,225,0
Brennenstuhl Connect Premium-Line {"NAME":"WS PL01 DE","GPIO":[34,33,0,32,224,225,0,0,288,0,35,289,576,0],"FLAG":0,"BASE":18}
BrilliantSmart Powerboard with USB Chargers {"NAME":"B_WiFi-4","GPIO":[320,0,0,321,256,32,0,0,258,257,259,0,228,4704],"FLAG":0,"BASE":18}
Calex 4AC 2USB {"NAME":"Calex Power Strip 429228","GPIO":[0,320,0,36,225,224,0,0,226,227,228,0,0,0],"FLAG":0,"BASE":18}
+Calex 4AC 4USB {"NAME":"Calex Power Strip 429228","GPIO":[0,0,0,288,224,226,0,0,0,228,227,225,32,0],"FLAG":0,"BASE":18}
CE Smart Home {"NAME":"CE Power Strip","GPIO":[288,0,0,0,227,228,0,0,225,226,224,0,32,0],"FLAG":0,"BASE":18}
CE Smart Home Garden Stake {"NAME":"CE Power Stake","GPIO":[0,0,0,0,320,321,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
CRST LTS-4G-W {"NAME":"CRST LTS-4G-W","GPIO":[0,0,0,0,227,0,0,0,225,226,224,0,0,0],"FLAG":0,"BASE":18}
@@ -1653,6 +1680,7 @@ Surge Protector 3AC 2USB {"NAME":"C158","GPIO":[260,0,0,0,261,230,0,0,224,0,
SWB1 {"NAME":"SWB1","GPIO":[288,0,0,0,0,227,0,0,224,32,225,226,0,0],"FLAG":0,"BASE":18}
SWB2 3AC + 2USB {"NAME":"SWB2","GPIO":[576,1,0,1,0,226,0,0,224,32,225,227,0,0],"FLAG":0,"BASE":18}
Swisstone 4AC 4USB {"NAME":"Swisstone SH140","GPIO":[0,576,0,32,225,224,0,0,226,227,228,0,0,0],"FLAG":0,"BASE":18}
+Sygonix 4AC {"NAME":"Sygonix SY-4538254","GPIO":[576,32,0,231,229,230,0,0,225,224,226,228,259,0],"FLAG":0,"BASE":18}
TCP Smart 4AC+USB {"NAME":"TCP WPS4WUK","GPIO":[1,320,0,32,226,227,0,0,225,224,228,0,0,1],"FLAG":0,"BASE":18}
Teckin SS30 {"NAME":"Teckin SS30","GPIO":[288,1,1,321,256,32,0,0,258,257,259,1,228,0],"FLAG":0,"BASE":18}
Tellur 3AC 4USB {"NAME":"Tellur","GPIO":[0,320,0,32,225,224,0,0,0,226,227,0,0,4704],"FLAG":0,"BASE":18}
@@ -1687,10 +1715,15 @@ ZLD-44USA-W {"NAME":"ZLD-44USA-W","GPIO":[0,320,0,32,225,224,0,
ZLD64-EU-W {"NAME":"ZLD64-EU-W","GPIO":[0,320,0,32,225,224,0,0,0,0,226,0,0,0],"FLAG":0,"BASE":18}
```
+## Presence Sensor
+```
+Tuya mmWave {"NAME":"ZY-M100","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54,"CMND":"SO97 1 | TuyaMCU 99,1 | TuyaMCU 75,104"}
+```
+
## RF Gateway
```
Sonoff RF Bridge 433 {"NAME":"Sonoff Bridge","GPIO":[32,3200,1,3232,1,1,0,0,1,320,1,0,0,0],"FLAG":0,"BASE":25}
-Virage Labs VirageBridge 433MHz {"NAME":"VirageBridge","GPIO":[32,3200,1,3232,1,1,0,0,1,320,1,0,0],"FLAG":0,"BASE":25}
+Virage Labs VirageBridge 433MHz {"NAME":"VirageBridge","GPIO":[32,3200,1,3232,1,1,0,0,1,320,1,0,0,0],"FLAG":0,"BASE":25}
```
## RGB
@@ -1714,6 +1747,7 @@ Wipro Garnet NS7001 480lm {"NAME":"WiproSmartBulb","GPIO":[0,0,0,0,416,419,0,
Aigital LE13 800lm {"NAME":"Aigital 9W RGB","GPIO":[0,0,0,0,420,417,0,0,418,0,419,416,0,0],"FLAG":0,"BASE":18}
Aisirer 10W 1000lm {"NAME":"Aisirer RGBCW","GPIO":[160,0,0,0,0,0,0,0,0,4032,4064,0,0,0],"FLAG":0,"BASE":18}
AiYaTo 12W {"NAME":"AiYaTo RGBCW","GPIO":[0,0,0,0,419,418,0,0,416,420,417,0,0,0],"FLAG":0,"BASE":18}
+AiYaTo 12W {"NAME":"AiYaTo RGBCW","GPIO":[0,0,0,0,419,418,0,0,416,420,417,0,0,0],"FLAG":0,"BASE":18}
Alfawise LE12 9W 900LM {"NAME":"Alfawise LE12 ","GPIO":[0,0,0,0,420,417,0,0,418,0,419,416,0,0],"FLAG":0,"BASE":18}
Aoycocr JL81 5W 400lm {"NAME":"AoycocrJLB1","GPIO":[0,0,0,0,418,0,0,0,417,420,416,419,0,0],"FLAG":0,"BASE":18}
Aoycocr Q10CWM BR30 9W 720lm {"NAME":"AoycocrBR30","GPIO":[0,0,0,0,0,418,0,0,417,0,416,419,0,0],"FLAG":0,"BASE":18}
@@ -1729,6 +1763,7 @@ Aunics 7W 600lm {"NAME":"Aunics RGBW","GPIO":[0,0,0,0,416,419,0,0,4
Avatar 8W 800lm {"NAME":"Avatar 8W RGBCW","GPIO":[1,1,1,1,416,419,1,1,417,420,418,1,1,1],"FLAG":0,"BASE":18}
Avatar ALB201W 720lm {"NAME":"AVATAR ALB201W","GPIO":[0,0,0,0,0,418,0,0,417,0,416,419,0,0],"FLAG":0,"BASE":18}
Avatar ALS18L A60 800lm {"NAME":"Avatar E14 7W","GPIO":[0,0,0,0,417,416,0,0,420,418,419,0,0,0],"FLAG":0,"BASE":20}
+AZzardo 10W {"NAME":"Azzardo AZ3213","GPIO":[0,0,0,0,4032,0,0,0,0,0,4064,0,0,0],"FLAG":0,"BASE":18,"CMND":"SetOption37 6"}
B.K. Licht 5.5W 350lm {"NAME":"BKL1262","GPIO":[0,0,0,0,417,416,0,0,420,418,419,0,0,0],"FLAG":0,"BASE":18}
B.K. Licht 9W 806lm {"NAME":"BKL1253","GPIO":[0,0,0,0,417,416,0,0,420,418,419,0,0,0],"FLAG":0,"BASE":18}
Bakibo TB95 9W 1000lm {"NAME":"Bakibo A19 9W","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
@@ -1806,6 +1841,7 @@ Legelite A60 7W {"NAME":"Legelite A60 7","GPIO":[0,0,0,0,416,419,0,
Legelite A60 7W 600lm {"NAME":"Legelite E26","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
Lenovo 800lm {"NAME":"Lenovo SE-241EB","GPIO":[0,0,0,0,416,419,0,0,417,452,418,0,0,0],"FLAG":0,"BASE":18}
Lloyd's 5W 400Lm {"NAME":"LLOYDS LC-1271","GPIO":[160,0,0,0,0,0,0,0,4064,0,4032,0,0,0],"FLAG":0,"BASE":18}
+Local Bytes 9W 900lm {"NAME":"localbytes bulb","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
Lohas ZN004 8W 680lm {"NAME":"Lohas B22 R63","GPIO":[0,0,0,0,417,416,0,0,420,418,419,0,0,0],"FLAG":0,"BASE":18}
Lohas ZN011 5W 420lm {"NAME":"LohasZN011","GPIO":[0,0,0,0,417,416,0,0,420,418,419,0,0,0],"FLAG":0,"BASE":18}
Lohas ZN014-2 5W 380lm {"NAME":"Lohas ZN014-2","GPIO":[0,0,0,0,417,416,0,0,420,418,419,0,0,0],"FLAG":0,"BASE":18}
@@ -1859,7 +1895,7 @@ Ruihai 9W 800lm {"NAME":"Ruihai SB50","GPIO":[0,0,0,0,416,419,0,0,4
RYE 5W 450LM Candle {"NAME":"RYE Candlebra","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
Saudio A19 7W 700lm {"NAME":"X002BU0DOL","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
Sealight A19 9W 810lm {"NAME":"DGO/SEASTAR","GPIO":[0,0,0,0,417,416,0,0,420,418,419,0,0,0],"FLAG":0,"BASE":18}
-Slitinto 5W Candle {"NAME":"Slitinto RGBWW","GPIO":[0,0,0,0,40,41,0,0,38,39,37,0,0,0],"FLAG":0,"BASE":18}
+Slitinto 5W Candle {"NAME":"Slitinto RGBWW","GPIO":[0,0,0,0,419,420,0,0,417,418,416,0,0,0],"FLAG":0,"BASE":18}
Slitinto TB95 9W 1000lm {"NAME":"Slitinto 9W","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
Smart 9W 800lm {"NAME":"SmartLED ","GPIO":[0,0,0,0,420,417,0,0,418,0,419,416,0,0],"FLAG":0,"BASE":18}
SmartLED 9W 400lm {"NAME":"SmartLED","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
@@ -1893,6 +1929,19 @@ ZunPulse 9W {"NAME":"ZunPulse B22 9W","GPIO":[0,0,0,0,416,419,0
ZZHXON 600lm {"NAME":"E27_RGB_Bulb","GPIO":[0,0,0,0,419,420,0,0,417,418,416,0,0,0],"FLAG":0,"BASE":18}
```
+## RGBIC LED
+```
+Athom 2812b Controller for {"NAME":"LS2812B-TAS","GPIO":[32,0,1376,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
+Athom ESP32 Music Controller for {"NAME":"Athom LS8P","GPIO":[32,1,224,1,1,1,1,1,1,1,1,7904,1,1377,1376,1,0,1,1,1,0,1088,1,1,0,0,0,0,7872,1,1,1,1,0,0,1],"FLAG":0,"BASE":1}
+Athom High Power 16A Controller for {"NAME":"LS_4PIN_TAS","GPIO":[32,1376,0,0,0,0,0,0,224,0,0,0,0,0],"FLAG":0,"BASE":18,"CMND":"Rule1 on Power1#State do power2 2 endon|Rule1 1"}
+BlitzWolf IC Smart RGB Controller for {"NAME":"BW-LT31","GPIO":[0,0,32,1376,0,0,0,0,0,1088,0,0,0,0],"FLAG":0,"BASE":18,"CMND":"SO37 24"}
+cod.m WLAN Pixel Controller v0.8 {"NAME":"cod.m Pixel Controller V0.8","GPIO":[0,0,0,0,0,544,0,0,0,0,0,32,1376,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1}
+ESP01 NeoPixel Ring {"NAME":"ESP-01S-RGB-LED-v1.0","GPIO":[1,1,1376,1,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
+H803WF 2048 Pixel 5V-24V {"NAME":"H803WF","GPIO":[0,0,0,0,3840,3840,0,0,3872,1376,0,3872,0,0],"FLAG":0,"BASE":18}
+IOTMCU {"NAME":"IOTMCU_ESP-12S-RGB-LED-v1","GPIO":[1,1,1,1,0,1376,0,0,1,1088,32,0,0,0],"FLAG":0,"BASE":18}
+SP501E WS2812B {"NAME":"SP501E","GPIO":[0,32,0,1376,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
+```
+
## RGBW
```
3Stone EBE-QPW36 1050lm {"NAME":"3STONE","GPIO":[0,0,0,0,2944,2912,0,0,416,2976,0,0,0,1],"FLAG":0,"BASE":18}
@@ -2031,7 +2080,7 @@ REPSN G45 5W 500lm {"NAME":"REPSN RGBW E14","GPIO":[0,0,0,0,0,0,0,0,40
Riversong Juno 10W {"NAME":"Juno10","GPIO":[0,0,0,0,2912,416,0,0,0,2976,2944,0,0,0],"FLAG":0,"BASE":18}
Rogoei EBE-QPZ04 6.5W 450lm {"NAME":"EBE-QPZ04","GPIO":[0,0,0,0,4032,0,0,0,0,0,4064,0,0,0],"FLAG":0,"BASE":18}
Saudio 7W 700lm {"NAME":"X002BU0DOL","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
-Shelly Duo RGBW 5W {"NAME":"Shelly Duo RGBW","GPIO":[0,0,0,0,0,419,0,0,417,416,418,0,0,0],"FLAG":0,"BASE":18}
+Shelly Duo RGBW 5W 400lm {"NAME":"Shelly Duo RGBW","GPIO":[0,0,0,0,0,419,0,0,417,416,418,0,0,0],"FLAG":0,"BASE":18}
Shelly Duo RGBW 9W 800lm {"NAME":"Shelly Duo RGBW","GPIO":[0,0,0,0,0,419,0,0,417,416,418,0,0,0],"FLAG":0,"BASE":18}
Smart 810lm {"NAME":"OOOLED 60W RGB","GPIO":[0,0,0,0,418,419,0,0,416,0,417,0,0,4704],"FLAG":0,"BASE":18}
SmartLED 9W 400lm {"NAME":"SmartLED RGBWW","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
@@ -2046,6 +2095,7 @@ Swisstone 806lm {"NAME":"SH 340","GPIO":[0,0,0,0,2912,416,0,0,0,297
Syska 7W 480lm {"NAME":"Syska","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
Syska 8W {"NAME":"Syska SMW-8W-C","GPIO":[0,0,0,0,420,419,0,0,417,418,416,0,0,0],"FLAG":0,"BASE":18}
Syska 9W 720lm {"NAME":"SyskaSmartBulb","GPIO":[0,0,0,0,416,419,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18}
+TCP Smart 5W {"NAME":"TAOLGU42OWW25RGBW","GPIO":[0,0,0,0,417,416,0,0,419,418,420,0,0,0],"FLAG":0,"BASE":18}
TCP Smart 9W 806lm {"NAME":"TCP Smart RGBW","GPIO":[0,0,0,0,2912,416,0,0,417,2976,2944,0,0,0],"FLAG":0,"BASE":18}
Teckin 7.5W 800lm {"NAME":"Teckin SB60","GPIO":[0,0,0,0,416,419,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18}
Teckin SB50 800lm {"NAME":"Teckin SB50","GPIO":[0,0,0,0,419,0,0,0,417,418,416,0,0,0],"FLAG":0,"BASE":18}
@@ -2072,6 +2122,11 @@ Zemismart A19 10W {"NAME":"Zemism_E27_A19","GPIO":[0,0,0,0,0,0,0,0,0,
Zilotek A19 800lm {"NAME":"Zilotek RGBW","GPIO":[0,0,0,0,2912,416,0,0,417,2976,2944,0,0,0],"FLAG":0,"BASE":18}
```
+## Relay
+```
+LilyGo T-Relay 8 {"NAME":"LilyGo ESP32 Relay 8","GPIO":[1,1,1,1,1,231,1,1,227,226,1,1,1,1,230,229,0,228,1,1,0,544,1,1,0,0,0,0,225,224,1,1,1,0,0,1],"FLAG":0,"BASE":1}
+```
+
## Relay Board
```
2 Channel Tuya {"NAME":"TY-DIY-S02","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 11,1 | TuyaMCU 12,2 | TuyaMCU 13,13 | TuyaMCU 1,101"}
@@ -2089,7 +2144,7 @@ Eachen ST-UDC1 {"NAME":"ST-UDC1","GPIO":[160,0,0,0,0,0,0,0,224,320
Electrodragon Board SPDT {"NAME":"ED Relay Board","GPIO":[1,1,1,1,1,1,0,0,224,225,1,1,288,4704],"FLAG":0,"BASE":18}
Electrodragon ESP8266 {"NAME":"ElectroDragon","GPIO":[33,1,32,1,1,1,0,0,225,224,1,1,288,4704],"FLAG":0,"BASE":15}
Electrodragon Inductive Load {"NAME":"ED RelayBoard IL","GPIO":[0,0,1,0,1,1,0,0,224,225,1,1,288,0],"FLAG":0,"BASE":18}
-ESP-01 Relay V4.0 {"NAME":"ESP01v4","GPIO":[256,320,0,32,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
+ESP-01 Relay V4.0 {"NAME":"ESP01v4","GPIO":[256,320,0,32,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
ESP-01S 5V Relay Module V1.0 {"NAME":"ESP-01S Relay","GPIO":[256,288,1,1,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
ESP-12F 5V/7-28V 1 Channel 30A {"NAME":"Aideepen","GPIO":[0,0,0,0,0,288,0,0,0,0,0,0,224,0],"FLAG":0,"BASE":18}
ESP-12F 5V/7-28V 4 Channel 30A {"NAME":"ESP12F_Relay_30A_X4","GPIO":[1,1,1,1,32,1,1,1,226,227,225,1,224,1],"FLAG":0,"BASE":18}
@@ -2111,6 +2166,7 @@ KRIDA 8 Channel 10A Electromagnetic {"NAME":"8CH Relay","GPIO":[230,1,231,229,1
LC Technology 12V 4 Channel {"NAME":"LC Technology 4CH Relay","GPIO":[224,0,225,0,226,227,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
LC Technology 5V 2 Channel {"NAME":"LC-ESP01-2R-5V","GPIO":[0,3200,0,3232,0,0,0,0,224,225,0,0,0,0],"FLAG":0,"BASE":18}
LC Technology 5V 4 Channel {"NAME":"LC-Tech_4CH ","GPIO":[288,1,32,1,0,0,0,0,224,225,226,227,0,0],"FLAG":0,"BASE":18}
+LC Technology 5V/7-30V 8 Channel {"NAME":"ESP32_Relay_X8","GPIO":[0,0,0,0,0,0,0,0,225,224,226,0,0,0,0,0,0,0,0,0,0,229,228,227,0,0,0,0,231,230,0,0,0,0,0,0],"FLAG":0,"BASE":1}
LC Technology 5V/8-80V 1 Channel {"NAME":"LC-Relay-ESP12-1R-MV","GPIO":[1,1,544,1,1,224,1,1,1,1,1,1,321,1],"FLAG":0,"BASE":18}
LC Technology 5V/8-80V 1 Channel {"NAME":"LC-Relay-ESP12-1R-D8","GPIO":[1,1,544,1,1,224,1,1,1,1,1,1,321,1],"FLAG":0,"BASE":18}
LC Technology AC90V-250V 1 Channel {"NAME":"ESP32_Relay_AC_X1","GPIO":[1,1,1,1,1,1,1,1,1,1,1,1,224,1,1,1,0,1,1,544,0,1,1,1,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1}
@@ -2140,12 +2196,14 @@ Yunshan 7-30V 10A {"NAME":"Yunshan 10A","GPIO":[32,1,288,1,224,161,0,
```
2 CH Smart Switch {"NAME":"Generic","GPIO":[32,1,1,1,1,225,33,1,224,288,1,1,1,1],"FLAG":0,"BASE":18}
Aubess Power Monitor Switch 16A {"NAME":"Aubess with (BL0942)","GPIO":[0,3200,0,7520,0,0,0,0,0,0,224,0,0,0],"FLAG":0,"BASE":18}
+Mini Smart Switch {"NAME":"SmartSwitch-MK601","GPIO":[0,0,0,160,32,224,0,0,0,0,288,0,0,0],"FLAG":0,"BASE":18}
Moes 10A {"NAME":"Moes MS-101","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
Smarsecur Smart Switch {"NAME":"ESP-02S","GPIO":[0,0,0,32,0,0,0,0,0,0,224,0,0,0],"FLAG":0,"BASE":18}
```
## Sensor
```
+Bresser 7-Kanal Thermo-/Hygrometer with Outdoor {"NAME":"Bresser","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54,"CMND":"SO97 1 | TuyaMCU 73,2 | TuyaMCU 71,102"}
Genesense IoT Controller {"NAME":"GNS24","GPIO":[32,1,1312,1,256,320,1,1,256,1216,160,3840,1,4704],"FLAG":0,"BASE":18}
Shelly 3EM Power Monitoring Module {"NAME":"Shelly 3EM","GPIO":[1,1,288,1,32,8065,0,0,640,8064,608,224,8096,0],"FLAG":0,"BASE":18}
```
@@ -2171,6 +2229,11 @@ Slampher {"NAME":"Slampher","GPIO":[32,1,0,1,0,0,0,0,224,320
SmartBase E0260 {"NAME":"SmartBaseE0260","GPIO":[0,0,0,0,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
```
+## Soil Sensor
+```
+DIY MORE ESP32 DHT11 {"NAME":"DIYMORESOILDHT11","GPIO":[1,1,1,1,1,1,1,1,1,1,1,1,544,1,1,1,0,1,1184,1,0,1,1,1,0,0,0,0,4864,288,4865,1,1,0,0,1],"FLAG":0,"BASE":1}
+```
+
## Switch
```
3 Way Smart Light {"NAME":"KS-602F","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
@@ -2179,6 +2242,7 @@ AGL 2 Gang {"NAME":"AGL WiFi 02","GPIO":[0,0,544,0,0,33,0,0,22
AGL 3 Gang {"NAME":"AGL WiFi 03","GPIO":[0,0,544,0,34,33,0,0,225,224,226,0,32,0],"FLAG":0,"BASE":18}
Aoycocr SW1 {"NAME":"Aoycocr SW1","GPIO":[576,1,321,1,1,1,1,1,320,32,1,224,1,1],"FLAG":0,"BASE":18}
APPIO 1 Gang Switch {"NAME":"Appio-9608","GPIO":[0,0,0,0,0,32,0,0,0,0,0,224,288,0],"FLAG":0,"BASE":18}
+Appio 3 Gang Touch {"NAME":"Appio 9611","GPIO":[0,0,0,0,226,33,0,0,32,224,34,225,288,0],"FLAG":0,"BASE":18}
Athom 1 Gang {"NAME":"Athom SW011EU","GPIO":[576,0,0,32,0,0,0,0,0,224,288,0,0,0],"FLAG":0,"BASE":1}
Athom 1 Gang {"NAME":"Athom SW031US","GPIO":[576,0,0,32,0,0,0,0,0,224,288,0,0,0],"FLAG":0,"BASE":1}
Athom 1 Gang No Neutral {"NAME":"Athom SW111EU","GPIO":[576,0,0,32,0,0,0,0,0,224,288,0,0,0],"FLAG":0,"BASE":1}
@@ -2225,7 +2289,7 @@ Dierya Touch Panel 2 Gang {"NAME":"CD302","GPIO":[544,0,0,33,225,0,0,0,32,224
Dierya Touch Panel 3 Gang {"NAME":"CD303","GPIO":[576,289,0,34,226,33,0,0,32,224,290,225,288,0],"FLAG":0,"BASE":18}
Digoo DG-S811 3 Gang {"NAME":"DIGOO Switch","GPIO":[0,0,0,0,34,33,0,0,225,224,226,0,32,0],"FLAG":0,"BASE":18}
DS-101 1 Gang {"NAME":"Smart Life Switch","GPIO":[0,0,0,32,0,0,0,0,0,224,288,0,0,0],"FLAG":0,"BASE":18}
-DS-101 2 Gang {"NAME":"Smart Life Switch","GPIO":[576,289,0,32,225,33,0,0,0,224,288,0,0],"FLAG":0,"BASE":18}
+DS-101 2 Gang {"NAME":"Smart Life Switch","GPIO":[576,289,0,32,225,33,0,0,0,224,288,0,0,0],"FLAG":0,"BASE":18}
DS-101 3 Gang {"NAME":"DS-101 3 gang","GPIO":[576,322,0,33,226,34,0,0,32,225,321,224,320,0],"FLAG":0,"BASE":18}
DS-101 4 Gang Switch {"NAME":"DS-101 4 Gang","GPIO":[544,0,0,33,225,34,0,0,32,224,227,226,35,0],"FLAG":0,"BASE":18}
DS-102 1 Gang {"NAME":"DS-102 1 Gang","GPIO":[576,0,0,32,0,0,0,0,0,224,288,0,0,0],"FLAG":0,"BASE":18}
@@ -2269,6 +2333,7 @@ Innens RF433 2 Gang 1 Way {"NAME":"Innens Light Switch 2G","GPIO":[0,0,289,0,
Jinvoo SM-SW101-1 {"NAME":"SM-SW101-1","GPIO":[288,0,0,33,0,0,0,0,32,224,0,0,0,4704],"FLAG":0,"BASE":18}
Jinvoo SM-SW101-2 {"NAME":"SM-SW101-2","GPIO":[288,0,0,33,225,0,0,0,32,224,0,0,0,4704],"FLAG":0,"BASE":18}
Jinvoo SM-SW101-3 {"NAME":"Jinvoo Wall Sw","GPIO":[288,0,0,33,225,34,0,0,32,224,0,226,0,4704],"FLAG":0,"BASE":18}
+KaBuM! 15A 3 Gang Touch {"NAME":"Kabum Switch 3","GPIO":[0,0,0,0,226,33,0,0,32,224,34,225,576,0],"FLAG":0,"BASE":18}
Kauf RGB Wall {"NAME":"Kauf SRF10","GPIO":[448,1,450,1,450,449,1,1,449,32,448,224,1,1],"FLAG":0,"BASE":18}
KingArt 1 Gang {"NAME":"KING-L1","GPIO":[0,0,0,0,0,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
KingArt 3 Gang {"NAME":"KING-L3","GPIO":[0,0,0,0,226,225,0,0,224,164,165,0,167,0],"FLAG":0,"BASE":18}
@@ -2292,6 +2357,7 @@ LerLink 2 Gang No Neutral {"NAME":"Lonsonho 2gang","GPIO":[0,0,0,33,32,0,0,0,
Lerlink 3 Gang {"NAME":"X803A","GPIO":[0,0,0,33,32,34,0,0,224,259,225,226,288,0],"FLAG":0,"BASE":18}
Lerlink 3 Gang {"NAME":"X803A","GPIO":[0,0,0,33,32,34,0,0,224,288,225,226,0,0],"FLAG":0,"BASE":18}
Lerlink 3 Gang No Neutral {"NAME":"X803K-L 3 Gang","GPIO":[0,0,320,0,32,34,33,0,224,0,225,226,0,0],"FLAG":0,"BASE":18}
+Lidl Silvercrest {"NAME":"Lidl Silvercrest HG06337","GPIO":[0,0,0,0,0,0,0,0,32,320,224,0,0,0],"FLAG":0,"BASE":18}
Lightstory WT02S {"NAME":"WT02S","GPIO":[0,0,0,0,321,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":50}
Linkind 2-Way {"NAME":"Linkind WS240010008","GPIO":[0,0,0,0,0,224,0,0,0,0,288,0,0,0,0,0,0,0,0,0,0,576,321,0,0,0,0,0,33,32,0,0,0,0,0,0],"FLAG":0,"BASE":1}
Linkind Dimmer {"NAME":"Linkind Dimmer WS240010108","GPIO":[6213,8448,0,0,640,0,0,0,0,0,288,0,0,0,0,0,0,0,608,0,0,0,544,0,0,0,0,0,33,32,0,0,0,0,0,0],"FLAG":0,"BASE":1}
@@ -2308,7 +2374,7 @@ LX-WIFI-00M 4 Gang {"NAME":"LX-WIFI-00M","GPIO":[32,228,1,1,226,225,33
MakeGood 2 Gang {"NAME":"MakeGood 2 Gang","GPIO":[0,0,0,0,0,0,0,0,0,0,290,0,0,0],"FLAG":0,"BASE":54}
MakeGood 4 Gang {"NAME":"MakeGood 4 Gang","GPIO":[0,0,0,0,0,0,0,0,0,0,290,0,0,0],"FLAG":0,"BASE":54}
Markevina KS-602S {"NAME":"Markevina KS-6","GPIO":[32,1,0,1,0,0,0,0,224,288,0,0,0,0],"FLAG":0,"BASE":18}
-Martin Jerry S01 15A {"NAME":"MJ-S01 Switch","GPIO":[0,0,0,0,320,321,0,0,224,32,0,0,0],"FLAG":0,"BASE":18}
+Martin Jerry S01 15A {"NAME":"MJ-S01 Switch","GPIO":[0,0,0,0,320,321,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
Martin Jerry ST01 3 Way {"NAME":"MJ 3Way Switch","GPIO":[1,1,1,1,288,289,0,0,224,160,544,1,0,0],"FLAG":0,"BASE":18}
Maxcio IT Wall 3 Gang Light {"NAME":"Maxcio 3 Gang Switch","GPIO":[544,0,0,0,32,33,0,0,225,226,224,0,34,0],"FLAG":0,"BASE":18}
Merkury MI-WW107-199W {"NAME":"MI-WW107-199W","GPIO":[288,0,0,0,0,0,0,0,32,224,0,0,0,0],"FLAG":0,"BASE":18}
@@ -2336,6 +2402,7 @@ Moes 3 Gang {"NAME":"Moes WS-EU3-W","GPIO":[544,0,290,33,225,34
Moes 3-Way {"NAME":"Moes 3-Way","GPIO":[1,1,1,1,224,321,0,0,257,161,160,1,1,0],"FLAG":0,"BASE":18}
Moes BS-US-W Boiler {"NAME":"BS-US-W","GPIO":[290,0,0,32,224,0,0,0,0,0,288,0,291,0],"FLAG":0,"BASE":18}
Moes Light and Fan {"NAME":"Moes WF-FL01","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
+Moes Push Button 3 Way Light {"NAME":"Moes ESW-1WAA-US","GPIO":[32,0,0,0,288,0,0,0,0,224,161,0,0,0],"FLAG":0,"BASE":18}
Moes RF433 2 Gang Switch {"NAME":"WS-EUB2-WR","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
Moes RF433 3 Gang {"NAME":"WS-EUB3-WR","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
Moes RF433 3 Gang Touch {"NAME":"WS-EU-RF","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 11,1 | TuyaMCU 12,2 | TuyaMCU 13,3"}
@@ -2357,11 +2424,13 @@ NaamaSmart KS602 {"NAME":"KS-602","GPIO":[32,0,0,0,0,0,0,0,224,576,0
Nedis Dual {"NAME":"SM-SW102U-2","GPIO":[576,0,0,33,225,0,0,0,32,224,0,0,0,4704],"FLAG":0,"BASE":18}
Nexete DS-123 {"NAME":"DS-123","GPIO":[544,321,1,32,224,33,0,0,1,225,320,1,1,0],"FLAG":0,"BASE":18}
Nexete DS-123 Single {"NAME":"DS-123","GPIO":[544,0,1,33,0,32,0,0,1,224,320,1,1,0],"FLAG":0,"BASE":18}
-Novadigital Interruptor Touch Led 1 Botno {"NAME":"Nova Digital Switch 1 Gang","GPIO":[544,0,0,32,224,0,0,0,0,0,288,0,0,0],"FLAG":0,"BASE":18}
+Novadigital Interruptor Touch Led 1 Boto {"NAME":"Nova Digital Switch 1 Gang","GPIO":[544,0,0,32,224,0,0,0,0,0,288,0,0,0],"FLAG":0,"BASE":18}
Prosto {"NAME":"Prosto WFS-T10","GPIO":[0,0,0,0,0,224,0,0,320,0,64,0,0,0],"FLAG":0,"BASE":18}
Push Button 1/2/3/4 Gang {"NAME":"DS-122","GPIO":[321,0,0,32,0,0,0,0,0,224,288,0,0,0],"FLAG":0,"BASE":18}
Q-touch 1 Gang {"NAME":"Qtouch","GPIO":[289,0,0,32,0,0,0,0,224,0,0,0,0,0],"FLAG":0,"BASE":1}
Q-touch 433MHz 1 Gang {"NAME":"Qtouch 1G","GPIO":[32,0,0,0,0,0,0,0,224,288,0,0,0,0],"FLAG":0,"BASE":18}
+Q-touch 433MHz 1 Gang No Neutral {"NAME":"QWP_W1_WIFI-TOUCH","GPIO":[32,1,1,1,0,0,0,0,224,320,0,0,0,0],"FLAG":0,"BASE":28}
+Q-touch 433MHz 2 Gang No Neutral {"NAME":"QWP_W2_WIFI-TOUCH","GPIO":[32,1,1,1,0,225,33,0,224,320,0,0,0,0],"FLAG":0,"BASE":29}
Qualitel 1 Gang {"NAME":"Qualitel 1 Gang","GPIO":[544,0,0,160,224,0,0,0,0,0,288,0,0,0],"FLAG":0,"BASE":18}
Qualitel 2-Gang {"NAME":"Qualitel 2 Gang","GPIO":[544,0,289,0,0,161,0,0,160,224,0,225,288,0],"FLAG":0,"BASE":18}
Qualitel 3 Gang {"NAME":"Qualitel 3 Gang","GPIO":[544,0,290,161,225,162,0,0,160,224,289,226,288,0],"FLAG":0,"BASE":18}
@@ -2488,7 +2557,7 @@ ZUCZUG 3 Gang {"NAME":"2ph105626a x3","GPIO":[0,288,0,32,34,33,0,
```
AGL Modulo Relay 01 Canal {"NAME":"AGL-Basic","GPIO":[0,1,0,0,224,32,0,0,0,0,320,0,0,0],"FLAG":0,"BASE":18}
Albohes 2 Channel {"NAME":"Albohes SH-08","GPIO":[0,3200,33,3232,321,320,0,0,224,544,32,0,225,1],"FLAG":0,"BASE":18}
-Athom 10A {"NAME":"CB01-TAS-1","GPIO":[0,0,0,32,576,0,0,0,0,224,0,0,0,1],"FLAG":0,"BASE":18}
+Athom 10A {"NAME":"CB01-TAS-1","GPIO":[0,0,0,32,320,0,0,0,0,224,0,0,0,1],"FLAG":0,"BASE":18}
Athom 2Ch Inching/Self-locking {"NAME":"Athom R02","GPIO":[1,1,1,1,225,224,1,1,1,1,1,1,576,0],"FLAG":0,"BASE":18}
Athom 3-Way Mini Relay {"NAME":"RS01-TAS-1","GPIO":[0,0,0,32,576,0,0,0,0,224,160,0,0,0],"FLAG":0,"BASE":18}
Athom 4Ch Inching/Self-locking 10A {"NAME":"Athom R04","GPIO":[1,1,1,1,32,576,1,1,226,227,225,1,224,0],"FLAG":0,"BASE":18}
@@ -2522,7 +2591,7 @@ LoveAnna AC85-250V 10A {"NAME":"2xSwitch No RF LoveAnna","GPIO":[32,0,0,0,
Luani HVIO {"NAME":"Luani HVIO","GPIO":[0,1,1,1,224,225,0,0,160,161,1,288,0,4704],"FLAG":0,"BASE":35}
Milfra Smart {"NAME":"Milfra Smart Module TB41","GPIO":[576,0,0,225,2688,2656,0,0,2592,193,480,224,192,0],"FLAG":0,"BASE":18}
Moes {"NAME":"Moes MS-104B","GPIO":[0,0,32,0,480,0,0,0,161,160,224,225,0,0],"FLAG":0,"BASE":18}
-Nedis 10A {"NAME":"Nedis WIFIPS10WT","GPIO":[0,0,0,0,21,0,0,0,17,57,0,52,0,0],"FLAG":0,"BASE":18}
+Nedis 10A {"NAME":"Nedis WIFIPS10WT","GPIO":[0,0,0,0,224,0,0,0,32,321,0,288,0,0],"FLAG":0,"BASE":18}
Nova Digital Basic 1 MS101 {"NAME":"NovaDigBasic1","GPIO":[0,1,0,1,320,0,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
PPA Contatto Wi-Fi {"NAME":"PPA Contatto","GPIO":[0,0,32,0,224,162,0,0,288,225,0,0,0,0],"FLAG":0,"BASE":18}
PS-1604 16A {"NAME":"PS-1604 16A","GPIO":[32,1,1,1,1,0,0,0,224,320,1,0,0,0],"FLAG":0,"BASE":1}
@@ -2534,10 +2603,10 @@ Shelly 1L No Neutral {"NAME":"Shelly 1L","GPIO":[320,0,0,0,192,224,0,0,0
Shelly 1PM {"NAME":"Shelly 1PM","GPIO":[320,0,0,0,192,2720,0,0,0,0,0,224,0,4736],"FLAG":0,"BASE":18}
Shelly 2 {"NAME":"Shelly 2","GPIO":[0,2752,0,2784,224,225,0,0,160,0,161,2816,0,0],"FLAG":0,"BASE":47}
Shelly 2.5 {"NAME":"Shelly 2.5","GPIO":[320,0,0,0,224,193,0,0,640,192,608,225,3456,4736],"FLAG":0,"BASE":18}
-Shelly EM {"NAME":"Shelly EM","GPIO":[0,0,0,0,0,0,0,0,640,3456,608,224,0,1],"FLAG":0,"BASE":18}
+Shelly EM {"NAME":"Shelly EM","GPIO":[0,0,0,0,0,0,0,0,640,3457,608,224,8832,1],"FLAG":0,"BASE":18}
Shelly i3 Action and Scenes Activation Device {"NAME":"Shelly i3","GPIO":[0,0,0,0,0,320,0,0,193,194,192,0,0,4736],"FLAG":0,"BASE":18}
Shelly Plus 1 {"NAME":"Shelly Plus 1 ","GPIO":[0,0,0,0,192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1}
-Shelly Plus 1PM {"NAME":"Shelly Plus 1PM","GPIO":[0,0,0,0,192,2720,0,0,0,0,0,0,0,0,2656,0,0,0,0,2624,0,0,224,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1}
+Shelly Plus 1PM {"NAME":"Shelly Plus 1PM","GPIO":[0,0,0,0,192,2720,0,0,0,0,0,0,0,0,2656,0,0,0,0,2624,0,32,224,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1}
Shelly Plus 2PM {"NAME":"Shelly Plus 2PM PCB v0.1.9","GPIO":[320,0,0,0,32,192,0,0,225,224,0,0,0,0,193,0,0,0,0,0,0,608,640,3456,0,0,0,0,0,0,0,4736,0,0,0,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"}
Shelly Plus i4 {"NAME":"Shelly Plus i4","GPIO":[0,0,0,0,0,0,0,0,192,0,193,0,0,0,0,0,0,0,0,0,0,0,195,194,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1,"CMND":"SwitchMode1 1 | SwitchMode2 1 | SwitchMode3 1 | SwitchMode4 1 | SwitchTopic 0 | SetOption114 1"}
Sinilink USB {"NAME":"XY-WFUSB","GPIO":[1,1,0,1,32,224,0,0,0,0,320,0,544,0],"FLAG":0,"BASE":18}
@@ -2594,7 +2663,8 @@ Shelly Add-on {"NAME":"Shelly 1 Temp ","GPIO":[1344,0,0,1312,224,
## Thermostat
```
Floor Heating or Water/Gas Boiler {"NAME":"ME81H Thermostat","GPIO":[1,1,1,1,1,1,0,0,1,1,1,1,1,0],"FLAG":0,"BASE":54}
-Moes Floor Heating or Water/Gas Boiler Wall {"NAME":"WHT-HY609-GB-WH-MS","GPIO":[0,2304,0,2272,0,0,0,0,0,0,896,928,0,0],"FLAG":0,"BASE":54}
+Lytko 101 {"NAME":"Lytko 101","GPIO":[1,7584,1312,1,1792,1824,0,0,1,1,1,224,1,4736],"FLAG":0,"BASE":18}
+Moes Floor Heating or Water/Gas Boiler Wall {"NAME":"WHT-HY609-GB-WH-MS","GPIO":[0,2304,0,2272,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
Mysa V1 Electric Baseboard Heater {"NAME":"Mysa Thermostat","GPIO":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,0,0,0,0,0,0,640,608,0,0,0,0,0,0],"FLAG":0,"BASE":1}
```
@@ -2613,8 +2683,9 @@ Tuya Gas/Water {"NAME":"Valve FM101","GPIO":[320,0,0,0,224,0,0,0,0
## Wall Outlet
```
2AC 1USB {"NAME":"SM-SW801U","GPIO":[0,0,0,0,288,32,0,0,224,0,225,0,226,0],"FLAG":0,"BASE":18}
+Aigostar P40 {"NAME":"Aigostar 8433325212278","GPIO":[0,0,0,0,544,288,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
Aseer THWFS01 {"NAME":"ASEER-THWFS01","GPIO":[320,33,544,323,2720,2656,0,0,2624,225,321,224,32,0],"FLAG":0,"BASE":18}
-Athom {"NAME":"Athom SK01","GPIO":[0,0,0,3104,0,32,0,0,224,576,0,0,0,0],"FLAG":0,"BASE":18}
+Athom {"NAME":"Athom SK01","GPIO":[0,0,0,3104,0,32,0,0,224,320,0,0,0,0],"FLAG":0,"BASE":18}
Bestten LO-2-W {"NAME":"BESTTEN LO-2-W","GPIO":[0,0,0,0,576,32,0,0,224,0,0,0,0,0],"FLAG":0,"BASE":18}
BingoElec 16A {"NAME":"BingoElecPower","GPIO":[0,0,0,0,288,289,1,1,224,32,0,0,1,1],"FLAG":0,"BASE":18}
BlitzWolf SHP8 {"NAME":"SHP8","GPIO":[0,320,0,32,2720,2656,0,0,2624,289,224,0,0,0],"FLAG":0,"BASE":64}
@@ -2632,6 +2703,7 @@ Kapok T16 {"NAME":"tiltech-t16","GPIO":[0,320,0,32,192,0,0,0,
Kesen KS-604 {"NAME":"KS-604","GPIO":[1,1,288,1,1,33,0,0,225,224,1,1,32,0],"FLAG":0,"BASE":18}
Kesen KS-604S {"NAME":"KS-604S","GPIO":[1,1,258,1,1,33,0,0,225,224,1,1,32,4704],"FLAG":0,"BASE":18}
Keygma KS-15TW {"NAME":"Keygma KS-15T","GPIO":[0,0,0,0,0,320,0,0,224,160,0,0,0,0],"FLAG":0,"BASE":18}
+Knightsbridge Dual Waterproof {"NAME":"Knightsbridge Dual Socket","GPIO":[321,544,320,544,225,0,0,0,0,33,0,224,32,0],"FLAG":0,"BASE":18}
KS-621 {"NAME":"KS-621","GPIO":[32,0,0,0,2688,2656,0,0,2592,288,0,224,65,1],"FLAG":0,"BASE":18}
Makegood MG-AUWF01 {"NAME":"MG-AUWF01","GPIO":[320,161,544,323,2720,2656,0,0,2624,225,321,224,160,0],"FLAG":0,"BASE":18}
Makegood MG-UKWSG01 {"NAME":"Aseer 2-Gang","GPIO":[321,160,544,323,2720,2656,0,0,2624,224,320,225,161,0],"FLAG":0,"BASE":18}
@@ -2649,8 +2721,8 @@ Steren Dual Plug and USB Charger {"NAME":"Steren_SHOME-118","GPIO":[0,576,0,32,
T16E Dual USB 10A {"NAME":"T16E 10A","GPIO":[0,0,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":18}
TCP Smart Dual {"NAME":"TCP TAUWIS2GUK","GPIO":[33,0,0,0,0,224,32,0,225,544,0,0,0,0],"FLAG":0,"BASE":18}
Teckin SR40 {"NAME":"RF-SR40-US","GPIO":[576,0,0,32,320,33,0,0,225,224,321,226,0,0],"FLAG":0,"BASE":18}
+TopGreener {"NAME":"TGWF15RM","GPIO":[0,320,0,32,2720,2656,0,0,2624,321,224,0,0,0],"FLAG":0,"BASE":55}
TopGreener Dual USB {"NAME":"TGWF215U2A","GPIO":[0,320,0,32,2720,2656,0,0,2624,225,224,321,0,0],"FLAG":0,"BASE":18}
-TopGreener TGWF15RM {"NAME":"TGWF15RM","GPIO":[0,320,0,32,2720,2656,0,0,2624,321,224,0,0,0],"FLAG":0,"BASE":55}
Vigica VGSPK00815 {"NAME":"VIGICA outlet","GPIO":[32,1,1,1,1,225,33,1,224,1,1,1,1,4704],"FLAG":0,"BASE":18}
Virage Labs ViragePlug {"NAME":"ViragePlug","GPIO":[544,0,0,32,320,33,0,0,225,224,320,226,0,0],"FLAG":0,"BASE":18}
Woox Dual {"NAME":"Woox R4053","GPIO":[33,0,0,0,0,224,32,0,225,320,0,0,0,0],"FLAG":0,"BASE":18}
@@ -2659,12 +2731,14 @@ Xenon 2AC 1USB {"NAME":"Xenon SM-PW801-U1","GPIO":[0,0,0,0,288,32,
## Water Sensor
```
+Nedis SmartLife Water Detector {"NAME":"Nedis WIFIDW10WT","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 51,21"}
W06 {"NAME":"W06 Water Sensor","GPIO":[0,3200,0,3232,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
Y09 {"NAME":"Y09","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54}
```
## Zigbee Gateway
```
+Athom ESP32 Ethernet {"NAME":"Athom ZG01","GPIO":[32,0,0,0,0,0,0,0,5472,0,5504,544,0,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,1,5792,0,0,0,0,0,0,0],"FLAG":0,"BASE":1}
Eachen eWeLink ZbBridge Pro Ethernet {"NAME":"ZB-GW03-V1.2","GPIO":[0,0,3552,0,3584,0,0,0,5793,5792,320,544,5536,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,608,640,32,0,0,0,0,0],"FLAG":0,"BASE":1}
Sonoff ZBBridge {"NAME":"Sonoff ZbBridge","GPIO":[320,3552,0,3584,5312,0,0,0,640,576,608,0,32,0],"FLAG":0,"BASE":75}
Sonoff ZBBridge Pro {"NAME":"Sonoff Zigbee Pro","GPIO":[0,0,576,0,480,0,0,0,0,1,1,5792,0,0,0,3552,0,320,5793,3584,0,640,608,32,0,0,0,0,0,1,0,0,0,0,0,0],"FLAG":0,"BASE":1}
diff --git a/boards/esp32-cam.json b/boards/esp32-fix.json
similarity index 67%
rename from boards/esp32-cam.json
rename to boards/esp32-fix.json
index 165b8ef58..90132b94e 100644
--- a/boards/esp32-cam.json
+++ b/boards/esp32-fix.json
@@ -4,7 +4,7 @@
"ldscript": "esp32_out.ld"
},
"core": "esp32",
- "extra_flags": "-DCAMERA_MODEL_AI_THINKER -DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DHAS_PSRAM_FIX -mfix-esp32-psram-cache-issue -mfix-esp32-psram-cache-strategy=memw -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_4M",
+ "extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DHAS_PSRAM_FIX -mfix-esp32-psram-cache-issue -mfix-esp32-psram-cache-strategy=memw -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_4M",
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "dio",
@@ -25,7 +25,7 @@
"arduino",
"espidf"
],
- "name": "AI Thinker ESP32-CAM, 4M Flash 4MB PSRAM, Tasmota 2880k Code/OTA, 320k FS",
+ "name": "Espressif Generic ESP32 >= 4M Flash, PSRAM with fix, Tasmota 2880k Code/OTA, 320k FS",
"upload": {
"arduino": {
"flash_extra_images": [
@@ -41,6 +41,6 @@
"require_upload_port": true,
"speed": 460800
},
- "url": "https://wiki.ai-thinker.com/esp32-cam",
- "vendor": "AI Thinker"
+ "url": "https://en.wikipedia.org/wiki/ESP32",
+ "vendor": "Espressif"
}
diff --git a/boards/esp32-m5core2.json b/boards/esp32-m5core2.json
deleted file mode 100644
index 7fc157edb..000000000
--- a/boards/esp32-m5core2.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "build": {
- "arduino":{
- "ldscript": "esp32_out.ld"
- },
- "core": "esp32",
- "extra_flags": "-DARDUINO_M5STACK_Core2 -DBOARD_HAS_PSRAM -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_16M",
- "f_cpu": "240000000L",
- "f_flash": "80000000L",
- "flash_mode": "qio",
- "mcu": "esp32",
- "variant": "m5stack_core2",
- "partitions": "partitions/esp32_partition_app2944k_fs10M.csv"
- },
- "connectivity": [
- "wifi",
- "bluetooth",
- "ethernet",
- "can"
- ],
- "debug": {
- "openocd_target": "esp32.cfg"
- },
- "frameworks": [
- "arduino",
- "espidf"
- ],
- "name": "M5Stack Core2 16M Flash, 4MB PSRAM, Tasmota 2944k Code/OTA, 10M FS",
- "upload": {
- "flash_size": "16MB",
- "maximum_ram_size": 327680,
- "maximum_size": 16777216,
- "require_upload_port": true,
- "speed": 2000000
- },
- "url": "http://www.m5stack.com",
- "vendor": "M5Stack"
-}
diff --git a/boards/esp32-odroid.json b/boards/esp32-odroid.json
deleted file mode 100644
index f7804af4e..000000000
--- a/boards/esp32-odroid.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "build": {
- "arduino":{
- "ldscript": "esp32_out.ld"
- },
- "core": "esp32",
- "extra_flags": "-DARDUINO_ODROID_ESP32 -DBOARD_HAS_PSRAM -DHAS_PSRAM_FIX -mfix-esp32-psram-cache-issue -mfix-esp32-psram-cache-strategy=memw -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_16M",
- "f_cpu": "240000000L",
- "f_flash": "80000000L",
- "flash_mode": "dio",
- "mcu": "esp32",
- "variant": "odroid_esp32",
- "partitions": "partitions/esp32_partition_app2944k_fs10M.csv"
- },
- "connectivity": [
- "wifi",
- "bluetooth",
- "ethernet",
- "can"
- ],
- "debug": {
- "openocd_target": "esp32.cfg"
- },
- "frameworks": [
- "arduino",
- "espidf"
- ],
- "name": "ESP32 ODROID-GO 16M Flash, 4MB PSRAM, Tasmota 2944k Code/OTA, 10M FS",
- "upload": {
- "flash_size": "16MB",
- "maximum_ram_size": 327680,
- "maximum_size": 16777216,
- "require_upload_port": true,
- "speed": 2000000
- },
- "url": "https://www.hardkernel.com/main/products/prdt_info.php?g_code=G152875062626",
- "vendor": "Hardkernel"
-}
diff --git a/boards/esp32_4M.json b/boards/esp32.json
similarity index 89%
rename from boards/esp32_4M.json
rename to boards/esp32.json
index d8e39873f..808ba0cd0 100644
--- a/boards/esp32_4M.json
+++ b/boards/esp32.json
@@ -5,7 +5,7 @@
},
"core": "esp32",
"extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_4M",
- "f_cpu": "80000000L",
+ "f_cpu": "160000000L",
"f_flash": "40000000L",
"flash_mode": "dio",
"mcu": "esp32",
@@ -25,7 +25,7 @@
"arduino",
"espidf"
],
- "name": "Espressif Generic ESP32 4M Flash, Tasmota 2880k Code/OTA, 320k FS",
+ "name": "Espressif Generic ESP32 >= 4M Flash PSRAM, Tasmota 2880k Code/OTA, 320k FS",
"upload": {
"arduino": {
"flash_extra_images": [
diff --git a/boards/esp32_16M.json b/boards/esp32_16M.json
deleted file mode 100644
index c0956a642..000000000
--- a/boards/esp32_16M.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "build": {
- "arduino":{
- "ldscript": "esp32_out.ld"
- },
- "core": "esp32",
- "extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_16M",
- "f_cpu": "80000000L",
- "f_flash": "40000000L",
- "flash_mode": "dio",
- "mcu": "esp32",
- "variant": "esp32",
- "partitions": "partitions/esp32_partition_app2944k_fs10M.csv"
- },
- "connectivity": [
- "wifi",
- "bluetooth",
- "ethernet",
- "can"
- ],
- "debug": {
- "openocd_target": "esp32.cfg"
- },
- "frameworks": [
- "arduino",
- "espidf"
- ],
- "name": "Espressif Generic ESP32 16M Flash, Tasmota 2944k Code/OTA, 10M FS",
- "upload": {
- "flash_size": "16MB",
- "maximum_ram_size": 327680,
- "maximum_size": 16777216,
- "require_upload_port": true,
- "speed": 460800
- },
- "url": "https://en.wikipedia.org/wiki/ESP32",
- "vendor": "Espressif"
-}
diff --git a/boards/esp32_4M_FS.json b/boards/esp32_4M_FS.json
deleted file mode 100644
index c2c7fb2ef..000000000
--- a/boards/esp32_4M_FS.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "build": {
- "arduino":{
- "ldscript": "esp32_out.ld"
- },
- "core": "esp32",
- "extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_4M",
- "f_cpu": "80000000L",
- "f_flash": "40000000L",
- "flash_mode": "dio",
- "mcu": "esp32",
- "variant": "esp32",
- "partitions": "partitions/esp32_partition_app1856k_fs1344k.csv"
- },
- "connectivity": [
- "wifi",
- "bluetooth",
- "ethernet",
- "can"
- ],
- "debug": {
- "openocd_target": "esp32.cfg"
- },
- "frameworks": [
- "arduino",
- "espidf"
- ],
- "name": "Espressif Generic ESP32 4M Flash, Tasmota 2880k Code/OTA, 320k FS",
- "upload": {
- "arduino": {
- "flash_extra_images": [
- [
- "0x10000",
- "variants/tasmota/tasmota32-safeboot.bin"
- ]
- ]
- },
- "flash_size": "4MB",
- "maximum_ram_size": 327680,
- "maximum_size": 4194304,
- "require_upload_port": true,
- "speed": 460800
- },
- "url": "https://en.wikipedia.org/wiki/ESP32",
- "vendor": "Espressif"
- }
diff --git a/boards/esp32_4M_Legacy.json b/boards/esp32_4M_Legacy.json
deleted file mode 100644
index fccad9d15..000000000
--- a/boards/esp32_4M_Legacy.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "build": {
- "arduino":{
- "ldscript": "esp32_out.ld"
- },
- "core": "esp32",
- "extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_4M",
- "f_cpu": "80000000L",
- "f_flash": "40000000L",
- "flash_mode": "dio",
- "mcu": "esp32",
- "variant": "esp32",
- "partitions": "partitions/esp32_partition_app1856k_fs320k.csv"
- },
- "connectivity": [
- "wifi",
- "bluetooth",
- "ethernet",
- "can"
- ],
- "debug": {
- "openocd_target": "esp32.cfg"
- },
- "frameworks": [
- "arduino",
- "espidf"
- ],
- "name": "Espressif Generic ESP32 4M Flash, Tasmota 2880k Code/OTA, 320k FS",
- "upload": {
- "flash_size": "4MB",
- "maximum_ram_size": 327680,
- "maximum_size": 4194304,
- "require_upload_port": true,
- "speed": 460800
- },
- "url": "https://en.wikipedia.org/wiki/ESP32",
- "vendor": "Espressif"
- }
diff --git a/boards/esp32_8M.json b/boards/esp32_8M.json
deleted file mode 100644
index e7a351a4d..000000000
--- a/boards/esp32_8M.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "build": {
- "arduino":{
- "ldscript": "esp32_out.ld"
- },
- "core": "esp32",
- "extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_8M",
- "f_cpu": "80000000L",
- "f_flash": "40000000L",
- "flash_mode": "dio",
- "mcu": "esp32",
- "variant": "esp32",
- "partitions": "partitions/esp32_partition_app2944k_fs2M.csv"
- },
- "connectivity": [
- "wifi",
- "bluetooth",
- "ethernet",
- "can"
- ],
- "debug": {
- "openocd_target": "esp32.cfg"
- },
- "frameworks": [
- "arduino",
- "espidf"
- ],
- "name": "Espressif Generic ESP32 8M Flash, Tasmota 2944k Code/OTA, 2112k FS",
- "upload": {
- "flash_size": "8MB",
- "maximum_ram_size": 327680,
- "maximum_size": 8388608,
- "require_upload_port": true,
- "speed": 460800
- },
- "url": "https://en.wikipedia.org/wiki/ESP32",
- "vendor": "Espressif"
-}
diff --git a/boards/esp32_solo1_4M.json b/boards/esp32_solo1.json
similarity index 79%
rename from boards/esp32_solo1_4M.json
rename to boards/esp32_solo1.json
index ebc5affe9..85b886a55 100644
--- a/boards/esp32_solo1_4M.json
+++ b/boards/esp32_solo1.json
@@ -4,8 +4,8 @@
"ldscript": "esp32_out.ld"
},
"core": "esp32",
- "extra_flags": "-DARDUINO_ESP32_DEV -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_4M -DCORE32SOLO1",
- "f_cpu": "80000000L",
+ "extra_flags": "-DARDUINO_ESP32_DEV -DBOARD_HAS_PSRAM -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_4M -DCORE32SOLO1",
+ "f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",
"mcu": "esp32",
@@ -25,7 +25,7 @@
"arduino",
"espidf"
],
- "name": "Espressif Generic ESP32 4M Flash, Tasmota 2880k Code/OTA, 320k FS",
+ "name": "Espressif Generic ESP32 >= 4M Flash, Tasmota 2880k Code/OTA, 320k FS",
"upload": {
"arduino": {
"flash_extra_images": [
diff --git a/boards/esp32c3.json b/boards/esp32c3.json
index 955589dd3..74a740dee 100644
--- a/boards/esp32c3.json
+++ b/boards/esp32c3.json
@@ -23,7 +23,7 @@
"arduino",
"espidf"
],
- "name": "Espressif Generic ESP32-C3 4M Flash, Tasmota 2880k Code/OTA, 320k FS",
+ "name": "Espressif Generic ESP32-C3 >= 4M Flash, Tasmota 2880k Code/OTA, 320k FS",
"upload": {
"arduino": {
"flash_extra_images": [
diff --git a/boards/esp32c3cdc.json b/boards/esp32c3cdc.json
index 648fce5ec..b29b2ca98 100644
--- a/boards/esp32c3cdc.json
+++ b/boards/esp32c3cdc.json
@@ -23,7 +23,7 @@
"arduino",
"espidf"
],
- "name": "Espressif Generic ESP32-C3 4M Flash, Tasmota 2880k Code/OTA, 320k FS",
+ "name": "Espressif Generic ESP32-C3 >= 4M Flash, Tasmota 2880k Code/OTA, 320k FS",
"upload": {
"arduino": {
"flash_extra_images": [
diff --git a/boards/esp32c3cdc_Legacy.json b/boards/esp32c3cdc_Legacy.json
deleted file mode 100644
index 8a5d88804..000000000
--- a/boards/esp32c3cdc_Legacy.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "build": {
- "arduino":{
- "ldscript": "esp32c3_out.ld"
- },
- "core": "esp32",
- "extra_flags": "-DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=0 -DESP32_4M -DESP32C3 -DUSE_USB_CDC_CONSOLE",
- "f_cpu": "160000000L",
- "f_flash": "80000000L",
- "flash_mode": "dio",
- "mcu": "esp32c3",
- "variant": "esp32c3",
- "partitions": "partitions/esp32_partition_app1856k_fs320k.csv"
- },
- "connectivity": [
- "wifi",
- "bluetooth"
- ],
- "debug": {
- "openocd_target": "esp32c3.cfg"
- },
- "frameworks": [
- "arduino",
- "espidf"
- ],
- "name": "Espressif Generic ESP32-C3 4M Flash, Tasmota 1856k Code/OTA, 320k FS",
- "upload": {
- "flash_size": "4MB",
- "maximum_ram_size": 327680,
- "maximum_size": 4194304,
- "require_upload_port": true,
- "before_reset": "usb_reset",
- "speed": 460800
- },
- "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/hw-reference/esp32c3/user-guide-devkitm-1.html",
- "vendor": "Espressif"
- }
diff --git a/boards/esp32s2.json b/boards/esp32s2.json
index 1fd5f0768..e24ffd17d 100644
--- a/boards/esp32s2.json
+++ b/boards/esp32s2.json
@@ -22,7 +22,7 @@
"espidf",
"arduino"
],
- "name": "Espressif Generic ESP32-S2 4M Flash, Tasmota 2880k Code/OTA, 320k FS",
+ "name": "Espressif Generic ESP32-S2 >= 4M Flash PSRAM, Tasmota 2880k Code/OTA, 320k FS",
"upload": {
"arduino": {
"flash_extra_images": [
diff --git a/boards/esp32s2_Legacy.json b/boards/esp32s2_Legacy.json
deleted file mode 100644
index 9bbae7b88..000000000
--- a/boards/esp32s2_Legacy.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "build": {
- "arduino":{
- "ldscript": "esp32s2_out.ld"
- },
- "core": "esp32",
- "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=0 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DESP32_4M -DESP32S2",
- "f_cpu": "240000000L",
- "f_flash": "80000000L",
- "flash_mode": "dio",
- "mcu": "esp32s2",
- "variant": "esp32s2",
- "partitions": "partitions/esp32_partition_app1856k_fs320k.csv"
- },
- "connectivity": [
- "wifi"
- ],
- "debug": {
- "openocd_target": "esp32s2.cfg"
- },
- "frameworks": [
- "espidf",
- "arduino"
- ],
- "name": "Espressif Generic ESP32-S2 4M Flash, Tasmota 1856k Code/OTA, 320k FS",
- "upload": {
- "flash_size": "4MB",
- "maximum_ram_size": 327680,
- "maximum_size": 4194304,
- "require_upload_port": true,
- "speed": 460800
- },
- "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-saola-1-v1.2.html",
- "vendor": "Espressif"
-}
diff --git a/boards/esp32s2cdc.json b/boards/esp32s2cdc.json
index e71bdbdf6..03be3a6c0 100644
--- a/boards/esp32s2cdc.json
+++ b/boards/esp32s2cdc.json
@@ -22,7 +22,7 @@
"espidf",
"arduino"
],
- "name": "Espressif Generic ESP32-S2 4M Flash, Tasmota 2880k Code/OTA, 320k FS",
+ "name": "Espressif Generic ESP32-S2 >= 4M Flash PSRAM, Tasmota 2880k Code/OTA, 320k FS",
"upload": {
"arduino": {
"flash_extra_images": [
diff --git a/boards/esp32s3_8M.json b/boards/esp32s3-qio_opi.json
similarity index 63%
rename from boards/esp32s3_8M.json
rename to boards/esp32s3-qio_opi.json
index 46dea18ba..003053268 100644
--- a/boards/esp32s3_8M.json
+++ b/boards/esp32s3-qio_opi.json
@@ -2,16 +2,16 @@
"build": {
"arduino":{
"ldscript": "esp32s3_out.ld",
- "memory_type": "qio_qspi"
+ "memory_type": "qio_opi"
},
"core": "esp32",
- "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=0 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DESP32_8M -DESP32S3",
+ "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=0 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DESP32_4M -DESP32S3",
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"mcu": "esp32s3",
"variant": "esp32s3",
- "partitions": "partitions/esp32_partition_app2944k_fs2M.csv"
+ "partitions": "partitions/esp32_partition_app2880k_fs320k.csv"
},
"connectivity": [
"wifi",
@@ -25,11 +25,19 @@
"espidf",
"arduino"
],
- "name": "Espressif Generic ESP32-S3 8M Flash, Tasmota 2944k Code/OTA, 2112k FS",
+ "name": "Espressif Generic ESP32-S3 >= 4M Flash OPI PSRAM, Tasmota 2880k Code/OTA, 320k FS",
"upload": {
- "flash_size": "8MB",
+ "arduino": {
+ "flash_extra_images": [
+ [
+ "0x10000",
+ "variants/tasmota/tasmota32s3-safeboot.bin"
+ ]
+ ]
+ },
+ "flash_size": "4MB",
"maximum_ram_size": 327680,
- "maximum_size": 8388608,
+ "maximum_size": 4194304,
"require_upload_port": true,
"speed": 460800
},
diff --git a/boards/esp32s3.json b/boards/esp32s3-qio_qspi.json
similarity index 92%
rename from boards/esp32s3.json
rename to boards/esp32s3-qio_qspi.json
index df9527c2c..64633ab50 100644
--- a/boards/esp32s3.json
+++ b/boards/esp32s3-qio_qspi.json
@@ -25,7 +25,7 @@
"espidf",
"arduino"
],
- "name": "Espressif Generic ESP32-S3 4M Flash, Tasmota 2880k Code/OTA, 320k FS",
+ "name": "Espressif Generic ESP32-S3 >= 4M Flash QSPI PSRAM, Tasmota 2880k Code/OTA, 320k FS",
"upload": {
"arduino": {
"flash_extra_images": [
diff --git a/boards/esp32s3cdc-box.json b/boards/esp32s3cdc-box.json
deleted file mode 100644
index 5388523be..000000000
--- a/boards/esp32s3cdc-box.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "build": {
- "arduino":{
- "ldscript": "esp32s3_out.ld",
- "memory_type": "qio_opi"
- },
- "core": "esp32",
- "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DUSE_USB_CDC_CONSOLE -DESP32_16M -DESP32S3",
- "f_cpu": "240000000L",
- "f_flash": "80000000L",
- "flash_mode": "qio",
- "mcu": "esp32s3",
- "variant": "esp32s3",
- "partitions": "partitions/esp32_partition_app2944k_fs10M.csv"
- },
- "connectivity": [
- "wifi",
- "bluetooth",
- "ethernet"
- ],
- "debug": {
- "openocd_target": "esp32s3.cfg"
- },
- "frameworks": [
- "espidf",
- "arduino"
- ],
- "name": "Espressif Generic ESP32-S3 16M Flash, Tasmota 2880k Code/OTA, 10M FS",
- "upload": {
- "flash_size": "16MB",
- "maximum_ram_size": 327680,
- "maximum_size": 16777216,
- "require_upload_port": true,
- "before_reset": "usb_reset",
- "speed": 460800
- },
- "url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/",
- "vendor": "Espressif"
-}
-
diff --git a/boards/esp32s3cdc-cam.json b/boards/esp32s3cdc-cam.json
deleted file mode 100644
index 761236e61..000000000
--- a/boards/esp32s3cdc-cam.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "build": {
- "arduino":{
- "ldscript": "esp32s3_out.ld",
- "memory_type": "qio_opi"
- },
- "core": "esp32",
- "extra_flags": "-DCAMERA_MODEL_TTGO_T_CAM_SIM -DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DUSE_USB_CDC_CONSOLE -DESP32_16M -DESP32S3",
- "f_cpu": "240000000L",
- "f_flash": "80000000L",
- "flash_mode": "qio",
- "hwids": [
- [
- "0x303A",
- "0x1001"
- ]
- ],
- "mcu": "esp32s3",
- "variant": "esp32s3",
- "partitions": "partitions/esp32_partition_app2944k_fs10M.csv"
- },
- "connectivity": [
- "wifi",
- "bluetooth",
- "ethernet"
- ],
- "debug": {
- "default_tool": "esp-builtin",
- "onboard_tools": [
- "esp-builtin"
- ],
- "openocd_target": "esp32s3.cfg"
- },
- "frameworks": [
- "espidf",
- "arduino"
- ],
- "name": "LilyGo T-SIMCAM ESP32-S3 16M Flash 8MB OPI PSRAM, Tasmota 2944k Code/OTA, 10M FS",
- "upload": {
- "flash_size": "16MB",
- "maximum_ram_size": 327680,
- "maximum_size": 16777216,
- "require_upload_port": true,
- "before_reset": "usb_reset",
- "speed": 460800
- },
- "url": "https://github.com/Xinyuan-LilyGO/LilyGo-Camera-Series",
- "vendor": "LilyGo"
-}
diff --git a/boards/esp32s3cdc-eye.json b/boards/esp32s3cdc-eye.json
deleted file mode 100644
index 3254a45df..000000000
--- a/boards/esp32s3cdc-eye.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "build": {
- "arduino":{
- "ldscript": "esp32s3_out.ld",
- "memory_type": "qio_opi"
- },
- "core": "esp32",
- "extra_flags": "-DCAMERA_MODEL_ESP32S3_EYE -DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DUSE_USB_CDC_CONSOLE -DESP32_8M -DESP32S3",
- "f_cpu": "240000000L",
- "f_flash": "80000000L",
- "flash_mode": "qio",
- "hwids": [
- [
- "0x303A",
- "0x1001"
- ]
- ],
- "mcu": "esp32s3",
- "variant": "esp32s3",
- "partitions": "partitions/esp32_partition_app2944k_fs2M.csv"
- },
- "connectivity": [
- "wifi",
- "bluetooth",
- "ethernet"
- ],
- "debug": {
- "default_tool": "esp-builtin",
- "onboard_tools": [
- "esp-builtin"
- ],
- "openocd_target": "esp32s3.cfg"
- },
- "frameworks": [
- "espidf",
- "arduino"
- ],
- "name": "ESP32-S3-EYE 8M Flash 8MB OPI PSRAM, Tasmota 2944k Code/OTA, 2M FS",
- "upload": {
- "flash_size": "8MB",
- "maximum_ram_size": 327680,
- "maximum_size": 8388608,
- "require_upload_port": true,
- "before_reset": "usb_reset",
- "speed": 460800
- },
- "url": "https://github.com/espressif/esp-who/blob/master/docs/en/get-started/ESP32-S3-EYE_Getting_Started_Guide.md",
- "vendor": "Espressif"
-}
diff --git a/boards/esp32s3cdc_Legacy.json b/boards/esp32s3cdc-qio_opi.json
similarity index 64%
rename from boards/esp32s3cdc_Legacy.json
rename to boards/esp32s3cdc-qio_opi.json
index 2fe80ff44..f01620ffc 100644
--- a/boards/esp32s3cdc_Legacy.json
+++ b/boards/esp32s3cdc-qio_opi.json
@@ -2,16 +2,22 @@
"build": {
"arduino":{
"ldscript": "esp32s3_out.ld",
- "memory_type": "qio_qspi"
+ "memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DUSE_USB_CDC_CONSOLE -DESP32_4M -DESP32S3",
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
+ "hwids": [
+ [
+ "0x303A",
+ "0x1001"
+ ]
+ ],
"mcu": "esp32s3",
"variant": "esp32s3",
- "partitions": "partitions/esp32_partition_app1856k_fs320k.csv"
+ "partitions": "partitions/esp32_partition_app2880k_fs320k.csv"
},
"connectivity": [
"wifi",
@@ -19,14 +25,26 @@
"ethernet"
],
"debug": {
+ "default_tool": "esp-builtin",
+ "onboard_tools": [
+ "esp-builtin"
+ ],
"openocd_target": "esp32s3.cfg"
},
"frameworks": [
"espidf",
"arduino"
],
- "name": "Espressif Generic ESP32-S3 4M Flash, Tasmota 1856k Code/OTA, 320k FS",
+ "name": "Espressif Generic ESP32-S3 >= 4M Flash OPI PSRAM, Tasmota 2880k Code/OTA, 320k FS",
"upload": {
+ "arduino": {
+ "flash_extra_images": [
+ [
+ "0x10000",
+ "variants/tasmota/tasmota32s3cdc-safeboot.bin"
+ ]
+ ]
+ },
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
diff --git a/boards/esp32s3cdc.json b/boards/esp32s3cdc-qio_qspi.json
similarity index 82%
rename from boards/esp32s3cdc.json
rename to boards/esp32s3cdc-qio_qspi.json
index f4cb53cde..349cbe9ce 100644
--- a/boards/esp32s3cdc.json
+++ b/boards/esp32s3cdc-qio_qspi.json
@@ -9,6 +9,12 @@
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
+ "hwids": [
+ [
+ "0x303A",
+ "0x1001"
+ ]
+ ],
"mcu": "esp32s3",
"variant": "esp32s3",
"partitions": "partitions/esp32_partition_app2880k_fs320k.csv"
@@ -19,13 +25,17 @@
"ethernet"
],
"debug": {
+ "default_tool": "esp-builtin",
+ "onboard_tools": [
+ "esp-builtin"
+ ],
"openocd_target": "esp32s3.cfg"
},
"frameworks": [
"espidf",
"arduino"
],
- "name": "Espressif Generic ESP32-S3 4M Flash, Tasmota 2880k Code/OTA, 320k FS",
+ "name": "Espressif Generic ESP32-S3 >= 4M Flash QSPI PSRAM, Tasmota 2880k Code/OTA, 320k FS",
"upload": {
"arduino": {
"flash_extra_images": [
diff --git a/boards/esp32s3cdc_LilyTDisp.json b/boards/esp32s3cdc_LilyTDisp.json
deleted file mode 100644
index f9a7c0702..000000000
--- a/boards/esp32s3cdc_LilyTDisp.json
+++ /dev/null
@@ -1,47 +0,0 @@
-{
- "build": {
- "arduino":{
- "ldscript": "esp32s3_out.ld",
- "memory_type": "qio_opi"
- },
- "core": "esp32",
- "extra_flags": "-DBOARD_HAS_PSRAM -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MSC_ON_BOOT=0 -DARDUINO_USB_DFU_ON_BOOT=0 -DUSE_USB_CDC_CONSOLE -DESP32_8M -DESP32S3",
- "f_cpu": "240000000L",
- "f_flash": "80000000L",
- "flash_mode": "qio",
- "hwids": [
- [
- "0x303A",
- "0x1001"
- ]
- ],
- "mcu": "esp32s3",
- "variant": "esp32s3",
- "partitions": "partitions/esp32_partition_app2944k_fs10M.csv"
- },
- "connectivity": [
- "wifi",
- "bluetooth",
- "ethernet"
- ],
- "debug": {
- "default_tool": "esp-builtin",
- "onboard_tools": "esp-builtin",
- "openocd_target": "esp32s3.cfg"
- },
- "frameworks": [
- "espidf",
- "arduino"
- ],
- "name": "LilyGo T-Display-S3 16M Flash 8MB OPI PSRAM, Tasmota 2944k Code/OTA, 10M FS",
- "upload": {
- "flash_size": "16MB",
- "maximum_ram_size": 327680,
- "maximum_size": 16777216,
- "require_upload_port": true,
- "before_reset": "usb_reset",
- "speed": 460800
- },
- "url": "https://github.com/Xinyuan-LilyGO/T-Display-S3",
- "vendor": "LilyGo"
- }
diff --git a/lib/default/Ext-printf/src/ext_printf.cpp b/lib/default/Ext-printf/src/ext_printf.cpp
index d15f4bcee..df9204e3e 100644
--- a/lib/default/Ext-printf/src/ext_printf.cpp
+++ b/lib/default/Ext-printf/src/ext_printf.cpp
@@ -208,9 +208,12 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
// get a fresh malloc allocated string based on the current pointer (can be in PROGMEM)
// It is the caller's responsibility to free the memory
+//
+// Returns nullptr if something went wrong
char * copyStr(const char * str) {
if (str == nullptr) { return nullptr; }
char * cpy = (char*) malloc(strlen_P(str) + 1);
+ if (cpy == nullptr) { return nullptr; } // something went wrong
strcpy_P(cpy, str);
return cpy;
}
@@ -224,8 +227,10 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
// iterate on fmt to extract arguments and patch them in place
char * fmt_cpy = copyStr(fmt_P);
- if (fmt_cpy == nullptr) { return 0; }
+ if (fmt_cpy == nullptr) { return 0; } // we couldn't copy the format, abort
char * fmt = fmt_cpy;
+ int32_t ret = 0; // return 0 if unsuccessful
+ bool aborted = true; // did something went wrong?
const uint32_t ALLOC_SIZE = 12;
static const char * allocs[ALLOC_SIZE] = {}; // initialized to zeroes
@@ -277,6 +282,7 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
if (cur_val < min_valid_ptr) { new_val_str = ext_invalid_mem; }
else if (decimals > 0) {
char * hex_char = (char*) malloc(decimals*2 + 2);
+ if (hex_char == nullptr) { goto free_allocs; }
ToHex_P((const uint8_t *)cur_val, decimals, hex_char, decimals*2 + 2);
new_val_str = hex_char;
allocs[alloc_idx++] = new_val_str;
@@ -292,6 +298,7 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
size_t buf_len = (&buf != nullptr) ? buf.len() : 0;
if (buf_len) {
char * hex_char = (char*) malloc(buf_len*2 + 2);
+ if (hex_char == nullptr) { goto free_allocs; }
ToHex_P(buf.getBuffer(), buf_len, hex_char, buf_len*2 + 2);
new_val_str = hex_char;
allocs[alloc_idx++] = new_val_str;
@@ -299,6 +306,28 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
}
}
break;
+/*
+ case 'V': // 2-byte values, decimals indicates the length, default 2
+ {
+ if (decimals < 0) { decimals = 0; }
+ if (cur_val < min_valid_ptr) { new_val_str = ext_invalid_mem; }
+ else if (decimals > 0) {
+ uint32_t val_size = decimals*6 + 2;
+ char * val_char = (char*) malloc(val_size);
+ if (val_char == nullptr) { goto free_allocs; }
+ val_char[0] = '\0';
+ for (uint32_t count = 0; count < decimals; count++) {
+ uint32_t value = pgm_read_byte((const uint8_t *)cur_val +1) << 8 | pgm_read_byte((const uint8_t *)cur_val);
+ snprintf_P(val_char, val_size, PSTR("%s%s%d"), val_char, (count)?",":"", value);
+ cur_val += 2;
+ }
+ new_val_str = val_char;
+ allocs[alloc_idx++] = new_val_str;
+ // Serial.printf("> values=%s\n", hex_char);
+ }
+ }
+ break;
+*/
// case 'D':
// decimals = *(int32_t*)cur_val_ptr;
// break;
@@ -307,6 +336,7 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
case 'I': // Input is `uint32_t` 32 bits IP address, output is decimal dotted address
{
char * ip_str = (char*) malloc(16);
+ if (ip_str == nullptr) { goto free_allocs; }
snprintf_P(ip_str, 16, PSTR("%u.%u.%u.%u"), cur_val & 0xFF, (cur_val >> 8) & 0xFF, (cur_val >> 16) & 0xFF, (cur_val >> 24) & 0xFF);
new_val_str = ip_str;
allocs[alloc_idx++] = new_val_str;
@@ -350,6 +380,7 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
}
}
new_val_str = copyStr(hex);
+ if (new_val_str == nullptr) { goto free_allocs; }
allocs[alloc_idx++] = new_val_str;
}
}
@@ -363,24 +394,11 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
if ((decimals < 0) || (decimals > 16)) { decimals = 16; }
U64toHex(*(uint64_t*)cur_val, hex, decimals);
new_val_str = copyStr(hex);
+ if (new_val_str == nullptr) { goto free_allocs; }
allocs[alloc_idx++] = new_val_str;
}
}
break;
- // Trying to do String allocation alternatives, but not as interesting as I thought in the beginning
- // case 's':
- // {
- // new_val_str = copyStr(((String*)cur_val)->c_str());
- // allocs[alloc_idx++] = new_val_str;
- // }
- // break;
- // case 'S':
- // {
- // funcString_t * func_str = (funcString_t*) cur_val;
- // new_val_str = copyStr((*func_str)().c_str());
- // allocs[alloc_idx++] = new_val_str;
- // }
- // break;
}
*cur_val_ptr = new_val_str;
*fmt = 's'; // replace `%_X` with `%0s` to display a string instead
@@ -392,9 +410,9 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
}
}
// Serial.printf("> format_final=%s\n", fmt_cpy); Serial.flush();
- int32_t ret = 0; // return 0 if unsuccessful
if (out_buf != nullptr) {
ret = vsnprintf_P(out_buf, buf_len, fmt_cpy, va_cpy);
+ aborted = false; // we completed without malloc error
} else {
// if there is no output buffer, we allocate one on the heap
// first we do a dry-run to know the target size
@@ -407,12 +425,18 @@ int32_t ext_vsnprintf_P(char * out_buf, size_t buf_len, const char * fmt_P, va_l
allocated_buf[0] = 0; // default to empty string
vsnprintf_P(allocated_buf, target_len + 1, fmt_cpy, va_cpy);
ret = (int32_t) allocated_buf;
+ aborted = false; // we completed without malloc error
}
}
}
va_end(va_cpy);
+free_allocs:
+ if (aborted && out_buf != nullptr) { // if something went wrong, set output string to empty string to avoid corrupt data
+ *out_buf = '\0';
+ }
+
// disallocated all temporary strings
for (uint32_t i = 0; i < alloc_idx; i++) {
free((void*)allocs[i]); // it is ok to call free() on nullptr so we don't test for nullptr first
diff --git a/lib/default/TasmotaSerial-3.5.0/README.md b/lib/default/TasmotaSerial-3.6.0/README.md
similarity index 100%
rename from lib/default/TasmotaSerial-3.5.0/README.md
rename to lib/default/TasmotaSerial-3.6.0/README.md
diff --git a/lib/default/TasmotaSerial-3.5.0/examples/swsertest/swsertest.ino b/lib/default/TasmotaSerial-3.6.0/examples/swsertest/swsertest.ino
similarity index 100%
rename from lib/default/TasmotaSerial-3.5.0/examples/swsertest/swsertest.ino
rename to lib/default/TasmotaSerial-3.6.0/examples/swsertest/swsertest.ino
diff --git a/lib/default/TasmotaSerial-3.5.0/keywords.txt b/lib/default/TasmotaSerial-3.6.0/keywords.txt
similarity index 100%
rename from lib/default/TasmotaSerial-3.5.0/keywords.txt
rename to lib/default/TasmotaSerial-3.6.0/keywords.txt
diff --git a/lib/default/TasmotaSerial-3.5.0/library.json b/lib/default/TasmotaSerial-3.6.0/library.json
similarity index 94%
rename from lib/default/TasmotaSerial-3.5.0/library.json
rename to lib/default/TasmotaSerial-3.6.0/library.json
index 45c0c4508..aa1fda280 100644
--- a/lib/default/TasmotaSerial-3.5.0/library.json
+++ b/lib/default/TasmotaSerial-3.6.0/library.json
@@ -1,6 +1,6 @@
{
"name": "TasmotaSerial",
- "version": "3.5.0",
+ "version": "3.6.0",
"keywords": [
"serial", "io", "TasmotaSerial"
],
diff --git a/lib/default/TasmotaSerial-3.5.0/library.properties b/lib/default/TasmotaSerial-3.6.0/library.properties
similarity index 94%
rename from lib/default/TasmotaSerial-3.5.0/library.properties
rename to lib/default/TasmotaSerial-3.6.0/library.properties
index 759c7f39d..3f6d5c133 100644
--- a/lib/default/TasmotaSerial-3.5.0/library.properties
+++ b/lib/default/TasmotaSerial-3.6.0/library.properties
@@ -1,5 +1,5 @@
name=TasmotaSerial
-version=3.5.0
+version=3.6.0
author=Theo Arends
maintainer=Theo Arends
sentence=Implementation of software serial with hardware serial fallback for ESP8266 and ESP32.
diff --git a/lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.cpp b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp
similarity index 70%
rename from lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.cpp
rename to lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp
index 99dc6caeb..7e960b05c 100644
--- a/lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.cpp
+++ b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.cpp
@@ -46,14 +46,18 @@ static uint32_t tasmota_serial_uart_bitmap = 0; // Assigned UARTs
TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fallback, int nwmode, int buffer_size) {
m_valid = false;
+ m_tx_enable_valid = false;
m_hardserial = false;
m_hardswap = false;
+ m_overflow = false;
+ m_data_bits = 8;
m_stop_bits = 1;
m_nwmode = nwmode;
serial_buffer_size = buffer_size;
m_rx_pin = receive_pin;
m_tx_pin = transmit_pin;
- m_in_pos = m_out_pos = 0;
+ m_in_pos = 0;
+ m_out_pos = 0;
#ifdef ESP8266
if (!((isValidGPIOpin(receive_pin)) && (isValidGPIOpin(transmit_pin) || transmit_pin == 16))) {
return;
@@ -95,7 +99,7 @@ TasmotaSerial::TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fal
void TasmotaSerial::end(bool turnOffDebug) {
#ifdef ESP8266
if (m_hardserial) {
- Serial.end();
+// Serial.end(); // Keep active for logging
} else {
if (m_rx_pin > -1) {
detachInterrupt(m_rx_pin);
@@ -120,7 +124,23 @@ TasmotaSerial::~TasmotaSerial(void) {
}
bool TasmotaSerial::isValidGPIOpin(int pin) {
+#ifdef ESP8266
return (pin >= -1 && pin <= 5) || (pin >= 12 && pin <= 15);
+#endif
+#ifdef ESP32
+ return GPIO_IS_VALID_OUTPUT_GPIO(pin);
+#endif
+}
+
+void TasmotaSerial::setTransmitEnablePin(int tx_enable_pin) {
+ if ((tx_enable_pin > -1) && isValidGPIOpin(tx_enable_pin)) {
+ m_tx_enable_valid = true;
+ m_tx_enable_pin = tx_enable_pin;
+ pinMode(m_tx_enable_pin, OUTPUT);
+ digitalWrite(m_tx_enable_pin, LOW);
+ } else {
+ m_tx_enable_valid = false;
+ }
}
#ifdef ESP32
@@ -134,12 +154,70 @@ bool TasmotaSerial::freeUart(void) {
}
return false;
}
+
+void TasmotaSerial::Esp32Begin(void) {
+ TSerial->begin(m_speed, m_config, m_rx_pin, m_tx_pin);
+ // For low bit rate, below 9600, set the Full RX threshold at 10 bytes instead of the default 120
+ if (m_speed <= 9600) {
+ // At 9600, 10 chars are ~10ms
+ uart_set_rx_full_threshold(m_uart, 10);
+ } else if (m_speed < 115200) {
+ // At 19200, 120 chars are ~60ms
+ // At 76800, 120 chars are ~15ms
+ uart_set_rx_full_threshold(m_uart, 120);
+ } else {
+ // At 115200, 256 chars are ~20ms
+ // Zigbee requires to keep frames together, i.e. 256 bytes max
+ uart_set_rx_full_threshold(m_uart, 256);
+ }
+ // For bitrate below 115200, set the Rx time out to 6 chars instead of the default 10
+ if (m_speed < 115200) {
+ // At 76800 the timeout is ~1ms
+ uart_set_rx_timeout(m_uart, 6);
+ }
+}
#endif
+size_t TasmotaSerial::setRxBufferSize(size_t size) {
+ if (size != serial_buffer_size) {
+ if (m_hardserial) {
+ if (size > 256) { // Default hardware serial Rx buffer size
+#ifdef ESP8266
+ serial_buffer_size = size;
+ Serial.setRxBufferSize(serial_buffer_size);
+#endif // ESP8266
+#ifdef ESP32
+ if (TSerial) {
+ // RX Buffer can't be resized when Serial is already running
+ serial_buffer_size = size;
+ TSerial->flush();
+ TSerial->end();
+ delay(10); // Allow time to cleanup queues - if not used hangs ESP32
+ TSerial->setRxBufferSize(serial_buffer_size);
+ Esp32Begin();
+ }
+#endif // ESP32
+ }
+ }
+ else if (m_buffer) {
+ uint8_t *m_buffer_temp = (uint8_t*)malloc(size); // Allocate new buffer
+ if (m_buffer_temp) { // If succesful de-allocate old buffer
+ free(m_buffer);
+ m_buffer = m_buffer_temp;
+ serial_buffer_size = size;
+ }
+ }
+ }
+ return serial_buffer_size;
+}
+
bool TasmotaSerial::begin(uint32_t speed, uint32_t config) {
if (!m_valid) { return false; }
if (m_hardserial) {
+ if (serial_buffer_size < 256) {
+ serial_buffer_size = 256;
+ }
#ifdef ESP8266
Serial.flush();
Serial.begin(speed, (SerialConfig)config);
@@ -157,10 +235,10 @@ bool TasmotaSerial::begin(uint32_t speed, uint32_t config) {
TSerial = new HardwareSerial(m_uart);
#else
if (0 == m_uart) {
- Serial.flush();
- Serial.end();
- delay(10); // Allow time to cleanup queues - if not used hangs ESP32
- TSerial = &Serial;
+ Serial.flush();
+ Serial.end();
+ delay(10); // Allow time to cleanup queues - if not used hangs ESP32
+ TSerial = &Serial;
} else {
TSerial = new HardwareSerial(m_uart);
}
@@ -173,34 +251,23 @@ bool TasmotaSerial::begin(uint32_t speed, uint32_t config) {
return m_valid; // As we currently only support hardware serial on ESP32 it's safe to exit here
}
}
- TSerial->begin(speed, config, m_rx_pin, m_tx_pin);
- // For low bit rate, below 9600, set the Full RX threshold at 10 bytes instead of the default 120
- if (speed <= 9600) {
- // At 9600, 10 chars are ~10ms
- uart_set_rx_full_threshold(m_uart, 10);
- } else if (speed < 115200) {
- // At 19200, 120 chars are ~60ms
- // At 76800, 120 chars are ~15ms
- uart_set_rx_full_threshold(m_uart, 120);
- } else {
- // At 115200, 256 chars are ~20ms
- // Zigbee requires to keep frames together, i.e. 256 bytes max
- uart_set_rx_full_threshold(m_uart, 256);
- }
- // For bitrate below 115200, set the Rx time out to 6 chars instead of the default 10
- if (speed < 115200) {
- // At 76800 the timeout is ~1ms
- uart_set_rx_timeout(m_uart, 6);
- }
+ m_speed = speed;
+ m_config = config;
+ Esp32Begin();
// Serial.printf("TSR: Using UART%d\n", m_uart);
#endif // ESP32
} else {
+ // #define UART_NB_BIT_5 0B00000000
+ // #define UART_NB_BIT_6 0B00000100
+ // #define UART_NB_BIT_7 0B00001000
+ // #define UART_NB_BIT_8 0B00001100
+ m_data_bits = 5 + ((config &0x0C) >> 2);
// Software serial fakes two stop bits if either stop bits is 2 or parity is not None
// #define UART_NB_STOP_BIT_0 0B00000000
// #define UART_NB_STOP_BIT_1 0B00010000
// #define UART_NB_STOP_BIT_15 0B00100000
// #define UART_NB_STOP_BIT_2 0B00110000
- m_stop_bits = ((config &0x30) >> 5) +1;
+ m_stop_bits = 1 + ((config &0x30) >> 5);
// #define UART_PARITY_NONE 0B00000000
// #define UART_PARITY_EVEN 0B00000010
// #define UART_PARITY_ODD 0B00000011
@@ -216,6 +283,10 @@ bool TasmotaSerial::begin(uint32_t speed, uint32_t config) {
return m_valid;
}
+void TasmotaSerial::setReadChunkMode(bool mode) {
+ m_very_high_speed = mode;
+}
+
bool TasmotaSerial::hardwareSerial(void) {
#ifdef ESP8266
return m_hardserial;
@@ -225,6 +296,21 @@ bool TasmotaSerial::hardwareSerial(void) {
#endif // ESP32
}
+bool TasmotaSerial::overflow(void) {
+ if (m_hardserial) {
+#ifdef ESP8266
+ return Serial.hasOverrun(); // Returns then clear overrun flag
+#endif // ESP8266
+#ifdef ESP32
+ return false; // Not implemented
+#endif // ESP32
+ } else {
+ bool res = m_overflow;
+ m_overflow = false;
+ return res;
+ }
+}
+
void TasmotaSerial::flush(void) {
if (m_hardserial) {
#ifdef ESP8266
@@ -235,7 +321,8 @@ void TasmotaSerial::flush(void) {
while (TSerial->available()) { TSerial->read(); }
#endif // ESP32
} else {
- m_in_pos = m_out_pos = 0;
+ m_in_pos = 0;
+ m_out_pos = 0;
}
}
@@ -262,7 +349,9 @@ int TasmotaSerial::read(void) {
return TSerial->read();
#endif // ESP32
} else {
- if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) return -1;
+ if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) {
+ return -1;
+ }
uint32_t ch = m_buffer[m_out_pos];
m_out_pos = (m_out_pos +1) % serial_buffer_size;
return ch;
@@ -278,9 +367,11 @@ size_t TasmotaSerial::read(char* buffer, size_t size) {
return TSerial->read(buffer, size);
#endif // ESP32
} else {
- if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) { return 0; }
+ if ((-1 == m_rx_pin) || (m_in_pos == m_out_pos)) {
+ return 0;
+ }
size_t count = 0;
- for( ; size && (m_in_pos == m_out_pos) ; --size, ++count) {
+ for( ; size && (m_in_pos != m_out_pos) ; --size, ++count) {
*buffer++ = m_buffer[m_out_pos];
m_out_pos = (m_out_pos +1) % serial_buffer_size;
}
@@ -299,13 +390,18 @@ int TasmotaSerial::available(void) {
} else {
int avail = m_in_pos - m_out_pos;
if (avail < 0) avail += serial_buffer_size;
+
+// if (!avail) {
+// optimistic_yield(10000);
+// }
+
return avail;
}
}
-#define TM_SERIAL_WAIT_SND { while (ESP.getCycleCount() < (wait + start)) if (!m_high_speed) optimistic_yield(1); wait += m_bit_time; } // Watchdog timeouts
+#define TM_SERIAL_WAIT_SND { while (ESP.getCycleCount() < (wait + start)) if (!m_high_speed) optimistic_yield(1); wait += m_bit_time; } // Watchdog timeouts
#define TM_SERIAL_WAIT_SND_FAST { while (ESP.getCycleCount() < (wait + start)); wait += m_bit_time; }
-#define TM_SERIAL_WAIT_RCV { while (ESP.getCycleCount() < (wait + start)); wait += m_bit_time; }
+#define TM_SERIAL_WAIT_RCV { while (ESP.getCycleCount() < (wait + start)); wait += m_bit_time; }
#define TM_SERIAL_WAIT_RCV_LOOP { while (ESP.getCycleCount() < (wait + start)); }
void IRAM_ATTR TasmotaSerial::_fast_write(uint8_t b) {
@@ -314,7 +410,7 @@ void IRAM_ATTR TasmotaSerial::_fast_write(uint8_t b) {
// Start bit;
digitalWrite(m_tx_pin, LOW);
TM_SERIAL_WAIT_SND_FAST;
- for (uint32_t i = 0; i < 8; i++) {
+ for (uint32_t i = 0; i < m_data_bits; i++) {
digitalWrite(m_tx_pin, (b & 1) ? HIGH : LOW);
TM_SERIAL_WAIT_SND_FAST;
b >>= 1;
@@ -327,15 +423,20 @@ void IRAM_ATTR TasmotaSerial::_fast_write(uint8_t b) {
}
size_t TasmotaSerial::write(uint8_t b) {
+ if (!m_hardserial && (-1 == m_tx_pin)) { return 0; }
+
+ if (m_tx_enable_valid) {
+ digitalWrite(m_tx_enable_pin, HIGH);
+ }
+ size_t size = 0;
if (m_hardserial) {
#ifdef ESP8266
- return Serial.write(b);
+ size = Serial.write(b);
#endif // ESP8266
#ifdef ESP32
- return TSerial->write(b);
+ size = TSerial->write(b);
#endif // ESP32
} else {
- if (-1 == m_tx_pin) return 0;
if (m_high_speed) {
cli(); // Disable interrupts in order to get a clean transmit
_fast_write(b);
@@ -347,7 +448,7 @@ size_t TasmotaSerial::write(uint8_t b) {
// Start bit;
digitalWrite(m_tx_pin, LOW);
TM_SERIAL_WAIT_SND;
- for (uint32_t i = 0; i < 8; i++) {
+ for (uint32_t i = 0; i < m_data_bits; i++) {
digitalWrite(m_tx_pin, (b & 1) ? HIGH : LOW);
TM_SERIAL_WAIT_SND;
b >>= 1;
@@ -359,30 +460,42 @@ size_t TasmotaSerial::write(uint8_t b) {
TM_SERIAL_WAIT_SND;
}
}
-
- return 1;
+ size = 1;
}
+ if (m_tx_enable_valid) {
+ digitalWrite(m_tx_enable_pin, LOW);
+ }
+ return size;
}
void IRAM_ATTR TasmotaSerial::rxRead(void) {
if (!m_nwmode) {
- int32_t loop_read = m_very_high_speed ? serial_buffer_size : 1;
+ uint32_t start = ESP.getCycleCount();
// Advance the starting point for the samples but compensate for the
// initial delay which occurs before the interrupt is delivered
uint32_t wait = m_bit_start_time;
- uint32_t start = ESP.getCycleCount();
- while (loop_read-- > 0) { // try to receveive all consecutive bytes in a raw
+ // Decide to read as much data as buffer can hold or a single byte
+ // The first option may keep interrupt busy too long resulting in Hardware Watchdog
+ // The second option may receive ocasional invalid data
+ // User control by function setReadChunkMode()
+ int32_t loop_read = m_very_high_speed ? serial_buffer_size : 1;
+ uint32_t bit_mask = 0x01 << (m_data_bits -1);
+ while (loop_read-- > 0) { // try to receive all consecutive bytes in a row
uint32_t rec = 0;
- for (uint32_t i = 0; i < 8; i++) {
+ for (uint32_t i = 0; i < m_data_bits; i++) {
TM_SERIAL_WAIT_RCV;
rec >>= 1;
- if (digitalRead(m_rx_pin)) rec |= 0x80;
+ if (digitalRead(m_rx_pin)) rec |= bit_mask;
}
// Store the received value in the buffer unless we have an overflow
- uint32_t next = (m_in_pos+1) % serial_buffer_size;
- if (next != (int)m_out_pos) {
+ uint32_t next = (m_in_pos + 1) % serial_buffer_size;
+ if (next != m_out_pos) {
m_buffer[m_in_pos] = rec;
m_in_pos = next;
+ } else {
+ // Buffer overrun - exit
+ m_overflow = true;
+ loop_read = 0;
}
TM_SERIAL_WAIT_RCV_LOOP; // wait for stop bit
@@ -415,6 +528,7 @@ void IRAM_ATTR TasmotaSerial::rxRead(void) {
// it gets set even when interrupts are disabled
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, 1 << m_rx_pin);
} else {
+ // Currently supports 8-bit data only
uint32_t diff;
uint32_t level;
@@ -444,7 +558,7 @@ void IRAM_ATTR TasmotaSerial::rxRead(void) {
}
//stobyte(0,ssp->ss_byte>>1);
uint32_t next = (m_in_pos + 1) % serial_buffer_size;
- if (next != (uint32_t)m_out_pos) {
+ if (next != m_out_pos) {
m_buffer[m_in_pos] = ss_byte >> 1;
m_in_pos = next;
}
@@ -458,7 +572,7 @@ void IRAM_ATTR TasmotaSerial::rxRead(void) {
// bit zero was 0,
//stobyte(0,ssp->ss_byte>>1);
uint32_t next = (m_in_pos + 1) % serial_buffer_size;
- if (next != (uint32_t)m_out_pos) {
+ if (next != m_out_pos) {
m_buffer[m_in_pos] = ss_byte >> 1;
m_in_pos = next;
}
diff --git a/lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.h b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.h
similarity index 82%
rename from lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.h
rename to lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.h
index f0ff57cd2..cf93f3443 100644
--- a/lib/default/TasmotaSerial-3.5.0/src/TasmotaSerial.h
+++ b/lib/default/TasmotaSerial-3.6.0/src/TasmotaSerial.h
@@ -39,6 +39,10 @@ class TasmotaSerial : public Stream {
public:
TasmotaSerial(int receive_pin, int transmit_pin, int hardware_fallback = 0, int nwmode = 0, int buffer_size = TM_SERIAL_BUFFER_SIZE);
virtual ~TasmotaSerial();
+ void setTransmitEnablePin(int tx_enable_pin);
+
+ size_t setRxBufferSize(size_t size);
+ size_t getRxBufferSize() { return serial_buffer_size; }
bool begin(uint32_t speed = TM_SERIAL_BAUDRATE, uint32_t config = SERIAL_8N1);
void end(bool turnOffDebug = true);
@@ -48,6 +52,10 @@ class TasmotaSerial : public Stream {
size_t write(uint8_t byte) override;
int read(void) override;
size_t read(char* buffer, size_t size);
+ size_t read(uint8_t* buffer, size_t size) {
+ return read(reinterpret_cast(buffer), size);
+ }
+ void setReadChunkMode(bool mode);
int available(void) override;
void flush(void) override;
@@ -57,20 +65,25 @@ class TasmotaSerial : public Stream {
#ifdef ESP32
uint32_t getUart(void) const { return m_uart; }
#endif
- bool isValid() { return m_valid; }
+ bool isValid(void) { return m_valid; }
+ bool overflow(void);
using Print::write;
private:
bool isValidGPIOpin(int pin);
+ size_t txWrite(uint8_t byte);
+ void _fast_write(uint8_t b); // IRAM minimized version
#ifdef ESP32
bool freeUart(void);
+ void Esp32Begin(void);
#endif
- size_t txWrite(uint8_t byte);
// Member variables
int m_rx_pin;
int m_tx_pin;
+ int m_tx_enable_pin;
+ uint32_t m_data_bits;
uint32_t m_stop_bits;
uint32_t ss_byte;
uint32_t ss_bstart;
@@ -80,18 +93,19 @@ class TasmotaSerial : public Stream {
uint32_t m_bit_follow_metric = 0;
uint32_t m_in_pos;
uint32_t m_out_pos;
- uint32_t serial_buffer_size;
+ uint32_t serial_buffer_size = TM_SERIAL_BUFFER_SIZE;
bool m_valid;
+ bool m_tx_enable_valid;
bool m_nwmode;
bool m_hardserial;
bool m_hardswap;
+ bool m_overflow;
bool m_high_speed = false;
bool m_very_high_speed = false; // above 100000 bauds
- uint8_t *m_buffer;
-
- void _fast_write(uint8_t b); // IRAM minimized version
-
+ uint8_t *m_buffer = nullptr;
#ifdef ESP32
+ uint32_t m_speed;
+ uint32_t m_config;
HardwareSerial *TSerial;
int m_uart = 0;
#endif
diff --git a/lib/libesp32/esp32-camera/driver/include/camera_pins.h b/lib/default/headers/camera_pins.h
similarity index 100%
rename from lib/libesp32/esp32-camera/driver/include/camera_pins.h
rename to lib/default/headers/camera_pins.h
diff --git a/lib/default/jsmn-shadinger-1.0/src/JsonParser.cpp b/lib/default/jsmn-shadinger-1.0/src/JsonParser.cpp
index 0668faa1a..22229e3f1 100644
--- a/lib/default/jsmn-shadinger-1.0/src/JsonParser.cpp
+++ b/lib/default/jsmn-shadinger-1.0/src/JsonParser.cpp
@@ -370,6 +370,9 @@ uint64_t JsonParserToken::getULong(void) const { return getULong(0); }
float JsonParserToken::getFloat(void) const { return getFloat(0); }
const char * JsonParserToken::getStr(void) const { return getStr(""); }
+bool JsonParserObject::getBool(const char * needle, bool val) const {
+ return (*this)[needle].getBool(val);
+}
int32_t JsonParserObject::getInt(const char * needle, int32_t val) const {
return (*this)[needle].getInt(val);
}
diff --git a/lib/default/jsmn-shadinger-1.0/src/JsonParser.h b/lib/default/jsmn-shadinger-1.0/src/JsonParser.h
index 03a0aba65..9d61044fd 100644
--- a/lib/default/jsmn-shadinger-1.0/src/JsonParser.h
+++ b/lib/default/jsmn-shadinger-1.0/src/JsonParser.h
@@ -162,6 +162,7 @@ public:
const char * findConstCharNull(const char * needle) const;
// all-in-one methods: search for key (case insensitive), convert value and set default
+ bool getBool(const char *, bool val) const;
int32_t getInt(const char *, int32_t) const;
uint32_t getUInt(const char *, uint32_t) const;
uint64_t getULong(const char *, uint64_t) const;
diff --git a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp
index 95db697f5..25ea7caaf 100644
--- a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp
+++ b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp
@@ -27,8 +27,9 @@ enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_D
//#define TASMOTAMODBUSDEBUG
-TasmotaModbus::TasmotaModbus(int receive_pin, int transmit_pin) : TasmotaSerial(receive_pin, transmit_pin, 1)
+TasmotaModbus::TasmotaModbus(int receive_pin, int transmit_pin, int tx_enable_pin) : TasmotaSerial(receive_pin, transmit_pin, 1)
{
+ setTransmitEnablePin(tx_enable_pin);
mb_address = 0;
}
@@ -91,7 +92,7 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1
}
else if ((function_code == 5) || (function_code == 6))
{
- if (write_data == NULL)
+ if (write_data == NULL)
{
free(frame);
return 13; // Register data not specified
@@ -108,10 +109,10 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1
{
frame[framepointer++] = (uint8_t)(count >> 8); // MSB
frame[framepointer++] = (uint8_t)(count); // LSB
-
+
frame[framepointer++] = byte_count;
- if (write_data == NULL)
+ if (write_data == NULL)
{
free(frame);
return 13; // Register data not specified
@@ -126,7 +127,7 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1
frame[framepointer++] = (uint8_t)(write_data[bytepointer/2] >> (bytepointer % 2 ? 0 : 8)); // MSB, LSB, MSB ....
}
}
- else
+ else
{
free(frame);
return 1; // Wrong function code
@@ -136,7 +137,7 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1
frame[framepointer++] = (uint8_t)(crc);
frame[framepointer++] = (uint8_t)(crc >> 8);
-#ifdef TASMOTAMODBUSDEBUG
+#ifdef TASMOTAMODBUSDEBUG
uint8_t *buf;
uint16_t bufsize=(framepointer + 1) * 3;
buf = (uint8_t *)malloc(bufsize);
@@ -147,7 +148,7 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: %s"), buf);
free(buf);
#endif
-
+
flush();
write(frame, framepointer);
free(frame);
@@ -213,7 +214,7 @@ uint8_t TasmotaModbus::ReceiveBuffer(uint8_t *buffer, uint8_t register_count, ui
// 10 = Gateway Path Unavailable
// 11 = Gateway Target device failed to respond
}
-
+
if (mb_len < 6) { return 7; } // 7 = Not enough data
/*
diff --git a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.h b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.h
index 520bb166d..ced5fb969 100644
--- a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.h
+++ b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.h
@@ -27,7 +27,7 @@
class TasmotaModbus : public TasmotaSerial {
public:
- TasmotaModbus(int receive_pin, int transmit_pin);
+ TasmotaModbus(int receive_pin, int transmit_pin, int tx_enable_pin = -1);
virtual ~TasmotaModbus() {}
int Begin(long speed = TM_MODBUS_BAUDRATE, uint32_t config = SERIAL_8N1);
diff --git a/lib/lib_display/Display_Renderer-gemu-1.0/src/font24_7seg.c b/lib/lib_display/Display_Renderer-gemu-1.0/src/font24_7seg.c
index 1844fc6cf..a4d740b09 100644
--- a/lib/lib_display/Display_Renderer-gemu-1.0/src/font24_7seg.c
+++ b/lib/lib_display/Display_Renderer-gemu-1.0/src/font24_7seg.c
@@ -41,712 +41,712 @@
const uint8_t Font24_Table_7seg [] PROGMEM =
{
- // @0 ' ' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+ // @0 ' ' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @72 '!' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x03,0x80,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x01,0x00,0x00, // #
- 0x01,0x00,0x00, // #
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x03,0x80,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @72 '!' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x07,0x00, // ###
+ 0x07,0x00, // ###
+ 0x07,0x00, // ###
+ 0x07,0x00, // ###
+ 0x07,0x00, // ###
+ 0x07,0x00, // ###
+ 0x07,0x00, // ###
+ 0x07,0x00, // ###
+ 0x07,0x00, // ###
+ 0x02,0x00, // #
+ 0x02,0x00, // #
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x07,0x00, // ###
+ 0x07,0x00, // ###
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @144 '"' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x0e,0x70,0x00, // ### ###
- 0x0e,0x70,0x00, // ### ###
- 0x0e,0x70,0x00, // ### ###
- 0x04,0x20,0x00, // # #
- 0x04,0x20,0x00, // # #
- 0x04,0x20,0x00, // # #
- 0x04,0x20,0x00, // # #
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @144 '"' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x1C,0xE0, // ### ###
+ 0x1C,0xE0, // ### ###
+ 0x1C,0xE0, // ### ###
+ 0x08,0x40, // # #
+ 0x08,0x40, // # #
+ 0x08,0x40, // # #
+ 0x08,0x40, // # #
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @216 '#' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x06,0x60,0x00, // ## ##
- 0x06,0x60,0x00, // ## ##
- 0x06,0x60,0x00, // ## ##
- 0x06,0x60,0x00, // ## ##
- 0x06,0x60,0x00, // ## ##
- 0x3f,0xf8,0x00, // ###########
- 0x3f,0xf8,0x00, // ###########
- 0x06,0x60,0x00, // ## ##
- 0x0c,0xc0,0x00, // ## ##
- 0x3f,0xf8,0x00, // ###########
- 0x3f,0xf8,0x00, // ###########
- 0x0c,0xc0,0x00, // ## ##
- 0x0c,0xc0,0x00, // ## ##
- 0x0c,0xc0,0x00, // ## ##
- 0x0c,0xc0,0x00, // ## ##
- 0x0c,0xc0,0x00, // ## ##
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @216 '#' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x0C,0xC0, // ## ##
+ 0x0C,0xC0, // ## ##
+ 0x0C,0xC0, // ## ##
+ 0x0C,0xC0, // ## ##
+ 0x0C,0xC0, // ## ##
+ 0x7F,0xF0, // ###########
+ 0x7F,0xF0, // ###########
+ 0x0C,0xC0, // ## ##
+ 0x19,0x80, // ## ##
+ 0x7F,0xF0, // ###########
+ 0x7F,0xF0, // ###########
+ 0x19,0x80, // ## ##
+ 0x19,0x80, // ## ##
+ 0x19,0x80, // ## ##
+ 0x19,0x80, // ## ##
+ 0x19,0x80, // ## ##
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @288 '$' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x01,0x80,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x07,0xb0,0x00, // #### ##
- 0x0f,0xf0,0x00, // ########
- 0x18,0x70,0x00, // ## ###
- 0x18,0x70,0x00, // ## ###
- 0x1c,0x00,0x00, // ###
- 0x0f,0x80,0x00, // #####
- 0x07,0xe0,0x00, // ######
- 0x00,0xf0,0x00, // ####
- 0x18,0x30,0x00, // ## ##
- 0x1c,0x30,0x00, // ### ##
- 0x1c,0x70,0x00, // ### ###
- 0x1f,0xe0,0x00, // ########
- 0x1b,0xc0,0x00, // ## ####
- 0x01,0x80,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @288 '$' (16 pixels wide)
+ 0x00,0x00, //
+ 0x03,0x00, // ##
+ 0x03,0x00, // ##
+ 0x0F,0x60, // #### ##
+ 0x1F,0xE0, // ########
+ 0x30,0xE0, // ## ###
+ 0x30,0xE0, // ## ###
+ 0x38,0x00, // ###
+ 0x1F,0x00, // #####
+ 0x0F,0xC0, // ######
+ 0x01,0xE0, // ####
+ 0x30,0x60, // ## ##
+ 0x38,0x60, // ### ##
+ 0x38,0xE0, // ### ###
+ 0x3F,0xC0, // ########
+ 0x37,0x80, // ## ####
+ 0x03,0x00, // ##
+ 0x03,0x00, // ##
+ 0x03,0x00, // ##
+ 0x03,0x00, // ##
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @360 '%' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x07,0x80,0x00, // ####
- 0x0f,0xc0,0x00, // ######
- 0x1c,0xe0,0x00, // ### ###
- 0x18,0x60,0x00, // ## ##
- 0x18,0x60,0x00, // ## ##
- 0x1c,0xe0,0x00, // ### ###
- 0x0f,0xf8,0x00, // #########
- 0x07,0xe0,0x00, // ######
- 0x1f,0xf0,0x00, // #########
- 0x07,0x38,0x00, // ### ###
- 0x06,0x18,0x00, // ## ##
- 0x06,0x18,0x00, // ## ##
- 0x07,0x38,0x00, // ### ###
- 0x03,0xf0,0x00, // ######
- 0x01,0xe0,0x00, // ####
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @360 '%' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x0F,0x00, // ####
+ 0x1F,0x80, // ######
+ 0x39,0xC0, // ### ###
+ 0x30,0xC0, // ## ##
+ 0x30,0xC0, // ## ##
+ 0x39,0xC0, // ### ###
+ 0x1F,0xF0, // #########
+ 0x0F,0xC0, // ######
+ 0x3F,0xE0, // #########
+ 0x0E,0x70, // ### ###
+ 0x0C,0x30, // ## ##
+ 0x0C,0x30, // ## ##
+ 0x0E,0x70, // ### ###
+ 0x07,0xE0, // ######
+ 0x03,0xC0, // ####
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @432 '&' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x03,0xf0,0x00, // ######
- 0x07,0xf0,0x00, // #######
- 0x0c,0x60,0x00, // ## ##
- 0x0c,0x00,0x00, // ##
- 0x0c,0x00,0x00, // ##
- 0x06,0x00,0x00, // ##
- 0x07,0x00,0x00, // ###
- 0x0f,0x9c,0x00, // ##### ###
- 0x1d,0xfc,0x00, // ### #######
- 0x18,0xf0,0x00, // ## ####
- 0x18,0x70,0x00, // ## ###
- 0x0f,0xfc,0x00, // ##########
- 0x07,0xdc,0x00, // ##### ###
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @432 '&' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x07,0xE0, // ######
+ 0x0F,0xE0, // #######
+ 0x18,0xC0, // ## ##
+ 0x18,0x00, // ##
+ 0x18,0x00, // ##
+ 0x0C,0x00, // ##
+ 0x0E,0x00, // ###
+ 0x1F,0x38, // ##### ###
+ 0x3B,0xF8, // ### #######
+ 0x31,0xE0, // ## ####
+ 0x30,0xE0, // ## ###
+ 0x1F,0xF8, // ##########
+ 0x0F,0xB8, // ##### ###
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @504 ''' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x03,0x80,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x01,0x00,0x00, // #
- 0x01,0x00,0x00, // #
- 0x01,0x00,0x00, // #
- 0x01,0x00,0x00, // #
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @504 ''' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x07,0x00, // ###
+ 0x07,0x00, // ###
+ 0x07,0x00, // ###
+ 0x02,0x00, // #
+ 0x02,0x00, // #
+ 0x02,0x00, // #
+ 0x02,0x00, // #
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @576 '(' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x18,0x00, // ##
- 0x00,0x38,0x00, // ###
- 0x00,0x70,0x00, // ###
- 0x00,0xf0,0x00, // ####
- 0x00,0xe0,0x00, // ###
- 0x00,0xe0,0x00, // ###
- 0x01,0xc0,0x00, // ###
- 0x01,0xc0,0x00, // ###
- 0x01,0xc0,0x00, // ###
- 0x01,0xc0,0x00, // ###
- 0x01,0xc0,0x00, // ###
- 0x01,0xc0,0x00, // ###
- 0x00,0xe0,0x00, // ###
- 0x00,0xe0,0x00, // ###
- 0x00,0x70,0x00, // ###
- 0x00,0x70,0x00, // ###
- 0x00,0x38,0x00, // ###
- 0x00,0x18,0x00, // ##
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @576 '(' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x30, // ##
+ 0x00,0x70, // ###
+ 0x00,0xE0, // ###
+ 0x01,0xE0, // ####
+ 0x01,0xC0, // ###
+ 0x01,0xC0, // ###
+ 0x03,0x80, // ###
+ 0x03,0x80, // ###
+ 0x03,0x80, // ###
+ 0x03,0x80, // ###
+ 0x03,0x80, // ###
+ 0x03,0x80, // ###
+ 0x01,0xC0, // ###
+ 0x01,0xC0, // ###
+ 0x00,0xE0, // ###
+ 0x00,0xE0, // ###
+ 0x00,0x70, // ###
+ 0x00,0x30, // ##
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @648 ')' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x18,0x00,0x00, // ##
- 0x1c,0x00,0x00, // ###
- 0x0e,0x00,0x00, // ###
- 0x0e,0x00,0x00, // ###
- 0x07,0x00,0x00, // ###
- 0x07,0x00,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x03,0x80,0x00, // ###
- 0x07,0x00,0x00, // ###
- 0x07,0x00,0x00, // ###
- 0x0f,0x00,0x00, // ####
- 0x0e,0x00,0x00, // ###
- 0x1c,0x00,0x00, // ###
- 0x18,0x00,0x00, // ##
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @648 ')' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x30,0x00, // ##
+ 0x38,0x00, // ###
+ 0x1C,0x00, // ###
+ 0x1C,0x00, // ###
+ 0x0E,0x00, // ###
+ 0x0E,0x00, // ###
+ 0x07,0x00, // ###
+ 0x07,0x00, // ###
+ 0x07,0x00, // ###
+ 0x07,0x00, // ###
+ 0x07,0x00, // ###
+ 0x07,0x00, // ###
+ 0x0E,0x00, // ###
+ 0x0E,0x00, // ###
+ 0x1E,0x00, // ####
+ 0x1C,0x00, // ###
+ 0x38,0x00, // ###
+ 0x30,0x00, // ##
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @720 '*' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x01,0x80,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x1d,0xb8,0x00, // ### ## ###
- 0x1f,0xf8,0x00, // ##########
- 0x07,0xe0,0x00, // ######
- 0x03,0xc0,0x00, // ####
- 0x03,0xc0,0x00, // ####
- 0x06,0x60,0x00, // ## ##
- 0x06,0x60,0x00, // ## ##
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @720 '*' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x03,0x00, // ##
+ 0x03,0x00, // ##
+ 0x03,0x00, // ##
+ 0x3B,0x70, // ### ## ###
+ 0x3F,0xF0, // ##########
+ 0x0F,0xC0, // ######
+ 0x07,0x80, // ####
+ 0x07,0x80, // ####
+ 0x0C,0xC0, // ## ##
+ 0x0C,0xC0, // ## ##
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @792 '+' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x01,0x80,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x3f,0xfc,0x00, // ############
- 0x3f,0xfc,0x00, // ############
- 0x01,0x80,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @792 '+' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x03,0x00, // ##
+ 0x03,0x00, // ##
+ 0x03,0x00, // ##
+ 0x03,0x00, // ##
+ 0x03,0x00, // ##
+ 0x7F,0xF8, // ############
+ 0x7F,0xF8, // ############
+ 0x03,0x00, // ##
+ 0x03,0x00, // ##
+ 0x03,0x00, // ##
+ 0x03,0x00, // ##
+ 0x03,0x00, // ##
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @864 ',' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0xe0,0x00, // ###
- 0x00,0xc0,0x00, // ##
- 0x01,0xc0,0x00, // ###
- 0x01,0x80,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x03,0x00,0x00, // ##
- 0x03,0x00,0x00, // ##
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @864 ',' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x01,0xC0, // ###
+ 0x01,0x80, // ##
+ 0x03,0x80, // ###
+ 0x03,0x00, // ##
+ 0x03,0x00, // ##
+ 0x06,0x00, // ##
+ 0x06,0x00, // ##
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @936 '-' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x1f,0xf8,0x00, // ##########
- 0x1f,0xf8,0x00, // ##########
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @936 '-' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x3F,0xF0, // ##########
+ 0x3F,0xF0, // ##########
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @1008 '.' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x03,0xc0,0x00, // ####
- 0x03,0xc0,0x00, // ####
- 0x03,0xc0,0x00, // ####
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @1008 ' ' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x07,0x80, // ####
+ 0x07,0x80, // ####
+ 0x07,0x80, // ####
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @1080 '/' (17 pixels wide)
- 0x00,0x18,0x00, // ##
- 0x00,0x18,0x00, // ##
- 0x00,0x38,0x00, // ###
- 0x00,0x30,0x00, // ##
- 0x00,0x70,0x00, // ###
- 0x00,0x60,0x00, // ##
- 0x00,0x60,0x00, // ##
- 0x00,0xc0,0x00, // ##
- 0x00,0xc0,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x01,0x80,0x00, // ##
- 0x03,0x00,0x00, // ##
- 0x03,0x00,0x00, // ##
- 0x06,0x00,0x00, // ##
- 0x06,0x00,0x00, // ##
- 0x0e,0x00,0x00, // ###
- 0x0c,0x00,0x00, // ##
- 0x1c,0x00,0x00, // ###
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @1080 '/' (16 pixels wide)
+ 0x00,0x30, // ##
+ 0x00,0x30, // ##
+ 0x00,0x70, // ###
+ 0x00,0x60, // ##
+ 0x00,0xE0, // ###
+ 0x00,0xC0, // ##
+ 0x00,0xC0, // ##
+ 0x01,0x80, // ##
+ 0x01,0x80, // ##
+ 0x03,0x00, // ##
+ 0x03,0x00, // ##
+ 0x06,0x00, // ##
+ 0x06,0x00, // ##
+ 0x0C,0x00, // ##
+ 0x0C,0x00, // ##
+ 0x1C,0x00, // ###
+ 0x18,0x00, // ##
+ 0x38,0x00, // ###
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @0 ' ' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x00,0x00,0x00, //
+// @0 ' ' (16 pixels wide)
+ 0x00,0x00, //
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x00,0x00, //
- // @0 ' ' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @0 ' ' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @0 ' ' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x00,0x00,0x00, //
+// @0 ' ' (16 pixels wide)
+ 0x00,0x00, //
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x00,0x00, //
- // @0 ' ' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x00,0x00,0x00, //
+// @0 ' ' (16 pixels wide)
+ 0x00,0x00, //
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x00,0x00, //
- // @0 ' ' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @0 ' ' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @0 ' ' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x00,0x00,0x00, //
+// @0 ' ' (16 pixels wide)
+ 0x00,0x00, //
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x00,0x00, //
- // @0 ' ' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x18,0x00,0x00, // ##
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x0f,0xfc,0x00, // ##########
- 0x0f,0xfc,0x00, // ##########
- 0x00,0x00,0x00, //
+// @0 ' ' (16 pixels wide)
+ 0x00,0x00, //
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x30,0x00, // ##
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x1F,0xF8, // ##########
+ 0x1F,0xF8, // ##########
+ 0x00,0x00, //
- // @0 ' ' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x0f,0xfc,0x00, // ##########
- 0x0f,0xfc,0x00, // ##########
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @0 ' ' (16 pixels wide)
+ 0x00,0x00, //
+ 0x1F,0xF8, // ##########
+ 0x1F,0xF8, // ##########
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @0 ' ' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x00,0x00,0x00, //
+// @0 ' ' (16 pixels wide)
+ 0x00,0x00, //
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x00,0x00, //
- // @0 ' ' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x18,0x03,0x00, // ## ##
- 0x07,0xfc,0x00, // #########
- 0x07,0xfc,0x00, // #########
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x03,0x00, // ##
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
+// @0 ' ' (16 pixels wide)
+ 0x00,0x00, //
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x30,0x06, // ## ##
+ 0x0F,0xF8, // #########
+ 0x0F,0xF8, // #########
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x06, // ##
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
- // @1872 ':' (17 pixels wide)
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0xf0,0x00, // ####
- 0x00,0xf0,0x00, // ####
- 0x00,0xf0,0x00, // ####
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0xf0,0x00, // ####
- 0x00,0xf0,0x00, // ####
- 0x00,0xf0,0x00, // ####
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00, //
- 0x00,0x00,0x00 //
+// @1872 ':' (16 pixels wide)
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x01,0xE0, // ####
+ 0x01,0xE0, // ####
+ 0x01,0xE0, // ####
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x01,0xE0, // ####
+ 0x01,0xE0, // ####
+ 0x01,0xE0, // ####
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00, //
+ 0x00,0x00 //
};
sFONT Font24_7seg = {
Font24_Table_7seg,
- 17, /* Width */
+ 16, /* Width */
24, /* Height */
};
diff --git a/lib/lib_display/UDisplay/uDisplay.cpp b/lib/lib_display/UDisplay/uDisplay.cpp
index af5835e3f..d3b55316e 100755
--- a/lib/lib_display/UDisplay/uDisplay.cpp
+++ b/lib/lib_display/UDisplay/uDisplay.cpp
@@ -670,10 +670,10 @@ Renderer *uDisplay::Init(void) {
}
} else {
for (uint32_t cnt = 0; cnt < 8; cnt ++) {
- bus_config.data_gpio_nums[cnt] = par_dbh[cnt];
+ bus_config.data_gpio_nums[cnt] = par_dbl[cnt];
}
for (uint32_t cnt = 0; cnt < 8; cnt ++) {
- bus_config.data_gpio_nums[cnt + 8] = par_dbl[cnt];
+ bus_config.data_gpio_nums[cnt + 8] = par_dbh[cnt];
}
}
@@ -2490,6 +2490,8 @@ void uDisplay::_setup_dma_desc_links(const uint8_t *data, int32_t len) {
*/
}
+#define WAIT_LCD_NOT_BUSY while (*reg_lcd_user & LCD_CAM_LCD_START) {}
+
void uDisplay::pb_beginTransaction(void) {
auto dev = _dev;
@@ -2533,84 +2535,60 @@ bool uDisplay::pb_busy(void) {
}
bool uDisplay::pb_writeCommand(uint32_t data, uint_fast8_t bit_length) {
- if (interface == _UDSP_PAR8) {
+ auto dev = _dev;
+ auto reg_lcd_user = &(dev->lcd_user.val);
+ dev->lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE | LCD_CAM_LCD_CD_CMD_SET;
+
+ if (interface == _UDSP_PAR8) {
// 8bit bus
auto bytes = bit_length >> 3;
- auto dev = _dev;
- auto reg_lcd_user = &(dev->lcd_user.val);
- dev->lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE | LCD_CAM_LCD_CD_CMD_SET;
do {
dev->lcd_cmd_val.lcd_cmd_value = data;
data >>= 8;
- while (*reg_lcd_user & LCD_CAM_LCD_START) {}
+ WAIT_LCD_NOT_BUSY
*reg_lcd_user = LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
} while (--bytes);
return true;
- } else {
- // 16 bit bus
- if (_has_align_data) { _send_align_data(); }
- auto dev = _dev;
- auto reg_lcd_user = &(dev->lcd_user.val);
- dev->lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE | LCD_CAM_LCD_CD_CMD_SET;
+ } else {
dev->lcd_cmd_val.val = data;
-
- if (bit_length <= 16) {
- while (*reg_lcd_user & LCD_CAM_LCD_START) {}
- *reg_lcd_user = LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
- return true;
- }
-
- while (*reg_lcd_user & LCD_CAM_LCD_START) {}
- *reg_lcd_user = LCD_CAM_LCD_CMD_2_CYCLE_EN | LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
+ WAIT_LCD_NOT_BUSY
+ *reg_lcd_user = LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
return true;
- }
- }
-
+ }
+}
void uDisplay::pb_writeData(uint32_t data, uint_fast8_t bit_length) {
- if (interface == _UDSP_PAR8) {
- auto bytes = bit_length >> 3;
- auto dev = _dev;
- auto reg_lcd_user = &(dev->lcd_user.val);
- dev->lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE;
+ auto dev = _dev;
+ auto reg_lcd_user = &(dev->lcd_user.val);
+ dev->lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE;
+ auto bytes = bit_length >> 3;
+ if (interface == _UDSP_PAR8) {
uint8_t shift = (bytes - 1) * 8;
for (uint32_t cnt = 0; cnt < bytes; cnt++) {
dev->lcd_cmd_val.lcd_cmd_value = (data >> shift) & 0xff;
shift -= 8;
- while (*reg_lcd_user & LCD_CAM_LCD_START) {}
+ WAIT_LCD_NOT_BUSY
*reg_lcd_user = LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
}
return;
} else {
- auto bytes = bit_length >> 3;
- auto dev = _dev;
- auto reg_lcd_user = &(dev->lcd_user.val);
- dev->lcd_misc.val = LCD_CAM_LCD_CD_IDLE_EDGE;
- if (_has_align_data) {
- _has_align_data = false;
- dev->lcd_cmd_val.val = _align_data | (data << 8);
- while (*reg_lcd_user & LCD_CAM_LCD_START) {}
- *reg_lcd_user = LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
- if (--bytes == 0) { return; }
- data >>= 8;
+ if (bytes == 1 || bytes == 4) {
+ uint8_t shift = (bytes - 1) * 8;
+ for (uint32_t cnt = 0; cnt < bytes; cnt++) {
+ dev->lcd_cmd_val.lcd_cmd_value = (data >> shift) & 0xff;
+ shift -= 8;
+ WAIT_LCD_NOT_BUSY
+ *reg_lcd_user = LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
+ }
+ return;
}
- if (bytes > 1) {
- dev->lcd_cmd_val.val = data;
- if (bytes == 4) {
- while (*reg_lcd_user & LCD_CAM_LCD_START) {}
- *reg_lcd_user = LCD_CAM_LCD_CMD_2_CYCLE_EN | LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
- return;
- }
- while (*reg_lcd_user & LCD_CAM_LCD_START) {}
- *reg_lcd_user = LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
- if (bytes == 2) { return; }
- data >>= 16;
- }
- _has_align_data = true;
- _align_data = data;
+ dev->lcd_cmd_val.val = data;
+ WAIT_LCD_NOT_BUSY
+ *reg_lcd_user = LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
+ return;
}
}
@@ -2626,7 +2604,7 @@ void uDisplay::pb_pushPixels(uint16_t* data, uint32_t length, bool swap_bytes, b
while (*reg_lcd_user & LCD_CAM_LCD_START) {}
*reg_lcd_user = LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
dev->lcd_cmd_val.lcd_cmd_value = *data >> 8;
- while (*reg_lcd_user & LCD_CAM_LCD_START) {}
+ WAIT_LCD_NOT_BUSY
*reg_lcd_user = LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
data++;
}
@@ -2636,7 +2614,7 @@ void uDisplay::pb_pushPixels(uint16_t* data, uint32_t length, bool swap_bytes, b
while (*reg_lcd_user & LCD_CAM_LCD_START) {}
*reg_lcd_user = LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
dev->lcd_cmd_val.lcd_cmd_value = *data;
- while (*reg_lcd_user & LCD_CAM_LCD_START) {}
+ WAIT_LCD_NOT_BUSY
*reg_lcd_user = LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
data++;
}
@@ -2648,14 +2626,13 @@ void uDisplay::pb_pushPixels(uint16_t* data, uint32_t length, bool swap_bytes, b
iob = *data++;
iob = (iob << 8) | (iob >> 8);
dev->lcd_cmd_val.lcd_cmd_value = iob;
- while (*reg_lcd_user & LCD_CAM_LCD_START) {}
+ WAIT_LCD_NOT_BUSY
*reg_lcd_user = LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
- data++;
}
} else {
for (uint32_t cnt = 0; cnt < length; cnt++) {
dev->lcd_cmd_val.lcd_cmd_value = *data++;
- while (*reg_lcd_user & LCD_CAM_LCD_START) {}
+ WAIT_LCD_NOT_BUSY
*reg_lcd_user = LCD_CAM_LCD_2BYTE_EN | LCD_CAM_LCD_CMD | LCD_CAM_LCD_UPDATE_REG | LCD_CAM_LCD_START;
}
}
diff --git a/lib/lib_rf/rc-switch/src/RCSwitch.cpp b/lib/lib_rf/rc-switch/src/RCSwitch.cpp
index 69b3f37a3..05d2a8313 100644
--- a/lib/lib_rf/rc-switch/src/RCSwitch.cpp
+++ b/lib/lib_rf/rc-switch/src/RCSwitch.cpp
@@ -57,21 +57,21 @@
/* Protocol description format
*
* {
- * Pulse length,
- *
+ * Pulse length,
+ *
* PreambleFactor,
* Preamble {high,low},
- *
+ *
* HeaderFactor,
* Header {high,low},
- *
+ *
* "0" bit {high,low},
* "1" bit {high,low},
- *
+ *
* Inverted Signal,
* Guard time
* }
- *
+ *
* Pulse length: pulse duration (Te) in microseconds,
* for example 350
* PreambleFactor: Number of high and low states to send
@@ -80,7 +80,7 @@
* Preamble: Pulse shape which defines a preamble bit.
* Sent ceil(PreambleFactor/2) times.
* For example, {1, 2} with factor 3 would send
- * _ _
+ * _ _
* | |__| |__ (each horizontal bar has a duration of Te,
* vertical bars are ignored)
* HeaderFactor: Number of times to send the header pulse.
@@ -88,22 +88,22 @@
* {1, 31} means one pulse of duration 1 Te high and 31 Te low
* _
* | |_______________________________ (don't count the vertical bars)
- *
+ *
* "0" bit: pulse shape defining a data bit, which is a logical "0"
* {1, 3} means 1 pulse duration Te high level and 3 low
* _
* | |___
- *
+ *
* "1" bit: pulse shape that defines the data bit, which is a logical "1"
* {3, 1} means 3 pulses with a duration of Te high level and 1 low
* ___
* | |_
*
* (note: to form the state bit Z (Tri-State bit), two codes are combined)
- *
+ *
* Inverted Signal: Signal inversion - if true the signal is inverted
* replacing high to low in a transmitted / received packet
- * Guard time: Separation time between two retries. It will be followed by the
+ * Guard time: Separation time between two retries. It will be followed by the
* next preamble of the next packet. In number of Te.
* e.g. 39 pulses of duration Te low level
*/
@@ -149,8 +149,10 @@ static const RCSwitch::Protocol PROGMEM proto[] = {
{ 400, 0, { 0, 0 }, 1, { 1, 1 }, { 1, 2 }, { 2, 1 }, false, 43 }, // 31 (Mertik Maxitrol G6R-H4T1)
{ 365, 0, { 0, 0 }, 1, { 18, 1 }, { 3, 1 }, { 1, 3 }, true, 0 }, // 32 (1ByOne Doorbell) from @Fatbeard https://github.com/sui77/rc-switch/pull/277
{ 340, 0, { 0, 0 }, 1, { 14, 4 }, { 1, 2 }, { 2, 1 }, false, 0 }, // 33 (Dooya Control DC2708L)
- { 120, 0, { 0, 0 }, 1, { 1, 28 }, { 1, 3 }, { 3, 1 }, false, 0 }, // 34 DIGOO SD10 - so as to use this protocol RCSWITCH_SEPARATION_LIMIT must be set to 2600
- { 20, 0, { 0, 0 }, 1, { 239, 78 }, {20, 35 }, {35, 20}, false, 10000 } // 35 Dooya 5-Channel blinds remote DC1603
+ { 120, 0, { 0, 0 }, 1, { 1, 28 }, { 1, 3 }, { 3, 1 }, false, 0 }, // 34 DIGOO SD10 - so as to use this protocol RCSWITCH_SEPARATION_LIMIT must be set to 2600
+ { 20, 0, { 0, 0 }, 1, { 239, 78 }, {20, 35 }, {35, 20}, false, 10000},// 35 Dooya 5-Channel blinds remote DC1603
+ { 250, 0, { 0, 0 }, 1, { 18, 6 }, { 1, 3 }, { 3, 1 }, false, 0 }, // 36 Dooya remote DC2700AC for Dooya DT82TV curtains motor
+ { 200, 0, { 0, 0 }, 0, { 0, 0 }, { 1, 3 }, { 3, 1} , false, 20} // 37 DEWENWILS Power Strip
};
enum {
@@ -756,7 +758,7 @@ bool RECEIVE_ATTR RCSwitch::receiveProtocol(const int p, unsigned int changeCoun
unsigned int sdelay = 0;
if (syncLengthInPulses > 0) {
sdelay = RCSwitch::timings[FirstTiming] / syncLengthInPulses;
- } else {
+ } else if (pro.PreambleFactor > 0) {
sdelay = RCSwitch::timings[FirstTiming-2] / pro.PreambleFactor;
}
const unsigned int delay = sdelay;
diff --git a/lib/libesp32/Berry-HttpClientLight/src/HttpClientLight.cpp b/lib/libesp32/Berry-HttpClientLight/src/HttpClientLight.cpp
index 1c1c6ac32..d8c85b2ac 100644
--- a/lib/libesp32/Berry-HttpClientLight/src/HttpClientLight.cpp
+++ b/lib/libesp32/Berry-HttpClientLight/src/HttpClientLight.cpp
@@ -5,8 +5,8 @@
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
* This file is part of the HTTPClient for Arduino.
- * Port to ESP32 by Evandro Luis Copercini (2017),
- * changed fingerprints to CA verification.
+ * Port to ESP32 by Evandro Luis Copercini (2017),
+ * changed fingerprints to CA verification.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -78,7 +78,7 @@ public:
_recv(recv), _xmit(xmit)
{
}
-
+
std::unique_ptr create() override
{
std::unique_ptr p = std::unique_ptr(new BearSSL::WiFiClientSecure_light(_recv, _xmit));
@@ -569,6 +569,20 @@ int HTTPClientLight::PUT(String payload) {
return PUT((uint8_t *) payload.c_str(), payload.length());
}
+/**
+ * sends a delete request to the server
+ * @param payload uint8_t *
+ * @param size size_t
+ * @return http code
+ */
+int HTTPClientLight::DELETE(uint8_t * payload, size_t size) {
+ return sendRequest("DELETE", payload, size);
+}
+
+int HTTPClientLight::DELETE(String payload) {
+ return DELETE((uint8_t *) payload.c_str(), payload.length());
+}
+
/**
* sendRequest
* @param type const char * "GET", "POST", ....
@@ -601,7 +615,7 @@ int HTTPClientLight::sendRequest(const char * type, uint8_t * payload, size_t si
}
log_d("request type: '%s' redirCount: %d\n", type, redirectCount);
-
+
// connect to server
if(!connect()) {
if (_secure) {
@@ -640,7 +654,7 @@ int HTTPClientLight::sendRequest(const char * type, uint8_t * payload, size_t si
//
redirect = false;
if (
- _followRedirects != HTTPC_DISABLE_FOLLOW_REDIRECTS &&
+ _followRedirects != HTTPC_DISABLE_FOLLOW_REDIRECTS &&
redirectCount < _redirectLimit &&
_location.length() > 0
) {
@@ -653,7 +667,7 @@ int HTTPClientLight::sendRequest(const char * type, uint8_t * payload, size_t si
// (the RFC require user to accept the redirection)
_followRedirects == HTTPC_FORCE_FOLLOW_REDIRECTS ||
// allow GET and HEAD methods without force
- !strcmp(type, "GET") ||
+ !strcmp(type, "GET") ||
!strcmp(type, "HEAD")
) {
redirectCount += 1;
@@ -972,7 +986,7 @@ String HTTPClientLight::getString(void)
// try to reserve needed memory (noop if _size == -1)
if(sstring.reserve((_size + 1))) {
writeToStream(&sstring);
- return sstring;
+ return sstring;
} else {
log_d("not enough memory to reserve a string! need: %d", (_size + 1));
}
@@ -1142,7 +1156,7 @@ bool HTTPClientLight::connect(void)
log_d("transport level verify failed");
_client->stop();
return false;
- }
+ }
#endif
if(!_client->connect(_host.c_str(), _port, _connectTimeout)) {
log_d("failed connect to %s:%u", _host.c_str(), _port);
@@ -1150,7 +1164,7 @@ bool HTTPClientLight::connect(void)
}
// set Timeout for WiFiClient and for Stream::readBytesUntil() and Stream::readStringUntil()
- _client->setTimeout((_tcpTimeout + 500) / 1000);
+ _client->setTimeout((_tcpTimeout + 500) / 1000);
log_d(" connected to %s:%u", _host.c_str(), _port);
@@ -1362,8 +1376,8 @@ int HTTPClientLight::writeToStreamDataBlock(Stream * stream, int size)
if(readBytes > buff_size) {
readBytes = buff_size;
}
-
- // stop if no more reading
+
+ // stop if no more reading
if (readBytes == 0)
break;
@@ -1491,8 +1505,8 @@ bool HTTPClientLight::setURL(const String& url)
_port = (_protocol == "https" ? 443 : 80);
}
- // disconnect but preserve _client.
- // Also have to keep the connection otherwise it will free some of the memory used by _client
+ // disconnect but preserve _client.
+ // Also have to keep the connection otherwise it will free some of the memory used by _client
// and will blow up later when trying to do _client->available() or similar
_canReuse = true;
disconnect(true);
diff --git a/lib/libesp32/Berry-HttpClientLight/src/HttpClientLight.h b/lib/libesp32/Berry-HttpClientLight/src/HttpClientLight.h
index a6d3be7eb..8c3709399 100644
--- a/lib/libesp32/Berry-HttpClientLight/src/HttpClientLight.h
+++ b/lib/libesp32/Berry-HttpClientLight/src/HttpClientLight.h
@@ -5,8 +5,8 @@
*
* Copyright (c) 2015 Markus Sattler. All rights reserved.
* This file is part of the HTTPClient for Arduino.
- * Port to ESP32 by Evandro Luis Copercini (2017),
- * changed fingerprints to CA verification.
+ * Port to ESP32 by Evandro Luis Copercini (2017),
+ * changed fingerprints to CA verification.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -154,7 +154,7 @@ public:
~HTTPClientLight();
/*
- * Since both begin() functions take a reference to client as a parameter, you need to
+ * Since both begin() functions take a reference to client as a parameter, you need to
* ensure the client object lives the entire time of the HTTPClientLight
*/
// bool begin(WiFiClient &client, String url);
@@ -194,6 +194,8 @@ public:
int POST(String payload);
int PUT(uint8_t * payload, size_t size);
int PUT(String payload);
+ int DELETE(uint8_t * payload, size_t size);
+ int DELETE(String payload);
int sendRequest(const char * type, String payload);
int sendRequest(const char * type, uint8_t * payload = NULL, size_t size = 0);
int sendRequest(const char * type, Stream * stream, size_t size = 0);
diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/AddrList.h b/lib/libesp32/ESP32-to-ESP8266-compat/src/AddrList.h
deleted file mode 100644
index cc32ea232..000000000
--- a/lib/libesp32/ESP32-to-ESP8266-compat/src/AddrList.h
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- AddrList.h - cycle through lwIP netif's ip addresses like a c++ list
- Copyright (c) 2018 david gauchard. All right reserved.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-/*
- This class allows to explore all configured IP addresses
- in lwIP netifs, with that kind of c++ loop:
-
- for (auto a: addrList)
- out.printf("IF='%s' index=%d legacy=%d IPv4=%d local=%d hostname='%s' addr= %s\n",
- a.iface().c_str(),
- a.ifnumber(),
- a.addr().isLegacy(),
- a.addr().isV4(),
- a.addr().isLocal(),
- a.hostname().c_str(),
- a.addr().toString().c_str());
-
- This loop:
-
- while (WiFi.status() != WL_CONNECTED()) {
- Serial.print('.');
- delay(500);
- }
-
- can be replaced by:
-
- for (bool configured = false; !configured; ) {
- for (auto iface: addrList)
- if ((configured = !iface.addr().isLocal())
- break;
- Serial.print('.');
- delay(500);
- }
-
- waiting for an IPv6 global address:
-
- for (bool configured = false; !configured; ) {
- for (auto iface: addrList)
- if ((configured = ( !iface.addr().isV4()
- && !iface.addr().isLocal())))
- break;
- Serial.print('.');
- delay(500);
- }
-
- waiting for an IPv6 global address, on a specific interface:
-
- for (bool configured = false; !configured; ) {
- for (auto iface: addrList)
- if ((configured = ( !iface.addr().isV4()
- && !iface.addr().isLocal()
- && iface.ifnumber() == STATION_IF)))
- break;
- Serial.print('.');
- delay(500);
- }
-*/
-
-#ifndef __ADDRLIST_H
-#define __ADDRLIST_H
-
-#include
-#include
-
-#if LWIP_IPV6
-#define IF_NUM_ADDRESSES (1 + LWIP_IPV6_NUM_ADDRESSES)
-#else
-#define IF_NUM_ADDRESSES (1)
-#endif
-
-
-namespace esp8266
-{
-
-namespace AddressListImplementation
-{
-
-
-struct netifWrapper
-{
- netifWrapper (netif* netif) : _netif(netif), _num(-1) {}
- netifWrapper (const netifWrapper& o) : _netif(o._netif), _num(o._num) {}
-
- netifWrapper& operator= (const netifWrapper& o)
- {
- _netif = o._netif;
- _num = o._num;
- return *this;
- }
-
- bool equal(const netifWrapper& o)
- {
- return _netif == o._netif && (!_netif || _num == o._num);
- }
-
- // address properties
- class IPAddress4 : public IPAddress
- {
- public:
- bool isV6() const
- {
- return false;
- }
- bool isLocal() const
- {
- return false;
- }
- };
- IPAddress4 addr () const { return ipFromNetifNum(); }
- bool isLegacy () const { return _num == 0; }
- //bool isLocal () const { return addr().isLocal(); }
- bool isV4 () const { return addr().isV4(); }
- bool isV6 () const { return !addr().isV4(); }
- String toString() const { return addr().toString(); }
-
- // related to legacy address (_num=0, ipv4)
- IPAddress ipv4 () const { return _netif->ip_addr; }
- IPAddress netmask () const { return _netif->netmask; }
- IPAddress gw () const { return _netif->gw; }
-
- // common to all addresses of this interface
- String ifname () const { return String(_netif->name[0]) + _netif->name[1]; }
- const char* ifhostname () const { return _netif->hostname?: emptyString.c_str(); }
- const char* ifmac () const { return (const char*)_netif->hwaddr; }
- int ifnumber () const { return _netif->num; }
- bool ifUp () const { return !!(_netif->flags & NETIF_FLAG_UP); }
- const netif* interface () const { return _netif; }
-
- const ip_addr_t* ipFromNetifNum () const
- {
-#if LWIP_IPV6
- return _num ? &_netif->ip6_addr[_num - 1] : &_netif->ip_addr;
-#else
- return &_netif->ip_addr;
-#endif
- }
-
- // lwIP interface
- netif* _netif;
-
- // address index within interface
- // 0: legacy address (IPv4)
- // n>0: (_num-1) is IPv6 index for netif->ip6_addr[]
- int _num;
-};
-
-
-class AddressListIterator
-{
-public:
- AddressListIterator (const netifWrapper& o) : netIf(o) {}
- AddressListIterator (netif* netif) : netIf(netif)
- {
- // This constructor is called with lwIP's global netif_list, or
- // nullptr. operator++() is designed to loop through _configured_
- // addresses. That's why netIf's _num is initialized to -1 to allow
- // returning the first usable address to AddressList::begin().
- (void)operator++();
- }
-
- const netifWrapper& operator* () const { return netIf; }
- const netifWrapper* operator-> () const { return &netIf; }
-
- bool operator== (AddressListIterator& o) { return netIf.equal(*o); }
- bool operator!= (AddressListIterator& o) { return !netIf.equal(*o); }
-
- AddressListIterator operator++ (int)
- {
- AddressListIterator ret = *this;
- (void)operator++();
- return ret;
- }
-
- AddressListIterator& operator++ ()
- {
- while (netIf._netif)
- {
- if (++netIf._num == IF_NUM_ADDRESSES)
- {
- // all addresses from current interface were iterated,
- // switching to next interface
- netIf = netifWrapper(netIf._netif->next);
- continue;
- }
- if (!ip_addr_isany(netIf.ipFromNetifNum()))
- // found an initialized address
- break;
- }
- return *this;
- }
-
- netifWrapper netIf;
-};
-
-
-class AddressList
-{
-public:
- using const_iterator = const AddressListIterator;
-
- const_iterator begin () const { return const_iterator(netif_list); }
- const_iterator end () const { return const_iterator(nullptr); }
-
-};
-
-inline AddressList::const_iterator begin (const AddressList& a) { return a.begin(); }
-inline AddressList::const_iterator end (const AddressList& a) { return a.end(); }
-
-
-} // AddressListImplementation
-
-} // esp8266
-
-extern AddressList addrList;
-
-
-#endif
diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp
index b700f2955..43ec90479 100644
--- a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp
+++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP32Wifi.cpp
@@ -91,6 +91,16 @@ bool WiFiClass32::getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int3
return WiFi.getNetworkInfo(i, ssid, encType, rssi, bssid, channel);
}
+// from https://github.com/espressif/arduino-esp32/pull/7520
+static const int WIFI_WANT_IP6_BIT_ALT = BIT15;
+bool WiFiClass32::IPv6(bool state) {
+ if (state)
+ WiFiGenericClass::setStatusBits(WIFI_WANT_IP6_BIT_ALT);
+ else
+ WiFiGenericClass::clearStatusBits(WIFI_WANT_IP6_BIT_ALT);
+ return true;
+}
+
void wifi_station_disconnect() {
// erase ap: empty ssid, ...
WiFi.disconnect(true, true);
diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h
index e7a760164..1c1630b4c 100644
--- a/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h
+++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/ESP8266WiFi.h
@@ -19,9 +19,6 @@
#pragma once
#include
-// sorry, no
-#undef LWIP_IPV6
-
#define ENC_TYPE_NONE WIFI_AUTH_OPEN
#define ENC_TYPE_WEP WIFI_AUTH_WEP
#define ENC_TYPE_CCMP WIFI_AUTH_WPA2_PSK
@@ -53,6 +50,8 @@ public:
static void forceSleepBegin();
static void forceSleepWake();
static bool getNetworkInfo(uint8_t i, String &ssid, uint8_t &encType, int32_t &rssi, uint8_t* &bssid, int32_t &channel, bool &hidden_scan);
+
+ bool IPv6(bool state); // make sure it always exists even with older Arduino framework
};
void wifi_station_disconnect();
diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h b/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h
index f6a6338c6..23ed7f1b4 100644
--- a/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h
+++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h
@@ -137,8 +137,6 @@ typedef int SerialConfig;
//#define PortUdp_writestr(log_data) PortUdp.write((const uint8_t *)(log_data), strlen(log_data))
#define PortUdp_write(log_data, n) PortUdp.write((const uint8_t *)(log_data), n)
-#undef LWIP_IPV6
-
#define REASON_DEFAULT_RST 0 // "Power on" normal startup by power on
#define REASON_WDT_RST 1 // "Hardware Watchdog" hardware watch dog reset
#define REASON_EXCEPTION_RST 2 // "Exception" exception reset, GPIO status won’t change
diff --git a/lib/libesp32/berry/default/be_modtab.c b/lib/libesp32/berry/default/be_modtab.c
index c02e2ca6d..ad1844d0a 100644
--- a/lib/libesp32/berry/default/be_modtab.c
+++ b/lib/libesp32/berry/default/be_modtab.c
@@ -50,6 +50,7 @@ be_extern_native_module(partition_core);
be_extern_native_module(crc);
be_extern_native_module(crypto);
be_extern_native_module(ULP);
+be_extern_native_module(mdns);
#ifdef USE_ZIGBEE
be_extern_native_module(zigbee);
#endif // USE_ZIGBEE
@@ -163,21 +164,23 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = {
&be_native_module(flash),
&be_native_module(partition_core),
&be_native_module(crc),
-#ifdef USE_ALEXA_AVS
&be_native_module(crypto),
-#endif
-#if defined(USE_BERRY_ULP) && defined(CONFIG_IDF_TARGET_ESP32)
+#if defined(USE_BERRY_ULP) && ((CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3))
&be_native_module(ULP),
#endif // USE_BERRY_ULP
#if defined(USE_MI_ESP32) && !defined(USE_BLE_ESP32)
&be_native_module(MI32),
&be_native_module(BLE),
#endif //USE_MI_ESP32
+#ifdef USE_DISCOVERY
+ &be_native_module(mdns),
+#endif // USE_DISCOVERY
#endif // TASMOTA
/* user-defined modules register end */
NULL /* do not remove */
};
+be_extern_native_class(dyn);
be_extern_native_class(tasmota);
be_extern_native_class(Trigger);
be_extern_native_class(Driver);
@@ -228,6 +231,7 @@ be_extern_native_class(int64);
BERRY_LOCAL bclass_array be_class_table = {
#ifdef TASMOTA
/* first list are direct classes */
+ &be_native_class(dyn),
&be_native_class(tasmota),
&be_native_class(Trigger),
&be_native_class(Driver),
diff --git a/lib/libesp32/berry/src/be_api.c b/lib/libesp32/berry/src/be_api.c
index 763187430..fb2b8e017 100644
--- a/lib/libesp32/berry/src/be_api.c
+++ b/lib/libesp32/berry/src/be_api.c
@@ -208,6 +208,31 @@ BERRY_API bbool be_isinstance(bvm *vm, int index)
return var_isinstance(v);
}
+static bbool be_isinstanceofbuiltin(bvm *vm, int rel_index, const char *classname)
+{
+ bbool ret = bfalse;
+ int index = be_absindex(vm, rel_index);
+ if (be_isinstance(vm, index)) {
+ be_getbuiltin(vm, classname);
+ if (be_isderived(vm, index)) {
+ ret = btrue;
+ }
+ be_pop(vm, 1);
+ }
+ return ret;
+}
+
+BERRY_API bbool be_ismapinstance(bvm *vm, int index)
+{
+ return be_isinstanceofbuiltin(vm, index, "map");
+}
+
+BERRY_API bbool be_islistinstance(bvm *vm, int index)
+{
+ return be_isinstanceofbuiltin(vm, index, "list");
+}
+
+
BERRY_API bbool be_ismodule(bvm *vm, int index)
{
bvalue *v = be_indexof(vm, index);
diff --git a/lib/libesp32/berry/src/be_byteslib.c b/lib/libesp32/berry/src/be_byteslib.c
index 299cc2fcd..6fcd457db 100644
--- a/lib/libesp32/berry/src/be_byteslib.c
+++ b/lib/libesp32/berry/src/be_byteslib.c
@@ -949,6 +949,109 @@ static int m_setfloat(bvm *vm)
be_return_nil(vm);
}
+/*
+ * Fills a buffer with another buffer.
+ *
+ * This is meant to be very flexible and avoid loops
+ *
+ * `setbytes(index:int, fill:bytes [, from:int, len:int]) -> nil`
+ *
+ */
+static int m_setbytes(bvm *vm)
+{
+ int argc = be_top(vm);
+ buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */
+ check_ptr(vm, &attr);
+ if (argc >=3 && be_isint(vm, 2) && (be_isbytes(vm, 3))) {
+ int32_t idx = be_toint(vm, 2);
+ size_t from_len_total;
+ const uint8_t* buf_ptr = (const uint8_t*) be_tobytes(vm, 3, &from_len_total);
+ if (idx < 0) { idx = 0; }
+ if (idx >= attr.len) { idx = attr.len; }
+
+ int32_t from_byte = 0;
+ if (argc >= 4 && be_isint(vm, 4)) {
+ from_byte = be_toint(vm, 4);
+ if (from_byte < 0) { from_byte = 0; }
+ if ((size_t)from_byte >= from_len_total) { from_byte = from_len_total; }
+ }
+
+ int32_t from_len = from_len_total - from_byte;
+ if (argc >= 5 && be_isint(vm, 5)) {
+ from_len = be_toint(vm, 5);
+ if (from_len < 0) { from_len = 0; }
+ if (from_len >= (int32_t)from_len_total) { from_len = from_len_total; }
+ }
+ if (idx + from_len >= attr.len) { from_len = attr.len - idx; }
+
+ // all parameters ok
+ if (from_len > 0) {
+ memmove(attr.bufptr + idx, buf_ptr + from_byte, from_len);
+ }
+ }
+ be_return_nil(vm);
+}
+
+
+/*
+ * Reverses in-place a sub-buffer composed of groups of n-bytes packets
+ *
+ * This is useful for pixel manipulation when displaying RGB pixels
+ *
+ * `reverse([index:int, len:int, grouplen:int]) -> self`
+ *
+ */
+static int m_reverse(bvm *vm)
+{
+ int argc = be_top(vm);
+ buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */
+ check_ptr(vm, &attr);
+
+ int32_t idx = 0; /* start from index 0 */
+ int32_t len = attr.len; /* entire len */
+ int32_t grouplen = 1; /* default to 1-byte group */
+
+ if (argc >= 2 && be_isint(vm, 2)) {
+ idx = be_toint(vm, 2);
+ if (idx < 0) { idx = 0; } /* railguards */
+ if (idx > attr.len) { idx = attr.len; }
+ }
+ if (argc >= 3 && be_isint(vm, 3)) {
+ len = be_toint(vm, 3);
+ if (len < 0) { len = attr.len - idx; } /* negative len means */
+ }
+ if (idx + len >= attr.len) { len = attr.len - idx; }
+
+ // truncate len to multiple of grouplen
+ if (argc >= 4 && be_isint(vm, 4)) {
+ grouplen = be_toint(vm, 4);
+ if (grouplen <= 0) { grouplen = 1; }
+ }
+ len = len - (len % grouplen);
+
+ // apply reverse
+ if (len > 0) {
+ if (grouplen == 1) {
+ /* fast version if simple byte inversion */
+ for (int32_t i = idx, j = idx + len -1; i < j; i++, j--) {
+ uint8_t temp = attr.bufptr[i];
+ attr.bufptr[i] = attr.bufptr[j];
+ attr.bufptr[j] = temp;
+ }
+ } else {
+ for (int32_t i = idx, j = idx + len - grouplen; i < j; i += grouplen, j -= grouplen) {
+ for (int32_t k = 0; k < grouplen; k++) {
+ uint8_t temp = attr.bufptr[i+k];
+ attr.bufptr[i+k] = attr.bufptr[j+k];
+ attr.bufptr[j+k] = temp;
+ }
+ }
+ }
+ }
+ be_pushvalue(vm, 1); /* push bytes object */
+ be_return(vm);
+}
+
static int m_setitem(bvm *vm)
{
int argc = be_top(vm);
@@ -1575,6 +1678,7 @@ void be_load_byteslib(bvm *vm)
{ "geti", m_geti },
{ "set", m_set },
{ "seti", m_set }, // setters for signed and unsigned are identical
+ { "setbytes", m_setbytes },
{ "getfloat", m_getfloat },
{ "setfloat", m_setfloat },
{ "item", m_item },
@@ -1582,6 +1686,7 @@ void be_load_byteslib(bvm *vm)
{ "size", m_size },
{ "resize", m_resize },
{ "clear", m_clear },
+ { "reverse", m_reverse },
{ "copy", m_copy },
{ "+", m_merge },
{ "..", m_connect },
@@ -1621,11 +1726,13 @@ class be_class_bytes (scope: global, name: bytes) {
setfloat, func(m_setfloat)
set, func(m_set)
seti, func(m_set)
+ setbytes, func(m_setbytes)
item, func(m_item)
setitem, func(m_setitem)
size, func(m_size)
resize, func(m_resize)
clear, func(m_clear)
+ reverse, func(m_reverse)
copy, func(m_copy)
+, func(m_merge)
.., func(m_connect)
diff --git a/lib/libesp32/berry/src/berry.h b/lib/libesp32/berry/src/berry.h
index 6d48e87f2..70ab0f87c 100644
--- a/lib/libesp32/berry/src/berry.h
+++ b/lib/libesp32/berry/src/berry.h
@@ -464,6 +464,8 @@ BERRY_API bbool be_isfunction(bvm *vm, int index);
BERRY_API bbool be_isproto(bvm *vm, int index);
BERRY_API bbool be_isclass(bvm *vm, int index);
BERRY_API bbool be_isinstance(bvm *vm, int index);
+BERRY_API bbool be_ismapinstance(bvm *vm, int index);
+BERRY_API bbool be_islistinstance(bvm *vm, int index);
BERRY_API bbool be_ismodule(bvm *vm, int index);
BERRY_API bbool be_islist(bvm *vm, int index);
BERRY_API bbool be_ismap(bvm *vm, int index);
diff --git a/lib/libesp32/berry/tests/bytes.be b/lib/libesp32/berry/tests/bytes.be
index d7b1bbdf8..d2b2c1573 100644
--- a/lib/libesp32/berry/tests/bytes.be
+++ b/lib/libesp32/berry/tests/bytes.be
@@ -202,3 +202,49 @@ assert(b == bytes())
b = bytes("FFFEAABBCC")
assert(b.tohex() == "FFFEAABBCC")
assert(bytes().tohex() == "")
+
+# assign buffer to bytes
+var a0 = bytes("112233445566778899")
+b = bytes("aabbccddeeff")
+
+a = a0.copy()
+a.setbytes(0, b) # assign from start
+assert(a == bytes('AABBCCDDEEFF778899'))
+a = a0.copy()
+a.setbytes(0, b, 0, 0) # zero len
+assert(a == a0)
+a = a0.copy()
+a.setbytes(100, b) # index out of range
+assert(a == a0)
+a = a0.copy()
+a.setbytes(6, b) # entire buffer not fitting
+assert(a == bytes('112233445566AABBCC'))
+a = a0.copy()
+a.setbytes(6, b, 2, 2)
+assert(a == bytes('112233445566CCDD99'))
+a = b.copy()
+a.setbytes(0, a0)
+assert(a == bytes('112233445566'))
+
+# reverse
+assert(bytes().reverse() == bytes())
+assert(bytes("AA").reverse() == bytes("AA"))
+assert(bytes("1122334455").reverse() == bytes("5544332211"))
+assert(bytes("11223344").reverse() == bytes("44332211"))
+
+assert(bytes("0011223344").reverse(1) == bytes("0044332211"))
+assert(bytes("0011223344").reverse(3) == bytes("0011224433"))
+assert(bytes("0011223344").reverse(4) == bytes("0011223344"))
+assert(bytes("0011223344").reverse(5) == bytes("0011223344"))
+assert(bytes("0011223344").reverse(15) == bytes("0011223344"))
+assert(bytes("0011223344").reverse(-2) == bytes("4433221100"))
+
+assert(bytes("0011223344").reverse(1,3) == bytes("0033221144"))
+assert(bytes("0011223344").reverse(1,0) == bytes("0011223344"))
+assert(bytes("0011223344").reverse(2,2) == bytes("0011332244"))
+assert(bytes("0011223344").reverse(0,2) == bytes("1100223344"))
+assert(bytes("0011223344").reverse(nil,2) == bytes("1100223344"))
+assert(bytes("0011223344").reverse(1, nil) == bytes("0044332211"))
+
+assert(bytes("0011223344").reverse(nil, nil, 2) == bytes("2233001144"))
+assert(bytes("001122334455").reverse(nil, nil, 3) == bytes("334455001122"))
diff --git a/lib/libesp32/berry_tasmota/src/be_ULP_lib.c b/lib/libesp32/berry_tasmota/src/be_ULP_lib.c
index 7edf43206..a5fe0e417 100644
--- a/lib/libesp32/berry_tasmota/src/be_ULP_lib.c
+++ b/lib/libesp32/berry_tasmota/src/be_ULP_lib.c
@@ -6,9 +6,9 @@
#include "be_constobj.h"
#include "be_mapping.h"
-#if defined(USE_BERRY_ULP) && defined(CONFIG_IDF_TARGET_ESP32)
+#if defined(USE_BERRY_ULP) && (defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3))
-#include "esp32/ulp.h"
+// #include "esp32/ulp.h"
#include "driver/rtc_io.h"
#include "driver/gpio.h"
#include "driver/adc.h"
@@ -37,8 +37,6 @@ BE_FUNC_CTYPE_DECLARE(be_ULP_sleep, "", "[i]"); // optional int arg
extern void be_ULP_load(struct bvm *vm, const uint8_t *buf, size_t size);
BE_FUNC_CTYPE_DECLARE(be_ULP_load, "", "@(bytes)~"); // pass: 1/ vm, 2/ bytes point, 3/ bytes size
-#include "be_fixed_ULP.h"
-
/* @const_object_info_begin
module ULP (scope: global) {
run, ctype_func(be_ULP_run)
@@ -51,5 +49,6 @@ module ULP (scope: global) {
adc_config, ctype_func(be_ULP_adc_config)
}
@const_object_info_end */
+#include "be_fixed_ULP.h"
-#endif // USE_BERRY_ULP
\ No newline at end of file
+#endif // USE_BERRY_ULP
diff --git a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c
index 4108fd16a..5e6818a00 100644
--- a/lib/libesp32/berry_tasmota/src/be_crypto_lib.c
+++ b/lib/libesp32/berry_tasmota/src/be_crypto_lib.c
@@ -7,8 +7,6 @@
*******************************************************************/
#include "be_constobj.h"
-#ifdef USE_ALEXA_AVS
-
extern int m_aes_gcm_init(bvm *vm);
extern int m_aes_gcm_encryt(bvm *vm);
extern int m_aes_gcm_decryt(bvm *vm);
@@ -23,7 +21,7 @@ extern int m_ec_c25519_sharedkey(bvm *vm);
/* @const_object_info_begin
-class be_class_aes_gcm (scope: global, name: AES_GCM, strings: weak) {
+class be_class_aes_gcm (scope: global, name: AES_GCM) {
.p1, var
.p2, var
@@ -33,16 +31,14 @@ class be_class_aes_gcm (scope: global, name: AES_GCM, strings: weak) {
tag, func(m_aes_gcm_tag)
}
-class be_class_ec_c25519 (scope: global, name: EC_C25519, strings: weak) {
+class be_class_ec_c25519 (scope: global, name: EC_C25519) {
public_key, func(m_ec_c25519_pubkey)
shared_key, func(m_ec_c25519_sharedkey)
}
-module crypto (scope: global, strings: weak) {
+module crypto (scope: global) {
AES_GCM, class(be_class_aes_gcm)
EC_C25519, class(be_class_ec_c25519)
}
@const_object_info_end */
-
-#endif // USE_ALEXA_AVS
diff --git a/lib/libesp32/berry_tasmota/src/be_dyn_class.c b/lib/libesp32/berry_tasmota/src/be_dyn_class.c
new file mode 100644
index 000000000..b41ac1b29
--- /dev/null
+++ b/lib/libesp32/berry_tasmota/src/be_dyn_class.c
@@ -0,0 +1,4 @@
+/********************************************************************
+ * Tasmota dyn class
+ *******************************************************************/
+#include "solidify/solidified_dyn.h"
diff --git a/lib/libesp32/berry_tasmota/src/be_mdns_module.cpp b/lib/libesp32/berry_tasmota/src/be_mdns_module.cpp
new file mode 100644
index 000000000..843090650
--- /dev/null
+++ b/lib/libesp32/berry_tasmota/src/be_mdns_module.cpp
@@ -0,0 +1,128 @@
+/********************************************************************
+ * Berry module `mdns`
+ *
+ * To use: `import mdns`
+ *
+ * MDNS support
+ *******************************************************************/
+#include "be_constobj.h"
+#include "be_mapping.h"
+#include "be_mem.h"
+
+#ifdef USE_DISCOVERY
+#include "mdns.h"
+#include
+
+//
+// `mdsn.start([hostname:string]) -> nil`
+// start or restart mdns, specify hostname or use tasmota.hostname() if none provided (default)
+extern char* NetworkHostname(void);
+static void m_mdns_start(struct bvm *vm, const char* hostname) {
+ esp_err_t err = mdns_init();
+ if (err != ESP_OK) {
+ be_raisef(vm, "internal_error", "could not initialize mdns err=%i", err);
+ }
+ if (hostname == NULL) {
+ hostname = NetworkHostname(); // revert to default hostname if none is specified
+ }
+ err = mdns_hostname_set(hostname);
+ if (err != ESP_OK) {
+ be_raisef(vm, "internal_error", "could not set hostname err=%i", err);
+ }
+}
+BE_FUNC_CTYPE_DECLARE(m_mdns_start, "", "@[s]")
+
+//
+// `msdn.stop() -> nil`
+// free all mdns resources
+static void m_mdns_stop(void) {
+ mdns_free();
+}
+BE_FUNC_CTYPE_DECLARE(m_mdns_stop, "", "")
+
+//
+// `mdns.set_hostname(hostname:string) -> nil`
+// change the hostname
+static void m_mdns_set_hostname(struct bvm *vm, const char * hostname) {
+ esp_err_t err = mdns_hostname_set(hostname);
+ if (err != ESP_OK) {
+ be_raisef(vm, "internal_error", "mdns set_hostname err=%i", err);
+ }
+}
+BE_FUNC_CTYPE_DECLARE(m_mdns_set_hostname, "", "@s")
+
+//
+// `mdns.add_service(service:string, proto:string, port:int, txt:map) -> nil`
+//
+// add a service declaration using the current hostname as instance name, and specify TXT fields as a `map`
+//
+// Test:
+// import mdns mdns.add_service("_arduino","_tcp",1111, {"board":"tasmota", "tcp_check":"no", "ssh_upload":"no", "auth_upload":"no"})
+//
+// import mdns mdns.add_service("_matterc","_udp", 5540, {"VP":"65521+32768", "SII":5000, "SAI":300, "T":1, "D":3840, "CM":1, "PH":33, "PI":""})
+static int32_t m_mdns_add_service(struct bvm *vm) {
+ int32_t top = be_top(vm);
+ if (top >= 3 && be_isstring(vm, 1) && be_isstring(vm, 2) && be_isint(vm, 3)) {
+ const char* service_type = be_tostring(vm, 1);
+ const char* proto = be_tostring(vm, 2);
+ uint16_t port = be_toint(vm, 3);
+
+ mdns_txt_item_t * txt_items = NULL;
+ int32_t txt_num = 0;
+ if (top >= 4 && be_ismapinstance(vm, 4)) {
+ // parse txt map
+ be_getmember(vm, 4, ".p");
+ int32_t map_len = be_data_size(vm, -1);
+ if (map_len > 0) {
+ uint32_t i= 0;
+ txt_items = (mdns_txt_item_t*) be_os_malloc(sizeof(mdns_txt_item_t) * map_len);
+ if (txt_items != NULL) {
+ be_pushiter(vm, -1); /* map iterator use 1 register */
+ while (be_iter_hasnext(vm, -2) && i < map_len) {
+ be_iter_next(vm, -2);
+ const char* key = be_tostring(vm, -2);
+ const char* val = be_tostring(vm, -1);
+ size_t key_len = strlen(key)+1;
+ txt_items[i].key = (const char*)be_os_malloc(key_len);
+ if (txt_items[i].key) { strcpy((char*)txt_items[i].key, key); }
+ size_t val_len = strlen(val)+1;
+ txt_items[i].value = (const char*)be_os_malloc(val_len);
+ if (txt_items[i].value) { strcpy((char*)txt_items[i].value, val); }
+ be_pop(vm, 2);
+ i++;
+ }
+ txt_num = i;
+ } else {
+ txt_num = 0; // failed to allocate, pretend it's empty
+ }
+ be_pop(vm, 1); /* pop iterator */
+ }
+ }
+ esp_err_t err = mdns_service_add(NULL, service_type, proto, port, txt_items, txt_num);
+ // free all allocated memory
+ if (txt_items != NULL) {
+ for (uint32_t i = 0; i < txt_num; i++) {
+ if (txt_items[i].key != NULL) { be_os_free((void*)txt_items[i].key); }
+ if (txt_items[i].value != NULL) { be_os_free((void*)txt_items[i].value); }
+ }
+ be_os_free(txt_items);
+ }
+ if (err != ESP_OK) {
+ be_raisef(vm, "internal_error", "mdns service_add err=%i", err);
+ }
+ be_return_nil(vm);
+ }
+ be_raise(vm, "value_error", "wrong or missing arguments");
+}
+
+/* @const_object_info_begin
+module mdns (scope: global) {
+ start, ctype_func(m_mdns_start)
+ stop, ctype_func(m_mdns_stop)
+ set_hostname, ctype_func(m_mdns_set_hostname)
+ add_service, func(m_mdns_add_service)
+}
+@const_object_info_end */
+#include "be_fixed_mdns.h"
+
+#endif // USE_DISCOVERY
\ No newline at end of file
diff --git a/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c b/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c
index db4f8648c..b3d7c540d 100644
--- a/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c
+++ b/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c
@@ -27,8 +27,10 @@ extern int l_strptime(bvm *vm);
extern int l_memory(bvm *vm);
extern int l_wifi(bvm *vm);
extern int l_eth(bvm *vm);
+extern int l_hostname(bvm *vm);
extern int l_yield(bvm *vm);
extern int l_delay(bvm *vm);
+extern int l_delay_microseconds(bvm *vm);
extern int l_scaleuint(bvm *vm);
extern int l_logInfo(bvm *vm);
extern int l_save(bvm *vm);
@@ -100,8 +102,10 @@ class be_class_tasmota (scope: global, name: Tasmota) {
memory, func(l_memory)
wifi, func(l_wifi)
eth, func(l_eth)
+ hostname, func(l_hostname)
yield, func(l_yield)
delay, func(l_delay)
+ delay_microseconds, func(l_delay_microseconds)
scale_uint, func(l_scaleuint)
log, func(l_logInfo)
save, func(l_save)
diff --git a/lib/libesp32/berry_tasmota/src/be_udp_lib.cpp b/lib/libesp32/berry_tasmota/src/be_udp_lib.cpp
index 439771fba..f6084b049 100644
--- a/lib/libesp32/berry_tasmota/src/be_udp_lib.cpp
+++ b/lib/libesp32/berry_tasmota/src/be_udp_lib.cpp
@@ -18,6 +18,10 @@
#include
#include "be_mapping.h"
+// Tasmota Logging
+extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
+enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
+
extern "C" {
// init()
@@ -37,22 +41,32 @@ extern "C" {
return be_call_c_func(vm, (void*) &be_udp_deinit_ntv, "=.p", "");
}
- // udp.begin(address:string, port:int) -> nil
- int32_t be_udp_begin_ntv(WiFiUDP *udp, const char *host, int32_t port) {
- IPAddress addr((uint32_t)0);
- // if no host or host is "" then we defult to INADDR_ANY (0.0.0.0)
- if(host && (*host != 0) && !WiFiGenericClass::hostByName(host, addr)){
- return 0;
- }
+ // udp.begin(address:string, port:int) -> bool
+ int32_t be_udp_begin_ntv(WiFiUDP *udp, int32_t port) {
+ IPAddress addr;
+ // AddLog(LOG_LEVEL_DEBUG, "BRY: udp.begin listening to '%s'", addr.toString().c_str());
return udp->begin(addr, port);
}
int32_t be_udp_begin(struct bvm *vm) {
- return be_call_c_func(vm, (void*) &be_udp_begin_ntv, "b", ".si");
+ if (be_top(vm) >= 3 && be_isstring(vm, 2)) {
+ // legacy string parameter, now ignored
+ return be_call_c_func(vm, (void*) &be_udp_begin_ntv, "b", ".-i");
+ } else {
+ return be_call_c_func(vm, (void*) &be_udp_begin_ntv, "b", ".i");
+ }
+ }
+
+ // udp.stop() -> nil
+ void be_udp_stop_ntv(WiFiUDP *udp) {
+ udp->stop();
+ }
+ int32_t be_udp_stop(struct bvm *vm) {
+ return be_call_c_func(vm, (void*) &be_udp_stop_ntv, "b", ".");
}
// udp.begin_multicast(address:string, port:int) -> nil
int32_t be_udp_begin_mcast_ntv(WiFiUDP *udp, const char *host, int32_t port) {
- IPAddress addr((uint32_t)0);
+ IPAddress addr;
if(!WiFiGenericClass::hostByName(host, addr)){
return 0;
}
@@ -64,10 +78,11 @@ extern "C" {
// udp.send(address:string, port:int, payload:bytes) -> bool
int32_t be_udp_send_ntv(WiFiUDP *udp, const char *host, int32_t port, const uint8_t* buf, int32_t len) {
- IPAddress addr((uint32_t)0);
+ IPAddress addr;
if (!WiFiGenericClass::hostByName(host, addr)){
return 0;
}
+ // AddLog(LOG_LEVEL_DEBUG, "BRY: udp.begin got host '%s'", addr.toString().c_str());
if (!udp->beginPacket(addr, port)) { return 0; }
int bw = udp->write(buf, len);
if (!bw) { return 0; }
@@ -94,10 +109,30 @@ extern "C" {
int32_t be_udp_read(struct bvm *vm) {
WiFiUDP *udp = (WiFiUDP*) be_convert_single_elt(vm, 1, NULL, NULL);
if (udp->parsePacket()) {
- int btr = udp->available();
- uint8_t * buf = (uint8_t*) be_pushbuffer(vm, btr);
+ int btr = udp->available(); // btr contains the size of bytes_to_read
+
+ int argc = be_top(vm);
+ if (argc >= 2 && be_isbytes(vm, 2)) {
+ // we have already a bytes() buffer
+ be_pushvalue(vm, 2); // push on top
+ // resize to btr
+ be_getmember(vm, -1, "resize");
+ be_pushvalue(vm, -2);
+ be_pushint(vm, btr);
+ be_call(vm, 2);
+ be_pop(vm, 3);
+ } else {
+ be_pushbytes(vm, nullptr, btr); // allocate a buffer of size btr filled with zeros
+ }
+
+ // get the address of the buffer
+ be_getmember(vm, -1, "_buffer");
+ be_pushvalue(vm, -2);
+ be_call(vm, 1);
+ uint8_t * buf = (uint8_t*) be_tocomptr(vm, -2);
+ be_pop(vm, 2);
+
int32_t btr2 = udp->read(buf, btr);
- be_pushbytes(vm, buf, btr2);
// set remotet ip
IPAddress remote_ip = udp->remoteIP();
@@ -139,6 +174,7 @@ class be_class_udp (scope: global, name: udp) {
begin, func(be_udp_begin)
begin_multicast, func(be_udp_begin_mcast)
read, func(be_udp_read)
+ close, func(be_udp_stop)
}
@const_object_info_end */
diff --git a/lib/libesp32/berry_tasmota/src/be_webclient_lib.c b/lib/libesp32/berry_tasmota/src/be_webclient_lib.c
index 87fb0afa2..ace4499a2 100644
--- a/lib/libesp32/berry_tasmota/src/be_webclient_lib.c
+++ b/lib/libesp32/berry_tasmota/src/be_webclient_lib.c
@@ -1,8 +1,8 @@
/********************************************************************
* Webclient mapped to Arduino framework
- *
+ *
* To use: `d = webclient()`
- *
+ *
*******************************************************************/
#include "be_constobj.h"
@@ -20,6 +20,9 @@ extern int wc_close(bvm *vm);
extern int wc_addheader(bvm *vm);
extern int wc_GET(bvm *vm);
extern int wc_POST(bvm *vm);
+extern int wc_PUT(bvm *vm);
+extern int wc_PATCH(bvm *vm);
+extern int wc_DELETE(bvm *vm);
extern int wc_getstring(bvm *vm);
extern int wc_writefile(bvm *vm);
extern int wc_writeflash(bvm *vm);
@@ -49,6 +52,9 @@ class be_class_webclient (scope: global, name: webclient) {
add_header, func(wc_addheader)
GET, func(wc_GET)
POST, func(wc_POST)
+ PUT, func(wc_PUT)
+ PATCH, func(wc_PATCH)
+ DELETE, func(wc_DELETE)
get_string, func(wc_getstring)
write_file, func(wc_writefile)
write_flash, func(wc_writeflash)
diff --git a/lib/libesp32/berry_tasmota/src/embedded/dyn.be b/lib/libesp32/berry_tasmota/src/embedded/dyn.be
new file mode 100644
index 000000000..5266304ba
--- /dev/null
+++ b/lib/libesp32/berry_tasmota/src/embedded/dyn.be
@@ -0,0 +1,27 @@
+#################################################################################
+# dyn class
+#
+# Allows to use a map with members
+# see https://github.com/berry-lang/berry/wiki/Chapter-8
+#################################################################################
+#@ solidify:dyn
+class dyn
+ var _attr
+ def init()
+ self._attr = {}
+ end
+ def setmember(name, value)
+ self._attr[name] = value
+ end
+ def member(name)
+ if self._attr.contains(name)
+ return self._attr[name]
+ else
+ import undefined
+ return undefined
+ end
+ end
+ def tostring()
+ return self._attr.tostring()
+ end
+end
diff --git a/lib/libesp32/berry_tasmota/src/embedded/leds.be b/lib/libesp32/berry_tasmota/src/embedded/leds.be
index 8cacf441c..ecde9b706 100644
--- a/lib/libesp32/berry_tasmota/src/embedded/leds.be
+++ b/lib/libesp32/berry_tasmota/src/embedded/leds.be
@@ -117,8 +117,14 @@ class Leds : Leds_ntv
def dirty()
self.call_native(5)
end
- def pixels_buffer()
- return self.call_native(6)
+ def pixels_buffer(old_buf)
+ var buf = self.call_native(6) # address of buffer in memory
+ if old_buf == nil
+ return bytes(buf, self.pixel_size() * self.pixel_count())
+ else
+ old_buf._change_buffer(buf)
+ return old_buf
+ end
end
def pixel_size()
return self.call_native(7)
@@ -249,6 +255,8 @@ class Leds : Leds_ntv
var offset
var h, w
var alternate # are rows in alternate mode (even/odd are reversed)
+ var pix_buffer
+ var pix_size
def init(strip, w, h, offset)
self.strip = strip
@@ -256,6 +264,9 @@ class Leds : Leds_ntv
self.h = h
self.w = w
self.alternate = false
+
+ self.pix_buffer = self.strip.pixels_buffer()
+ self.pix_size = self.strip.pixel_size()
end
def clear()
@@ -270,6 +281,7 @@ class Leds : Leds_ntv
# don't trigger on segment, you will need to trigger on full strip instead
if bool(force) || (self.offset == 0 && self.w * self.h == self.strip.leds)
self.strip.show()
+ self.pix_buffer = self.strip.pixels_buffer(self.pix_buffer) # update buffer after show()
end
end
def can_show()
@@ -282,10 +294,10 @@ class Leds : Leds_ntv
self.strip.dirty()
end
def pixels_buffer()
- return nil
+ return self.strip.pixels_buffer()
end
def pixel_size()
- return self.strip.pixel_size()
+ return self.pix_size
end
def pixel_count()
return self.w * self.h
@@ -304,6 +316,15 @@ class Leds : Leds_ntv
return self.strip.get_pixel_color(idx + self.offseta)
end
+ # setbytes(row, bytes)
+ # sets the raw bytes for `row`, copying at most 3 or 4 x col bytes
+ def set_bytes(row, buf, offset, len)
+ var h_bytes = self.h * self.pix_size
+ if (len > h_bytes) len = h_bytes end
+ var offset_in_matrix = (self.offset + row) * h_bytes
+ self.pix_buffer.setbytes(offset_in_matrix, buf, offset, len)
+ end
+
# Leds_matrix specific
def set_alternate(alt)
self.alternate = alt
diff --git a/lib/libesp32/berry_tasmota/src/embedded/leds_animator.be b/lib/libesp32/berry_tasmota/src/embedded/leds_animator.be
index 16573828b..a6f4fb337 100644
--- a/lib/libesp32/berry_tasmota/src/embedded/leds_animator.be
+++ b/lib/libesp32/berry_tasmota/src/embedded/leds_animator.be
@@ -17,7 +17,8 @@ class Leds_animator
#
self.clear() # clear all leds first
#
- tasmota.add_driver(self)
+ tasmota.add_fast_loop(/-> self.fast_loop())
+ # it may be useful to reduce Sleep time here
end
def add_anim(anim)
@@ -43,7 +44,7 @@ class Leds_animator
return self.bri
end
- def every_50ms()
+ def fast_loop()
if self.running
# run animators first
var i = 0
diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_dyn.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_dyn.h
new file mode 100644
index 000000000..ccb1c98e5
--- /dev/null
+++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_dyn.h
@@ -0,0 +1,157 @@
+/* Solidification of dyn.h */
+/********************************************************************\
+* Generated code, don't edit *
+\********************************************************************/
+#include "be_constobj.h"
+
+/********************************************************************
+** Solidified function: tostring
+********************************************************************/
+be_local_closure(dyn_tostring, /* name */
+ be_nested_proto(
+ 3, /* nstack */
+ 1, /* argc */
+ 2, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ ( &(const bvalue[ 2]) { /* constants */
+ /* K0 */ be_nested_str(_attr),
+ /* K1 */ be_nested_str(tostring),
+ }),
+ &be_const_str_tostring,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 4]) { /* code */
+ 0x88040100, // 0000 GETMBR R1 R0 K0
+ 0x8C040301, // 0001 GETMET R1 R1 K1
+ 0x7C040200, // 0002 CALL R1 1
+ 0x80040200, // 0003 RET 1 R1
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: member
+********************************************************************/
+be_local_closure(dyn_member, /* name */
+ be_nested_proto(
+ 5, /* nstack */
+ 2, /* argc */
+ 2, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ ( &(const bvalue[ 3]) { /* constants */
+ /* K0 */ be_nested_str(_attr),
+ /* K1 */ be_nested_str(contains),
+ /* K2 */ be_nested_str(undefined),
+ }),
+ &be_const_str_member,
+ &be_const_str_solidified,
+ ( &(const binstruction[12]) { /* code */
+ 0x88080100, // 0000 GETMBR R2 R0 K0
+ 0x8C080501, // 0001 GETMET R2 R2 K1
+ 0x5C100200, // 0002 MOVE R4 R1
+ 0x7C080400, // 0003 CALL R2 2
+ 0x780A0003, // 0004 JMPF R2 #0009
+ 0x88080100, // 0005 GETMBR R2 R0 K0
+ 0x94080401, // 0006 GETIDX R2 R2 R1
+ 0x80040400, // 0007 RET 1 R2
+ 0x70020001, // 0008 JMP #000B
+ 0xA40A0400, // 0009 IMPORT R2 K2
+ 0x80040400, // 000A RET 1 R2
+ 0x80000000, // 000B RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: setmember
+********************************************************************/
+be_local_closure(dyn_setmember, /* name */
+ be_nested_proto(
+ 4, /* nstack */
+ 3, /* argc */
+ 2, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ ( &(const bvalue[ 1]) { /* constants */
+ /* K0 */ be_nested_str(_attr),
+ }),
+ &be_const_str_setmember,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 3]) { /* code */
+ 0x880C0100, // 0000 GETMBR R3 R0 K0
+ 0x980C0202, // 0001 SETIDX R3 R1 R2
+ 0x80000000, // 0002 RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: init
+********************************************************************/
+be_local_closure(dyn_init, /* name */
+ be_nested_proto(
+ 2, /* nstack */
+ 1, /* argc */
+ 2, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ ( &(const bvalue[ 1]) { /* constants */
+ /* K0 */ be_nested_str(_attr),
+ }),
+ &be_const_str_init,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 4]) { /* code */
+ 0x60040013, // 0000 GETGBL R1 G19
+ 0x7C040000, // 0001 CALL R1 0
+ 0x90020001, // 0002 SETMBR R0 K0 R1
+ 0x80000000, // 0003 RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified class: dyn
+********************************************************************/
+be_local_class(dyn,
+ 1,
+ NULL,
+ be_nested_map(5,
+ ( (struct bmapnode*) &(const bmapnode[]) {
+ { be_const_key(tostring, 2), be_const_closure(dyn_tostring_closure) },
+ { be_const_key(member, 3), be_const_closure(dyn_member_closure) },
+ { be_const_key(init, 4), be_const_closure(dyn_init_closure) },
+ { be_const_key(setmember, -1), be_const_closure(dyn_setmember_closure) },
+ { be_const_key(_attr, -1), be_const_var(0) },
+ })),
+ (bstring*) &be_const_str_dyn
+);
+/*******************************************************************/
+
+void be_load_dyn_class(bvm *vm) {
+ be_pushntvclass(vm, &be_class_dyn);
+ be_setglobal(vm, "dyn");
+ be_pop(vm, 1);
+}
+/********************************************************************/
+/* End of solidification */
diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_leds.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_leds.h
index b872474e4..d7ca9b0bd 100644
--- a/lib/libesp32/berry_tasmota/src/solidify/solidified_leds.h
+++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_leds.h
@@ -736,66 +736,9 @@ be_local_closure(Leds_is_dirty, /* name */
/********************************************************************
-** Solidified function: pixel_count
+** Solidified function: pixels_buffer
********************************************************************/
-be_local_closure(Leds_matrix_pixel_count, /* name */
- be_nested_proto(
- 3, /* nstack */
- 1, /* argc */
- 2, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- ( &(const bvalue[ 2]) { /* constants */
- /* K0 */ be_nested_str(w),
- /* K1 */ be_nested_str(h),
- }),
- &be_const_str_pixel_count,
- &be_const_str_solidified,
- ( &(const binstruction[ 4]) { /* code */
- 0x88040100, // 0000 GETMBR R1 R0 K0
- 0x88080101, // 0001 GETMBR R2 R0 K1
- 0x08040202, // 0002 MUL R1 R1 R2
- 0x80040200, // 0003 RET 1 R1
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: set_alternate
-********************************************************************/
-be_local_closure(Leds_matrix_set_alternate, /* name */
- be_nested_proto(
- 2, /* nstack */
- 2, /* argc */
- 2, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- ( &(const bvalue[ 1]) { /* constants */
- /* K0 */ be_nested_str(alternate),
- }),
- &be_const_str_set_alternate,
- &be_const_str_solidified,
- ( &(const binstruction[ 2]) { /* code */
- 0x90020001, // 0000 SETMBR R0 K0 R1
- 0x80000000, // 0001 RET 0
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: pixel_size
-********************************************************************/
-be_local_closure(Leds_matrix_pixel_size, /* name */
+be_local_closure(Leds_matrix_pixels_buffer, /* name */
be_nested_proto(
3, /* nstack */
1, /* argc */
@@ -807,9 +750,9 @@ be_local_closure(Leds_matrix_pixel_size, /* name */
1, /* has constants */
( &(const bvalue[ 2]) { /* constants */
/* K0 */ be_nested_str(strip),
- /* K1 */ be_nested_str(pixel_size),
+ /* K1 */ be_nested_str(pixels_buffer),
}),
- &be_const_str_pixel_size,
+ &be_const_str_pixels_buffer,
&be_const_str_solidified,
( &(const binstruction[ 4]) { /* code */
0x88040100, // 0000 GETMBR R1 R0 K0
@@ -822,6 +765,54 @@ be_local_closure(Leds_matrix_pixel_size, /* name */
/*******************************************************************/
+/********************************************************************
+** Solidified function: init
+********************************************************************/
+be_local_closure(Leds_matrix_init, /* name */
+ be_nested_proto(
+ 7, /* nstack */
+ 5, /* argc */
+ 2, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ ( &(const bvalue[ 9]) { /* constants */
+ /* K0 */ be_nested_str(strip),
+ /* K1 */ be_nested_str(offset),
+ /* K2 */ be_nested_str(h),
+ /* K3 */ be_nested_str(w),
+ /* K4 */ be_nested_str(alternate),
+ /* K5 */ be_nested_str(pix_buffer),
+ /* K6 */ be_nested_str(pixels_buffer),
+ /* K7 */ be_nested_str(pix_size),
+ /* K8 */ be_nested_str(pixel_size),
+ }),
+ &be_const_str_init,
+ &be_const_str_solidified,
+ ( &(const binstruction[15]) { /* code */
+ 0x90020001, // 0000 SETMBR R0 K0 R1
+ 0x90020204, // 0001 SETMBR R0 K1 R4
+ 0x90020403, // 0002 SETMBR R0 K2 R3
+ 0x90020602, // 0003 SETMBR R0 K3 R2
+ 0x50140000, // 0004 LDBOOL R5 0 0
+ 0x90020805, // 0005 SETMBR R0 K4 R5
+ 0x88140100, // 0006 GETMBR R5 R0 K0
+ 0x8C140B06, // 0007 GETMET R5 R5 K6
+ 0x7C140200, // 0008 CALL R5 1
+ 0x90020A05, // 0009 SETMBR R0 K5 R5
+ 0x88140100, // 000A GETMBR R5 R0 K0
+ 0x8C140B08, // 000B GETMET R5 R5 K8
+ 0x7C140200, // 000C CALL R5 1
+ 0x90020E05, // 000D SETMBR R0 K7 R5
+ 0x80000000, // 000E RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
/********************************************************************
** Solidified function: set_pixel_color
********************************************************************/
@@ -857,6 +848,180 @@ be_local_closure(Leds_matrix_set_pixel_color, /* name */
/*******************************************************************/
+/********************************************************************
+** Solidified function: begin
+********************************************************************/
+be_local_closure(Leds_matrix_begin, /* name */
+ be_nested_proto(
+ 1, /* nstack */
+ 1, /* argc */
+ 2, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 0, /* has constants */
+ NULL, /* no const */
+ &be_const_str_begin,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 1]) { /* code */
+ 0x80000000, // 0000 RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: get_pixel_color
+********************************************************************/
+be_local_closure(Leds_matrix_get_pixel_color, /* name */
+ be_nested_proto(
+ 5, /* nstack */
+ 2, /* argc */
+ 2, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ ( &(const bvalue[ 3]) { /* constants */
+ /* K0 */ be_nested_str(strip),
+ /* K1 */ be_nested_str(get_pixel_color),
+ /* K2 */ be_nested_str(offseta),
+ }),
+ &be_const_str_get_pixel_color,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 6]) { /* code */
+ 0x88080100, // 0000 GETMBR R2 R0 K0
+ 0x8C080501, // 0001 GETMET R2 R2 K1
+ 0x88100102, // 0002 GETMBR R4 R0 K2
+ 0x00100204, // 0003 ADD R4 R1 R4
+ 0x7C080400, // 0004 CALL R2 2
+ 0x80040400, // 0005 RET 1 R2
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: pixel_size
+********************************************************************/
+be_local_closure(Leds_matrix_pixel_size, /* name */
+ be_nested_proto(
+ 2, /* nstack */
+ 1, /* argc */
+ 2, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ ( &(const bvalue[ 1]) { /* constants */
+ /* K0 */ be_nested_str(pix_size),
+ }),
+ &be_const_str_pixel_size,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 2]) { /* code */
+ 0x88040100, // 0000 GETMBR R1 R0 K0
+ 0x80040200, // 0001 RET 1 R1
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: set_alternate
+********************************************************************/
+be_local_closure(Leds_matrix_set_alternate, /* name */
+ be_nested_proto(
+ 2, /* nstack */
+ 2, /* argc */
+ 2, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ ( &(const bvalue[ 1]) { /* constants */
+ /* K0 */ be_nested_str(alternate),
+ }),
+ &be_const_str_set_alternate,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 2]) { /* code */
+ 0x90020001, // 0000 SETMBR R0 K0 R1
+ 0x80000000, // 0001 RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: can_show
+********************************************************************/
+be_local_closure(Leds_matrix_can_show, /* name */
+ be_nested_proto(
+ 3, /* nstack */
+ 1, /* argc */
+ 2, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ ( &(const bvalue[ 2]) { /* constants */
+ /* K0 */ be_nested_str(strip),
+ /* K1 */ be_nested_str(can_show),
+ }),
+ &be_const_str_can_show,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 4]) { /* code */
+ 0x88040100, // 0000 GETMBR R1 R0 K0
+ 0x8C040301, // 0001 GETMET R1 R1 K1
+ 0x7C040200, // 0002 CALL R1 1
+ 0x80040200, // 0003 RET 1 R1
+ })
+ )
+);
+/*******************************************************************/
+
+
+/********************************************************************
+** Solidified function: clear
+********************************************************************/
+be_local_closure(Leds_matrix_clear, /* name */
+ be_nested_proto(
+ 4, /* nstack */
+ 1, /* argc */
+ 2, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ ( &(const bvalue[ 3]) { /* constants */
+ /* K0 */ be_nested_str(clear_to),
+ /* K1 */ be_const_int(0),
+ /* K2 */ be_nested_str(show),
+ }),
+ &be_const_str_clear,
+ &be_const_str_solidified,
+ ( &(const binstruction[ 6]) { /* code */
+ 0x8C040100, // 0000 GETMET R1 R0 K0
+ 0x580C0001, // 0001 LDCONST R3 K1
+ 0x7C040400, // 0002 CALL R1 2
+ 0x8C040102, // 0003 GETMET R1 R0 K2
+ 0x7C040200, // 0004 CALL R1 1
+ 0x80000000, // 0005 RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
/********************************************************************
** Solidified function: set_matrix_pixel_color
********************************************************************/
@@ -919,58 +1084,9 @@ be_local_closure(Leds_matrix_set_matrix_pixel_color, /* name */
/********************************************************************
-** Solidified function: show
+** Solidified function: pixel_count
********************************************************************/
-be_local_closure(Leds_matrix_show, /* name */
- be_nested_proto(
- 4, /* nstack */
- 2, /* argc */
- 2, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- ( &(const bvalue[ 7]) { /* constants */
- /* K0 */ be_nested_str(offset),
- /* K1 */ be_const_int(0),
- /* K2 */ be_nested_str(w),
- /* K3 */ be_nested_str(h),
- /* K4 */ be_nested_str(strip),
- /* K5 */ be_nested_str(leds),
- /* K6 */ be_nested_str(show),
- }),
- &be_const_str_show,
- &be_const_str_solidified,
- ( &(const binstruction[18]) { /* code */
- 0x60080017, // 0000 GETGBL R2 G23
- 0x5C0C0200, // 0001 MOVE R3 R1
- 0x7C080200, // 0002 CALL R2 1
- 0x740A0009, // 0003 JMPT R2 #000E
- 0x88080100, // 0004 GETMBR R2 R0 K0
- 0x1C080501, // 0005 EQ R2 R2 K1
- 0x780A0009, // 0006 JMPF R2 #0011
- 0x88080102, // 0007 GETMBR R2 R0 K2
- 0x880C0103, // 0008 GETMBR R3 R0 K3
- 0x08080403, // 0009 MUL R2 R2 R3
- 0x880C0104, // 000A GETMBR R3 R0 K4
- 0x880C0705, // 000B GETMBR R3 R3 K5
- 0x1C080403, // 000C EQ R2 R2 R3
- 0x780A0002, // 000D JMPF R2 #0011
- 0x88080104, // 000E GETMBR R2 R0 K4
- 0x8C080506, // 000F GETMET R2 R2 K6
- 0x7C080200, // 0010 CALL R2 1
- 0x80000000, // 0011 RET 0
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: is_dirty
-********************************************************************/
-be_local_closure(Leds_matrix_is_dirty, /* name */
+be_local_closure(Leds_matrix_pixel_count, /* name */
be_nested_proto(
3, /* nstack */
1, /* argc */
@@ -981,15 +1097,15 @@ be_local_closure(Leds_matrix_is_dirty, /* name */
NULL, /* no sub protos */
1, /* has constants */
( &(const bvalue[ 2]) { /* constants */
- /* K0 */ be_nested_str(strip),
- /* K1 */ be_nested_str(is_dirty),
+ /* K0 */ be_nested_str(w),
+ /* K1 */ be_nested_str(h),
}),
- &be_const_str_is_dirty,
+ &be_const_str_pixel_count,
&be_const_str_solidified,
( &(const binstruction[ 4]) { /* code */
0x88040100, // 0000 GETMBR R1 R0 K0
- 0x8C040301, // 0001 GETMET R1 R1 K1
- 0x7C040200, // 0002 CALL R1 1
+ 0x88080101, // 0001 GETMBR R2 R0 K1
+ 0x08040202, // 0002 MUL R1 R1 R2
0x80040200, // 0003 RET 1 R1
})
)
@@ -997,6 +1113,62 @@ be_local_closure(Leds_matrix_is_dirty, /* name */
/*******************************************************************/
+/********************************************************************
+** Solidified function: show
+********************************************************************/
+be_local_closure(Leds_matrix_show, /* name */
+ be_nested_proto(
+ 5, /* nstack */
+ 2, /* argc */
+ 2, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ ( &(const bvalue[ 9]) { /* constants */
+ /* K0 */ be_nested_str(offset),
+ /* K1 */ be_const_int(0),
+ /* K2 */ be_nested_str(w),
+ /* K3 */ be_nested_str(h),
+ /* K4 */ be_nested_str(strip),
+ /* K5 */ be_nested_str(leds),
+ /* K6 */ be_nested_str(show),
+ /* K7 */ be_nested_str(pix_buffer),
+ /* K8 */ be_nested_str(pixels_buffer),
+ }),
+ &be_const_str_show,
+ &be_const_str_solidified,
+ ( &(const binstruction[23]) { /* code */
+ 0x60080017, // 0000 GETGBL R2 G23
+ 0x5C0C0200, // 0001 MOVE R3 R1
+ 0x7C080200, // 0002 CALL R2 1
+ 0x740A0009, // 0003 JMPT R2 #000E
+ 0x88080100, // 0004 GETMBR R2 R0 K0
+ 0x1C080501, // 0005 EQ R2 R2 K1
+ 0x780A000E, // 0006 JMPF R2 #0016
+ 0x88080102, // 0007 GETMBR R2 R0 K2
+ 0x880C0103, // 0008 GETMBR R3 R0 K3
+ 0x08080403, // 0009 MUL R2 R2 R3
+ 0x880C0104, // 000A GETMBR R3 R0 K4
+ 0x880C0705, // 000B GETMBR R3 R3 K5
+ 0x1C080403, // 000C EQ R2 R2 R3
+ 0x780A0007, // 000D JMPF R2 #0016
+ 0x88080104, // 000E GETMBR R2 R0 K4
+ 0x8C080506, // 000F GETMET R2 R2 K6
+ 0x7C080200, // 0010 CALL R2 1
+ 0x88080104, // 0011 GETMBR R2 R0 K4
+ 0x8C080508, // 0012 GETMET R2 R2 K8
+ 0x88100107, // 0013 GETMBR R4 R0 K7
+ 0x7C080400, // 0014 CALL R2 2
+ 0x90020E02, // 0015 SETMBR R0 K7 R2
+ 0x80000000, // 0016 RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
/********************************************************************
** Solidified function: clear_to
********************************************************************/
@@ -1044,100 +1216,6 @@ be_local_closure(Leds_matrix_clear_to, /* name */
/*******************************************************************/
-/********************************************************************
-** Solidified function: clear
-********************************************************************/
-be_local_closure(Leds_matrix_clear, /* name */
- be_nested_proto(
- 4, /* nstack */
- 1, /* argc */
- 2, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- ( &(const bvalue[ 3]) { /* constants */
- /* K0 */ be_nested_str(clear_to),
- /* K1 */ be_const_int(0),
- /* K2 */ be_nested_str(show),
- }),
- &be_const_str_clear,
- &be_const_str_solidified,
- ( &(const binstruction[ 6]) { /* code */
- 0x8C040100, // 0000 GETMET R1 R0 K0
- 0x580C0001, // 0001 LDCONST R3 K1
- 0x7C040400, // 0002 CALL R1 2
- 0x8C040102, // 0003 GETMET R1 R0 K2
- 0x7C040200, // 0004 CALL R1 1
- 0x80000000, // 0005 RET 0
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: pixels_buffer
-********************************************************************/
-be_local_closure(Leds_matrix_pixels_buffer, /* name */
- be_nested_proto(
- 2, /* nstack */
- 1, /* argc */
- 2, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 0, /* has constants */
- NULL, /* no const */
- &be_const_str_pixels_buffer,
- &be_const_str_solidified,
- ( &(const binstruction[ 2]) { /* code */
- 0x4C040000, // 0000 LDNIL R1
- 0x80040200, // 0001 RET 1 R1
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: init
-********************************************************************/
-be_local_closure(Leds_matrix_init, /* name */
- be_nested_proto(
- 6, /* nstack */
- 5, /* argc */
- 2, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- ( &(const bvalue[ 5]) { /* constants */
- /* K0 */ be_nested_str(strip),
- /* K1 */ be_nested_str(offset),
- /* K2 */ be_nested_str(h),
- /* K3 */ be_nested_str(w),
- /* K4 */ be_nested_str(alternate),
- }),
- &be_const_str_init,
- &be_const_str_solidified,
- ( &(const binstruction[ 7]) { /* code */
- 0x90020001, // 0000 SETMBR R0 K0 R1
- 0x90020204, // 0001 SETMBR R0 K1 R4
- 0x90020403, // 0002 SETMBR R0 K2 R3
- 0x90020602, // 0003 SETMBR R0 K3 R2
- 0x50140000, // 0004 LDBOOL R5 0 0
- 0x90020805, // 0005 SETMBR R0 K4 R5
- 0x80000000, // 0006 RET 0
- })
- )
-);
-/*******************************************************************/
-
-
/********************************************************************
** Solidified function: dirty
********************************************************************/
@@ -1168,39 +1246,6 @@ be_local_closure(Leds_matrix_dirty, /* name */
/*******************************************************************/
-/********************************************************************
-** Solidified function: get_pixel_color
-********************************************************************/
-be_local_closure(Leds_matrix_get_pixel_color, /* name */
- be_nested_proto(
- 5, /* nstack */
- 2, /* argc */
- 2, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- ( &(const bvalue[ 3]) { /* constants */
- /* K0 */ be_nested_str(strip),
- /* K1 */ be_nested_str(get_pixel_color),
- /* K2 */ be_nested_str(offseta),
- }),
- &be_const_str_get_pixel_color,
- &be_const_str_solidified,
- ( &(const binstruction[ 6]) { /* code */
- 0x88080100, // 0000 GETMBR R2 R0 K0
- 0x8C080501, // 0001 GETMET R2 R2 K1
- 0x88100102, // 0002 GETMBR R4 R0 K2
- 0x00100204, // 0003 ADD R4 R1 R4
- 0x7C080400, // 0004 CALL R2 2
- 0x80040400, // 0005 RET 1 R2
- })
- )
-);
-/*******************************************************************/
-
-
/********************************************************************
** Solidified function: get_alternate
********************************************************************/
@@ -1229,33 +1274,9 @@ be_local_closure(Leds_matrix_get_alternate, /* name */
/********************************************************************
-** Solidified function: begin
+** Solidified function: is_dirty
********************************************************************/
-be_local_closure(Leds_matrix_begin, /* name */
- be_nested_proto(
- 1, /* nstack */
- 1, /* argc */
- 2, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 0, /* has constants */
- NULL, /* no const */
- &be_const_str_begin,
- &be_const_str_solidified,
- ( &(const binstruction[ 1]) { /* code */
- 0x80000000, // 0000 RET 0
- })
- )
-);
-/*******************************************************************/
-
-
-/********************************************************************
-** Solidified function: can_show
-********************************************************************/
-be_local_closure(Leds_matrix_can_show, /* name */
+be_local_closure(Leds_matrix_is_dirty, /* name */
be_nested_proto(
3, /* nstack */
1, /* argc */
@@ -1267,9 +1288,9 @@ be_local_closure(Leds_matrix_can_show, /* name */
1, /* has constants */
( &(const bvalue[ 2]) { /* constants */
/* K0 */ be_nested_str(strip),
- /* K1 */ be_nested_str(can_show),
+ /* K1 */ be_nested_str(is_dirty),
}),
- &be_const_str_can_show,
+ &be_const_str_is_dirty,
&be_const_str_solidified,
( &(const binstruction[ 4]) { /* code */
0x88040100, // 0000 GETMBR R1 R0 K0
@@ -1282,35 +1303,84 @@ be_local_closure(Leds_matrix_can_show, /* name */
/*******************************************************************/
+/********************************************************************
+** Solidified function: set_bytes
+********************************************************************/
+be_local_closure(Leds_matrix_set_bytes, /* name */
+ be_nested_proto(
+ 13, /* nstack */
+ 5, /* argc */
+ 2, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ ( &(const bvalue[ 5]) { /* constants */
+ /* K0 */ be_nested_str(h),
+ /* K1 */ be_nested_str(pix_size),
+ /* K2 */ be_nested_str(offset),
+ /* K3 */ be_nested_str(pix_buffer),
+ /* K4 */ be_nested_str(setbytes),
+ }),
+ &be_const_str_set_bytes,
+ &be_const_str_solidified,
+ ( &(const binstruction[17]) { /* code */
+ 0x88140100, // 0000 GETMBR R5 R0 K0
+ 0x88180101, // 0001 GETMBR R6 R0 K1
+ 0x08140A06, // 0002 MUL R5 R5 R6
+ 0x24180805, // 0003 GT R6 R4 R5
+ 0x781A0000, // 0004 JMPF R6 #0006
+ 0x5C100A00, // 0005 MOVE R4 R5
+ 0x88180102, // 0006 GETMBR R6 R0 K2
+ 0x00180C01, // 0007 ADD R6 R6 R1
+ 0x08180C05, // 0008 MUL R6 R6 R5
+ 0x881C0103, // 0009 GETMBR R7 R0 K3
+ 0x8C1C0F04, // 000A GETMET R7 R7 K4
+ 0x5C240C00, // 000B MOVE R9 R6
+ 0x5C280400, // 000C MOVE R10 R2
+ 0x5C2C0600, // 000D MOVE R11 R3
+ 0x5C300800, // 000E MOVE R12 R4
+ 0x7C1C0A00, // 000F CALL R7 5
+ 0x80000000, // 0010 RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
/********************************************************************
** Solidified class: Leds_matrix
********************************************************************/
be_local_class(Leds_matrix,
- 5,
+ 7,
NULL,
- be_nested_map(21,
+ be_nested_map(24,
( (struct bmapnode*) &(const bmapnode[]) {
- { be_const_key(pixel_count, -1), be_const_closure(Leds_matrix_pixel_count_closure) },
- { be_const_key(h, 6), be_const_var(2) },
- { be_const_key(set_alternate, 7), be_const_closure(Leds_matrix_set_alternate_closure) },
- { be_const_key(pixel_size, 16), be_const_closure(Leds_matrix_pixel_size_closure) },
- { be_const_key(set_pixel_color, 19), be_const_closure(Leds_matrix_set_pixel_color_closure) },
- { be_const_key(set_matrix_pixel_color, 10), be_const_closure(Leds_matrix_set_matrix_pixel_color_closure) },
- { be_const_key(show, -1), be_const_closure(Leds_matrix_show_closure) },
- { be_const_key(alternate, -1), be_const_var(4) },
- { be_const_key(strip, -1), be_const_var(0) },
- { be_const_key(clear_to, -1), be_const_closure(Leds_matrix_clear_to_closure) },
- { be_const_key(w, 15), be_const_var(3) },
- { be_const_key(pixels_buffer, -1), be_const_closure(Leds_matrix_pixels_buffer_closure) },
+ { be_const_key(set_bytes, -1), be_const_closure(Leds_matrix_set_bytes_closure) },
+ { be_const_key(pix_buffer, -1), be_const_var(5) },
+ { be_const_key(pix_size, 20), be_const_var(6) },
{ be_const_key(init, -1), be_const_closure(Leds_matrix_init_closure) },
- { be_const_key(dirty, -1), be_const_closure(Leds_matrix_dirty_closure) },
- { be_const_key(get_pixel_color, -1), be_const_closure(Leds_matrix_get_pixel_color_closure) },
- { be_const_key(get_alternate, 17), be_const_closure(Leds_matrix_get_alternate_closure) },
- { be_const_key(offset, 8), be_const_var(1) },
- { be_const_key(clear, -1), be_const_closure(Leds_matrix_clear_closure) },
+ { be_const_key(set_pixel_color, 16), be_const_closure(Leds_matrix_set_pixel_color_closure) },
+ { be_const_key(alternate, -1), be_const_var(4) },
{ be_const_key(begin, -1), be_const_closure(Leds_matrix_begin_closure) },
- { be_const_key(is_dirty, -1), be_const_closure(Leds_matrix_is_dirty_closure) },
+ { be_const_key(h, -1), be_const_var(2) },
+ { be_const_key(get_pixel_color, -1), be_const_closure(Leds_matrix_get_pixel_color_closure) },
+ { be_const_key(pixel_size, 21), be_const_closure(Leds_matrix_pixel_size_closure) },
+ { be_const_key(set_alternate, -1), be_const_closure(Leds_matrix_set_alternate_closure) },
{ be_const_key(can_show, -1), be_const_closure(Leds_matrix_can_show_closure) },
+ { be_const_key(get_alternate, 13), be_const_closure(Leds_matrix_get_alternate_closure) },
+ { be_const_key(w, -1), be_const_var(3) },
+ { be_const_key(set_matrix_pixel_color, 12), be_const_closure(Leds_matrix_set_matrix_pixel_color_closure) },
+ { be_const_key(pixel_count, -1), be_const_closure(Leds_matrix_pixel_count_closure) },
+ { be_const_key(show, -1), be_const_closure(Leds_matrix_show_closure) },
+ { be_const_key(offset, -1), be_const_var(1) },
+ { be_const_key(clear_to, 17), be_const_closure(Leds_matrix_clear_to_closure) },
+ { be_const_key(dirty, -1), be_const_closure(Leds_matrix_dirty_closure) },
+ { be_const_key(clear, 10), be_const_closure(Leds_matrix_clear_closure) },
+ { be_const_key(strip, -1), be_const_var(0) },
+ { be_const_key(is_dirty, -1), be_const_closure(Leds_matrix_is_dirty_closure) },
+ { be_const_key(pixels_buffer, 0), be_const_closure(Leds_matrix_pixels_buffer_closure) },
})),
(bstring*) &be_const_str_Leds_matrix
);
@@ -1386,24 +1456,44 @@ be_local_closure(Leds_create_matrix, /* name */
********************************************************************/
be_local_closure(Leds_pixels_buffer, /* name */
be_nested_proto(
- 4, /* nstack */
- 1, /* argc */
+ 8, /* nstack */
+ 2, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
- ( &(const bvalue[ 1]) { /* constants */
+ ( &(const bvalue[ 4]) { /* constants */
/* K0 */ be_nested_str(call_native),
+ /* K1 */ be_nested_str(pixel_size),
+ /* K2 */ be_nested_str(pixel_count),
+ /* K3 */ be_nested_str(_change_buffer),
}),
&be_const_str_pixels_buffer,
&be_const_str_solidified,
- ( &(const binstruction[ 4]) { /* code */
- 0x8C040100, // 0000 GETMET R1 R0 K0
- 0x540E0005, // 0001 LDINT R3 6
- 0x7C040400, // 0002 CALL R1 2
- 0x80040200, // 0003 RET 1 R1
+ ( &(const binstruction[21]) { /* code */
+ 0x8C080100, // 0000 GETMET R2 R0 K0
+ 0x54120005, // 0001 LDINT R4 6
+ 0x7C080400, // 0002 CALL R2 2
+ 0x4C0C0000, // 0003 LDNIL R3
+ 0x1C0C0203, // 0004 EQ R3 R1 R3
+ 0x780E0009, // 0005 JMPF R3 #0010
+ 0x600C0015, // 0006 GETGBL R3 G21
+ 0x5C100400, // 0007 MOVE R4 R2
+ 0x8C140101, // 0008 GETMET R5 R0 K1
+ 0x7C140200, // 0009 CALL R5 1
+ 0x8C180102, // 000A GETMET R6 R0 K2
+ 0x7C180200, // 000B CALL R6 1
+ 0x08140A06, // 000C MUL R5 R5 R6
+ 0x7C0C0400, // 000D CALL R3 2
+ 0x80040600, // 000E RET 1 R3
+ 0x70020003, // 000F JMP #0014
+ 0x8C0C0303, // 0010 GETMET R3 R1 K3
+ 0x5C140400, // 0011 MOVE R5 R2
+ 0x7C0C0400, // 0012 CALL R3 2
+ 0x80040200, // 0013 RET 1 R1
+ 0x80000000, // 0014 RET 0
})
)
);
diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_leds_animator.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_leds_animator.h
index 1952c41dd..4d6d70726 100644
--- a/lib/libesp32/berry_tasmota/src/solidify/solidified_leds_animator.h
+++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_leds_animator.h
@@ -14,8 +14,32 @@ be_local_closure(Leds_animator_init, /* name */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
+ 1, /* has sup protos */
+ ( &(const struct bproto*[ 1]) {
+ be_nested_proto(
+ 2, /* nstack */
+ 0, /* argc */
+ 0, /* varg */
+ 1, /* has upvals */
+ ( &(const bupvaldesc[ 1]) { /* upvals */
+ be_local_const_upval(1, 0),
+ }),
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ ( &(const bvalue[ 1]) { /* constants */
+ /* K0 */ be_nested_str_weak(fast_loop),
+ }),
+ be_str_weak(_X3Clambda_X3E),
+ &be_const_str_solidified,
+ ( &(const binstruction[ 4]) { /* code */
+ 0x68000000, // 0000 GETUPV R0 U0
+ 0x8C000100, // 0001 GETMET R0 R0 K0
+ 0x7C000200, // 0002 CALL R0 1
+ 0x80040000, // 0003 RET 1 R0
+ })
+ ),
+ }),
1, /* has constants */
( &(const bvalue[ 8]) { /* constants */
/* K0 */ be_nested_str_weak(strip),
@@ -25,11 +49,11 @@ be_local_closure(Leds_animator_init, /* name */
/* K4 */ be_nested_str_weak(animators),
/* K5 */ be_nested_str_weak(clear),
/* K6 */ be_nested_str_weak(tasmota),
- /* K7 */ be_nested_str_weak(add_driver),
+ /* K7 */ be_nested_str_weak(add_fast_loop),
}),
be_str_weak(init),
&be_const_str_solidified,
- ( &(const binstruction[18]) { /* code */
+ ( &(const binstruction[19]) { /* code */
0x90020001, // 0000 SETMBR R0 K0 R1
0x540A0031, // 0001 LDINT R2 50
0x90020202, // 0002 SETMBR R0 K1 R2
@@ -45,9 +69,10 @@ be_local_closure(Leds_animator_init, /* name */
0x7C080200, // 000C CALL R2 1
0xB80A0C00, // 000D GETNGBL R2 K6
0x8C080507, // 000E GETMET R2 R2 K7
- 0x5C100000, // 000F MOVE R4 R0
+ 0x84100000, // 000F CLOSURE R4 P0
0x7C080400, // 0010 CALL R2 2
- 0x80000000, // 0011 RET 0
+ 0xA0000000, // 0011 CLOSE R0
+ 0x80000000, // 0012 RET 0
})
)
);
@@ -55,11 +80,11 @@ be_local_closure(Leds_animator_init, /* name */
/********************************************************************
-** Solidified function: set_bri
+** Solidified function: add_anim
********************************************************************/
-be_local_closure(Leds_animator_set_bri, /* name */
+be_local_closure(Leds_animator_add_anim, /* name */
be_nested_proto(
- 2, /* nstack */
+ 5, /* nstack */
2, /* argc */
2, /* varg */
0, /* has upvals */
@@ -67,14 +92,21 @@ be_local_closure(Leds_animator_set_bri, /* name */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
- ( &(const bvalue[ 1]) { /* constants */
- /* K0 */ be_nested_str_weak(bri),
+ ( &(const bvalue[ 3]) { /* constants */
+ /* K0 */ be_nested_str_weak(animators),
+ /* K1 */ be_nested_str_weak(push),
+ /* K2 */ be_nested_str_weak(run),
}),
- be_str_weak(set_bri),
+ be_str_weak(add_anim),
&be_const_str_solidified,
- ( &(const binstruction[ 2]) { /* code */
- 0x90020001, // 0000 SETMBR R0 K0 R1
- 0x80000000, // 0001 RET 0
+ ( &(const binstruction[ 7]) { /* code */
+ 0x88080100, // 0000 GETMBR R2 R0 K0
+ 0x8C080501, // 0001 GETMET R2 R2 K1
+ 0x5C100200, // 0002 MOVE R4 R1
+ 0x7C080400, // 0003 CALL R2 2
+ 0x8C080302, // 0004 GETMET R2 R1 K2
+ 0x7C080200, // 0005 CALL R2 1
+ 0x80000000, // 0006 RET 0
})
)
);
@@ -109,6 +141,62 @@ be_local_closure(Leds_animator_stop, /* name */
/*******************************************************************/
+/********************************************************************
+** Solidified function: fast_loop
+********************************************************************/
+be_local_closure(Leds_animator_fast_loop, /* name */
+ be_nested_proto(
+ 6, /* nstack */
+ 1, /* argc */
+ 2, /* varg */
+ 0, /* has upvals */
+ NULL, /* no upvals */
+ 0, /* has sup protos */
+ NULL, /* no sub protos */
+ 1, /* has constants */
+ ( &(const bvalue[ 7]) { /* constants */
+ /* K0 */ be_nested_str_weak(running),
+ /* K1 */ be_const_int(0),
+ /* K2 */ be_nested_str_weak(animators),
+ /* K3 */ be_nested_str_weak(is_running),
+ /* K4 */ be_nested_str_weak(animate),
+ /* K5 */ be_const_int(1),
+ /* K6 */ be_nested_str_weak(remove),
+ }),
+ be_str_weak(fast_loop),
+ &be_const_str_solidified,
+ ( &(const binstruction[25]) { /* code */
+ 0x88040100, // 0000 GETMBR R1 R0 K0
+ 0x78060015, // 0001 JMPF R1 #0018
+ 0x58040001, // 0002 LDCONST R1 K1
+ 0x6008000C, // 0003 GETGBL R2 G12
+ 0x880C0102, // 0004 GETMBR R3 R0 K2
+ 0x7C080200, // 0005 CALL R2 1
+ 0x14080202, // 0006 LT R2 R1 R2
+ 0x780A000D, // 0007 JMPF R2 #0016
+ 0x88080102, // 0008 GETMBR R2 R0 K2
+ 0x94080401, // 0009 GETIDX R2 R2 R1
+ 0x8C0C0503, // 000A GETMET R3 R2 K3
+ 0x7C0C0200, // 000B CALL R3 1
+ 0x780E0003, // 000C JMPF R3 #0011
+ 0x8C0C0504, // 000D GETMET R3 R2 K4
+ 0x7C0C0200, // 000E CALL R3 1
+ 0x00040305, // 000F ADD R1 R1 K5
+ 0x70020003, // 0010 JMP #0015
+ 0x880C0102, // 0011 GETMBR R3 R0 K2
+ 0x8C0C0706, // 0012 GETMET R3 R3 K6
+ 0x5C140200, // 0013 MOVE R5 R1
+ 0x7C0C0400, // 0014 CALL R3 2
+ 0x7001FFEC, // 0015 JMP #0003
+ 0x8C080104, // 0016 GETMET R2 R0 K4
+ 0x7C080200, // 0017 CALL R2 1
+ 0x80000000, // 0018 RET 0
+ })
+ )
+);
+/*******************************************************************/
+
+
/********************************************************************
** Solidified function: animate
********************************************************************/
@@ -165,55 +253,26 @@ be_local_closure(Leds_animator_remove, /* name */
/********************************************************************
-** Solidified function: every_50ms
+** Solidified function: set_bri
********************************************************************/
-be_local_closure(Leds_animator_every_50ms, /* name */
+be_local_closure(Leds_animator_set_bri, /* name */
be_nested_proto(
- 6, /* nstack */
- 1, /* argc */
+ 2, /* nstack */
+ 2, /* argc */
2, /* varg */
0, /* has upvals */
NULL, /* no upvals */
0, /* has sup protos */
NULL, /* no sub protos */
1, /* has constants */
- ( &(const bvalue[ 7]) { /* constants */
- /* K0 */ be_nested_str_weak(running),
- /* K1 */ be_const_int(0),
- /* K2 */ be_nested_str_weak(animators),
- /* K3 */ be_nested_str_weak(is_running),
- /* K4 */ be_nested_str_weak(animate),
- /* K5 */ be_const_int(1),
- /* K6 */ be_nested_str_weak(remove),
+ ( &(const bvalue[ 1]) { /* constants */
+ /* K0 */ be_nested_str_weak(bri),
}),
- be_str_weak(every_50ms),
+ be_str_weak(set_bri),
&be_const_str_solidified,
- ( &(const binstruction[25]) { /* code */
- 0x88040100, // 0000 GETMBR R1 R0 K0
- 0x78060015, // 0001 JMPF R1 #0018
- 0x58040001, // 0002 LDCONST R1 K1
- 0x6008000C, // 0003 GETGBL R2 G12
- 0x880C0102, // 0004 GETMBR R3 R0 K2
- 0x7C080200, // 0005 CALL R2 1
- 0x14080202, // 0006 LT R2 R1 R2
- 0x780A000D, // 0007 JMPF R2 #0016
- 0x88080102, // 0008 GETMBR R2 R0 K2
- 0x94080401, // 0009 GETIDX R2 R2 R1
- 0x8C0C0503, // 000A GETMET R3 R2 K3
- 0x7C0C0200, // 000B CALL R3 1
- 0x780E0003, // 000C JMPF R3 #0011
- 0x8C0C0504, // 000D GETMET R3 R2 K4
- 0x7C0C0200, // 000E CALL R3 1
- 0x00040305, // 000F ADD R1 R1 K5
- 0x70020003, // 0010 JMP #0015
- 0x880C0102, // 0011 GETMBR R3 R0 K2
- 0x8C0C0706, // 0012 GETMET R3 R3 K6
- 0x5C140200, // 0013 MOVE R5 R1
- 0x7C0C0400, // 0014 CALL R3 2
- 0x7001FFEC, // 0015 JMP #0003
- 0x8C080104, // 0016 GETMET R2 R0 K4
- 0x7C080200, // 0017 CALL R2 1
- 0x80000000, // 0018 RET 0
+ ( &(const binstruction[ 2]) { /* code */
+ 0x90020001, // 0000 SETMBR R0 K0 R1
+ 0x80000000, // 0001 RET 0
})
)
);
@@ -275,40 +334,6 @@ be_local_closure(Leds_animator_start, /* name */
/*******************************************************************/
-/********************************************************************
-** Solidified function: add_anim
-********************************************************************/
-be_local_closure(Leds_animator_add_anim, /* name */
- be_nested_proto(
- 5, /* nstack */
- 2, /* argc */
- 2, /* varg */
- 0, /* has upvals */
- NULL, /* no upvals */
- 0, /* has sup protos */
- NULL, /* no sub protos */
- 1, /* has constants */
- ( &(const bvalue[ 3]) { /* constants */
- /* K0 */ be_nested_str_weak(animators),
- /* K1 */ be_nested_str_weak(push),
- /* K2 */ be_nested_str_weak(run),
- }),
- be_str_weak(add_anim),
- &be_const_str_solidified,
- ( &(const binstruction[ 7]) { /* code */
- 0x88080100, // 0000 GETMBR R2 R0 K0
- 0x8C080501, // 0001 GETMET R2 R2 K1
- 0x5C100200, // 0002 MOVE R4 R1
- 0x7C080400, // 0003 CALL R2 2
- 0x8C080302, // 0004 GETMET R2 R1 K2
- 0x7C080200, // 0005 CALL R2 1
- 0x80000000, // 0006 RET 0
- })
- )
-);
-/*******************************************************************/
-
-
/********************************************************************
** Solidified function: clear
********************************************************************/
@@ -352,18 +377,18 @@ be_local_class(Leds_animator,
( (struct bmapnode*) &(const bmapnode[]) {
{ be_const_key_weak(init, 12), be_const_closure(Leds_animator_init_closure) },
{ be_const_key_weak(clear, -1), be_const_closure(Leds_animator_clear_closure) },
- { be_const_key_weak(stop, -1), be_const_closure(Leds_animator_stop_closure) },
- { be_const_key_weak(strip, 4), be_const_var(0) },
+ { be_const_key_weak(stop, 13), be_const_closure(Leds_animator_stop_closure) },
+ { be_const_key_weak(add_anim, 4), be_const_closure(Leds_animator_add_anim_closure) },
{ be_const_key_weak(pixel_count, 6), be_const_var(1) },
{ be_const_key_weak(animate, -1), be_const_closure(Leds_animator_animate_closure) },
- { be_const_key_weak(add_anim, 13), be_const_closure(Leds_animator_add_anim_closure) },
+ { be_const_key_weak(animators, 7), be_const_var(4) },
+ { be_const_key_weak(strip, -1), be_const_var(0) },
{ be_const_key_weak(bri, -1), be_const_var(2) },
- { be_const_key_weak(every_50ms, -1), be_const_closure(Leds_animator_every_50ms_closure) },
- { be_const_key_weak(remove, 7), be_const_closure(Leds_animator_remove_closure) },
+ { be_const_key_weak(remove, 8), be_const_closure(Leds_animator_remove_closure) },
{ be_const_key_weak(get_bri, -1), be_const_closure(Leds_animator_get_bri_closure) },
{ be_const_key_weak(start, -1), be_const_closure(Leds_animator_start_closure) },
{ be_const_key_weak(running, -1), be_const_var(3) },
- { be_const_key_weak(animators, -1), be_const_var(4) },
+ { be_const_key_weak(fast_loop, -1), be_const_closure(Leds_animator_fast_loop_closure) },
{ be_const_key_weak(set_bri, 1), be_const_closure(Leds_animator_set_bri_closure) },
})),
be_str_weak(Leds_animator)
diff --git a/lib/libesp32/esp32-camera/LICENSE b/lib/libesp32/esp32-camera/LICENSE
deleted file mode 100644
index d64569567..000000000
--- a/lib/libesp32/esp32-camera/LICENSE
+++ /dev/null
@@ -1,202 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/lib/libesp32/esp32-camera/README.md b/lib/libesp32/esp32-camera/README.md
deleted file mode 100644
index e93d5cdba..000000000
--- a/lib/libesp32/esp32-camera/README.md
+++ /dev/null
@@ -1,368 +0,0 @@
-# ESP32 Camera Driver
-
-[](https://github.com/espressif/esp32-camera/actions/workflows/build.yml)
-## General Information
-
-This repository hosts ESP32 series Soc compatible driver for image sensors. Additionally it provides a few tools, which allow converting the captured frame data to the more common BMP and JPEG formats.
-
-### Supported Soc
-
-- ESP32
-- ESP32-S2
-- ESP32-S3
-
-### Supported Sensor
-
-| model | max resolution | color type | output format | Len Size |
-| ------- | -------------- | ---------- | ------------------------------------------------------------ | -------- |
-| OV2640 | 1600 x 1200 | color | YUV(422/420)/YCbCr422
RGB565/555
8-bit compressed data
8/10-bit Raw RGB data | 1/4" |
-| OV3660 | 2048 x 1536 | color | raw RGB data
RGB565/555/444
CCIR656
YCbCr422
compression | 1/5" |
-| OV5640 | 2592 x 1944 | color | RAW RGB
RGB565/555/444
CCIR656
YUV422/420
YCbCr422
compression | 1/4" |
-| OV7670 | 640 x 480 | color | Raw Bayer RGB
Processed Bayer RGB
YUV/YCbCr422
GRB422
RGB565/555 | 1/6" |
-| OV7725 | 640 x 480 | color | Raw RGB
GRB 422
RGB565/555/444
YCbCr 422 | 1/4" |
-| NT99141 | 1280 x 720 | color | YCbCr 422
RGB565/555/444
Raw
CCIR656
JPEG compression | 1/4" |
-| GC032A | 640 x 480 | color | YUV/YCbCr422
RAW Bayer
RGB565 | 1/10" |
-| GC0308 | 640 x 480 | color | YUV/YCbCr422
RAW Bayer
RGB565 | 1/6.5" |
-| GC2145 | 1600 x 1200 | color | YUV/YCbCr422
RAW Bayer
RGB565 | 1/5" |
-
-## Important to Remember
-
-- Except when using CIF or lower resolution with JPEG, the driver requires PSRAM to be installed and activated.
-- Using YUV or RGB puts a lot of strain on the chip because writing to PSRAM is not particularly fast. The result is that image data might be missing. This is particularly true if WiFi is enabled. If you need RGB data, it is recommended that JPEG is captured and then turned into RGB using `fmt2rgb888` or `fmt2bmp`/`frame2bmp`.
-- When 1 frame buffer is used, the driver will wait for the current frame to finish (VSYNC) and start I2S DMA. After the frame is acquired, I2S will be stopped and the frame buffer returned to the application. This approach gives more control over the system, but results in longer time to get the frame.
-- When 2 or more frame bufers are used, I2S is running in continuous mode and each frame is pushed to a queue that the application can access. This approach puts more strain on the CPU/Memory, but allows for double the frame rate. Please use only with JPEG.
-
-## Installation Instructions
-
-
-### Using esp-idf
-
-- Clone or download and extract the repository to the components folder of your ESP-IDF project
-- Enable PSRAM in `menuconfig` (also set Flash and PSRAM frequiencies to 80MHz)
-- Include `esp_camera.h` in your code
-
-### Using PlatformIO
-
-The easy way -- on the `env` section of `platformio.ini`, add the following:
-
-```ini
-[env]
-lib_deps =
- esp32-camera
-```
-
-Now the `esp_camera.h` is available to be included:
-
-```c
-#include "esp_camera.h"
-```
-
-Enable PSRAM on `menuconfig` or type it direclty on `sdkconfig`. Check the [official doc](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/kconfig.html#config-esp32-spiram-support) for more info.
-
-```
-CONFIG_ESP32_SPIRAM_SUPPORT=y
-```
-
-***Arduino*** The easy-way (content above) only seems to work if you're using `framework=arduino` which seems to take a bunch of the guesswork out (thanks Arduino!) but also suck up a lot more memory and flash, almost crippling the performance. If you plan to use the `framework=espidf` then read the sections below carefully!!
-
-## Platform.io lib/submodule (for framework=espidf)
-
-It's probably easier to just skip the platform.io library registry version and link the git repo as a submodule. (i.e. using code outside the platform.io library management). In this example we will install this as a submodule inside the platform.io $project/lib folder:
-```
-cd $project\lib
-git submodule add -b master https://github.com/espressif/esp32-camera.git
-```
-
-Then in `platformio.ini` file
-```
-build_flags =
- -I../lib/esp32-camera
-```
-After that `#include "esp_camera.h"` statement will be available. Now the module is included, and you're hopefully back to the same place as the easy-Arduino way.
-
-**Warning about platform.io/espidf and fresh (not initialized) git repos**
-There is a sharp-edge on you'll discover in the platform.io build process (in espidf v3.3 & 4.0.1) where a project which has only had `git init` but nothing committed will crash platform.io build process with highly non-useful output. The cause is due to lack of a version (making you think you did something wrong, when you didn't at all) - the output is horribly non-descript. Solution: the devs want you to create a file called version.txt with a number in it, or simply commit any file to the projects git repo and use git. This happens because platform.io build process tries to be too clever and determine the build version number from the git repo - it's a sharp edge you'll only encounter if you're experimenting on a new project with no commits .. like wtf is my camera not working let's try a 'clean project'?!
-
-## Platform.io Kconfig
-Kconfig is used by the platform.io menuconfig (accessed by running: `pio run -t menuconfig`) to interactively manage the various #ifdef statements throughout the espidf and supporting libraries (i.e. this repo: esp32-camera and arduino-esp32.git). The menuconfig process generates the `sdkconfig` file which is ultimately used behind the scenes by espidf compile+build process.
-
-**Make sure to append or symlink** [this `Kconfig`](./Kconfig) content into the `Kconfig` of your project.
-
-You symlink (or copy) the included Kconfig into your platform.io projects src directory. The file should be named `Kconfig.projbuild` in your projects src\ directory or you could also add the library path to a CMakefile.txt and hope the `Kconfig` (or `Kconfig.projbuild`) gets discovered by the menuconfig process, though this unpredictable for me.
-
-The unpredictable wonky behavior in platform.io build process around Kconfig naming (Kconfig vs. Kconfig.projbuild) occurs between espidf versions 3.3 and 4.0 - but if you don't see "Camera configuration" in your `pio run -t menuconfig` then there is no point trying to test camera code (it may compile, but it probably won't work!) and it seems the platform.io devs (when they built their wrapper around the espidf menuconfig) didn't implement it properly. You've probably already figured out you can't use the espidf build tools since the files are in totally different locations and also different versions with sometimes different syntax. This is one of those times you might consider changing the `platformio.ini` from `platform=espressif32` to `platform=https://github.com/platformio/platform-espressif32.git#develop` to get a more recent version of the espidf 4.0 tools.
-
-However with a bit of patience and experimenting you'll figure the Kconfig out. Once Kconfig (or Kconfig.projbuild) is working then you will be able to choose the configurations according to your setup or the camera libraries will be compiled. Although you might also need to delete your .pio/build directory before the options appear .. again, the `pio run -t menuconfig` doens't always notice the new Kconfig files!
-
-If you miss-skip-ignore this critical step the camera module will compile but camera logic inside the library will be 'empty' because the Kconfig sets the proper #ifdef statements during the build process to initialize the selected cameras. It's very not optional!
-
-
-## Examples
-
-### Initialization
-
-```c
-#include "esp_camera.h"
-
-//WROVER-KIT PIN Map
-#define CAM_PIN_PWDN -1 //power down is not used
-#define CAM_PIN_RESET -1 //software reset will be performed
-#define CAM_PIN_XCLK 21
-#define CAM_PIN_SIOD 26
-#define CAM_PIN_SIOC 27
-
-#define CAM_PIN_D7 35
-#define CAM_PIN_D6 34
-#define CAM_PIN_D5 39
-#define CAM_PIN_D4 36
-#define CAM_PIN_D3 19
-#define CAM_PIN_D2 18
-#define CAM_PIN_D1 5
-#define CAM_PIN_D0 4
-#define CAM_PIN_VSYNC 25
-#define CAM_PIN_HREF 23
-#define CAM_PIN_PCLK 22
-
-static camera_config_t camera_config = {
- .pin_pwdn = CAM_PIN_PWDN,
- .pin_reset = CAM_PIN_RESET,
- .pin_xclk = CAM_PIN_XCLK,
- .pin_sscb_sda = CAM_PIN_SIOD,
- .pin_sscb_scl = CAM_PIN_SIOC,
-
- .pin_d7 = CAM_PIN_D7,
- .pin_d6 = CAM_PIN_D6,
- .pin_d5 = CAM_PIN_D5,
- .pin_d4 = CAM_PIN_D4,
- .pin_d3 = CAM_PIN_D3,
- .pin_d2 = CAM_PIN_D2,
- .pin_d1 = CAM_PIN_D1,
- .pin_d0 = CAM_PIN_D0,
- .pin_vsync = CAM_PIN_VSYNC,
- .pin_href = CAM_PIN_HREF,
- .pin_pclk = CAM_PIN_PCLK,
-
- .xclk_freq_hz = 20000000,//EXPERIMENTAL: Set to 16MHz on ESP32-S2 or ESP32-S3 to enable EDMA mode
- .ledc_timer = LEDC_TIMER_0,
- .ledc_channel = LEDC_CHANNEL_0,
-
- .pixel_format = PIXFORMAT_JPEG,//YUV422,GRAYSCALE,RGB565,JPEG
- .frame_size = FRAMESIZE_UXGA,//QQVGA-QXGA Do not use sizes above QVGA when not JPEG
-
- .jpeg_quality = 12, //0-63 lower number means higher quality
- .fb_count = 1, //if more than one, i2s runs in continuous mode. Use only with JPEG
- .grab_mode = CAMERA_GRAB_WHEN_EMPTY//CAMERA_GRAB_LATEST. Sets when buffers should be filled
-};
-
-esp_err_t camera_init(){
- //power up the camera if PWDN pin is defined
- if(CAM_PIN_PWDN != -1){
- pinMode(CAM_PIN_PWDN, OUTPUT);
- digitalWrite(CAM_PIN_PWDN, LOW);
- }
-
- //initialize the camera
- esp_err_t err = esp_camera_init(&camera_config);
- if (err != ESP_OK) {
- ESP_LOGE(TAG, "Camera Init Failed");
- return err;
- }
-
- return ESP_OK;
-}
-
-esp_err_t camera_capture(){
- //acquire a frame
- camera_fb_t * fb = esp_camera_fb_get();
- if (!fb) {
- ESP_LOGE(TAG, "Camera Capture Failed");
- return ESP_FAIL;
- }
- //replace this with your own function
- process_image(fb->width, fb->height, fb->format, fb->buf, fb->len);
-
- //return the frame buffer back to the driver for reuse
- esp_camera_fb_return(fb);
- return ESP_OK;
-}
-```
-
-### JPEG HTTP Capture
-
-```c
-#include "esp_camera.h"
-#include "esp_http_server.h"
-#include "esp_timer.h"
-
-typedef struct {
- httpd_req_t *req;
- size_t len;
-} jpg_chunking_t;
-
-static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len){
- jpg_chunking_t *j = (jpg_chunking_t *)arg;
- if(!index){
- j->len = 0;
- }
- if(httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK){
- return 0;
- }
- j->len += len;
- return len;
-}
-
-esp_err_t jpg_httpd_handler(httpd_req_t *req){
- camera_fb_t * fb = NULL;
- esp_err_t res = ESP_OK;
- size_t fb_len = 0;
- int64_t fr_start = esp_timer_get_time();
-
- fb = esp_camera_fb_get();
- if (!fb) {
- ESP_LOGE(TAG, "Camera capture failed");
- httpd_resp_send_500(req);
- return ESP_FAIL;
- }
- res = httpd_resp_set_type(req, "image/jpeg");
- if(res == ESP_OK){
- res = httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg");
- }
-
- if(res == ESP_OK){
- if(fb->format == PIXFORMAT_JPEG){
- fb_len = fb->len;
- res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
- } else {
- jpg_chunking_t jchunk = {req, 0};
- res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk)?ESP_OK:ESP_FAIL;
- httpd_resp_send_chunk(req, NULL, 0);
- fb_len = jchunk.len;
- }
- }
- esp_camera_fb_return(fb);
- int64_t fr_end = esp_timer_get_time();
- ESP_LOGI(TAG, "JPG: %uKB %ums", (uint32_t)(fb_len/1024), (uint32_t)((fr_end - fr_start)/1000));
- return res;
-}
-```
-
-### JPEG HTTP Stream
-
-```c
-#include "esp_camera.h"
-#include "esp_http_server.h"
-#include "esp_timer.h"
-
-#define PART_BOUNDARY "123456789000000000000987654321"
-static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
-static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
-static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
-
-esp_err_t jpg_stream_httpd_handler(httpd_req_t *req){
- camera_fb_t * fb = NULL;
- esp_err_t res = ESP_OK;
- size_t _jpg_buf_len;
- uint8_t * _jpg_buf;
- char * part_buf[64];
- static int64_t last_frame = 0;
- if(!last_frame) {
- last_frame = esp_timer_get_time();
- }
-
- res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
- if(res != ESP_OK){
- return res;
- }
-
- while(true){
- fb = esp_camera_fb_get();
- if (!fb) {
- ESP_LOGE(TAG, "Camera capture failed");
- res = ESP_FAIL;
- break;
- }
- if(fb->format != PIXFORMAT_JPEG){
- bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
- if(!jpeg_converted){
- ESP_LOGE(TAG, "JPEG compression failed");
- esp_camera_fb_return(fb);
- res = ESP_FAIL;
- }
- } else {
- _jpg_buf_len = fb->len;
- _jpg_buf = fb->buf;
- }
-
- if(res == ESP_OK){
- res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
- }
- if(res == ESP_OK){
- size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
-
- res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
- }
- if(res == ESP_OK){
- res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
- }
- if(fb->format != PIXFORMAT_JPEG){
- free(_jpg_buf);
- }
- esp_camera_fb_return(fb);
- if(res != ESP_OK){
- break;
- }
- int64_t fr_end = esp_timer_get_time();
- int64_t frame_time = fr_end - last_frame;
- last_frame = fr_end;
- frame_time /= 1000;
- ESP_LOGI(TAG, "MJPG: %uKB %ums (%.1ffps)",
- (uint32_t)(_jpg_buf_len/1024),
- (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time);
- }
-
- last_frame = 0;
- return res;
-}
-```
-
-### BMP HTTP Capture
-
-```c
-#include "esp_camera.h"
-#include "esp_http_server.h"
-#include "esp_timer.h"
-
-esp_err_t bmp_httpd_handler(httpd_req_t *req){
- camera_fb_t * fb = NULL;
- esp_err_t res = ESP_OK;
- int64_t fr_start = esp_timer_get_time();
-
- fb = esp_camera_fb_get();
- if (!fb) {
- ESP_LOGE(TAG, "Camera capture failed");
- httpd_resp_send_500(req);
- return ESP_FAIL;
- }
-
- uint8_t * buf = NULL;
- size_t buf_len = 0;
- bool converted = frame2bmp(fb, &buf, &buf_len);
- esp_camera_fb_return(fb);
- if(!converted){
- ESP_LOGE(TAG, "BMP conversion failed");
- httpd_resp_send_500(req);
- return ESP_FAIL;
- }
-
- res = httpd_resp_set_type(req, "image/x-windows-bmp")
- || httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.bmp")
- || httpd_resp_send(req, (const char *)buf, buf_len);
- free(buf);
- int64_t fr_end = esp_timer_get_time();
- ESP_LOGI(TAG, "BMP: %uKB %ums", (uint32_t)(buf_len/1024), (uint32_t)((fr_end - fr_start)/1000));
- return res;
-}
-```
-
-
-
diff --git a/lib/libesp32/esp32-camera/driver/include/cam_hal.h b/lib/libesp32/esp32-camera/driver/include/cam_hal.h
deleted file mode 100644
index c8e38ed47..000000000
--- a/lib/libesp32/esp32-camera/driver/include/cam_hal.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2010-2020 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include "esp_camera.h"
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief Uninitialize the lcd_cam module
- *
- * @param handle Provide handle pointer to release resources
- *
- * @return
- * - ESP_OK Success
- * - ESP_FAIL Uninitialize fail
- */
-esp_err_t cam_deinit(void);
-
-/**
- * @brief Initialize the lcd_cam module
- *
- * @param config Configurations - see lcd_cam_config_t struct
- *
- * @return
- * - ESP_OK Success
- * - ESP_ERR_INVALID_ARG Parameter error
- * - ESP_ERR_NO_MEM No memory to initialize lcd_cam
- * - ESP_FAIL Initialize fail
- */
-esp_err_t cam_init(const camera_config_t *config);
-
-esp_err_t cam_config(const camera_config_t *config, framesize_t frame_size, uint16_t sensor_pid);
-
-void cam_stop(void);
-
-void cam_start(void);
-
-camera_fb_t *cam_take(TickType_t timeout);
-
-void cam_give(camera_fb_t *dma_buffer);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/lib/libesp32/esp32-camera/driver/include/esp_camera.h b/lib/libesp32/esp32-camera/driver/include/esp_camera.h
deleted file mode 100644
index e9981671f..000000000
--- a/lib/libesp32/esp32-camera/driver/include/esp_camera.h
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-/*
- * Example Use
- *
- static camera_config_t camera_example_config = {
- .pin_pwdn = PIN_PWDN,
- .pin_reset = PIN_RESET,
- .pin_xclk = PIN_XCLK,
- .pin_sscb_sda = PIN_SIOD,
- .pin_sscb_scl = PIN_SIOC,
- .pin_d7 = PIN_D7,
- .pin_d6 = PIN_D6,
- .pin_d5 = PIN_D5,
- .pin_d4 = PIN_D4,
- .pin_d3 = PIN_D3,
- .pin_d2 = PIN_D2,
- .pin_d1 = PIN_D1,
- .pin_d0 = PIN_D0,
- .pin_vsync = PIN_VSYNC,
- .pin_href = PIN_HREF,
- .pin_pclk = PIN_PCLK,
-
- .xclk_freq_hz = 20000000,
- .ledc_timer = LEDC_TIMER_0,
- .ledc_channel = LEDC_CHANNEL_0,
- .pixel_format = PIXFORMAT_JPEG,
- .frame_size = FRAMESIZE_SVGA,
- .jpeg_quality = 10,
- .fb_count = 2,
- .grab_mode = CAMERA_GRAB_WHEN_EMPTY
- };
-
- esp_err_t camera_example_init(){
- return esp_camera_init(&camera_example_config);
- }
-
- esp_err_t camera_example_capture(){
- //capture a frame
- camera_fb_t * fb = esp_camera_fb_get();
- if (!fb) {
- ESP_LOGE(TAG, "Frame buffer could not be acquired");
- return ESP_FAIL;
- }
-
- //replace this with your own function
- display_image(fb->width, fb->height, fb->pixformat, fb->buf, fb->len);
-
- //return the frame buffer back to be reused
- esp_camera_fb_return(fb);
-
- return ESP_OK;
- }
-*/
-
-#pragma once
-
-#include "esp_err.h"
-#include "driver/ledc.h"
-#include "sensor.h"
-#include "sys/time.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * @brief Configuration structure for camera initialization
- */
-typedef enum {
- CAMERA_GRAB_WHEN_EMPTY, /*!< Fills buffers when they are empty. Less resources but first 'fb_count' frames might be old */
- CAMERA_GRAB_LATEST /*!< Except when 1 frame buffer is used, queue will always contain the last 'fb_count' frames */
-} camera_grab_mode_t;
-
-/**
- * @brief Camera frame buffer location
- */
-typedef enum {
- CAMERA_FB_IN_PSRAM, /*!< Frame buffer is placed in external PSRAM */
- CAMERA_FB_IN_DRAM /*!< Frame buffer is placed in internal DRAM */
-} camera_fb_location_t;
-
-/**
- * @brief Configuration structure for camera initialization
- */
-typedef struct {
- int pin_pwdn; /*!< GPIO pin for camera power down line */
- int pin_reset; /*!< GPIO pin for camera reset line */
- int pin_xclk; /*!< GPIO pin for camera XCLK line */
- int pin_sscb_sda; /*!< GPIO pin for camera SDA line */
- int pin_sscb_scl; /*!< GPIO pin for camera SCL line */
- int pin_d7; /*!< GPIO pin for camera D7 line */
- int pin_d6; /*!< GPIO pin for camera D6 line */
- int pin_d5; /*!< GPIO pin for camera D5 line */
- int pin_d4; /*!< GPIO pin for camera D4 line */
- int pin_d3; /*!< GPIO pin for camera D3 line */
- int pin_d2; /*!< GPIO pin for camera D2 line */
- int pin_d1; /*!< GPIO pin for camera D1 line */
- int pin_d0; /*!< GPIO pin for camera D0 line */
- int pin_vsync; /*!< GPIO pin for camera VSYNC line */
- int pin_href; /*!< GPIO pin for camera HREF line */
- int pin_pclk; /*!< GPIO pin for camera PCLK line */
-
- int xclk_freq_hz; /*!< Frequency of XCLK signal, in Hz. EXPERIMENTAL: Set to 16MHz on ESP32-S2 or ESP32-S3 to enable EDMA mode */
-
- ledc_timer_t ledc_timer; /*!< LEDC timer to be used for generating XCLK */
- ledc_channel_t ledc_channel; /*!< LEDC channel to be used for generating XCLK */
-
- pixformat_t pixel_format; /*!< Format of the pixel data: PIXFORMAT_ + YUV422|GRAYSCALE|RGB565|JPEG */
- framesize_t frame_size; /*!< Size of the output image: FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA */
-
- int jpeg_quality; /*!< Quality of JPEG output. 0-63 lower means higher quality */
- size_t fb_count; /*!< Number of frame buffers to be allocated. If more than one, then each frame will be acquired (double speed) */
- camera_fb_location_t fb_location; /*!< The location where the frame buffer will be allocated */
- camera_grab_mode_t grab_mode; /*!< When buffers should be filled */
-} camera_config_t;
-
-/**
- * @brief Data structure of camera frame buffer
- */
-typedef struct {
- uint8_t * buf; /*!< Pointer to the pixel data */
- size_t len; /*!< Length of the buffer in bytes */
- size_t width; /*!< Width of the buffer in pixels */
- size_t height; /*!< Height of the buffer in pixels */
- pixformat_t format; /*!< Format of the pixel data */
- struct timeval timestamp; /*!< Timestamp since boot of the first DMA buffer of the frame */
-} camera_fb_t;
-
-#define ESP_ERR_CAMERA_BASE 0x20000
-#define ESP_ERR_CAMERA_NOT_DETECTED (ESP_ERR_CAMERA_BASE + 1)
-#define ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE (ESP_ERR_CAMERA_BASE + 2)
-#define ESP_ERR_CAMERA_FAILED_TO_SET_OUT_FORMAT (ESP_ERR_CAMERA_BASE + 3)
-#define ESP_ERR_CAMERA_NOT_SUPPORTED (ESP_ERR_CAMERA_BASE + 4)
-
-/**
- * @brief Initialize the camera driver
- *
- * @note call camera_probe before calling this function
- *
- * This function detects and configures camera over I2C interface,
- * allocates framebuffer and DMA buffers,
- * initializes parallel I2S input, and sets up DMA descriptors.
- *
- * Currently this function can only be called once and there is
- * no way to de-initialize this module.
- *
- * @param config Camera configuration parameters
- *
- * @return ESP_OK on success
- */
-esp_err_t esp_camera_init(const camera_config_t* config);
-
-/**
- * @brief Deinitialize the camera driver
- *
- * @return
- * - ESP_OK on success
- * - ESP_ERR_INVALID_STATE if the driver hasn't been initialized yet
- */
-esp_err_t esp_camera_deinit();
-
-/**
- * @brief Obtain pointer to a frame buffer.
- *
- * @return pointer to the frame buffer
- */
-camera_fb_t* esp_camera_fb_get();
-
-/**
- * @brief Return the frame buffer to be reused again.
- *
- * @param fb Pointer to the frame buffer
- */
-void esp_camera_fb_return(camera_fb_t * fb);
-
-/**
- * @brief Get a pointer to the image sensor control structure
- *
- * @return pointer to the sensor
- */
-sensor_t * esp_camera_sensor_get();
-
-/**
- * @brief Save camera settings to non-volatile-storage (NVS)
- *
- * @param key A unique nvs key name for the camera settings
- */
-esp_err_t esp_camera_save_to_nvs(const char *key);
-
-/**
- * @brief Load camera settings from non-volatile-storage (NVS)
- *
- * @param key A unique nvs key name for the camera settings
- */
-esp_err_t esp_camera_load_from_nvs(const char *key);
-
-#ifdef __cplusplus
-}
-#endif
-
-#include "img_converters.h"
-
diff --git a/lib/libesp32/esp32-camera/driver/include/sensor.h b/lib/libesp32/esp32-camera/driver/include/sensor.h
deleted file mode 100644
index 1f99c1541..000000000
--- a/lib/libesp32/esp32-camera/driver/include/sensor.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * This file is part of the OpenMV project.
- * Copyright (c) 2013/2014 Ibrahim Abdelkader
- * This work is licensed under the MIT license, see the file LICENSE for details.
- *
- * Sensor abstraction layer.
- *
- */
-#ifndef __SENSOR_H__
-#define __SENSOR_H__
-#include
-#include
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
- OV9650_PID = 0x96,
- OV7725_PID = 0x77,
- OV2640_PID = 0x26,
- OV3660_PID = 0x3660,
- OV5640_PID = 0x5640,
- OV7670_PID = 0x76,
- NT99141_PID = 0x1410,
- GC2145_PID = 0x2145,
- GC032A_PID = 0x232a,
- GC0308_PID = 0x9b,
-} camera_pid_t;
-
-typedef enum {
- CAMERA_OV7725,
- CAMERA_OV2640,
- CAMERA_OV3660,
- CAMERA_OV5640,
- CAMERA_OV7670,
- CAMERA_NT99141,
- CAMERA_GC2145,
- CAMERA_GC032A,
- CAMERA_GC0308,
- CAMERA_MODEL_MAX,
- CAMERA_NONE,
-} camera_model_t;
-
-typedef enum {
- OV2640_SCCB_ADDR = 0x30,// 0x60 >> 1
- OV5640_SCCB_ADDR = 0x3C,// 0x78 >> 1
- OV3660_SCCB_ADDR = 0x3C,// 0x78 >> 1
- OV7725_SCCB_ADDR = 0x21,// 0x42 >> 1
- OV7670_SCCB_ADDR = 0x21,// 0x42 >> 1
- NT99141_SCCB_ADDR = 0x2A,// 0x54 >> 1
- GC2145_SCCB_ADDR = 0x3C,// 0x78 >> 1
- GC032A_SCCB_ADDR = 0x21,// 0x42 >> 1
- GC0308_SCCB_ADDR = 0x21,// 0x42 >> 1
-} camera_sccb_addr_t;
-
-typedef enum {
- PIXFORMAT_RGB565, // 2BPP/RGB565
- PIXFORMAT_YUV422, // 2BPP/YUV422
- PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE
- PIXFORMAT_JPEG, // JPEG/COMPRESSED
- PIXFORMAT_RGB888, // 3BPP/RGB888
- PIXFORMAT_RAW, // RAW
- PIXFORMAT_RGB444, // 3BP2P/RGB444
- PIXFORMAT_RGB555, // 3BP2P/RGB555
-} pixformat_t;
-
-typedef enum {
- FRAMESIZE_96X96, // 96x96
- FRAMESIZE_QQVGA, // 160x120
- FRAMESIZE_QCIF, // 176x144
- FRAMESIZE_HQVGA, // 240x176
- FRAMESIZE_240X240, // 240x240
- FRAMESIZE_QVGA, // 320x240
- FRAMESIZE_CIF, // 400x296
- FRAMESIZE_HVGA, // 480x320
- FRAMESIZE_VGA, // 640x480
- FRAMESIZE_SVGA, // 800x600
- FRAMESIZE_XGA, // 1024x768
- FRAMESIZE_HD, // 1280x720
- FRAMESIZE_SXGA, // 1280x1024
- FRAMESIZE_UXGA, // 1600x1200
- // 3MP Sensors
- FRAMESIZE_FHD, // 1920x1080
- FRAMESIZE_P_HD, // 720x1280
- FRAMESIZE_P_3MP, // 864x1536
- FRAMESIZE_QXGA, // 2048x1536
- // 5MP Sensors
- FRAMESIZE_QHD, // 2560x1440
- FRAMESIZE_WQXGA, // 2560x1600
- FRAMESIZE_P_FHD, // 1080x1920
- FRAMESIZE_QSXGA, // 2560x1920
- FRAMESIZE_INVALID
-} framesize_t;
-
-typedef struct {
- const camera_model_t model;
- const char *name;
- const camera_sccb_addr_t sccb_addr;
- const camera_pid_t pid;
- const framesize_t max_size;
- const bool support_jpeg;
-} camera_sensor_info_t;
-
-typedef enum {
- ASPECT_RATIO_4X3,
- ASPECT_RATIO_3X2,
- ASPECT_RATIO_16X10,
- ASPECT_RATIO_5X3,
- ASPECT_RATIO_16X9,
- ASPECT_RATIO_21X9,
- ASPECT_RATIO_5X4,
- ASPECT_RATIO_1X1,
- ASPECT_RATIO_9X16
-} aspect_ratio_t;
-
-typedef enum {
- GAINCEILING_2X,
- GAINCEILING_4X,
- GAINCEILING_8X,
- GAINCEILING_16X,
- GAINCEILING_32X,
- GAINCEILING_64X,
- GAINCEILING_128X,
-} gainceiling_t;
-
-typedef struct {
- uint16_t max_width;
- uint16_t max_height;
- uint16_t start_x;
- uint16_t start_y;
- uint16_t end_x;
- uint16_t end_y;
- uint16_t offset_x;
- uint16_t offset_y;
- uint16_t total_x;
- uint16_t total_y;
-} ratio_settings_t;
-
-typedef struct {
- const uint16_t width;
- const uint16_t height;
- const aspect_ratio_t aspect_ratio;
-} resolution_info_t;
-
-// Resolution table (in sensor.c)
-extern const resolution_info_t resolution[];
-// camera sensor table (in sensor.c)
-extern const camera_sensor_info_t camera_sensor[];
-
-typedef struct {
- uint8_t MIDH;
- uint8_t MIDL;
- uint16_t PID;
- uint8_t VER;
-} sensor_id_t;
-
-typedef struct {
- framesize_t framesize;//0 - 10
- bool scale;
- bool binning;
- uint8_t quality;//0 - 63
- int8_t brightness;//-2 - 2
- int8_t contrast;//-2 - 2
- int8_t saturation;//-2 - 2
- int8_t sharpness;//-2 - 2
- uint8_t denoise;
- uint8_t special_effect;//0 - 6
- uint8_t wb_mode;//0 - 4
- uint8_t awb;
- uint8_t awb_gain;
- uint8_t aec;
- uint8_t aec2;
- int8_t ae_level;//-2 - 2
- uint16_t aec_value;//0 - 1200
- uint8_t agc;
- uint8_t agc_gain;//0 - 30
- uint8_t gainceiling;//0 - 6
- uint8_t bpc;
- uint8_t wpc;
- uint8_t raw_gma;
- uint8_t lenc;
- uint8_t hmirror;
- uint8_t vflip;
- uint8_t dcw;
- uint8_t colorbar;
-} camera_status_t;
-
-typedef struct _sensor sensor_t;
-typedef struct _sensor {
- sensor_id_t id; // Sensor ID.
- uint8_t slv_addr; // Sensor I2C slave address.
- pixformat_t pixformat;
- camera_status_t status;
- int xclk_freq_hz;
-
- // Sensor function pointers
- int (*init_status) (sensor_t *sensor);
- int (*reset) (sensor_t *sensor);
- int (*set_pixformat) (sensor_t *sensor, pixformat_t pixformat);
- int (*set_framesize) (sensor_t *sensor, framesize_t framesize);
- int (*set_contrast) (sensor_t *sensor, int level);
- int (*set_brightness) (sensor_t *sensor, int level);
- int (*set_saturation) (sensor_t *sensor, int level);
- int (*set_sharpness) (sensor_t *sensor, int level);
- int (*set_denoise) (sensor_t *sensor, int level);
- int (*set_gainceiling) (sensor_t *sensor, gainceiling_t gainceiling);
- int (*set_quality) (sensor_t *sensor, int quality);
- int (*set_colorbar) (sensor_t *sensor, int enable);
- int (*set_whitebal) (sensor_t *sensor, int enable);
- int (*set_gain_ctrl) (sensor_t *sensor, int enable);
- int (*set_exposure_ctrl) (sensor_t *sensor, int enable);
- int (*set_hmirror) (sensor_t *sensor, int enable);
- int (*set_vflip) (sensor_t *sensor, int enable);
-
- int (*set_aec2) (sensor_t *sensor, int enable);
- int (*set_awb_gain) (sensor_t *sensor, int enable);
- int (*set_agc_gain) (sensor_t *sensor, int gain);
- int (*set_aec_value) (sensor_t *sensor, int gain);
-
- int (*set_special_effect) (sensor_t *sensor, int effect);
- int (*set_wb_mode) (sensor_t *sensor, int mode);
- int (*set_ae_level) (sensor_t *sensor, int level);
-
- int (*set_dcw) (sensor_t *sensor, int enable);
- int (*set_bpc) (sensor_t *sensor, int enable);
- int (*set_wpc) (sensor_t *sensor, int enable);
-
- int (*set_raw_gma) (sensor_t *sensor, int enable);
- int (*set_lenc) (sensor_t *sensor, int enable);
-
- int (*get_reg) (sensor_t *sensor, int reg, int mask);
- int (*set_reg) (sensor_t *sensor, int reg, int mask, int value);
- int (*set_res_raw) (sensor_t *sensor, int startX, int startY, int endX, int endY, int offsetX, int offsetY, int totalX, int totalY, int outputX, int outputY, bool scale, bool binning);
- int (*set_pll) (sensor_t *sensor, int bypass, int mul, int sys, int root, int pre, int seld5, int pclken, int pclk);
- int (*set_xclk) (sensor_t *sensor, int timer, int xclk);
-} sensor_t;
-
-camera_sensor_info_t *esp_camera_sensor_get_info(sensor_id_t *id);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __SENSOR_H__ */
diff --git a/lib/libesp32/esp32-camera/driver/include/xclk.h b/lib/libesp32/esp32-camera/driver/include/xclk.h
deleted file mode 100644
index 3d721a613..000000000
--- a/lib/libesp32/esp32-camera/driver/include/xclk.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-#include "esp_system.h"
-
-esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz);
-
-esp_err_t camera_enable_out_clock();
-
-void camera_disable_out_clock();
diff --git a/lib/libesp32/esp32-camera/library.json b/lib/libesp32/esp32-camera/library.json
deleted file mode 100644
index bb542c0bf..000000000
--- a/lib/libesp32/esp32-camera/library.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "name": "esp32-camera-header",
- "version": "1.0.0",
- "keywords": "esp32, camera, espressif, esp32-cam",
- "description": "ESP32 camera header files",
- "repository": {
- "type": "git",
- "url": "https://github.com/espressif/esp32-camera"
- },
- "frameworks": "arduino",
- "platforms": "espressif32",
- "build": {
- "flags": [
- "-Idriver/include"
- ],
- "includeDir": ".",
- "srcDir": ".",
- "srcFilter": ["-<*>", "+"]
- }
-}
diff --git a/lib/libesp32_div/NimBLE-Arduino/CHANGELOG.md b/lib/libesp32_div/NimBLE-Arduino/CHANGELOG.md
index 5d1d2d409..43fbc62cf 100644
--- a/lib/libesp32_div/NimBLE-Arduino/CHANGELOG.md
+++ b/lib/libesp32_div/NimBLE-Arduino/CHANGELOG.md
@@ -2,6 +2,22 @@
All notable changes to this project will be documented in this file.
+## [1.4.1] - 2022-10-23
+
+### Fixed
+ - Compile warning removed for esp32c3
+ - NimBLEDevice::getPower incorrect value when power level is -3db.
+ - Failed pairing when already in progress.
+
+### Changed
+ - Revert previous change that forced writing with response when subscribing in favor of allowing the application to decide.
+
+### Added
+ - Added NimBLEHIDDevice::batteryLevel.
+ - Added NimBLEDevice::setDeviceName allowing for changing the device name while the BLE stack is active.
+ - CI build tests.
+ - Missing items in CHANGELOG that were not recorded correctly
+
## [1.4.0] - 2022-07-10
### Fixed
@@ -11,6 +27,9 @@ All notable changes to this project will be documented in this file.
### Changed
- Updated NimBLE core to use the v1.4.0 branch of esp-nimble.
- AD flags are no longer set in the advertisements of non-connectable beacons, freeing up 3 bytes of advertisement room.
+- Config option CONFIG_BT_NIMBLE_DEBUG replaced with CONFIG_BT_NIMBLE_LOG_LEVEL (see src/nimconfig.h for usage)
+- Config option CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT renamed to CONFIG_NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT
+- Config option CONFIG_BT_NIMBLE_TASK_STACK_SIZE renamed to CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE
### Added
- Preliminary support for non-esp devices, NRF51 and NRF52 devices supported with [n-able arduino core](https://github.com/h2zero/n-able-Arduino)
diff --git a/lib/libesp32_div/NimBLE-Arduino/docs/Doxyfile b/lib/libesp32_div/NimBLE-Arduino/docs/Doxyfile
index 54129a191..d9c430338 100644
--- a/lib/libesp32_div/NimBLE-Arduino/docs/Doxyfile
+++ b/lib/libesp32_div/NimBLE-Arduino/docs/Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = NimBLE-Arduino
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 1.4.0
+PROJECT_NUMBER = 1.4.1
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -58,7 +58,7 @@ PROJECT_LOGO =
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
-OUTPUT_DIRECTORY = docs
+OUTPUT_DIRECTORY = doxydocs
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
@@ -836,7 +836,7 @@ WARN_NO_PARAMDOC = NO
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
# The default value is: NO.
-WARN_AS_ERROR = FAIL_ON_WARNINGS
+WARN_AS_ERROR = YES
# The WARN_FORMAT tag determines the format of the warning messages that doxygen
# can produce. The string should contain the $file, $line, and $text tags, which
diff --git a/lib/libesp32_div/NimBLE-Arduino/library.properties b/lib/libesp32_div/NimBLE-Arduino/library.properties
index 16ddf82b5..d1b32b9cf 100644
--- a/lib/libesp32_div/NimBLE-Arduino/library.properties
+++ b/lib/libesp32_div/NimBLE-Arduino/library.properties
@@ -1,5 +1,5 @@
name=NimBLE-Arduino
-version=1.4.0
+version=1.4.1
author=h2zero
maintainer=h2zero
sentence=Bluetooth low energy (BLE) library for arduino-esp32 based on NimBLE.
diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEClient.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEClient.cpp
index d923e6a0a..a83e23b4a 100644
--- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEClient.cpp
+++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEClient.cpp
@@ -336,6 +336,7 @@ bool NimBLEClient::connect(const NimBLEAddress &address, bool deleteAttributes)
* @return True on success.
*/
bool NimBLEClient::secureConnection() {
+ NIMBLE_LOGD(LOG_TAG, ">> secureConnection()");
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
ble_task_data_t taskData = {this, cur_task, 0, nullptr};
@@ -345,7 +346,7 @@ bool NimBLEClient::secureConnection() {
m_pTaskData = &taskData;
int rc = NimBLEDevice::startSecurity(m_conn_id);
- if(rc != 0){
+ if(rc != 0 && rc != BLE_HS_EALREADY){
m_lastErr = rc;
m_pTaskData = nullptr;
return false;
@@ -360,9 +361,11 @@ bool NimBLEClient::secureConnection() {
if(taskData.rc != 0){
m_lastErr = taskData.rc;
+ NIMBLE_LOGE(LOG_TAG, "secureConnection: failed rc=%d", taskData.rc);
return false;
}
+ NIMBLE_LOGD(LOG_TAG, "<< secureConnection: success");
return true;
} // secureConnection
diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.cpp
index 6ae9a7745..43ba21909 100644
--- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.cpp
+++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.cpp
@@ -971,6 +971,15 @@ void NimBLEDevice::deinit(bool clearAll) {
}
} // deinit
+/**
+ * @brief Set the BLEDevice's name
+ * @param [in] deviceName The device name of the device.
+ */
+/* STATIC */
+void NimBLEDevice::setDeviceName(const std::string &deviceName) {
+ ble_svc_gap_device_name_set(deviceName.c_str());
+} // setDeviceName
+
/**
* @brief Check if the initialization is complete.
diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.h
index b7e804b8f..8d4d849e4 100644
--- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.h
+++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.h
@@ -97,6 +97,7 @@ class NimBLEDevice {
public:
static void init(const std::string &deviceName);
static void deinit(bool clearAll = false);
+ static void setDeviceName(const std::string &deviceName);
static bool getInitialized();
static NimBLEAddress getAddress();
static std::string toString();
@@ -150,7 +151,8 @@ public:
int max_events = 0);
static bool stopAdvertising(uint8_t inst_id);
static bool stopAdvertising();
-# else
+# endif
+# if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
static NimBLEAdvertising* getAdvertising();
static bool startAdvertising();
static bool stopAdvertising();
diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.cpp
index 29150ce63..a2310eb9e 100644
--- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.cpp
+++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.cpp
@@ -203,12 +203,12 @@ void NimBLEHIDDevice::setBatteryLevel(uint8_t level) {
/*
* @brief Returns battery level characteristic
* @ return battery level characteristic
- *//*
-BLECharacteristic* BLEHIDDevice::batteryLevel() {
+ */
+NimBLECharacteristic* NimBLEHIDDevice::batteryLevel() {
return m_batteryLevelCharacteristic;
}
-
+/*
BLECharacteristic* BLEHIDDevice::reportMap() {
return m_reportMapCharacteristic;
diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.h
index ef2ed7395..0e8b2828a 100644
--- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.h
+++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEHIDDevice.h
@@ -55,7 +55,7 @@ public:
void pnp(uint8_t sig, uint16_t vid, uint16_t pid, uint16_t version);
//NimBLECharacteristic* hidInfo();
void hidInfo(uint8_t country, uint8_t flags);
- //NimBLECharacteristic* batteryLevel();
+ NimBLECharacteristic* batteryLevel();
void setBatteryLevel(uint8_t level);
diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.cpp
index 68982f89e..6cca615db 100644
--- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.cpp
+++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.cpp
@@ -616,7 +616,6 @@ bool NimBLERemoteCharacteristic::setNotify(uint16_t val, notify_callback notifyC
NIMBLE_LOGD(LOG_TAG, "<< setNotify()");
- response = true; // Always write with response as per Bluetooth core specification.
return desc->writeValue((uint8_t *)&val, 2, response);
} // setNotify
diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.h
index 7042b19bf..353d83221 100644
--- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.h
+++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLERemoteCharacteristic.h
@@ -73,8 +73,8 @@ public:
bool subscribe(bool notifications = true,
notify_callback notifyCallback = nullptr,
- bool response = true);
- bool unsubscribe(bool response = true);
+ bool response = false);
+ bool unsubscribe(bool response = false);
bool registerForNotify(notify_callback notifyCallback,
bool notifications = true,
bool response = true)
diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEServer.h b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEServer.h
index 19fecfdde..54bbb9ab1 100644
--- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEServer.h
+++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEServer.h
@@ -58,7 +58,8 @@ public:
int duration = 0,
int max_events = 0);
bool stopAdvertising(uint8_t inst_id);
-#else
+#endif
+#if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_)
NimBLEAdvertising* getAdvertising();
bool startAdvertising();
#endif
diff --git a/lib/libesp32_lvgl/lv_binding_berry/generate/be_lv_c_mapping.h b/lib/libesp32_lvgl/lv_binding_berry/generate/be_lv_c_mapping.h
index 7c99171d3..425bb7da1 100644
--- a/lib/libesp32_lvgl/lv_binding_berry/generate/be_lv_c_mapping.h
+++ b/lib/libesp32_lvgl/lv_binding_berry/generate/be_lv_c_mapping.h
@@ -899,7 +899,7 @@ const be_ntv_func_def_t lv_label_func[] = {
{ "get_letter_pos", { (const void*) &lv_label_get_letter_pos, "", "(lv.lv_obj)i(lv.lv_point)" } },
{ "get_long_mode", { (const void*) &lv_label_get_long_mode, "i", "(lv.lv_obj)" } },
{ "get_recolor", { (const void*) &lv_label_get_recolor, "b", "(lv.lv_obj)" } },
- { "get_text", { (const void*) &lv_label_get_text, "c", "(lv.lv_obj)" } },
+ { "get_text", { (const void*) &lv_label_get_text, "s", "(lv.lv_obj)" } },
{ "get_text_selection_end", { (const void*) &lv_label_get_text_selection_end, "i", "(lv.lv_obj)" } },
{ "get_text_selection_start", { (const void*) &lv_label_get_text_selection_start, "i", "(lv.lv_obj)" } },
{ "ins_text", { (const void*) &lv_label_ins_text, "", "(lv.lv_obj)is" } },
diff --git a/lib/libesp32_lvgl/lv_binding_berry/tools/convert.py b/lib/libesp32_lvgl/lv_binding_berry/tools/convert.py
index a8f4ba4ad..e3df18958 100644
--- a/lib/libesp32_lvgl/lv_binding_berry/tools/convert.py
+++ b/lib/libesp32_lvgl/lv_binding_berry/tools/convert.py
@@ -38,6 +38,7 @@ return_types = {
"char *": "c",
"uint8_t *": "c",
"const char *": "s",
+ "retchar *": "s",
"constchar *": "s", # special construct
"lv_obj_user_data_t": "i",
@@ -245,6 +246,7 @@ with open(lv_widgets_file) as f:
l_raw = re.sub('static ', '', l_raw)
l_raw = re.sub('inline ', '', l_raw)
l_raw = re.sub('const\s+char\s*\*', 'constchar *', l_raw)
+ l_raw = re.sub('^char\s*\*', 'retchar *', l_raw) # special case for returning a char*
l_raw = re.sub('const ', '', l_raw)
l_raw = re.sub('struct ', '', l_raw)
if (len(l_raw) == 0): continue
diff --git a/lib/libesp32_lvgl/lvgl/library.json b/lib/libesp32_lvgl/lvgl/library.json
index 58e13fca2..fe8ef4c15 100644
--- a/lib/libesp32_lvgl/lvgl/library.json
+++ b/lib/libesp32_lvgl/lvgl/library.json
@@ -1,6 +1,6 @@
{
"name": "lvgl",
- "version": "8.3.2",
+ "version": "8.3.3",
"keywords": "graphics, gui, embedded, tft, lvgl",
"description": "Graphics library to create embedded GUI with easy-to-use graphical elements, beautiful visual effects and low memory footprint. It offers anti-aliasing, opacity, and animations using only one frame buffer.",
"repository": {
diff --git a/lib/libesp32_lvgl/lvgl/library.properties b/lib/libesp32_lvgl/lvgl/library.properties
index 2d4880773..816446a93 100644
--- a/lib/libesp32_lvgl/lvgl/library.properties
+++ b/lib/libesp32_lvgl/lvgl/library.properties
@@ -1,5 +1,5 @@
name=lvgl
-version=8.3.2
+version=8.3.3
author=kisvegabor
maintainer=kisvegabor,embeddedt,pete-pjb
sentence=Full-featured Graphics Library for Embedded Systems
diff --git a/lib/libesp32_lvgl/lvgl/lv_conf_template.h b/lib/libesp32_lvgl/lvgl/lv_conf_template.h
index 618bf7f92..3d087f0f3 100644
--- a/lib/libesp32_lvgl/lvgl/lv_conf_template.h
+++ b/lib/libesp32_lvgl/lvgl/lv_conf_template.h
@@ -1,6 +1,6 @@
/**
* @file lv_conf.h
- * Configuration file for v8.3.2
+ * Configuration file for v8.3.3
*/
/*
diff --git a/lib/libesp32_lvgl/lvgl/lvgl.h b/lib/libesp32_lvgl/lvgl/lvgl.h
index 4cd9a8326..c0be411b2 100644
--- a/lib/libesp32_lvgl/lvgl/lvgl.h
+++ b/lib/libesp32_lvgl/lvgl/lvgl.h
@@ -15,7 +15,7 @@ extern "C" {
***************************/
#define LVGL_VERSION_MAJOR 8
#define LVGL_VERSION_MINOR 3
-#define LVGL_VERSION_PATCH 1
+#define LVGL_VERSION_PATCH 3
#define LVGL_VERSION_INFO ""
/*********************
diff --git a/pio-tools/gzip-firmware.py b/pio-tools/gzip-firmware.py
index 080448a30..90e7f80d6 100644
--- a/pio-tools/gzip-firmware.py
+++ b/pio-tools/gzip-firmware.py
@@ -1,11 +1,9 @@
Import("env")
import os
import shutil
-import gzip
import pathlib
-
import tasmotapiolib
-
+import gzip
def map_gzip(source, target, env):
# create string with location and file names based on variant
@@ -33,7 +31,7 @@ if not tasmotapiolib.is_env_set(tasmotapiolib.DISABLE_MAP_GZ, env):
# gzip only for ESP8266
if env["PIOPLATFORM"] != "espressif32":
-
+ from zopfli.gzip import compress
def bin_gzip(source, target, env):
# create string with location and file names based on variant
bin_file = tasmotapiolib.get_final_bin_path(env)
@@ -45,8 +43,9 @@ if env["PIOPLATFORM"] != "espressif32":
# write gzip firmware file
with open(bin_file, "rb") as fp:
- with gzip.open(gzip_file, "wb", compresslevel=9) as f:
- shutil.copyfileobj(fp, f)
+ with open(gzip_file, "wb") as f:
+ zopfli_gz = compress(fp.read())
+ f.write(zopfli_gz)
ORG_FIRMWARE_SIZE = bin_file.stat().st_size
GZ_FIRMWARE_SIZE = gzip_file.stat().st_size
diff --git a/pio-tools/post_esp32.py b/pio-tools/post_esp32.py
index 2ca0afc4f..370934845 100644
--- a/pio-tools/post_esp32.py
+++ b/pio-tools/post_esp32.py
@@ -33,15 +33,22 @@ import subprocess
sys.path.append(join(platform.get_package_dir("tool-esptoolpy")))
import esptool
+github_actions = os.getenv('GITHUB_ACTIONS')
extra_flags = ''.join([element.replace("-D", " ") for element in env.BoardConfig().get("build.extra_flags", "")])
build_flags = ''.join([element.replace("-D", " ") for element in env.GetProjectOption("build_flags")])
if "CORE32SOLO1" in extra_flags or "FRAMEWORK_ARDUINO_SOLO1" in build_flags:
FRAMEWORK_DIR = platform.get_package_dir("framework-arduino-solo1")
+ if github_actions and os.path.exists("./firmware/firmware"):
+ shutil.copytree("./firmware/firmware", "/home/runner/.platformio/packages/framework-arduino-solo1/variants/tasmota")
elif "CORE32ITEAD" in extra_flags or "FRAMEWORK_ARDUINO_ITEAD" in build_flags:
FRAMEWORK_DIR = platform.get_package_dir("framework-arduino-ITEAD")
+ if github_actions and os.path.exists("./firmware/firmware"):
+ shutil.copytree("./firmware/firmware", "/home/runner/.platformio/packages/framework-arduino-ITEAD/variants/tasmota")
else:
FRAMEWORK_DIR = platform.get_package_dir("framework-arduinoespressif32")
+ if github_actions and os.path.exists("./firmware/firmware"):
+ shutil.copytree("./firmware/firmware", "/home/runner/.platformio/packages/framework-arduinoespressif32/variants/tasmota")
variants_dir = join(FRAMEWORK_DIR, "variants", "tasmota")
@@ -132,6 +139,11 @@ def esp32_create_combined_bin(source, target, env):
firmware_name = env.subst("$BUILD_DIR/${PROGNAME}.bin")
chip = env.get("BOARD_MCU")
tasmota_platform = esp32_create_chip_string(chip)
+
+ if "-DUSE_USB_CDC_CONSOLE" in env.BoardConfig().get("build.extra_flags") and "cdc" not in tasmota_platform:
+ tasmota_platform += "cdc"
+ print("WARNING: board definition uses CDC configuration, but environment name does not -> changing tasmota safeboot binary to:", tasmota_platform + "-safeboot.bin")
+
if not os.path.exists(variants_dir):
os.makedirs(variants_dir)
if("safeboot" in firmware_name):
diff --git a/platformio.ini b/platformio.ini
index 57b6c9404..3e08f6cb2 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -99,6 +99,7 @@ build_flags = ${esp_defaults.build_flags}
; NONOSDK22x_190703 = 2.2.2-dev(38a443e)
-DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK22x_190703
-DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
+ ; -DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_HIGHER_BANDWIDTH ; enables IPv6
; VTABLES in Flash
-DVTABLES_IN_FLASH
; remove the 4-bytes alignment for PSTR()
@@ -110,7 +111,7 @@ build_flags = ${esp_defaults.build_flags}
[core]
; *** Esp8266 Tasmota modified Arduino core based on core 2.7.4. Added Backport for PWM selection
-platform = https://github.com/tasmota/platform-espressif8266/releases/download/v2.7.4.9/platform-espressif8266-2.7.4.9.zip
+platform = https://github.com/tasmota/platform-espressif8266/releases/download/v2.7.4/platform-espressif8266-2.7.4.zip
platform_packages =
build_unflags = ${esp_defaults.build_unflags}
build_flags = ${esp82xx_defaults.build_flags}
diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini
index ad7937d1c..02a8f92e6 100644
--- a/platformio_override_sample.ini
+++ b/platformio_override_sample.ini
@@ -98,19 +98,18 @@ lib_extra_dirs = ${library.lib_extra_dirs}
; *** Uncomment next lines ";" to enable development Tasmota Arduino version ESP32
;platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.5.1/platform-espressif32-2.0.5.1.zip
;platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1008/framework-arduinoespressif32-IDF_Arduino-d772747b2.zip
-; = framework-arduino-ITEAD @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1014/framework-arduinoespressif32-solo1-IDF_Arduino-d772747b2.zip
-; framework-arduino-solo1 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1013/framework-arduinoespressif32-ITEAD-IDF_Arduino-d772747b2.zip
+; framework-arduino-solo1 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1014/framework-arduinoespressif32-solo1-IDF_Arduino-d772747b2.zip
+; framework-arduino-ITEAD @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/1013/framework-arduinoespressif32-ITEAD-IDF_Arduino-d772747b2.zip
;build_unflags = ${esp32_defaults.build_unflags}
;build_flags = ${esp32_defaults.build_flags}
-
-; Build variant ESP32 4M Flash, Tasmota 1856k Code/OTA, 1344k LITTLEFS (default)
-;board = esp32_4M
-; Build variant ESP32 8M Flash, Tasmota 2944k Code/OTA, 2112k LITTLEFS
-;board = esp32_8M
-; Build variant ESP32 16M Flash, Tasmota 2944k Code/OTA, 10M LITTLEFS
-;board = esp32_16M
+;board = esp32
;board_build.f_cpu = 240000000L
;board_build.f_flash = 40000000L
+;board_build.flash_mode = qio
+;board_build.flash_size = 8MB
+;board_upload.maximum_size = 8388608
+;board_upload.arduino.flash_extra_images =
+;board_build.partitions = partitions/esp32_partition_app2944k_fs2M.csv
monitor_speed = 115200
; *** Serial port used for erasing/flashing the ESP32
;upload_port = ${common.upload_port}
diff --git a/platformio_tasmota32.ini b/platformio_tasmota32.ini
index 90db20366..38c0209d4 100644
--- a/platformio_tasmota32.ini
+++ b/platformio_tasmota32.ini
@@ -40,7 +40,7 @@ extra_scripts = pre:pio-tools/add_c_flags.py
${esp_defaults.extra_scripts}
[core32]
-platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.5.1/platform-espressif32-2.0.5.1.zip
+platform = https://github.com/tasmota/platform-espressif32/releases/download/v.2.0.5/platform-espressif32-v.2.0.5.zip
platform_packages =
build_unflags = ${esp32_defaults.build_unflags}
build_flags = ${esp32_defaults.build_flags}
diff --git a/platformio_tasmota_cenv_sample.ini b/platformio_tasmota_cenv_sample.ini
index bb10ec1b1..e086b1094 100644
--- a/platformio_tasmota_cenv_sample.ini
+++ b/platformio_tasmota_cenv_sample.ini
@@ -14,12 +14,29 @@ build_flags = ${env:tasmota32_base.build_flags}
[env:tasmota32s3-file]
extends = env:tasmota32_base
-board = esp32s3
+board = esp32s3-qio_qspi
+board_build.f_cpu = 240000000L
+board_build.f_flash = 80000000L
build_flags = ${env:tasmota32_base.build_flags} -D FIRMWARE_TASMOTA32
-; example for custom file upload in Tasmota Filesystem
-; custom_files_upload = ${env:tasmota32_base.custom_files_upload}
-; tasmota/berry/modules/Partition_wizard.tapp
-; https://github.com/tasmota/autoconf/raw/main/esp32s3/DevKitC-1.autoconf
+; !!! Real flash size needed, avoid autoresize since it is formating FS !!!
+board_upload.flash_size = 8MB
+board_upload.maximum_size = 8388608
+; Without autoresize a partition scheme is needed which does fit to flash size
+board_build.partitions = partitions/esp32_partition_app2944k_fs2M.csv
+; Dont use safeboot, not used in this partition scheme -> an empty entry needed to overwrite the default setting
+board_upload.arduino.flash_extra_images =
+; Example for custom file upload in Tasmota Filesystem
+custom_files_upload = ${env:tasmota32_base.custom_files_upload}
+ tasmota/berry/modules/Partition_wizard.tapp
+ https://github.com/tasmota/autoconf/raw/main/esp32s3/DevKitC-1.autoconf
+
+[env:tasmota32s3-qio_opi-all]
+extends = env:tasmota32_base
+board = esp32s3-qio_opi
+board_build.f_cpu = 240000000L
+board_build.f_flash = 80000000L
+build_flags = ${env:tasmota32_base.build_flags} -DUSE_WEBCAM -DUSE_BERRY_ULP -DFIRMWARE_LVGL -DUSE_LVGL_OPENHASP
+
[env:tasmota32c3-bluetooth]
extends = env:tasmota32c3
@@ -50,7 +67,6 @@ lib_ignore = ESP8266Audio
TTGO TWatch Library
Micro-RTSP
epdiy
- esp32-camera
[env:tasmota32c3-mi32-homebridge]
extends = env:tasmota32c3
@@ -64,7 +80,6 @@ lib_ignore = ESP8266Audio
TTGO TWatch Library
Micro-RTSP
epdiy
- esp32-camera
[env:tasmota32s3-mi32-homebridge]
extends = env:tasmota32s3
@@ -78,7 +93,6 @@ lib_ignore = ESP8266Audio
TTGO TWatch Library
Micro-RTSP
epdiy
- esp32-camera
; *** Debug version used for PlatformIO Home Project Inspection
[env:tasmota-debug]
@@ -108,7 +122,7 @@ monitor_filters = esp32_exception_decoder
[env:tasmota32-ocd]
build_type = debug
extends = env:tasmota32_base
-board = esp32_4M
+board = esp32
debug_tool = esp-prog
upload_protocol = esp-prog
debug_init_break = tbreak setup
@@ -119,7 +133,7 @@ monitor_filters = esp32_exception_decoder
[env:tasmota32solo1-ocd]
build_type = debug
extends = env:tasmota32solo1
-board = esp32_solo1_4M
+board = esp32_solo1
debug_tool = esp-prog
upload_protocol = esp-prog
debug_init_break = tbreak setup
@@ -143,7 +157,7 @@ monitor_filters = esp32_exception_decoder
[env:tasmota32s3cdc-ocd]
build_type = debug
extends = env:tasmota32s3
-board = esp32s3cdc
+board = esp32s3cdc-qio_opi
debug_tool = esp-builtin
upload_protocol = esp-builtin
debug_init_break = tbreak setup
@@ -154,7 +168,7 @@ monitor_filters = esp32_exception_decoder
[env:tasmota32c3cdc-ocd]
build_type = debug
extends = env:tasmota32c3
-board = esp32c3cdc
+board = esp32c3cdc-qio_opi
debug_tool = esp-builtin
upload_protocol = esp-builtin
debug_init_break = tbreak setup
diff --git a/platformio_tasmota_env32.ini b/platformio_tasmota_env32.ini
index 154d5d42f..8acfebe40 100644
--- a/platformio_tasmota_env32.ini
+++ b/platformio_tasmota_env32.ini
@@ -4,7 +4,7 @@ platform = ${core32.platform}
platform_packages = ${core32.platform_packages}
board_build.filesystem = ${common.board_build.filesystem}
custom_unpack_dir = ${common.custom_unpack_dir}
-board = esp32_4M
+board = esp32
monitor_speed = 115200
upload_port = ${common.upload_port}
upload_resetmethod = ${common.upload_resetmethod}
@@ -54,29 +54,24 @@ lib_ignore =
extends = env:tasmota32_base
build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_TASMOTA32
-[env:tasmota32_8M]
-extends = env:tasmota32_base
-board = esp32_8M
-build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_TASMOTA32
-
-[env:tasmota32_16M]
-extends = env:tasmota32_base
-board = esp32_16M
-build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_TASMOTA32
-
[env:tasmota32-webcam]
extends = env:tasmota32_base
-board = esp32-cam
-build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_WEBCAM
+board = esp32-fix
+board_build.f_cpu = 240000000L
+build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_WEBCAM -DCAMERA_MODEL_AI_THINKER
lib_extra_dirs = lib/lib_ssl, lib/libesp32
[env:tasmota32-odroidgo]
extends = env:tasmota32-lvgl
-board = esp32-odroid
+board_build.f_cpu = 240000000L
+build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_TASMOTA32 -DARDUINO_ODROID_ESP32
+board = esp32-fix
[env:tasmota32-core2]
extends = env:tasmota32-lvgl
-board = esp32-m5core2
+board_build.flash_mode = qio
+board_build.f_cpu = 240000000L
+board_build.f_flash = 80000000L
build_flags = ${env:tasmota32-lvgl.build_flags} -DUSE_I2S_SAY_TIME -DUSE_I2S_WEBRADIO -DUSE_SENDMAIL
lib_extra_dirs = lib/libesp32, lib/libesp32_lvgl, lib/lib_basic, lib/lib_i2c, lib/lib_rf, lib/lib_div, lib/lib_ssl, lib/lib_display, lib/lib_audio
@@ -93,7 +88,7 @@ lib_extra_dirs = lib/libesp32, lib/lib_basic, lib/lib_display, lib/lib_
[env:tasmota32-lvgl]
extends = env:tasmota32_base
build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_LVGL
-board_build.f_cpu = 160000000L
+board_build.f_cpu = 240000000L
lib_extra_dirs = lib/libesp32, lib/libesp32_lvgl, lib/lib_basic, lib/lib_i2c, lib/lib_rf, lib/lib_div, lib/lib_ssl, lib/lib_display
[env:tasmota32-ir]
@@ -103,11 +98,11 @@ lib_extra_dirs = lib/libesp32, lib/lib_basic, lib/lib_ssl
[env:tasmota32solo1]
extends = env:tasmota32_base
-board = esp32_solo1_4M
+board = esp32_solo1
[env:tasmota32solo1-safeboot]
extends = env:tasmota32_base
-board = esp32_solo1_4M
+board = esp32_solo1
build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_SAFEBOOT
lib_extra_dirs = lib/lib_ssl, lib/libesp32
lib_ignore =
@@ -117,7 +112,7 @@ lib_ignore =
[env:tasmota32-zbbrdgpro]
extends = env:tasmota32_base
-board = esp32_4M_FS
+board_build.partitions = partitions/esp32_partition_app1856k_fs1344k.csv
build_flags = ${env:tasmota32_base.build_flags}
-DFIRMWARE_ZBBRDGPRO
-DFRAMEWORK_ARDUINO_ITEAD
@@ -201,7 +196,7 @@ board = esp32s2cdc
[env:tasmota32s3-safeboot]
extends = env:tasmota32_base
-board = esp32s3
+board = esp32s3-qio_qspi
build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_SAFEBOOT
lib_extra_dirs = lib/lib_ssl, lib/libesp32
lib_ignore =
@@ -211,7 +206,7 @@ lib_ignore =
[env:tasmota32s3]
extends = env:tasmota32_base
-board = esp32s3
+board = esp32s3-qio_qspi
build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_TASMOTA32
lib_ignore =
TTGO TWatch Library
@@ -220,11 +215,11 @@ lib_ignore =
[env:tasmota32s3cdc-safeboot]
extends = env:tasmota32s3-safeboot
-board = esp32s3cdc
+board = esp32s3cdc-qio_qspi
[env:tasmota32s3cdc]
extends = env:tasmota32s3
-board = esp32s3cdc
+board = esp32s3cdc-qio_qspi
[env:tasmota32-AD]
extends = env:tasmota32_base
diff --git a/tasmota/berry/ArtNet.tapp b/tasmota/berry/ArtNet.tapp
new file mode 100644
index 000000000..d03a2bba3
Binary files /dev/null and b/tasmota/berry/ArtNet.tapp differ
diff --git a/tasmota/berry/artnet/artnet.be b/tasmota/berry/artnet/artnet.be
new file mode 100644
index 000000000..b4f36f98b
--- /dev/null
+++ b/tasmota/berry/artnet/artnet.be
@@ -0,0 +1,149 @@
+# Art-Net driver
+
+class ArtNet
+ var matrix # the led matrix
+ var port # port number for listening for incoming packets
+ var udp_server # instance of `udp` class
+ var universe_start # base universe number
+ var universe_end # last universe number allowed (excluded)
+ # static var artnet_sig = bytes().fromstring("Art-Net\x00") # 8 bytes # signature of packet
+ static var artnet_sig_0 = 0x4172742D # "Art-"
+ static var artnet_sig_4 = 0x4E657400 # "Net\x00"
+
+ var packet # try reusing the same packer bytes() object for performance
+
+ # local copy of led matrix attributes for faster access
+ var alternate # field from matrix, alternate lines (reversed). Contains 0 if not alternate, or the number of bytes per pixel
+
+ def init(matrix, universe_start, port, ip_addr)
+ self.matrix = matrix
+ self.alternate = matrix.alternate ? matrix.pixel_size() : 0
+ # self.v = self.matrix.v
+ if universe_start == nil universe_start = 0 end
+ self.universe_start = universe_start
+ self.universe_end = universe_start + matrix.h
+
+ if port == nil port = 6454 end
+ self.port = int(port)
+ if ip_addr == nil ip_addr = "" end
+
+ self.packet = bytes() # instanciate a single bytes() buffer that will be used for all received packets
+
+ self.udp_server = udp()
+ self.udp_server.begin(ip_addr, self.port)
+
+ # register as fast_loop
+ tasmota.add_fast_loop(/-> self.fast_loop())
+ # set sleep to 5 for a smooth animation
+ tasmota.global.sleep = 5
+ end
+
+ def stop()
+ import introspect
+ # if usd_server has a stop() method, call it
+ if introspect.get(self.udp_server, "stop")
+ self.udp_server.stop()
+ end
+ self.matrix.clear()
+ end
+
+ def fast_loop()
+ var universe_start = self.universe_start
+ var universe_end = self.universe_end
+ var artnet_sig_0 = self.artnet_sig_0
+ var artnet_sig_4 = self.artnet_sig_4
+ var dirty = false
+ var packet = self.udp_server.read(self.packet)
+ while (packet != nil)
+ if size(packet) >= 18 &&
+ packet.get(0, -4) == artnet_sig_0 && packet.get(4, -4) == artnet_sig_4
+ var opcode = packet.get(8, 2) # should be 0x5000
+ var protocol = packet.get(10, -2) # big endian, should be 14
+ var universe = packet.get(14, 2)
+
+ if opcode == 0x5000 && protocol == 14 && universe >= universe_start && universe < universe_end
+ # tasmota.log("DMX: received Art-Net packet :" + packet.tohex())
+ # var seq = packet.get(12, 1)
+ # var phy = packet.get(13, 1)
+ var data_len = packet.get(16, -2)
+ # data starts at offset 18
+ if size(packet) >= 18 + data_len # check size
+ if self.alternate > 0 && (universe - self.universe_start) % 2
+ packet.reverse(18, self.alternate, -1)
+ end
+ self.matrix.set_bytes(universe, packet, 18, data_len)
+ dirty = true
+ end
+ # import string
+ # tasmota.log(string.format("DMX: opcode=0x%04X protocol=%i seq=%i phy=%i universe=%i data_len=%i data=%s",
+ # opcode, protocol, seq, phy, universe, data_len, packet[18..-1].tohex()))
+ end
+ end
+ packet = self.udp_server.read(self.packet)
+ if packet == nil
+ tasmota.delay_microseconds(20) # wait 20 us just in case
+ packet = self.udp_server.read(self.packet)
+ end
+ end
+
+ if dirty
+ self.matrix.dirty()
+ self.matrix.show()
+ end
+ end
+
+ static def read_persist()
+ import persist
+ var conf = dyn()
+
+ conf.gpio = persist.find("artnet_gpio", 0) # gpio number from template
+ conf.rows = persist.find("artnet_rows", 5) # number of rows (min: 1)
+ conf.cols = persist.find("artnet_cols", 5) # number of columns (min: 1)
+ conf.offs = persist.find("artnet_offs", 0) # offset in the led strip where the matrix starts (min: 0)
+ conf.alt = persist.find("artnet_alt", false) # are the rows in alternate directions
+
+ conf.univ = persist.find("artnet_univ", 0) # start universe
+
+ # conf.addr = persist.find("artnet_addr", "uni") # listening mode, either 'uni' or 'multi' for multicast
+ conf.port = persist.find("artnet_port", 6454) # UDP port number
+
+ conf.auto = persist.find("artnet_auto", true) # autorun at startup
+ return conf
+ end
+
+ static def run_from_conf()
+ import persist
+
+ var conf = ArtNet.read_persist()
+ var r = conf.rows
+ var c = conf.cols
+
+ var strip = Leds(r * c, gpio.pin(gpio.WS2812, conf.gpio))
+ var matrix = strip.create_matrix(r, c, conf.offs)
+ if conf.alt matrix.set_alternate(true)
+ end
+ var dmx = ArtNet(matrix, conf.univ, conf.port)
+
+ global._artnet = dmx
+ end
+
+ static def stop_global()
+ var dmx = global._artnet
+ if type(dmx) == 'instance'
+ dmx.stop()
+ global._artnet = nil # dereference
+ tasmota.gc() # force gc
+ end
+ end
+end
+
+return ArtNet
+
+#-
+# Example for M5Stack ATOM Matrix (5x5 matrix without alternate)
+import artnet
+# var artnet = ArtNet
+var strip = Leds(25, gpio.pin(gpio.WS2812, 0))
+var m = strip.create_matrix(5, 5, 0)
+var dmx = artnet(m)
+-#
\ No newline at end of file
diff --git a/tasmota/berry/artnet/artnet_dyn.be b/tasmota/berry/artnet/artnet_dyn.be
new file mode 100644
index 000000000..bfac24463
--- /dev/null
+++ b/tasmota/berry/artnet/artnet_dyn.be
@@ -0,0 +1,28 @@
+#################################################################################
+# dyn class
+#
+# Allows to use a map with members
+# see https://github.com/berry-lang/berry/wiki/Chapter-8
+#################################################################################
+class dyn
+ var _attr
+ def init()
+ self._attr = {}
+ end
+ def setmember(name, value)
+ self._attr[name] = value
+ end
+ def member(name)
+ if self._attr.contains(name)
+ return self._attr[name]
+ else
+ import undefined
+ return undefined
+ end
+ end
+ def tostring()
+ return self._attr.tostring()
+ end
+end
+
+return dyn
diff --git a/tasmota/berry/artnet/artnet_ui.be b/tasmota/berry/artnet/artnet_ui.be
new file mode 100644
index 000000000..05869a6c4
--- /dev/null
+++ b/tasmota/berry/artnet/artnet_ui.be
@@ -0,0 +1,288 @@
+#######################################################################
+# DMX ArtNet UI for ESP32(C3/S2/S3)
+#
+#######################################################################
+
+var artnet_ui = module('artnet_ui')
+
+#################################################################################
+# ArtNet_UI
+#
+# WebUI
+#################################################################################
+class ArtNet_UI
+
+ def init()
+ import persist
+
+ if persist.find("artnet_autorun") == true
+ # autorun
+ end
+ end
+
+ # ####################################################################################################
+ # Init web handlers
+ # ####################################################################################################
+ # Displays a "DMX ArtNet" button on the configuration page
+ def web_add_config_button()
+ import webserver
+ webserver.content_send("
")
+ end
+
+ # ####################################################################################################
+ # Get WS2812 gpios
+ #
+ # Returns an array of valid WS2812 gpios as defined in the template, or empty array
+ # ####################################################################################################
+ def get_ws2812_gpios()
+ import gpio
+ var ret = []
+ for p:0..31
+ if gpio.pin_used(gpio.WS2812, p)
+ ret.push(p)
+ end
+ end
+ return ret
+ end
+
+ static def read_persist()
+ import persist
+ var conf = dyn()
+
+ conf.gpio = persist.find("artnet_gpio", 0) # gpio number from template
+ conf.rows = persist.find("artnet_rows", 5) # number of rows (min: 1)
+ conf.cols = persist.find("artnet_cols", 5) # number of columns (min: 1)
+ conf.offs = persist.find("artnet_offs", 0) # offset in the led strip where the matrix starts (min: 0)
+ conf.alt = persist.find("artnet_alt", false) # are the rows in alternate directions
+
+ conf.univ = persist.find("artnet_univ", 0) # start universe
+
+ # conf.addr = persist.find("artnet_addr", "uni") # listening mode, either 'uni' or 'multi' for multicast
+ conf.port = persist.find("artnet_port", 6454) # UDP port number
+
+ conf.auto = persist.find("artnet_auto", true) # autorun at startup
+ return conf
+ end
+
+ def save_persist(conf)
+ import persist
+ persist.artnet_gpio = conf.gpio
+ persist.artnet_rows = conf.rows
+ persist.artnet_cols = conf.cols
+ persist.artnet_offs = conf.offs
+ persist.artnet_alt = conf.alt
+
+ persist.artnet_univ = conf.univ
+
+ # persist.artnet_addr = conf.addr
+ persist.artnet_port = conf.port
+
+ persist.artnet_auto = conf.auto
+
+ persist.save()
+ end
+
+ #######################################################################
+ # Display the complete page on `/artnet_ui`
+ #######################################################################
+ def page_artnet_ui()
+ import webserver
+ import string
+ if !webserver.check_privileged_access() return nil end
+
+ # read configuration
+ var conf = self.read_persist()
+
+ webserver.content_start("ArtNet") #- title of the web page -#
+ webserver.content_send_style() #- send standard Tasmota styles -#
+
+ # webserver.content_send("Warning: actions below can brick your device.
")
+ # webserver.content_send(" (This feature requires an internet connection)
")
+
+ webserver.content_send("")
+ webserver.content_button(webserver.BUTTON_CONFIGURATION)
+ webserver.content_stop()
+ end
+
+ #######################################################################
+ # Web Controller, called by POST to `/artnet_ui`
+ #######################################################################
+ def page_artnet_ctl()
+ import webserver
+ if !webserver.check_privileged_access() return nil end
+
+ import string
+ import persist
+ import introspect
+
+ try
+ if webserver.has_arg("artnetapply")
+
+ # read argumments, sanity check and put in conf object
+ var conf = dyn()
+
+ # read gpio
+ var ws2812_list = self.get_ws2812_gpios()
+ var gp_ws2812 = int(webserver.arg("ws2812"))
+ if ws2812_list.find(gp_ws2812) != nil
+ conf.gpio = gp_ws2812
+ else
+ conf.gpio = -1
+ end
+
+ # read rows and cols
+ var rows = int(webserver.arg("rows"))
+ if rows < 1 || rows > 999 rows = 1 end
+ conf.rows = rows
+ var cols = int(webserver.arg("cols"))
+ if cols < 1 || cols > 999 cols = 1 end
+ conf.cols = cols
+ # alternate
+ conf.alt = webserver.arg("alt") == 'on'
+
+ # offset
+ var offs = int(webserver.arg("offs"))
+ if offs < 0 || offs > 999 offs = 0 end
+ conf.offs = offs
+
+ # universe
+ var univ = int(webserver.arg("univ"))
+ if univ < 0 || univ > 999 univ = 0 end
+ conf.univ = univ
+
+ # universe
+ var port = int(webserver.arg("port"))
+ if port < 1 || port > 65535 port = 6454 end
+ conf.port = port
+
+ # autorun
+ conf.auto = webserver.arg("auto") == 'on'
+
+ self.save_persist(conf)
+
+ artnet.stop_global()
+ artnet.run_from_conf()
+
+ # tasmota.log("BRY: conf=" + str(conf), 2);
+ webserver.redirect("/cn?")
+ else
+ raise "value_error", "Unknown command"
+ end
+ except .. as e, m
+ print(string.format("BRY: Exception> '%s' - %s", e, m))
+ #- display error page -#
+ webserver.content_start("Parameter error") #- title of the web page -#
+ webserver.content_send_style() #- send standard Tasmota styles -#
+
+ webserver.content_send(string.format("Exception:
'%s'
%s
", e, m))
+
+ webserver.content_button(webserver.BUTTON_CONFIGURATION) #- button back to management page -#
+ webserver.content_stop() #- end of web page -#
+ end
+ end
+
+ #- ---------------------------------------------------------------------- -#
+ # respond to web_add_handler() event to register web listeners
+ #- ---------------------------------------------------------------------- -#
+ #- this is called at Tasmota start-up, as soon as Wifi/Eth is up and web server running -#
+ def web_add_handler()
+ import webserver
+ #- we need to register a closure, not just a function, that captures the current instance -#
+ webserver.on("/artnet_ui", / -> self.page_artnet_ui(), webserver.HTTP_GET)
+ webserver.on("/artnet_ui", / -> self.page_artnet_ctl(), webserver.HTTP_POST)
+ end
+end
+artnet_ui.ArtNet_UI = ArtNet_UI
+
+
+#- create and register driver in Tasmota -#
+if tasmota
+ var artnet_ui_instance = artnet_ui.ArtNet_UI()
+ tasmota.add_driver(artnet_ui_instance)
+ ## can be removed if put in 'autoexec.bat'
+ artnet_ui_instance.web_add_handler()
+end
+
+return artnet_ui
+
+#- Example
+
+import partition
+
+# read
+p = partition.Partition()
+print(p)
+
+-#
diff --git a/tasmota/berry/artnet/autoexec.be b/tasmota/berry/artnet/autoexec.be
new file mode 100644
index 000000000..7f5e9d45c
--- /dev/null
+++ b/tasmota/berry/artnet/autoexec.be
@@ -0,0 +1,15 @@
+# rm ArtNet.tapp; zip ArtNet.tapp -j -0 artnet/*
+#
+# check if `dyn` class is embedded, or load it
+if !global.contains("dyn")
+ import artnet_dyn
+ global.dyn = artnet_dyn
+end
+
+import artnet
+import artnet_ui
+
+import persist
+if persist.find("artnet_auto")
+ tasmota.add_rule("Wifi#Connected", def () tasmota.remove_rule("Wifi#Connected", "artnet_run") artnet.run_from_conf() end, "artnet_run")
+end
diff --git a/tasmota/berry/drivers/lv_touch_3_buttons.be b/tasmota/berry/drivers/lv_touch_3_buttons.be
index c33ed0aff..ef0711ea5 100644
--- a/tasmota/berry/drivers/lv_touch_3_buttons.be
+++ b/tasmota/berry/drivers/lv_touch_3_buttons.be
@@ -19,7 +19,7 @@ class lv_touch_3_buttons
static ACTIVE_LOW = true
# Arguments:
- # Physical GPIOs, generally through `gpio.pin(gpio.INPUT, 0), gpio.pin(gpio.INPUT, 1), gpio.pin(gpio.INPUT, 2)`
+ # Physical GPIOs, generally through `gpio.pin(gpio.GPIO_INPUT, 0), gpio.pin(gpio.GPIO_INPUT, 1), gpio.pin(gpio.GPIO_INPUT, 2)`
#
# Pre-condition:
# LVGL must be already started
@@ -85,9 +85,9 @@ class lv_touch_3_buttons
end
end
-return lv_touch_3_buttons(gpio.pin(gpio.INPUT, 0), gpio.pin(gpio.INPUT, 1), gpio.pin(gpio.INPUT, 2), true)
+return lv_touch_3_buttons(gpio.pin(gpio.GPIO_INPUT, 0), gpio.pin(gpio.GPIO_INPUT, 1), gpio.pin(gpio.GPIO_INPUT, 2), true)
#-
-lv_btn3 = lv_touch_3_buttons(gpio.pin(gpio.INPUT, 0), gpio.pin(gpio.INPUT, 1), gpio.pin(gpio.INPUT, 2), lv_touch_3_buttons.ACTIVE_LOW)
+lv_btn3 = lv_touch_3_buttons(gpio.pin(gpio.GPIO_INPUT, 0), gpio.pin(gpio.GPIO_INPUT, 1), gpio.pin(gpio.GPIO_INPUT, 2), lv_touch_3_buttons.ACTIVE_LOW)
tasmota.add_driver(lv_btn3)
-#
diff --git a/tasmota/berry/drivers/tm1637.be b/tasmota/berry/drivers/tm1637.be
new file mode 100644
index 000000000..9e7b572f0
--- /dev/null
+++ b/tasmota/berry/drivers/tm1637.be
@@ -0,0 +1,190 @@
+#-
+Simplified Tasmota TM1637 driver written in Berry
+Might be helpful in the case of using multiple displays
+Supports only the 4 digit basic display
+
+DIO_PIN and CLK_PIN are your esp32 pin numbers
+How to use
+
+> load('tm1637')
+> tm = Tm1637(DIO_PIN, CLK_PIN)
+> tm.set_on(4)
+> tm.print('0123')
+> tm.print(456)
+
+Add custom commands to the native Tasmota console:
+> tm_add_custom_commands(DIO_PIN, CLK_PIN)
+
+And then:
+TmBrightness 2
+TmPrint 0123
+TmPrint -5.67
+
+Note: adding these commands to autoexec.be should be performed via creating an additional .be file with the content:
+ tm_add_custom_commands(DIO_PIN, CLK_PIN)
+
+and then loading it in autoexec.be via load('tm1637') and load('script_name')
+The direct addition may not work
+-#
+
+class Tm1637
+ static var CMD_CTRL = 0x80
+ static var CMD_DISP_ON = 0x08
+ static var CMD_DATA = 0x40
+ static var CMD_ADDR = 0xC0
+
+ static var SYMB_DOT = 0x80
+
+ static var DIGIT_MAP = {
+ '0': 0x3F,
+ '1': 0x06,
+ '2': 0x5B,
+ '3': 0x4F,
+ '4': 0x66,
+ '5': 0x6D,
+ '6': 0x7D,
+ '7': 0x07,
+ '8': 0x7F,
+ '9': 0x6F,
+ '-': 0x40,
+ ' ': 0x00
+ }
+
+ var PIN_DIO
+ var PIN_CLK
+
+ def init(dio, clk)
+ self.PIN_DIO = dio
+ self.PIN_CLK = clk
+ gpio.pin_mode(self.PIN_DIO, gpio.OUTPUT)
+ gpio.pin_mode(self.PIN_CLK, gpio.OUTPUT)
+ gpio.digital_write(self.PIN_DIO, 1)
+ gpio.digital_write(self.PIN_CLK, 1)
+ end
+
+ def start()
+ gpio.digital_write(self.PIN_DIO, 1)
+ gpio.digital_write(self.PIN_CLK, 1)
+ gpio.digital_write(self.PIN_DIO, 0)
+ end
+
+ def stop()
+ gpio.digital_write(self.PIN_CLK, 0)
+ gpio.digital_write(self.PIN_DIO, 0)
+ gpio.digital_write(self.PIN_CLK, 1)
+ gpio.digital_write(self.PIN_DIO, 1)
+ end
+
+ def ack()
+ gpio.digital_write(self.PIN_CLK, 0)
+ gpio.pin_mode(self.PIN_DIO, gpio.INPUT_PULLUP)
+ var ack_state = gpio.digital_read(self.PIN_DIO) == 0
+ gpio.digital_write(self.PIN_CLK, 1)
+ gpio.digital_write(self.PIN_CLK, 0)
+ gpio.pin_mode(self.PIN_DIO, gpio.OUTPUT)
+ return ack_state
+ end
+
+ def write_bit(bitval)
+ gpio.digital_write(self.PIN_CLK, 0)
+ gpio.digital_write(self.PIN_DIO, bitval)
+ gpio.digital_write(self.PIN_CLK, 1)
+ end
+
+ def write_byte(byteval)
+ for pos: 0..7
+ self.write_bit((byteval >> pos) & 0x01)
+ end
+ end
+
+ def send_command(command)
+ self.start()
+ self.write_byte(command)
+ var ack_state = self.ack()
+ self.stop()
+ return ack_state
+ end
+
+ def send_data(data)
+ var ack_state = true
+ self.start()
+ for i : 0..size(data)-1
+ self.write_byte(data[i])
+ ack_state = self.ack() && ack_state
+ end
+ self.stop()
+ return ack_state
+ end
+
+ # 0-8 range, 0 to 'OFF'
+ def set_on(brightness)
+ if brightness == nil || brightness > 8
+ brightness = 8
+ elif brightness < 0
+ brightness = 0
+ end
+ var cmd = self.CMD_CTRL
+ if brightness
+ cmd |= self.CMD_DISP_ON
+ brightness -= 1
+ end
+ return self.send_command(cmd | brightness)
+ end
+
+ def print(num)
+ import string
+
+ num = str(num)
+ var max_str_len = 4
+
+ do
+ var dot_pos = string.find(num, '.')
+ if dot_pos >= 0 && dot_pos < 5
+ max_str_len = 5
+ end
+ end
+ if size(num) > max_str_len
+ num = string.split(num, max_str_len)[0]
+ end
+ num = string.format('%4s', num)
+ var payload = bytes(-5)
+ payload[0] = self.CMD_ADDR
+ var int_offset = 1
+ for i : 0..size(num)-1
+ if num[i] == '.'
+ payload[i] |= self.SYMB_DOT
+ int_offset = 0
+ else
+ payload[i + int_offset] = self.DIGIT_MAP[num[i]]
+ end
+ end
+ var ack_state = self.send_command(self.CMD_DATA) && self.send_data(payload)
+ if !ack_state
+ log('TM1637 - no ACK, please check connections')
+ end
+ return ack_state
+ end
+
+ def clear()
+ self.print(' ')
+ end
+
+ # Won't be called on the system restart
+ def deinit()
+ self.set_on(0)
+ end
+end
+
+def tm_add_custom_commands(dio, clk)
+ var tm = Tm1637(dio, clk)
+ tm.clear()
+ tm.set_on(4)
+ tasmota.add_cmd('tmprint', def(cmd, idx, payload)
+ tm.print(payload) ? tasmota.resp_cmnd_done() : tasmota.resp_cmnd_failed()
+ end)
+ # 0-8 range, 0 to 'OFF'
+ tasmota.add_cmd('tmbrightness', def(cmd, idx, payload)
+ tm.set_on(int(payload)) ? tasmota.resp_cmnd_done() : tasmota.resp_cmnd_failed()
+ end)
+ log("Tasmota custom commands registered: TmPrint, TmBrightness")
+end
diff --git a/tasmota/berry/include/be_gpio_defines.h b/tasmota/berry/include/be_gpio_defines.h
index 7e97defe5..eee29d979 100644
--- a/tasmota/berry/include/be_gpio_defines.h
+++ b/tasmota/berry/include/be_gpio_defines.h
@@ -19,7 +19,9 @@ const be_const_member_t lv_gpio_constants[] = {
{ "ADC_RANGE", (int32_t) GPIO_ADC_RANGE },
{ "ADC_TEMP", (int32_t) GPIO_ADC_TEMP },
{ "ADE7880_IRQ", (int32_t) GPIO_ADE7880_IRQ },
+ { "ADE7953_CS", (int32_t) GPIO_ADE7953_CS },
{ "ADE7953_IRQ", (int32_t) GPIO_ADE7953_IRQ },
+ { "ADE7953_RST", (int32_t) GPIO_ADE7953_RST },
{ "ARIRFRCV", (int32_t) GPIO_ARIRFRCV },
{ "ARIRFSEL", (int32_t) GPIO_ARIRFSEL },
{ "AS3935", (int32_t) GPIO_AS3935 },
@@ -35,6 +37,8 @@ const be_const_member_t lv_gpio_constants[] = {
{ "BL6523_TX", (int32_t) GPIO_BL6523_TX },
{ "BOILER_OT_RX", (int32_t) GPIO_BOILER_OT_RX },
{ "BOILER_OT_TX", (int32_t) GPIO_BOILER_OT_TX },
+ { "BP5758D_CLK", (int32_t) GPIO_BP5758D_CLK },
+ { "BP5758D_DAT", (int32_t) GPIO_BP5758D_DAT },
{ "BS814_CLK", (int32_t) GPIO_BS814_CLK },
{ "BS814_DAT", (int32_t) GPIO_BS814_DAT },
{ "BUZZER", (int32_t) GPIO_BUZZER },
@@ -75,6 +79,7 @@ const be_const_member_t lv_gpio_constants[] = {
{ "FALLING", FALLING },
{ "FLOWRATEMETER_SIGNAL", (int32_t) GPIO_FLOWRATEMETER_IN },
{ "FTC532", (int32_t) GPIO_FTC532 },
+ { "GPIO_INPUT", (int32_t) GPIO_INPUT },
{ "GPS_RX", (int32_t) GPIO_GPS_RX },
{ "GPS_TX", (int32_t) GPIO_GPS_TX },
{ "HALLEFFECT", (int32_t) GPIO_HALLEFFECT },
@@ -99,6 +104,7 @@ const be_const_member_t lv_gpio_constants[] = {
{ "I2S_IN_CLK", (int32_t) GPIO_I2S_BCLK_IN },
{ "I2S_IN_DATA", (int32_t) GPIO_I2S_DIN },
{ "I2S_IN_SLCT", (int32_t) GPIO_I2S_WS_IN },
+ { "I2S_MCLK", (int32_t) GPIO_I2S_MCLK },
{ "I2S_OUT_CLK", (int32_t) GPIO_I2S_BCLK },
{ "I2S_OUT_DATA", (int32_t) GPIO_I2S_DOUT },
{ "I2S_OUT_SLCT", (int32_t) GPIO_I2S_WS },
@@ -109,7 +115,7 @@ const be_const_member_t lv_gpio_constants[] = {
{ "ILI9341_CS", (int32_t) GPIO_ILI9341_CS },
{ "ILI9341_DC", (int32_t) GPIO_ILI9341_DC },
{ "ILI9488_CS", (int32_t) GPIO_ILI9488_CS },
- { "INPUT", (int32_t) GPIO_INPUT },
+ { "INPUT", INPUT },
{ "INPUT_PULLDOWN", INPUT_PULLDOWN },
{ "INPUT_PULLUP", INPUT_PULLUP },
{ "INTERRUPT", (int32_t) GPIO_INTERRUPT },
@@ -137,6 +143,8 @@ const be_const_member_t lv_gpio_constants[] = {
{ "MAX7219CS", (int32_t) GPIO_MAX7219CS },
{ "MAX7219DIN", (int32_t) GPIO_MAX7219DIN },
{ "MAX_RMT", MAX_RMT },
+ { "MBR_RX", (int32_t) GPIO_MBR_RX },
+ { "MBR_TX", (int32_t) GPIO_MBR_TX },
{ "MCP2515_CS", (int32_t) GPIO_MCP2515_CS },
{ "MCP39F5_RST", (int32_t) GPIO_MCP39F5_RST },
{ "MCP39F5_RX", (int32_t) GPIO_MCP39F5_RX },
@@ -148,6 +156,7 @@ const be_const_member_t lv_gpio_constants[] = {
{ "MIEL_HVAC_RX", (int32_t) GPIO_MIEL_HVAC_RX },
{ "MIEL_HVAC_TX", (int32_t) GPIO_MIEL_HVAC_TX },
{ "MP3_DFR562", (int32_t) GPIO_MP3_DFR562 },
+ { "MP3_DFR562_BUSY", (int32_t) GPIO_MP3_DFR562_BUSY },
{ "MS01", (int32_t) GPIO_MS01 },
{ "NEOPOOL_RX", (int32_t) GPIO_NEOPOOL_RX },
{ "NEOPOOL_TX", (int32_t) GPIO_NEOPOOL_TX },
@@ -155,6 +164,8 @@ const be_const_member_t lv_gpio_constants[] = {
{ "NRF24_CS", (int32_t) GPIO_NRF24_CS },
{ "NRF24_DC", (int32_t) GPIO_NRF24_DC },
{ "NRG_CF1", (int32_t) GPIO_NRG_CF1 },
+ { "NRG_MBS_RX", (int32_t) GPIO_NRG_MBS_RX },
+ { "NRG_MBS_TX", (int32_t) GPIO_NRG_MBS_TX },
{ "NRG_SEL", (int32_t) GPIO_NRG_SEL },
{ "NRG_SEL_INV", (int32_t) GPIO_NRG_SEL_INV },
{ "OLED_RESET", (int32_t) GPIO_OLED_RESET },
@@ -186,6 +197,8 @@ const be_const_member_t lv_gpio_constants[] = {
{ "RC522_RST", (int32_t) GPIO_RC522_RST },
{ "RDM6300_RX", (int32_t) GPIO_RDM6300_RX },
{ "REL1", (int32_t) GPIO_REL1 },
+ { "REL1_BI", (int32_t) GPIO_REL1_BI },
+ { "REL1_BI_INV", (int32_t) GPIO_REL1_BI_INV },
{ "REL1_INV", (int32_t) GPIO_REL1_INV },
{ "RESET", (int32_t) GPIO_RESET },
{ "RFRECV", (int32_t) GPIO_RFRECV },
@@ -231,6 +244,8 @@ const be_const_member_t lv_gpio_constants[] = {
{ "SM16716_SEL", (int32_t) GPIO_SM16716_SEL },
{ "SM2135_CLK", (int32_t) GPIO_SM2135_CLK },
{ "SM2135_DAT", (int32_t) GPIO_SM2135_DAT },
+ { "SM2335_CLK", (int32_t) GPIO_SM2335_CLK },
+ { "SM2335_DAT", (int32_t) GPIO_SM2335_DAT },
{ "SOLAXX1_RTS", (int32_t) GPIO_SOLAXX1_RTS },
{ "SOLAXX1_RX", (int32_t) GPIO_SOLAXX1_RX },
{ "SOLAXX1_TX", (int32_t) GPIO_SOLAXX1_TX },
@@ -266,6 +281,10 @@ const be_const_member_t lv_gpio_constants[] = {
{ "TELEINFO_RX", (int32_t) GPIO_TELEINFO_RX },
{ "TFMINIPLUS_RX", (int32_t) GPIO_TFMINIPLUS_RX },
{ "TFMINIPLUS_TX", (int32_t) GPIO_TFMINIPLUS_TX },
+ { "TM1621_CS", (int32_t) GPIO_TM1621_CS },
+ { "TM1621_DAT", (int32_t) GPIO_TM1621_DAT },
+ { "TM1621_RD", (int32_t) GPIO_TM1621_RD },
+ { "TM1621_WR", (int32_t) GPIO_TM1621_WR },
{ "TM1637CLK", (int32_t) GPIO_TM1637CLK },
{ "TM1637DIO", (int32_t) GPIO_TM1637DIO },
{ "TM1638CLK", (int32_t) GPIO_TM1638CLK },
@@ -300,8 +319,6 @@ const be_const_member_t lv_gpio_constants[] = {
{ "ZIGBEE_RST", (int32_t) GPIO_ZIGBEE_RST },
{ "ZIGBEE_RX", (int32_t) GPIO_ZIGBEE_RX },
{ "ZIGBEE_TX", (int32_t) GPIO_ZIGBEE_TX },
- { "MBR_RX", (int32_t) GPIO_MBR_RX },
- { "MBR_TX", (int32_t) GPIO_MBR_TX },
};
diff --git a/tasmota/berry/internal/gpio.be b/tasmota/berry/internal/gpio.be
deleted file mode 100644
index 5d9437d62..000000000
--- a/tasmota/berry/internal/gpio.be
+++ /dev/null
@@ -1,257 +0,0 @@
-gpio = module('gpio')
-#- HIGH/LOW -#
-gpio.LOW = 0
-gpio.HIGH = 1
-#- GPIO states -#
-gpio.INPUT = 1
-gpio.OUTPUT = 2
-gpio.PULLUP = 4
-gpio.INPUT_PULLUP = 5
-gpio.PULLDOWN = 8
-gpio.OPEN_DRAIN = 16
-gpio.OUTPUT_OPEN_DRAIN = 18
-#- Interrupt trigger -#
-gpio.RISING = 1
-gpio.FALLING = 2
-gpio.CHANGE = 4
-#- Tasmota GPIOs -#
-gpio.NONE = 0
-gpio.KEY1 = 1
-gpio.KEY1_NP = 2
-gpio.KEY1_INV = 3
-gpio.KEY1_INV_NP = 4
-gpio.SWT1 = 5
-gpio.SWT1_NP = 6
-gpio.REL1 = 7
-gpio.REL1_INV = 8
-gpio.LED1 = 9
-gpio.LED1_INV = 10
-gpio.CNTR1 = 11
-gpio.CNTR1_NP = 12
-gpio.PWM1 = 13
-gpio.PWM1_INV = 14
-gpio.BUZZER = 15
-gpio.BUZZER_INV = 16
-gpio.LEDLNK = 17
-gpio.LEDLNK_INV = 18
-gpio.I2C_SCL = 19
-gpio.I2C_SDA = 20
-gpio.SPI_MISO = 21
-gpio.SPI_MOSI = 22
-gpio.SPI_CLK = 23
-gpio.SPI_CS = 24
-gpio.SPI_DC = 25
-gpio.SSPI_MISO = 26
-gpio.SSPI_MOSI = 27
-gpio.SSPI_SCLK = 28
-gpio.SSPI_CS = 29
-gpio.SSPI_DC = 30
-gpio.BACKLIGHT = 31
-gpio.OLED_RESET = 32
-gpio.IRSEND = 33
-gpio.IRRECV = 34
-gpio.RFSEND = 35
-gpio.RFRECV = 36
-gpio.DHT11 = 37
-gpio.DHT22 = 38
-gpio.SI7021 = 39
-gpio.DHT11_OUT = 40
-gpio.DSB = 41
-gpio.DSB_OUT = 42
-gpio.WS2812 = 43
-gpio.MHZ_TXD = 44
-gpio.MHZ_RXD = 45
-gpio.PZEM0XX_TX = 46
-gpio.PZEM004_RX = 47
-gpio.PZEM016_RX = 48
-gpio.PZEM017_RX = 49
-gpio.SAIR_TX = 50
-gpio.SAIR_RX = 51
-gpio.PMS5003_TX = 52
-gpio.PMS5003_RX = 53
-gpio.SDS0X1_TX = 54
-gpio.SDS0X1_RX = 55
-gpio.SBR_TX = 56
-gpio.SBR_RX = 57
-gpio.SR04_TRIG = 58
-gpio.SR04_ECHO = 59
-gpio.SDM120_TX = 60
-gpio.SDM120_RX = 61
-gpio.SDM630_TX = 62
-gpio.SDM630_RX = 63
-gpio.TM1638CLK = 64
-gpio.TM1638DIO = 65
-gpio.TM1638STB = 66
-gpio.MP3_DFR562 = 67
-gpio.HX711_SCK = 68
-gpio.HX711_DAT = 69
-gpio.TX2X_TXD_BLACK = 70
-gpio.TUYA_TX = 71
-gpio.TUYA_RX = 72
-gpio.MGC3130_XFER = 73
-gpio.MGC3130_RESET = 74
-gpio.RF_SENSOR = 75
-gpio.AZ_TXD = 76
-gpio.AZ_RXD = 77
-gpio.MAX31855CS = 78
-gpio.MAX31855CLK = 79
-gpio.MAX31855DO = 80
-gpio.NRG_SEL = 81
-gpio.NRG_SEL_INV = 82
-gpio.NRG_CF1 = 83
-gpio.HLW_CF = 84
-gpio.HJL_CF = 85
-gpio.MCP39F5_TX = 86
-gpio.MCP39F5_RX = 87
-gpio.MCP39F5_RST = 88
-gpio.PN532_TXD = 89
-gpio.PN532_RXD = 90
-gpio.SM16716_CLK = 91
-gpio.SM16716_DAT = 92
-gpio.SM16716_SEL = 93
-gpio.DI = 94
-gpio.DCKI = 95
-gpio.CSE7766_TX = 96
-gpio.CSE7766_RX = 97
-gpio.ARIRFRCV = 98
-gpio.ARIRFSEL = 99
-gpio.TXD = 100
-gpio.RXD = 101
-gpio.ROT1A = 102
-gpio.ROT1B = 103
-gpio.ADC_JOY = 104
-gpio.SSPI_MAX31865_CS1 = 105
-gpio.HRE_CLOCK = 106
-gpio.HRE_DATA = 107
-gpio.ADE7953_IRQ = 108
-gpio.SOLAXX1_TX = 109
-gpio.SOLAXX1_RX = 110
-gpio.ZIGBEE_TX = 111
-gpio.ZIGBEE_RX = 112
-gpio.RDM6300_RX = 113
-gpio.IBEACON_TX = 114
-gpio.IBEACON_RX = 115
-gpio.A4988_DIR = 116
-gpio.A4988_STP = 117
-gpio.A4988_ENA = 118
-gpio.A4988_MS1 = 119
-gpio.OUTPUT_HI = 120
-gpio.OUTPUT_LO = 121
-gpio.DDS2382_TX = 122
-gpio.DDS2382_RX = 123
-gpio.DDSU666_TX = 124
-gpio.DDSU666_RX = 125
-gpio.SM2135_CLK = 126
-gpio.SM2135_DAT = 127
-gpio.DEEPSLEEP = 128
-gpio.EXS_ENABLE = 129
-gpio.TASMOTACLIENT_TXD = 130
-gpio.TASMOTACLIENT_RXD = 131
-gpio.TASMOTACLIENT_RST = 132
-gpio.TASMOTACLIENT_RST_INV = 133
-gpio.HPMA_RX = 134
-gpio.HPMA_TX = 135
-gpio.GPS_RX = 136
-gpio.GPS_TX = 137
-gpio.HM10_RX = 138
-gpio.HM10_TX = 139
-gpio.LE01MR_RX = 140
-gpio.LE01MR_TX = 141
-gpio.CC1101_GDO0 = 142
-gpio.CC1101_GDO2 = 143
-gpio.HRXL_RX = 144
-gpio.ELECTRIQ_MOODL_TX = 145
-gpio.AS3935 = 146
-gpio.ADC_INPUT = 147
-gpio.ADC_TEMP = 148
-gpio.ADC_LIGHT = 149
-gpio.ADC_BUTTON = 150
-gpio.ADC_BUTTON_INV = 151
-gpio.ADC_RANGE = 152
-gpio.ADC_CT_POWER = 153
-gpio.WEBCAM_PWDN = 154
-gpio.WEBCAM_RESET = 155
-gpio.WEBCAM_XCLK = 156
-gpio.WEBCAM_SIOD = 157
-gpio.WEBCAM_SIOC = 158
-gpio.WEBCAM_DATA = 159
-gpio.WEBCAM_VSYNC = 160
-gpio.WEBCAM_HREF = 161
-gpio.WEBCAM_PCLK = 162
-gpio.WEBCAM_PSCLK = 163
-gpio.WEBCAM_HSD = 164
-gpio.WEBCAM_PSRCS = 165
-gpio.BOILER_OT_RX = 166
-gpio.BOILER_OT_TX = 167
-gpio.WINDMETER_SPEED = 168
-gpio.KEY1_TC = 169
-gpio.BL0940_RX = 170
-gpio.TCP_TX = 171
-gpio.TCP_RX = 172
-gpio.ETH_PHY_POWER = 173
-gpio.ETH_PHY_MDC = 174
-gpio.ETH_PHY_MDIO = 175
-gpio.TELEINFO_RX = 176
-gpio.TELEINFO_ENABLE = 177
-gpio.LMT01 = 178
-gpio.IEM3000_TX = 179
-gpio.IEM3000_RX = 180
-gpio.ZIGBEE_RST = 181
-gpio.DYP_RX = 182
-gpio.MIEL_HVAC_TX = 183
-gpio.MIEL_HVAC_RX = 184
-gpio.WE517_TX = 185
-gpio.WE517_RX = 186
-gpio.AS608_TX = 187
-gpio.AS608_RX = 188
-gpio.SHELLY_DIMMER_BOOT0 = 189
-gpio.SHELLY_DIMMER_RST_INV = 190
-gpio.RC522_RST = 191
-gpio.P9813_CLK = 192
-gpio.P9813_DAT = 193
-gpio.OPTION_A = 194
-gpio.FTC532 = 195
-gpio.RC522_CS = 196
-gpio.NRF24_CS = 197
-gpio.NRF24_DC = 198
-gpio.ILI9341_CS = 199
-gpio.ILI9341_DC = 200
-gpio.ILI9488_CS = 201
-gpio.EPAPER29_CS = 202
-gpio.EPAPER42_CS = 203
-gpio.SSD1351_CS = 204
-gpio.RA8876_CS = 205
-gpio.ST7789_CS = 206
-gpio.ST7789_DC = 207
-gpio.SSD1331_CS = 208
-gpio.SSD1331_DC = 209
-gpio.SDCARD_CS = 210
-gpio.ROT1A_NP = 211
-gpio.ROT1B_NP = 212
-gpio.ADC_PH = 213
-gpio.BS814_CLK = 214
-gpio.BS814_DAT = 215
-gpio.WIEGAND_D0 = 216
-gpio.WIEGAND_D1 = 217
-gpio.NEOPOOL_TX = 218
-gpio.NEOPOOL_RX = 219
-gpio.SDM72_TX = 220
-gpio.SDM72_RX = 221
-gpio.TM1637CLK = 222
-gpio.TM1637DIO = 223
-gpio.PROJECTOR_CTRL_TX = 224
-gpio.PROJECTOR_CTRL_RX = 225
-gpio.SSD1351_DC = 226
-gpio.XPT2046_CS = 227
-gpio.CSE7761_TX = 228
-gpio.CSE7761_RX = 229
-gpio.VL53LXX_XSHUT1 = 230
-gpio.MAX7219CLK = 231
-gpio.MAX7219DIN = 232
-gpio.MAX7219CS = 233
-gpio.TFMINIPLUS_TX = 234
-gpio.TFMINIPLUS_RX = 235
-gpio.ZEROCROSS = 236
-gpio.HALLEFFECT = 237
-gpio.SENSOR_END = 238
-gpio.ADC_MQ = 239
diff --git a/tasmota/berry/modules/DisplayCalibrate.tapp b/tasmota/berry/modules/DisplayCalibrate.tapp
index 7a8b80e72..0c75a7042 100644
Binary files a/tasmota/berry/modules/DisplayCalibrate.tapp and b/tasmota/berry/modules/DisplayCalibrate.tapp differ
diff --git a/tasmota/berry/modules/ts_calibrate/ts_calibrate.be b/tasmota/berry/modules/ts_calibrate/ts_calibrate.be
index 8435c2199..04cddf69c 100644
--- a/tasmota/berry/modules/ts_calibrate/ts_calibrate.be
+++ b/tasmota/berry/modules/ts_calibrate/ts_calibrate.be
@@ -1,4 +1,7 @@
# TouchScreen calibration
+#
+# rm DisplayCalibrate.tapp; zip -j -0 DisplayCalibrate.tapp ts_calibrate/*
+#
var ts_calibrate = module("ts_calibrate")
ts_calibrate.init = def (m)
@@ -104,8 +107,8 @@ ts_calibrate.init = def (m)
end
# draw cross
- def draw_cross(x, y, size)
- var sz2 = size / 2
+ def draw_cross(x, y, sz)
+ var sz2 = sz / 2
self.p1.x = x - sz2
self.p1.y = y
self.p2.x = x + sz2
diff --git a/tasmota/displaydesc/MF_ILI9488_p16_display.ini b/tasmota/displaydesc/MF_ILI9488_p16_display.ini
new file mode 100644
index 000000000..e73eae9f0
--- /dev/null
+++ b/tasmota/displaydesc/MF_ILI9488_p16_display.ini
@@ -0,0 +1,30 @@
+:H,ILI9488,480,320,16,PAR,16,-1,37,36,35,48,45,47,21,14,13,12,11,10,9,3,8,16,15,7,6,5,4,20
+:S,2,1,1,0,40,20
+:I
+E0,0F,00,03,09,08,16,0A,3F,78,4C,09,0A,08,16,1A,0F
+E1,0F,00,16,19,03,0F,05,32,45,46,04,0E,0D,35,37,0F
+C0,2,17,15
+C1,1,41
+C5,3,00,12,80
+36,1,48
+3A,1,55
+B0,1,80
+B1,1,A0
+B4,1,02
+B6,2,02,02
+E9,1,00
+F7,4,A9,51,2C,82
+11,80
+29,0
+:o,28
+:O,29
+:A,2A,2B,2C,16
+:R,36
+:0,28,00,00,85
+:1,88,00,00,02
+:2,E8,00,00,84
+:3,48,00,00,00
+:i,20,21
+:TI1,38,*,*
+:B,20,0
+#
diff --git a/tasmota/include/i18n.h b/tasmota/include/i18n.h
index 84c0a78a6..4294c3297 100644
--- a/tasmota/include/i18n.h
+++ b/tasmota/include/i18n.h
@@ -110,6 +110,8 @@
#define D_JSON_IMPORT_REACTIVE "ImportReactive"
#define D_JSON_INFRARED "Infrared"
#define D_JSON_INVALID_FILE_TYPE "Invalid filetype or buffer"
+#define D_JSON_IP6_GLOBAL "IP6Global"
+#define D_JSON_IP6_LOCAL "IP6Local"
#define D_JSON_UNKNOWN "Unknown"
#define D_JSON_LIGHT "Light"
#define D_JSON_LINK_COUNT "LinkCount"
@@ -502,6 +504,9 @@
#define D_CMND_PALETTE "Palette"
#define D_CMND_PIXELS "Pixels"
#define D_CMND_STEPPIXELS "StepPixels"
+#define D_CMND_ARTNET "ArtNet"
+#define D_CMND_ARTNET_CONFIG "ArtNetConfig"
+#define D_SO_ARTNET_AUTORUN "ArtNetAutorun"
#define D_CMND_RGBWWTABLE "RGBWWTable"
#define D_CMND_ROTATION "Rotation"
#define D_CMND_SCHEME "Scheme"
@@ -572,6 +577,7 @@
// Commands xdrv_08_serial_bridge.ino
#define D_CMND_SSERIALSEND "SSerialSend"
#define D_CMND_SBAUDRATE "SBaudrate"
+#define D_CMND_SSERIALBUFFER "SSerialBuffer"
#define D_CMND_SSERIALCONFIG "SSerialConfig"
#define D_JSON_SSERIALRECEIVED "SSerialReceived"
@@ -685,6 +691,7 @@
#define D_CMND_ZIGBEE_LOAD "Load"
#define D_CMND_ZIGBEE_LOADDUMP "LoadDump"
#define D_CMND_ZIGBEE_UNLOAD "Unload"
+#define D_CMND_ZIGBEE_ATTRDUMP "AttrDump"
// Commands xdrv_25_A4988_Stepper.ino
#define D_CMND_MOTOR "MOTOR"
@@ -753,6 +760,10 @@
// Commands xdrv_60_shift595.ino - 74x595 family shift register driver
#define D_CMND_SHIFT595_DEVICE_COUNT "Shift595DeviceCount"
+// Commands xdrv_89_dali.ino
+#define D_CMND_DALI_POWER "power"
+#define D_CMND_DALI_DIMMER "dim"
+
// Commands xsns_02_analog.ino
#define D_CMND_ADCPARAM "AdcParam"
@@ -797,6 +808,7 @@
#define D_LOG_UPLOAD "UPL: " // Upload
#define D_LOG_UPNP "UPP: " // UPnP
#define D_LOG_WIFI "WIF: " // Wifi
+#define D_LOG_ETH "ETH: " // Ethernet
#define D_LOG_ZIGBEE "ZIG: " // Zigbee
#define D_LOG_TCP "TCP: " // TCP bridge
#define D_LOG_BERRY "BRY: " // Berry scripting language
@@ -882,6 +894,7 @@ const float kSpeedConversionFactor[] = {1, // none
const char HTTP_SNS_F_TEMP[] PROGMEM = "{s}%s " D_TEMPERATURE "{m}%*_f " D_UNIT_DEGREE "%c{e}";
const char HTTP_SNS_F_VOLTAGE[] PROGMEM = "{s}%s " D_VOLTAGE "{m}%*_f " D_UNIT_VOLT "{e}";
const char HTTP_SNS_F_CURRENT_MA[] PROGMEM = "{s}%s " D_CURRENT "{m}%*_f " D_UNIT_MILLIAMPERE "{e}";
+const char HTTP_SNS_F_DISTANCE_CM[] PROGMEM = "{s}%s " D_DISTANCE "{m}%1_f " D_UNIT_CENTIMETER "{e}";
const char HTTP_SNS_HUM[] PROGMEM = "{s}%s " D_HUMIDITY "{m}%s " D_UNIT_PERCENT "{e}";
const char HTTP_SNS_DEW[] PROGMEM = "{s}%s " D_DEWPOINT "{m}%s " D_UNIT_DEGREE "%c{e}";
const char HTTP_SNS_PRESSURE[] PROGMEM = "{s}%s " D_PRESSURE "{m}%s " "%s{e}";
@@ -895,8 +908,6 @@ const char HTTP_SNS_GPM[] PROGMEM = "{s}%s " D_FLOW_RATE "{
const char HTTP_SNS_MOISTURE[] PROGMEM = "{s}%s " D_MOISTURE "{m}%d " D_UNIT_PERCENT "{e}";
const char HTTP_SNS_RANGE_CHR[] PROGMEM = "{s}%s " D_RANGE "{m}%s" "{e}";
const char HTTP_SNS_RANGE[] PROGMEM = "{s}%s " D_RANGE "{m}%d" "{e}";
-const char HTTP_SNS_DISTANCE[] PROGMEM = "{s}%s " D_DISTANCE "{m}%d " D_UNIT_MILLIMETER "{e}";
-const char HTTP_SNS_DISTANCE_CM[] PROGMEM = "{s}%s " D_DISTANCE "{m}%s " D_UNIT_CENTIMETER "{e}";
const char HTTP_SNS_HALL_EFFECT[] PROGMEM = "{s}%s " D_HALL_EFFECT "{m}%d" "{e}";
const char HTTP_SNS_VOLTAGE[] PROGMEM = "{s}" D_VOLTAGE "{m}%s " D_UNIT_VOLT "{e}";
const char HTTP_SNS_CURRENT[] PROGMEM = "{s}" D_CURRENT "{m}%s " D_UNIT_AMPERE "{e}";
diff --git a/tasmota/include/tasmota.h b/tasmota/include/tasmota.h
index 614832513..911df0171 100644
--- a/tasmota/include/tasmota.h
+++ b/tasmota/include/tasmota.h
@@ -303,6 +303,7 @@ const uint32_t LOOP_SLEEP_DELAY = 50; // Lowest number of milliseconds to
#define XPT2046_MAXX 3895
#define XPT2046_MINY 346
#define XPT2046_MAXY 3870
+
/*********************************************************************************************\
* Enumeration
\*********************************************************************************************/
@@ -321,8 +322,17 @@ enum WifiConfigOptions {WIFI_RESTART, EX_WIFI_SMARTCONFIG, WIFI_MANAGER, EX_WIFI
enum WifiTestOptions {WIFI_NOT_TESTING, WIFI_TESTING, WIFI_TEST_FINISHED, WIFI_TEST_FINISHED_BAD};
-enum SwitchModeOptions {TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON, PUSHBUTTON_INV, PUSHBUTTONHOLD, PUSHBUTTONHOLD_INV, PUSHBUTTON_TOGGLE, TOGGLEMULTI,
- FOLLOWMULTI, FOLLOWMULTI_INV, PUSHHOLDMULTI, PUSHHOLDMULTI_INV, PUSHON, PUSHON_INV, PUSH_IGNORE, MAX_SWITCH_OPTION};
+enum SwitchModeOptions {TOGGLE, // 0
+ FOLLOW, FOLLOW_INV, // 1, 2 - Follow switch state
+ PUSHBUTTON, PUSHBUTTON_INV, // 3, 4 - Pushbutton (default 1, 0 = toggle)
+ PUSHBUTTONHOLD, PUSHBUTTONHOLD_INV, // 5, 6 - Pushbutton with hold (default 1, 0 = toggle, Hold = hold)
+ PUSHBUTTON_TOGGLE, // 7 - = 0
+ TOGGLEMULTI, // 8 - = 0 with multi toggle
+ FOLLOWMULTI, FOLLOWMULTI_INV, // 9, 10 - Multi change follow (0 = off, 1 = on, 2x change = hold)
+ PUSHHOLDMULTI, PUSHHOLDMULTI_INV, // 11, 12 - Pushbutton with dimmer mode
+ PUSHON, PUSHON_INV, // 13, 14 - Pushon mode (1 = on, switch off using PulseTime)
+ PUSH_IGNORE, PUSH_IGNORE_INV, // 15, 16 - Send only MQTT message on switch change
+ MAX_SWITCH_OPTION};
enum LedStateOptions {LED_OFF, LED_POWER, LED_MQTTSUB, LED_POWER_MQTTSUB, LED_MQTTPUB, LED_POWER_MQTTPUB, LED_MQTT, LED_POWER_MQTT, MAX_LED_OPTION};
@@ -349,7 +359,7 @@ enum Shortcuts { SC_CLEAR, SC_DEFAULT, SC_USER };
enum SO32_49Index { P_HOLD_TIME, // SetOption32 - (Button/Switch) Key hold time detection in decaseconds (default 40)
P_MAX_POWER_RETRY, // SetOption33 - (Energy) Maximum number of retries before deciding power limit overflow (default 5)
P_BACKLOG_DELAY, // SetOption34 - (Backlog) Minimal delay in milliseconds between executing backlog commands (default 200)
- P_MDNS_DELAYED_START, // SetOption35 - (mDNS) Number of seconds before mDNS is started (default 0) - Obsolete
+ P_SERIAL_SKIP, // SetOption35 - (SerialBridge) Skip number of serial messages received (default 0)
P_BOOT_LOOP_OFFSET, // SetOption36 - (Restart) Number of restarts to start detecting boot loop (default 1)
P_RGB_REMAP, // SetOption37 - (Light) RGB and White channel separation (default 0)
P_IR_UNKNOW_THRESHOLD, // SetOption38 - (IR) Set the smallest sized "UNKNOWN" message packets we actually care about (default 6, max 255)
@@ -361,7 +371,7 @@ enum SO32_49Index { P_HOLD_TIME, // SetOption32 - (Button/Switch) K
P_IR_TOLERANCE, // SetOption44 - (IR) Base tolerance percentage for matching incoming IR messages (default 25, max 100)
P_BISTABLE_PULSE, // SetOption45 - (Bistable) Pulse time for two coil bistable latching relays (default 40)
P_POWER_ON_DELAY, // SetOption46 - (PowerOn) Add delay of 10 x value milliseconds at power on
- P_SO47_FREE, // SetOption47
+ P_POWER_ON_DELAY2, // SetOption47 - (PowerOn) Add delay of value seconds at power on before activating relays
P_SO48_FREE, // SetOption48
P_SO49_FREE // SetOption49
}; // Max is PARAM8_SIZE (18) - SetOption32 until SetOption49
@@ -377,16 +387,17 @@ enum LightTypes { LT_BASIC, LT_PWM1, LT_PWM2, LT_PWM3, LT_PWM4, LT
LT_NU8, LT_SERIAL1, LT_SERIAL2, LT_RGB, LT_RGBW, LT_RGBWC, LT_NU14, LT_NU15 }; // Do not insert new fields
enum XsnsFunctions {FUNC_SETTINGS_OVERRIDE, FUNC_PIN_STATE, FUNC_I2C_INIT, FUNC_MODULE_INIT, FUNC_PRE_INIT, FUNC_INIT,
- FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_SECOND,
+ FUNC_LOOP, FUNC_SLEEP_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_SECOND,
FUNC_SAVE_SETTINGS, FUNC_SAVE_AT_MIDNIGHT, FUNC_SAVE_BEFORE_RESTART,
FUNC_AFTER_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_SENSOR, FUNC_WEB_COL_SENSOR, FUNC_COMMAND, FUNC_COMMAND_SENSOR, FUNC_COMMAND_DRIVER,
FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA,
- FUNC_SET_POWER, FUNC_SET_DEVICE_POWER, FUNC_SHOW_SENSOR, FUNC_ANY_KEY,
+ FUNC_SET_POWER, FUNC_SET_DEVICE_POWER, FUNC_SHOW_SENSOR, FUNC_ANY_KEY, FUNC_LED_LINK,
FUNC_ENERGY_EVERY_SECOND, FUNC_ENERGY_RESET,
FUNC_RULES_PROCESS, FUNC_TELEPERIOD_RULES_PROCESS, FUNC_SERIAL, FUNC_FREE_MEM, FUNC_BUTTON_PRESSED, FUNC_BUTTON_MULTI_PRESSED,
FUNC_WEB_ADD_BUTTON, FUNC_WEB_ADD_CONSOLE_BUTTON, FUNC_WEB_ADD_MANAGEMENT_BUTTON, FUNC_WEB_ADD_MAIN_BUTTON,
FUNC_WEB_GET_ARG, FUNC_WEB_ADD_HANDLER, FUNC_SET_CHANNELS, FUNC_SET_SCHEME, FUNC_HOTPLUG_SCAN, FUNC_TIME_SYNCED,
- FUNC_DEVICE_GROUP_ITEM };
+ FUNC_DEVICE_GROUP_ITEM,
+ FUNC_NETWORK_UP, FUNC_NETWORK_DOWN };
enum AddressConfigSteps { ADDR_IDLE, ADDR_RECEIVE, ADDR_SEND };
@@ -458,10 +469,10 @@ enum DevGroupShareItem { DGR_SHARE_POWER = 1, DGR_SHARE_LIGHT_BRI = 2, DGR_SHARE
enum CommandSource { SRC_IGNORE, SRC_MQTT, SRC_RESTART, SRC_BUTTON, SRC_SWITCH, SRC_BACKLOG, SRC_SERIAL, SRC_WEBGUI, SRC_WEBCOMMAND, SRC_WEBCONSOLE, SRC_PULSETIMER,
SRC_TIMER, SRC_RULE, SRC_MAXPOWER, SRC_MAXENERGY, SRC_OVERTEMP, SRC_LIGHT, SRC_KNX, SRC_DISPLAY, SRC_WEMO, SRC_HUE, SRC_RETRY, SRC_REMOTE, SRC_SHUTTER,
- SRC_THERMOSTAT, SRC_CHAT, SRC_TCL, SRC_BERRY, SRC_FILE, SRC_SSERIAL, SRC_USBCONSOLE, SRC_MAX };
+ SRC_THERMOSTAT, SRC_CHAT, SRC_TCL, SRC_BERRY, SRC_FILE, SRC_SSERIAL, SRC_USBCONSOLE, SRC_SO47, SRC_MAX };
const char kCommandSource[] PROGMEM = "I|MQTT|Restart|Button|Switch|Backlog|Serial|WebGui|WebCommand|WebConsole|PulseTimer|"
"Timer|Rule|MaxPower|MaxEnergy|Overtemp|Light|Knx|Display|Wemo|Hue|Retry|Remote|Shutter|"
- "Thermostat|Chat|TCL|Berry|File|SSerial|UsbConsole";
+ "Thermostat|Chat|TCL|Berry|File|SSerial|UsbConsole|SO47";
const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 };
diff --git a/tasmota/include/tasmota_configurations.h b/tasmota/include/tasmota_configurations.h
index afc97f7ea..60799d67c 100644
--- a/tasmota/include/tasmota_configurations.h
+++ b/tasmota/include/tasmota_configurations.h
@@ -173,11 +173,12 @@
#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 PMS_MODEL_PMS5003T // Enable support for PMSx003T models that report temperature and humidity (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_SERIAL_BRIDGE // Add support for software Serial Bridge (+2k code)
//#define USE_MODBUS_BRIDGE // Add support for software Modbus Bridge (+3k code)
#define USE_MP3_PLAYER // Use of the DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop
//#define USE_AZ7798 // Add support for AZ-Instrument 7798 CO2 datalogger
diff --git a/tasmota/include/tasmota_configurations_ESP32.h b/tasmota/include/tasmota_configurations_ESP32.h
index e5bd679c9..11966f961 100644
--- a/tasmota/include/tasmota_configurations_ESP32.h
+++ b/tasmota/include/tasmota_configurations_ESP32.h
@@ -181,7 +181,7 @@
#define USE_WEBSERVER
#define USE_WEBCLIENT
#define USE_WEBCLIENT_HTTPS
-#define USE_SERIAL_BRIDGE // Add support for software Serial Bridge console Tee (+0k8 code)
+#define USE_SERIAL_BRIDGE // Add support for software Serial Bridge console Tee (+2k code)
#define USE_ETHERNET
#endif // FIRMWARE_SAFEBOOT
@@ -439,11 +439,12 @@
#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 PMS_MODEL_PMS5003T // Enable support for PMSx003T models that report temperature and humidity (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_SERIAL_BRIDGE // Add support for software Serial Bridge (+2k code)
//#define USE_MODBUS_BRIDGE // Add support for software Modbus Bridge (+3k code)
//#define USE_MP3_PLAYER // Use of the DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop
//#define USE_AZ7798 // Add support for AZ-Instrument 7798 CO2 datalogger
@@ -558,6 +559,7 @@
#undef USE_SHELLY_DIMMER // Disable support for Shelly Dimmer (+3k code)
#define USE_LIGHT_PALETTE // Add support for color palette (+0k9 code)
+#define USE_LIGHT_ARTNET // Add support for DMX/ArtNet via UDP on port 6454 (+3.5k code)
#define USE_DS18x20 // Add support for DS18x20 sensors with id sort, single scan and read retry (+1k3 code)
@@ -642,6 +644,7 @@
//#define USE_RC522 // Add support for MFRC522 13.56Mhz Rfid reader (+6k code)
//#define USE_MCP2515 // Add support for can bus using MCP2515 (+7k code)
//#define USE_CANSNIFFER // Add support for can bus sniffer using MCP2515 (+5k code)
+#define USE_SHELLY_PRO // Add support for Shelly Pro
#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)
@@ -654,11 +657,12 @@
#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 PMS_MODEL_PMS5003T // Enable support for PMSx003T models that report temperature and humidity (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_SERIAL_BRIDGE // Add support for software Serial Bridge (+2k code)
#define USE_MODBUS_BRIDGE // Add support for software Modbus Bridge (+3k code)
#define USE_MP3_PLAYER // Use of the DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop
//#define USE_AZ7798 // Add support for AZ-Instrument 7798 CO2 datalogger
@@ -706,6 +710,9 @@
#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_SHIFT595 // Add support for 74xx595 8-bit shift registers (+0k7 code)
+// #define SHIFT595_INVERT_OUTPUTS false // [SetOption133] Don't invert outputs of 74x595 shift register
+// #define SHIFT595_DEVICE_COUNT 1 // [Shift595DeviceCount] Set the number of connected 74x595 shift registers
#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)
@@ -719,6 +726,7 @@
#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
+#define USE_BP1658CJ // Add support for BP1658CJ 5 channel led controller as used in Orein OS0100411267 Bulb
#define USE_ETHERNET // Add support for ethernet (+20k code)
#define USE_DISPLAY_TM1621_SONOFF // Add support for TM1621 display driver used by Sonoff POWR3xxD and THR3xxD
diff --git a/tasmota/include/tasmota_template.h b/tasmota/include/tasmota_template.h
index 09b52c94f..e4e622cb8 100644
--- a/tasmota/include/tasmota_template.h
+++ b/tasmota/include/tasmota_template.h
@@ -197,6 +197,12 @@ enum UserSelectablePins {
GPIO_MBR_TX, GPIO_MBR_RX, // Modbus Bridge Serial interface
GPIO_ADE7953_RST, // ADE7953 Reset
GPIO_NRG_MBS_TX, GPIO_NRG_MBS_RX, // Generic Energy Modbus device
+ GPIO_ADE7953_CS, // ADE7953 SPI Chip Select
+ GPIO_DALI_RX, GPIO_DALI_TX, // Dali
+ GPIO_BP1658CJ_CLK, GPIO_BP1658CJ_DAT,// BP1658CJ
+ GPIO_DINGTIAN_CLK, GPIO_DINGTIAN_SDI, GPIO_DINGTIAN_Q7, GPIO_DINGTIAN_PL, GPIO_DINGTIAN_RCK, // Dingtian relay board - 595's & 165's pins
+ GPIO_LD2410_TX, GPIO_LD2410_RX, // HLK-LD2410
+ GPIO_MBR_TX_ENA, GPIO_NRG_MBS_TX_ENA, // Modbus Bridge Serial Transmit Enable
GPIO_SENSOR_END };
// Error as warning to rethink GPIO usage with max 2045
@@ -207,7 +213,7 @@ enum ProgramSelectablePins {
GPIO_USER, // User configurable needs to be 2047
GPIO_MAX };
-#define MAX_OPTIONS_A 6 // Increase if more bits are used from GpioOptionABits
+#define MAX_OPTIONS_A 7 // Increase if more bits are used from GpioOptionABits
typedef union { // Restricted by MISRA-C Rule 18.4 but so useful...
uint32_t data; // Allow bit manipulation using SetOption
@@ -218,7 +224,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t enable_ccloader : 1; // bit 3 (v9.4.0.5) - Option_A4 - (Zigbee) Enable CCLoader using Zigbee Rx/Tx/Rst Gpios
uint32_t rotary_mi_desk : 1; // bit 4 (v9.5.0.5) - Option_A5 - (Rotary) Enable Mi Desk emulation
uint32_t linkind_support : 1; // bit 5 (v10.1.0.4) - Option_A6 - (Light) LinkInd support
- uint32_t spare06 : 1; // bit 6
+ uint32_t shelly_pro : 1; // bit 6 (v12.2.0.1) - Option_A7 - (Device) Shelly Pro
uint32_t spare07 : 1; // bit 7
uint32_t spare08 : 1; // bit 8
uint32_t spare09 : 1; // bit 9
@@ -441,11 +447,18 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_MBR_TX "|" D_SENSOR_MBR_RX "|"
D_SENSOR_ADE7953_RST "|"
D_SENSOR_NRG_MBS_TX "|" D_SENSOR_NRG_MBS_RX "|"
+ D_SENSOR_ADE7953_CS "|"
+ D_SENSOR_DALI_RX "|" D_SENSOR_DALI_TX "|"
+ D_SENSOR_BP1658CJ_CLK "|" D_SENSOR_BP1658CJ_DAT "|"
+ D_GPIO_DINGTIAN_CLK "|" D_GPIO_DINGTIAN_SDI "|" D_GPIO_DINGTIAN_Q7 "|" D_GPIO_DINGTIAN_PL "|" D_GPIO_DINGTIAN_RCK "|"
+ D_SENSOR_LD2410_TX "|" D_SENSOR_LD2410_RX "|"
+ D_SENSOR_MBR_TX_ENA "|" D_SENSOR_NRG_MBS_TX_ENA "|"
;
const char kSensorNamesFixed[] PROGMEM =
D_SENSOR_USER;
+// Max number of GPIOs
#define MAX_MAX31865S 6
#define MAX_FLOWRATEMETER 2
#define MAX_A4988_MSS 3
@@ -453,6 +466,9 @@ const char kSensorNamesFixed[] PROGMEM =
#define MAX_WEBCAM_HSD 3
#define MAX_SM2135_DAT 10
#define MAX_SM2335_DAT 16
+#define MAX_DSB 4
+#define MAX_BP1658CJ_DAT 16
+#define MAX_DINGTIAN_SHIFT 4
const uint16_t kGpioNiceList[] PROGMEM = {
GPIO_NONE, // Not used
@@ -523,6 +539,11 @@ const uint16_t kGpioNiceList[] PROGMEM = {
* Protocol specifics
\*-------------------------------------------------------------------------------------------*/
+#if defined(USE_DALI) && defined(ESP32)
+ AGPIO(GPIO_DALI_RX), // DALI RX
+ AGPIO(GPIO_DALI_TX), // DALI TX
+#endif // USE_DALI
+
#ifdef USE_I2C
AGPIO(GPIO_I2C_SCL) + MAX_I2C, // I2C SCL
AGPIO(GPIO_I2C_SDA) + MAX_I2C, // I2C SDA
@@ -571,11 +592,11 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_SDIO_D3),
#endif // USE_SDCARD
- 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
+ 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
#if defined(USE_DISPLAY) || defined(USE_LVGL)
#ifdef USE_DISPLAY_ILI9341
@@ -584,7 +605,7 @@ const uint16_t kGpioNiceList[] PROGMEM = {
#endif // USE_DISPLAY_ILI9341
#ifdef USE_XPT2046
- AGPIO(GPIO_XPT2046_CS), // XPT2046 SPI Chip Select
+ AGPIO(GPIO_XPT2046_CS), // XPT2046 SPI Chip Select
#endif
#ifdef USE_DISPLAY_ILI9488
@@ -611,7 +632,6 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_SSD1331_CS),
AGPIO(GPIO_SSD1331_DC),
#endif // USE_DISPLAY_SSD1331
-
#ifdef USE_DISPLAY_MAX7219_MATRIX
#undef USE_DISPLAY_MAX7219
#undef USE_DISPLAY_TM1637
@@ -619,7 +639,11 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_MAX7219DIN),
AGPIO(GPIO_MAX7219CS),
#endif // USE_DISPLAY_MAX7219_MATRIX
-
+#ifdef USE_DISPLAY_MAX7219
+ AGPIO(GPIO_MAX7219CLK),
+ AGPIO(GPIO_MAX7219DIN),
+ AGPIO(GPIO_MAX7219CS),
+#endif // USE_DISPLAY_MAX7219
#ifdef USE_DISPLAY_TM1637
AGPIO(GPIO_TM1637CLK),
AGPIO(GPIO_TM1637DIO),
@@ -627,10 +651,10 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_TM1638DIO),
AGPIO(GPIO_TM1638STB),
#endif // USE_DISPLAY_TM1637
- AGPIO(GPIO_BACKLIGHT), // Display backlight control
- AGPIO(GPIO_OLED_RESET), // OLED Display Reset
+ AGPIO(GPIO_BACKLIGHT), // Display backlight control
+ AGPIO(GPIO_OLED_RESET), // OLED Display Reset
#ifdef ESP32
- AGPIO(GPIO_EPD_DATA), // Base connection EPD driver
+ AGPIO(GPIO_EPD_DATA), // Base connection EPD driver
#endif
#endif // USE_DISPLAY
@@ -646,26 +670,28 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_SSPI_MAX31865_CS1) + MAX_MAX31865S,
#endif
- AGPIO(GPIO_TXD), // Serial interface
- AGPIO(GPIO_RXD), // Serial interface
+ AGPIO(GPIO_TXD), // Serial interface
+ AGPIO(GPIO_RXD), // Serial interface
/*-------------------------------------------------------------------------------------------*\
* Single wire sensors
\*-------------------------------------------------------------------------------------------*/
#ifdef USE_DHT
- AGPIO(GPIO_DHT11), // DHT11
- AGPIO(GPIO_DHT22), // DHT21, DHT22, AM2301, AM2302, AM2321
- AGPIO(GPIO_SI7021), // iTead SI7021
- AGPIO(GPIO_MS01), // Sonoff MS01
- AGPIO(GPIO_DHT11_OUT), // Pseudo Single wire DHT11, DHT21, DHT22, AM2301, AM2302, AM2321
+ AGPIO(GPIO_DHT11), // DHT11
+ AGPIO(GPIO_DHT22), // DHT21, DHT22, AM2301, AM2302, AM2321
+ AGPIO(GPIO_SI7021), // iTead SI7021
+ AGPIO(GPIO_MS01), // Sonoff MS01
+ AGPIO(GPIO_DHT11_OUT), // Pseudo Single wire DHT11, DHT21, DHT22, AM2301, AM2302, AM2321
#endif
#ifdef USE_DS18x20
- AGPIO(GPIO_DSB), // Single wire DS18B20 or DS18S20
- AGPIO(GPIO_DSB_OUT), // Pseudo Single wire DS18B20 or DS18S20
-#endif
+ AGPIO(GPIO_DSB) + MAX_DSB, // Single wire DS18B20 or DS18S20
+#ifdef ESP8266
+ AGPIO(GPIO_DSB_OUT) + MAX_DSB, // Pseudo Single wire DS18B20 or DS18S20
+#endif // ESP8266
+#endif // USE_DS18x20
#ifdef USE_LMT01
- AGPIO(GPIO_LMT01), // LMT01, count pulses on GPIO
+ AGPIO(GPIO_LMT01), // LMT01, count pulses on GPIO
#endif
/*-------------------------------------------------------------------------------------------*\
@@ -675,43 +701,47 @@ const uint16_t kGpioNiceList[] PROGMEM = {
#ifdef USE_LIGHT
#ifdef USE_WS2812
#if (USE_WS2812_HARDWARE == NEO_HW_P9813)
- AGPIO(GPIO_P9813_CLK), // P9813 CLOCK
- AGPIO(GPIO_P9813_DAT), // P9813 DATA
+ AGPIO(GPIO_P9813_CLK), // P9813 CLOCK
+ AGPIO(GPIO_P9813_DAT), // P9813 DATA
#else
- AGPIO(GPIO_WS2812) + (MAX_RMT ? MAX_RMT + 1 : 0),// WS2812 Led string, using RMT on ESP32
+ AGPIO(GPIO_WS2812) + (MAX_RMT ? MAX_RMT + 1 : 0), // WS2812 Led string, using RMT on ESP32
#endif // NEO_HW_P9813
#endif
#ifdef USE_ARILUX_RF
- AGPIO(GPIO_ARIRFRCV), // AriLux RF Receive input
- AGPIO(GPIO_ARIRFSEL), // Arilux RF Receive input selected
+ AGPIO(GPIO_ARIRFRCV), // AriLux RF Receive input
+ AGPIO(GPIO_ARIRFSEL), // Arilux RF Receive input selected
#endif
#ifdef USE_MY92X1
- AGPIO(GPIO_DI), // my92x1 PWM input
- AGPIO(GPIO_DCKI), // my92x1 CLK input
+ AGPIO(GPIO_DI), // my92x1 PWM input
+ AGPIO(GPIO_DCKI), // my92x1 CLK input
#endif // USE_MY92X1
#ifdef USE_SM16716
- AGPIO(GPIO_SM16716_CLK), // SM16716 CLOCK
- AGPIO(GPIO_SM16716_DAT), // SM16716 DATA
- AGPIO(GPIO_SM16716_SEL), // SM16716 SELECT
+ AGPIO(GPIO_SM16716_CLK), // SM16716 CLOCK
+ AGPIO(GPIO_SM16716_DAT), // SM16716 DATA
+ AGPIO(GPIO_SM16716_SEL), // SM16716 SELECT
#endif // USE_SM16716
#ifdef USE_SM2135
- AGPIO(GPIO_SM2135_CLK), // SM2135 CLOCK
- AGPIO(GPIO_SM2135_DAT) + MAX_SM2135_DAT, // SM2135 DATA
+ AGPIO(GPIO_SM2135_CLK), // SM2135 CLOCK
+ AGPIO(GPIO_SM2135_DAT) + MAX_SM2135_DAT, // SM2135 DATA
#endif // USE_SM2135
#ifdef USE_SM2335
- AGPIO(GPIO_SM2335_CLK), // SM2335 CLOCK
- AGPIO(GPIO_SM2335_DAT) + MAX_SM2335_DAT, // SM2335 DATA
+ AGPIO(GPIO_SM2335_CLK), // SM2335 CLOCK
+ AGPIO(GPIO_SM2335_DAT) + MAX_SM2335_DAT, // SM2335 DATA
#endif // USE_SM2335
+#ifdef USE_BP1658CJ
+ AGPIO(GPIO_BP1658CJ_CLK), // BP1658CJ CLOCK
+ AGPIO(GPIO_BP1658CJ_DAT) + MAX_BP1658CJ_DAT, // BP1658CJ DATA
+#endif // USE_BP1658CJ
#ifdef USE_BP5758D
- AGPIO(GPIO_BP5758D_CLK), // BP5758D CLOCK
- AGPIO(GPIO_BP5758D_DAT), // BP5758D DATA
+ AGPIO(GPIO_BP5758D_CLK), // BP5758D CLOCK
+ AGPIO(GPIO_BP5758D_DAT), // BP5758D DATA
#endif // USE_BP5758D
#ifdef USE_TUYA_MCU
- AGPIO(GPIO_TUYA_TX), // Tuya Serial interface
- AGPIO(GPIO_TUYA_RX), // Tuya Serial interface
+ AGPIO(GPIO_TUYA_TX), // Tuya Serial interface
+ AGPIO(GPIO_TUYA_RX), // Tuya Serial interface
#endif
#ifdef USE_EXS_DIMMER
- AGPIO(GPIO_EXS_ENABLE), // EXS MCU Enable
+ AGPIO(GPIO_EXS_ENABLE), // EXS MCU Enable
#endif
#ifdef USE_ELECTRIQ_MOODL
AGPIO(GPIO_ELECTRIQ_MOODL_TX),
@@ -727,34 +757,34 @@ const uint16_t kGpioNiceList[] PROGMEM = {
\*-------------------------------------------------------------------------------------------*/
#if defined(USE_IR_REMOTE) || defined(USE_IR_REMOTE_FULL)
- AGPIO(GPIO_IRSEND) + MAX_IRSEND, // IR remote
+ AGPIO(GPIO_IRSEND) + MAX_IRSEND, // IR remote
#if defined(USE_IR_RECEIVE) || defined(USE_IR_REMOTE_FULL)
- AGPIO(GPIO_IRRECV), // IR receiver
+ AGPIO(GPIO_IRRECV), // IR receiver
#endif
#endif
#ifdef USE_RC_SWITCH
- AGPIO(GPIO_RFSEND), // RF transmitter
- AGPIO(GPIO_RFRECV), // RF receiver
+ AGPIO(GPIO_RFSEND), // RF transmitter
+ AGPIO(GPIO_RFRECV), // RF receiver
#endif
#ifdef USE_RF_SENSOR
- AGPIO(GPIO_RF_SENSOR), // Rf receiver with sensor decoding
+ AGPIO(GPIO_RF_SENSOR), // Rf receiver with sensor decoding
#endif
#ifdef USE_SR04
- AGPIO(GPIO_SR04_TRIG), // SR04 Tri/TXgger pin
- AGPIO(GPIO_SR04_ECHO), // SR04 Ech/RXo pin
+ AGPIO(GPIO_SR04_TRIG), // SR04 Tri/TXgger pin
+ AGPIO(GPIO_SR04_ECHO), // SR04 Ech/RXo pin
#endif
#ifdef USE_TM1638
- AGPIO(GPIO_TM1638CLK), // TM1638 Clock
- AGPIO(GPIO_TM1638DIO), // TM1638 Data I/O
- AGPIO(GPIO_TM1638STB), // 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
- AGPIO(GPIO_HX711_DAT), // HX711 Load Cell data
+ AGPIO(GPIO_HX711_SCK), // HX711 Load Cell clock
+ AGPIO(GPIO_HX711_DAT), // HX711 Load Cell data
#endif
#ifdef USE_TFMINIPLUS
- AGPIO(GPIO_TFMINIPLUS_TX), // TFmini Plus TX pin
- AGPIO(GPIO_TFMINIPLUS_RX), // TFmini Plus RX pin
+ AGPIO(GPIO_TFMINIPLUS_TX), // TFmini Plus TX pin
+ AGPIO(GPIO_TFMINIPLUS_RX), // TFmini Plus RX pin
#endif
/*-------------------------------------------------------------------------------------------*\
@@ -763,98 +793,104 @@ const uint16_t kGpioNiceList[] PROGMEM = {
#ifdef USE_ENERGY_SENSOR
#ifdef USE_HLW8012
- AGPIO(GPIO_NRG_SEL), // HLW8012/HLJ-01 Sel output (1 = Voltage)
- AGPIO(GPIO_NRG_SEL_INV), // HLW8012/HLJ-01 Sel output (0 = Voltage)
- AGPIO(GPIO_NRG_CF1), // HLW8012/HLJ-01 CF1 voltage / current
- AGPIO(GPIO_HLW_CF), // HLW8012 CF power
- AGPIO(GPIO_HJL_CF), // HJL-01/BL0937 CF power
+ AGPIO(GPIO_NRG_SEL), // HLW8012/HLJ-01 Sel output (1 = Voltage)
+ AGPIO(GPIO_NRG_SEL_INV), // HLW8012/HLJ-01 Sel output (0 = Voltage)
+ AGPIO(GPIO_NRG_CF1), // HLW8012/HLJ-01 CF1 voltage / current
+ AGPIO(GPIO_HLW_CF), // HLW8012 CF power
+ AGPIO(GPIO_HJL_CF), // HJL-01/BL0937 CF power
#endif
#if defined(USE_I2C) && defined(USE_ADE7880)
- AGPIO(GPIO_ADE7880_IRQ) + 2, // ADE7880 IRQ - (1 = IRQ1, 2 = IRQ2)
-#endif
-#if defined(USE_I2C) && defined(USE_ADE7953)
- AGPIO(GPIO_ADE7953_IRQ) + 3, // ADE7953 IRQ - (1 = Shelly 2.5, 2 = Shelly EM, 3 = Shelly Plus 2PM)
- AGPIO(GPIO_ADE7953_RST), // ADE7953 Reset
+ AGPIO(GPIO_ADE7880_IRQ) + 2, // ADE7880 IRQ - (1 = IRQ1, 2 = IRQ2)
#endif
+#ifdef USE_ADE7953
+#if defined(USE_I2C) || defined(USE_SPI)
+ AGPIO(GPIO_ADE7953_IRQ) + 5, // ADE7953 IRQ - (1 = Shelly 2.5, 2 = Shelly EM, 3 = Shelly Plus 2PM, 4 = Shelly Pro 1PM, 5 = Shelly Pro 2PM)
+ AGPIO(GPIO_ADE7953_RST), // ADE7953 Reset
+#ifdef USE_SPI
+ AGPIO(GPIO_ADE7953_CS) + 2, // ADE7953 SPI Chip Select (1 = CS1 (1PM, 2PM), 2 = CS2 (2PM))
+#endif // USE_SPI
+#endif // USE_I2C or USE_SPI
+#endif // USE_ADE7953
#ifdef USE_CSE7761
- AGPIO(GPIO_CSE7761_TX), // CSE7761 Serial interface (Dual R3)
- AGPIO(GPIO_CSE7761_RX), // CSE7761 Serial interface (Dual R3)
+ AGPIO(GPIO_CSE7761_TX), // CSE7761 Serial interface (Dual R3)
+ AGPIO(GPIO_CSE7761_RX), // CSE7761 Serial interface (Dual R3)
#endif
#ifdef USE_CSE7766
- AGPIO(GPIO_CSE7766_TX), // CSE7766 Serial interface (S31 and Pow R2)
- AGPIO(GPIO_CSE7766_RX), // CSE7766 Serial interface (S31 and Pow R2)
+ AGPIO(GPIO_CSE7766_TX), // CSE7766 Serial interface (S31 and Pow R2)
+ AGPIO(GPIO_CSE7766_RX), // CSE7766 Serial interface (S31 and Pow R2)
#endif
#ifdef USE_MCP39F501
- AGPIO(GPIO_MCP39F5_TX), // MCP39F501 Serial interface (Shelly2)
- AGPIO(GPIO_MCP39F5_RX), // MCP39F501 Serial interface (Shelly2)
- AGPIO(GPIO_MCP39F5_RST), // MCP39F501 Reset (Shelly2)
+ AGPIO(GPIO_MCP39F5_TX), // MCP39F501 Serial interface (Shelly2)
+ AGPIO(GPIO_MCP39F5_RX), // MCP39F501 Serial interface (Shelly2)
+ AGPIO(GPIO_MCP39F5_RST), // MCP39F501 Reset (Shelly2)
#endif
+ AGPIO(GPIO_NRG_MBS_TX_ENA), // Generic Energy Modbus Transmit Enable
#if defined(USE_PZEM004T) || defined(USE_PZEM_AC) || defined(USE_PZEM_DC)
- AGPIO(GPIO_PZEM0XX_TX), // PZEM0XX Serial interface
+ AGPIO(GPIO_PZEM0XX_TX), // PZEM0XX Serial interface
#endif
#ifdef USE_PZEM004T
- AGPIO(GPIO_PZEM004_RX), // PZEM004T Serial interface
+ AGPIO(GPIO_PZEM004_RX), // PZEM004T Serial interface
#endif
#ifdef USE_PZEM_AC
- AGPIO(GPIO_PZEM016_RX), // PZEM-014,016 Serial Modbus interface
+ AGPIO(GPIO_PZEM016_RX), // PZEM-014,016 Serial Modbus interface
#endif
#ifdef USE_PZEM_DC
- AGPIO(GPIO_PZEM017_RX), // PZEM-003,017 Serial Modbus interface
+ AGPIO(GPIO_PZEM017_RX), // PZEM-003,017 Serial Modbus interface
#endif
#ifdef USE_MODBUS_ENERGY
- AGPIO(GPIO_NRG_MBS_TX), // Generic Energy Modbus device
+ AGPIO(GPIO_NRG_MBS_TX), // Generic Energy Modbus device
AGPIO(GPIO_NRG_MBS_RX),
#endif
#ifdef USE_SDM120
- AGPIO(GPIO_SDM120_TX), // SDM120 Serial interface
- AGPIO(GPIO_SDM120_RX), // SDM120 Serial interface
+ AGPIO(GPIO_SDM120_TX), // SDM120 Serial interface
+ AGPIO(GPIO_SDM120_RX), // SDM120 Serial interface
#endif
#ifdef USE_SDM630
- AGPIO(GPIO_SDM630_TX), // SDM630 Serial interface
- AGPIO(GPIO_SDM630_RX), // SDM630 Serial interface
+ AGPIO(GPIO_SDM630_TX), // SDM630 Serial interface
+ AGPIO(GPIO_SDM630_RX), // SDM630 Serial interface
#endif
#ifdef USE_DDS2382
- AGPIO(GPIO_DDS2382_TX), // DDS2382 Serial interface
- AGPIO(GPIO_DDS2382_RX), // DDS2382 Serial interface
+ AGPIO(GPIO_DDS2382_TX), // DDS2382 Serial interface
+ AGPIO(GPIO_DDS2382_RX), // DDS2382 Serial interface
#endif
#ifdef USE_DDSU666
- AGPIO(GPIO_DDSU666_TX), // DDSU666 Serial interface
- AGPIO(GPIO_DDSU666_RX), // DDSU666 Serial interface
+ AGPIO(GPIO_DDSU666_TX), // DDSU666 Serial interface
+ AGPIO(GPIO_DDSU666_RX), // DDSU666 Serial interface
#endif // USE_DDSU666
#ifdef USE_SOLAX_X1
- AGPIO(GPIO_SOLAXX1_TX), // Solax Inverter tx pin
- AGPIO(GPIO_SOLAXX1_RX), // Solax Inverter rx pin
- AGPIO(GPIO_SOLAXX1_RTS), // Solax Inverter RTS pin
+ AGPIO(GPIO_SOLAXX1_TX), // Solax Inverter tx pin
+ AGPIO(GPIO_SOLAXX1_RX), // Solax Inverter rx pin
+ AGPIO(GPIO_SOLAXX1_RTS), // Solax Inverter RTS pin
#endif // USE_SOLAX_X1
#ifdef USE_LE01MR
- AGPIO(GPIO_LE01MR_TX), // F7F LE-01MR energy meter tx pin
- AGPIO(GPIO_LE01MR_RX), // F7F LE-01MR energy meter rx pin
+ AGPIO(GPIO_LE01MR_TX), // F7F LE-01MR energy meter tx pin
+ AGPIO(GPIO_LE01MR_RX), // F7F LE-01MR energy meter rx pin
#endif // IFDEF:USE_LE01MR
#if defined(USE_BL0940) || defined(USE_BL09XX)
- AGPIO(GPIO_BL0939_RX), // BL0939 Serial interface (Dual R3 v2)
- AGPIO(GPIO_BL0940_RX), // BL0940 Serial interface
- AGPIO(GPIO_BL0942_RX), // BL0940 Serial interface
+ AGPIO(GPIO_BL0939_RX), // BL0939 Serial interface (Dual R3 v2)
+ AGPIO(GPIO_BL0940_RX), // BL0940 Serial interface
+ AGPIO(GPIO_BL0942_RX), // BL0940 Serial interface
#endif
#ifdef USE_IEM3000
- AGPIO(GPIO_IEM3000_TX), // IEM3000 Serial interface
- AGPIO(GPIO_IEM3000_RX), // IEM3000 Serial interface
+ AGPIO(GPIO_IEM3000_TX), // IEM3000 Serial interface
+ AGPIO(GPIO_IEM3000_RX), // IEM3000 Serial interface
#endif
#ifdef USE_WE517
- AGPIO(GPIO_WE517_TX), // WE517 Serial interface
- AGPIO(GPIO_WE517_RX), // WE517 Serial interface
+ AGPIO(GPIO_WE517_TX), // WE517 Serial interface
+ AGPIO(GPIO_WE517_RX), // WE517 Serial interface
#endif
#ifdef USE_SDM72
- AGPIO(GPIO_SDM72_TX), // SDM72 Serial interface
- AGPIO(GPIO_SDM72_RX), // SDM72 Serial interface
+ AGPIO(GPIO_SDM72_TX), // SDM72 Serial interface
+ AGPIO(GPIO_SDM72_RX), // SDM72 Serial interface
#endif
AGPIO(GPIO_ZEROCROSS),
#ifdef USE_SDM230
- AGPIO(GPIO_SDM230_TX), // SDM230 Serial interface
- AGPIO(GPIO_SDM230_RX), // SDM230 Serial interface
+ AGPIO(GPIO_SDM230_TX), // SDM230 Serial interface
+ AGPIO(GPIO_SDM230_RX), // SDM230 Serial interface
#endif
#ifdef USE_BL6523
- AGPIO(GPIO_BL6523_TX), // BL6523 based Watt meter Serial interface
- AGPIO(GPIO_BL6523_RX), // BL6523 based Watt meter Serial interface
+ AGPIO(GPIO_BL6523_TX), // BL6523 based Watt meter Serial interface
+ AGPIO(GPIO_BL6523_RX), // BL6523 based Watt meter Serial interface
#endif
#endif // USE_ENERGY_SENSOR
@@ -863,99 +899,108 @@ const uint16_t kGpioNiceList[] PROGMEM = {
\*-------------------------------------------------------------------------------------------*/
#ifdef USE_SERIAL_BRIDGE
- AGPIO(GPIO_SBR_TX), // Serial Bridge Serial interface
- AGPIO(GPIO_SBR_RX), // Serial Bridge Serial interface
+ AGPIO(GPIO_SBR_TX), // Serial Bridge Serial interface
+ AGPIO(GPIO_SBR_RX), // Serial Bridge Serial interface
#endif
#ifdef USE_MODBUS_BRIDGE
- AGPIO(GPIO_MBR_TX), // Modbus Bridge Serial interface
- AGPIO(GPIO_MBR_RX), // Modbus Bridge Serial interface
+ AGPIO(GPIO_MBR_TX_ENA), // Modbus Bridge Serial interface
+ AGPIO(GPIO_MBR_TX), // Modbus Bridge Serial interface
+ AGPIO(GPIO_MBR_RX), // Modbus Bridge Serial interface
#endif
#ifdef USE_TCP_BRIDGE
- AGPIO(GPIO_TCP_TX), // TCP Serial bridge
- AGPIO(GPIO_TCP_RX), // TCP Serial bridge
+ AGPIO(GPIO_TCP_TX), // TCP Serial bridge
+ AGPIO(GPIO_TCP_RX), // TCP Serial bridge
#endif
#ifdef USE_ZIGBEE
- AGPIO(GPIO_ZIGBEE_TX), // Zigbee Serial interface
- AGPIO(GPIO_ZIGBEE_RX), // Zigbee Serial interface
- AGPIO(GPIO_ZIGBEE_RST) + 2, // Zigbee reset, pin 1 is reset, pin 2 is bootloader mode
+ AGPIO(GPIO_ZIGBEE_TX), // Zigbee Serial interface
+ AGPIO(GPIO_ZIGBEE_RX), // Zigbee Serial interface
+ AGPIO(GPIO_ZIGBEE_RST) + 2, // Zigbee reset, pin 1 is reset, pin 2 is bootloader mode
#endif
#ifdef USE_MHZ19
- AGPIO(GPIO_MHZ_TXD), // MH-Z19 Serial interface
- AGPIO(GPIO_MHZ_RXD), // MH-Z19 Serial interface
+ AGPIO(GPIO_MHZ_TXD), // MH-Z19 Serial interface
+ AGPIO(GPIO_MHZ_RXD), // MH-Z19 Serial interface
#endif
#ifdef USE_SENSEAIR
- AGPIO(GPIO_SAIR_TX), // SenseAir Serial interface
- AGPIO(GPIO_SAIR_RX), // SenseAir Serial interface
+ AGPIO(GPIO_SAIR_TX), // SenseAir Serial interface
+ AGPIO(GPIO_SAIR_RX), // SenseAir Serial interface
#endif
#ifdef USE_NOVA_SDS
- AGPIO(GPIO_SDS0X1_TX), // Nova Fitness SDS011 Serial interface
- AGPIO(GPIO_SDS0X1_RX), // Nova Fitness SDS011 Serial interface
+ AGPIO(GPIO_SDS0X1_TX), // Nova Fitness SDS011 Serial interface
+ AGPIO(GPIO_SDS0X1_RX), // Nova Fitness SDS011 Serial interface
#endif
#ifdef USE_HPMA
- AGPIO(GPIO_HPMA_TX), // Honeywell HPMA115S0 Serial interface
- AGPIO(GPIO_HPMA_RX), // Honeywell HPMA115S0 Serial interface
+ AGPIO(GPIO_HPMA_TX), // Honeywell HPMA115S0 Serial interface
+ AGPIO(GPIO_HPMA_RX), // Honeywell HPMA115S0 Serial interface
#endif
#ifdef USE_PMS5003
- AGPIO(GPIO_PMS5003_TX), // Plantower PMS5003 Serial interface
- AGPIO(GPIO_PMS5003_RX), // Plantower PMS5003 Serial interface
+ AGPIO(GPIO_PMS5003_TX), // Plantower PMS5003 Serial interface
+ AGPIO(GPIO_PMS5003_RX), // Plantower PMS5003 Serial interface
#endif
#ifdef USE_VINDRIKTNING
- AGPIO(GPIO_VINDRIKTNING_RX),
+ AGPIO(GPIO_VINDRIKTNING_RX), // Ikea Vindriktning
#endif
#ifdef USE_HM330X
- AGPIO(GPIO_HM330X_SET), // HM330X Sleep pin (active low)
+ AGPIO(GPIO_HM330X_SET), // HM330X Sleep pin (active low)
#endif
#if defined(USE_TX20_WIND_SENSOR) || defined(USE_TX23_WIND_SENSOR) || defined(USE_WS2300_WIND_SENSOR)
- AGPIO(GPIO_TX2X_TXD_BLACK), // TX20/TX23 Transmission Pin
+ AGPIO(GPIO_TX2X_TXD_BLACK), // TX20/TX23 Transmission Pin
#endif
-#ifdef USE_WINDMETER
+#ifdef USE_WINDMETER // xsns_68_windmeter.ino
AGPIO(GPIO_WINDMETER_SPEED),
#endif
-#ifdef USE_MP3_PLAYER
- AGPIO(GPIO_MP3_DFR562), // RB-DFR-562, DFPlayer Mini MP3 Player Serial interface
- AGPIO(GPIO_MP3_DFR562_BUSY),// RB-DFR-562, DFPlayer Mini MP3 Player optional Busy flag
+#ifdef USE_MP3_PLAYER // xdrv_14_mp3.ino
+ AGPIO(GPIO_MP3_DFR562), // RB-DFR-562, DFPlayer Mini MP3 Player Serial interface
+ AGPIO(GPIO_MP3_DFR562_BUSY), // RB-DFR-562, DFPlayer Mini MP3 Player optional Busy flag
#endif
-#ifdef USE_AZ7798
- AGPIO(GPIO_AZ_TXD), // AZ-Instrument 7798 CO2 datalogger Serial interface
- AGPIO(GPIO_AZ_RXD), // AZ-Instrument 7798 CO2 datalogger Serial interface
+#ifdef USE_AZ7798 // xsns_38_az7798
+ AGPIO(GPIO_AZ_TXD), // AZ-Instrument 7798 CO2 datalogger Serial interface
+ AGPIO(GPIO_AZ_RXD), // AZ-Instrument 7798 CO2 datalogger Serial interface
#endif
-#ifdef USE_PN532_HSU
- AGPIO(GPIO_PN532_TXD), // PN532 HSU Tx
- AGPIO(GPIO_PN532_RXD), // PN532 HSU Rx
+#ifdef USE_PN532_HSU // xsns_40_pn532.ino
+ AGPIO(GPIO_PN532_TXD), // PN532 HSU Tx
+ AGPIO(GPIO_PN532_RXD), // PN532 HSU Rx
#endif
-#ifdef USE_TASMOTA_CLIENT
- AGPIO(GPIO_TASMOTACLIENT_TXD), // Tasmota Client TX
- AGPIO(GPIO_TASMOTACLIENT_RXD), // Tasmota Client RX
- AGPIO(GPIO_TASMOTACLIENT_RST), // Tasmota Client Reset
- AGPIO(GPIO_TASMOTACLIENT_RST_INV), // Tasmota Client Reset Inverted
+#ifdef USE_TASMOTA_CLIENT // xdrv_31_tasmota_client.ino
+ AGPIO(GPIO_TASMOTACLIENT_TXD), // Tasmota Client TX
+ AGPIO(GPIO_TASMOTACLIENT_RXD), // Tasmota Client RX
+ AGPIO(GPIO_TASMOTACLIENT_RST), // Tasmota Client Reset
+ AGPIO(GPIO_TASMOTACLIENT_RST_INV), // Tasmota Client Reset Inverted
#endif
-#ifdef USE_RDM6300
+#ifdef USE_RDM6300 // xsns_51_rdm6300.ino
AGPIO(GPIO_RDM6300_RX),
#endif
-#ifdef USE_IBEACON
+#ifdef USE_IBEACON // xsns_52_ibeacon.ino
AGPIO(GPIO_IBEACON_TX),
AGPIO(GPIO_IBEACON_RX),
#endif
-#ifdef USE_GPS
- AGPIO(GPIO_GPS_TX), // GPS serial interface
- AGPIO(GPIO_GPS_RX), // GPS serial interface
+#ifdef USE_GPS // xsns_60_gps.ino
+ AGPIO(GPIO_GPS_TX), // GPS serial interface
+ AGPIO(GPIO_GPS_RX), // GPS serial interface
#endif
-#ifdef USE_HM10
- AGPIO(GPIO_HM10_TX), // GPS serial interface
- AGPIO(GPIO_HM10_RX), // GPS serial interface
+#ifdef USE_HM10 // xsns_62_mi_hm10.ino
+ AGPIO(GPIO_HM10_TX), // HM10 serial interface
+ AGPIO(GPIO_HM10_RX), // HM10 serial interface
#endif
-#ifdef USE_OPENTHERM
+#ifdef USE_OPENTHERM // xsns_69_opentherm.ino
AGPIO(GPIO_BOILER_OT_TX),
AGPIO(GPIO_BOILER_OT_RX),
#endif
-#ifdef USE_AS608
+#ifdef USE_AS608 // xsns_79_as608.ino
AGPIO(GPIO_AS608_TX),
AGPIO(GPIO_AS608_RX),
#endif
-#ifdef USE_HRG15
+#ifdef USE_HRG15 // xsns_90_hrg15.ino
AGPIO(GPIO_HRG15_TX),
AGPIO(GPIO_HRG15_RX),
#endif
+#ifdef USE_CM110x // xsns_95_cm110x.ino
+ AGPIO(GPIO_CM11_TXD), // CM110x Serial interface
+ AGPIO(GPIO_CM11_RXD), // CM110x Serial interface
+#endif
+#ifdef USE_LD2410 // xsns_102_ld2410.ino
+ AGPIO(GPIO_LD2410_TX), // HLK-LD2410 Serial interface
+ AGPIO(GPIO_LD2410_RX), // HLK-LD2410 Serial interface
+#endif
/*-------------------------------------------------------------------------------------------*\
* Other sensors
@@ -966,27 +1011,27 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_MGC3130_RESET),
#endif
#ifdef USE_MAX31855
- AGPIO(GPIO_MAX31855CS), // MAX31855 Serial interface
- AGPIO(GPIO_MAX31855CLK), // MAX31855 Serial interface
- AGPIO(GPIO_MAX31855DO), // MAX31855 Serial interface
+ AGPIO(GPIO_MAX31855CS), // MAX31855 Serial interface
+ AGPIO(GPIO_MAX31855CLK), // MAX31855 Serial interface
+ AGPIO(GPIO_MAX31855DO), // MAX31855 Serial interface
#endif
#ifdef USE_HRE
AGPIO(GPIO_HRE_CLOCK),
AGPIO(GPIO_HRE_DATA),
#endif
#ifdef USE_A4988_STEPPER
- AGPIO(GPIO_A4988_DIR), // A4988 direction pin
- AGPIO(GPIO_A4988_STP), // A4988 step pin
+ AGPIO(GPIO_A4988_DIR), // A4988 direction pin
+ AGPIO(GPIO_A4988_STP), // A4988 step pin
// folowing are not mandatory
- AGPIO(GPIO_A4988_ENA), // A4988 enabled pin
+ AGPIO(GPIO_A4988_ENA), // A4988 enabled pin
AGPIO(GPIO_A4988_MS1) + MAX_A4988_MSS, // A4988 microstep pin1 to pin3
#endif
#ifdef USE_DEEPSLEEP
AGPIO(GPIO_DEEPSLEEP),
#endif
#ifdef USE_KEELOQ
- AGPIO(GPIO_CC1101_GDO0), // CC1101 pin for RX
- AGPIO(GPIO_CC1101_GDO2), // CC1101 pin for RX
+ AGPIO(GPIO_CC1101_GDO0), // CC1101 pin for RX
+ AGPIO(GPIO_CC1101_GDO2), // CC1101 pin for RX
#endif
#ifdef USE_HRXL
AGPIO(GPIO_HRXL_RX),
@@ -995,54 +1040,57 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_DYP_RX),
#endif
#ifdef USE_AS3935
- AGPIO(GPIO_AS3935), // AS3935 IRQ Pin
+ AGPIO(GPIO_AS3935), // AS3935 IRQ Pin
#endif
#ifdef USE_TELEINFO
AGPIO(GPIO_TELEINFO_RX),
AGPIO(GPIO_TELEINFO_ENABLE),
#endif
#ifdef USE_MIEL_HVAC
- AGPIO(GPIO_MIEL_HVAC_TX), // Mitsubishi Electric HVAC TX pin
- AGPIO(GPIO_MIEL_HVAC_RX), // Mitsubishi Electric HVAC RX pin
+ AGPIO(GPIO_MIEL_HVAC_TX), // Mitsubishi Electric HVAC TX pin
+ AGPIO(GPIO_MIEL_HVAC_RX), // Mitsubishi Electric HVAC RX pin
#endif
#ifdef USE_WIEGAND
- AGPIO(GPIO_WIEGAND_D0), // Date line D0 of Wiegand devices
- AGPIO(GPIO_WIEGAND_D1), // Date line D1 of Wiegand devices
+ AGPIO(GPIO_WIEGAND_D0), // Date line D0 of Wiegand devices
+ AGPIO(GPIO_WIEGAND_D1), // Date line D1 of Wiegand devices
#endif
#ifdef USE_NEOPOOL
- AGPIO(GPIO_NEOPOOL_TX), // Sugar Valley RS485 Interface
- AGPIO(GPIO_NEOPOOL_RX), // Sugar Valley RS485 Interface
+ AGPIO(GPIO_NEOPOOL_TX), // Sugar Valley RS485 Interface
+ AGPIO(GPIO_NEOPOOL_RX), // Sugar Valley RS485 Interface
#endif
#ifdef USE_PROJECTOR_CTRL
- AGPIO(GPIO_PROJECTOR_CTRL_TX), // LCD/DLP Projector Serial Control
- AGPIO(GPIO_PROJECTOR_CTRL_RX), // LCD/DLP Projector Serial Control
+ AGPIO(GPIO_PROJECTOR_CTRL_TX), // LCD/DLP Projector Serial Control
+ AGPIO(GPIO_PROJECTOR_CTRL_RX), // LCD/DLP Projector Serial Control
#endif
#if defined(USE_VL53L0X) or defined (USE_VL53L1X)
AGPIO(GPIO_VL53LXX_XSHUT1) + VL53LXX_MAX_SENSORS, // When using multiple VL53LXX.
#endif
-
-#ifdef USE_DISPLAY_MAX7219
- AGPIO(GPIO_MAX7219CLK),
- AGPIO(GPIO_MAX7219DIN),
- AGPIO(GPIO_MAX7219CS),
-#endif // USE_DISPLAY_MAX7219
-
-#ifdef USE_CM110x
- AGPIO(GPIO_CM11_TXD), // CM110x Serial interface
- AGPIO(GPIO_CM11_RXD), // CM110x Serial interface
-#endif
-
#ifdef USE_FLOWRATEMETER
AGPIO(GPIO_FLOWRATEMETER_IN) + MAX_FLOWRATEMETER, // Flow meter Pin
#endif
+#ifdef USE_SHIFT595
+ AGPIO(GPIO_SHIFT595_SRCLK), // 74x595 shift register
+ AGPIO(GPIO_SHIFT595_RCLK),
+ AGPIO(GPIO_SHIFT595_OE),
+ AGPIO(GPIO_SHIFT595_SER),
+#endif
+
+#if defined (ESP32) && defined(USE_DINGTIAN_RELAY)
+ AGPIO(GPIO_DINGTIAN_CLK) + MAX_DINGTIAN_SHIFT, // Dingtian Relay board - 8,16,24 or 32 relays & inputs
+ AGPIO(GPIO_DINGTIAN_SDI),
+ AGPIO(GPIO_DINGTIAN_Q7),
+ AGPIO(GPIO_DINGTIAN_PL),
+ AGPIO(GPIO_DINGTIAN_RCK),
+#endif
+
/*-------------------------------------------------------------------------------------------*\
* ESP32 specifics
\*-------------------------------------------------------------------------------------------*/
#ifdef ESP32
#if CONFIG_IDF_TARGET_ESP32
- AGPIO(GPIO_HALLEFFECT) + 2, // Hall effect sensor connected to GPIO36 and 39
+ AGPIO(GPIO_HALLEFFECT) + 2, // Hall effect sensor connected to GPIO36 and 39
#endif // CONFIG_IDF_TARGET_ESP32
#ifdef USE_WEBCAM
AGPIO(GPIO_WEBCAM_PWDN),
@@ -1061,31 +1109,24 @@ const uint16_t kGpioNiceList[] PROGMEM = {
#ifdef USE_ETHERNET
AGPIO(GPIO_ETH_PHY_POWER),
AGPIO(GPIO_ETH_PHY_MDC),
- AGPIO(GPIO_ETH_PHY_MDIO), // Ethernet
+ AGPIO(GPIO_ETH_PHY_MDIO), // Ethernet
#endif // USE_ETHERNET
/*-------------------------------------------------------------------------------------------*\
* ESP32 multiple Analog / Digital converter inputs
\*-------------------------------------------------------------------------------------------*/
- AGPIO(GPIO_ADC_INPUT) + MAX_ADCS, // Analog inputs
- AGPIO(GPIO_ADC_TEMP) + MAX_ADCS, // Thermistor
- AGPIO(GPIO_ADC_LIGHT) + MAX_ADCS, // Light sensor
- AGPIO(GPIO_ADC_BUTTON) + MAX_KEYS, // Button
+ AGPIO(GPIO_ADC_INPUT) + MAX_ADCS, // Analog inputs
+ AGPIO(GPIO_ADC_TEMP) + MAX_ADCS, // Thermistor
+ AGPIO(GPIO_ADC_LIGHT) + MAX_ADCS, // Light sensor
+ AGPIO(GPIO_ADC_BUTTON) + MAX_KEYS, // Button
AGPIO(GPIO_ADC_BUTTON_INV) + MAX_KEYS,
- AGPIO(GPIO_ADC_RANGE) + MAX_ADCS, // Range
- AGPIO(GPIO_ADC_CT_POWER) + MAX_ADCS, // Current
- AGPIO(GPIO_ADC_JOY) + MAX_ADCS, // Joystick
- AGPIO(GPIO_ADC_PH) + MAX_ADCS, // Analog PH Sensor
- AGPIO(GPIO_ADC_MQ) + MAX_ADCS, // Analog MQ Sensor
+ AGPIO(GPIO_ADC_RANGE) + MAX_ADCS, // Range
+ AGPIO(GPIO_ADC_CT_POWER) + MAX_ADCS, // Current
+ AGPIO(GPIO_ADC_JOY) + MAX_ADCS, // Joystick
+ AGPIO(GPIO_ADC_PH) + MAX_ADCS, // Analog PH Sensor
+ AGPIO(GPIO_ADC_MQ) + MAX_ADCS, // Analog MQ Sensor
#endif // ESP32
-
-#ifdef USE_SHIFT595
- AGPIO(GPIO_SHIFT595_SRCLK), // 74x595 shift register
- AGPIO(GPIO_SHIFT595_RCLK),
- AGPIO(GPIO_SHIFT595_OE),
- AGPIO(GPIO_SHIFT595_SER),
-#endif
};
/*-------------------------------------------------------------------------------------------*\
diff --git a/tasmota/include/tasmota_types.h b/tasmota/include/tasmota_types.h
index e1964b9e6..fbd94f0ab 100644
--- a/tasmota/include/tasmota_types.h
+++ b/tasmota/include/tasmota_types.h
@@ -181,7 +181,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
struct { // SetOption146 .. SetOption177
uint32_t use_esp32_temperature : 1; // bit 0 (v12.1.1.1) - SetOption146 - (ESP32) Show ESP32 internal temperature sensor
uint32_t mqtt_disable_sserialrec : 1; // bit 1 (v12.1.1.2) - SetOption147 - (MQTT) Disable publish SSerialReceived MQTT messages, you must use event trigger rules instead.
- uint32_t spare02 : 1; // bit 2
+ uint32_t artnet_autorun : 1; // bit 2 (v12.2.0.4) - SetOption148 - (Light) start DMX ArtNet at boot, listen to UDP port as soon as network is up
uint32_t spare03 : 1; // bit 3
uint32_t spare04 : 1; // bit 4
uint32_t spare05 : 1; // bit 5
@@ -268,7 +268,7 @@ typedef union {
uint32_t spare25 : 1; // bit 25
uint32_t spare26 : 1; // bit 26
uint32_t spare27 : 1; // bit 27
- uint32_t sunrise_dawn_angle : 2; // bits 28/29 (v12.1.1.4) -
+ uint32_t sunrise_dawn_angle : 2; // bits 28/29 (v12.1.1.4) -
uint32_t temperature_set_res : 2; // bits 30/31 (v9.3.1.4) - (Tuya)
};
} SysMBitfield2;
@@ -549,10 +549,9 @@ typedef struct {
uint32_t energy_power_calibration; // 364
uint32_t energy_voltage_calibration; // 368
uint32_t energy_current_calibration; // 36C
- uint32_t ex_energy_kWhtoday; // 370
- uint32_t ex_energy_kWhyesterday; // 374
- uint16_t energy_kWhdoy; // 378
- uint16_t energy_min_power; // 37A
+ uint32_t energy_power_calibration2; // 370 - ex_energy_kWhtoday
+ uint32_t energy_voltage_calibration2; // 374 - ex_energy_kWhyesterday
+ uint32_t energy_current_calibration2; // 378 - ex_energy_kWhdoy, ex_energy_min_power
uint16_t energy_max_power; // 37C
uint16_t energy_min_voltage; // 37E
uint16_t energy_max_voltage; // 380
@@ -573,8 +572,9 @@ typedef struct {
uint16_t blinkcount; // 39C
uint16_t light_rotation; // 39E
SOBitfield3 flag3; // 3A0
-
- uint8_t ex_switchmode[8]; // 3A4 - Free since 9.2.0.6
+ uint16_t energy_kWhdoy; // 3A4
+ uint16_t energy_min_power; // 3A6
+ uint32_t pn532_password; // 3A8 - ex_switchmode4-7, Free since 9.2.0.6
#ifdef CONFIG_IDF_TARGET_ESP32S3
// ------------------------------------
@@ -687,15 +687,15 @@ typedef struct {
uint16_t mqtt_socket_timeout; // 52E
uint8_t mqtt_wifi_timeout; // 530
uint8_t ina219_mode; // 531
- uint16_t ex_pulse_timer[8]; // 532 Free since 11.0.0.3
+
+ uint16_t ex_pulse_timer[8]; // 532 ex_pulse_timer free since 11.0.0.3
+
uint16_t button_debounce; // 542
uint32_t ipv4_address[5]; // 544
uint32_t ipv4_rgx_address; // 558
uint32_t ipv4_rgx_subnetmask; // 55C
uint16_t pwm_value_ext[16-5]; // 560 Extension to pwm_value to store up to 16 PWM for ESP32. This array stores values 5..15
-
- uint8_t free_576[2]; // 576
-
+ uint16_t pn532_pack; // 576
int32_t weight_offset; // 578
uint16_t pulse_timer[MAX_PULSETIMERS]; // 57C
SysMBitfield1 flag2; // 5BC
@@ -722,14 +722,16 @@ typedef struct {
char user_template_name[15]; // 720 15 bytes - Backward compatibility since v8.2.0.3
#ifdef ESP8266
- mytmplt8285 ex_user_template8; // 72F 14 bytes (ESP8266) - Free since 9.0.0.1
+ uint8_t ex_user_template8[5]; // 72F 14 bytes (ESP8266) - Free since 9.0.0.1 - only 5 bytes referenced now
#endif // ESP8266
#ifdef ESP32
uint8_t webcam_clk; // 72F
WebCamCfg2 webcam_config2; // 730
-
- uint8_t free_esp32_734[9]; // 734
#endif // ESP32
+ uint16_t artnet_universe; // 734
+ uint16_t modbus_sbaudrate; // 736
+
+ uint8_t free_esp32_738[5]; // 738
uint8_t novasds_startingoffset; // 73D
uint8_t web_color[18][3]; // 73E
@@ -830,18 +832,22 @@ typedef struct {
uint8_t shd_warmup_time; // F5E
uint8_t tcp_config; // F5F
uint8_t light_step_pixels; // F60
- uint8_t modbus_sbaudrate; // F61
+
+ uint8_t ex_modbus_sbaudrate; // F61 - v12.2.0.5
+
uint8_t modbus_sconfig; // F62
uint8_t free_f63[13]; // F63 - Decrement if adding new Setting variables just above and below
// Only 32 bit boundary variables below
- uint32_t touch_threshold; // F70
+ uint32_t touch_threshold; // F70
SOBitfield6 flag6; // F74
uint16_t flowratemeter_calibration[2];// F78
int32_t energy_kWhexport_ph[3]; // F7C
uint32_t eth_ipv4_address[5]; // F88
+
uint32_t ex_energy_kWhtotal; // F9C
+
SBitfield1 sbflag1; // FA0
TeleinfoCfg teleinfo; // FA4
uint64_t rf_protocol_mask; // FA8
diff --git a/tasmota/include/tasmota_version.h b/tasmota/include/tasmota_version.h
index 72767362d..2665d17c2 100644
--- a/tasmota/include/tasmota_version.h
+++ b/tasmota/include/tasmota_version.h
@@ -20,6 +20,6 @@
#ifndef _TASMOTA_VERSION_H_
#define _TASMOTA_VERSION_H_
-const uint32_t VERSION = 0x0C020000; // 12.2.0.0
+const uint32_t VERSION = 0x0C030000; // 12.3.0.0
#endif // _TASMOTA_VERSION_H_
diff --git a/tasmota/include/xsns_62_esp32_mi.h b/tasmota/include/xsns_62_esp32_mi.h
index 409821481..8418554df 100644
--- a/tasmota/include/xsns_62_esp32_mi.h
+++ b/tasmota/include/xsns_62_esp32_mi.h
@@ -201,7 +201,6 @@ struct {
uint32_t allwaysAggregate:1; // always show all known values of one sensor in brdigemode
uint32_t noSummary:1; // no sensor values at TELE-period
uint32_t directBridgeMode:1; // send every received BLE-packet as a MQTT-message in real-time
- uint32_t showRSSI:1;
uint32_t activeScan:1;
uint32_t ignoreBogusBattery:1;
uint32_t minimalSummary:1; // DEPRECATED!!
diff --git a/tasmota/language/af_AF.h b/tasmota/language/af_AF.h
index 51431cb18..b3ff8c4b7 100644
--- a/tasmota/language/af_AF.h
+++ b/tasmota/language/af_AF.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Ontfout"
#define D_DEWPOINT "Dou punt"
#define D_DISABLED "Gedeaktiveer"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Afstand"
#define D_DNS_SERVER "DNS"
#define D_DO "Opgeloste suurstof"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM gevind by adres"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Ewekansige Zigbee parameters, kyk asseblief met 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energie Vandag"
#define D_ENERGY_YESTERDAY "Energie Gister"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Gonser"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "Diep slaap"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h
index a184ee348..3281cdc47 100644
--- a/tasmota/language/bg_BG.h
+++ b/tasmota/language/bg_BG.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Дебъгване"
#define D_DEWPOINT "Температура на оросяване"
#define D_DISABLED "Забранено"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Разстояние"
#define D_DNS_SERVER "Сървър на DNS"
#define D_DO "Разтворен кислород"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Консумация за днес"
#define D_ENERGY_YESTERDAY "Консумация за вчера"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Зумер"
#define D_SENSOR_DISP_RESET "Нулиране дисплей"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Дебитомер"
diff --git a/tasmota/language/ca_AD.h b/tasmota/language/ca_AD.h
index dc9e953c9..8ac3e95c7 100644
--- a/tasmota/language/ca_AD.h
+++ b/tasmota/language/ca_AD.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Depuració"
#define D_DEWPOINT "Punt de rossada"
#define D_DISABLED "Deshabilitat"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Distancia"
#define D_DNS_SERVER "Servidor DNS"
#define D_DO "Oxígen dissolt"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energy Today"
#define D_ENERGY_YESTERDAY "Energy Yesterday"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Brunzidor"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Cabal"
diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h
index f970244f0..9707e8836 100644
--- a/tasmota/language/cs_CZ.h
+++ b/tasmota/language/cs_CZ.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Debug"
#define D_DEWPOINT "Dew point"
#define D_DISABLED "Zablokováno"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Distance"
#define D_DNS_SERVER "Server DNS"
#define D_DO "Disolved Oxygen"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Spotřeba Dnes"
#define D_ENERGY_YESTERDAY "Spotřeba Včera"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h
index 62237ae3d..cdd50b101 100644
--- a/tasmota/language/de_DE.h
+++ b/tasmota/language/de_DE.h
@@ -83,6 +83,9 @@
#define D_DEBUG "debug"
#define D_DEWPOINT "Taupunkt"
#define D_DISABLED "deaktiviert"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Abstand"
#define D_DNS_SERVER "DNS-Server"
#define D_DO "gelöster Sauerstoff"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM gefunden an Adresse"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Zufällige Zigbee Parameter erstellt, Überprüfung mit 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energie heute"
#define D_ENERGY_YESTERDAY "Energie gestern"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h
index 8a93f5e95..308dc79bb 100644
--- a/tasmota/language/el_GR.h
+++ b/tasmota/language/el_GR.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Debug"
#define D_DEWPOINT "Dew point"
#define D_DISABLED "Ανενεργό"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Απόσταση"
#define D_DNS_SERVER "Διακομιστής DNS"
#define D_DO "Disolved Oxygen"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Ενέργεια σήμερα"
#define D_ENERGY_YESTERDAY "Ενέργεια χθες"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h
index 2fdfd1a71..a42565b7e 100644
--- a/tasmota/language/en_GB.h
+++ b/tasmota/language/en_GB.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Debug"
#define D_DEWPOINT "Dew point"
#define D_DISABLED "Disabled"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Distance"
#define D_DNS_SERVER "DNS Server"
#define D_DO "Disolved Oxygen"
@@ -355,7 +358,7 @@
#define D_PROGRAM_VERSION "Program Version"
#define D_BUILD_DATE_AND_TIME "Build Date & Time"
#define D_CORE_AND_SDK_VERSION "Core/SDK Version"
-#define D_FLASH_WRITE_COUNT "Flash write Count"
+#define D_FLASH_WRITE_COUNT "Flash Write Count"
#define D_MAC_ADDRESS "MAC Address"
#define D_MQTT_HOST "MQTT Host"
#define D_MQTT_PORT "MQTT Port"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energy Today"
#define D_ENERGY_YESTERDAY "Energy Yesterday"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h
index d52cd714c..b3608171e 100644
--- a/tasmota/language/es_ES.h
+++ b/tasmota/language/es_ES.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Debug"
#define D_DEWPOINT "Punto de Rocío"
#define D_DISABLED "Deshabilitado"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Distancia"
#define D_DNS_SERVER "Servidor DNS"
#define D_DO "Oxígeno Disuelto"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "Encontrada EEPROM de ZBBridge en"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Configurando parámetros Zigbee de forma aleatoria. Usar 'ZbConfig' para revisarlos."
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energía Hoy"
#define D_ENERGY_YESTERDAY "Energía Ayer"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h
index 9de3e227c..8f0425f16 100644
--- a/tasmota/language/fr_FR.h
+++ b/tasmota/language/fr_FR.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Debug"
#define D_DEWPOINT "Point de rosée"
#define D_DISABLED "Désactivé"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Distance"
#define D_DNS_SERVER "Serveur DNS"
#define D_DO "Oxygène dissout"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "EEPROM ZBBridge trouvée à l'adresse"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomisation des paramètres ZigBee, veuillez vérifier avec 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xsns_03_energy.ino
#define D_ENERGY_TODAY "Énergie aujourd'hui"
#define D_ENERGY_YESTERDAY "Énergie hier"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr TX"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 TX"
#define D_SENSOR_SDM72_RX "SDM72 RX"
#define D_SENSOR_SDM120_TX "SDMx20 TX"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 RX"
#define D_SENSOR_WE517_TX "WE517 TX"
#define D_SENSOR_WE517_RX "WE517 RX"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "ZigBee TX"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 DAT"
#define D_SENSOR_SM2335_CLK "SM2335 CLK"
#define D_SENSOR_SM2335_DAT "SM2335 DAT"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "Hibernation"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/fy_NL.h b/tasmota/language/fy_NL.h
index 2054bd5f8..10a5a9798 100644
--- a/tasmota/language/fy_NL.h
+++ b/tasmota/language/fy_NL.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Debugearje"
#define D_DEWPOINT "Dauwpunt"
#define D_DISABLED "Útsetten"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Ôfstân"
#define D_DNS_SERVER "DNS Server"
#define D_DO "Oploste soerstof"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM fûn op adres"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, kontrolearje asjebleaft mei 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Konsumpsje hjoed"
#define D_ENERGY_YESTERDAY "Konsumpsje juster"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Zoemer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h
index 81da7bfa0..653dba154 100644
--- a/tasmota/language/he_HE.h
+++ b/tasmota/language/he_HE.h
@@ -83,6 +83,9 @@
#define D_DEBUG "באגים"
#define D_DEWPOINT "Dew point"
#define D_DISABLED "מבוטל"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "מרחק"
#define D_DNS_SERVER "DNS שרת"
#define D_DO "Disolved Oxygen"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "צריכה יומית"
#define D_ENERGY_YESTERDAY "צריכה בעבר"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h
index 368de4c26..66cce299b 100644
--- a/tasmota/language/hu_HU.h
+++ b/tasmota/language/hu_HU.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Debug"
#define D_DEWPOINT "Harmatpont"
#define D_DISABLED "Letiltva"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Távolság"
#define D_DNS_SERVER "DNS szerver"
#define D_DO "Oldott oxygén"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM található a címen"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Zigbee paramétereknek véletlennek kell lenniük, ellenőrizd a 'ZbConfig'-gal"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Mai energia"
#define D_ENERGY_YESTERDAY "Tegnapi energia"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h
index fd2a0c33b..f595ca2ec 100644
--- a/tasmota/language/it_IT.h
+++ b/tasmota/language/it_IT.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.4.0.1 - Last update 05.10.2022
+ * Updated until v9.4.0.1 - Last update 07.12.2022
\*********************************************************************/
#define LANGUAGE_MODULE_NAME // Enable to display "Module Generic" (ie Spanish), Disable to display "Generic Module" (ie English)
@@ -83,6 +83,9 @@
#define D_DEBUG "Debug"
#define D_DEWPOINT "Punto rugiada" //
#define D_DISABLED "Disabilitato/a"
+#define D_MOVING_DISTANCE "Distanza in movimento"
+#define D_STATIC_DISTANCE "Distanza statica"
+#define D_DETECT_DISTANCE "Rileva distanza"
#define D_DISTANCE "Distanza"
#define D_DNS_SERVER "Server DNS"
#define D_DO "Ossigeno dissolto"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "Trovata EEPROM ZBBridge all'indirizzo"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizzazione parametri Zigbee, controlla con \"ZbConfig\""
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali - RX"
+#define D_SENSOR_DALI_TX "Dali - TX"
+#define D_CONFIGURE_DALI "DALI - Config"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energia - oggi"
#define D_ENERGY_YESTERDAY "Energia - ieri"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr - TX"
#define D_SENSOR_MBR_TX "ModBr - TX"
#define D_SENSOR_MBR_RX "ModBr - RX"
+#define D_SENSOR_MBR_TX_ENA "ModBr - TX ON"
#define D_SENSOR_SR04_TRIG "SR04 Tri - TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech - RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus - TX"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus - RX"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs - TX"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs - RX"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs - TX ON"
#define D_SENSOR_SDM72_TX "SDM72 - TX"
#define D_SENSOR_SDM72_RX "SDM72 - RX"
#define D_SENSOR_SDM120_TX "SDMx20 - TX"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 - RX"
#define D_SENSOR_WE517_TX "WE517 - TX"
#define D_SENSOR_WE517_RX "WE517 - RX"
+#define D_SENSOR_LD2410_TX "LD2410 - TX"
+#define D_SENSOR_LD2410_RX "LD2410 - RX"
#define D_GPIO_TM1621_CS "TM1621 - CS"
#define D_GPIO_TM1621_WR "TM1621 - WR"
#define D_GPIO_TM1621_RD "TM1621 - RD"
@@ -764,6 +776,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 - IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 - IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 - RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 - CS"
#define D_SENSOR_BUZZER "Cicalino"
#define D_SENSOR_DISP_RESET "Display - RESET"
#define D_SENSOR_ZIGBEE_TXD "Zigbee - TX"
@@ -792,6 +805,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 - DATI"
#define D_SENSOR_SM2335_CLK "SM2335 - CLK"
#define D_SENSOR_SM2335_DAT "SM2335 - DATI"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ - CLK"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ - DATI"
#define D_SENSOR_BP5758D_CLK "BP5758D - CLK"
#define D_SENSOR_BP5758D_DAT "BP5758D - DATI"
#define D_SENSOR_DEEPSLEEP "Sleep profondo"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 - RCLK"
#define D_GPIO_SHIFT595_OE "74x595 - OE"
#define D_GPIO_SHIFT595_SER "74x595 - SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian - CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian - SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian - Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian - PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian - RCK"
#define D_SENSOR_CM11_TX "CM110x - TX"
#define D_SENSOR_CM11_RX "CM110x - RX"
#define D_SENSOR_FLOWRATEMETER "Portata"
diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h
index 669a803d9..d397732fd 100644
--- a/tasmota/language/ko_KO.h
+++ b/tasmota/language/ko_KO.h
@@ -83,6 +83,9 @@
#define D_DEBUG "디버그"
#define D_DEWPOINT "Dew point"
#define D_DISABLED "사용안함"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "거리"
#define D_DNS_SERVER "DNS 서버"
#define D_DO "Disolved Oxygen"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "금일 전력 사용량"
#define D_ENERGY_YESTERDAY "어제 전력 사용량"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h
index 975f6da08..2e738f427 100644
--- a/tasmota/language/nl_NL.h
+++ b/tasmota/language/nl_NL.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Debug"
#define D_DEWPOINT "Dauwpunt"
#define D_DISABLED "Uitgeschakeld"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Afstand"
#define D_DNS_SERVER "DNS Server"
#define D_DO "Opgelost zuurstof"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM aanwezig op adres"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Willekeurige Zigbee parameters gemaakt, controleer met 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Verbruik vandaag"
#define D_ENERGY_YESTERDAY "Verbruik gisteren"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Zoemer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h
index 56b45c3a1..c4ace8791 100644
--- a/tasmota/language/pl_PL.h
+++ b/tasmota/language/pl_PL.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Debug"
#define D_DEWPOINT "Punkt rosy"
#define D_DISABLED "Wyłączony"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Odległość"
#define D_DNS_SERVER "Serwer DNS"
#define D_DO "Rozpuszczalność tlenu"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "Znaleziono ZBBridge EEPROM na adresie"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Losowanie parametrów Zigbee, proszę sprawdzić 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energia dzisiaj"
#define D_ENERGY_YESTERDAY "Energia wczoraj"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Dzwonek"
#define D_SENSOR_DISP_RESET "Reset Display"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "Głęboko uśpiony"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h
index 6658540c7..288d5c74b 100644
--- a/tasmota/language/pt_BR.h
+++ b/tasmota/language/pt_BR.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Depurar"
#define D_DEWPOINT "Ponto de orvalho"
#define D_DISABLED "Desabilitado"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Distância"
#define D_DNS_SERVER "Servidor DNS"
#define D_DO "Oxigênio dissolvido"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "EEPROM ZBBridge encontrada no endereço" // "ZBBridge EEPROM found at address"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizando parametros Zigbee, por favor congira em 'ZbConfig'" // "Randomizing Zigbee parameters, please check with 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Consumo energético de hoje"
#define D_ENERGY_YESTERDAY "Consumo energético de ontem"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h
index 45a9cf352..8e30a194a 100644
--- a/tasmota/language/pt_PT.h
+++ b/tasmota/language/pt_PT.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Depurar"
#define D_DEWPOINT "Ponto de Condensação"
#define D_DISABLED "Disabilitado"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Distância"
#define D_DNS_SERVER "Servidor DNS"
#define D_DO "Oxigénio Dissolvido"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM encontrada no edereço"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomização de parâmetros Zigbee, por-favor verifique a 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Consumo energético de hoje"
#define D_ENERGY_YESTERDAY "Consumo energético de ontem"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h
index 189b782f5..30458b06f 100644
--- a/tasmota/language/ro_RO.h
+++ b/tasmota/language/ro_RO.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Depanare"
#define D_DEWPOINT "Punct de rouă"
#define D_DISABLED "Dezactivat"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Distanță"
#define D_DNS_SERVER "Server DNS"
#define D_DO "Disolved Oxygen"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energia de Azi"
#define D_ENERGY_YESTERDAY "Energia de Ieri"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h
index 1e9bdb7cb..22baa6b7f 100644
--- a/tasmota/language/ru_RU.h
+++ b/tasmota/language/ru_RU.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Отладка"
#define D_DEWPOINT "Dew point"
#define D_DISABLED "Блокирован"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Distance"
#define D_DNS_SERVER "DNS Сервер"
#define D_DO "Disolved Oxygen"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Конфигурация DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Энергия Сегодня"
#define D_ENERGY_YESTERDAY "Энергия Вчера"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h
index d4e10bfd2..2c26bc49e 100644
--- a/tasmota/language/sk_SK.h
+++ b/tasmota/language/sk_SK.h
@@ -84,6 +84,9 @@
#define D_DEBUG "Debug"
#define D_DEWPOINT "Dew point"
#define D_DISABLED "Zablokované"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Vzdialenosť"
#define D_DNS_SERVER "Server DNS"
#define D_DO "Disolved Oxygen"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Spotreba dnes"
#define D_ENERGY_YESTERDAY "Spotreba včera"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h
index f00257d5d..8e0b22ed6 100644
--- a/tasmota/language/sv_SE.h
+++ b/tasmota/language/sv_SE.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Debug"
#define D_DEWPOINT "Dew point"
#define D_DISABLED "Inaktiverad"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Distans"
#define D_DNS_SERVER "DNS-server"
#define D_DO "Disolved Oxygen"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energi idag"
#define D_ENERGY_YESTERDAY "Energi igår"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h
index b33bbd15a..9feaf5034 100644
--- a/tasmota/language/tr_TR.h
+++ b/tasmota/language/tr_TR.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Hata Ayıklama"
#define D_DEWPOINT "Dew point"
#define D_DISABLED "Etkin Değil"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Mesage"
#define D_DNS_SERVER "DNS Sunucu"
#define D_DO "Disolved Oxygen"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energy Today"
#define D_ENERGY_YESTERDAY "Energy Yesterday"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h
index e499efe8c..96fae7c7e 100644
--- a/tasmota/language/uk_UA.h
+++ b/tasmota/language/uk_UA.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Налагодження"
#define D_DEWPOINT "Tочка роси"
#define D_DISABLED "Вимкнено"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Відстань"
#define D_DNS_SERVER "Сервер DNS"
#define D_DO "Disolved Oxygen"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Енергія Сьогодні"
#define D_ENERGY_YESTERDAY "Енергія Вчора"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Зуммер"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/vi_VN.h b/tasmota/language/vi_VN.h
index aae3a48f3..e0a9df039 100644
--- a/tasmota/language/vi_VN.h
+++ b/tasmota/language/vi_VN.h
@@ -83,6 +83,9 @@
#define D_DEBUG "Tìm lỗi"
#define D_DEWPOINT "Điểm sương"
#define D_DISABLED "Vô hiệu hóa"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "Khoảng cách"
#define D_DNS_SERVER "Máy chủ DNS"
#define D_DO "Disolved Oxygen"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Năng lượng tiêu thụ hôm nay"
#define D_ENERGY_YESTERDAY "Năng lượng tiêu thụ hôm qua"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h
index 884b26b63..c96261c13 100644
--- a/tasmota/language/zh_CN.h
+++ b/tasmota/language/zh_CN.h
@@ -83,6 +83,9 @@
#define D_DEBUG "调试"
#define D_DEWPOINT "Dew point"
#define D_DISABLED "禁用"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "距离"
#define D_DNS_SERVER "DNS服务器"
#define D_DO "Disolved Oxygen"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "找到 ZBBridge EEPROM, 地址:"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "正在随机化 Zigbee 参数, 请通过 'ZbConfig' 检查"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "今日用电量"
#define D_ENERGY_YESTERDAY "昨日用电量"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h
index 66ffdd1aa..c0072dba0 100644
--- a/tasmota/language/zh_TW.h
+++ b/tasmota/language/zh_TW.h
@@ -83,6 +83,9 @@
#define D_DEBUG "偵錯"
#define D_DEWPOINT "Dew point"
#define D_DISABLED "已停用"
+#define D_MOVING_DISTANCE "Moving Distance"
+#define D_STATIC_DISTANCE "Static Distance"
+#define D_DETECT_DISTANCE "Detect Distance"
#define D_DISTANCE "距離"
#define D_DNS_SERVER "DNS伺服器"
#define D_DO "Disolved Oxygen"
@@ -511,6 +514,11 @@
#define D_ZIGBEE_EEPROM_FOUND_AT_ADDRESS "ZBBridge EEPROM found at address"
#define D_ZIGBEE_RANDOMIZING_ZBCONFIG "Randomizing Zigbee parameters, please check with 'ZbConfig'"
+// xdrv_89_dali.ino
+#define D_SENSOR_DALI_RX "Dali RX"
+#define D_SENSOR_DALI_TX "Dali TX"
+#define D_CONFIGURE_DALI "Config DALI"
+
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "今日用電量"
#define D_ENERGY_YESTERDAY "昨日用電量"
@@ -683,10 +691,12 @@
#define D_SENSOR_SBR_TX "SerBr Tx"
#define D_SENSOR_MBR_TX "ModBr Tx"
#define D_SENSOR_MBR_RX "ModBr Rx"
+#define D_SENSOR_MBR_TX_ENA "ModBr Tx Ena"
#define D_SENSOR_SR04_TRIG "SR04 Tri/TX"
#define D_SENSOR_SR04_ECHO "SR04 Ech/RX"
-#define D_SENSOR_NRG_MBS_TX "NrgModbus Tx"
-#define D_SENSOR_NRG_MBS_RX "NrgModbus Rx"
+#define D_SENSOR_NRG_MBS_TX "NrgMbs Tx"
+#define D_SENSOR_NRG_MBS_RX "NrgMbs Rx"
+#define D_SENSOR_NRG_MBS_TX_ENA "NrgMbs Tx Ena"
#define D_SENSOR_SDM72_TX "SDM72 Tx"
#define D_SENSOR_SDM72_RX "SDM72 Rx"
#define D_SENSOR_SDM120_TX "SDMx20 Tx"
@@ -697,6 +707,8 @@
#define D_SENSOR_SDM630_RX "SDM630 Rx"
#define D_SENSOR_WE517_TX "WE517 Tx"
#define D_SENSOR_WE517_RX "WE517 Rx"
+#define D_SENSOR_LD2410_TX "LD2410 Tx"
+#define D_SENSOR_LD2410_RX "LD2410 Rx"
#define D_GPIO_TM1621_CS "TM1621 CS"
#define D_GPIO_TM1621_WR "TM1621 WR"
#define D_GPIO_TM1621_RD "TM1621 RD"
@@ -766,6 +778,7 @@
#define D_SENSOR_ADE7880_IRQ "ADE7880 IRQ"
#define D_SENSOR_ADE7953_IRQ "ADE7953 IRQ"
#define D_SENSOR_ADE7953_RST "ADE7953 RST"
+#define D_SENSOR_ADE7953_CS "ADE7953 CS"
#define D_SENSOR_BUZZER "Buzzer"
#define D_SENSOR_DISP_RESET "Display Rst"
#define D_SENSOR_ZIGBEE_TXD "Zigbee Tx"
@@ -794,6 +807,8 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_SM2335_CLK "SM2335 Clk"
#define D_SENSOR_SM2335_DAT "SM2335 Dat"
+#define D_SENSOR_BP1658CJ_CLK "BP1658CJ Clk"
+#define D_SENSOR_BP1658CJ_DAT "BP1658CJ Dat"
#define D_SENSOR_BP5758D_CLK "BP5758D Clk"
#define D_SENSOR_BP5758D_DAT "BP5758D Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
@@ -892,6 +907,11 @@
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
#define D_GPIO_SHIFT595_OE "74x595 OE"
#define D_GPIO_SHIFT595_SER "74x595 SER"
+#define D_GPIO_DINGTIAN_CLK "Dingtian CLK"
+#define D_GPIO_DINGTIAN_SDI "Dingtian SDI"
+#define D_GPIO_DINGTIAN_Q7 "Dingtian Q7"
+#define D_GPIO_DINGTIAN_PL "Dingtian PL"
+#define D_GPIO_DINGTIAN_RCK "Dingtian RCK"
#define D_SENSOR_CM11_TX "CM110x TX"
#define D_SENSOR_CM11_RX "CM110x RX"
#define D_SENSOR_FLOWRATEMETER "Flowrate"
diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h
index 98bd812fa..b73e0ff80 100644
--- a/tasmota/my_user_config.h
+++ b/tasmota/my_user_config.h
@@ -405,6 +405,12 @@
#define WIFI_SOFT_AP_CHANNEL 1 // Soft Access Point Channel number between 1 and 13 as used by Wi-Fi Manager web GUI
#define USE_IMPROV // Add support for IMPROV serial protocol as used by esp-web-tools (+2k code)
+// -- IPv6 support -------------------------------
+// #define USE_IPV6 // Enable IPv6 support (if the underlying esp-idf is also configured to support it)
+ // Code size increase:
+ // ESP8266: tbd
+ // ESP32: tbd
+
// -- ESP-NOW -------------------------------------
//#define USE_TASMESH // Enable Tasmota Mesh using ESP-NOW (+11k code)
@@ -488,7 +494,7 @@
// -- mDNS ----------------------------------------
//#define USE_DISCOVERY // Enable mDNS for the following services (+8k code or +23.5k code with core 2_5_x, +0.3k mem)
#define WEBSERVER_ADVERTISE // Provide access to webserver by name .local/
- #define MQTT_HOST_DISCOVERY // Find MQTT host server (overrides MQTT_HOST if found)
+ // #define MQTT_HOST_DISCOVERY // Find MQTT host server (overrides MQTT_HOST if found) - disabled by default because it causes blocked repeated 3000ms pauses
// -- Time ----------------------------------------
#define USE_TIMERS // Add support for up to 16 timers (+2k2 code)
@@ -562,6 +568,7 @@
#define USE_SM16716 // Add support for SM16716 RGB LED controller (+0k7 code)
#define USE_SM2135 // Add support for SM2135 RGBCW led control as used in Action LSC (+0k6 code)
#define USE_SM2335 // Add support for SM2335 RGBCW led control as used in SwitchBot Color Bulb (+0k7 code)
+#define USE_BP1658CJ // Add support for BP1658CJ RGBCW led control as used in Orein OS0100411267 Bulb
#define USE_BP5758D // Add support for BP5758D RGBCW led control as used in some Tuya lightbulbs (+0k8 code)
#define USE_SONOFF_L1 // Add support for Sonoff L1 led control
#define USE_ELECTRIQ_MOODL // Add support for ElectriQ iQ-wifiMOODL RGBW LED controller (+0k3 code)
@@ -570,6 +577,9 @@
#define USE_DGR_LIGHT_SEQUENCE // Add support for device group light sequencing (requires USE_DEVICE_GROUPS) (+0k2 code)
//#define USE_LSC_MCSL // Add support for GPE Multi color smart light as sold by Action in the Netherlands (+1k1 code)
+// #define USE_LIGHT_ARTNET // Add support for DMX/ArtNet via UDP on port 6454 (+3.5k code)
+ #define USE_LIGHT_ARTNET_MCAST 239,255,25,54 // Multicast address used to listen: 239.255.25.24
+
// -- Counter input -------------------------------
#define USE_COUNTER // Enable inputs as counter (+0k8 code)
@@ -579,7 +589,7 @@
// -- One wire sensors ----------------------------
#define USE_DS18x20 // Add support for DS18x20 sensors with id sort, single scan and read retry (+2k6 code)
// #define W1_PARASITE_POWER // Optimize for parasite powered sensors
-// #define DS18x20_USE_ID_ALIAS
+// #define DS18x20_USE_ID_ALIAS // Add support aliasing for DS18x20 sensors. See comments in xsns_05 files (+0k5 code)
// -- I2C sensors ---------------------------------
#define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram)
@@ -687,6 +697,7 @@
// #define USE_HYT // [I2CDriver68] Enable HYTxxx temperature and humidity sensor (I2C address 0x28) (+0k5 code)
// #define USE_LUXV30B // [I2CDriver70] Enable RFRobot SEN0390 LuxV30b ambient light sensor (I2C address 0x4A) (+0k5 code)
// #define USE_QMC5883L // [I2CDriver71] Enable QMC5883L magnetic induction sensor (I2C address 0x0D) (+0k8 code)
+// #define USE_HMC5883L // [I2CDriver73] Enable HMC5883L magnetic induction sensor (I2C address 0x1E) (+1k3 code)
// #define QMC5883L_TEMP_SHIFT 23 // sensor temperature are not calibrated (only relativ measurement) and need an absolute ground value in °C (see datasheet)
// #define USE_INA3221 // [I2CDriver72] Enable INA3221 3-channel DC voltage and current sensor (I2C address 0x40-0x44) (+3.2k code)
// #define INA3221_ADDRESS1 // allow to change the 1st address to search for INA3221 to 0x41..0x43
@@ -698,7 +709,7 @@
// #define USE_BM8563 // [I2cDriver59] Enable BM8563 RTC - found in M5Stack - support both I2C buses on ESP32 (I2C address 0x51) (+2.5k code)
// #define USE_PCF85363 // [I2cDriver66] Enable PCF85363 RTC - found Shelly 3EM (I2C address 0x51) (+0k7 code)
-// #define USE_DISPLAY // Add I2C Display Support (+2k code)
+// #define USE_DISPLAY // Add I2C/TM1637/MAX7219 Display Support (+2k code)
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0
#define USE_DISPLAY_LCD // [DisplayModel 1] [I2cDriver3] Enable Lcd display (I2C addresses 0x27 and 0x3F) (+6k code)
#define USE_DISPLAY_SSD1306 // [DisplayModel 2] [I2cDriver4] Enable SSD1306 Oled 128x64 display (I2C addresses 0x3C and 0x3D) (+16k code)
@@ -712,7 +723,7 @@
#define MTX_ADDRESS7 0x00 // [DisplayAddress7] I2C address of seventh 8x8 matrix module
#define MTX_ADDRESS8 0x00 // [DisplayAddress8] I2C address of eigth 8x8 matrix module
#define USE_DISPLAY_SEVENSEG // [DisplayModel 11] [I2cDriver47] Enable sevenseg display (I2C 0x70-0x77) (<+11k code)
-// #define USE_DISPLAY_SEVENSEG_COMMON_ANODE // Enable support for common anode sevenseg displays
+// #define USE_DISPLAY_SEVENSEG_COMMON_ANODE // Enable support for common anode sevenseg displays
// Multiple sevenseg displays are logically arranged vertically with MTX_ADDRESS1 at y=0,
// MTX_ADDRESS2 at y=1, up to MTX_ADDRESS8 at y=7
// Command: DisplayText [yn]8888
@@ -720,14 +731,22 @@
// Each segment may be address Command: DisplayText [xn]m
// where n is 0..4 (4 digits and middle :) and m is decimal for bitmap of which segment to turn on.
// Reference: https://cdn-learn.adafruit.com/downloads/pdf/adafruit-led-backpack.pdf
- // #define SEVENSEG_ADDRESS1 0x70 // No longer used. Use MTX_ADDRESS1 - MTX_ADDRESS8 instead to specify I2C address of sevenseg displays
+ // #define SEVENSEG_ADDRESS1 0x70 // No longer used. Use MTX_ADDRESS1 - MTX_ADDRESS8 instead to specify I2C address of sevenseg displays
// #define USE_DISPLAY_SH1106 // [DisplayModel 7] [I2cDriver6] Enable SH1106 Oled 128x64 display (I2C addresses 0x3C and 0x3D)
+// #define USE_DT_VARS // Display variables that are exposed in JSON MQTT strings e.g. in TelePeriod messages.
+// #define MAX_DT_VARS 16 // Defaults to 7
+// #define USE_GRAPH // Enable line charts with displays
+// #define NUM_GRAPHS 4 // Max 16
+
#endif // USE_I2C
+// #define USE_DISPLAY // Add I2C/TM1637/MAX7219 Display Support (+2k code)
+// #define USE_DISPLAY_TM1637 // [DisplayModel 15] Enable TM1637 Module
+// #define USE_DISPLAY_MAX7219 // [DisplayModel 15] Enable MAX7219 Module
// -- Universal Display Driver ---------------------------------
// #define USE_UNIVERSAL_DISPLAY // New universal display driver for both I2C and SPI
- #define MAX_TOUCH_BUTTONS 16 // Virtual touch buttons
+ #define MAX_TOUCH_BUTTONS 16 // Virtual touch buttons
// -- SPI sensors ---------------------------------
//#define USE_SPI // Hardware SPI using GPIO12(MISO), GPIO13(MOSI) and GPIO14(CLK) in addition to two user selectable GPIOs(CS and DC)
@@ -751,9 +770,6 @@
#endif // USE_SPI
-//#define USE_DISPLAY // Add Display support
-// #define USE_DISPLAY_TM1637 // [DisplayModel 15] Enable TM1637 module
-
// -- Serial sensors ------------------------------
//#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)
@@ -762,13 +778,15 @@
#define CO2_HIGH 1200 // Above this CO2 value show red light (needs PWM or WS2812 RG(B) led and enable with SetOption18 1)
//#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 PMS_MODEL_PMS5003T // Enable support for PMSx003T models that report temperature and humidity (needs the USE_PMS5003 above)
//#define USE_NOVA_SDS // Add support for SDS011 and SDS021 particle concentration sensor (+1k5 code)
#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_SERIAL_BRIDGE // Add support for software Serial Bridge (+2k code)
+// #define SERIAL_BRIDGE_BUFFER_SIZE 256 // Serial Bridge receive buffer size (Default ESP8266 = 256, ESP32 = 800)
//#define USE_MODBUS_BRIDGE // Add support for software Modbus Bridge (+4.5k code)
//#define USE_MODBUS_BRIDGE_TCP // Add support for software Modbus TCP Bridge (also enable Modbus TCP Bridge) (+2k code)
//#define USE_TCP_BRIDGE // Add support for Serial to TCP bridge (+1.3k code)
@@ -776,9 +794,8 @@
#define MP3_VOLUME 30 // Set the startup volume on init, the range can be 0..100(max)
// #define USE_DY_SV17F // Use of DY-SV17F MP3 Player commands: play, stop, track and volume
//#define USE_AZ7798 // Add support for AZ-Instrument 7798 CO2 datalogger (+1k6 code)
-//#define USE_PN532_HSU // Add support for PN532 using HSU (Serial) interface (+1k8 code, 140 bytes mem)
-// #define USE_PN532_DATA_FUNCTION // Add sensor40 command support for erase, setting data block content (+1k7 code, 388 bytes mem)
-// #define USE_PN532_DATA_RAW // Allow DATA block to be used by non-alpha-numberic data (+ 80 bytes code, 48 bytes ram)
+//#define USE_PN532_HSU // Add support for PN532 using HSU (Serial) interface (+1k7 code, 156 bytes mem)
+// #define USE_PN532_DATA_FUNCTION // Add sensor40 command support for erase, setting data block content (+3k code, 32 bytes mem)
//#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 (+3k1 code, +132 bytes RAM)
@@ -800,6 +817,7 @@
//#define USE_VINDRIKTNING // Add support for IKEA VINDRIKTNING particle concentration sensor (+0k6 code)
// #define VINDRIKTNING_SHOW_PM1 // Display undocumented/supposed PM1.0 values
// #define VINDRIKTNING_SHOW_PM10 // Display undocumented/supposed PM10 values
+//#define USE_LD2410 // Add support for HLK-LD2410 24GHz smart wave motion sensor (+2k8 code)
// -- Power monitoring sensors --------------------
#define USE_ENERGY_SENSOR // Add support for Energy Monitors (+14k code)
@@ -1034,6 +1052,11 @@
#define USE_ESP32_SENSORS // Add support for ESP32 temperature and optional hall effect sensor
+// #define USE_DALI // Add support for DALI
+ #define DALI_IN_INVERT 0 // DALI RX inverted ?
+ #define DALI_OUT_INVERT 0 // DALI TX inverted ?
+ #define DALI_TIMER 0 // ESP32 hardware timer number 0-3 !!! timer 3 used in xdrv_10_scripter.ino !!!
+
//#define USE_SONOFF_SPM // Add support for ESP32 based Sonoff Smart Stackable Power Meter (+11k code)
//#define USE_DISPLAY_TM1621_SONOFF // Add support for TM1621 dsiplay driver used by Sonoff POWR3xxD and THR3xxD
@@ -1070,6 +1093,7 @@
#define USE_BERRY_PSRAM // Allocate Berry memory in PSRAM if PSRAM is connected - this might be slightly slower but leaves main memory intact
#define USE_BERRY_IRAM // Allocate some data structures in IRAM (which is ususally unused) when possible and if no PSRAM is available
// #define USE_BERRY_DEBUG // Compile Berry bytecode with line number information, makes exceptions easier to debug. Adds +8% of memory consumption for compiled code
+ // #define UBE_BERRY_DEBUG_GC // Print low-level GC metrics
// #define USE_BERRY_INT64 // Add 64 bits integer support (+1.7KB Flash)
#define USE_WEBCLIENT // Enable `webclient` to make HTTP/HTTPS requests. Can be disabled for security reasons.
// #define USE_WEBCLIENT_HTTPS // Enable HTTPS outgoing requests based on BearSSL (much ligher then mbedTLS, 42KB vs 150KB) in insecure mode (no verification of server's certificate)
@@ -1078,6 +1102,9 @@
#define USE_BERRY_WEBCLIENT_TIMEOUT 2000 // Default timeout in milliseconds
#define USE_BERRY_TCPSERVER // Enable TCP socket server (+0.6k)
// #define USE_BERRY_ULP // Enable ULP (Ultra Low Power) support (+4.9k)
+ // Berry crypto extensions below:
+ #define USE_BERRY_CRYPTO_AES_GCM // enable AES GCM 256 bits
+ // #define USE_BERRY_CRYPTO_EC_C25519 // enable Elliptic Curve C C25519
#define USE_CSE7761 // Add support for CSE7761 Energy monitor as used in Sonoff Dual R3
// -- LVGL Graphics Library ---------------------------------
@@ -1176,7 +1203,7 @@
* Mutual exclude options
\*********************************************************************************************/
-#if defined(USE_DISCOVERY) && (defined(USE_MQTT_AWS_IOT) || defined(USE_MQTT_AWS_IOT_LIGHT))
+#if defined(ESP8266) && defined(USE_DISCOVERY) && (defined(USE_MQTT_AWS_IOT) || defined(USE_MQTT_AWS_IOT_LIGHT))
#error "Select either USE_DISCOVERY or USE_MQTT_AWS_IOT, mDNS takes too much code space and is not needed for AWS IoT"
#endif
@@ -1214,7 +1241,7 @@
#endif
#endif
-#if defined(USE_MQTT_TLS) || defined(USE_TELEGRAM) || defined(USE_WEBCLIENT_HTTPS) || defined(USE_ALEXA_AVS)
+#if defined(USE_MQTT_TLS) || defined(USE_TELEGRAM) || defined(USE_WEBCLIENT_HTTPS)
#define USE_TLS // flag indicates we need to include TLS code
#endif
diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino
index 4a820a229..479dce33a 100644
--- a/tasmota/tasmota.ino
+++ b/tasmota/tasmota.ino
@@ -32,6 +32,13 @@
#include "include/i18n.h" // Language support configured by my_user_config.h
#include "include/tasmota_template.h" // Hardware configuration
+// ------------------------------------------------------------------------------------------
+// If IPv6 is not support by the underlying esp-idf, disable it
+// ------------------------------------------------------------------------------------------
+#if !LWIP_IPV6
+ #undef USE_IPV6
+#endif
+
// Libraries
#include // Ota
#include // Ota
@@ -118,6 +125,8 @@ struct WIFI {
bool wifi_test_AP_TIMEOUT = false;
bool wifi_Test_Restart = false;
bool wifi_Test_Save_SSID2 = false;
+ // IPv6 support, not guarded with #if LWIP_IPV6 to avoid bloating code with ifdefs
+ bool ipv6_local_link_called = false; // did we already enable IPv6 Local-Link address, needs to be redone at each reconnect
} Wifi;
typedef struct {
@@ -127,7 +136,7 @@ typedef struct {
} TRtcReboot;
TRtcReboot RtcReboot;
#ifdef ESP32
-RTC_NOINIT_ATTR TRtcReboot RtcDataReboot;
+static RTC_NOINIT_ATTR TRtcReboot RtcDataReboot;
#endif // ESP32
typedef struct {
@@ -154,10 +163,11 @@ typedef struct {
} TRtcSettings;
TRtcSettings RtcSettings;
#ifdef ESP32
-RTC_NOINIT_ATTR TRtcSettings RtcDataSettings;
+static RTC_NOINIT_ATTR TRtcSettings RtcDataSettings;
#endif // ESP32
struct TIME_T {
+ uint32_t nanos;
uint8_t second;
uint8_t minute;
uint8_t hour;
@@ -252,6 +262,7 @@ struct TasmotaGlobal_t {
power_t blink_power; // Blink power state
power_t blink_powersave; // Blink start power save state
power_t blink_mask; // Blink relay active mask
+ power_t power_on_delay_state;
int serial_in_byte_counter; // Index in receive buffer
@@ -312,7 +323,6 @@ struct TasmotaGlobal_t {
uint8_t latching_relay_pulse; // Latching relay pulse timer
uint8_t active_device; // Active device in ExecuteCommandPower
uint8_t sleep; // Current copy of Settings->sleep
- uint8_t skip_sleep; // Abandon sleep and allow loop
uint8_t leds_present; // Max number of LED supported
uint8_t led_inverted; // LED inverted flag (1 = (0 = On, 1 = Off))
uint8_t led_power; // LED power state
@@ -322,6 +332,7 @@ struct TasmotaGlobal_t {
uint8_t light_driver; // Light module configured
uint8_t light_type; // Light types
uint8_t serial_in_byte; // Received byte
+ uint8_t serial_skip; // Skip number of received messages
uint8_t devices_present; // Max number of devices supported
uint8_t masterlog_level; // Master log level used to override set log level
uint8_t seriallog_level; // Current copy of Settings->seriallog_level
@@ -330,8 +341,10 @@ struct TasmotaGlobal_t {
uint8_t module_type; // Current copy of Settings->module or user template type
uint8_t emulated_module_type; // Emulated module type as requested by ESP32
uint8_t last_source; // Last command source
+ uint8_t last_command_source; // Last command source
uint8_t shutters_present; // Number of actual define shutters
uint8_t discovery_counter; // Delayed discovery counter
+ uint8_t power_on_delay; // Delay relay power on to reduce power surge (SetOption47)
#ifdef USE_PWM_DIMMER
uint8_t restore_powered_off_led_counter; // Seconds before powered-off LED (LEDLink) is restored
uint8_t pwm_dimmer_led_bri; // Adjusted brightness LED level
@@ -488,7 +501,7 @@ void setup(void) {
#ifdef ESP32
AddLog(LOG_LEVEL_INFO, PSTR("HDW: %s %s"), GetDeviceHardware().c_str(),
FoundPSRAM() ? (CanUsePSRAM() ? "(PSRAM)" : "(PSRAM disabled)") : "" );
- AddLog(LOG_LEVEL_DEBUG, PSTR("HDW: FoundPSRAM=%i CanUsePSRAM=%i"), FoundPSRAM(), CanUsePSRAM());
+ // AddLog(LOG_LEVEL_DEBUG, PSTR("HDW: FoundPSRAM=%i CanUsePSRAM=%i"), FoundPSRAM(), CanUsePSRAM());
#if !defined(HAS_PSRAM_FIX)
if (FoundPSRAM() && !CanUsePSRAM()) {
AddLog(LOG_LEVEL_INFO, PSTR("HDW: PSRAM is disabled, requires specific compilation on this hardware (see doc)"));
@@ -515,7 +528,7 @@ void setup(void) {
Settings->baudrate = APP_BAUDRATE / 300;
Settings->serial_config = TS_SERIAL_8N1;
}
- SetSerialBaudrate(Settings->baudrate * 300); // Reset serial interface if current baudrate is different from requested baudrate
+ SetSerialInitBegin(); // Reset serial interface if current baudrate and/or config is different from requested settings
if (1 == RtcReboot.fast_reboot_count) { // Allow setting override only when all is well
UpdateQuickPowerCycle(true);
@@ -546,7 +559,7 @@ void setup(void) {
#endif
#endif // USE_EMULATION
-// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t*)&TasmotaGlobal, sizeof(TasmotaGlobal));
+// AddLog(LOG_LEVEL_INFO, PSTR("DBG: TasmotaGlobal size %d, data %100_H"), sizeof(TasmotaGlobal), (uint8_t*)&TasmotaGlobal);
if (Settings->param[P_BOOT_LOOP_OFFSET]) { // SetOption36
// Disable functionality as possible cause of fast restart within BOOT_LOOP_TIME seconds (Exception, WDT or restarts)
@@ -558,6 +571,7 @@ void setup(void) {
bitWrite(Settings->rule_enabled, i, 0); // Disable rules causing boot loop
}
}
+ Settings->flag4.network_wifi = 1; // Enable wifi if disabled
}
if (RtcReboot.fast_reboot_count > Settings->param[P_BOOT_LOOP_OFFSET] +2) { // Restarted 4 times
Settings->rule_enabled = 0; // Disable all rules
@@ -615,8 +629,7 @@ void setup(void) {
}
#endif // USE_BERRY
- XdrvCall(FUNC_PRE_INIT);
- XsnsCall(FUNC_PRE_INIT);
+ XdrvXsnsCall(FUNC_PRE_INIT);
TasmotaGlobal.init_state = INIT_GPIOS;
@@ -634,8 +647,7 @@ void setup(void) {
ArduinoOTAInit();
#endif // USE_ARDUINO_OTA
- XdrvCall(FUNC_INIT);
- XsnsCall(FUNC_INIT);
+ XdrvXsnsCall(FUNC_INIT);
#ifdef USE_SCRIPT
if (bitRead(Settings->rule_enabled, 0)) Run_Scripter(">BS",3,0);
#endif
@@ -679,7 +691,8 @@ void BacklogLoop(void) {
void SleepDelay(uint32_t mseconds) {
if (!TasmotaGlobal.backlog_nodelay && mseconds) {
uint32_t wait = millis() + mseconds;
- while (!TimeReached(wait) && !Serial.available() && !TasmotaGlobal.skip_sleep) { // We need to service serial buffer ASAP as otherwise we get uart buffer overrun
+ while (!TimeReached(wait) && !Serial.available()) { // We need to service serial buffer ASAP as otherwise we get uart buffer overrun
+ XdrvXsnsCall(FUNC_SLEEP_LOOP); // Main purpose is reacting ASAP on serial data availability or interrupt handling (ADE7880)
delay(1);
}
} else {
@@ -688,8 +701,7 @@ void SleepDelay(uint32_t mseconds) {
}
void Scheduler(void) {
- XdrvCall(FUNC_LOOP);
- XsnsCall(FUNC_LOOP);
+ XdrvXsnsCall(FUNC_LOOP);
// check LEAmDNS.h
// MDNS.update() needs to be called in main loop
@@ -717,32 +729,28 @@ void Scheduler(void) {
#ifdef ROTARY_V1
RotaryHandler();
#endif // ROTARY_V1
- XdrvCall(FUNC_EVERY_50_MSECOND);
- XsnsCall(FUNC_EVERY_50_MSECOND);
+ XdrvXsnsCall(FUNC_EVERY_50_MSECOND);
}
static uint32_t state_100msecond = 0; // State 100msecond timer
if (TimeReached(state_100msecond)) {
SetNextTimeInterval(state_100msecond, 100);
Every100mSeconds();
- XdrvCall(FUNC_EVERY_100_MSECOND);
- XsnsCall(FUNC_EVERY_100_MSECOND);
+ XdrvXsnsCall(FUNC_EVERY_100_MSECOND);
}
static uint32_t state_250msecond = 0; // State 250msecond timer
if (TimeReached(state_250msecond)) {
SetNextTimeInterval(state_250msecond, 250);
Every250mSeconds();
- XdrvCall(FUNC_EVERY_250_MSECOND);
- XsnsCall(FUNC_EVERY_250_MSECOND);
+ XdrvXsnsCall(FUNC_EVERY_250_MSECOND);
}
static uint32_t state_second = 0; // State second timer
if (TimeReached(state_second)) {
SetNextTimeInterval(state_second, 1000);
PerformEverySecond();
- XdrvCall(FUNC_EVERY_SECOND);
- XsnsCall(FUNC_EVERY_SECOND);
+ XdrvXsnsCall(FUNC_EVERY_SECOND);
}
if (!TasmotaGlobal.serial_local) { SerialInput(); }
diff --git a/tasmota/tasmota_support/settings.ino b/tasmota/tasmota_support/settings.ino
index 5d0e8c6d7..4837cbdaa 100644
--- a/tasmota/tasmota_support/settings.ino
+++ b/tasmota/tasmota_support/settings.ino
@@ -45,7 +45,7 @@ void RtcSettingsSave(void) {
if (RTC_MEM_VALID != RtcSettings.valid) {
memset(&RtcSettings, 0, sizeof(RtcSettings));
RtcSettings.valid = RTC_MEM_VALID;
-// RtcSettings.ex_energy_kWhtoday = Settings->ex_energy_kWhtoday;
+// RtcSettings.ex_energy_kWhtoday = Settings->energy_power_calibration2; // = ex_energy_kWhtoday
// RtcSettings.ex_energy_kWhtotal = Settings->ex_energy_kWhtotal;
for (uint32_t i = 0; i < 3; i++) {
RtcSettings.energy_kWhtoday_ph[i] = Settings->energy_kWhtoday_ph[i];
@@ -367,8 +367,7 @@ void SettingsSaveAll(void) {
} else {
Settings->power = 0;
}
- XsnsCall(FUNC_SAVE_BEFORE_RESTART);
- XdrvCall(FUNC_SAVE_BEFORE_RESTART);
+ XsnsXdrvCall(FUNC_SAVE_BEFORE_RESTART);
SettingsSave(0);
}
@@ -603,8 +602,7 @@ void SettingsSave(uint8_t rotate) {
* stop_flash_rotate 1 = Allow only eeprom flash slot use (SetOption12 1)
*/
#ifndef FIRMWARE_MINIMAL
- XsnsCall(FUNC_SAVE_SETTINGS);
- XdrvCall(FUNC_SAVE_SETTINGS);
+ XsnsXdrvCall(FUNC_SAVE_SETTINGS);
UpdateBackwardCompatibility();
if ((GetSettingsCrc32() != settings_crc32) || rotate) {
if (1 == rotate) { // Use eeprom flash slot only and disable flash rotate from now on (upgrade)
@@ -914,6 +912,7 @@ void SettingsDefaultSet2(void) {
// Serial
Settings->serial_config = TS_SERIAL_8N1;
Settings->baudrate = APP_BAUDRATE / 300;
+ Settings->sserial_config = TS_SERIAL_8N1;
Settings->sbaudrate = SOFT_BAUDRATE / 300;
Settings->serial_delimiter = 0xff;
Settings->seriallog_level = SERIAL_LOG_LEVEL;
@@ -1046,6 +1045,9 @@ void SettingsDefaultSet2(void) {
Settings->energy_power_calibration = HLW_PREF_PULSE;
Settings->energy_voltage_calibration = HLW_UREF_PULSE;
Settings->energy_current_calibration = HLW_IREF_PULSE;
+ Settings->energy_power_calibration2 = HLW_PREF_PULSE;
+ Settings->energy_voltage_calibration2 = HLW_UREF_PULSE;
+ Settings->energy_current_calibration2 = HLW_IREF_PULSE;
// Settings->energy_kWhtoday_ph[0] = 0;
// Settings->energy_kWhtoday_ph[1] = 0;
// Settings->energy_kWhtoday_ph[2] = 0;
@@ -1468,7 +1470,7 @@ void SettingsDelta(void) {
}
if (Settings->version < 0x09020006) {
for (uint32_t i = 0; i < MAX_SWITCHES_SET; i++) {
- Settings->switchmode[i] = (i < 8) ? Settings->ex_switchmode[i] : SWITCH_MODE;
+ Settings->switchmode[i] = SWITCH_MODE;
}
for (uint32_t i = 0; i < MAX_INTERLOCKS_SET; i++) {
Settings->interlock[i] = (i < 4) ? Settings->ds3502_state[i] : 0;
@@ -1532,8 +1534,8 @@ void SettingsDelta(void) {
memset(&Settings->energy_kWhtoday_ph, 0, 36);
memset(&RtcSettings.energy_kWhtoday_ph, 0, 24);
Settings->energy_kWhtotal_ph[0] = Settings->ex_energy_kWhtotal;
- Settings->energy_kWhtoday_ph[0] = Settings->ex_energy_kWhtoday;
- Settings->energy_kWhyesterday_ph[0] = Settings->ex_energy_kWhyesterday;
+ Settings->energy_kWhtoday_ph[0] = Settings->energy_power_calibration2; // = ex_energy_kWhtoday
+ Settings->energy_kWhyesterday_ph[0] = Settings->energy_voltage_calibration2; // = ex_energy_kWhyesterday
RtcSettings.energy_kWhtoday_ph[0] = RtcSettings.ex_energy_kWhtoday;
RtcSettings.energy_kWhtotal_ph[0] = RtcSettings.ex_energy_kWhtotal;
}
@@ -1598,6 +1600,17 @@ void SettingsDelta(void) {
Settings->webcam_clk = 20;
}
#endif // ESP32
+ if (Settings->version < 0x0C020002) { // 12.2.0.2
+ Settings->energy_kWhdoy = Settings->energy_current_calibration2 & 0xFFFF;
+ Settings->energy_min_power = (Settings->energy_current_calibration2 >> 16) & 0xFFFF;
+ Settings->energy_power_calibration2 = Settings->energy_power_calibration;
+ Settings->energy_voltage_calibration2 = Settings->energy_voltage_calibration;
+ Settings->energy_current_calibration2 = Settings->energy_current_calibration;
+ }
+ if (Settings->version < 0x0C020005) { // 12.2.0.5
+ Settings->modbus_sbaudrate = Settings->ex_modbus_sbaudrate;
+ Settings->param[P_SERIAL_SKIP] = 0;
+ }
Settings->version = VERSION;
SettingsSave(1);
diff --git a/tasmota/tasmota_support/support.ino b/tasmota/tasmota_support/support.ino
index 3dbebd6e0..bb92157b6 100755
--- a/tasmota/tasmota_support/support.ino
+++ b/tasmota/tasmota_support/support.ino
@@ -21,10 +21,6 @@ extern "C" {
extern struct rst_info resetInfo;
}
-#ifdef USE_KNX
-bool knx_started = false;
-#endif // USE_KNX
-
/*********************************************************************************************\
* Watchdog extension (https://github.com/esp8266/Arduino/issues/1532)
\*********************************************************************************************/
@@ -106,6 +102,11 @@ uint32_t ResetReason(void) {
return ESP_ResetInfoReason();
}
+bool ResetReasonPowerOn(void) {
+ uint32_t reset_reason = ESP_ResetInfoReason();
+ return ((reset_reason == REASON_DEFAULT_RST) || (reset_reason == REASON_EXT_SYS_RST));
+}
+
String GetResetReason(void) {
if (OsWatchBlockedLoop()) {
char buff[32];
@@ -382,7 +383,7 @@ char* Unescape(char* buffer, uint32_t* size)
int32_t end_size = *size;
uint8_t che = 0;
-// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t*)buffer, *size);
+// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: UnescapeIn %*_H"), *size, (uint8_t*)buffer);
while (start_size > 0) {
uint8_t ch = *read++;
@@ -426,7 +427,7 @@ char* Unescape(char* buffer, uint32_t* size)
}
*size = end_size;
*write++ = 0; // add the end string pointer reference
-// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t*)buffer, *size);
+// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: UnescapeOut %*_H"), *size, (uint8_t*)buffer);
return buffer;
}
@@ -1478,7 +1479,7 @@ void GetInternalTemplate(void* ptr, uint32_t module, uint32_t option) {
memcpy_P(&template8, &kModules8285[module_template - TMP_WEMOS], sizeof(template8));
}
-// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t *)&template8, sizeof(mytmplt8285));
+// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: GetInternalTemplate %*_H"), sizeof(mytmplt8285), (uint8_t *)&template8);
// template16 = GPIO 0,1,2,3,4,5,9,10,12,13,14,15,16,Adc,Flg
uint16_t template16[(sizeof(mytmplt) / 2)] = { GPIO_NONE };
@@ -1499,8 +1500,7 @@ void GetInternalTemplate(void* ptr, uint32_t module, uint32_t option) {
}
memcpy(ptr, &template16[index], size);
-// AddLog(LOG_LEVEL_DEBUG, PSTR("FNC: GetInternalTemplate option %d"), option);
-// AddLogBufferSize(LOG_LEVEL_DEBUG, (uint8_t *)ptr, size / 2, 2);
+// AddLog(LOG_LEVEL_DEBUG, PSTR("FNC: GetInternalTemplate option %d, %*_V"), option, size / 2, (uint8_t *)ptr);
}
#endif // ESP8266
@@ -1527,7 +1527,7 @@ void TemplateGpios(myio *gp)
}
// 11 85 00 85 85 00 00 00 15 38 85 00 00 81
-// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t *)&src, sizeof(mycfgio));
+// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: TemplateGpiosIn %*_H"), sizeof(mycfgio), (uint8_t *)&src);
// Expand template to physical GPIO array, j=phy_GPIO, i=template_GPIO
uint32_t j = 0;
@@ -1549,7 +1549,7 @@ void TemplateGpios(myio *gp)
}
// 11 85 00 85 85 00 00 00 00 00 00 00 15 38 85 00 00 81
-// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t *)gp, sizeof(myio));
+// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: TemplateGpiosOut %*_H"), sizeof(myio), (uint8_t *)gp);
}
gpio_flag ModuleFlag(void)
@@ -1756,16 +1756,14 @@ bool JsonTemplate(char* dataBuf)
}
}
-// AddLog(LOG_LEVEL_DEBUG, PSTR("TPL: Converted"));
-// AddLogBufferSize(LOG_LEVEL_DEBUG, (uint8_t*)&Settings->user_template, sizeof(Settings->user_template) / 2, 2);
+// AddLog(LOG_LEVEL_DEBUG, PSTR("TPL: Converted %*_V"), sizeof(Settings->user_template) / 2, (uint8_t*)&Settings->user_template);
return true;
}
void TemplateJson(void)
{
-// AddLog(LOG_LEVEL_DEBUG, PSTR("TPL: Show"));
-// AddLogBufferSize(LOG_LEVEL_DEBUG, (uint8_t*)&Settings->user_template, sizeof(Settings->user_template) / 2, 2);
+// AddLog(LOG_LEVEL_DEBUG, PSTR("TPL: Show %*_V"), sizeof(Settings->user_template) / 2, (uint8_t*)&Settings->user_template);
Response_P(PSTR("{\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), SettingsText(SET_TEMPLATE_NAME));
for (uint32_t i = 0; i < nitems(Settings->user_template.gp.io); i++) {
@@ -1977,6 +1975,13 @@ void SetSerialBegin(void) {
#endif // ESP32
}
+void SetSerialInitBegin(void) {
+ TasmotaGlobal.baudrate = Settings->baudrate * 300;
+ if ((GetSerialBaudrate() != TasmotaGlobal.baudrate) || (TS_SERIAL_8N1 != Settings->serial_config)) {
+ SetSerialBegin();
+ }
+}
+
void SetSerialConfig(uint32_t serial_config) {
if (serial_config > TS_SERIAL_8O2) {
serial_config = TS_SERIAL_8N1;
@@ -2745,15 +2750,13 @@ void AddLog(uint32_t loglevel, PGM_P formatP, ...) {
}
}
-void AddLogBuffer(uint32_t loglevel, uint8_t *buffer, uint32_t count)
-{
+void AddLogBuffer(uint32_t loglevel, uint8_t *buffer, uint32_t count) {
char hex_char[(count * 3) + 2];
AddLog(loglevel, PSTR("DMP: %s"), ToHex_P(buffer, count, hex_char, sizeof(hex_char), ' '));
}
-void AddLogSerial(uint32_t loglevel)
-{
- AddLogBuffer(loglevel, (uint8_t*)TasmotaGlobal.serial_in_buffer, TasmotaGlobal.serial_in_byte_counter);
+void AddLogSerial() {
+ AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t*)TasmotaGlobal.serial_in_buffer, TasmotaGlobal.serial_in_byte_counter);
}
void AddLogMissed(const char *sensor, uint32_t misses)
@@ -2761,21 +2764,6 @@ void AddLogMissed(const char *sensor, uint32_t misses)
AddLog(LOG_LEVEL_DEBUG, PSTR("SNS: %s missed %d"), sensor, SENSOR_MAX_MISS - misses);
}
-void AddLogBufferSize(uint32_t loglevel, uint8_t *buffer, uint32_t count, uint32_t size) {
- char log_data[4 + (count * size * 3)];
-
- snprintf_P(log_data, sizeof(log_data), PSTR("DMP:"));
- for (uint32_t i = 0; i < count; i++) {
- if (1 == size) { // uint8_t
- snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X"), log_data, *(buffer));
- } else { // uint16_t
- snprintf_P(log_data, sizeof(log_data), PSTR("%s %02X%02X"), log_data, *(buffer +1), *(buffer));
- }
- buffer += size;
- }
- AddLogData(loglevel, log_data);
-}
-
void AddLogSpi(bool hardware, uint32_t clk, uint32_t mosi, uint32_t miso) {
// Needs optimization
uint32_t enabled = (hardware) ? TasmotaGlobal.spi_enabled : TasmotaGlobal.soft_spi_enabled;
diff --git a/tasmota/tasmota_support/support_button_v3.ino b/tasmota/tasmota_support/support_button_v3.ino
index bdfad5330..b12ef5714 100644
--- a/tasmota/tasmota_support/support_button_v3.ino
+++ b/tasmota/tasmota_support/support_button_v3.ino
@@ -473,6 +473,11 @@ void ButtonHandler(void) {
valid_relay = (Button.press_counter[button_index] <= TasmotaGlobal.devices_present);
}
#endif // ESP8266
+#ifdef USE_SHELLY_PRO
+ if (TasmotaGlobal.gpio_optiona.shelly_pro) {
+ valid_relay = (Button.press_counter[button_index] <= TasmotaGlobal.devices_present);
+ }
+#endif // USE_SHELLY_PRO
if ((Button.press_counter[button_index] > 1) && valid_relay && (Button.press_counter[button_index] <= MAX_RELAY_BUTTON1)) {
ExecuteCommandPower(button_index + Button.press_counter[button_index], POWER_TOGGLE, SRC_BUTTON); // Execute Toggle command internally
// AddLog(LOG_LEVEL_DEBUG, PSTR("BTN: Relay%d found on GPIO%d"), Button.press_counter[button_index], Pin(GPIO_REL1, Button.press_counter[button_index]-1));
diff --git a/tasmota/tasmota_support/support_command.ino b/tasmota/tasmota_support/support_command.ino
index 6086572db..07fba6fe4 100644
--- a/tasmota/tasmota_support/support_command.ino
+++ b/tasmota/tasmota_support/support_command.ino
@@ -329,6 +329,7 @@ void ExecuteCommand(const char *cmnd, uint32_t source)
// cmnd: "var1=1" = stopic "var1" and svalue "=1"
SHOW_FREE_MEM(PSTR("ExecuteCommand"));
ShowSource(source);
+ TasmotaGlobal.last_command_source = source;
const char *pos = cmnd;
while (*pos && isspace(*pos)) {
@@ -411,7 +412,8 @@ void CommandHandler(char* topicBuf, char* dataBuf, uint32_t data_len)
bool binary_data = (index > 199); // Suppose binary data on topic index > 199
if (!binary_data) {
- if (strstr_P(type, PSTR("SERIALSEND")) == nullptr) { // Do not skip leading spaces on (s)serialsend
+ bool keep_spaces = ((strstr_P(type, PSTR("SERIALSEND")) != nullptr) && (index > 9)); // Do not skip leading spaces on (s)serialsend10 and up
+ if (!keep_spaces) {
while (*dataBuf && isspace(*dataBuf)) {
dataBuf++; // Skip leading spaces in data
data_len--;
@@ -800,14 +802,25 @@ void CmndStatus(void)
}
if ((0 == payload) || (5 == payload)) {
+#ifdef USE_IPV6
+ if (5 == payload) { WifiDumpAddressesIPv6(); }
+#endif // USE_IPV6
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS5_NETWORK "\":{\"" D_CMND_HOSTNAME "\":\"%s\",\""
D_CMND_IPADDRESS "\":\"%_I\",\"" D_JSON_GATEWAY "\":\"%_I\",\"" D_JSON_SUBNETMASK "\":\"%_I\",\""
D_JSON_DNSSERVER "1\":\"%_I\",\"" D_JSON_DNSSERVER "2\":\"%_I\",\""
- D_JSON_MAC "\":\"%s\""),
+ D_JSON_MAC "\":\"%s\""
+#ifdef USE_IPV6
+ ",\"" D_JSON_IP6_GLOBAL "\":\"%s\",\"" D_JSON_IP6_LOCAL "\":\"%s\""
+#endif // USE_IPV6
+ ),
TasmotaGlobal.hostname,
(uint32_t)WiFi.localIP(), Settings->ipv4_address[1], Settings->ipv4_address[2],
Settings->ipv4_address[3], Settings->ipv4_address[4],
- WiFi.macAddress().c_str());
+ WiFi.macAddress().c_str()
+#ifdef USE_IPV6
+ ,WifiGetIPv6().c_str(), WifiGetIPv6LinkLocal().c_str()
+#endif // USE_IPV6
+ );
#ifdef USE_TASMESH
ResponseAppend_P(PSTR(",\"SoftAPMac\":\"%s\""), WiFi.softAPmacAddress().c_str());
#endif // USE_TASMESH
@@ -815,11 +828,20 @@ void CmndStatus(void)
ResponseAppend_P(PSTR(",\"Ethernet\":{\"" D_CMND_HOSTNAME "\":\"%s\",\""
D_CMND_IPADDRESS "\":\"%_I\",\"" D_JSON_GATEWAY "\":\"%_I\",\"" D_JSON_SUBNETMASK "\":\"%_I\",\""
D_JSON_DNSSERVER "1\":\"%_I\",\"" D_JSON_DNSSERVER "2\":\"%_I\",\""
- D_JSON_MAC "\":\"%s\"}"),
+ D_JSON_MAC "\":\"%s\""
+
+#ifdef USE_IPV6
+ ",\"" D_JSON_IP6_GLOBAL "\":\"%s\",\"" D_JSON_IP6_LOCAL "\":\"%s\""
+#endif // USE_IPV6
+ "}"),
EthernetHostname(),
(uint32_t)EthernetLocalIP(), Settings->eth_ipv4_address[1], Settings->eth_ipv4_address[2],
Settings->eth_ipv4_address[3], Settings->eth_ipv4_address[4],
- EthernetMacAddress().c_str());
+ EthernetMacAddress().c_str()
+#ifdef USE_IPV6
+ ,EthernetGetIPv6().c_str(), EthernetGetIPv6LinkLocal().c_str()
+#endif // USE_IPV6
+ );
#endif // USE_ETHERNET
ResponseAppend_P(PSTR(",\"" D_CMND_WEBSERVER "\":%d,\"HTTP_API\":%d,\"" D_CMND_WIFICONFIG "\":%d,\"" D_CMND_WIFIPOWER "\":%s}}"),
Settings->webserver, Settings->flag5.disable_referer_chk, Settings->sta_config, WifiGetOutputPower().c_str());
@@ -1870,8 +1892,8 @@ void CmndSerialBuffer(void) {
#endif
}
-void CmndSerialSend(void)
-{
+void CmndSerialSend(void) {
+ if (XdrvMailbox.index > 9) { XdrvMailbox.index -= 10; }
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 6)) {
SetSeriallog(LOG_LEVEL_NONE);
Settings->flag.mqtt_serial = 1; // CMND_SERIALSEND and CMND_SERIALLOG
diff --git a/tasmota/tasmota_support/support_esp.ino b/tasmota/tasmota_support/support_esp.ino
index b4fb28cf6..30b6129c9 100644
--- a/tasmota/tasmota_support/support_esp.ino
+++ b/tasmota/tasmota_support/support_esp.ino
@@ -99,13 +99,49 @@ void *special_calloc(size_t num, size_t size) {
}
String GetDeviceHardware(void) {
+ /*
+ ESP8266 SoCs
+ - 32-bit MCU & 2.4 GHz Wi-Fi
+ - High-performance 160 MHz single-core CPU
+ - +19.5 dBm output power ensures a good physical range
+ - Sleep current is less than 20 μA, making it suitable for battery-powered and wearable-electronics applications
+ - Peripherals include UART, GPIO, I2C, I2S, SDIO, PWM, ADC and SPI
+ */
// esptool.py get_efuses
- uint32_t efuse1 = *(uint32_t*)(0x3FF00050);
- uint32_t efuse2 = *(uint32_t*)(0x3FF00054);
-// uint32_t efuse3 = *(uint32_t*)(0x3FF00058);
-// uint32_t efuse4 = *(uint32_t*)(0x3FF0005C);
+ uint32_t efuse0 = *(uint32_t*)(0x3FF00050);
+// uint32_t efuse1 = *(uint32_t*)(0x3FF00054);
+ uint32_t efuse2 = *(uint32_t*)(0x3FF00058);
+ uint32_t efuse3 = *(uint32_t*)(0x3FF0005C);
- if (((efuse1 & (1 << 4)) || (efuse2 & (1 << 16))) && (ESP.getFlashChipRealSize() < 1048577)) { // ESP8285 can only have 1M flash
+ bool r0_4 = efuse0 & (1 << 4); // ESP8285
+ bool r2_16 = efuse2 & (1 << 16); // ESP8285
+ if (r0_4 || r2_16) { // ESP8285
+ // 1M 2M 2M 4M flash size
+ // r0_4 1 1 0 0
+ bool r3_25 = efuse3 & (1 << 25); // flash matrix 0 0 1 1
+ bool r3_26 = efuse3 & (1 << 26); // flash matrix 0 1 0 1
+ bool r3_27 = efuse3 & (1 << 27); // flash matrix 0 0 0 0
+ uint32_t pkg_version = 0;
+ if (!r3_27) {
+ if (r0_4 && !r3_25) {
+ pkg_version = (r3_26) ? 2 : 1;
+ }
+ else if (!r0_4 && r3_25) {
+ pkg_version = (r3_26) ? 4 : 2;
+ }
+ }
+ bool max_temp = efuse0 & (1 << 5); // Max flash temperature (0 = 85C, 1 = 105C)
+ switch (pkg_version) {
+ case 1:
+ if (max_temp) { return F("ESP8285H08"); } // 1M flash
+ else { return F("ESP8285N08"); }
+ case 2:
+ if (max_temp) { return F("ESP8285H16"); } // 2M flash
+ else { return F("ESP8285N16"); }
+ case 4:
+ if (max_temp) { return F("ESP8285H32"); } // 4M flash
+ else { return F("ESP8285N32"); }
+ }
return F("ESP8285");
}
return F("ESP8266EX");
@@ -618,11 +654,9 @@ uint8_t* FlashDirectAccess(void) {
uint32_t address = FlashWriteStartSector() * SPI_FLASH_SEC_SIZE;
uint8_t* data = EspFlashMmap(address);
/*
- AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Flash start address 0x%08X, Mmap address 0x%08X"), address, data);
-
uint8_t buf[32];
memcpy(buf, data, sizeof(buf));
- AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t*)&buf, 32);
+ AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Flash start address 0x%08X, Mmap address 0x%08X, Data %*_H"), address, data, sizeof(buf), (uint8_t*)&buf);
*/
return data;
}
@@ -768,6 +802,17 @@ typedef struct {
bool single_core = (1 == chip_info.cores);
if (chip_model < 2) { // ESP32
+ /*
+ ESP32 Series
+ - 32-bit MCU & 2.4 GHz Wi-Fi & Bluetooth/Bluetooth LE
+ - Two or one CPU core(s) with adjustable clock frequency, ranging from 80 MHz to 240 MHz
+ - +19.5 dBm output power ensures a good physical range
+ - Classic Bluetooth for legacy connections, also supporting L2CAP, SDP, GAP, SMP, AVDTP, AVCTP, A2DP (SNK) and AVRCP (CT)
+ - Support for Bluetooth Low Energy (Bluetooth LE) profiles including L2CAP, GAP, GATT, SMP, and GATT-based profiles like BluFi, SPP-like, etc
+ - Bluetooth Low Energy (Bluetooth LE) connects to smart phones, broadcasting low-energy beacons for easy detection
+ - Sleep current is less than 5 μA, making it suitable for battery-powered and wearable-electronics applications
+ - Peripherals include capacitive touch sensors, Hall sensor, SD card interface, Ethernet, high-speed SPI, UART, I2S and I2C
+ */
#ifdef CONFIG_IDF_TARGET_ESP32
/* esptool:
def get_pkg_version(self):
@@ -807,6 +852,15 @@ typedef struct {
return F("ESP32");
}
else if (2 == chip_model) { // ESP32-S2
+ /*
+ ESP32-S2 Series
+ - 32-bit MCU & 2.4 GHz Wi-Fi
+ - High-performance 240 MHz single-core CPU
+ - Ultra-low-power performance: fine-grained clock gating, dynamic voltage and frequency scaling
+ - Security features: eFuse、flash encryption, secure boot, signature verification, integrated AES, SHA and RSA algorithms
+ - Peripherals include 43 GPIOs, 1 full-speed USB OTG interface, SPI, I2S, UART, I2C, LED PWM, LCD interface, camera interface, ADC, DAC, touch sensor, temperature sensor
+ - Availability of common cloud connectivity agents and common product features shortens the time to market
+ */
#ifdef CONFIG_IDF_TARGET_ESP32S2
/* esptool:
def get_flash_version(self):
@@ -840,13 +894,19 @@ typedef struct {
#endif // CONFIG_IDF_TARGET_ESP32S2
return F("ESP32-S2");
}
- else if (9 == chip_model) { // ESP32-S3
-#ifdef CONFIG_IDF_TARGET_ESP32S3
- // no variants for now
-#endif // CONFIG_IDF_TARGET_ESP32S3
- return F("ESP32-S3"); // Max 240MHz, Dual core, QFN 7*7, ESP32-S3-WROOM-1, ESP32-S3-DevKitC-1
+ else if (4 == chip_model) { // ESP32-S3(beta2)
+ return F("ESP32-S3");
}
- else if (5 == chip_model) { // ESP32-C3
+ else if (5 == chip_model) { // ESP32-C3 = ESP8685
+ /*
+ ESP32-C3 Series
+ - 32-bit RISC-V MCU & 2.4 GHz Wi-Fi & Bluetooth 5 (LE)
+ - 32-bit RISC-V single-core processor with a four-stage pipeline that operates at up to 160 MHz
+ - State-of-the-art power and RF performance
+ - 400 KB of SRAM and 384 KB of ROM on the chip, and SPI, Dual SPI, Quad SPI, and QPI interfaces that allow connection to flash
+ - Reliable security features ensured by RSA-3072-based secure boot, AES-128-XTS-based flash encryption, the innovative digital signature and the HMAC peripheral, hardware acceleration support for cryptographic algorithms
+ - Rich set of peripheral interfaces and GPIOs, ideal for various scenarios and complex applications
+ */
#ifdef CONFIG_IDF_TARGET_ESP32C3
/* esptool:
def get_pkg_version(self):
@@ -894,7 +954,22 @@ typedef struct {
#endif // CONFIG_IDF_TARGET_ESP32C6
return F("ESP32-C6");
}
- else if (10 == chip_model) { // ESP32-H2
+ else if (9 == chip_model) { // ESP32-S3
+ /*
+ ESP32-S3 Series
+ - 32-bit MCU & 2.4 GHz Wi-Fi & Bluetooth 5 (LE)
+ - Xtensa® 32-bit LX7 dual-core processor that operates at up to 240 MHz
+ - 512 KB of SRAM and 384 KB of ROM on the chip, and SPI, Dual SPI, Quad SPI, Octal SPI, QPI, and OPI interfaces that allow connection to flash and external RAM
+ - Additional support for vector instructions in the MCU, which provides acceleration for neural network computing and signal processing workloads
+ - Peripherals include 45 programmable GPIOs, SPI, I2S, I2C, PWM, RMT, ADC and UART, SD/MMC host and TWAITM
+ - Reliable security features ensured by RSA-based secure boot, AES-XTS-based flash encryption, the innovative digital signature and the HMAC peripheral, “World Controller”
+ */
+#ifdef CONFIG_IDF_TARGET_ESP32S3
+ // no variants for now
+#endif // CONFIG_IDF_TARGET_ESP32S3
+ return F("ESP32-S3"); // Max 240MHz, Dual core, QFN 7*7, ESP32-S3-WROOM-1, ESP32-S3-DevKitC-1
+ }
+ else if (10 == chip_model) { // ESP32-H2(beta1)
#ifdef CONFIG_IDF_TARGET_ESP32H2
/* esptool:
def get_pkg_version(self):
@@ -916,6 +991,33 @@ typedef struct {
#endif // CONFIG_IDF_TARGET_ESP32H2
return F("ESP32-H2");
}
+ else if (12 == chip_model) { // ESP32-C2 = ESP8684
+ /*
+ ESP32-C2 Series
+ - 32-bit RISC-V MCU & 2.4 GHz Wi-Fi & Bluetooth 5 (LE)
+ - 32-bit RISC-V single-core processor that operates at up to 120 MHz
+ - State-of-the-art power and RF performance
+ - 576 KB ROM, 272 KB SRAM (16 KB for cache) on the chip
+ - 14 programmable GPIOs: SPI, UART, I2C, LED PWM controller, General DMA controller (GDMA), SAR ADC, Temperature sensor
+ */
+
+ return F("ESP32-C2");
+ }
+ else if (13 == chip_model) { // ESP32-C6
+ /*
+ ESP32-C6 Series
+ - 32-bit RISC-V MCU & 2.4 GHz Wi-Fi 6 & Bluetooth 5 (LE) & IEEE 802.15.4
+ - 32-bit RISC-V single-core processor that operates at up to 160 MHz
+ - State-of-the-art power and RF performance
+ - 320 KB ROM, 512 KB SRAM, 16 KB Low-power SRAM on the chip, and works with external flash
+ - 30 (QFN40) or 22 (QFN32) programmable GPIOs, with support for SPI, UART, I2C, I2S, RMT, TWAI and PWM
+ */
+
+ return F("ESP32-C6");
+ }
+ else if (14 == chip_model) { // ESP32-H2(beta2)
+ return F("ESP32-H2");
+ }
return F("ESP32");
}
diff --git a/tasmota/tasmota_support/support_features.ino b/tasmota/tasmota_support/support_features.ino
index 78d972340..b70ed8c93 100644
--- a/tasmota/tasmota_support/support_features.ino
+++ b/tasmota/tasmota_support/support_features.ino
@@ -840,13 +840,24 @@ void ResponseAppendFeatures(void)
#if defined(USE_ENERGY_SENSOR) && defined(USE_MODBUS_ENERGY)
feature9 |= 0x00000010; // xnrg_29_modbus.ino
#endif
-// feature9 |= 0x00000020;
-// feature9 |= 0x00000040;
-// feature9 |= 0x00000080;
-
-// feature9 |= 0x00000100;
-// feature9 |= 0x00000200;
-// feature9 |= 0x00000400;
+#if defined(USE_SPI) && defined(USE_SHELLY_PRO)
+ feature9 |= 0x00000020; // xdrv_88_esp32_shelly_pro.ino
+#endif
+#ifdef USE_DALI
+ feature9 |= 0x00000040; // xdrv_89_esp32_dali.ino
+#endif
+#if defined(USE_LIGHT) && defined(USE_BP1658CJ)
+ feature9 |= 0x00000080; // xlgt_10_bp1658cj.ino
+#endif
+#ifdef USE_DINGTIAN_RELAY
+ feature9 |= 0x00000100; // xdrv_90_dingtian_relay.ino
+#endif
+#if defined(USE_I2C) && defined(USE_HMC5883L)
+ feature9 |= 0x00000200; // xsns_101_hmc5883l.ino
+#endif
+#ifdef USE_LD2410
+ feature9 |= 0x00000400; // xsns_102_ld2410.ino
+#endif
// feature9 |= 0x00000800;
// feature9 |= 0x00001000;
diff --git a/tasmota/tasmota_support/support_network.ino b/tasmota/tasmota_support/support_network.ino
index a6975c750..5dd32cfc1 100644
--- a/tasmota/tasmota_support/support_network.ino
+++ b/tasmota/tasmota_support/support_network.ino
@@ -27,19 +27,11 @@ struct {
#ifdef USE_DISCOVERY
void StartMdns(void) {
-// static uint8_t mdns_delayed_start = Settings->param[P_MDNS_DELAYED_START];
-
if (Settings->flag3.mdns_enabled) { // SetOption55 - Control mDNS service
if (!Mdns.begun) {
-// if (mdns_delayed_start) {
-// AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_ATTEMPTING_CONNECTION));
-// mdns_delayed_start--;
-// } else {
-// mdns_delayed_start = Settings->param[P_MDNS_DELAYED_START];
- MDNS.end(); // close existing or MDNS.begin will fail
- Mdns.begun = (uint8_t)MDNS.begin(TasmotaGlobal.hostname);
- AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS "%s"), (Mdns.begun) ? PSTR(D_INITIALIZED) : PSTR(D_FAILED));
-// }
+ MDNS.end(); // close existing or MDNS.begin will fail
+ Mdns.begun = (uint8_t)MDNS.begin(TasmotaGlobal.hostname);
+ AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS "%s '%s.local'"), (Mdns.begun) ? PSTR(D_INITIALIZED) : PSTR(D_FAILED), TasmotaGlobal.hostname);
}
}
}
diff --git a/tasmota/tasmota_support/support_rtc.ino b/tasmota/tasmota_support/support_rtc.ino
index 85efa6a84..1c10811fc 100644
--- a/tasmota/tasmota_support/support_rtc.ino
+++ b/tasmota/tasmota_support/support_rtc.ino
@@ -43,10 +43,12 @@ struct RTC {
uint32_t standard_time = 0;
uint32_t midnight = 0;
uint32_t restart_time = 0;
+ uint32_t nanos = 0;
uint32_t millis = 0;
// uint32_t last_sync = 0;
int32_t time_timezone = 0;
bool time_synced = false;
+ bool last_synced = false;
bool midnight_now = false;
bool user_time_entry = false; // Override NTP by user setting
} Rtc;
@@ -235,11 +237,14 @@ uint32_t RtcMillis(void) {
return (millis() - Rtc.millis) % 1000;
}
-void BreakTime(uint32_t time_input, TIME_T &tm) {
+void BreakNanoTime(uint32_t time_input, uint32_t time_nanos, TIME_T &tm) {
// break the given time_input into time components
// this is a more compact version of the C library localtime function
// note that year is offset from 1970 !!!
+ time_input += time_nanos / 1000000000U;
+ tm.nanos = time_nanos % 1000000000U;
+
uint8_t year;
uint8_t month;
uint8_t month_length;
@@ -290,6 +295,10 @@ void BreakTime(uint32_t time_input, TIME_T &tm) {
tm.valid = (time_input > START_VALID_TIME); // 2016-01-01
}
+void BreakTime(uint32_t time_input, TIME_T &tm) {
+ BreakNanoTime(time_input, 0, tm);
+}
+
uint32_t MakeTime(TIME_T &tm) {
// assemble time elements into time_t
// note year argument is offset from 1970
@@ -403,6 +412,7 @@ void RtcSecond(void) {
mutex = true;
Rtc.time_synced = false;
+ Rtc.last_synced = true;
last_sync = Rtc.utc_time;
if (Rtc.restart_time == 0) {
@@ -420,7 +430,13 @@ void RtcSecond(void) {
TasmotaGlobal.rules_flag.time_set = 1;
}
} else {
- Rtc.utc_time++; // Increment every second
+ if (Rtc.last_synced) {
+ Rtc.last_synced = false;
+ uint32_t nanos = Rtc.nanos + (millis() - Rtc.millis) * 1000000U;
+ Rtc.utc_time += nanos / 1000000000U;
+ Rtc.nanos = nanos % 1000000000U;
+ } else
+ Rtc.utc_time++; // Increment every second
}
Rtc.millis = millis();
@@ -442,7 +458,7 @@ void RtcSecond(void) {
}
}
- BreakTime(Rtc.local_time, RtcTime);
+ BreakNanoTime(Rtc.local_time, Rtc.nanos, RtcTime);
if (RtcTime.valid) {
if (!Rtc.midnight) {
Rtc.midnight = Rtc.local_time - (RtcTime.hour * 3600) - (RtcTime.minute * 60) - RtcTime.second;
diff --git a/tasmota/tasmota_support/support_switch.ino b/tasmota/tasmota_support/support_switch.ino
index 7a3f01dae..6bf59bbcb 100644
--- a/tasmota/tasmota_support/support_switch.ino
+++ b/tasmota/tasmota_support/support_switch.ino
@@ -409,6 +409,9 @@ void SwitchHandler(uint32_t mode) {
Switch.last_state[i] = button; // Update switch state before publishing
MqttPublishSensor();
break;
+ case PUSH_IGNORE_INV:
+ MqttPublishSensor(); // Publishing before update
+ break;
}
Switch.last_state[i] = button;
}
diff --git a/tasmota/tasmota_support/support_tasmota.ino b/tasmota/tasmota_support/support_tasmota.ino
index 77163871e..f8234b9d3 100644
--- a/tasmota/tasmota_support/support_tasmota.ino
+++ b/tasmota/tasmota_support/support_tasmota.ino
@@ -221,6 +221,16 @@ void ZeroCrossInit(uint32_t offset) {
/********************************************************************************************/
+void XdrvXsnsCall(uint32_t function) {
+ XdrvCall(function);
+ XsnsCall(function);
+}
+
+void XsnsXdrvCall(uint32_t function) {
+ XsnsCall(function);
+ XdrvCall(function);
+}
+
void SetLatchingRelay(power_t lpower, uint32_t state) {
// TasmotaGlobal.power xx00 - toggle REL1 (Off) and REL3 (Off) - device 1 Off, device 2 Off
// TasmotaGlobal.power xx01 - toggle REL2 (On) and REL3 (Off) - device 1 On, device 2 Off
@@ -240,6 +250,11 @@ void SetLatchingRelay(power_t lpower, uint32_t state) {
}
void SetDevicePower(power_t rpower, uint32_t source) {
+ if (TasmotaGlobal.power_on_delay) {
+ TasmotaGlobal.power_on_delay_state = rpower;
+ return;
+ }
+
ShowSource(source);
TasmotaGlobal.last_source = source;
@@ -271,8 +286,7 @@ void SetDevicePower(power_t rpower, uint32_t source) {
}
XdrvMailbox.index = rpower;
- XdrvCall(FUNC_SET_POWER); // Signal power state
- XsnsCall(FUNC_SET_POWER); // Signal power state
+ XdrvXsnsCall(FUNC_SET_POWER); // Signal power state
XdrvMailbox.index = rpower;
XdrvMailbox.payload = source;
@@ -384,7 +398,7 @@ void SetPowerOnState(void)
SetDevicePower(1, SRC_RESTART);
} else {
power_t devices_mask = POWER_MASK >> (POWER_SIZE - TasmotaGlobal.devices_present);
- if ((ResetReason() == REASON_DEFAULT_RST) || (ResetReason() == REASON_EXT_SYS_RST)) {
+ if (ResetReasonPowerOn()) {
switch (Settings->poweronstate) {
case POWER_ALL_OFF:
case POWER_ALL_OFF_PULSETIME_ON:
@@ -422,7 +436,8 @@ void SetPowerOnState(void)
uint32_t port = 0;
for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) {
#ifdef ESP8266
- if (!Settings->flag3.no_power_feedback) { // SetOption63 - Don't scan relay power state at restart - #5594 and #5663
+ if (!Settings->flag3.no_power_feedback && // SetOption63 - Don't scan relay power state at restart - #5594 and #5663
+ !TasmotaGlobal.power_on_delay) { // SetOption47 - Delay switching relays to reduce power surge at power on
if ((port < MAX_RELAYS) && PinUsed(GPIO_REL1, port)) {
if (bitRead(TasmotaGlobal.rel_bistable, port)) {
port++; // Skip both bistable relays as always 0
@@ -517,8 +532,13 @@ void SetLedPowerAll(uint32_t state)
}
}
-void SetLedLink(uint32_t state)
-{
+void SetLedLink(uint32_t state) {
+#ifdef ESP32
+ uint32_t index = XdrvMailbox.index;
+ XdrvMailbox.index = state;
+ XdrvCall(FUNC_LED_LINK);
+ XdrvMailbox.index = index;
+#endif // ESP32
int led_pin = Pin(GPIO_LEDLNK);
uint32_t led_inv = TasmotaGlobal.ledlnk_inverted;
if (-1 == led_pin) { // Legacy - LED1 is status
@@ -878,8 +898,7 @@ void GetSensorValues(void) {
char *start = ResponseData();
int data_start = ResponseLength();
- XsnsCall(FUNC_JSON_APPEND);
- XdrvCall(FUNC_JSON_APPEND);
+ XsnsXdrvCall(FUNC_JSON_APPEND);
if (data_start == ResponseLength()) { return; }
@@ -1008,19 +1027,6 @@ void MqttPublishTeleperiodSensor(void) {
}
}
-void SkipSleep(bool state) {
- if (state) {
- TasmotaGlobal.skip_sleep += 2;
- } else {
- if (TasmotaGlobal.skip_sleep) {
- TasmotaGlobal.skip_sleep--;
- }
- if (TasmotaGlobal.skip_sleep) {
- TasmotaGlobal.skip_sleep--;
- }
- }
-}
-
/*********************************************************************************************\
* State loops
\*********************************************************************************************/
@@ -1051,6 +1057,29 @@ void PerformEverySecond(void)
#endif
}
+ if (TasmotaGlobal.power_on_delay) {
+ if (1 == Settings->param[P_POWER_ON_DELAY2]) { // SetOption47 1
+ // Allow relay power on once network is available
+ if (!TasmotaGlobal.global_state.network_down) {
+ TasmotaGlobal.power_on_delay = 0;
+ }
+ }
+ else if (2 == Settings->param[P_POWER_ON_DELAY2]) { // SetOption47 2
+ // Allow relay power on once mqtt is available
+ if (!TasmotaGlobal.global_state.mqtt_down) {
+ TasmotaGlobal.power_on_delay = 0;
+ }
+ }
+ else { // SetOption47 3..255
+ // Allow relay power on after x seconds
+ TasmotaGlobal.power_on_delay--;
+ }
+ if (!TasmotaGlobal.power_on_delay && TasmotaGlobal.power_on_delay_state) {
+ // Set relays according to last SetDevicePower() request
+ SetDevicePower(TasmotaGlobal.power_on_delay_state, SRC_SO47);
+ }
+ }
+
if (TasmotaGlobal.mqtt_cmnd_blocked_reset) {
TasmotaGlobal.mqtt_cmnd_blocked_reset--;
if (!TasmotaGlobal.mqtt_cmnd_blocked_reset) {
@@ -1103,8 +1132,7 @@ void PerformEverySecond(void)
MqttPublishTeleState();
MqttPublishTeleperiodSensor();
- XsnsCall(FUNC_AFTER_TELEPERIOD);
- XdrvCall(FUNC_AFTER_TELEPERIOD);
+ XsnsXdrvCall(FUNC_AFTER_TELEPERIOD);
} else {
// Global values (Temperature, Humidity and Pressure) update every 10 seconds
if (!(TasmotaGlobal.tele_period % 10)) {
@@ -1161,10 +1189,6 @@ void Every100mSeconds(void)
}
}
- if (TasmotaGlobal.skip_sleep) {
- TasmotaGlobal.skip_sleep--; // Clean up possible residue
- }
-
for (uint32_t i = 0; i < MAX_PULSETIMERS; i++) {
if (TasmotaGlobal.pulse_timer[i] != 0L) { // Timer active?
if (TimeReached(TasmotaGlobal.pulse_timer[i])) { // Timer finished?
@@ -1528,76 +1552,70 @@ void Every250mSeconds(void)
WifiDisable();
}
break;
- case 3: // Every x.75 second
- if (!TasmotaGlobal.global_state.network_down) {
+ case 3:
+ {
+ if (!TasmotaGlobal.global_state.network_down) {
#ifdef FIRMWARE_MINIMAL
#ifdef CONFIG_IDF_TARGET_ESP32C3
- if (OtaFactoryRead()) {
- OtaFactoryWrite(false);
- TasmotaGlobal.ota_state_flag = 3;
- }
+ if (OtaFactoryRead()) {
+ OtaFactoryWrite(false);
+ TasmotaGlobal.ota_state_flag = 3;
+ }
#endif
- if (1 == RtcSettings.ota_loader) {
- RtcSettings.ota_loader = 0;
- TasmotaGlobal.ota_state_flag = 3;
- }
+ if (1 == RtcSettings.ota_loader) {
+ RtcSettings.ota_loader = 0;
+ TasmotaGlobal.ota_state_flag = 3;
+ }
#endif // FIRMWARE_MINIMAL
#ifdef USE_DISCOVERY
- StartMdns();
+ StartMdns();
#endif // USE_DISCOVERY
#ifdef USE_WEBSERVER
- if (Settings->webserver) {
+ if (Settings->webserver) {
#ifdef ESP8266
- if (!WifiIsInManagerMode()) { StartWebserver(Settings->webserver, WiFi.localIP()); }
+ if (!WifiIsInManagerMode()) { StartWebserver(Settings->webserver, WiFi.localIP()); }
#endif // ESP8266
#ifdef ESP32
#ifdef USE_ETHERNET
- StartWebserver(Settings->webserver, (EthernetLocalIP()) ? EthernetLocalIP() : WiFi.localIP());
+ StartWebserver(Settings->webserver, (EthernetLocalIP()) ? EthernetLocalIP() : WiFi.localIP());
#else
- StartWebserver(Settings->webserver, WiFi.localIP());
+ StartWebserver(Settings->webserver, WiFi.localIP());
#endif
#endif // ESP32
#ifdef USE_DISCOVERY
#ifdef WEBSERVER_ADVERTISE
- MdnsAddServiceHttp();
+ MdnsAddServiceHttp();
#endif // WEBSERVER_ADVERTISE
#endif // USE_DISCOVERY
- } else {
- StopWebserver();
- }
-#ifdef USE_EMULATION
- if (Settings->flag2.emulation) { UdpConnect(); }
-#endif // USE_EMULATION
+
+ } else {
+ StopWebserver();
+ }
#endif // USE_WEBSERVER
#ifdef USE_DEVICE_GROUPS
- DeviceGroupsStart();
+ DeviceGroupsStart();
#endif // USE_DEVICE_GROUPS
-#ifdef USE_KNX
- if (!knx_started && Settings->flag.knx_enabled) { // CMND_KNX_ENABLED
- KNXStart();
- knx_started = true;
- }
-#endif // USE_KNX
+ // send FUNC_NETWORK_UP to all modules
+// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("WIF: Sending FUNC_NETWORK_UP"));
+ XdrvXsnsCall(FUNC_NETWORK_UP);
- MqttCheck();
- } else {
-#ifdef USE_EMULATION
- UdpDisconnect();
-#endif // USE_EMULATION
+ MqttCheck();
+ } else {
#ifdef USE_DEVICE_GROUPS
- DeviceGroupsStop();
+ DeviceGroupsStop();
#endif // USE_DEVICE_GROUPS
-#ifdef USE_KNX
- knx_started = false;
-#endif // USE_KNX
+ // send FUNC_NETWORK_DOWN to all modules
+// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("WIF: Sending FUNC_NETWORK_DOWN"));
+ XdrvXsnsCall(FUNC_NETWORK_DOWN);
+ } // Every x.75 second
}
break;
}
@@ -1820,8 +1838,7 @@ void SerialInput(void)
} else {
ResponseAppend_P(PSTR("\""));
if (Settings->flag.mqtt_serial_raw) {
- char hex_char[(TasmotaGlobal.serial_in_byte_counter * 2) + 2];
- ResponseAppend_P(ToHex_P((unsigned char*)TasmotaGlobal.serial_in_buffer, TasmotaGlobal.serial_in_byte_counter, hex_char, sizeof(hex_char)));
+ ResponseAppend_P(PSTR("%*_H"), TasmotaGlobal.serial_in_byte_counter, TasmotaGlobal.serial_in_buffer);
} else {
ResponseAppend_P(EscapeJSONString(TasmotaGlobal.serial_in_buffer).c_str());
}
@@ -2039,7 +2056,20 @@ void GpioInit(void)
if (mpin) { SetPin(i, mpin); } // Anything above GPIO_NONE and below GPIO_SENSOR_END
}
-// AddLogBufferSize(LOG_LEVEL_DEBUG, (uint8_t*)TasmotaGlobal.gpio_pin, nitems(TasmotaGlobal.gpio_pin), sizeof(TasmotaGlobal.gpio_pin[0]));
+// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: TasmotaGlobal.gpio_pin %*_V"), nitems(TasmotaGlobal.gpio_pin), (uint8_t*)TasmotaGlobal.gpio_pin);
+
+ if (ResetReasonPowerOn()) {
+ TasmotaGlobal.power_on_delay = Settings->param[P_POWER_ON_DELAY2]; // SetOption47 - Delay switching relays to reduce power surge at power on
+ if (TasmotaGlobal.power_on_delay) {
+ // This is the earliest possibility to disable relays connected to esp8266/esp32 gpios at power up to reduce power surge
+ for (uint32_t i = 0; i < MAX_RELAYS; i++) {
+ if (PinUsed(GPIO_REL1, i)) {
+ DigitalWrite(GPIO_REL1, i, bitRead(TasmotaGlobal.rel_inverted, i) ? 1 : 0); // Off
+ }
+ }
+ AddLog(LOG_LEVEL_DEBUG, PSTR("INI: SO47 %d Power off relays"), Settings->param[P_POWER_ON_DELAY2]);
+ }
+ }
analogWriteRange(Settings->pwm_range); // Default is 1023 (Arduino.h)
analogWriteFreq(Settings->pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c)
@@ -2164,7 +2194,11 @@ void GpioInit(void)
}
}
- delay(Settings->param[P_POWER_ON_DELAY] * 10); // SetOption46 - Allow Wemos D1 power to stabilize before starting I2C polling for devices powered locally
+ if (Settings->param[P_POWER_ON_DELAY]) { // SetOption46 - Allow Wemos D1 power to stabilize before starting I2C polling for devices powered locally
+ uint32_t init_delay = Settings->param[P_POWER_ON_DELAY] * 10;
+ AddLog(LOG_LEVEL_DEBUG, PSTR("INI: SO46 Wait %d msec"), init_delay);
+ delay(init_delay);
+ }
#ifdef USE_I2C
TasmotaGlobal.i2c_enabled = (PinUsed(GPIO_I2C_SCL) && PinUsed(GPIO_I2C_SDA));
diff --git a/tasmota/tasmota_support/support_wifi.ino b/tasmota/tasmota_support/support_wifi.ino
index 0700fcc2d..b72c309cd 100644
--- a/tasmota/tasmota_support/support_wifi.ino
+++ b/tasmota/tasmota_support/support_wifi.ino
@@ -41,9 +41,6 @@ const uint8_t WIFI_CHECK_SEC = 20; // seconds
const uint8_t WIFI_RETRY_OFFSET_SEC = WIFI_RETRY_SECONDS; // seconds
#include // Wifi, MQTT, Ota, WifiManager
-#if LWIP_IPV6
-#include // IPv6 DualStack
-#endif // LWIP_IPV6=1
int WifiGetRssiAsQuality(int rssi) {
int quality = 0;
@@ -203,17 +200,28 @@ void WiFiSetSleepMode(void)
WifiSetOutputPower();
}
-void WifiBegin(uint8_t flag, uint8_t channel)
-{
+void WifiBegin(uint8_t flag, uint8_t channel) {
#ifdef USE_EMULATION
UdpDisconnect();
#endif // USE_EMULATION
WiFi.persistent(false); // Solve possible wifi init errors (re-add at 6.2.1.16 #4044, #4083)
+#if defined(USE_IPV6) && defined(ESP32)
+ WiFi.IPv6(true);
+#endif
+
+#ifdef USE_WIFI_RANGE_EXTENDER
+ if (WiFi.getMode() != WIFI_AP_STA || !RgxApUp()) { // Preserve range extender connections (#17103)
+ WiFi.disconnect(true); // Delete SDK wifi config
+ delay(200);
+ WifiSetMode(WIFI_STA); // Disable AP mode
+ }
+#else
WiFi.disconnect(true); // Delete SDK wifi config
delay(200);
-
WifiSetMode(WIFI_STA); // Disable AP mode
+#endif
+
WiFiSetSleepMode();
// if (WiFi.getPhyMode() != WIFI_PHY_MODE_11N) { WiFi.setPhyMode(WIFI_PHY_MODE_11N); } // B/G/N
// if (WiFi.getPhyMode() != WIFI_PHY_MODE_11G) { WiFi.setPhyMode(WIFI_PHY_MODE_11G); } // B/G
@@ -255,20 +263,6 @@ void WifiBegin(uint8_t flag, uint8_t channel)
if (Settings->flag5.wait_for_wifi_result) { // SetOption142 - (Wifi) Wait 1 second for wifi connection solving some FRITZ!Box modem issues (1)
WiFi.waitForConnectResult(1000); // https://github.com/arendst/Tasmota/issues/14985
}
-
-#if LWIP_IPV6
- for (bool configured = false; !configured;) {
- uint16_t cfgcnt = 0;
- for (auto addr : addrList) {
- if ((configured = !addr.isLocal() && addr.isV6()) || cfgcnt==30) {
- AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_WIFI "Got IPv6 global address %s"), addr.toString().c_str());
- break; // IPv6 is mandatory but stop after 15 seconds
- }
- delay(500); // Loop until real IPv6 address is aquired or too many tries failed
- cfgcnt++;
- }
- }
-#endif // LWIP_IPV6=1
}
void WifiBeginAfterScan(void)
@@ -464,26 +458,83 @@ void WifiSetState(uint8_t state)
}
}
-#if LWIP_IPV6
+#ifdef USE_IPV6
+//
+// Scan through all interfaces to find a global or local IPv6 address
+// Arg:
+// is_local: is the address Link-Local (true) or Global (false)
+// if_type: possible values are "st" for Wifi STA, "en" for Ethernet, "lo" for localhost (not useful)
+static String WifiFindIPv6(bool is_local, const char * if_type = "st") {
+ for (netif* intf = netif_list; intf != nullptr; intf = intf->next) {
+ if (intf->name[0] == if_type[0] && intf->name[1] == if_type[1]) {
+ for (uint32_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+ ip_addr_t *ipv6 = &intf->ip6_addr[i];
+ if (IP_IS_V6_VAL(*ipv6) && !ip_addr_isloopback(ipv6) && !ip_addr_isany(ipv6) && ((bool)ip_addr_islinklocal(ipv6) == is_local)) {
+ return IPAddress(ipv6).toString();
+ }
+ }
+ }
+ }
+ return String();
+}
+
+// Returns only IPv6 global address (no loopback and no link-local)
String WifiGetIPv6(void)
{
- for (auto a : addrList) {
- if(!a.isLocal() && a.isV6()) return a.toString();
- }
- return "";
+ return WifiFindIPv6(false, "st");
}
-#endif // LWIP_IPV6=1
+
+String WifiGetIPv6LinkLocal(void)
+{
+ return WifiFindIPv6(true, "st");
+}
+
+// add an IPv6 link-local address to all netif
+void CreateLinkLocalIPv6(void)
+{
+#ifdef ESP32
+ for (auto intf = esp_netif_next(NULL); intf != NULL; intf = esp_netif_next(intf)) {
+ esp_netif_create_ip6_linklocal(intf);
+ }
+#endif // ESP32
+}
+
+//
+void WifiDumpAddressesIPv6(void)
+{
+ for (netif* intf = netif_list; intf != nullptr; intf = intf->next) {
+ if (!ip_addr_isany_val(intf->ip_addr)) AddLog(LOG_LEVEL_DEBUG, "WIF: '%c%c' IPv4 %s", intf->name[0], intf->name[1], IPAddress(intf->ip_addr).toString().c_str());
+ for (uint32_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+ if (!ip_addr_isany_val(intf->ip6_addr[i]))
+ AddLog(LOG_LEVEL_DEBUG, "WIF: '%c%c' IPv6 %s %s", intf->name[0], intf->name[1],
+ IPAddress(intf->ip6_addr[i]).toString().c_str(),
+ ip_addr_islinklocal(&intf->ip6_addr[i]) ? "local" : "");
+ }
+ }
+}
+#endif // USE_IPV6
// Check to see if we have any routable IP address
bool WifiHasIP(void) {
-#ifdef LWIP2_IPV6
- return !a.isLocal();
+#ifdef USE_IPV6
+ return !WiFi.localIP().isAny();
#else
return (uint32_t)WiFi.localIP() != 0;
-#endif
+#endif // USE_IPV6
}
void WifiCheckIp(void) {
+#ifdef USE_IPV6
+ if (WL_CONNECTED == WiFi.status()) {
+ if (!Wifi.ipv6_local_link_called) {
+ WiFi.enableIpV6();
+ Wifi.ipv6_local_link_called = true;
+ // AddLog(LOG_LEVEL_DEBUG, PSTR("WIF: calling enableIpV6"));
+ }
+
+ }
+#endif // USE_IPV6
+
if ((WL_CONNECTED == WiFi.status()) && WifiHasIP()) {
WifiSetState(1);
Wifi.counter = WIFI_CHECK_SEC;
@@ -682,10 +733,21 @@ void WifiEnable(void) {
//#include // sntp_servermode_dhcp()
//#endif // ESP8266
+#ifdef ESP32
+void WifiEvents(arduino_event_t *event);
+#endif
+
void WifiConnect(void)
{
if (!Settings->flag4.network_wifi) { return; }
+#if defined(ESP32) && !defined(FIRMWARE_MINIMAL)
+ static bool wifi_event_registered = false;
+ if (!wifi_event_registered) {
+ WiFi.onEvent(WifiEvents); // register event listener only once
+ wifi_event_registered = true;
+ }
+#endif // ESP32
WifiSetState(0);
WifiSetOutputPower();
@@ -836,6 +898,7 @@ bool WifiHostByName(const char* aHostname, IPAddress& aResult) {
if (WiFi.hostByName(aHostname, aResult)) {
// Host name resolved
if (0xFFFFFFFF != (uint32_t)aResult) {
+ AddLog(LOG_LEVEL_DEBUG, "WIF: Resolving '%s' (%s)", aHostname, aResult.toString().c_str());
return true;
}
}
@@ -844,6 +907,7 @@ bool WifiHostByName(const char* aHostname, IPAddress& aResult) {
uint32_t dns_address = (!TasmotaGlobal.global_state.eth_down) ? Settings->eth_ipv4_address[3] : Settings->ipv4_address[3];
DnsClient.begin((IPAddress)dns_address);
if (1 == DnsClient.getHostByName(aHostname, aResult)) {
+ AddLog(LOG_LEVEL_DEBUG, "WIF: Resolving '%s' (%s)", aHostname, aResult.toString().c_str());
return true;
}
}
@@ -878,13 +942,15 @@ void WifiPollNtp() {
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("NTP: Sync time..."));
ntp_run_time = millis();
- uint32_t ntp_time = WifiGetNtp();
+ uint64_t ntp_nanos = WifiGetNtp();
+ uint32_t ntp_time = ntp_nanos / 1000000000;
ntp_run_time = (millis() - ntp_run_time) / 1000;
// AddLog(LOG_LEVEL_DEBUG, PSTR("NTP: Runtime %d"), ntp_run_time);
if (ntp_run_time < 5) { ntp_run_time = 0; } // DNS timeout is around 10s
if (ntp_time > START_VALID_TIME) {
Rtc.utc_time = ntp_time;
+ Rtc.nanos = ntp_nanos % 1000000000;
ntp_sync_minute = 60; // Sync so block further requests
RtcSync("NTP");
} else {
@@ -893,7 +959,7 @@ void WifiPollNtp() {
}
}
-uint32_t WifiGetNtp(void) {
+uint64_t WifiGetNtp(void) {
static uint8_t ntp_server_id = 0;
// AddLog(LOG_LEVEL_DEBUG, PSTR("NTP: Start NTP Sync %d ..."), ntp_server_id);
@@ -983,7 +1049,12 @@ uint32_t WifiGetNtp(void) {
ntp_server_id++; // Next server next time
return 0;
}
- return secs_since_1900 - 2208988800UL;
+ uint32_t tmp_fraction = (uint32_t)packet_buffer[44] << 24;
+ tmp_fraction |= (uint32_t)packet_buffer[45] << 16;
+ tmp_fraction |= (uint32_t)packet_buffer[46] << 8;
+ tmp_fraction |= (uint32_t)packet_buffer[47];
+ uint32_t fraction = (((uint64_t)tmp_fraction) * 1000000000) >> 32;
+ return (((uint64_t)secs_since_1900) - 2208988800UL) * 1000000000 + fraction;
}
delay(10);
}
@@ -993,3 +1064,53 @@ uint32_t WifiGetNtp(void) {
ntp_server_id++; // Next server next time
return 0;
}
+
+// --------------------------------------------------------------------------------
+// Respond to some Arduino/esp-idf events for better IPv6 support
+// --------------------------------------------------------------------------------
+#ifdef ESP32
+// typedef void (*WiFiEventSysCb)(arduino_event_t *event);
+void WifiEvents(arduino_event_t *event) {
+ switch (event->event_id) {
+
+#ifdef USE_IPV6
+ case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
+ case ARDUINO_EVENT_ETH_GOT_IP6:
+ {
+ ip_addr_t ip_addr6;
+ ip_addr_copy_from_ip6(ip_addr6, event->event_info.got_ip6.ip6_info.ip);
+ IPAddress addr(ip_addr6);
+ AddLog(LOG_LEVEL_DEBUG, PSTR("%s: IPv6 %s %s"),
+ event->event_id == ARDUINO_EVENT_ETH_GOT_IP6 ? "ETH" : "WIF",
+ addr.isLocal() ? PSTR("Local") : PSTR("Global"), addr.toString().c_str());
+ }
+ break;
+#endif // USE_IPV6
+ case ARDUINO_EVENT_WIFI_STA_GOT_IP:
+ case ARDUINO_EVENT_ETH_GOT_IP:
+ {
+ ip_addr_t ip_addr4;
+ ip_addr_copy_from_ip4(ip_addr4, event->event_info.got_ip.ip_info.ip);
+ AddLog(LOG_LEVEL_DEBUG, PSTR("%s: IPv4 %_I, mask %_I, gateway %_I"),
+ event->event_id == ARDUINO_EVENT_ETH_GOT_IP ? "ETH" : "WIF",
+ event->event_info.got_ip.ip_info.ip.addr,
+ event->event_info.got_ip.ip_info.netmask.addr,
+ event->event_info.got_ip.ip_info.gw.addr);
+
+ }
+ break;
+
+ case ARDUINO_EVENT_WIFI_STA_CONNECTED:
+ // AddLog(LOG_LEVEL_DEBUG, PSTR("WIF: Received ARDUINO_EVENT_WIFI_STA_CONNECTED"));
+ Wifi.ipv6_local_link_called = false; // not sure if this is needed, make sure link-local is restored at each reconnect
+ break;
+ case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
+ case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE:
+ Wifi.ipv6_local_link_called = false;
+ break;
+
+ default:
+ break;
+ }
+}
+#endif // ESP32
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino b/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino
index 1b454348f..94eaf5d27 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino
@@ -597,8 +597,7 @@ void StartWebserver(int type, IPAddress ipweb)
// Webserver->on(F("/u2"), HTTP_POST, HandleUploadDone, HandleUploadLoop); // this call requires 2 functions so we keep a direct call
Webserver->on("/u2", HTTP_POST, HandleUploadDone, HandleUploadLoop); // this call requires 2 functions so we keep a direct call
#ifndef FIRMWARE_MINIMAL
- XdrvCall(FUNC_WEB_ADD_HANDLER);
- XsnsCall(FUNC_WEB_ADD_HANDLER);
+ XdrvXsnsCall(FUNC_WEB_ADD_HANDLER);
#endif // Not FIRMWARE_MINIMAL
if (!Web.initial_config) {
@@ -611,7 +610,7 @@ void StartWebserver(int type, IPAddress ipweb)
Webserver->begin(); // Web server start
}
if (Web.state != type) {
-#if LWIP_IPV6
+#ifdef USE_IPV6
String ipv6_addr = WifiGetIPv6();
if (ipv6_addr!="") {
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %_I and IPv6 global address %s "),
@@ -623,7 +622,7 @@ void StartWebserver(int type, IPAddress ipweb)
#else
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %_I"),
NetworkHostname(), (Mdns.begun) ? PSTR(".local") : "", (uint32_t)ipweb);
-#endif // LWIP_IPV6 = 1
+#endif // USE_IPV6
TasmotaGlobal.rules_flag.http_init = 1;
Web.state = type;
}
@@ -1085,8 +1084,7 @@ uint32_t WebUseManagementSubmenu(void) {
if (!management_count) {
XdrvMailbox.index = 1;
- XdrvCall(FUNC_WEB_ADD_CONSOLE_BUTTON);
- XsnsCall(FUNC_WEB_ADD_CONSOLE_BUTTON);
+ XdrvXsnsCall(FUNC_WEB_ADD_CONSOLE_BUTTON);
XdrvCall(FUNC_WEB_ADD_MANAGEMENT_BUTTON);
management_count = XdrvMailbox.index;
}
@@ -1288,8 +1286,7 @@ void HandleRoot(void)
}
#ifndef FIRMWARE_MINIMAL
- XdrvCall(FUNC_WEB_ADD_MAIN_BUTTON);
- XsnsCall(FUNC_WEB_ADD_MAIN_BUTTON);
+ XdrvXsnsCall(FUNC_WEB_ADD_MAIN_BUTTON);
#endif // Not FIRMWARE_MINIMAL
if (HTTP_ADMIN == Web.state) {
@@ -1442,8 +1439,7 @@ bool HandleRootStatusRefresh(void)
}
#endif // USE_ZIGBEE
- XsnsCall(FUNC_WEB_GET_ARG);
- XdrvCall(FUNC_WEB_GET_ARG);
+ XsnsXdrvCall(FUNC_WEB_GET_ARG);
#ifdef USE_WEB_SSE
WSContentBegin(200, CT_STREAM);
@@ -1455,8 +1451,7 @@ bool HandleRootStatusRefresh(void)
if (Settings->web_time_end) {
WSContentSend_P(PSTR("{s}" D_TIMER_TIME "{m}%s{e}"), GetDateAndTime(DT_LOCAL).substring(Settings->web_time_start, Settings->web_time_end).c_str());
}
- XsnsCall(FUNC_WEB_SENSOR);
- XdrvCall(FUNC_WEB_SENSOR);
+ XsnsXdrvCall(FUNC_WEB_SENSOR);
WSContentSend_P(PSTR(""));
@@ -1522,8 +1517,7 @@ void HandleConfiguration(void)
WSContentButton(BUTTON_MODULE);
WSContentButton(BUTTON_WIFI);
- XdrvCall(FUNC_WEB_ADD_BUTTON);
- XsnsCall(FUNC_WEB_ADD_BUTTON);
+ XdrvXsnsCall(FUNC_WEB_ADD_BUTTON);
WSContentButton(BUTTON_LOGGING);
WSContentButton(BUTTON_OTHER);
@@ -2365,12 +2359,16 @@ void HandleInformation(void)
int32_t rssi = WiFi.RSSI();
WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s (%d%%, %d dBm) 11%c"), Settings->sta_active +1, HtmlEscape(SettingsText(SET_STASSID1 + Settings->sta_active)).c_str(), WifiGetRssiAsQuality(rssi), rssi, pgm_read_byte(&kWifiPhyMode[WiFi.getPhyMode() & 0x3]) );
WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), TasmotaGlobal.hostname, (Mdns.begun) ? PSTR(".local") : "");
-#if LWIP_IPV6
+#ifdef USE_IPV6
String ipv6_addr = WifiGetIPv6();
if (ipv6_addr != "") {
- WSContentSend_P(PSTR("}1 IPv6 Address }2%s"), ipv6_addr.c_str());
+ WSContentSend_P(PSTR("}1 IPv6 Global (wifi)}2%s"), ipv6_addr.c_str());
}
-#endif // LWIP_IPV6 = 1
+ ipv6_addr = WifiGetIPv6LinkLocal();
+ if (ipv6_addr != "") {
+ WSContentSend_P(PSTR("}1 IPv6 Local (wifi)}2%s"), ipv6_addr.c_str());
+ }
+#endif // USE_IPV6
if (static_cast(WiFi.localIP()) != 0) {
WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.macAddress().c_str());
WSContentSend_P(PSTR("}1" D_IP_ADDRESS " (wifi)}2%_I"), (uint32_t)WiFi.localIP());
@@ -2389,6 +2387,16 @@ void HandleInformation(void)
WSContentSend_P(PSTR("}1
}2
"));
}
WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), EthernetHostname(), (Mdns.begun) ? PSTR(".local") : "");
+#ifdef USE_IPV6
+ String ipv6_eth_addr = EthernetGetIPv6();
+ if (ipv6_eth_addr != "") {
+ WSContentSend_P(PSTR("}1 IPv6 Global (eth)}2%s"), ipv6_eth_addr.c_str());
+ }
+ ipv6_eth_addr = EthernetGetIPv6LinkLocal();
+ if (ipv6_eth_addr != "") {
+ WSContentSend_P(PSTR("}1 IPv6 Local (eth)}2%s"), ipv6_eth_addr.c_str());
+ }
+#endif // USE_IPV6
WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), EthernetMacAddress().c_str());
WSContentSend_P(PSTR("}1" D_IP_ADDRESS " (eth)}2%_I"), (uint32_t)EthernetLocalIP());
}
@@ -2853,8 +2861,7 @@ void HandleUploadLoop(void) {
#ifdef USE_WEB_FW_UPGRADE
else if (BUpload.active) {
// Write a block
-// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Size %d"), upload.currentSize);
-// AddLogBuffer(LOG_LEVEL_DEBUG, upload.buf, 32);
+// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Size %d, Data '%32_H'"), upload.currentSize, upload.buf);
Web.upload_error = BUploadWriteBuffer(upload.buf, upload.currentSize);
if (Web.upload_error != 0) { return; }
}
@@ -3106,8 +3113,7 @@ void HandleManagement(void)
WSContentButton(BUTTON_CONSOLE);
XdrvMailbox.index = 0;
- XdrvCall(FUNC_WEB_ADD_CONSOLE_BUTTON);
- XsnsCall(FUNC_WEB_ADD_CONSOLE_BUTTON);
+ XdrvXsnsCall(FUNC_WEB_ADD_CONSOLE_BUTTON);
WSContentSend_P(PSTR("")); // 5px padding
XdrvCall(FUNC_WEB_ADD_MANAGEMENT_BUTTON);
@@ -3696,7 +3702,7 @@ void CmndCors(void)
* Interface
\*********************************************************************************************/
-bool Xdrv01(uint8_t function)
+bool Xdrv01(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino b/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino
index 1d328d447..950085016 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_02_9_mqtt.ino
@@ -522,11 +522,30 @@ bool MqttPublishLib(const char* topic, const uint8_t* payload, unsigned int plen
// AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_MQTT "Connection lost or message too large"));
return false;
}
+
uint32_t written = MqttClient.write(payload, plength);
if (written != plength) {
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_MQTT "Message too large"));
return false;
}
+/*
+ // Solves #6525??
+ const uint8_t* write_buf = payload;
+ uint32_t bytes_remaining = plength;
+ uint32_t bytes_to_write;
+ uint32_t written;
+ while (bytes_remaining > 0) {
+ bytes_to_write = (bytes_remaining > 256) ? 256 : bytes_remaining;
+ written = MqttClient.write(write_buf, bytes_to_write);
+ if (written != bytes_to_write) {
+ AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_MQTT "Message too large"));
+ return false;
+ }
+ write_buf += written;
+ bytes_remaining -= written;
+ }
+*/
+
MqttClient.endPublish();
yield(); // #3313
@@ -952,9 +971,10 @@ void MqttConnected(void) {
if (static_cast(WiFi.localIP()) != 0) {
ResponseAppend_P(PSTR(",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%_I\""),
TasmotaGlobal.hostname, (uint32_t)WiFi.localIP());
-#if LWIP_IPV6
- ResponseAppend_P(PSTR(",\"IPv6Address\":\"%s\""), WifiGetIPv6().c_str());
-#endif // LWIP_IPV6 = 1
+#ifdef USE_IPV6
+ ResponseAppend_P(PSTR(",\"" D_JSON_IP6_GLOBAL "\":\"%s\""), WifiGetIPv6().c_str());
+ ResponseAppend_P(PSTR(",\"" D_JSON_IP6_LOCAL "\":\"%s\""), WifiGetIPv6LinkLocal().c_str());
+#endif // USE_IPV6
}
#if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET)
if (static_cast(EthernetLocalIP()) != 0) {
@@ -1984,7 +2004,7 @@ void MqttSaveSettings(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv02(uint8_t function)
+bool Xdrv02(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino
index 4752702b2..065cabc5e 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino
@@ -41,6 +41,9 @@
#define D_CMND_TARIFF "Tariff"
#define D_CMND_MODULEADDRESS "ModuleAddress"
+enum EnergyCalibration {
+ ENERGY_POWER_CALIBRATION, ENERGY_VOLTAGE_CALIBRATION, ENERGY_CURRENT_CALIBRATION, ENERGY_FREQUENCY_CALIBRATION };
+
enum EnergyCommands {
CMND_POWERCAL, CMND_VOLTAGECAL, CMND_CURRENTCAL, CMND_FREQUENCYCAL,
CMND_POWERSET, CMND_VOLTAGESET, CMND_CURRENTSET, CMND_FREQUENCYSET, CMND_MODULEADDRESS, CMND_ENERGYCONFIG };
@@ -344,6 +347,7 @@ void Energy200ms(void)
if (!Energy.kWhtoday_offset_init && (RtcTime.day_of_year == Settings->energy_kWhdoy)) {
for (uint32_t i = 0; i < 3; i++) {
Energy.kWhtoday_offset[i] = Settings->energy_kWhtoday_ph[i];
+// RtcSettings.energy_kWhtoday_ph[i] = 0;
}
Energy.kWhtoday_offset_init = true;
}
@@ -361,6 +365,8 @@ void Energy200ms(void)
Energy.kWhtoday[i] = 0;
Energy.kWhtoday_offset[i] = 0;
RtcSettings.energy_kWhtoday_ph[i] = 0;
+ Settings->energy_kWhtoday_ph[i] = 0;
+
Energy.start_energy[i] = 0;
// Energy.kWhtoday_delta = 0; // dont zero this, we need to carry the remainder over to tomorrow
Energy.daily_sum_import_balanced = 0.0;
@@ -412,8 +418,8 @@ bool EnergyMargin(bool type, uint16_t margin, uint16_t value, bool &flag, bool &
return (change != save_flag);
}
-void EnergyMarginCheck(void)
-{
+void EnergyMarginCheck(void) {
+ if (!Energy.phase_count || (TasmotaGlobal.uptime < 8)) { return; }
if (Energy.power_steady_counter) {
Energy.power_steady_counter--;
return;
@@ -637,11 +643,6 @@ void EnergyEverySecond(void)
* Commands
\*********************************************************************************************/
-void EnergyCommandCalResponse(uint32_t nvalue) {
- snprintf_P(XdrvMailbox.command, CMDSZ, PSTR("%sCal"), XdrvMailbox.command);
- ResponseCmndNumber(nvalue);
-}
-
void ResponseCmndEnergyTotalYesterdayToday(void) {
char value_chr[TOPSZ]; // Used by EnergyFormatIndex
char value2_chr[TOPSZ];
@@ -835,71 +836,117 @@ void CmndTariff(void) {
GetStateText(Settings->flag3.energy_weekend)); // CMND_TARIFF
}
+uint32_t EnergyGetCalibration(uint32_t chan, uint32_t cal_type) {
+ uint32_t channel = ((1 == chan) && (2 == Energy.phase_count)) ? 1 : 0;
+ if (channel) {
+ switch (cal_type) {
+ case ENERGY_POWER_CALIBRATION: return Settings->energy_power_calibration2;
+ case ENERGY_VOLTAGE_CALIBRATION: return Settings->energy_voltage_calibration2;
+ case ENERGY_CURRENT_CALIBRATION: return Settings->energy_current_calibration2;
+ }
+ } else {
+ switch (cal_type) {
+ case ENERGY_POWER_CALIBRATION: return Settings->energy_power_calibration;
+ case ENERGY_VOLTAGE_CALIBRATION: return Settings->energy_voltage_calibration;
+ case ENERGY_CURRENT_CALIBRATION: return Settings->energy_current_calibration;
+ }
+ }
+ return Settings->energy_frequency_calibration;
+}
+
+void EnergyCommandCalSetResponse(uint32_t cal_type) {
+ if (XdrvMailbox.payload > 99) {
+ uint32_t channel = ((2 == XdrvMailbox.index) && (2 == Energy.phase_count)) ? 1 : 0;
+ if (channel) {
+ switch (cal_type) {
+ case ENERGY_POWER_CALIBRATION: Settings->energy_power_calibration2 = XdrvMailbox.payload; break;
+ case ENERGY_VOLTAGE_CALIBRATION: Settings->energy_voltage_calibration2 = XdrvMailbox.payload; break;
+ case ENERGY_CURRENT_CALIBRATION: Settings->energy_current_calibration2 = XdrvMailbox.payload; break;
+ case ENERGY_FREQUENCY_CALIBRATION: Settings->energy_frequency_calibration = XdrvMailbox.payload; break;
+ }
+ } else {
+ switch (cal_type) {
+ case ENERGY_POWER_CALIBRATION: Settings->energy_power_calibration = XdrvMailbox.payload; break;
+ case ENERGY_VOLTAGE_CALIBRATION: Settings->energy_voltage_calibration = XdrvMailbox.payload; break;
+ case ENERGY_CURRENT_CALIBRATION: Settings->energy_current_calibration = XdrvMailbox.payload; break;
+ case ENERGY_FREQUENCY_CALIBRATION: Settings->energy_frequency_calibration = XdrvMailbox.payload; break;
+ }
+ }
+ }
+ if (ENERGY_FREQUENCY_CALIBRATION == cal_type) {
+ ResponseAppend_P(PSTR("%d}"), Settings->energy_frequency_calibration);
+ } else {
+ if (2 == Energy.phase_count) {
+ ResponseAppend_P(PSTR("[%d,%d]}"), EnergyGetCalibration(0, cal_type), EnergyGetCalibration(1, cal_type));
+ } else {
+ ResponseAppend_P(PSTR("%d}"), EnergyGetCalibration(0, cal_type));
+ }
+ }
+}
+
+void EnergyCommandCalResponse(uint32_t cal_type) {
+ Response_P(PSTR("{\"%s\":"), XdrvMailbox.command);
+ EnergyCommandCalSetResponse(cal_type);
+}
+
+void EnergyCommandSetCalResponse(uint32_t cal_type) {
+ Response_P(PSTR("{\"%sCal\":"), XdrvMailbox.command);
+ EnergyCommandCalSetResponse(cal_type);
+}
+
void CmndPowerCal(void) {
Energy.command_code = CMND_POWERCAL;
if (XnrgCall(FUNC_COMMAND)) { // microseconds
- if (XdrvMailbox.payload > 999) {
- Settings->energy_power_calibration = XdrvMailbox.payload;
- }
- ResponseCmndNumber(Settings->energy_power_calibration);
+ EnergyCommandCalResponse(ENERGY_POWER_CALIBRATION);
}
}
void CmndVoltageCal(void) {
Energy.command_code = CMND_VOLTAGECAL;
if (XnrgCall(FUNC_COMMAND)) { // microseconds
- if (XdrvMailbox.payload > 999) {
- Settings->energy_voltage_calibration = XdrvMailbox.payload;
- }
- ResponseCmndNumber(Settings->energy_voltage_calibration);
+ EnergyCommandCalResponse(ENERGY_VOLTAGE_CALIBRATION);
}
}
void CmndCurrentCal(void) {
Energy.command_code = CMND_CURRENTCAL;
if (XnrgCall(FUNC_COMMAND)) { // microseconds
- if (XdrvMailbox.payload > 999) {
- Settings->energy_current_calibration = XdrvMailbox.payload;
- }
- ResponseCmndNumber(Settings->energy_current_calibration);
+ EnergyCommandCalResponse(ENERGY_CURRENT_CALIBRATION);
}
}
void CmndFrequencyCal(void) {
Energy.command_code = CMND_FREQUENCYCAL;
if (XnrgCall(FUNC_COMMAND)) { // microseconds
- if (XdrvMailbox.payload > 999) {
- Settings->energy_frequency_calibration = XdrvMailbox.payload;
- }
- ResponseCmndNumber(Settings->energy_frequency_calibration);
+ EnergyCommandCalResponse(ENERGY_FREQUENCY_CALIBRATION);
}
}
void CmndPowerSet(void) {
Energy.command_code = CMND_POWERSET;
if (XnrgCall(FUNC_COMMAND)) { // Watt
- EnergyCommandCalResponse(Settings->energy_power_calibration);
+ EnergyCommandSetCalResponse(ENERGY_POWER_CALIBRATION);
}
}
void CmndVoltageSet(void) {
Energy.command_code = CMND_VOLTAGESET;
if (XnrgCall(FUNC_COMMAND)) { // Volt
- EnergyCommandCalResponse(Settings->energy_voltage_calibration);
+ EnergyCommandSetCalResponse(ENERGY_VOLTAGE_CALIBRATION);
}
}
void CmndCurrentSet(void) {
Energy.command_code = CMND_CURRENTSET;
if (XnrgCall(FUNC_COMMAND)) { // milliAmpere
- EnergyCommandCalResponse(Settings->energy_current_calibration);
+ EnergyCommandSetCalResponse(ENERGY_CURRENT_CALIBRATION);
}
}
void CmndFrequencySet(void) {
Energy.command_code = CMND_FREQUENCYSET;
if (XnrgCall(FUNC_COMMAND)) { // Hz
- EnergyCommandCalResponse(Settings->energy_frequency_calibration);
+ EnergyCommandSetCalResponse(ENERGY_FREQUENCY_CALIBRATION);
}
}
@@ -925,7 +972,7 @@ void CmndEnergyConfig(void) {
#ifdef USE_ENERGY_MARGIN_DETECTION
void CmndPowerDelta(void) {
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= ENERGY_MAX_PHASES)) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32000)) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 32000)) {
Settings->energy_power_delta[XdrvMailbox.index -1] = XdrvMailbox.payload;
}
ResponseCmndIdxNumber(Settings->energy_power_delta[XdrvMailbox.index -1]);
@@ -933,42 +980,42 @@ void CmndPowerDelta(void) {
}
void CmndPowerLow(void) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) {
Settings->energy_min_power = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings->energy_min_power);
}
void CmndPowerHigh(void) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) {
Settings->energy_max_power = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings->energy_max_power);
}
void CmndVoltageLow(void) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 501)) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 500)) {
Settings->energy_min_voltage = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings->energy_min_voltage);
}
void CmndVoltageHigh(void) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 501)) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 500)) {
Settings->energy_max_voltage = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings->energy_max_voltage);
}
void CmndCurrentLow(void) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 16001)) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 25000)) {
Settings->energy_min_current = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings->energy_min_current);
}
void CmndCurrentHigh(void) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 16001)) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 25000)) {
Settings->energy_max_current = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings->energy_max_current);
@@ -976,35 +1023,35 @@ void CmndCurrentHigh(void) {
#ifdef USE_ENERGY_POWER_LIMIT
void CmndMaxPower(void) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) {
Settings->energy_max_power_limit = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings->energy_max_power_limit);
}
void CmndMaxPowerHold(void) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) {
Settings->energy_max_power_limit_hold = (1 == XdrvMailbox.payload) ? MAX_POWER_HOLD : XdrvMailbox.payload;
}
ResponseCmndNumber(Settings->energy_max_power_limit_hold);
}
void CmndMaxPowerWindow(void) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) {
Settings->energy_max_power_limit_window = (1 == XdrvMailbox.payload) ? MAX_POWER_WINDOW : XdrvMailbox.payload;
}
ResponseCmndNumber(Settings->energy_max_power_limit_window);
}
void CmndSafePower(void) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) {
Settings->energy_max_power_safe_limit = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings->energy_max_power_safe_limit);
}
void CmndSafePowerHold(void) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) {
Settings->energy_max_power_safe_limit_hold = (1 == XdrvMailbox.payload) ? SAFE_POWER_HOLD : XdrvMailbox.payload;
}
ResponseCmndNumber(Settings->energy_max_power_safe_limit_hold);
@@ -1018,7 +1065,7 @@ void CmndSafePowerWindow(void) {
}
void CmndMaxEnergy(void) {
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) {
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6000)) {
Settings->energy_max_energy = XdrvMailbox.payload;
Energy.max_energy_state = 3;
}
@@ -1036,6 +1083,9 @@ void CmndMaxEnergyStart(void) {
void EnergyDrvInit(void) {
memset(&Energy, 0, sizeof(Energy)); // Reset all to 0 and false;
+// Energy.voltage_common = false;
+// Energy.frequency_common = false;
+// Energy.use_overtemp = false;
for (uint32_t phase = 0; phase < ENERGY_MAX_PHASES; phase++) {
Energy.apparent_power[phase] = NAN;
Energy.reactive_power[phase] = NAN;
@@ -1047,9 +1097,6 @@ void EnergyDrvInit(void) {
Energy.voltage_available = true; // Enable if voltage is measured
Energy.current_available = true; // Enable if current is measured
Energy.power_on = true;
-#ifdef USE_ENERGY_MARGIN_DETECTION
- Energy.power_steady_counter = 8; // Allow for power on stabilization
-#endif // USE_ENERGY_MARGIN_DETECTION
TasmotaGlobal.energy_driver = ENERGY_NONE;
XnrgCall(FUNC_PRE_INIT); // Find first energy driver
@@ -1063,6 +1110,13 @@ void EnergySnsInit(void)
XnrgCall(FUNC_INIT);
if (TasmotaGlobal.energy_driver) {
+
+ AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: Rtc valid %d, kWhtoday_ph Rtc %d/%d/%d, Set %d/%d/%d"),
+ RtcSettingsValid(),
+ RtcSettings.energy_kWhtoday_ph[0],RtcSettings.energy_kWhtoday_ph[1],RtcSettings.energy_kWhtoday_ph[2],
+ Settings->energy_kWhtoday_ph[0],Settings->energy_kWhtoday_ph[1],Settings->energy_kWhtoday_ph[2]
+ );
+
for (uint32_t i = 0; i < 3; i++) {
// Energy.kWhtoday_offset[i] = 0; // Reset by EnergyDrvInit()
// 20220805 - Change from https://github.com/arendst/Tasmota/issues/16118
@@ -1340,7 +1394,7 @@ void EnergyShow(bool json) {
* Interface
\*********************************************************************************************/
-bool Xdrv03(uint8_t function)
+bool Xdrv03(uint32_t function)
{
bool result = false;
@@ -1350,6 +1404,7 @@ bool Xdrv03(uint8_t function)
else if (TasmotaGlobal.energy_driver) {
switch (function) {
case FUNC_LOOP:
+ case FUNC_SLEEP_LOOP:
XnrgCall(FUNC_LOOP);
break;
case FUNC_EVERY_250_MSECOND:
@@ -1371,12 +1426,18 @@ bool Xdrv03(uint8_t function)
case FUNC_COMMAND:
result = DecodeCommand(kEnergyCommands, EnergyCommand);
break;
+ case FUNC_NETWORK_UP:
+ XnrgCall(FUNC_NETWORK_UP);
+ break;
+ case FUNC_NETWORK_DOWN:
+ XnrgCall(FUNC_NETWORK_DOWN);
+ break;
}
}
return result;
}
-bool Xsns03(uint8_t function)
+bool Xsns03(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_04_light.ino b/tasmota/tasmota_xdrv_driver/xdrv_04_light.ino
index 27acc5ae7..a4c305416 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_04_light.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_04_light.ino
@@ -135,7 +135,7 @@ const uint8_t LIGHT_COLOR_SIZE = 25; // Char array scolor size
const char kLightCommands[] PROGMEM = "|" // No prefix
// SetOptions synonyms
D_SO_CHANNELREMAP "|" D_SO_MULTIPWM "|" D_SO_ALEXACTRANGE "|" D_SO_POWERONFADE "|" D_SO_PWMCT "|"
- D_SO_WHITEBLEND "|"
+ D_SO_WHITEBLEND "|" D_SO_ARTNET_AUTORUN "|"
// Other commands
D_CMND_COLOR "|" D_CMND_COLORTEMPERATURE "|" D_CMND_DIMMER "|" D_CMND_DIMMER_RANGE "|" D_CMND_DIMMER_STEP "|" D_CMND_LEDTABLE "|" D_CMND_FADE "|"
D_CMND_RGBWWTABLE "|" D_CMND_SCHEME "|" D_CMND_SPEED "|" D_CMND_WAKEUP "|" D_CMND_WAKEUPDURATION "|"
@@ -150,11 +150,14 @@ const char kLightCommands[] PROGMEM = "|" // No prefix
#ifdef USE_DGR_LIGHT_SEQUENCE
"|" D_CMND_SEQUENCE_OFFSET
#endif // USE_DGR_LIGHT_SEQUENCE
+#ifdef USE_LIGHT_ARTNET
+ "|" D_CMND_ARTNET "|" D_CMND_ARTNET_CONFIG
+#endif
"|UNDOCA" ;
SO_SYNONYMS(kLightSynonyms,
37, 68, 82, 91, 92,
- 105,
+ 105, 148,
);
void (* const LightCommand[])(void) PROGMEM = {
@@ -171,6 +174,9 @@ void (* const LightCommand[])(void) PROGMEM = {
#ifdef USE_DGR_LIGHT_SEQUENCE
&CmndSequenceOffset,
#endif // USE_DGR_LIGHT_SEQUENCE
+#ifdef USE_LIGHT_ARTNET
+ &CmndArtNet, &CmndArtNetConfig,
+#endif
&CmndUndocA };
// Light color mode, either RGB alone, or white-CT alone, or both only available if ct_rgb_linked is false
@@ -1763,6 +1769,7 @@ void LightReapplyColor(void) {
void LightAnimate(void)
{
bool power_off = false;
+ static int32_t sleep_previous = -1; // previous value of sleep before changing it to PWM_MAX_SLEEP, -1 means unchanged
// make sure we update CT range in case SetOption82 was changed
Light.strip_timer_counter++;
@@ -1770,13 +1777,17 @@ void LightAnimate(void)
// set sleep parameter: either settings,
// or set a maximum of PWM_MAX_SLEEP if light is on or Fade is running
if (Light.power || Light.fade_running) {
- if (Settings->sleep > PWM_MAX_SLEEP) {
+ if (TasmotaGlobal.sleep > PWM_MAX_SLEEP) {
+ sleep_previous = TasmotaGlobal.sleep; // save previous value of sleep
TasmotaGlobal.sleep = PWM_MAX_SLEEP; // set a maximum value (in milliseconds) to sleep to ensure that animations are smooth
} else {
- TasmotaGlobal.sleep = Settings->sleep; // or keep the current sleep if it's low enough
+ sleep_previous = -1; // if low enough, don't change it
}
} else {
- TasmotaGlobal.sleep = Settings->sleep;
+ if (sleep_previous > 0) {
+ TasmotaGlobal.sleep = sleep_previous;
+ sleep_previous = -1; // rearm
+ }
}
if (!Light.power) { // All channels powered off
@@ -1857,7 +1868,7 @@ void LightAnimate(void)
break;
#endif
default:
- XlgtCall(FUNC_SET_SCHEME);
+ XlgtCall(FUNC_SET_SCHEME);
}
#ifdef USE_DEVICE_GROUPS
@@ -1951,7 +1962,7 @@ void LightAnimate(void)
Light.fade_start_10[channel_ct] = Light.fade_end_10[channel_ct];
}
}
-
+
Light.fade_running = true;
Light.fade_duration = 0; // set the value to zero to force a recompute
Light.fade_start = 0;
@@ -2180,10 +2191,10 @@ void LightSetOutputs(const uint16_t *cur_col_10) {
}
if (!Settings->flag4.zerocross_dimmer) {
#ifdef ESP32
- TasmotaGlobal.pwm_value[i] = cur_col; // mark the new expected value
+ TasmotaGlobal.pwm_value[i] = ac_zero_cross_power(cur_col); // mark the new expected value
// AddLog(LOG_LEVEL_DEBUG_MORE, "analogWrite-%i 0x%03X", i, cur_col);
#else // ESP32
- analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - cur_col : cur_col);
+ analogWrite(Pin(GPIO_PWM1, i), bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - ac_zero_cross_power(cur_col) : ac_zero_cross_power(cur_col));
// AddLog(LOG_LEVEL_DEBUG_MORE, "analogWrite-%i 0x%03X", bitRead(TasmotaGlobal.pwm_inverted, i) ? Settings->pwm_range - cur_col : cur_col);
#endif // ESP32
}
@@ -2224,6 +2235,10 @@ void LightSetOutputs(const uint16_t *cur_col_10) {
XdrvMailbox.data = (char*)cur_col;
XdrvMailbox.topic = (char*)scale_col;
XdrvMailbox.command = (char*)cur_col_10;
+#ifdef USE_LIGHT_ARTNET
+ if (ArtNetSetChannels()) { /* Serviced */}
+ else
+#endif
if (XlgtCall(FUNC_SET_CHANNELS)) { /* Serviced */ }
else if (XdrvCall(FUNC_SET_CHANNELS)) { /* Serviced */ }
XdrvMailbox.data = tmp_data;
@@ -3390,7 +3405,7 @@ void CmndUndocA(void)
* Interface
\*********************************************************************************************/
-bool Xdrv04(uint8_t function)
+bool Xdrv04(uint32_t function)
{
bool result = false;
@@ -3408,6 +3423,9 @@ bool Xdrv04(uint8_t function)
LightSetOutputs(Light.fade_cur_10);
}
}
+#ifdef USE_LIGHT_ARTNET
+ ArtNetLoop();
+#endif // USE_LIGHT_ARTNET
break;
case FUNC_EVERY_50_MSECOND:
LightAnimate();
@@ -3440,6 +3458,17 @@ bool Xdrv04(uint8_t function)
case FUNC_PRE_INIT:
LightInit();
break;
+#ifdef USE_LIGHT_ARTNET
+ case FUNC_JSON_APPEND:
+ ArtNetJSONAppend();
+ break;
+ case FUNC_NETWORK_UP:
+ ArtNetFuncNetworkUp();
+ break;
+ case FUNC_NETWORK_DOWN:
+ ArtNetFuncNetworkDown();
+ break;
+#endif // USE_LIGHT_ARTNET
}
}
return result;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_04_light_artnet.ino b/tasmota/tasmota_xdrv_driver/xdrv_04_light_artnet.ino
new file mode 100644
index 000000000..00259f326
--- /dev/null
+++ b/tasmota/tasmota_xdrv_driver/xdrv_04_light_artnet.ino
@@ -0,0 +1,454 @@
+/*
+ xdrv_04_light_artnet.ino - Converter functions for lights
+
+ Copyright (C) 2020 Stephan Hadinger & 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_LIGHT
+#ifdef USE_LIGHT_ARTNET
+
+#ifndef USE_WS2812
+#define USE_WS2812 // needed since USE_LIGHT_ARTNET is enabled for ESP32 by default
+#endif
+
+#ifndef WS2812_ARTNET_UDP_BUFFER_SIZE
+#define WS2812_ARTNET_UDP_BUFFER_SIZE 140 // Max 30 columns with 4 bytes per pixel
+#endif
+
+#ifndef WS2812_ARTNET_UDP_MAX_PACKETS
+#define WS2812_ARTNET_UDP_MAX_PACKETS 30 // Max 30 rows (packets consecutive)
+#endif
+
+#ifndef WS2812_ARTNET_MAX_SLEEP
+#define WS2812_ARTNET_MAX_SLEEP 5 // sleep at most 5ms
+#endif
+
+typedef struct {
+ uint8_t rows = 1; // number of rows (min:1)
+ uint8_t cols = 0; // number of columns (if cols == 0 then apply to the entire light)
+ uint8_t offs = 0; // offset in the led strip where the matrix starts (min: 0)
+ bool alt = false; // are the rows in alternate directions
+ uint16_t univ = 0; // start at universe number (+1)
+ uint16_t port = 6454; // UDP port number
+ uint8_t dimm = 100; // Dimmer 0..100
+ bool on = true;
+ bool matrix = true; // true if light is a WS2812 matrix, false if single light
+ // metrics
+ uint32_t packet_received = 0;
+ uint32_t packet_accepted = 0;
+ uint32_t strip_refresh = 0;
+} ArtNetConfig;
+
+uint32_t * packets_per_row = nullptr;
+
+ArtNetConfig artnet_conf;
+
+#ifdef ESP8266
+#include "UdpListener.h"
+UdpListener * ArtNetUdp = nullptr;
+#else
+WiFiUDP * ArtNetUdp;
+#endif
+
+bool artnet_udp_connected = false;
+// IPAddress artnet_udp_remote_ip; // remote IP address
+// uint16_t artnet_udp_remote_port; // remote port
+
+
+/*********************************************************************************************\
+ * ArtNet support
+\*********************************************************************************************/
+
+void ArtNetLoadSettings(void) {
+ // read settings and copy locally
+ artnet_conf.dimm = Settings->light_dimmer;
+ artnet_conf.cols = Settings->light_step_pixels;
+ artnet_conf.rows = (artnet_conf.cols != 0) ? Settings->light_pixels / artnet_conf.cols : 0;
+ artnet_conf.offs = Settings->light_rotation;
+ artnet_conf.alt = Settings->flag.ws_clock_reverse; // SetOption16
+ artnet_conf.univ = Settings->artnet_universe;
+ artnet_conf.on = (Light.power & 1);
+ ArtNetValidate();
+}
+
+// validate that parameters in artnet_conf are in valid ranges
+void ArtNetValidate(void) {
+ if (artnet_conf.dimm > 100) { artnet_conf.dimm = 100; }
+ if (artnet_conf.cols == 0 || artnet_conf.rows == 0) { artnet_conf.rows = 1; } // if single light, both are supposed to be 0
+ artnet_conf.matrix = (artnet_conf.cols > 0) && Ws2812StripConfigured();
+ if (artnet_conf.univ > 32767) { artnet_conf.univ = 0; }
+ if (artnet_conf.port == 0) { artnet_conf.port = 6454; }
+}
+
+void ArtNetSaveSettings(void) {
+ ArtNetValidate();
+ // write to settings
+ Settings->light_dimmer = artnet_conf.dimm;
+ Settings->light_step_pixels = artnet_conf.cols;
+ if (artnet_conf.cols > 0) { Settings->light_pixels = artnet_conf.rows * artnet_conf.cols; }
+ Settings->light_rotation = artnet_conf.offs;
+ Settings->artnet_universe = artnet_conf.univ;
+ Settings->flag.ws_clock_reverse = artnet_conf.alt; // SetOption16
+}
+
+
+bool ArtNetSetChannels(void)
+{
+ if (artnet_udp_connected && ArtNetUdp != nullptr) {
+ // ArtNet is running
+ if (artnet_conf.matrix) {
+ if (Light.power & 1) { return true; } // serviced, don't cascade to WS2812
+ } else {
+ return false; // if regular bulb, cascade change
+ }
+ } else if (Settings->flag6.artnet_autorun) {
+ // ArtNet is not running but is planned to get running
+ return true; // if ArtNet autorun is own but has not started yet, block update to lights
+ }
+ return false;
+}
+
+// process ArtNet packet
+// returns `true` if strip is dirty, i.e. we changed the value of some leds
+void ArtNetProcessPacket(uint8_t * buf, size_t len) {
+ artnet_conf.packet_received++;
+ if (buf == nullptr || len <= 18) { return; }
+ // is the signature correct?
+ // 4172742D4E657400
+ static const char ARTNET_SIG[] = "Art-Net";
+ if (memcmp(buf, ARTNET_SIG, sizeof(ARTNET_SIG))) { return; }
+
+ uint16_t opcode = buf[8] | (buf[9] << 8);
+ uint16_t protocol = (buf[10] << 8) | buf[11]; // Big Endian
+ uint16_t universe = buf[14] | (buf[15] << 8);
+ uint16_t datalen = (buf[16] << 8) | buf[17];
+ // AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("DMX: opcode=0x%04X procotol=%i universe=%i datalen=%i univ_start=%i univ_end=%i"), opcode, protocol, universe, datalen, artnet_conf.univ, artnet_conf.univ + artnet_conf.rows);
+ if (opcode != 0x5000 || protocol != 14) { return; }
+
+ if (len + 18 < datalen) {
+ AddLog(LOG_LEVEL_DEBUG, PSTR("DMX: packet is truncated, ignoring packet"));
+ }
+
+ if (universe < artnet_conf.univ || universe >= artnet_conf.univ + artnet_conf.rows) { return; } // universe is not ours, ignore
+ size_t idx = 18; // start of payload data in the UDP frame
+ uint16_t row = universe - artnet_conf.univ;
+
+ if (artnet_conf.matrix) {
+ // Ws2812 led strip
+ size_t pix_size = Ws2812StripGetPixelSize();
+ // check that datalen does not exceed the number of columns
+ if (datalen > artnet_conf.cols * pix_size) { datalen = artnet_conf.cols * pix_size; }
+ // round to exact number of pixels
+ datalen = datalen - (datalen % pix_size);
+
+ size_t offset_in_matrix = 0;
+ if (artnet_conf.alt && (row % 2)) {
+ for (int32_t i = idx, j = idx + datalen - pix_size; i < j; i += pix_size, j -= pix_size) {
+ for (int32_t k = 0; k < pix_size; k++) {
+ uint8_t temp = buf[i+k];
+ buf[i+k] = buf[j+k];
+ buf[j+k] = temp;
+ }
+ }
+ offset_in_matrix = artnet_conf.cols * pix_size - datalen; // add a potential offset if the frame is smaller than the columns
+ }
+
+ // process dimmer
+ if (artnet_conf.dimm != 100) {
+ // No Gamma for now
+ if (pix_size == 3) {
+ for (int32_t i = idx; i < idx+datalen; i += pix_size) {
+ buf[i] = changeUIntScale(buf[i], 0, 100, 0, artnet_conf.dimm);
+ buf[i+1] = changeUIntScale(buf[i+1], 0, 100, 0, artnet_conf.dimm);
+ buf[i+2] = changeUIntScale(buf[i+2], 0, 100, 0, artnet_conf.dimm);
+ }
+ } else if (pix_size == 4) {
+ for (int32_t i = idx; i < idx+datalen; i += pix_size) {
+ buf[i] = changeUIntScale(buf[i], 0, 100, 0, artnet_conf.dimm);
+ buf[i+1] = changeUIntScale(buf[i+1], 0, 100, 0, artnet_conf.dimm);
+ buf[i+2] = changeUIntScale(buf[i+2], 0, 100, 0, artnet_conf.dimm);
+ buf[i+3] = changeUIntScale(buf[i+2], 0, 100, 0, artnet_conf.dimm);
+ }
+ }
+ }
+
+ // process pixels
+ size_t h_bytes = artnet_conf.cols * pix_size; // size in bytes of a single row
+ offset_in_matrix += artnet_conf.offs * pix_size + row * h_bytes;
+ if (datalen > h_bytes) { datalen = h_bytes; } // copy at most one line
+
+ Ws2812CopyPixels(&buf[idx], datalen, offset_in_matrix);
+ } else {
+ // single light
+ uint8_t r8 = buf[idx+1];
+ uint8_t g8 = buf[idx];
+ uint8_t b8 = buf[idx+2];
+ uint16_t dimmer10 = changeUIntScale(artnet_conf.dimm, 0, 100, 0, 1023);
+ uint16_t color[LST_MAX] = {0};
+ color[0] = changeUIntScale(r8, 0, 255, 0, dimmer10);
+ color[1] = changeUIntScale(g8, 0, 255, 0, dimmer10);
+ color[2] = changeUIntScale(b8, 0, 255, 0, dimmer10);
+ // AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("DMX: %02X-%02X-%02X univ=%i rows=%i max_univ=%i"), buf[idx+1], buf[idx], buf[idx+2], universe, row, artnet_conf.univ + artnet_conf.rows);
+ LightSetOutputs(color);
+ }
+ // AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("DMX: ok universe=%i datalen=%i"), universe, datalen);
+ artnet_conf.packet_accepted++;
+ if (packets_per_row) {
+ packets_per_row[row]++;
+ }
+}
+
+//
+// Called at event loop, checks for incoming data from the CC2530
+//
+void ArtNetLoop(void)
+{
+ if (artnet_udp_connected && ArtNetUdp != nullptr) {
+ ArtNetLoadSettings();
+ bool packet_ready = false;
+ int32_t packet_len = 0;
+#ifdef ESP8266
+ packet_ready = ArtNetUdp->next();
+ while (packet_ready) {
+ UdpPacket *packet;
+ packet = ArtNetUdp->read();
+ uint8_t * packet_buffer = (uint8_t*) &packet->buf;
+ packet_len = packet->len;
+#else
+ packet_len = ArtNetUdp->parsePacket();
+ packet_ready = (packet_len > 0);
+ while (packet_ready) {
+ uint8_t packet_buffer[WS2812_ARTNET_UDP_BUFFER_SIZE]; // buffer to hold incoming UDP/SSDP packet
+
+ packet_len = ArtNetUdp->read(packet_buffer, WS2812_ARTNET_UDP_BUFFER_SIZE);
+ ArtNetUdp->flush(); // Finish reading the current packet
+#endif
+ // AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("UDP: Packet %*_H (%d)"), 32, packet_buffer, packet_len);
+ if (artnet_conf.on) {
+ ArtNetProcessPacket(packet_buffer, packet_len);
+ }
+
+#ifdef ESP8266
+ packet_ready = ArtNetUdp->next();
+ if (!packet_ready) {
+ // if no more incoming packet, still wait for 20 microseconds
+ delay(1); // delayMicroseconds seems broken, need to
+ packet_ready = ArtNetUdp->next();
+ }
+#else
+ packet_len = ArtNetUdp->parsePacket();
+ packet_ready = (packet_len > 0);
+ if (!packet_ready) {
+ // if no more incoming packet, still wait for 20 microseconds
+ delayMicroseconds(20);
+ packet_len = ArtNetUdp->parsePacket();
+ packet_ready = (packet_len > 0);
+ }
+#endif
+ }
+ if (artnet_conf.on) { // ignore action if not on
+ if (artnet_conf.matrix) {
+ if (Ws2812StripRefresh()) {
+ artnet_conf.strip_refresh++; // record metric
+ }
+ }
+ }
+ }
+}
+
+
+//
+// Published state
+//
+void ArtNetJSONAppend(void) {
+ if (artnet_udp_connected) {
+ ResponseAppend_P(PSTR(",\"ArtNet\":{\"PacketsReceived\":%u,\"PacketsAccepted\":%u,\"Frames\":%u"),
+ artnet_conf.packet_received, artnet_conf.packet_accepted, artnet_conf.strip_refresh);
+ if (packets_per_row) {
+ ResponseAppend_P(PSTR(",\"PacketsPerRow\":["));
+ for (int32_t i = 0; i < artnet_conf.rows; i++) {
+ ResponseAppend_P(PSTR("%s%i"), i ? "," : "", packets_per_row[i]);
+ }
+ ResponseAppend_P(PSTR("]"));
+ }
+ ResponseAppend_P(PSTR("}"));
+ }
+}
+
+//
+// Command `ArtNetConfig`
+// Params: JSON
+// {"Rows":5, "Cols":5, "Offset":0, "Alternate":false, "Universe":0, "Port":6454}
+//
+void CmndArtNetConfig() {
+ bool was_running = artnet_udp_connected;
+ if (was_running) {
+ ArtNetStop();
+ }
+ ArtNetLoadSettings();
+
+ TrimSpace(XdrvMailbox.data);
+ if (strlen(XdrvMailbox.data) > 0) {
+ JsonParser parser(XdrvMailbox.data);
+ JsonParserObject root = parser.getRootObject();
+ if (!root) { ResponseCmndChar_P(PSTR(D_JSON_INVALID_JSON)); return; }
+
+ artnet_conf.rows = root.getUInt(PSTR("Rows"), artnet_conf.rows);
+ artnet_conf.cols = root.getUInt(PSTR("Cols"), artnet_conf.cols);
+ artnet_conf.offs = root.getUInt(PSTR("Offset"), artnet_conf.offs);
+ artnet_conf.alt = root.getBool(PSTR("Alternate"), artnet_conf.alt);
+ artnet_conf.univ = root.getUInt(PSTR("Universe"), artnet_conf.univ);
+ artnet_conf.port = root.getUInt(PSTR("Port"), artnet_conf.port);
+ artnet_conf.dimm = root.getUInt(PSTR("Dimmer"), artnet_conf.dimm);
+
+ ArtNetSaveSettings();
+ }
+
+ if (was_running) {
+ ArtNetStart();
+ }
+ // display the current or new configuration
+ // {"Rows":5, "Cols":5, "Offset":0, "Alternate":false, "Universe":0, "Port":6454}
+ Response_P(PSTR("{\"Rows\":%u,\"Cols\":%u,\"Dimmer\":%u,\"Offset\":%u"
+ ",\"Alternate\":%s,\"Universe\":%u,\"Port\":%u}"),
+ artnet_conf.rows, artnet_conf.cols, artnet_conf.dimm, artnet_conf.offs,
+ artnet_conf.alt ? "true":"false", artnet_conf.univ, artnet_conf.port);
+}
+
+// ArtNetStart
+// Returns true if ok
+bool ArtNetStart(void) {
+ ArtNetLoadSettings();
+ if (!artnet_udp_connected && !TasmotaGlobal.restart_flag) {
+ if (ArtNetUdp == nullptr) {
+#ifdef ESP8266
+ ArtNetUdp = new UdpListener(WS2812_ARTNET_UDP_MAX_PACKETS);
+#else
+ ArtNetUdp = new WiFiUDP();
+#endif
+ if (ArtNetUdp == nullptr) {
+ AddLog(LOG_LEVEL_INFO, PSTR("DMX: cannot allocate memory"));
+ return false;
+ }
+ }
+
+#ifdef ESP8266
+ ArtNetUdp->reset();
+ ip_addr_t addr = IPADDR4_INIT(INADDR_ANY);
+ if ((igmp_joingroup(WiFi.localIP(), IPAddress(USE_LIGHT_ARTNET_MCAST)) == ERR_OK) &&
+ (ArtNetUdp->listen(&addr, artnet_conf.port))) {
+ // if (ArtNetUdp->listen(&addr, artnet_conf.port)) {
+#else
+ if (ArtNetUdp->beginMulticast(IPAddress(USE_LIGHT_ARTNET_MCAST), artnet_conf.port)) {
+#endif
+ // OK
+ AddLog(LOG_LEVEL_INFO, PSTR("DMX: listening to port %i"), artnet_conf.port);
+ artnet_udp_connected = true;
+
+ packets_per_row = (uint32_t*) malloc(artnet_conf.rows * sizeof(uint32_t*));
+ if (packets_per_row) { memset((void*)packets_per_row, 0, artnet_conf.rows * sizeof(uint32_t*)); }
+ // set sleep to at most 5
+ if (TasmotaGlobal.sleep > WS2812_ARTNET_MAX_SLEEP) {
+ TasmotaGlobal.sleep = WS2812_ARTNET_MAX_SLEEP;
+ }
+
+ // change settings to ArtNet specific scheme
+ Settings->flag6.artnet_autorun = true;
+
+ // change strip configuration
+ if (artnet_conf.matrix) {
+ if ((Settings->light_pixels != artnet_conf.rows * artnet_conf.cols + artnet_conf.offs) || (Settings->light_rotation != 0)) {
+ Settings->light_pixels = artnet_conf.rows * artnet_conf.cols + artnet_conf.offs;
+ Settings->light_rotation = 0;
+ Ws2812ReinitStrip();
+ } else {
+ Ws2812Clear();
+ }
+ }
+
+ // turn power on if it's not
+ if (!(Light.power & 1)) {
+ LightPowerOn();
+ }
+ } else {
+ AddLog(LOG_LEVEL_INFO, PSTR("DMX: error opening port %i"), artnet_conf.port);
+ return false;
+ }
+ }
+ return true;
+}
+
+// Stop the ArtNet UDP flow and disconnect server
+void ArtNetStop(void) {
+ artnet_udp_connected = false;
+ if (ArtNetUdp != nullptr) {
+#ifdef ESP8266
+ ArtNetUdp->disconnect();
+#else
+ ArtNetUdp->stop();
+#endif
+ delete ArtNetUdp;
+ ArtNetUdp = nullptr;
+ }
+ if (packets_per_row) {
+ free((void*)packets_per_row);
+ packets_per_row = nullptr;
+ }
+}
+
+void CmndArtNet(void) {
+ if (0 == XdrvMailbox.payload) {
+ ArtNetStop();
+ Settings->flag6.artnet_autorun = false; // SetOption148 - (Light) start DMX ArtNet at boot, listen to UDP port as soon as network is up
+// Settings->light_scheme = LS_POWER; // restore default scheme
+ TasmotaGlobal.sleep = Settings->sleep; // Restore sleep value
+ Light.update = true; // Restore old color
+ }
+ if (1 == XdrvMailbox.payload) {
+ if (!ArtNetStart()) {
+ Settings->flag6.artnet_autorun = false; // SetOption148 - (Light) start DMX ArtNet at boot, listen to UDP port as soon as network is up
+ }
+ }
+ ResponseCmndStateText(artnet_udp_connected & Settings->flag6.artnet_autorun);
+}
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool artnet_network_up = false;
+
+void ArtNetFuncNetworkUp(void) {
+ if (!artnet_network_up) {
+ artnet_network_up = true;
+ if (Settings->flag6.artnet_autorun) {
+ if (!ArtNetStart()) {
+ Settings->flag6.artnet_autorun = false; // disable autorun if it failed, avoid nasty loop errors
+ }
+ }
+ }
+}
+
+void ArtNetFuncNetworkDown(void) {
+ if (artnet_network_up) {
+ artnet_network_up = false;
+ ArtNetStop();
+ }
+}
+
+#endif // USE_LIGHT_ARTNET
+#endif // USE_LIGHT
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_04_light_utils.ino b/tasmota/tasmota_xdrv_driver/xdrv_04_light_utils.ino
index dffc12019..9567fdd48 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_04_light_utils.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_04_light_utils.ino
@@ -31,6 +31,19 @@ typedef struct gamma_table_t {
uint16_t to_gamma;
} gamma_table_t;
+const gamma_table_t ac_dimmer_table[] = { // don't put in PROGMEM for performance reasons
+ { 0, 0 },
+ { 10, 64 },
+ { 50, 175 },
+ { 100, 235 },
+ { 500, 485 },
+ { 900, 704 },
+ { 950, 748 },
+ { 990, 850 },
+ { 1024, 1024 },
+ { 0xFFFF, 0xFFFF } // fail-safe if out of range
+};
+
const gamma_table_t gamma_table[] = { // don't put in PROGMEM for performance reasons
{ 1, 1 },
{ 4, 1 },
@@ -318,6 +331,11 @@ uint16_t ledGammaReverse_internal(uint16_t vg, const struct gamma_table_t *gt_pt
}
}
+// 10 bits power select to 10 bits timing based on sinus curve
+uint16_t ac_zero_cross_power(uint16_t v) {
+ return ledGamma_internal(v, ac_dimmer_table);
+}
+
// 10 bits in, 10 bits out
uint16_t ledGamma10_10(uint16_t v) {
return ledGamma_internal(v, gamma_table);
@@ -345,4 +363,4 @@ uint16_t ledGammaFast(uint16_t v) {
uint16_t leddGammaReverseFast(uint16_t vg) {
return ledGammaReverse_internal(vg, gamma_table_fast);
-}
\ No newline at end of file
+}
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_05_irremote.ino b/tasmota/tasmota_xdrv_driver/xdrv_05_irremote.ino
index ba403f72f..0996484b5 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_05_irremote.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_05_irremote.ino
@@ -416,7 +416,7 @@ void IrRemoteCmndResponse(uint32_t error)
* Interface
\*********************************************************************************************/
-bool Xdrv05(uint8_t function)
+bool Xdrv05(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_05_irremote_full.ino b/tasmota/tasmota_xdrv_driver/xdrv_05_irremote_full.ino
index a74270de2..4ffb34a2c 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_05_irremote_full.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_05_irremote_full.ino
@@ -852,7 +852,7 @@ void IrInit(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv05(uint8_t function)
+bool Xdrv05(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_06_snfbridge.ino b/tasmota/tasmota_xdrv_driver/xdrv_06_snfbridge.ino
index c3aa42bd8..cf62932b4 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_06_snfbridge.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_06_snfbridge.ino
@@ -105,7 +105,7 @@ uint32_t rf_search_and_write(uint8_t *data, size_t size) {
if (rec_end == sizeof(buf)) { return 9; } // File too large - Failed to decode RF firmware
rec_size = rec_end - rec_start;
-// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t*)&buf + rec_start, rec_size);
+// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: %*_H"), rec_size, (uint8_t*)&buf + rec_start);
err = rf_decode_and_write(buf + rec_start, rec_size);
if (err != 0) { return err; }
@@ -128,6 +128,9 @@ uint8_t rf_erase_flash(void) {
}
err = c2_device_erase();
if (err != C2_SUCCESS) {
+
+// AddLog(LOG_LEVEL_DEBUG, PSTR("RFB: Device erase error %d"), err);
+
if (i < 3) {
c2_reset(); // Reset RF chip and try again
} else {
@@ -194,7 +197,7 @@ void SonoffBridgeReceived(void)
char rfkey[8];
char stemp[16];
- AddLogSerial(LOG_LEVEL_DEBUG);
+ AddLogSerial();
if (0xA2 == TasmotaGlobal.serial_in_buffer[0]) { // Learn timeout
SonoffBridgeLearnFailed();
@@ -535,7 +538,7 @@ void SonoffBridgeWebGetArg(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv06(uint8_t function)
+bool Xdrv06(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_07_domoticz.ino b/tasmota/tasmota_xdrv_driver/xdrv_07_domoticz.ino
index 7687ac644..6fa70cfc4 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_07_domoticz.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_07_domoticz.ino
@@ -641,7 +641,7 @@ void DomoticzSaveSettings(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv07(uint8_t function) {
+bool Xdrv07(uint32_t function) {
bool result = false;
if (Settings->flag.mqtt_enabled) { // SetOption3 - Enable MQTT
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_08_serial_bridge.ino b/tasmota/tasmota_xdrv_driver/xdrv_08_serial_bridge.ino
index e8c156a5d..bcb38fc90 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_08_serial_bridge.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_08_serial_bridge.ino
@@ -27,20 +27,23 @@
#define USE_SERIAL_BRIDGE_TEE
-#ifdef ESP8266
-const uint16_t SERIAL_BRIDGE_BUFFER_SIZE = MIN_INPUT_BUFFER_SIZE;
+#ifdef SERIAL_BRIDGE_BUFFER_SIZE
+const uint16_t SERIAL_BRIDGE_BUFSIZE = SERIAL_BRIDGE_BUFFER_SIZE;
#else
-const uint16_t SERIAL_BRIDGE_BUFFER_SIZE = INPUT_BUFFER_SIZE;
-#endif
+#ifdef ESP8266
+const uint16_t SERIAL_BRIDGE_BUFSIZE = MIN_INPUT_BUFFER_SIZE; // 256
+#else
+const uint16_t SERIAL_BRIDGE_BUFSIZE = INPUT_BUFFER_SIZE; // 800
+#endif // ESP32
+#endif // SERIAL_BRIDGE_BUFFER_SIZE
const char kSerialBridgeCommands[] PROGMEM = "|" // No prefix
- D_CMND_SSERIALSEND "|" D_CMND_SBAUDRATE "|" D_CMND_SSERIALCONFIG;
+ D_CMND_SSERIALSEND "|" D_CMND_SBAUDRATE "|" D_CMND_SSERIALBUFFER "|" D_CMND_SSERIALCONFIG;
void (* const SerialBridgeCommand[])(void) PROGMEM = {
- &CmndSSerialSend, &CmndSBaudrate, &CmndSSerialConfig };
+ &CmndSSerialSend, &CmndSBaudrate, &CmndSSerialBuffer, &CmndSSerialConfig };
#include
-
TasmotaSerial *SerialBridgeSerial = nullptr;
unsigned long serial_bridge_polling_window = 0;
@@ -73,7 +76,8 @@ void SerialBridgePrintf(PGM_P formatP, ...) {
va_end(arg);
if (data == nullptr) { return; }
- SerialBridgeSerial->printf(data);
+// SerialBridgeSerial->printf(data); // This resolves "MqttClientMask":"DVES_%06X" into "DVES_000002"
+ SerialBridgeSerial->print(data); // This does not resolve "DVES_%06X"
free(data);
}
#endif // USE_SERIAL_BRIDGE_TEE
@@ -91,7 +95,7 @@ void SerialBridgeInput(void) {
static bool serial_bridge_overrun = false;
if (isprint(serial_in_byte)) { // Any char between 32 and 127
- if (serial_bridge_in_byte_counter < SERIAL_BRIDGE_BUFFER_SIZE -1) { // Add char to string if it still fits
+ if (serial_bridge_in_byte_counter < SERIAL_BRIDGE_BUFSIZE -1) { // Add char to string if it still fits
serial_bridge_buffer[serial_bridge_in_byte_counter++] = serial_in_byte;
} else {
serial_bridge_overrun = true; // Signal overrun but continue reading input to flush until '\n' (EOL)
@@ -125,12 +129,12 @@ void SerialBridgeInput(void) {
((Settings->serial_delimiter == 128) && !isprint(serial_in_byte))) && // Any char not between 32 and 127
!serial_bridge_raw; // In raw mode (CMND_SERIALSEND3) there is never a delimiter
- if ((serial_bridge_in_byte_counter < SERIAL_BRIDGE_BUFFER_SIZE -1) && // Add char to string if it still fits and ...
+ if ((serial_bridge_in_byte_counter < SERIAL_BRIDGE_BUFSIZE -1) && // Add char to string if it still fits and ...
!in_byte_is_delimiter) { // Char is not a delimiter
serial_bridge_buffer[serial_bridge_in_byte_counter++] = serial_in_byte;
}
- if ((serial_bridge_in_byte_counter >= SERIAL_BRIDGE_BUFFER_SIZE -1) || // Send message when buffer is full or ...
+ if ((serial_bridge_in_byte_counter >= SERIAL_BRIDGE_BUFSIZE -1) || // Send message when buffer is full or ...
in_byte_is_delimiter) { // Char is delimiter
serial_bridge_polling_window = 0; // Publish now
break;
@@ -152,26 +156,31 @@ void SerialBridgeInput(void) {
serial_bridge_buffer[serial_bridge_in_byte_counter] = 0; // Serial data completed
bool assume_json = (!serial_bridge_raw && (serial_bridge_buffer[0] == '{'));
- Response_P(PSTR("{\"" D_JSON_SSERIALRECEIVED "\":"));
- if (assume_json) {
- ResponseAppend_P(serial_bridge_buffer);
- } else {
- ResponseAppend_P(PSTR("\""));
- if (serial_bridge_raw) {
- char hex_char[(serial_bridge_in_byte_counter * 2) + 2];
- ResponseAppend_P(ToHex_P((unsigned char*)serial_bridge_buffer, serial_bridge_in_byte_counter, hex_char, sizeof(hex_char)));
- } else {
- ResponseAppend_P(EscapeJSONString(serial_bridge_buffer).c_str());
- }
- ResponseAppend_P(PSTR("\""));
- }
- ResponseJsonEnd();
+ TasmotaGlobal.serial_skip++; // SetOption35 Skip number of serial messages received (default 0)
+ if (TasmotaGlobal.serial_skip > Settings->param[P_SERIAL_SKIP]) { // Handle intermediate changes to SetOption35
+ TasmotaGlobal.serial_skip = 0;
+
+ Response_P(PSTR("{\"" D_JSON_SSERIALRECEIVED "\":"));
+ if (assume_json) {
+ ResponseAppend_P(serial_bridge_buffer);
+ } else {
+ ResponseAppend_P(PSTR("\""));
+ if (serial_bridge_raw) {
+ ResponseAppend_P(PSTR("%*_H"), serial_bridge_in_byte_counter, serial_bridge_buffer);
+ } else {
+ ResponseAppend_P(EscapeJSONString(serial_bridge_buffer).c_str());
+ }
+ ResponseAppend_P(PSTR("\""));
+ }
+ ResponseJsonEnd();
+
+ if (Settings->flag6.mqtt_disable_sserialrec ) { // SetOption147 If it is activated, Tasmota will not publish SSerialReceived MQTT messages, but it will proccess event trigger rules
+ XdrvRulesProcess(0);
+ } else {
+ MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_SSERIALRECEIVED));
+ }
+ }
- if (Settings->flag6.mqtt_disable_sserialrec ) { // SetOption147 If it is activated, Tasmota will not publish SSerialReceived MQTT messages, but it will proccess event trigger rules
- XdrvRulesProcess(0);
- } else {
- MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_SSERIALRECEIVED));
- }
serial_bridge_in_byte_counter = 0;
}
}
@@ -180,16 +189,20 @@ void SerialBridgeInput(void) {
void SerialBridgeInit(void) {
if (PinUsed(GPIO_SBR_RX) && PinUsed(GPIO_SBR_TX)) {
- SerialBridgeSerial = new TasmotaSerial(Pin(GPIO_SBR_RX), Pin(GPIO_SBR_TX), HARDWARE_FALLBACK);
+// SerialBridgeSerial = new TasmotaSerial(Pin(GPIO_SBR_RX), Pin(GPIO_SBR_TX), HARDWARE_FALLBACK); // Default TM_SERIAL_BUFFER_SIZE (=64) size
+ SerialBridgeSerial = new TasmotaSerial(Pin(GPIO_SBR_RX), Pin(GPIO_SBR_TX), HARDWARE_FALLBACK, 0, MIN_INPUT_BUFFER_SIZE); // 256
if (SetSSerialBegin()) {
if (SerialBridgeSerial->hardwareSerial()) {
ClaimSerial();
serial_bridge_buffer = TasmotaGlobal.serial_in_buffer; // Use idle serial buffer to save RAM
} else {
- serial_bridge_buffer = (char*)(malloc(SERIAL_BRIDGE_BUFFER_SIZE));
+ serial_bridge_buffer = (char*)(malloc(SERIAL_BRIDGE_BUFSIZE));
}
SerialBridgeSerial->flush();
SerialBridgePrintf("\r\n");
+#ifdef ESP32
+ AddLog(LOG_LEVEL_DEBUG, PSTR("SBR: Serial UART%d"), SerialBridgeSerial->getUart());
+#endif
}
}
}
@@ -199,6 +212,7 @@ void SerialBridgeInit(void) {
\*********************************************************************************************/
void CmndSSerialSend(void) {
+ if (XdrvMailbox.index > 9) { XdrvMailbox.index -= 10; }
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 6)) {
serial_bridge_raw = (XdrvMailbox.index > 3);
Settings->sbflag1.serbridge_console = 0; // Disable console Tee
@@ -260,6 +274,28 @@ void CmndSBaudrate(void) {
ResponseCmndNumber(Settings->sbaudrate * 300);
}
+void CmndSSerialBuffer(void) {
+ // Allow non-pesistent serial receive buffer size change
+ if (SerialBridgeSerial->hardwareSerial()) {
+ // between MIN_INPUT_BUFFER_SIZE and MAX_INPUT_BUFFER_SIZE characters
+ CmndSerialBuffer();
+ } else {
+ // ESP8266 (software serial): between MIN_INPUT_BUFFER_SIZE and SERIAL_BRIDGE_BUFSIZE characters
+ // ESP32 (hardware serial only): between MIN_INPUT_BUFFER_SIZE and MAX_INPUT_BUFFER_SIZE characters
+ if (XdrvMailbox.data_len > 0) {
+ size_t size = XdrvMailbox.payload;
+ if (XdrvMailbox.payload < MIN_INPUT_BUFFER_SIZE) {
+ size = MIN_INPUT_BUFFER_SIZE; // 256 / 256
+ }
+ else if (XdrvMailbox.payload > SERIAL_BRIDGE_BUFSIZE) {
+ size = SERIAL_BRIDGE_BUFSIZE; // 256 / 800
+ }
+ SerialBridgeSerial->setRxBufferSize(size);
+ }
+ ResponseCmndNumber(SerialBridgeSerial->getRxBufferSize());
+ }
+}
+
void CmndSSerialConfig(void) {
// See TasmotaSerialConfig for possible options
// SSerialConfig 0..23 where 3 equals 8N1
@@ -285,7 +321,7 @@ void CmndSSerialConfig(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv08(uint8_t function) {
+bool Xdrv08(uint32_t function) {
bool result = false;
if (FUNC_PRE_INIT == function) {
@@ -294,6 +330,7 @@ bool Xdrv08(uint8_t function) {
else if (serial_bridge_buffer) {
switch (function) {
case FUNC_LOOP:
+ case FUNC_SLEEP_LOOP:
SerialBridgeInput();
break;
case FUNC_COMMAND:
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_09_timers.ino b/tasmota/tasmota_xdrv_driver/xdrv_09_timers.ino
index 438ade4d5..8575cf685 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_09_timers.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_09_timers.ino
@@ -253,10 +253,10 @@ uint16_t TimerGetTimeOfDay(uint8_t index)
int16_t xtime = xtimer.time;
#ifdef USE_SUNRISE
if (xtimer.mode) {
- if (xtime >= 12*60) xtime = 12*60 - xtime;
- xtime += (int16_t)SunMinutes(xtimer.mode-1);
- if (xtime < 0) xtime += 24*60;
- if (xtime >= 24*60) xtime -= 24*60;
+ ApplyTimerOffsets(&xtimer);
+ xtime = xtimer.time;
+ if (xtime==2047 && xtimer.mode==1) xtime *= -1; // Sun always has already rises
+ if (xtime==2046 && xtimer.mode==2) xtime *= -1; // Sun always has already set
}
#endif
return xtime;
@@ -946,7 +946,7 @@ void TimerSaveSettings(void)
* Interface
\*********************************************************************************************/
-bool Xdrv09(uint8_t function)
+bool Xdrv09(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino
index 6686b8770..6f9003d70 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_10_rules.ino
@@ -1458,19 +1458,7 @@ bool findNextVariableValue(char * &pVarname, float &value)
} else if (sVarName.startsWith(F("TIMER"))) {
uint32_t index = sVarName.substring(5).toInt();
if (index > 0 && index <= MAX_TIMERS) {
- value = Settings->timer[index -1].time;
-#if defined(USE_SUNRISE)
- // Correct %timerN% values for sunrise/sunset timers
- if ((1 == Settings->timer[index -1].mode) || (2 == Settings->timer[index -1].mode)) {
- // in this context, time variable itself is merely an offset, with <720 being negative
- value += -720 + SunMinutes(Settings->timer[index -1].mode -1);
- if (2 == Settings->timer[index -1].mode) {
- // To aid rule comparative statements, sunset past midnight (high lattitudes) is expressed past 24h00
- // So sunset at 00h45 is at 24h45
- if (value < 360) { value += 1440; }
- }
- }
-#endif // USE_SUNRISE
+ value = TimerGetTimeOfDay(index -1);
}
#if defined(USE_SUNRISE)
} else if (sVarName.equals(F("SUNRISE"))) {
@@ -2453,7 +2441,7 @@ float map_double(float x, float in_min, float in_max, float out_min, float out_m
* Interface
\*********************************************************************************************/
-bool Xdrv10(uint8_t function)
+bool Xdrv10(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino
index 66d699bab..1f8596ec3 100755
--- a/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_10_scripter.ino
@@ -76,6 +76,7 @@ keywords if then else endif, or, and are better readable for beginners (others m
#define MAX_SARRAY_NUM 32
#endif
+void Draw_jpeg(uint8_t *mem, uint16_t jpgsize, uint16_t xp, uint16_t yp, uint8_t scale);
uint32_t EncodeLightId(uint8_t relay_id);
uint32_t DecodeLightId(uint32_t hue_id);
char *web_send_line(char mc, char *lp);
@@ -182,7 +183,7 @@ void Script_ticker4_end(void) {
#endif
#if defined(USE_SML_M) && defined (USE_SML_SCRIPT_CMD)
-extern uint8_t sml_json_enable;
+extern uint8_t sml_options;
#endif
#if defined(EEP_SCRIPT_SIZE) && !defined(ESP32)
@@ -468,6 +469,7 @@ struct SCRIPT_MEM {
char *fast_script = 0;
char *event_script = 0;
char *html_script = 0;
+ char *teleperiod = 0;
char *web_pages[10];
uint32_t script_lastmillis;
bool event_handeled = false;
@@ -1877,6 +1879,117 @@ if (hsv.S == 0) {
}
#endif //USE_LIGHT
+#ifdef ESP32
+#ifdef JPEG_PICTS
+#ifdef STREAM_JPEG_PICTS
+struct JPG_TASK {
+ char boundary[40];
+ bool draw;
+ uint8_t scale;
+ uint16_t xp;
+ uint16_t yp;
+ WiFiClient stream;
+ HTTPClient http;
+} jpg_task;
+
+// "e8b8c539-047d-4777-a985-fbba6edff11e"
+
+int32_t fetch_jpg(uint32_t sel, char *url, uint32_t xp, uint32_t yp, uint32_t scale) {
+ char hbuff[64];
+ int32_t httpCode = 0;
+ const char * headerKeys[] = {"Content-Type", "Content-Length"} ;
+ const size_t numberOfHeaders = 2;
+
+ switch (sel) {
+ case 0:
+ // open
+ jpg_task.boundary[0] = 0;
+ jpg_task.draw = false;
+ jpg_task.xp = xp;
+ jpg_task.yp = yp;
+ jpg_task.scale = scale;
+ sprintf(hbuff,"http://%s", url);
+ jpg_task.http.begin(jpg_task.stream, hbuff);
+ jpg_task.http.collectHeaders(headerKeys, numberOfHeaders);
+ httpCode = jpg_task.http.GET();
+ if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
+ String boundary = jpg_task.http.header(headerKeys[0]);
+ char *cp = strchr(boundary.c_str(), '=');
+ if (cp) {
+ strcpy(jpg_task.boundary,cp + 1);
+ }
+ } else {
+ AddLog(LOG_LEVEL_INFO,PSTR("HTTP error %d = %s"), httpCode, jpg_task.http.errorToString(httpCode).c_str());
+ }
+ return httpCode;
+ break;
+ case 1:
+ // close
+ jpg_task.stream.stop();
+ jpg_task.http.end();
+ break;
+ case 2:
+ // get next frame
+ /*Wc.client.print("--" BOUNDARY "\r\n");
+ Wc.client.printf("Content-Type: image/jpeg\r\n"
+ "Content-Length: %d\r\n"
+ "\r\n", static_cast(_jpg_buf_len));
+ */
+ {
+ if (jpg_task.http.connected()) {
+ char inbuff[64];
+ memset(inbuff, 0, sizeof(inbuff));
+ jpg_task.stream.readBytesUntil('\n', inbuff, sizeof(inbuff));
+ if (inbuff[0] == '\r') {
+ memset(inbuff, 0, sizeof(inbuff));
+ jpg_task.stream.readBytesUntil('\n', inbuff, sizeof(inbuff));
+ }
+ //AddLog(LOG_LEVEL_INFO, PSTR("boundary = %s"), inbuff);
+ memset(inbuff, 0, sizeof(inbuff));
+ jpg_task.stream.readBytesUntil('\n', inbuff, sizeof(inbuff));
+ //AddLog(LOG_LEVEL_INFO, PSTR("type = %s"), inbuff);
+ memset(inbuff, 0, sizeof(inbuff));
+ jpg_task.stream.readBytesUntil('\n', inbuff, sizeof(inbuff));
+ //AddLog(LOG_LEVEL_INFO, PSTR("size = %s"), inbuff);
+ char *cp = strchr(inbuff, ':');
+ uint16_t size = 0;
+ if (cp) {
+ size = atoi(cp + 1);
+ }
+ jpg_task.stream.readBytesUntil('\n', inbuff, sizeof(inbuff));
+
+ if (size > 0) {
+ //AddLog(LOG_LEVEL_INFO, PSTR("size = %d"), size);
+ uint8_t *buff = (uint8_t *)special_malloc(size);
+ if (buff) {
+ jpg_task.stream.readBytes(buff, size);
+ }
+ if (jpg_task.draw) {
+ Draw_jpeg(buff, size, jpg_task.xp, jpg_task.yp, jpg_task.scale);
+ }
+ if (buff) {
+ free(buff);
+ }
+ }
+ return size;
+ }
+ }
+ break;
+ case 3:
+ // stop drawing
+ jpg_task.draw = false;
+ break;
+ case 4:
+ // resume drawing
+ jpg_task.draw = true;
+ break;
+ }
+ return 0;
+}
+#endif // STREAM_JPEG_PICTS
+#endif // JPEG_PICTS
+#endif // ESP32
+
#ifdef USE_ANGLE_FUNC
uint32_t pulse_time_hl;
@@ -3575,12 +3688,41 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value);
#endif // ESP32
break;
+#ifdef ESP32
+#ifdef JPEG_PICTS
+#ifdef STREAM_JPEG_PICTS
+ case 'j':
+ if (!strncmp(lp, "jpg(", 4)) {
+ lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, 0);
+ uint8_t selector = fvar;
+ switch (selector) {
+ case 0:
+ // start streaming
+ char url[SCRIPT_MAXSSIZE];
+ lp = GetStringArgument(lp, OPER_EQU, url, 0);
+ float xp, yp, scale ;
+ lp = GetNumericArgument(lp, OPER_EQU, &xp, 0);
+ lp = GetNumericArgument(lp, OPER_EQU, &yp, 0);
+ lp = GetNumericArgument(lp, OPER_EQU, &scale, 0);
+ fvar = fetch_jpg(0, url, xp, yp, scale);
+ break;
+ default:
+ // other cmds
+ fvar = fetch_jpg(selector, 0, 0, 0, 0);
+ break;
+ }
+ goto nfuncexit;
+ }
+ break;
+#endif // STREAM_JPEG_PICTS
+#endif // JPEG_PICTS
+#endif // ESP32
+
#ifdef USE_KNX
case 'k':
if (!strncmp(lp, "knx(", 4)) {
float type;
lp = GetNumericArgument(lp + 4, OPER_EQU, &type, gv);
- SCRIPT_SKIP_SPACES
lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv);
SCRIPT_SKIP_SPACES
KnxSensor(type, fvar);
@@ -3942,6 +4084,10 @@ extern void W8960_SetGain(uint8_t sel, uint16_t value);
}
goto strexit;
}
+ if (!strncmp(lp, "rax", 3)) {
+ TasmotaGlobal.no_autoexec = 0;
+ goto exit;
+ }
break;
case 's':
@@ -4219,7 +4365,7 @@ extern char *SML_GetSVal(uint32_t index);
goto nfuncexit;
}
if (!strncmp(vname, "smlj", 4)) {
- fvar = sml_json_enable;
+ fvar = sml_options;
tind->index = SML_JSON_ENABLE;
goto exit_settable;
}
@@ -5880,7 +6026,8 @@ int16_t retval;
if (!glob_script_mem.scriptptr) {
return -99;
}
- if (tasm_cmd_activ && tlen > 0) return 0;
+ if (tasm_cmd_activ && tlen >= 0) return 0;
+
struct GVARS gv;
gv.jo = 0;
retval = Run_script_sub(type, tlen, &gv);
@@ -5895,7 +6042,7 @@ int16_t retval;
return -99;
}
- if (tasm_cmd_activ && tlen>0) return 0;
+ if (tasm_cmd_activ && tlen >= 0) return 0;
struct GVARS gv;
@@ -6663,7 +6810,7 @@ getnext:
break;
#if defined(USE_SML_M) && defined (USE_SML_SCRIPT_CMD)
case SML_JSON_ENABLE:
- sml_json_enable = *dfvar;
+ sml_options = *dfvar;
break;
#endif
}
@@ -6917,7 +7064,8 @@ void ScripterEvery100ms(void) {
if (ResponseLength()) {
ResponseJsonStart();
ResponseJsonEnd();
- Run_Scripter(">T", 2, ResponseData());
+ //Run_Scripter(">T", 2, ResponseData());
+ if (glob_script_mem.teleperiod) Run_Scripter(glob_script_mem.teleperiod, 0, ResponseData());
}
}
if (bitRead(Settings->rule_enabled, 0)) {
@@ -7409,6 +7557,7 @@ void set_callbacks() {
if (Run_Scripter1(">F", -2, 0) == 99) {glob_script_mem.fast_script = glob_script_mem.section_ptr + 2;} else {glob_script_mem.fast_script = 0;}
if (Run_Scripter1(">E", -2, 0) == 99) {glob_script_mem.event_script = glob_script_mem.section_ptr + 2;} else {glob_script_mem.event_script = 0;}
if (Run_Scripter1(">C", -2, 0) == 99) {glob_script_mem.html_script = glob_script_mem.section_ptr + 2;} else {glob_script_mem.html_script = 0;}
+ if (Run_Scripter1(">T", -2, 0) == 99) {glob_script_mem.teleperiod = glob_script_mem.section_ptr + 2;} else {glob_script_mem.teleperiod = 0;}
}
void set_wpages(char *id, uint16_t index) {
@@ -7567,14 +7716,14 @@ else light_status += "true";
light_status += ",";
break;
*/
-
+String GetHueDeviceId(uint16_t id, uint8_t ep);
void Script_HueStatus(String *response, uint16_t hue_devs) {
if (hue_script[hue_devs].type=='p') {
*response += FPSTR(SCRIPT_HUE_LIGHTS_STATUS_JSON2);
response->replace("{j1", hue_script[hue_devs].name);
- response->replace("{j2", GetHueDeviceId(hue_devs));
+ response->replace("{j2", GetHueDeviceId(hue_devs, 0));
uint8_t pwr = glob_script_mem.fvars[hue_script[hue_devs].index[0] - 1];
response->replace("{state}", (pwr ? "true" : "false"));
return;
@@ -7648,7 +7797,7 @@ void Script_HueStatus(String *response, uint16_t hue_devs) {
response->replace("{light_status}", light_status);
response->replace("{j1", hue_script[hue_devs].name);
- response->replace("{j2", GetHueDeviceId(hue_devs));
+ response->replace("{j2", GetHueDeviceId(hue_devs, 0));
}
@@ -8047,7 +8196,7 @@ bool ScriptCommand(void) {
float *fpd = 0;
uint16_t alend;
char *cp = get_array_by_name(lp, &fpd, &alend, 0);
- if (fpd && cp) {
+ if (fpd && cp && (!strchr(lp, '[')) ) {
// is array
Response_P(PSTR("{\"script\":{\"%s\":["), lp);
for (uint16_t cnt = 0; cnt < alend; cnt++) {
@@ -9064,7 +9213,7 @@ uint16_t cipos = 0;
if (*lp == ')' || *lp == 0) break;
char *lp1 = lp;
float sysvar;
- lp=isvar(lp, &vtype, &ind, &sysvar, 0, 0);
+ lp = isvar(lp, &vtype, &ind, &sysvar, 0, 0);
if (vtype != VAR_NV) {
SCRIPT_SKIP_SPACES
uint8_t index = glob_script_mem.type[ind.index].index;
@@ -9813,12 +9962,12 @@ exgc:
lp++;
strcpy_P(stacked,"true");
}
- if (*lp=='2') {
+ if (*lp == '2') {
lp++;
nanum = 2;
y2f = 1;
}
- if (*lp=='t') {
+ if (*lp == 't') {
lp++;
tonly = 1;
}
@@ -9837,6 +9986,7 @@ exgc:
if (!ind.bits.constant && glob_script_mem.type[ind.index].bits.is_filter) {
// is 1. array
lp = slp;
+ max_entries = 0;
}
}
}
@@ -9864,7 +10014,7 @@ exgc:
// we know how many arrays and the number of entries
//Serial.printf("arrays %d\n",anum);
//Serial.printf("entries %d\n",entries);
- if (gs_ctype=='T') {
+ if (gs_ctype == 'T') {
if (anum && !(entries & 1)) {
WSContentSend_P(SCRIPT_MSG_GTABLEa);
char label[SCRIPT_MAXSSIZE];
@@ -9872,7 +10022,7 @@ exgc:
SCRIPT_SKIP_SPACES
char lab2[SCRIPT_MAXSSIZE];
lab2[0] = 0;
- if (*lp!=')') {
+ if (*lp != ')') {
lp = GetStringArgument(lp, OPER_EQU, lab2, 0);
WSContentSend_P(SCRIPT_MSG_GTABLEe);
} else {
@@ -9923,6 +10073,7 @@ exgc:
//goto nextwebline;
}
} else {
+
// we need to fetch the labels now
WSContentSend_P(SCRIPT_MSG_GTABLEa);
lp = gc_send_labels(lp, anum);
@@ -9948,13 +10099,15 @@ exgc:
hmflg = 1;
cp++;
}
+ // cnth2016/240
+
//todflg=atoi(&label[3]);
todflg = strtol(cp, &cp, 10);
if (!hmflg) {
if (todflg >= entries) todflg = entries - 1;
if (todflg < 0) todflg = 0;
}
- if (*cp=='/') {
+ if (*cp == '/') {
cp++;
divflg = strtol(cp, &cp, 10);
}
@@ -9974,7 +10127,6 @@ exgc:
divflg = entries / segments;
if (!divflg) divflg = 1;
}
-
uint32_t aind = ipos;
if (aind >= entries) aind = entries - 1;
for (uint32_t cnt = 0; cnt < entries; cnt++) {
@@ -11116,7 +11268,7 @@ void script_add_subpage(uint8_t num) {
-bool Xdrv10(uint8_t function)
+bool Xdrv10(uint32_t function)
{
bool result = false;
glob_script_mem.event_handeled = false;
@@ -11326,7 +11478,8 @@ bool Xdrv10(uint8_t function)
case FUNC_TELEPERIOD_RULES_PROCESS:
if (bitRead(Settings->rule_enabled, 0)) {
if (ResponseLength()) {
- Run_Scripter(">T", 2, ResponseData());
+ //Run_Scripter(">T", 2, ResponseData());
+ if (glob_script_mem.teleperiod) Run_Scripter(glob_script_mem.teleperiod, 0, ResponseData());
}
}
break;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_11_knx.ino b/tasmota/tasmota_xdrv_driver/xdrv_11_knx.ino
index bb3d0ae71..04d1225d3 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_11_knx.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_11_knx.ino
@@ -52,6 +52,8 @@ uint8_t Settings->knx_CB_param[MAX_KNX_CB] Type of Output (set relay,
#include // KNX Library
+bool knx_started = false;
+
address_t KNX_physs_addr; // Physical KNX address of this device
address_t KNX_addr; // KNX Address converter variable
@@ -491,7 +493,7 @@ void KNX_INIT(void)
device_param[KNX_HUMIDITY-1].show = true;
}
#ifdef USE_DS18x20
- if (PinUsed(GPIO_DSB)) {
+ if (PinUsed(GPIO_DSB, GPIO_ANY)) {
device_param[KNX_TEMPERATURE-1].show = true;
}
#endif
@@ -1298,7 +1300,7 @@ void CmndKnxCb(void)
* Interface
\*********************************************************************************************/
-bool Xdrv11(uint8_t function)
+bool Xdrv11(uint32_t function)
{
bool result = false;
switch (function) {
@@ -1329,6 +1331,15 @@ bool Xdrv11(uint8_t function)
case FUNC_PRE_INIT:
KNX_INIT();
break;
+ case FUNC_NETWORK_UP:
+ if (!knx_started && Settings->flag.knx_enabled) { // CMND_KNX_ENABLED
+ KNXStart();
+ knx_started = true;
+ }
+ break;
+ case FUNC_NETWORK_DOWN:
+ knx_started = false;
+ break;
// case FUNC_SET_POWER:
// break;
}
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_98_file_settings_demo.ino b/tasmota/tasmota_xdrv_driver/xdrv_122_file_settings_demo.ino
similarity index 98%
rename from tasmota/tasmota_xdrv_driver/xdrv_98_file_settings_demo.ino
rename to tasmota/tasmota_xdrv_driver/xdrv_122_file_settings_demo.ino
index e4459aeb7..8be544611 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_98_file_settings_demo.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_122_file_settings_demo.ino
@@ -1,5 +1,5 @@
/*
- xdrv_98_file_settings_demo.ino - Demo for Tasmota
+ xdrv_122_file_settings_demo.ino - Demo for Tasmota
Copyright (C) 2021 Theo Arends
@@ -174,7 +174,7 @@ void DrvDemoSettingsSave(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv98(uint8_t function) {
+bool Xdrv98(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_99_debug.ino b/tasmota/tasmota_xdrv_driver/xdrv_127_debug.ino
similarity index 97%
rename from tasmota/tasmota_xdrv_driver/xdrv_99_debug.ino
rename to tasmota/tasmota_xdrv_driver/xdrv_127_debug.ino
index 61896a610..5a02108eb 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_99_debug.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_127_debug.ino
@@ -1,5 +1,5 @@
/*
- xdrv_99_debug.ino - debug support for Tasmota
+ xdrv_127_debug.ino - debug support for Tasmota
Copyright (C) 2021 Theo Arends
@@ -32,7 +32,7 @@
* Needs file zzzz_debug.ino due to DEFINE processing
\*********************************************************************************************/
-#define XDRV_99 99
+#define XDRV_127 127
#ifndef CPU_LOAD_CHECK
#define CPU_LOAD_CHECK 1 // Seconds between each CPU_LOAD log
@@ -46,6 +46,7 @@
#define D_CMND_CFGDUMP "CfgDump"
#define D_CMND_CFGPEEK "CfgPeek"
#define D_CMND_CFGPOKE "CfgPoke"
+#define D_CMND_SHOWHEAP "ShowHeap"
#define D_CMND_CFGXOR "CfgXor"
#define D_CMND_CPUCHECK "CpuChk"
#define D_CMND_EXCEPTION "Exception"
@@ -62,6 +63,11 @@
const char kDebugCommands[] PROGMEM = "|" // No prefix
D_CMND_MEMDUMP "|" D_CMND_CFGDUMP "|" D_CMND_CFGPEEK "|" D_CMND_CFGPOKE "|"
+#ifdef ESP8266
+#ifdef UMM_INLINE_METRICS
+ D_CMND_SHOWHEAP "|"
+#endif
+#endif
#ifdef USE_WEBSERVER
D_CMND_CFGXOR "|"
#endif
@@ -77,6 +83,11 @@ const char kDebugCommands[] PROGMEM = "|" // No prefix
void (* const DebugCommand[])(void) PROGMEM = {
&CmndMemDump, &CmndCfgDump, &CmndCfgPeek, &CmndCfgPoke,
+#ifdef ESP8266
+#ifdef UMM_INLINE_METRICS
+ &CmndShowHeap,
+#endif
+#endif
#ifdef USE_WEBSERVER
&CmndCfgXor,
#endif
@@ -355,7 +366,6 @@ void DebugDump(uint32_t start, uint32_t size) {
}
}
-
void DebugCfgDump(char* parms)
{
uint32_t CFG_COLS = 16;
@@ -522,6 +532,15 @@ void CmndCfgPoke(void)
ResponseCmndDone();
}
+#ifdef ESP8266
+#ifdef UMM_INLINE_METRICS
+void CmndShowHeap(void) {
+ system_show_malloc();
+ ResponseCmndDone();
+}
+#endif
+#endif
+
#ifdef USE_WEBSERVER
void CmndCfgXor(void)
{
@@ -640,7 +659,7 @@ void CmndI2cWrite(void)
}
if (index > 1) {
- AddLogBuffer(LOG_LEVEL_INFO, buffer, index);
+ AddLog(LOG_LEVEL_INFO, PSTR("DBG: CmndI2cWrite %*_H"), index, buffer);
Wire.beginTransmission(buffer[0]);
for (uint32_t i = 1; i < index; i++) {
@@ -679,7 +698,7 @@ void CmndI2cRead(void)
buffer[index++] = Wire.read();
}
if (index > 0) {
- AddLogBuffer(LOG_LEVEL_INFO, buffer, index);
+ AddLog(LOG_LEVEL_INFO, PSTR("DBG: CmndI2cRead %*_H"), index, buffer);
}
}
}
@@ -709,7 +728,7 @@ void CmndI2cClock(void)
* Interface
\*********************************************************************************************/
-bool Xdrv99(uint8_t function)
+bool Xdrv127(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino b/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino
index 25632cd32..a7cbe6c6e 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino
@@ -298,7 +298,7 @@ void CmndTasDiscover(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv12(uint8_t function) {
+bool Xdrv12(uint32_t function) {
bool result = false;
if (Settings->flag.mqtt_enabled) { // SetOption3 - Enable MQTT
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino b/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino
index e9e976acb..531d8463e 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_12_home_assistant.ino
@@ -1271,7 +1271,7 @@ void HassLwtSubscribe(bool hasslwt)
* Interface
\*********************************************************************************************/
-bool Xdrv12(uint8_t function)
+bool Xdrv12(uint32_t function)
{
bool result = false;
bool hasslwt = HOME_ASSISTANT_LWT_SUBSCRIBE;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino b/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino
index 99033c4e1..547fdde95 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_13_display.ino
@@ -477,6 +477,7 @@ void DisplayText(void)
escape = 1;
cp++;
// if string in buffer print it
+ dp -= decode_te(linebuf);
if ((uint32_t)dp - (uint32_t)linebuf) {
if (!fill) { *dp = 0; }
if (col > 0 && lin > 0) {
@@ -585,12 +586,17 @@ void DisplayText(void)
break;
#ifdef USE_UFILESYS
case 'P':
- { char *ep=strchr(cp,':');
+ { char *ep = strchr(cp,':');
if (ep) {
- *ep=0;
+ *ep = 0;
ep++;
- Draw_RGB_Bitmap(cp,disp_xpos,disp_ypos, false);
- cp=ep;
+ int16_t scale = 0;
+ if (isdigit(*ep)) {
+ var = atoiv(ep, &scale);
+ ep += var;
+ }
+ Draw_RGB_Bitmap(cp,disp_xpos,disp_ypos, scale, false);
+ cp = ep;
}
}
break;
@@ -862,7 +868,7 @@ void DisplayText(void)
cp = get_string(bbuff, sizeof(bbuff), cp);
char unit[4];
cp = get_string(unit, sizeof(unit), cp);
- decode_te(unit);
+ decode_te(unit);
define_dt_var(num, gxp, gyp, textbcol, textfcol, font, textsize, txlen, time, dp, bbuff, unit);
}
}
@@ -2271,7 +2277,7 @@ char ppath[16];
} else {
strcat(ppath, ".jpg");
}
- Draw_RGB_Bitmap(ppath, xp, yp, inverted);
+ Draw_RGB_Bitmap(ppath, xp, yp, 0, inverted);
}
#endif // USE_TOUCH_BUTTONS
@@ -2281,51 +2287,62 @@ char ppath[16];
#include "img_converters.h"
#include "esp_jpg_decode.h"
bool jpg2rgb888(const uint8_t *src, size_t src_len, uint8_t * out, jpg_scale_t scale);
+bool jpg2rgb565(const uint8_t *src, size_t src_len, uint8_t * out, jpg_scale_t scale);
char get_jpeg_size(unsigned char* data, unsigned int data_size, unsigned short *width, unsigned short *height);
#endif // JPEG_PICTS
#endif // ESP32
+//#define SLOW_RGB16
+
#ifdef USE_UFILESYS
extern FS *ufsp;
#define XBUFF_LEN 128
-void Draw_RGB_Bitmap(char *file,uint16_t xp, uint16_t yp, bool inverted ) {
+void Draw_RGB_Bitmap(char *file, uint16_t xp, uint16_t yp, uint8_t scale, bool inverted ) {
if (!renderer) return;
File fp;
- char *ending = strrchr(file,'.');
- if (!ending) return;
- ending++;
- char estr[8];
- memset(estr,0,sizeof(estr));
- for (uint32_t cnt=0; cnt= 0; cnt--) {
+ if (file[cnt] == '.') {
+ ending = &file[cnt + 1];
+ break;
+ }
}
+ if (!ending) return;
+ char estr[8];
+ memset(estr, 0, sizeof(estr));
+ for (uint32_t cnt = 0; cnt < strlen(ending); cnt++) {
+ estr[cnt] = tolower(ending[cnt]);
+ }
+ estr[3] = 0;
if (!strcmp(estr,"rgb")) {
// special rgb format
- fp=ufsp->open(file,FS_FILE_READ);
+ fp = ufsp->open(file, FS_FILE_READ);
if (!fp) return;
uint16_t xsize;
- fp.read((uint8_t*)&xsize,2);
+ fp.read((uint8_t*)&xsize, 2);
uint16_t ysize;
- fp.read((uint8_t*)&ysize,2);
-#if 1
- renderer->setAddrWindow(xp,yp,xp+xsize,yp+ysize);
- uint16_t rgb[xsize];
- for (int16_t j=0; jpushColors(rgb,xsize,true);
- // }
- OsWatchLoop();
+ fp.read((uint8_t*)&ysize, 2);
+#ifndef SLOW_RGB16
+ renderer->setAddrWindow(xp, yp, xp + xsize, yp + ysize);
+ uint16_t *rgb = (uint16_t *)special_malloc(xsize * 2);
+ if (rgb) {
+ //uint16_t rgb[xsize];
+ for (int16_t j = 0; j < ysize; j++) {
+ fp.read((uint8_t*)rgb, xsize * 2);
+ renderer->pushColors(rgb, xsize, true);
+ OsWatchLoop();
+ }
+ free(rgb);
}
- renderer->setAddrWindow(0,0,0,0);
+ renderer->setAddrWindow(0, 0, 0, 0);
#else
- for(int16_t j=0; jwritePixel(xp+i,yp,rgb);
+ renderer->writePixel(xp + i, yp, rgb);
}
delay(0);
OsWatchLoop();
@@ -2337,37 +2354,41 @@ void Draw_RGB_Bitmap(char *file,uint16_t xp, uint16_t yp, bool inverted ) {
// jpeg files on ESP32 with more memory
#ifdef ESP32
#ifdef JPEG_PICTS
- fp=ufsp->open(file,FS_FILE_READ);
- if (!fp) return;
+ fp = ufsp->open(file, FS_FILE_READ);
+ if (!fp) {
+ // try url
+ Draw_JPG_from_URL(file, xp, yp, scale);
+ return;
+ }
uint32_t size = fp.size();
- uint8_t *mem = (uint8_t *)special_malloc(size+4);
+ uint8_t *mem = (uint8_t *)special_malloc(size + 4);
if (mem) {
- uint8_t res=fp.read(mem, size);
+ uint8_t res = fp.read(mem, size);
if (res) {
uint16_t xsize;
uint16_t ysize;
- if (mem[0]==0xff && mem[1]==0xd8) {
+ if (mem[0] == 0xff && mem[1] == 0xd8) {
get_jpeg_size(mem, size, &xsize, &ysize);
//Serial.printf(" x,y,fs %d - %d - %d\n",xsize, ysize, size );
if (xsize && ysize) {
- uint8_t *out_buf = (uint8_t *)special_malloc((xsize*ysize*3)+4);
+ uint8_t *out_buf = (uint8_t *)special_malloc((xsize * ysize * 3) + 4);
if (out_buf) {
- uint16_t *pixb = (uint16_t *)special_malloc((xsize*2)+4);
+ uint16_t *pixb = (uint16_t *)special_malloc((xsize * 2) + 4);
if (pixb) {
- uint8_t *ob=out_buf;
+ uint8_t *ob = out_buf;
if (jpg2rgb888(mem, size, out_buf, (jpg_scale_t)JPG_SCALE_NONE)) {
- renderer->setAddrWindow(xp,yp,xp+xsize,yp+ysize);
- for(int32_t j=0; jsetAddrWindow(xp, yp, xp + xsize, yp + ysize);
+ for (int32_t j = 0; j < ysize; j++) {
+ if (inverted == false) {
rgb888_to_565(ob, pixb, xsize);
} else {
rgb888_to_565i(ob, pixb, xsize);
}
- ob+=xsize*3;
+ ob += xsize * 3;
renderer->pushColors(pixb, xsize, true);
OsWatchLoop();
}
- renderer->setAddrWindow(0,0,0,0);
+ renderer->setAddrWindow(0, 0, 0, 0);
}
free(out_buf);
free(pixb);
@@ -2385,6 +2406,77 @@ void Draw_RGB_Bitmap(char *file,uint16_t xp, uint16_t yp, bool inverted ) {
#endif // ESP32
}
}
+
+#ifdef ESP32
+#ifdef JPEG_PICTS
+#define JPG_DEFSIZE 150000
+void Draw_JPG_from_URL(char *url, uint16_t xp, uint16_t yp, uint8_t scale) {
+ uint8_t *mem = 0;
+ WiFiClient http_client;
+ HTTPClient http;
+ int32_t httpCode = 0;
+ String weburl = "http://" + UrlEncode(url);
+ http.begin(http_client, weburl);
+ httpCode = http.GET();
+ //AddLog(LOG_LEVEL_INFO, PSTR("HTTP RESULT %d %s"), httpCode , weburl.c_str());
+ uint32_t jpgsize = 0;
+ if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
+ mem = (uint8_t *)special_malloc(JPG_DEFSIZE);
+ if (!mem) return;
+ uint8_t *jpgp = mem;
+ WiFiClient *stream = http.getStreamPtr();
+ int32_t len = http.getSize();
+ if (len < 0) len = 99999999;
+ while (http.connected() && (len > 0)) {
+ size_t size = stream->available();
+ if (size) {
+ if (size > JPG_DEFSIZE) {
+ size = JPG_DEFSIZE;
+ }
+ uint32_t read = stream->readBytes(jpgp, size);
+ len -= read;
+ jpgp += read;
+ jpgsize += read;
+ //AddLog(LOG_LEVEL_INFO,PSTR("HTTP read %d - %d"), read, jpgsize);
+ }
+ delayMicroseconds(1);
+ }
+ } else {
+ AddLog(LOG_LEVEL_INFO, PSTR("HTTP ERROR %s"), http.getString().c_str());
+ }
+ http.end();
+ http_client.stop();
+
+ if (jpgsize) {
+ Draw_jpeg(mem, jpgsize, xp, yp, scale);
+ }
+ if (mem) free(mem);
+}
+
+void Draw_jpeg(uint8_t *mem, uint16_t jpgsize, uint16_t xp, uint16_t yp, uint8_t scale) {
+ if (mem[0] == 0xff && mem[1] == 0xd8) {
+ uint16_t xsize;
+ uint16_t ysize;
+ get_jpeg_size(mem, jpgsize, &xsize, &ysize);
+ //AddLog(LOG_LEVEL_INFO, PSTR("Pict size %d - %d - %d"), xsize, ysize, jpgsize);
+ scale &= 3;
+ uint8_t fac = 1 << scale;
+ xsize /= fac;
+ ysize /= fac;
+ renderer->setAddrWindow(xp, yp, xp + xsize, yp + ysize);
+ uint8_t *rgbmem = (uint8_t *)special_malloc(xsize * ysize * 2);
+ if (rgbmem) {
+ //jpg2rgb565(mem, jpgsize, rgbmem, JPG_SCALE_NONE);
+ jpg2rgb565(mem, jpgsize, rgbmem, (jpg_scale_t)scale);
+ renderer->pushColors((uint16_t*)rgbmem, xsize * ysize, true);
+ free(rgbmem);
+ }
+ renderer->setAddrWindow(0, 0, 0, 0);
+ }
+}
+#endif // JPEG_PICTS
+#endif // ESP32
+
#endif // USE_UFILESYS
/*********************************************************************************************\
@@ -2787,7 +2879,7 @@ void AddValue(uint8_t num,float fval) {
* Interface
\*********************************************************************************************/
-bool Xdrv13(uint8_t function)
+bool Xdrv13(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_14_mp3.ino b/tasmota/tasmota_xdrv_driver/xdrv_14_mp3.ino
index 88eff7dec..625f0359c 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_14_mp3.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_14_mp3.ino
@@ -395,7 +395,7 @@ if (PinUsed(GPIO_MP3_DFR562_BUSY)) // optional MP3 player busy pi
* Interface
\*********************************************************************************************/
-bool Xdrv14(uint8_t function)
+bool Xdrv14(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_15_pca9685.ino b/tasmota/tasmota_xdrv_driver/xdrv_15_pca9685.ino
index 9f6cee154..8f82432c2 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_15_pca9685.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_15_pca9685.ino
@@ -207,7 +207,7 @@ void PCA9685_OutputTelemetry(bool telemetry)
}
}
-bool Xdrv15(uint8_t function)
+bool Xdrv15(uint32_t function)
{
if (!I2cEnabled(XI2C_01)) { return false; }
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu.ino b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino
similarity index 99%
rename from tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu.ino
rename to tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino
index 102f4374c..6bd5a655e 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v1.ino
@@ -18,7 +18,10 @@
*/
#ifdef USE_LIGHT
-#ifdef USE_TUYA_MCU
+#ifdef USE_TUYA_MCU_V1
+/*********************************************************************************************\
+ * Tuya MCU V1
+\*********************************************************************************************/
#define XDRV_16 16
#define XNRG_32 32 // Needs to be the last XNRG_xx
@@ -551,7 +554,7 @@ void TuyaSendHexString(uint8_t id, char data[]) {
TuyaSendCmd(TUYA_CMD_SET_DP, payload_buffer, payload_len);
}
-void TuyaSendString(uint8_t id, char data[]) {
+void TuyaSendString(uint8_t id, const char data[]) {
uint16_t len = strlen(data);
uint16_t payload_len = 4 + len;
@@ -1535,7 +1538,7 @@ void TuyaAddButton(void) {
#ifdef USE_ENERGY_SENSOR
-bool Xnrg32(uint8_t function)
+bool Xnrg32(uint32_t function)
{
bool result = false;
@@ -1556,7 +1559,7 @@ bool Xnrg32(uint8_t function)
}
#endif // USE_ENERGY_SENSOR
-bool Xdrv16(uint8_t function) {
+bool Xdrv16(uint32_t function) {
bool result = false;
if (FUNC_MODULE_INIT == function) {
@@ -1566,6 +1569,7 @@ bool Xdrv16(uint8_t function) {
else if (Tuya.active) {
switch (function) {
case FUNC_LOOP:
+ case FUNC_SLEEP_LOOP:
if (TuyaSerial) { TuyaSerialInput(); }
break;
case FUNC_PRE_INIT:
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino
new file mode 100644
index 000000000..969235e71
--- /dev/null
+++ b/tasmota/tasmota_xdrv_driver/xdrv_16_tuyamcu_v2.ino
@@ -0,0 +1,2572 @@
+/*
+ xdrv_16_tuyamcu.ino - Tuya MCU support for Tasmota
+
+ Copyright (C) 2021 Federico Leoni, digiblur, Joel Stein and Theo Arends
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ 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_LIGHT
+#ifdef USE_TUYA_MCU
+/*********************************************************************************************\
+ * Tuya MCU V2
+
+ rework 2022-04-03 SH:
+ the intent of the rework is:
+ 1/ make the protocol parsing more robust.
+ to this end, it now observes a byte timeout on receive, and looks for 55AA rather than just 55 to reset.
+ Parsing has been split from message processing for better readability.
+ 2/ try to observe to 'tuya' state machine as per thier documentation.
+ - at least for startup.
+ ALL sends should originate from the state machine (except manual sends?).
+ ALL sends which need a return (synchronous) wait for an expected command before
+ the next command can be sent. (commands were observed being dropped by the MCU).
+ 3/ sending of DP data is now 'requested', and only sent if the DP value is
+ different to the one the MCU has (fixes an issue with Athom dimmer).
+ (data is stored in DPStore[], and serviced in the state machine)
+
+\*********************************************************************************************/
+
+#define XDRV_16 16
+#define XNRG_32 32 // Needs to be the last XNRG_xx
+
+#ifndef TUYA_DIMMER_ID
+#define TUYA_DIMMER_ID 0
+#endif
+
+//#define TUYA_MORE_DEBUG
+
+/*********************************************************************************************/
+
+#define TUYA_CMD_HEARTBEAT 0x00
+#define TUYA_CMD_QUERY_PRODUCT 0x01
+#define TUYA_CMD_MCU_CONF 0x02
+#define TUYA_CMD_WIFI_STATE 0x03
+#define TUYA_CMD_WIFI_RESET 0x04
+#define TUYA_CMD_WIFI_SELECT 0x05
+#define TUYA_CMD_SET_DP 0x06
+#define TUYA_CMD_STATE 0x07
+#define TUYA_CMD_QUERY_STATE 0x08
+#define TUYA_CMD_INITIATING_UPGRADE 0x0A // not implemented
+#define TUYA_CMD_UPGRADE_PACKAGE 0x0B // not implemented
+
+// MCU sends to request a 0x0c return of GMT
+#define TUYA_CMD_GET_TIME_GMT 0x0C // not implemented
+
+// MCU sends
+#define TUYA_CMD_TEST_WIFI 0x0E // not implemented
+// MCU sends
+#define TUYA_CMD_GET_MEMORY 0x0F // not implemented
+
+// MCU sends to request a 0x1c return of Local Time
+// we send unsolicited??
+#define TUYA_CMD_SET_TIME 0x1C
+
+// MCU Sends, we must respond with 0x22, len1 00 failure, 01 success
+#define TUYA_CMD_STATUS_SYNC 0x22 // not implemented
+#define TUYA_CMD_STATUS_SYNC_RES 0x23 // not implemented
+
+// From MCU. Response should be 0x0b 00/01/02
+// subcmd 03 -> request weather data
+// subcmd 06 -> get map id
+#define TUYA_CMD_REPORT_STATUS_RECORD_TYPE 0x34 // not implemented
+
+// MCU sends 'after 01 bute before 02'. Response should be 0x37, len 2, 00, 00/01/02
+// subcmd 01->file download notification
+#define TUYA_CMD_NEW_FEATURES 0x37 // not implemented
+
+// MCU sends
+#define TUYA_CMD_ENABLE_WEATHER 0x20 // not implemented
+// we send every 30 mins, if enabled, MCU acks with 0x21
+#define TUYA_CMD_SEND_WEATHER 0x21 // not implemented
+
+// MCU sends, response 0x24, len 1, -ve dB or 0
+#define TUYA_CMD_GET_WIFI_STRENGTH 0x24 // not implemented
+
+// MCU sends, response 0x25
+#define TUYA_CMD_DISABLE_HEARTBEAT 0x25 // not implemented
+// MCU sends JSON, response 0x2A, len1 00/01/02/03
+#define TUYA_CMD_SERIAL_PAIRING 0x2A // not implemented
+
+#define TUYA_CMD_VACUUM_MAP_STREAMING 0x28 // not implemented
+#define TUYA_CMD_VACUUM_MAP_STREAMING_MULTIPLE 0x30 // not implemented
+
+// MCU sends, response 0x2D
+#define TUYA_CMD_GET_MAC 0x2D // not implemented
+// MCU sends, response 0x2E
+#define TUYA_CMD_IR_STATUS 0x2E // not implemented
+// MCU sends, response 0x2E
+#define TUYA_CMD_IR_TEST 0x2F // not implemented
+// We send, response 0x33
+// uses subcommands, 01->learning, 02->data, 03->report.
+#define TUYA_CMD_RF 0x33 // not implemented
+
+#define TUYA_LOW_POWER_CMD_WIFI_STATE 0x02
+#define TUYA_LOW_POWER_CMD_WIFI_RESET 0x03
+#define TUYA_LOW_POWER_CMD_WIFI_CONFIG 0x04
+#define TUYA_LOW_POWER_CMD_STATE 0x05
+
+#define TUYA_TYPE_RAW 0x00
+#define TUYA_TYPE_BOOL 0x01
+#define TUYA_TYPE_VALUE 0x02
+#define TUYA_TYPE_STRING 0x03
+#define TUYA_TYPE_ENUM 0x04
+
+// limit to what we store for DPs of type string
+#define TUYA_MAX_STRING_SIZE 16
+
+#define TUYA_BUFFER_SIZE 256
+
+#define TUYA_BYTE_TIMEOUT_MS 500
+
+#define TUYAREAD32FROMPTR(x) (((uint8_t*)x)[0] << 24 | ((uint8_t*)x)[1] << 16 | ((uint8_t*)x)[2] << 8 | ((uint8_t*)x)[3])
+
+enum {
+ TUYA_STARTUP_STATE_INIT = 0,
+ TUYA_STARTUP_STATE_WAIT_ACK_INIT, // 1
+
+ TUYA_STARTUP_STATE_PRODUCT, //2
+ TUYA_STARTUP_STATE_WAIT_ACK_PRODUCT, // 3
+
+ TUYA_STARTUP_STATE_WAIT_OPTIONAL_NEW_FEATURES, // 4
+
+ TUYA_STARTUP_STATE_CONF, // 5
+ TUYA_STARTUP_STATE_WAIT_ACK_CONF, //6
+
+ TUYA_STARTUP_STATE_WIFI_STATE, //7
+ TUYA_STARTUP_STATE_WAIT_ACK_WIFI,//8
+
+ TUYA_STARTUP_STATE_QUERY_STATE,//9
+ TUYA_STARTUP_STATE_WAIT_ACK_QUERY,//10
+
+ TUYA_STARTUP_STATE_SEND_CMD,//11
+ TUYA_STARTUP_STATE_WAIT_ACK_CMD,//12
+
+ TUYA_STARTUP_STATE_SEND_HEARTBEAT,//13
+ TUYA_STARTUP_STATE_WAIT_ACK_HEARTBEAT,//14
+
+};
+
+#include
+TasmotaSerial *TuyaSerial = nullptr;
+
+#define TUYA_MAX_STORED_DPs 10
+typedef struct TUYA_DP_STORE_tag {
+ uint8_t DPid;
+ uint8_t Type;
+ uint8_t rxedValueLen;
+ uint8_t desiredValueLen;
+ // NOTE - THESE MUST BE 32 bit ALIGNED, hence uint32_t
+ // DPValues are changed by every TUYA_CMD_STATE
+ uint32_t rxedValue[(TUYA_MAX_STRING_SIZE+3)/4];
+ // desired DPValues are set, and toSet is set to request
+ uint32_t desiredValue[(TUYA_MAX_STRING_SIZE+3)/4];
+ // set to 1 if desired value changed
+ uint8_t toSet;
+ // flag to indicate we saw it at least once from MCU.
+ uint8_t rxed;
+} TUYA_DP_STORE;
+
+typedef struct TUYA_STRUCT_tag {
+ // variables to handle setting of a DP.
+ // DPIds are filled out by initial TUYA_CMD_QUERY_STATE
+ // or by an easrly set request.
+ TUYA_DP_STORE DPStore[TUYA_MAX_STORED_DPs];
+ uint8_t numRxedDPids;
+
+ // set to indicate the command which is an ack to the last sent command.
+ // e.g. 7 is ack to 6 and 8
+ // if state is TUYA_STARTUP_STATE_WAIT_ACK_CMD
+ uint8_t expectedResponseCmd;
+
+// uint8_t rxedDPids[TUYA_MAX_STORED_DPs];
+// uint8_t rxedDPidType[TUYA_MAX_STORED_DPs];
+ // DPValues are changed by every TUYA_CMD_STATE
+// uint32_t rxedDPvalues[TUYA_MAX_STORED_DPs];
+ // DPValues are changed by every TUYA_CMD_STATE
+// uint32_t desiredDPvalues[TUYA_MAX_STORED_DPs];
+ // set to 1 if desired value changed
+// uint8_t toSet[TUYA_MAX_STORED_DPs];
+ // set to 1 if a DP is to be sent
+ uint8_t requestSend;
+
+ uint16_t Levels[5]; // Array to store the values of TuyaMCU channels
+ uint16_t Snapshot[5]; // Array to store a snapshot of Tasmota actual channel values
+ uint16_t EnumState[4]; // Array to store up to four Enum type 4 values
+ char RGBColor[7]; // Stores RGB Color string in Hex format
+ uint16_t CTMin; // Minimum CT level allowed - When SetOption82 is enabled will default to 200
+ uint16_t CTMax; // Maximum CT level allowed - When SetOption82 is enabled will default to 380
+ int16_t Sensors[14]; // Stores the values of Sensors connected to the Tuya Device
+ bool ModeSet; // Controls 0 - Single Tone light, 1 - RGB Light
+ bool SensorsValid[14]; // Bool used for nullify the sensor value until a real value is received from the MCU
+ bool SuspendTopic; // Used to reduce the load at init time or when polling the configuraton on demand
+ bool ignore_dim; // Flag to skip serial send to prevent looping when processing inbound states from the faceplate interaction
+ uint32_t ignore_topic_timeout; // Suppress the /STAT topic (if enabled) to avoid data overflow until the configuration is over
+ uint8_t cmd_status; // Current status of serial-read
+ uint8_t cmd_checksum; // Checksum of tuya command
+ uint8_t data_len; // Data lenght of command
+ uint8_t wifi_state; // Keep MCU wifi-status in sync with WifiState()
+ uint8_t heartbeat_timer; // 10 second heartbeat timer for tuya module
+
+ // flasg which trigger sends of certain messages
+ uint8_t send_heartbeat; // trigger heartbeat when we can next send.
+ uint8_t send_time; // trigger time send when we can in running mode.
+
+#ifdef USE_ENERGY_SENSOR
+ uint32_t lastPowerCheckTime; // Time when last power was checked
+#endif // USE_ENERGY_SENSOR
+ unsigned char buffer[TUYA_BUFFER_SIZE]; // Serial receive buffer
+ int byte_counter; // Index in serial receive buffer
+ uint32_t ignore_dimmer_cmd_timeout; // Time until which received dimmer commands should be ignored
+ bool low_power_mode; // Normal or Low power mode protocol
+ bool send_success_next_second; // Second command success in low power mode
+ bool active;
+
+ int timeout; // command timeout in ms
+ // every time we get a long press, add 10000. If we get to 20000, then go to wifimanager mode, if enabled
+ // decremented by 1000 each second.
+ int wifiTimer;
+
+ char inStateMachine;
+ char startup_state;
+ char timeout_state; // state to go to if timeout.
+
+ unsigned char lastByte;
+ unsigned int lastByteTime; // time of last byte receipt.
+
+ unsigned int errorcnt; // increment every time something goes awry
+ unsigned int lasterrorcnt; // used to choose when to log errorcnt
+
+ int dimDelay_ms[2]; // SIGNED the delay after a dim result after which we are allowed to send a dim value
+ int defaultDimDelay_ms; // the delay after a dim result after which we are allowed to send a dim value
+ uint8_t dimCmdEnable; // we are allowed to send a dim command - bitfield
+ uint8_t dimDebug; // enables a single dim debug - bitfield
+
+ int sends;
+ int rxs;
+
+} TUYA_STRUCT;
+
+TUYA_STRUCT *pTuya = (TUYA_STRUCT *)0;
+//void TuyaSendCmd(uint8_t cmd, uint8_t payload[] = nullptr, uint16_t payload_len = 0);
+
+void TuyaSendState(uint8_t id, uint8_t type, uint8_t* value, int len);
+
+int init_tuya_struct() {
+ if (pTuya) return 0; // done already
+ pTuya = (TUYA_STRUCT *)malloc(sizeof(TUYA_STRUCT));
+ if (!pTuya) return 0;
+ memset(pTuya, 0, sizeof(TUYA_STRUCT));
+ strcpy(pTuya->RGBColor, "000000"); // Stores RGB Color string in Hex format
+ pTuya->CTMin = 153; // Minimum CT level allowed - When SetOption82 is enabled will default to 200
+ pTuya->CTMax = 500; // Maximum CT level allowed - When SetOption82 is enabled will default to 380
+ pTuya->wifi_state = -2; // Keep MCU wifi-status in sync with WifiState()
+ pTuya->defaultDimDelay_ms = 2000; // 2s delay from a power command to a dim command, or from an rxed dim command to sending one.
+#ifdef TUYA_MORE_DEBUG
+ AddLog(LOG_LEVEL_INFO, PSTR("TYA: Init struct done"));
+#endif
+ return 1;
+}
+
+#define D_JSON_TUYA_MCU_RECEIVED "TuyaReceived"
+
+#define D_PRFX_TUYA "Tuya"
+#define D_CMND_TUYA_MCU "MCU"
+#define D_CMND_TUYA_MCU_SEND_STATE "Send"
+#define D_CMND_TUYARGB "RGB"
+#define D_CMND_TUYA_ENUM "Enum"
+#define D_CMND_TUYA_ENUM_LIST "EnumList"
+// #define D_CMND_TUYA_SET_TEMP "SetTemp"
+// #define D_CMND_TUYA_SET_HUM "SetHum"
+// #define D_CMND_TUYA_SET_TIMER "SetTimer"
+
+const char kTuyaSensors[] PROGMEM = // List of available sensors (can be expanded in the future)
+// 71 72 73 74 75
+ "" D_JSON_TEMPERATURE "|TempSet|" D_JSON_HUMIDITY "|HumSet|" D_JSON_ILLUMINANCE
+// 76 77 78 79 80 81 82 83 84
+ "|" D_JSON_TVOC "|" D_JSON_ECO2 "|" D_JSON_CO2 "|" D_JSON_GAS "|" D_ENVIRONMENTAL_CONCENTRATION "||Timer1|Timer2|Timer3|TImer4";
+
+const char kTuyaCommand[] PROGMEM = D_PRFX_TUYA "|" // Prefix
+ D_CMND_TUYA_MCU "|" D_CMND_TUYA_MCU_SEND_STATE "|" D_CMND_TUYARGB "|" D_CMND_TUYA_ENUM "|" D_CMND_TUYA_ENUM_LIST "|TempSetRes|DimDelay";
+
+void (* const TuyaCommand[])(void) PROGMEM = {
+ &CmndTuyaMcu, &CmndTuyaSend, &CmndTuyaRgb, &CmndTuyaEnum, &CmndTuyaEnumList, &CmndTuyaTempSetRes, &CmdTuyaSetDimDelay
+};
+
+const uint8_t TuyaExcludeCMDsFromMQTT[] PROGMEM = { // don't publish this received commands via MQTT if SetOption66 and SetOption137 is active (can be expanded in the future)
+ TUYA_CMD_HEARTBEAT, TUYA_CMD_WIFI_STATE, TUYA_CMD_SET_TIME, TUYA_CMD_UPGRADE_PACKAGE
+};
+
+/*********************************************************************************************\
+ * Web Interface
+\*********************************************************************************************/
+
+bool IsModuleTuya(void) {
+ if (!pTuya) return false;
+ bool is_tuya = pTuya->active;
+//#ifdef ESP8266
+ // This is not a Tuya driven device. It uses a Tuya provided ESP8266. Why it was here is a mystery to me.
+// if (SK03_TUYA == TasmotaGlobal.module_type) {
+// is_tuya = true;
+// }
+//#endif
+ return is_tuya;
+}
+
+bool AsModuleTuyaMS(void) // ModeSet Layout
+{
+ return ((TasmotaGlobal.light_type > LT_RGB) && TuyaGetDpId(TUYA_MCU_FUNC_MODESET) != 0);
+}
+
+bool TuyaModeSet(void) // ModeSet Status
+{
+ if (!pTuya) return false;
+ return pTuya->ModeSet;
+}
+
+/*********************************************************************************************\
+ * Web Interface
+\*********************************************************************************************/
+
+/*
+TuyaSend dpId,data
+
+TuyaSend0 -> Sends TUYA_CMD_QUERY_STATE
+TuyaSend1 11,1 -> Sends boolean (Type 1) data 0/1 to dpId 11 (Max data length 1 byte)
+TuyaSend2 11,100 -> Sends integer (Type 2) data 100 to dpId 11 (Max data length 4 bytes)
+TuyaSend2 11,0xAABBCCDD -> Sends 4 bytes (Type 2) data to dpId 11 (Max data length 4 bytes)
+TuyaSend3 11,ThisIsTheData -> Sends the supplied string (Type 3) to dpId 11 ( Max data length not-known)
+TuyaSend4 11,1 -> Sends enum (Type 4) data 1 to dpId 11 (Max data length 1 bytes)
+TuyaSend5 11,ABCD -> Sends an HEX string (Type 3) data to dpId
+TuyaSend6 11,ABCD -> Sends raw (Type 0) data to dpId
+
+TuyaSend8 -> Sends TUYA_CMD_QUERY_PRODUCT ?
+*/
+
+void CmndTuyaSend(void) {
+ if (!pTuya) return;
+ switch(XdrvMailbox.index){
+ case 0:
+ TuyaRequestState(0);
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ {
+ if (XdrvMailbox.data_len > 0) {
+ char *p;
+ const char *data = "";
+ uint8_t i = 0;
+ uint8_t dpId = 0;
+ for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < 2; str = strtok_r(nullptr, ", ", &p)) {
+ if ( i == 0) {
+ // note: can be a number, or 0xnn for hex because base is 0
+ dpId = strtoul(str, nullptr, 0);
+ } else {
+ data = str;
+ }
+ i++;
+ }
+
+ if (1 == XdrvMailbox.index) {
+ TuyaSendBool(dpId, strtoul(data, nullptr, 0));
+ } else if (2 == XdrvMailbox.index) {
+ TuyaSendValue(dpId, strtoull(data, nullptr, 0));
+ } else if (3 == XdrvMailbox.index) {
+ TuyaSendString(dpId, data);
+ } else if (5 == XdrvMailbox.index) {
+ TuyaSendHexString(dpId, data);
+ } else if (4 == XdrvMailbox.index) {
+ TuyaSendEnum(dpId, strtoul(data, nullptr, 0));
+ } else if (6 == XdrvMailbox.index) {
+ TuyaSendRaw(dpId, data);
+ } else if (7 == XdrvMailbox.index) {
+ uint8_t cmd = dpId;
+ // send ANY cmd with payload from hex string
+ // calculates length and checksum for you.
+ // like "0," to send a heartbeat, "3,4" to set wifi led mode,
+ // "0x1c,0110041305060702" - set local time
+ // sends immediately....
+ TuyaSendRawCmd(cmd, data);
+ }
+ }
+ } break;
+
+ case 8:
+ // product info
+ TuyaRequestState(8);
+ break;
+ case 9:
+ Settings->tuyamcu_topic = !Settings->tuyamcu_topic;
+ AddLog(LOG_LEVEL_INFO, PSTR("TYA: TuyaMCU Stat Topic %s"), (Settings->tuyamcu_topic ? PSTR("enabled") : PSTR("disabled")));
+ break;
+ }
+ ResponseCmndDone();
+}
+
+
+void CmdTuyaSetDimDelay(void) {
+ if (!pTuya) return;
+
+ switch(XdrvMailbox.index){
+ case 1: {
+ if (XdrvMailbox.data_len > 0) {
+ int32_t delay = strtol(XdrvMailbox.data, nullptr, 0);
+ pTuya->defaultDimDelay_ms = delay;
+ } else {
+ // report only
+ Response_P(PSTR("{\"%s\":{\"dimdelay\":%d}}"), XdrvMailbox.command, pTuya->defaultDimDelay_ms); // Builds TuyaMCU
+ return;
+ }
+ } break;
+
+ default: // no response
+ return;
+ }
+ ResponseCmndDone();
+}
+
+// TuyaMcu fnid,dpid
+
+void CmndTuyaMcu(void) {
+ if (!pTuya) return;
+ if (XdrvMailbox.data_len > 0) {
+ char *p;
+ uint8_t i = 0;
+ uint8_t parm[3] = { 0 };
+ for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < 2; str = strtok_r(nullptr, ", ", &p)) {
+ parm[i] = strtoul(str, nullptr, 0);
+ i++;
+ }
+
+ if (TuyaFuncIdValid(parm[0])) {
+ bool DualDim;
+ if (TUYA_MCU_FUNC_DIMMER2 == parm[0] && parm[1] != 0) {
+ if (TuyaGetDpId(TUYA_MCU_FUNC_DIMMER) != 0) { DualDim = true; }
+ } else if (TUYA_MCU_FUNC_DIMMER == parm[0] && parm[1] != 0) {
+ if (TuyaGetDpId(TUYA_MCU_FUNC_DIMMER2) != 0) { DualDim = true; }
+ } else if ((TUYA_MCU_FUNC_DIMMER == parm[0] && parm[1] == 0) || (TUYA_MCU_FUNC_DIMMER2 == parm[0] && parm[1] == 0)) { DualDim = false; };
+ if (DualDim) { // If the second dimmer is enabled CT, RGB or WHITE function must be removed
+ if (TuyaGetDpId(TUYA_MCU_FUNC_CT) != 0) { TuyaAddMcuFunc(TUYA_MCU_FUNC_CT, 0); }
+ if (TuyaGetDpId(TUYA_MCU_FUNC_RGB) != 0) { TuyaAddMcuFunc(TUYA_MCU_FUNC_RGB, 0); }
+ if (TuyaGetDpId(TUYA_MCU_FUNC_WHITE) != 0) { TuyaAddMcuFunc(TUYA_MCU_FUNC_WHITE, 0); }
+ Settings->flag3.pwm_multi_channels = 1;
+ } else { Settings->flag3.pwm_multi_channels = 0; }
+ TuyaAddMcuFunc(parm[0], parm[1]);
+ TasmotaGlobal.restart_flag = 2;
+ } else {
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: TuyaMcu Invalid function id=%d"), parm[0]);
+ }
+ }
+
+ Response_P(PSTR("{\"%s\":["), XdrvMailbox.command); // Builds TuyaMCU
+ bool added = false;
+ for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) {
+ if (Settings->tuya_fnid_map[i].fnid != 0) {
+ if (added) {
+ ResponseAppend_P(PSTR(","));
+ }
+ ResponseAppend_P(PSTR("{\"fnId\":%d,\"dpId\":%d}" ), Settings->tuya_fnid_map[i].fnid, Settings->tuya_fnid_map[i].dpid);
+ added = true;
+ }
+ }
+ ResponseAppend_P(PSTR("]}"));
+}
+
+void CmndTuyaRgb(void) { // Command to control the RGB format
+ if (!pTuya) return;
+
+ uint16_t payload = XdrvMailbox.payload;
+
+ if (XdrvMailbox.data_len > 0) {
+ if (payload < 0 || payload > 3 || TuyaGetDpId(TUYA_MCU_FUNC_RGB) == 0) {
+ return;
+ } else {
+ if (payload != Settings->tuya_fnid_map[230].dpid) { // fnid 230 is reserved for RGB
+ Settings->tuya_fnid_map[230].fnid = 230;
+ Settings->tuya_fnid_map[230].dpid = payload;
+ }
+ }
+ }
+ ResponseCmndNumber(Settings->tuya_fnid_map[230].dpid);
+}
+
+void CmndTuyaTempSetRes(void)
+{
+ if (!pTuya) return;
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 3)) {
+ Settings->mbflag2.temperature_set_res = XdrvMailbox.payload;
+ }
+ ResponseCmndNumber(Settings->mbflag2.temperature_set_res);
+}
+
+void CmndTuyaEnum(void) { // Command to control up to four type 4 Enum
+ if (!pTuya) return;
+ uint16_t EnumIdx = XdrvMailbox.index;
+ int32_t payload = XdrvMailbox.payload;
+
+ if (EnumIdx > 4 || TuyaGetDpId(TUYA_MCU_FUNC_ENUM1 + (EnumIdx-1)) == 0) {
+ return;
+ }
+
+ if (XdrvMailbox.data_len > 0) {
+ if (payload < 0 || payload > Settings->tuya_fnid_map[EnumIdx + 230].dpid ) {
+ return;
+ } else {
+ if (payload != pTuya->EnumState[EnumIdx-1]) {
+ pTuya->EnumState[EnumIdx-1] = payload;
+ TuyaSendEnum(TuyaGetDpId(TUYA_MCU_FUNC_ENUM1 + (EnumIdx-1)), payload);
+ }
+ ResponseCmndIdxNumber(pTuya->EnumState[EnumIdx-1]);
+ }
+ } else {
+ Response_P(PSTR("{\"%s\":{"), XdrvMailbox.command); // Builds TuyaEnum
+ bool added = false;
+ for (uint8_t i = 0; i <= 3; i++) {
+ if (TuyaGetDpId(TUYA_MCU_FUNC_ENUM1 + i) != 0) {
+ if (added) {
+ ResponseAppend_P(PSTR(","));
+ }
+ ResponseAppend_P(PSTR("\"Enum%d\":%d"), i + 1, pTuya->EnumState[i]); // Returns the actual values of Enum as list
+ added = true;
+ }
+ }
+ ResponseAppend_P(PSTR("}}"));
+ }
+}
+
+void CmndTuyaEnumList(void) { // Command to declare the number of items in list for up to four type 4 enum. Min = 0, Max = 31, Default = 0
+ if (!pTuya) return;
+
+ if (XdrvMailbox.data_len > 0) {
+ char *p;
+ uint8_t i = 0;
+ uint8_t parm[3] = { 0 };
+ for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < 2; str = strtok_r(nullptr, ", ", &p)) {
+ parm[i] = strtoul(str, nullptr, 0);
+ i++;
+ }
+ if ((parm[0] >= 1 && parm[0] <= 4) && (parm[1] >= 1 && parm[1] <= 31)) {
+ uint16_t idx = parm[0] + 230; // fnid 231, 232, 233 and 234 are reserved for enum
+ Settings->tuya_fnid_map[idx].fnid = idx;
+ Settings->tuya_fnid_map[idx].dpid = parm[1];
+ }
+ }
+ if ((TuyaGetDpId(TUYA_MCU_FUNC_ENUM1) != 0) || (TuyaGetDpId(TUYA_MCU_FUNC_ENUM3) != 0) ||
+ (TuyaGetDpId(TUYA_MCU_FUNC_ENUM3) != 0) || (TuyaGetDpId(TUYA_MCU_FUNC_ENUM4) != 0)) {
+ Response_P(PSTR("{\"%s\":{"), XdrvMailbox.command); // Builds TuyaEnumList
+ bool added = false;
+ for (uint8_t i = 0; i <= 3; i++) {
+ if (TuyaGetDpId(TUYA_MCU_FUNC_ENUM1 + i) != 0) {
+ if (added) {
+ ResponseAppend_P(PSTR(","));
+ if ( Settings->tuya_fnid_map[i + 231].dpid > 31 ) { Settings->tuya_fnid_map[i + 231].dpid = 0; } // default to 0 it the value exceed the range
+ }
+ ResponseAppend_P(PSTR("\"Enum%d\":%d"), i + 1, Settings->tuya_fnid_map[i + 231].dpid); // fnid 231, 232, 233 and 234 are reserved for Enum
+ added = true;
+ }
+ }
+ ResponseAppend_P(PSTR("}}"));
+ } else { return; }
+}
+
+int StrCmpNoCase(char const *Str1, char const *Str2) // Compare case sensistive RGB strings
+{
+ for (;; Str1++, Str2++) {
+ int StrCmp = tolower((unsigned char)*Str1) - tolower((unsigned char)*Str2);
+ if (StrCmp != 0 || !*Str1) { return StrCmp; }
+ }
+}
+
+float TuyaAdjustedTemperature(int16_t packetValue, uint8_t res)
+{
+ switch (res)
+ {
+ case 1:
+ return (float)packetValue / 10.0;
+ break;
+ case 2:
+ return (float)packetValue / 100.0;
+ break;
+ case 3:
+ return (float)packetValue / 1000.0;
+ break;
+ default:
+ return (float)packetValue;
+ break;
+ }
+}
+
+/*********************************************************************************************\
+ * Internal Functions
+\*********************************************************************************************/
+
+void TuyaAddMcuFunc(uint8_t fnId, uint8_t dpId) {
+ bool added = false;
+
+ if (fnId == 0 || dpId == 0) { // Delete entry
+ for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) {
+ if ((dpId > 0 && Settings->tuya_fnid_map[i].dpid == dpId) || (fnId > TUYA_MCU_FUNC_NONE && Settings->tuya_fnid_map[i].fnid == fnId)) {
+ Settings->tuya_fnid_map[i].fnid = TUYA_MCU_FUNC_NONE;
+ Settings->tuya_fnid_map[i].dpid = 0;
+ break;
+ }
+ }
+ } else { // Add or update
+ for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) {
+ if (Settings->tuya_fnid_map[i].dpid == dpId || Settings->tuya_fnid_map[i].dpid == 0 || Settings->tuya_fnid_map[i].fnid == fnId || Settings->tuya_fnid_map[i].fnid == 0) {
+ if (!added) { // Update entry if exisiting entry or add
+ Settings->tuya_fnid_map[i].fnid = fnId;
+ Settings->tuya_fnid_map[i].dpid = dpId;
+ added = true;
+ } else if (Settings->tuya_fnid_map[i].dpid == dpId || Settings->tuya_fnid_map[i].fnid == fnId) { // Remove existing entry if added to empty place
+ Settings->tuya_fnid_map[i].fnid = TUYA_MCU_FUNC_NONE;
+ Settings->tuya_fnid_map[i].dpid = 0;
+ }
+ }
+ }
+ }
+ UpdateDevices();
+}
+
+void UpdateDevices() {
+ for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) {
+ uint8_t fnId = Settings->tuya_fnid_map[i].fnid;
+ if (fnId > TUYA_MCU_FUNC_NONE && Settings->tuya_fnid_map[i].dpid > 0) {
+
+ if (fnId >= TUYA_MCU_FUNC_REL1 && fnId <= TUYA_MCU_FUNC_REL8) { //Relay
+ bitClear(TasmotaGlobal.rel_inverted, fnId - TUYA_MCU_FUNC_REL1);
+ } else if (fnId >= TUYA_MCU_FUNC_REL1_INV && fnId <= TUYA_MCU_FUNC_REL8_INV) { // Inverted Relay
+ bitSet(TasmotaGlobal.rel_inverted, fnId - TUYA_MCU_FUNC_REL1_INV);
+ }
+ }
+ }
+}
+
+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_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) ||
+ (fnId == TUYA_MCU_FUNC_LOWPOWER_MODE) ||
+ (fnId >= TUYA_MCU_FUNC_TEMP && fnId <= TUYA_MCU_FUNC_HUMSET) ||
+ (fnId >= TUYA_MCU_FUNC_LX && fnId <= TUYA_MCU_FUNC_PM25) ||
+ (fnId >= TUYA_MCU_FUNC_TIMER1 && fnId <= TUYA_MCU_FUNC_TIMER4);
+}
+
+uint8_t TuyaGetFuncId(uint8_t dpid) {
+ for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) {
+ if (Settings->tuya_fnid_map[i].dpid == dpid) {
+ return Settings->tuya_fnid_map[i].fnid;
+ }
+ }
+ return TUYA_MCU_FUNC_NONE;
+}
+
+uint8_t TuyaGetDpId(uint8_t fnId) {
+ for (uint8_t i = 0; i < MAX_TUYA_FUNCTIONS; i++) {
+ if (Settings->tuya_fnid_map[i].fnid == fnId) {
+ return Settings->tuya_fnid_map[i].dpid;
+ }
+ }
+ return 0;
+}
+
+uint8_t TuyaFnIdIsDimmer(uint8_t fnId){
+ //TUYA_MCU_FUNC_DIMMER = 21, TUYA_MCU_FUNC_DIMMER2, TUYA_MCU_FUNC_CT, TUYA_MCU_FUNC_RGB, TUYA_MCU_FUNC_WHITE,
+
+ if ((fnId >= TUYA_MCU_FUNC_DIMMER) &&
+ (fnId <= TUYA_MCU_FUNC_WHITE)){
+ return 1;
+ }
+ return 0;
+}
+
+uint8_t TuyaDpIdIsDimmer(uint8_t dpId){
+ uint8_t fnId = TuyaGetFuncId(dpId);
+ return TuyaFnIdIsDimmer(fnId);
+}
+
+// pTuya->timeout hit zero
+void Tuya_timeout(){
+ // timeout_state should have been set to the correct state to go to after the timeout
+ if (pTuya->startup_state != TUYA_STARTUP_STATE_WAIT_ACK_QUERY){
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: Protocol timeout state %d -> %d"), pTuya->startup_state, pTuya->timeout_state);
+ }
+ pTuya->startup_state = pTuya->timeout_state;
+ pTuya->timeout = 0;
+}
+
+void TuyaSendCmd(uint8_t cmd, uint8_t payload[] = nullptr, uint16_t payload_len = 0, int noerror = 0)
+{
+ if (!pTuya->inStateMachine && !noerror){
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: TuyaSendCmd should only be called from within the state machine! - if this was a manual command, then ok."));
+ }
+
+ // include ver = 0 in checksum for completeness
+ uint8_t checksum = (0xFF + 0x00 + cmd + (payload_len >> 8) + (payload_len & 0xFF));
+ TuyaSerial->write(0x55); // Tuya header 55AA
+ TuyaSerial->write(0xAA);
+ TuyaSerial->write((uint8_t)0x00); // version 00 - send TO MCU
+ TuyaSerial->write(cmd); // Tuya command
+ TuyaSerial->write(payload_len >> 8); // following data length (Hi)
+ TuyaSerial->write(payload_len & 0xFF); // following data length (Lo)
+ char log_data[700]; // Was MAX_LOGSZ
+ snprintf_P(log_data, sizeof(log_data), PSTR("T:>\"55aa00%02x%02x%02x"), cmd, payload_len >> 8, payload_len & 0xFF);
+ for (uint32_t i = 0; i < payload_len; ++i) {
+ TuyaSerial->write(payload[i]);
+ checksum += payload[i];
+ snprintf_P(log_data, sizeof(log_data), PSTR("%s%02x"), log_data, payload[i]);
+ }
+ TuyaSerial->write(checksum);
+ TuyaSerial->flush();
+ snprintf_P(log_data, sizeof(log_data), PSTR("%s%02x\""), log_data, checksum);
+ AddLogData(LOG_LEVEL_DEBUG, log_data);
+ pTuya->sends ++;
+}
+
+
+// note: normally regularly called with defaults
+// ONLY called with cmd, len, data from an incoming command with ver 03.
+// - and this is ONLY used to recognise acks when they occur/are needed.
+void Tuya_statemachine(int cmd = -1, int len = 0, unsigned char *payload = (unsigned char *)0) {
+ pTuya->inStateMachine = 1;
+ int state = pTuya->startup_state;
+ switch (pTuya->startup_state){
+ case TUYA_STARTUP_STATE_INIT://0
+ if (cmd >= 0) break;
+ TuyaSendCmd(TUYA_CMD_HEARTBEAT);
+ pTuya->timeout = 3000;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_INIT;
+ pTuya->startup_state = TUYA_STARTUP_STATE_WAIT_ACK_INIT;
+ break;
+ case TUYA_STARTUP_STATE_WAIT_ACK_INIT: // 1
+ if (cmd == TUYA_CMD_HEARTBEAT){
+ pTuya->timeout = 0;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_INIT;
+ pTuya->startup_state = TUYA_STARTUP_STATE_PRODUCT;
+ }
+ break;
+ case TUYA_STARTUP_STATE_PRODUCT: //2
+ if (cmd >= 0) break;
+ TuyaSendCmd(TUYA_CMD_QUERY_PRODUCT);
+ pTuya->timeout = 1000;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_INIT;
+ pTuya->startup_state = TUYA_STARTUP_STATE_WAIT_ACK_PRODUCT;
+ break;
+ case TUYA_STARTUP_STATE_WAIT_ACK_PRODUCT: // 3
+ if (cmd == TUYA_CMD_QUERY_PRODUCT){
+ pTuya->timeout = 300; // Optional - we will wait 300ms for this after TUYA_CMD_QUERY_PRODUCT response
+ pTuya->timeout_state = TUYA_STARTUP_STATE_CONF; // move on at timeout.
+ pTuya->startup_state = TUYA_STARTUP_STATE_WAIT_OPTIONAL_NEW_FEATURES;
+ }
+ break;
+ case TUYA_STARTUP_STATE_WAIT_OPTIONAL_NEW_FEATURES: // 4
+ /* Optional - we will wait 300ms for this after TUYA_CMD_QUERY_PRODUCT response
+ After the device is powered on,
+ the MCU sends this command to notify the module of feature configuration
+ after the command 0x01 and before the command 0x02.*/
+ if (cmd == TUYA_CMD_NEW_FEATURES){
+ pTuya->timeout = 0;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_CONF;
+ pTuya->startup_state = TUYA_STARTUP_STATE_CONF;
+ }
+ break;
+ case TUYA_STARTUP_STATE_CONF: // 5
+ if (cmd >= 0) break;
+ TuyaSendCmd(TUYA_CMD_MCU_CONF);
+ pTuya->timeout = 1000;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_INIT;
+ pTuya->startup_state = TUYA_STARTUP_STATE_WAIT_ACK_CONF;
+ break;
+ case TUYA_STARTUP_STATE_WAIT_ACK_CONF: //
+ if (cmd == TUYA_CMD_MCU_CONF){
+ if (len > 0){
+ pTuya->startup_state = TUYA_STARTUP_STATE_QUERY_STATE;
+ } else {
+ pTuya->startup_state = TUYA_STARTUP_STATE_WIFI_STATE;
+ }
+ pTuya->timeout = 0;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_INIT;
+ }
+ break;
+
+ case TUYA_STARTUP_STATE_WIFI_STATE: {//
+ uint8_t t = 0x04;
+ if (cmd >= 0) break;
+ TuyaSendCmd(TUYA_CMD_WIFI_STATE, &t, 1);
+ pTuya->timeout = 1000;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_INIT;
+ pTuya->startup_state = TUYA_STARTUP_STATE_WAIT_ACK_WIFI;
+ } break;
+ case TUYA_STARTUP_STATE_WAIT_ACK_WIFI://
+ if (cmd == TUYA_CMD_WIFI_STATE){
+ pTuya->timeout = 0;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_INIT;
+ pTuya->startup_state = TUYA_STARTUP_STATE_QUERY_STATE;
+ }
+ break;
+ case TUYA_STARTUP_STATE_QUERY_STATE://
+ if (cmd >= 0) break;
+ TuyaSendCmd(TUYA_CMD_QUERY_STATE);
+ pTuya->timeout = 1000;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_INIT;
+ pTuya->startup_state = TUYA_STARTUP_STATE_WAIT_ACK_QUERY;
+ break;
+ case TUYA_STARTUP_STATE_WAIT_ACK_QUERY://
+ if (cmd == TUYA_CMD_STATE){
+ // wait a further 500ms for the next command.
+ // only on timeout, move on to runtime
+ pTuya->timeout = 500;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_SEND_CMD;
+ pTuya->startup_state = TUYA_STARTUP_STATE_WAIT_ACK_QUERY;
+ }
+ break;
+
+ // we hit runtime.....
+ case TUYA_STARTUP_STATE_SEND_CMD://
+ if (pTuya->send_time & 1){
+ TuyaSetTime();
+ pTuya->send_time &= 0xfe;
+ // ??? TODO - if no MCU support, we'll just wait 100ms.
+ // we should *not* get a response - as this is normally a command which is requested
+ pTuya->expectedResponseCmd = TUYA_CMD_SET_TIME;
+ // always wait a bit before sending anything else, otherwise we may overflow the MCU input buffer.
+ pTuya->timeout = 200;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_SEND_CMD;
+ pTuya->startup_state = TUYA_STARTUP_STATE_WAIT_ACK_CMD;
+ break;
+ }
+
+ if (pTuya->wifi_state != TuyaGetTuyaWifiState()) {
+ pTuya->wifi_state = TuyaGetTuyaWifiState();
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Set WiFi LED %d (%d)"), pTuya->wifi_state, WifiState());
+ if (pTuya->low_power_mode) {
+ TuyaSendCmd(TUYA_LOW_POWER_CMD_WIFI_STATE, &pTuya->wifi_state, 1);
+ pTuya->expectedResponseCmd = TUYA_CMD_WIFI_STATE; // ??? TODO
+ pTuya->timeout = 300;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_SEND_CMD;
+ pTuya->startup_state = TUYA_STARTUP_STATE_WAIT_ACK_CMD;
+ break;
+ } else {
+ TuyaSendCmd(TUYA_CMD_WIFI_STATE, &pTuya->wifi_state, 1);
+ pTuya->expectedResponseCmd = TUYA_CMD_WIFI_STATE;
+ pTuya->timeout = 300;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_SEND_CMD;
+ pTuya->startup_state = TUYA_STARTUP_STATE_WAIT_ACK_CMD;
+ break;
+ }
+ }
+
+ if (pTuya->low_power_mode) {
+ if (pTuya->send_success_next_second) {
+ uint8_t success = 1;
+ TuyaSendCmd(TUYA_LOW_POWER_CMD_STATE, &success, 1);
+ pTuya->expectedResponseCmd = TUYA_LOW_POWER_CMD_STATE; // ?? TODO - if no resp, we'll wait 300ms
+ pTuya->timeout = 300;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_SEND_CMD;
+ pTuya->startup_state = TUYA_STARTUP_STATE_WAIT_ACK_CMD;
+ pTuya->send_success_next_second = false;
+ break;
+ }
+ //TuyaSendLowPowerSuccessIfNeeded();
+ }
+
+ // send any DP chang requests
+ // only if different from the received or last send values
+ int i;
+ for (i = 0; i < pTuya->numRxedDPids; i++){
+ TUYA_DP_STORE *dp = &pTuya->DPStore[i];
+ // if set requested, and MCU has reported at least once
+ if (dp->toSet && dp->rxed){
+ // if value is different
+ if ((dp->rxedValueLen != dp->desiredValueLen) || memcmp(dp->rxedValue, dp->desiredValue, dp->desiredValueLen)){
+ uint8_t send = 1;
+ if (TuyaDpIdIsDimmer(dp->DPid)){
+ uint8_t fnId = TuyaGetFuncId(dp->DPid);
+ uint8_t dimindex = 0;
+ if (fnId == TUYA_MCU_FUNC_DIMMER2){ // first dimmer
+ dimindex = 1;
+ }
+ // set every time a dim value is rxed, and if just turned on
+ if (pTuya->dimDelay_ms[dimindex]){
+ if (pTuya->dimDebug & (1<dimDelay_ms[dimindex]);
+ pTuya->dimDebug &= (0xff ^ (1<dimCmdEnable & (1<dimDebug & (1<dimDebug &= (0xff ^ (1<DPid,
+ dp->Type,
+ (uint8_t*)dp->desiredValue, dp->desiredValueLen);
+ // assume it worked? maybe not
+ //dp->rxedValueLen = dp->desiredValueLen;
+ //memcpy(dp->rxedValue, dp->desiredValue, dp->desiredValueLen);
+ dp->toSet = 0;
+ pTuya->expectedResponseCmd = TUYA_CMD_STATE;
+ pTuya->timeout = 300;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_SEND_CMD;
+ pTuya->startup_state = TUYA_STARTUP_STATE_WAIT_ACK_CMD;
+#ifdef TUYA_MORE_DEBUG
+ MqttPublishLoggingAsync(false);
+ SyslogAsync(false);
+#endif
+
+ break;
+ }
+ } else {
+ // if equal values, ignore set
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: DPset ign-same value dp%d=0x%x,%d"), dp->DPid, dp->desiredValue[0], dp->desiredValueLen);
+ dp->toSet = 0;
+ }
+ }
+ }
+
+ // triggered from second timer
+ if (pTuya->send_heartbeat) {
+ pTuya->send_heartbeat = 0;
+ pTuya->startup_state = TUYA_STARTUP_STATE_SEND_HEARTBEAT;
+ break;
+ }
+ break;
+
+ case TUYA_STARTUP_STATE_WAIT_ACK_CMD:
+ if (cmd == pTuya->expectedResponseCmd){
+ pTuya->timeout = 0;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_SEND_CMD;
+ pTuya->startup_state = TUYA_STARTUP_STATE_SEND_CMD;
+ }
+ break;
+
+ case TUYA_STARTUP_STATE_SEND_HEARTBEAT://
+ // send a heartbeat, and wait up to a second
+ if (cmd >= 0) break;
+ TuyaSendCmd(TUYA_CMD_HEARTBEAT);
+ pTuya->timeout = 1000;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_INIT;
+ pTuya->startup_state = TUYA_STARTUP_STATE_WAIT_ACK_HEARTBEAT;
+ break;
+
+ // wait for heartbeat return
+ case TUYA_STARTUP_STATE_WAIT_ACK_HEARTBEAT://
+ if (cmd == TUYA_CMD_HEARTBEAT){
+ pTuya->timeout = 0;
+ pTuya->timeout_state = TUYA_STARTUP_STATE_SEND_CMD;
+ pTuya->startup_state = TUYA_STARTUP_STATE_SEND_CMD;
+ if (len > 0 && payload[0] == 0){
+ pTuya->startup_state = TUYA_STARTUP_STATE_INIT;
+ }
+ }
+ if (cmd == TUYA_CMD_STATE){
+ // dealt with in receive
+ }
+ break;
+ }
+
+ if (state != pTuya->startup_state){
+ AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("TYA: %d->%d-%d/%d"), state, pTuya->startup_state, pTuya->sends, pTuya->rxs);
+ }
+
+ pTuya->inStateMachine = 0;
+
+}
+
+void TuyaDumpDPStore(){
+#ifdef TUYA_MORE_DEBUG
+ for (int i = 0; i < pTuya->numRxedDPids; i++){
+ TUYA_DP_STORE *dp = &pTuya->DPStore[i];
+
+/*
+ dp->DPid;
+ dp->Type;
+ dp->rxedValue[TUYA_MAX_STRING_SIZE];
+ dp->desiredValue[TUYA_MAX_STRING_SIZE];
+ dp->toSet;
+ dp->rxed;
+*/
+
+ switch(dp->Type){
+ case TUYA_TYPE_RAW:
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: DP%d T%d m:0x%X d0x%X s%d r%d"),
+ dp->DPid, dp->Type, dp->rxedValue[0], dp->desiredValue[0], dp->toSet, dp->rxed);
+ break;
+ case TUYA_TYPE_BOOL:
+ case TUYA_TYPE_ENUM:
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: DP%d T%d m0x%X d0x%X s%d r%d"),
+ dp->DPid, dp->Type, dp->rxedValue[0], dp->desiredValue[0], dp->toSet, dp->rxed);
+ break;
+ case TUYA_TYPE_VALUE:
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: DP%d T%d m%d d%d s%d r%d"),
+ dp->DPid, dp->Type, TUYAREAD32FROMPTR(dp->rxedValue), TUYAREAD32FROMPTR(dp->desiredValue), dp->toSet, dp->rxed);
+ break;
+ case TUYA_TYPE_STRING:
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: DP%d T%d m0x%X d0x%X s%d r%d"),
+ dp->DPid, dp->Type, dp->rxedValue[0], dp->desiredValue[0], dp->toSet, dp->rxed);
+ break;
+ }
+ }
+#endif
+}
+
+// sets a desired value for a DPId,
+// and sets a flag to say we want this value.
+// this is then serviced later to ensure we don't send the same value twice.
+// this solves an issue with some wallplate touch dimmers
+// which are killed by sending off when the device is already off.
+void TuyaPostState(uint8_t id, uint8_t type, uint8_t *value, int len = 4){
+ int i;
+ if (!pTuya){
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: PostState before pTuya DP %d"), id);
+ return;
+ }
+
+ for (i = 0; i < pTuya->numRxedDPids; i++){
+ TUYA_DP_STORE *dp = &pTuya->DPStore[i];
+/*
+ dp->DPid;
+ dp->Type;
+ dp->rxedValue[TUYA_MAX_STRING_SIZE];
+ dp->desiredValue[TUYA_MAX_STRING_SIZE];
+ dp->toSet;
+ dp->rxed;
+*/
+ if (id == dp->DPid){
+ if (type == dp->Type){
+ if (len <= TUYA_MAX_STRING_SIZE){
+ memcpy(dp->desiredValue, value, len);
+ dp->desiredValueLen = len;
+ dp->toSet = 1;
+ pTuya->requestSend = 1;
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: DP%d des v set (0x%x,%d)"), id, dp->desiredValue[0], dp->desiredValueLen);
+
+ if (TuyaDpIdIsDimmer(id)){
+ pTuya->dimDebug = 1; // enable debug to be printed once.
+ }
+ } else {
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: DP %d value over len (%d > %d)"), id, len, TUYA_MAX_STRING_SIZE);
+ }
+ break;
+ } else {
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: set of dpid %d ignored - type %d != requred %d"), id, type, dp->Type);
+ TuyaDumpDPStore();
+ return;
+ }
+ }
+ }
+ if (i == pTuya->numRxedDPids){
+ if (pTuya->numRxedDPids < TUYA_MAX_STORED_DPs){
+ TUYA_DP_STORE *dp = &pTuya->DPStore[pTuya->numRxedDPids];
+ dp->DPid = id;
+ dp->Type = type;
+ if (len <= TUYA_MAX_STRING_SIZE){
+ memcpy(dp->desiredValue, value, len);
+ dp->desiredValueLen = len;
+ dp->toSet = 1;
+ pTuya->requestSend = 1;
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: NEW DP %d desiredvalue set (0x%08x len %d)"), id, dp->desiredValue[0], dp->desiredValueLen);
+ } else {
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: DP %d value over len (%d > %d)"), id, len, TUYA_MAX_STRING_SIZE);
+ }
+ pTuya->numRxedDPids++;
+#ifdef TUYA_MORE_DEBUG
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Add unknown dpid %d in set - num DP:%d"), id, pTuya->numRxedDPids);
+#endif
+ } else {
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: Max Stored DPs exceeded at set of unknown dpid %d ignored - num DP:%d"), id, pTuya->numRxedDPids);
+ }
+ }
+#ifdef TUYA_MORE_DEBUG
+ switch(type){
+ case TUYA_TYPE_RAW:
+ case TUYA_TYPE_BOOL:
+ case TUYA_TYPE_ENUM:
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: dp%d to %d req"), id, *(uint8_t*)value);
+ break;
+ case TUYA_TYPE_VALUE:
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: dp%d to %d req"), id, TUYAREAD32FROMPTR(value));
+ break;
+ case TUYA_TYPE_STRING:
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: dp%d to (?) req"), id);
+ break;
+ }
+ TuyaDumpDPStore();
+#endif
+}
+
+
+// note - direct send using TuyaSendCmd
+void TuyaSendState(uint8_t id, uint8_t type, uint8_t* value, int len)
+{
+ uint16_t payload_len = 4;
+ uint8_t payload_buffer[8+TUYA_MAX_STRING_SIZE];
+ payload_buffer[0] = id;
+ payload_buffer[1] = type;
+ switch (type) {
+ case TUYA_TYPE_BOOL:
+ case TUYA_TYPE_ENUM:
+ payload_len += 1;
+ payload_buffer[2] = 0x00;
+ payload_buffer[3] = 0x01;
+ payload_buffer[4] = value[0];
+ break;
+ case TUYA_TYPE_VALUE:
+ payload_len += 4;
+ payload_buffer[2] = 0x00;
+ payload_buffer[3] = 0x04;
+ // note - already reversed
+ payload_buffer[4] = value[0];
+ payload_buffer[5] = value[1];
+ payload_buffer[6] = value[2];
+ payload_buffer[7] = value[3];
+ break;
+ case TUYA_TYPE_STRING:
+ case TUYA_TYPE_RAW:
+ payload_buffer[2] = len >> 8;
+ payload_buffer[3] = len & 0xFF;
+
+ if (len <= TUYA_MAX_STRING_SIZE){
+ for (uint16_t i = 0; i < len; i++) {
+ payload_buffer[payload_len++] = value[i];
+ }
+ } else {
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: SendState: DP %d value over len (%d > %d)"), id, len, TUYA_MAX_STRING_SIZE);
+ return;
+ }
+ break;
+ }
+
+ TuyaSendCmd(TUYA_CMD_SET_DP, payload_buffer, payload_len);
+}
+
+void TuyaSendBool(uint8_t id, bool value)
+{
+ TuyaPostState(id, TUYA_TYPE_BOOL, (uint8_t*)&value, 1);
+}
+
+void TuyaSendValue(uint8_t id, uint32_t value)
+{
+ uint32_t reversed = TUYAREAD32FROMPTR(&value);
+ TuyaPostState(id, TUYA_TYPE_VALUE, (uint8_t*)&reversed, 4);
+}
+
+void TuyaSendEnum(uint8_t id, uint32_t value)
+{
+ TuyaPostState(id, TUYA_TYPE_ENUM, (uint8_t*)&value, 1);
+}
+
+static uint16_t convertHexStringtoBytes (uint8_t * dest, const char src[], uint16_t dest_len){
+ if (NULL == dest || NULL == src || 0 == dest_len){
+ return 0;
+ }
+
+ char hexbyte[3];
+ hexbyte[2] = 0;
+ uint16_t i;
+
+ for (i = 0; i < dest_len; i++) {
+ hexbyte[0] = src[2*i];
+ hexbyte[1] = src[2*i+1];
+ dest[i] = strtol(hexbyte, NULL, 16);
+ }
+
+ return i;
+}
+
+// note - send immediate, not deferred
+void TuyaSendHexString(uint8_t id, const char data[]) {
+
+ uint16_t len = strlen(data)/2;
+ uint8_t value[len];
+ convertHexStringtoBytes(value, data, len);
+ TuyaPostState(id, TUYA_TYPE_STRING, value, len);
+}
+
+// note - send immediate, not deferred
+void TuyaSendString(uint8_t id, const char data[]) {
+ uint16_t len = strlen(data);
+ TuyaPostState(id, TUYA_TYPE_STRING, (uint8_t*) data, len);
+}
+
+void TuyaSendRaw(uint8_t id, const char data[]) {
+ const char* beginPos = strchr(data, 'x');
+ if(!beginPos) {
+ beginPos = strchr(data, 'X');
+ }
+ if(!beginPos) {
+ beginPos = data;
+ } else {
+ beginPos += 1;
+ }
+ uint16_t strSize = strlen(beginPos);
+ uint16_t len = strSize/2;
+ uint8_t value[len];
+ convertHexStringtoBytes(value, beginPos, len);
+ TuyaPostState(id, TUYA_TYPE_RAW, value, len);
+}
+
+// send ANY cmd with payload from hex string
+void TuyaSendRawCmd(uint8_t cmd, const char data[]) {
+ uint16_t strSize = strlen(data);
+ uint16_t len = strSize/2;
+ uint8_t value[len];
+ convertHexStringtoBytes(value, data, len);
+ TuyaSendCmd(cmd, value, len, 1);
+}
+
+
+bool TuyaSetPower(void)
+{
+ bool status = false;
+
+ uint8_t rpower = XdrvMailbox.index;
+ int16_t source = XdrvMailbox.payload;
+
+ uint8_t dpid = TuyaGetDpId(TUYA_MCU_FUNC_REL1 + TasmotaGlobal.active_device - 1);
+ if (dpid == 0) dpid = TuyaGetDpId(TUYA_MCU_FUNC_REL1_INV + TasmotaGlobal.active_device - 1);
+ uint8_t dev = TasmotaGlobal.active_device-1;
+ uint8_t value = bitRead(rpower, dev) ^ bitRead(TasmotaGlobal.rel_inverted, dev);
+
+ if (source != SRC_SWITCH && TuyaSerial && dpid) { // ignore to prevent loop from pushing state from faceplate interaction
+ TuyaSendBool(dpid, value);
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: post rpower%d v%d dp%d s%d d%d"), rpower, value, dpid, source, dev);
+ // no longer needed as commands wait for ack.
+ //delay(20); // Hack when power is off and dimmer is set then both commands go too soon to Serial out.
+ status = true;
+ } else {
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: rpower%d v%d dp%d ignored s%d d%d"), rpower, value, dpid, source, dev);
+ }
+ return status;
+}
+
+bool TuyaSetChannels(void)
+{
+ uint16_t hue, TuyaData;
+ uint8_t sat, bri;
+ uint8_t TuyaIdx = 0;
+ char hex_char[15];
+ bool noupd = false;
+
+ if ((SRC_SWITCH == TasmotaGlobal.last_source) || (SRC_SWITCH == TasmotaGlobal.last_command_source)) {
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: setchan disbl SRC_SWITCH"));
+ // but pretend we did set them
+ return true;
+ }
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: setchan"));
+
+ bool LightMode = TuyaGetDpId(TUYA_MCU_FUNC_MODESET) != 0;
+ uint8_t idx = 0;
+ snprintf_P(hex_char, sizeof(hex_char), PSTR("000000000000"));
+
+ if (LT_SERIAL1 == TasmotaGlobal.light_type) {
+ pTuya->Snapshot[0] = light_state.getDimmer();
+ }
+
+ if (LT_SERIAL2 == TasmotaGlobal.light_type || LT_RGBWC == TasmotaGlobal.light_type) {
+ idx = 1;
+ if (LT_SERIAL2 == TasmotaGlobal.light_type &&
+ Settings->flag3.pwm_multi_channels &&
+ (TuyaGetDpId(TUYA_MCU_FUNC_DIMMER2) != 0)) {
+ // Special setup for dual dimmer (like the MOES 2 Way Dimmer) emulating 2 PWM channels
+ pTuya->Snapshot[0] = changeUIntScale(Light.current_color[0], 0, 255, 0, 100);
+ pTuya->Snapshot[1] = changeUIntScale(Light.current_color[1], 0, 255, 0, 100);
+ } else { // CT Light or RGBWC
+ getCTRange(&pTuya->CTMin, &pTuya->CTMax); // SetOption82 - Reduce the CT range from 153..500 to 200..380 to accomodate with Alexa range
+ pTuya->Snapshot[0] = light_state.getDimmer();
+ pTuya->Snapshot[1] = light_state.getCT();
+ }
+ }
+
+ if (LT_RGBW == TasmotaGlobal.light_type) {
+ idx = 1;
+ pTuya->Snapshot[0] = light_state.getDimmer(1);
+ pTuya->Snapshot[1] = light_state.getDimmer(2);
+ }
+
+ if (TasmotaGlobal.light_type > LT_BASIC) {
+
+ if (LT_RGB != TasmotaGlobal.light_type) {
+ for (uint8_t i = 0; i <= idx; i++) {
+ if (pTuya->Snapshot[i] != pTuya->Levels[i]) {
+ if (i == 0 && LightMode && pTuya->ModeSet ) { noupd = true;}
+ if (!noupd) {
+ LightSerialDuty(pTuya->Snapshot[i], &hex_char[0], i+1);
+ //pTuya->Levels[i] = pTuya->Snapshot[i];
+ }
+ noupd = false;
+ }
+ }
+ }
+
+ if (TasmotaGlobal.light_type >= LT_RGB) {
+
+ // There are two types of rgb format, configure the correct one using TuyaRGB command.
+ // The most common is 0HUE0SAT0BRI0 and the less common is RRGGBBFFFF6464 and sometimes both are case sensitive:
+ // 0 type 1 Uppercase - 00DF00DC0244
+ // 1 Type 1 Lowercase - 008003e8037a
+ // 2 Type 2 Uppercase - 00FF00FFFF6464
+ // 3 Type 2 Lowercase - 00e420ffff6464
+
+ uint8_t RGBType = Settings->tuya_fnid_map[230].dpid; // Select the type of RGB payload
+ char scolor[7];
+ LightGetColor(scolor, 1); // Always get the color in hex format
+ light_state.getHSB(&hue, &sat, &bri);
+ sat = changeUIntScale(sat, 0, 255, 0, 100);
+ bri = changeUIntScale(bri, 0, 255, 0, 100);
+
+ if ((RGBType > 1 && (StrCmpNoCase(scolor, pTuya->RGBColor) != 0)) ||
+ (RGBType <= 1 && ((hue != pTuya->Snapshot[2]) || (sat != pTuya->Snapshot[3]) || (bri != pTuya->Snapshot[4])) )) {
+
+ if ((LightMode && pTuya->ModeSet) ||
+ LT_RGB == TasmotaGlobal.light_type) {
+ if (TuyaGetDpId(TUYA_MCU_FUNC_RGB) != 0) {
+ switch (RGBType) {
+ case 0: // Uppercase Type 1 payload
+ snprintf_P(hex_char, sizeof(hex_char), PSTR("%04X%04X%04X"), hue, sat * 10, bri * 10);
+ break;
+ case 1: // Lowercase Type 1 payload
+ snprintf_P(hex_char, sizeof(hex_char), PSTR("%04x%04x%04x"), hue, sat * 10, bri * 10);
+ break;
+ case 2: // Uppercase Type 2 payload
+ snprintf_P(hex_char, sizeof(hex_char), PSTR("%sFFFF6464"), scolor);
+ break;
+ case 3: // Lowercase Type 2 payload
+ snprintf_P(hex_char, sizeof(hex_char), PSTR("%sffff6464"), LowerCase(scolor, scolor));
+ break;
+ }
+ memcpy_P(pTuya->RGBColor, scolor, strlen(scolor));
+ pTuya->Snapshot[2] = hue;
+ pTuya->Snapshot[3] = sat;
+ pTuya->Snapshot[4] = bri;
+ }
+ LightSerialDuty(0, &hex_char[0], 3);
+ }
+ }
+ }
+ }
+ return true;
+}
+
+void LightSerialDuty(uint16_t duty, char *hex_char, uint8_t TuyaIdx)
+{
+ uint8_t dpid = TuyaGetDpId(TUYA_MCU_FUNC_DIMMER);
+ bool CTLight = false;
+
+ if (TuyaIdx > 0 && TuyaIdx <= 2) {
+
+ if (TuyaIdx == 2) {
+ if (!Settings->flag3.pwm_multi_channels) {
+ CTLight = true;
+ dpid = TuyaGetDpId(TUYA_MCU_FUNC_CT);
+ } else {
+ dpid = TuyaGetDpId(TUYA_MCU_FUNC_DIMMER2);
+ }
+ }
+
+// if (pTuya->ignore_dim && pTuya->ignore_dimmer_cmd_timeout < millis()) {
+// pTuya->ignore_dim = false;
+// }
+ pTuya->ignore_dim = false;
+
+ if (duty > 0 && !pTuya->ignore_dim && TuyaSerial && dpid > 0) {
+ if (TuyaIdx == 2 && CTLight) {
+ duty = changeUIntScale(duty, pTuya->CTMin, pTuya->CTMax, Settings->dimmer_hw_max, 0);
+ } else {
+ duty = changeUIntScale(duty, 0, 100, Settings->dimmer_hw_min, Settings->dimmer_hw_max);
+ }
+
+ // dimming acts odd below 25(10%) - this mirrors the threshold set on the faceplate itself
+ if (duty < Settings->dimmer_hw_min) {
+ duty = Settings->dimmer_hw_min;
+ }
+
+ //pTuya->ignore_dimmer_cmd_timeout = millis() + 250; // Ignore serial received dim commands for the next 250ms
+ if (pTuya->ModeSet &&
+ (TuyaGetDpId(TUYA_MCU_FUNC_MODESET) != 0) &&
+ TasmotaGlobal.light_type > LT_RGB) {
+ TuyaSendEnum(TuyaGetDpId(TUYA_MCU_FUNC_MODESET), 0);
+ }
+ TuyaSendValue(dpid, duty);
+
+ } else {
+ if (dpid > 0 && TuyaIdx <= 2) {
+ int tasduty = duty;
+
+ pTuya->ignore_dim = false; // reset flag
+
+ if (TuyaIdx == 2 && CTLight) {
+ duty = changeUIntScale(duty, pTuya->CTMin, pTuya->CTMax, Settings->dimmer_hw_max, 0);
+ } else {
+ duty = changeUIntScale(duty, 0, 100, Settings->dimmer_hw_min, Settings->dimmer_hw_max);
+ }
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: dim skip duty%d v%d dp%d"), tasduty, duty, dpid); // due to 0 or already set
+ } else {
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Cannot set dimmer. Dimmer Id unknown"));
+ }
+ }
+ }
+
+ if (TuyaIdx == 3) {
+ dpid = TuyaGetDpId(TUYA_MCU_FUNC_RGB);
+ if (!pTuya->ModeSet &&
+ (TuyaGetDpId(TUYA_MCU_FUNC_MODESET) != 0) &&
+ TasmotaGlobal.light_type > LT_RGB) {
+ TuyaSendEnum(TuyaGetDpId(TUYA_MCU_FUNC_MODESET), 1);
+ }
+ TuyaSendString(dpid, hex_char);
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: TX RGB hex %s to dpId %d"), hex_char, dpid);
+ }
+}
+
+// only use manually!!!
+void TuyaRequestState(uint8_t state_type)
+{
+ if (TuyaSerial) {
+ // Get current status of MCU
+#ifdef TUYA_MORE_DEBUG
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Read MCU state"));
+#endif
+ pTuya->SuspendTopic = true;
+ pTuya->ignore_topic_timeout = millis() + 1000; // suppress /STAT topic for 1000ms to limit data
+ switch (state_type) {
+ case 0:
+ TuyaSendCmd(TUYA_CMD_QUERY_STATE);
+ break;
+ case 8:
+ TuyaSendCmd(TUYA_CMD_QUERY_PRODUCT);
+ break;
+ }
+ }
+}
+
+void TuyaResetWifi(void)
+{
+ if (!Settings->flag.button_restrict) { // SetOption1 - Control button multipress
+ if (pTuya->wifiTimer > 20000){
+ char scmnd[20];
+ snprintf_P(scmnd, sizeof(scmnd), D_CMND_WIFICONFIG " %d", 2);
+ ExecuteCommand(scmnd, SRC_BUTTON);
+ }
+ pTuya->wifiTimer += 10000;
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: Wifi reset button pressed. Press repeatedly to achieve reset"));
+ }
+}
+
+
+///////////////////////////////////////
+// store all DPs received with values,
+// these are used so we don't send DP value which are the same
+// as the MCU has already - e.g. double 'off' can crash dimmers
+void TuyaStoreRxedDP(uint8_t dpid, uint8_t type, uint8_t *data, int dpDataLen){
+ int i;
+ for (i = 0; i < pTuya->numRxedDPids; i++){
+ TUYA_DP_STORE *dp = &pTuya->DPStore[i];
+ if (dp->DPid == dpid){
+ if (type != dp->Type){
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: Type change in rxed dpId=%d type %d -> %d"), dpid, dp->Type, type);
+ dp->Type = type;
+ }
+
+ // if a relay command, then set dim delay, and if value is zero, disable dim command.
+ // if 1, enable dim command.
+ // make it work for single or dual dimmers...
+ uint8_t fnId = TuyaGetFuncId(dpid);
+ if ((fnId == TUYA_MCU_FUNC_REL1) ||
+ (fnId == TUYA_MCU_FUNC_REL1_INV) ||
+ (fnId == TUYA_MCU_FUNC_REL2) ||
+ (fnId == TUYA_MCU_FUNC_REL2_INV)){
+ uint8_t dimindex = 0;
+ if ((fnId == TUYA_MCU_FUNC_REL2) ||
+ (fnId == TUYA_MCU_FUNC_REL2_INV)){
+ dimindex = 1;
+ }
+
+ pTuya->dimDelay_ms[dimindex] = pTuya->defaultDimDelay_ms;
+ int value = data[0];
+ if (!value){
+ pTuya->dimCmdEnable &= 0xfe; (0xff ^ (1<dimCmdEnable |= (1<rxedValue, data, dpDataLen);
+ dp->rxedValueLen = dpDataLen;
+ } else {
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: DP len exceeded dpId=%d type %d (%d > %d"), dpid, type, dpDataLen, TUYA_MAX_STRING_SIZE);
+ }
+ dp->rxed = 1;
+ break;
+ }
+ }
+ if (i == pTuya->numRxedDPids){
+ if (i < TUYA_MAX_STORED_DPs){
+ TUYA_DP_STORE *dp = &pTuya->DPStore[i];
+ dp->DPid = dpid;
+ dp->Type = type;
+ if (dpDataLen <= TUYA_MAX_STRING_SIZE){
+ memcpy(dp->rxedValue, data, dpDataLen);
+ dp->rxedValueLen = dpDataLen;
+ } else {
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: DP len exceeded dpId=%d type %d (%d > %d"), dpid, type, dpDataLen, TUYA_MAX_STRING_SIZE);
+ }
+ dp->rxed = 1;
+ pTuya->numRxedDPids++;
+ } else {
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: Max stored DPs exceeded dpId=%d type %d"), dpid, type);
+ }
+ }
+ TuyaDumpDPStore();
+}
+
+
+////////////////////////////////////////////////
+// process ONE rxed DP value
+void TuyaProcessRxedDP(uint8_t dpid, uint8_t type, uint8_t *data, int dpDataLen){
+ char scmnd[20];
+ bool PowerOff = false;
+ bool tuya_energy_enabled = (XNRG_32 == TasmotaGlobal.energy_driver);
+ uint8_t fnId = TuyaGetFuncId(dpid);
+ uint32_t value = 0;
+
+ if (TuyaFnIdIsDimmer(fnId)){
+ if (fnId == TUYA_MCU_FUNC_DIMMER){ // first dimmer
+ pTuya->dimDelay_ms[0] = pTuya->defaultDimDelay_ms;
+ } else {
+ if (fnId == TUYA_MCU_FUNC_DIMMER2){ // second dimmer
+ pTuya->dimDelay_ms[1] = pTuya->defaultDimDelay_ms;
+ } else { // must be other light, single dimmable thing
+ pTuya->dimDelay_ms[0] = pTuya->defaultDimDelay_ms;
+ }
+ }
+ }
+
+ ////////////////////
+ // get value for types that fit in 4 byte as uint32_t
+ switch(type){
+ case TUYA_TYPE_RAW: // variable length combined?
+ break;
+ case TUYA_TYPE_BOOL: // 1 = 1 byte bool
+ value = data[0];
+ break;
+ case TUYA_TYPE_VALUE: // 2 = 32 bit int
+ value = TUYAREAD32FROMPTR(data);
+ break;
+ case TUYA_TYPE_STRING: // 3
+ break;
+ case TUYA_TYPE_ENUM: // 4 = 1 byte value
+ value = data[0];
+ break;
+ }
+ //////////////////
+
+
+ // incorporated into logs below to save one log line.
+ //AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: fnId=%d is set for dpId=%d"), fnId, dpid);
+ switch(type) {
+ case TUYA_TYPE_RAW: {
+#ifdef USE_ENERGY_SENSOR
+ if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_POWER_COMBINED) {
+ if (dpDataLen >= 8) {
+ // data is pTuya->buffer[dpidStart + 4];
+ uint16_t tmpVol = data[4 - 4] << 8 | data[5 - 4];
+ uint16_t tmpCur = data[7 - 4] << 8 | data[8 - 4];
+ uint16_t tmpPow = data[10 - 4] << 8 | data[11 - 4];
+/* uint16_t tmpVol = pTuya->buffer[dpidStart + 4] << 8 | pTuya->buffer[dpidStart + 5];
+ uint16_t tmpCur = pTuya->buffer[dpidStart + 7] << 8 | pTuya->buffer[dpidStart + 8];
+ uint16_t tmpPow = pTuya->buffer[dpidStart + 10] << 8 | pTuya->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: fnId=%d Rx ID=%d Voltage=%d Current=%d Active_Power=%d"), fnId, dpid, tmpVol, tmpCur, tmpPow);
+
+ if (RtcTime.valid) {
+ if (pTuya->lastPowerCheckTime != 0 && Energy.active_power[0] > 0) {
+ Energy.kWhtoday[0] += Energy.active_power[0] * (float)(Rtc.utc_time - pTuya->lastPowerCheckTime) / 36.0;
+ EnergyUpdateToday();
+ }
+ pTuya->lastPowerCheckTime = Rtc.utc_time;
+ }
+ } else {
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: fnId=%d Rx ID=%d INV_LEN=%d"), fnId, dpid, dpDataLen);
+ }
+ }
+ #endif // USE_ENERGY_SENSOR
+ } break;
+
+ case TUYA_TYPE_BOOL: { // Data Type 1
+ if (fnId >= TUYA_MCU_FUNC_REL1 && fnId <= TUYA_MCU_FUNC_REL8) {
+ AddLog(LOG_LEVEL_DEBUG, PSTR("T:fn%d Relay%d-->M%s T%s"), fnId, fnId - TUYA_MCU_FUNC_REL1 + 1, value?"On":"Off",bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1)?"On":"Off");
+ if (value != bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1)) {
+ if (!value) { PowerOff = true; }
+ ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1 + 1, value, SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction
+ }
+ } else if (fnId >= TUYA_MCU_FUNC_REL1_INV && fnId <= TUYA_MCU_FUNC_REL8_INV) {
+ AddLog(LOG_LEVEL_DEBUG, PSTR("T:fn%d Relay%d-Inv-->M%s T%s"), fnId, fnId - TUYA_MCU_FUNC_REL1_INV + 1, value?"Off":"On",bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1?"Off":"On");
+ if (value != bitRead(TasmotaGlobal.power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1) {
+ ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1_INV + 1, value ^ 1, SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction
+ if (value) { PowerOff = true; }
+ }
+ } else if (fnId >= TUYA_MCU_FUNC_SWT1 && fnId <= TUYA_MCU_FUNC_SWT4) {
+ AddLog(LOG_LEVEL_DEBUG, PSTR("T:fn%d Switch%d --> M%d T%d"),fnId, fnId - TUYA_MCU_FUNC_SWT1 + 1, value, SwitchGetVirtual(fnId - TUYA_MCU_FUNC_SWT1));
+
+ if (SwitchGetVirtual(fnId - TUYA_MCU_FUNC_SWT1) != value) {
+ SwitchSetVirtual(fnId - TUYA_MCU_FUNC_SWT1, value);
+ SwitchHandler(1);
+ }
+ }
+ //if (PowerOff) { pTuya->ignore_dimmer_cmd_timeout = millis() + 250; }
+ } break;
+
+ case TUYA_TYPE_VALUE: { // Data Type 2
+ uint32_t packetValue = value; // TYpe 2 is a 32 bit integer
+ uint8_t dimIndex;
+ bool SnsUpdate = false;
+
+ if ((fnId >= TUYA_MCU_FUNC_TEMP) && (fnId <= TUYA_MCU_FUNC_TIMER4)) { // Sensors start from fnId 71
+ if (packetValue != pTuya->Sensors[fnId-71]) {
+ pTuya->SensorsValid[fnId-71] = true;
+ pTuya->Sensors[fnId-71] = packetValue;
+ SnsUpdate = true;
+ }
+ }
+
+ if (SnsUpdate) {
+ char sname[20];
+ char tempval[5];
+ uint8_t res;
+ bool dont_publish = Settings->flag5.tuyasns_no_immediate;
+
+ if (TasmotaGlobal.uptime < 8) { // delay to avoid multiple topics at the same time at boot time
+ return;
+ } else {
+ if (fnId > 80 || fnId == 74 || fnId == 72) {
+ dont_publish = false;
+ }
+ if (fnId > 74) {
+ res = 0;
+ } else if (fnId > 72) {
+ res = Settings->flag2.humidity_resolution;
+ } else if (fnId == 72) {
+ res = Settings->mbflag2.temperature_set_res;
+ } else {
+ res = Settings->flag2.temperature_resolution;
+ }
+ GetTextIndexed(sname, sizeof(sname), (fnId-71), kTuyaSensors);
+ ResponseClear(); // Clear retained message
+ Response_P(PSTR("{\"TuyaSNS\":{\"%s\":%s}}"), sname, dtostrfd(TuyaAdjustedTemperature(packetValue, res), res, tempval)); // sensor update is just on change
+ if (dont_publish) {
+ XdrvRulesProcess(0);
+ } else {
+ MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_CMND_SENSOR));
+ }
+ }
+ }
+
+ if (fnId == TUYA_MCU_FUNC_DIMMER || fnId == TUYA_MCU_FUNC_REPORT1) { dimIndex = 0; }
+
+ if (fnId == TUYA_MCU_FUNC_DIMMER2 || fnId == TUYA_MCU_FUNC_REPORT2 || fnId == TUYA_MCU_FUNC_CT) { dimIndex = 1; }
+
+ if (dimIndex == 1 && !Settings->flag3.pwm_multi_channels) {
+ pTuya->Levels[1] = changeUIntScale(packetValue, 0, Settings->dimmer_hw_max, pTuya->CTMax, pTuya->CTMin);
+ } else {
+ pTuya->Levels[dimIndex] = changeUIntScale(packetValue, Settings->dimmer_hw_min, Settings->dimmer_hw_max, 0, 100);
+ }
+
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: fn%d value %d dp%d "), fnId, packetValue, dpid);
+
+ if ((fnId == TUYA_MCU_FUNC_DIMMER) || (fnId == TUYA_MCU_FUNC_REPORT1) ||
+ (fnId == TUYA_MCU_FUNC_DIMMER2) || (fnId == TUYA_MCU_FUNC_REPORT2) ||
+ (fnId == TUYA_MCU_FUNC_CT) || (fnId == TUYA_MCU_FUNC_WHITE)) {
+
+ // SetOption54 - Apply SetOption20 settings to Tuya device / SetOption131 Allow save dimmer = 0 receved by MCU
+ if (1) {//pTuya->ignore_dimmer_cmd_timeout < millis()) {
+ if ((TasmotaGlobal.power || Settings->flag3.tuya_apply_o20) &&
+ ((pTuya->Levels[dimIndex] > 0 || Settings->flag5.tuya_allow_dimmer_0) &&
+ (pTuya->Levels[dimIndex] != pTuya->Snapshot[dimIndex]))) {
+ //pTuya->ignore_dim = true;
+ TasmotaGlobal.skip_light_fade = true;
+
+ scmnd[0] = '\0';
+ if ((fnId == TUYA_MCU_FUNC_DIMMER) || (fnId == TUYA_MCU_FUNC_REPORT1)) {
+ if (Settings->flag3.pwm_multi_channels && (abs(pTuya->Levels[0] - changeUIntScale(Light.current_color[0], 0, 255, 0, 100))) > 1) {
+ snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_CHANNEL "1 %d"), pTuya->Levels[0]);
+ }
+ else if ((abs(pTuya->Levels[0] - light_state.getDimmer())) > 1) {
+ snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER "3 %d"), pTuya->Levels[0]);
+ }
+ }
+ if (((fnId == TUYA_MCU_FUNC_DIMMER2) || (fnId == TUYA_MCU_FUNC_REPORT2)) &&
+ Settings->flag3.pwm_multi_channels && (abs(pTuya->Levels[1] - changeUIntScale(Light.current_color[1], 0, 255, 0, 100))) > 1) {
+ snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_CHANNEL "2 %d"), pTuya->Levels[1]);
+ }
+ if ((fnId == TUYA_MCU_FUNC_CT) && (abs(pTuya->Levels[1] - light_state.getCT())) > 1) {
+ snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_COLORTEMPERATURE " %d"), pTuya->Levels[1]);
+ }
+ if ((fnId == TUYA_MCU_FUNC_WHITE) && (abs(pTuya->Levels[1] - light_state.getDimmer(2))) > 1) {
+ snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_WHITE " %d"), pTuya->Levels[1]);
+ }
+ if (scmnd[0] != '\0') {
+ ExecuteCommand(scmnd, SRC_SWITCH);
+ }
+ }
+ pTuya->Snapshot[dimIndex] = pTuya->Levels[dimIndex];
+ }
+ }
+ #ifdef USE_ENERGY_SENSOR
+ else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_VOLTAGE) {
+ Energy.voltage[0] = (float)packetValue / 10;
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: fnId=%d Rx ID=%d Voltage=%d"), fnId, dpid, packetValue);
+ } else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_CURRENT) {
+ Energy.current[0] = (float)packetValue / 1000;
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: fnId=%d Rx ID=%d Current=%d"), fnId, dpid, packetValue);
+ } else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_POWER) {
+ Energy.active_power[0] = (float)packetValue / 10;
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: fnId=%d Rx ID=%d Active_Power=%d"), fnId, dpid, packetValue);
+
+ if (RtcTime.valid) {
+ if (pTuya->lastPowerCheckTime != 0 && Energy.active_power[0] > 0) {
+ Energy.kWhtoday[0] += Energy.active_power[0] * (float)(Rtc.utc_time - pTuya->lastPowerCheckTime) / 36.0;
+ EnergyUpdateToday();
+ }
+ pTuya->lastPowerCheckTime = Rtc.utc_time;
+ }
+ } else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_POWER_TOTAL) {
+ Energy.import_active[0] = (float)packetValue / 100;
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: fnId=%d Rx ID=%d Total_Power=%d"), fnId, dpid, packetValue);
+ EnergyUpdateTotal();
+ }
+ #endif // USE_ENERGY_SENSOR
+ } break;
+
+ case TUYA_TYPE_STRING: { // Data Type 3
+ const unsigned char *dpData = (unsigned char*)data;
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: (str) fnId=%d is set for dpId=%d"), dpid);
+ if ((TuyaGetDpId(TUYA_MCU_FUNC_RGB) != 0)) {
+
+ uint8_t RGBType = Settings->tuya_fnid_map[230].dpid; // Select the type of hex configured
+ char RgbData[15];
+ char RGB[7];
+ char HSB1[5], HSB2[5], HSB3[5];
+ scmnd[0] = '\0';
+ snprintf_P(RgbData, sizeof(RgbData), PSTR("%.*s"), dpDataLen, dpData);
+
+ if (RGBType <= 1 && dpDataLen == 12) {
+ snprintf_P(HSB1, sizeof(HSB1), PSTR("%.4s\n"), &RgbData[0]);
+ snprintf_P(HSB2, sizeof(HSB2), PSTR("%.4s\n"), &RgbData[4]);
+ snprintf_P(HSB3, sizeof(HSB3), PSTR("%.4s\n"), &RgbData[8]);
+ if ((pTuya->Snapshot[2] != ((int)strtol(HSB1, NULL, 16)) ||
+ (pTuya->Snapshot[3] != ((int)strtol(HSB2, NULL, 16)) / 10) ||
+ (pTuya->Snapshot[4] !=((int)strtol(HSB3, NULL, 16)) / 10)) ) {
+ pTuya->Snapshot[2] = ((int)strtol(HSB1, NULL, 16));
+ pTuya->Snapshot[3] = ((int)strtol(HSB2, NULL, 16)) / 10;
+ pTuya->Snapshot[4] = ((int)strtol(HSB3, NULL, 16)) / 10;
+ snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_HSBCOLOR " %d,%d,%d"), ((int)strtol(HSB1, NULL, 16)),
+ ((int)strtol(HSB2, NULL, 16)) / 10, ((int)strtol(HSB3, NULL, 16)) / 10);
+ }
+ }
+ if (RGBType > 1 && dpDataLen == 14) {
+ snprintf_P(RGB, sizeof(RGB), PSTR("%.6s\n"), &RgbData[0]);
+ if (StrCmpNoCase(RGB, pTuya->RGBColor) != 0) {
+ snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_COLOR " %s"), RGB);
+ memcpy_P(pTuya->RGBColor, RGB, strlen(RGB));
+ }
+ }
+ if (scmnd[0] != '\0') {
+ ExecuteCommand(scmnd, SRC_SWITCH);
+ }
+ }
+
+ } break;
+
+ case TUYA_TYPE_ENUM: { // Data Type 4
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: (enum) fnId=%d is set for dpId=%d"), dpid);
+ if ((fnId == TUYA_MCU_FUNC_MODESET)) { // Toggle light type
+ pTuya->ModeSet = value;
+ pTuya->Levels[3] = value;
+ }
+ if ((fnId >= TUYA_MCU_FUNC_ENUM1) && (fnId <= TUYA_MCU_FUNC_ENUM4)) {
+ for (uint8_t i = 0; i <= 3; i++) {
+ bool noupdate = false;
+ if ((TUYA_MCU_FUNC_ENUM1 + i) == fnId) {
+ if (pTuya->EnumState[i] != value) {
+ pTuya->EnumState[i] = value;
+ snprintf_P(scmnd, sizeof(scmnd), PSTR(D_PRFX_TUYA D_CMND_TUYA_ENUM "%d %d"), i+1, value);
+ ExecuteCommand(scmnd, SRC_SWITCH);
+ }
+ }
+ }
+ }
+ } break;
+ }
+}
+
+
+void TuyaProcessStatePacket(void) {
+ uint8_t dpidStart = 6;
+
+ while (dpidStart + 4 < pTuya->byte_counter) {
+ uint8_t dpid = pTuya->buffer[dpidStart];
+ uint8_t type = pTuya->buffer[dpidStart + 1];
+ uint8_t *data = pTuya->buffer + dpidStart + 4;
+ uint16_t dpDataLen = pTuya->buffer[dpidStart + 2] << 8 | pTuya->buffer[dpidStart + 3];
+ TuyaStoreRxedDP(dpid, type, data, dpDataLen);
+ TuyaProcessRxedDP(dpid, type, data, dpDataLen);
+ dpidStart += dpDataLen + 4;
+ }
+}
+
+void TuyaLowPowerModePacketProcess(void) {
+ switch (pTuya->buffer[3]) {
+ case TUYA_CMD_QUERY_PRODUCT:
+ TuyaHandleProductInfoPacket();
+ //TuyaSetWifiLed();
+ break;
+
+ case TUYA_LOW_POWER_CMD_STATE:
+ TuyaProcessStatePacket();
+ pTuya->send_success_next_second = true;
+ break;
+ }
+
+}
+
+void TuyaHandleProductInfoPacket(void) {
+ uint16_t dataLength = pTuya->buffer[4] << 8 | pTuya->buffer[5];
+ char *data = (char *)&pTuya->buffer[6];
+ AddLog(LOG_LEVEL_INFO, PSTR("TYA: MCU Product ID: %.*s"), dataLength, data);
+}
+
+void TuyaNormalPowerModePacketProcess(void)
+{
+ switch (pTuya->buffer[3]) {
+ case TUYA_CMD_QUERY_PRODUCT:
+ TuyaHandleProductInfoPacket();
+ // next send now done as part of startup state machine
+ //TuyaSendCmd(TUYA_CMD_MCU_CONF);
+ break;
+
+ case TUYA_CMD_HEARTBEAT:
+#ifdef TUYA_MORE_DEBUG
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Hbt"));
+#endif
+ if (pTuya->buffer[6] == 0) {
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Detected MCU restart"));
+ pTuya->wifi_state = -2;
+ }
+ break;
+
+ case TUYA_CMD_STATE:
+ TuyaProcessStatePacket();
+ break;
+
+ case TUYA_CMD_WIFI_RESET:
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: RX WiFi Reset"));
+ // ack MCU request immediately
+ // https://developer.tuya.com/en/docs/iot/wifi-module-mcu-development-overview-for-homekit?id=Kaa8fvusmgapc
+ // set 'noerror', as we are responding
+ TuyaSendCmd(TUYA_CMD_WIFI_RESET, nullptr, 0, 1);
+ TuyaResetWifi();
+ break;
+ case TUYA_CMD_WIFI_SELECT:
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: RX WiFi Select"));
+ // ack MCU request immediately
+ // https://developer.tuya.com/en/docs/iot/wifi-module-mcu-development-overview-for-homekit?id=Kaa8fvusmgapc
+ // set 'noerror', as we are responding
+ TuyaSendCmd(TUYA_CMD_WIFI_SELECT, nullptr, 0, 1);
+ TuyaResetWifi();
+ break;
+
+ case TUYA_CMD_WIFI_STATE:
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: RX WiFi LED set ACK"));
+ pTuya->wifi_state = TuyaGetTuyaWifiState();
+ break;
+
+ case TUYA_CMD_MCU_CONF:
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: RX MCU configuration Mode=%d"), pTuya->buffer[5]);
+
+ if (pTuya->buffer[5] == 2) { // Processing by ESP module mode
+ uint8_t led1_gpio = pTuya->buffer[6];
+ uint8_t key1_gpio = pTuya->buffer[7];
+ bool key1_set = false;
+ bool led1_set = false;
+ for (uint32_t i = 0; i < nitems(Settings->my_gp.io); i++) {
+ if (Settings->my_gp.io[i] == AGPIO(GPIO_LED1)) led1_set = true;
+ else if (Settings->my_gp.io[i] == AGPIO(GPIO_KEY1)) key1_set = true;
+ }
+ if (!Settings->my_gp.io[led1_gpio] && !led1_set) {
+ Settings->my_gp.io[led1_gpio] = AGPIO(GPIO_LED1);
+ TasmotaGlobal.restart_flag = 2;
+ }
+ if (!Settings->my_gp.io[key1_gpio] && !key1_set) {
+ Settings->my_gp.io[key1_gpio] = AGPIO(GPIO_KEY1);
+ TasmotaGlobal.restart_flag = 2;
+ }
+ }
+ // next send now done as part of startup state machine
+ //TuyaRequestState(0);
+ break;
+#ifdef USE_TUYA_TIME
+ case TUYA_CMD_SET_TIME:
+ // send from state machine.
+ pTuya->send_time = 3;
+ //TuyaSetTime();
+ break;
+#endif
+ default:
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: RX unknown command"));
+ }
+}
+
+/*********************************************************************************************\
+ * API Functions
+\*********************************************************************************************/
+
+bool TuyaModuleSelected(void) {
+#ifdef ESP8266
+ if (TUYA_DIMMER != TasmotaGlobal.module_type) { return false; }
+
+ if (!PinUsed(GPIO_TUYA_RX) || !PinUsed(GPIO_TUYA_TX)) { // fallback to hardware-serial if not explicitly selected
+ SetPin(1, AGPIO(GPIO_TUYA_TX));
+ SetPin(3, AGPIO(GPIO_TUYA_RX));
+ Settings->my_gp.io[1] = AGPIO(GPIO_TUYA_TX);
+ Settings->my_gp.io[3] = AGPIO(GPIO_TUYA_RX);
+ TasmotaGlobal.restart_flag = 2;
+ }
+#endif
+ if (!PinUsed(GPIO_TUYA_RX) || !PinUsed(GPIO_TUYA_TX)) { return false; }
+ // allocate and initialise the sturcture only if we will use it.
+ init_tuya_struct();
+
+ if (!pTuya){ return false; }
+
+ if (TuyaGetDpId(TUYA_MCU_FUNC_DIMMER) == 0 && TUYA_DIMMER_ID > 0) {
+ TuyaAddMcuFunc(TUYA_MCU_FUNC_DIMMER, TUYA_DIMMER_ID);
+ }
+
+ bool relaySet = false;
+
+ for (uint8_t i = 0 ; i < MAX_TUYA_FUNCTIONS; i++) {
+ if ((Settings->tuya_fnid_map[i].fnid >= TUYA_MCU_FUNC_REL1 && Settings->tuya_fnid_map[i].fnid <= TUYA_MCU_FUNC_REL8 ) ||
+ (Settings->tuya_fnid_map[i].fnid >= TUYA_MCU_FUNC_REL1_INV && Settings->tuya_fnid_map[i].fnid <= TUYA_MCU_FUNC_REL8_INV )) {
+ relaySet = true;
+ TasmotaGlobal.devices_present++;
+ }
+ }
+
+ if (!relaySet && TuyaGetDpId(TUYA_MCU_FUNC_DUMMY) == 0) { //by default the first relay is created automatically the dummy let remove it if not needed
+ TuyaAddMcuFunc(TUYA_MCU_FUNC_REL1, 1);
+ TasmotaGlobal.devices_present++;
+ SettingsSaveAll();
+ }
+
+ // Possible combinations for Lights:
+ // 0: NONE = LT_BASIC
+ // 1: DIMMER = LT_SERIAL1 - Common one channel dimmer
+ // 2: DIMMER, DIMMER2 = LT_SERIAL2 - Two channels dimmer (special setup used with SetOption68)
+ // 3: DIMMER, CT = LT_SERIAL2 - Dimmable light and White Color Temperature
+ // 4: DIMMER, RGB = LT_RGB - RGB Light
+ // 5: DIMMER, RGB, CT = LT_RGBWC - RGB LIght and White Color Temperature
+ // 6: DIMMER, RGB, WHITE = LT_RGBW - RGB LIght and White
+
+ if (TuyaGetDpId(TUYA_MCU_FUNC_DIMMER) != 0) {
+ if (TuyaGetDpId(TUYA_MCU_FUNC_RGB) != 0) {
+ if (TuyaGetDpId(TUYA_MCU_FUNC_CT) != 0) {
+ TasmotaGlobal.light_type = LT_RGBWC;
+ } else if (TuyaGetDpId(TUYA_MCU_FUNC_WHITE) != 0) {
+ TasmotaGlobal.light_type = LT_RGBW;
+ } else { TasmotaGlobal.light_type = LT_RGB; }
+ } else if (TuyaGetDpId(TUYA_MCU_FUNC_CT) != 0 || TuyaGetDpId(TUYA_MCU_FUNC_DIMMER2) != 0) {
+ if (TuyaGetDpId(TUYA_MCU_FUNC_RGB) != 0) {
+ TasmotaGlobal.light_type = LT_RGBWC;
+ } else { TasmotaGlobal.light_type = LT_SERIAL2; }
+ } else { TasmotaGlobal.light_type = LT_SERIAL1; }
+ } else {
+ TasmotaGlobal.light_type = LT_BASIC;
+ }
+
+ if (TuyaGetDpId(TUYA_MCU_FUNC_LOWPOWER_MODE) != 0) {
+ pTuya->low_power_mode = true;
+ Settings->flag3.fast_power_cycle_disable = true; // SetOption65 - Disable fast power cycle detection for device reset
+ }
+
+ UpdateDevices();
+ return true;
+}
+
+void TuyaInit(void) {
+ int baudrate = 9600;
+ if (Settings->flag4.tuyamcu_baudrate) { baudrate = 115200; } // SetOption97 - Set Baud rate for TuyaMCU serial communication (0 = 9600 or 1 = 115200)
+
+ TuyaSerial = new TasmotaSerial(Pin(GPIO_TUYA_RX), Pin(GPIO_TUYA_TX), 2);
+ if (TuyaSerial->begin(baudrate)) {
+ if (TuyaSerial->hardwareSerial()) { ClaimSerial(); }
+ // Get MCU Configuration
+ pTuya->SuspendTopic = true;
+ pTuya->ignore_topic_timeout = millis() + 1000; // suppress /STAT topic for 1000ms to avoid data overflow
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Request MCU configuration at %d bps"), baudrate);
+
+ pTuya->heartbeat_timer = 0; // init heartbeat timer when dimmer init is done
+ return;
+ }
+ pTuya->active = false;
+}
+
+// dump a buffer to debug
+void TuyaDump(unsigned char *buffer, int len){
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Raw Data %*_H"), len, buffer);
+}
+
+// here we have a complete packet with valid checksum
+void TuyaProcessCommand(unsigned char *buffer){
+ uint16_t len = buffer[4] << 8 | buffer[5];
+ uint16_t totallen = len + 7;
+ uint8_t ver = buffer[2];
+ uint8_t cmd = buffer[3];
+
+ pTuya->rxs ++;
+
+
+ // see if we are awaiting this cmd ack
+ // some MCU send 0x00 in ver field,
+ // so we could assume some send 0x01, some 0x02, some 0x03?
+ // I'v not seen any docs about what the VER means!....
+ //if (0x03 == ver) {
+ Tuya_statemachine(cmd, len, (unsigned char *)buffer+6);
+ //}
+
+ Response_P(PSTR("{\"" D_JSON_TUYA_MCU_RECEIVED "\":{\"Data\":\"%*_H\",\"Cmnd\":%d"), totallen, buffer, cmd);
+
+ uint16_t DataVal = 0;
+ uint8_t dpId = 0;
+ uint8_t dpDataType = 0;
+ char DataStr[15];
+ bool isCmdToSuppress = false;
+
+ if (len > 0) {
+ ResponseAppend_P(PSTR(",\"CmndData\":\"%*_H\""), len, (unsigned char*)&buffer[6]);
+ if (TUYA_CMD_STATE == cmd) {
+ //55 AA 03 07 00 0D 01 04 00 01 02 02 02 00 04 00 00 00 1A 40
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+ uint8_t dpidStart = 6;
+ while (dpidStart + 4 < totallen-1) {
+ dpId = buffer[dpidStart];
+ dpDataType = buffer[dpidStart + 1];
+ uint16_t dpDataLen = buffer[dpidStart + 2] << 8 | buffer[dpidStart + 3];
+ const unsigned char *dpData = (unsigned char*)&buffer[dpidStart + 4];
+
+ if (TUYA_CMD_STATE == buffer[3]) {
+ ResponseAppend_P(PSTR(",\"DpType%uId%u\":"), dpDataType, dpId);
+ if (TUYA_TYPE_BOOL == dpDataType && dpDataLen == 1) {
+ ResponseAppend_P(PSTR("%u"), dpData[0]);
+ DataVal = dpData[0];
+ } else if (TUYA_TYPE_VALUE == dpDataType && dpDataLen == 4) {
+ uint32_t dpValue = (uint32_t)dpData[0] << 24 | (uint32_t)dpData[1] << 16 | (uint32_t)dpData[2] << 8 | (uint32_t)dpData[3] << 0;
+ ResponseAppend_P(PSTR("%u"), dpValue);
+ DataVal = dpValue;
+ } else if (TUYA_TYPE_STRING == dpDataType) {
+ ResponseAppend_P(PSTR("\"%.*s\""), dpDataLen, dpData);
+ snprintf_P(DataStr, sizeof(DataStr), PSTR("%.*s"), dpDataLen, dpData);
+ } else if (TUYA_TYPE_ENUM == dpDataType && dpDataLen == 1) {
+ ResponseAppend_P(PSTR("%u"), dpData[0]);
+ DataVal = dpData[0];
+ } else {
+ ResponseAppend_P(PSTR("\"0x%*_H\""), dpDataLen, dpData);
+ snprintf_P(DataStr, sizeof(DataStr), PSTR("%*_H"), dpDataLen, dpData);
+ }
+ }
+
+ ResponseAppend_P(PSTR(",\"%d\":{\"DpId\":%d,\"DpIdType\":%d,\"DpIdData\":\"%*_H\""), dpId, dpId, dpDataType, dpDataLen, dpData);
+ if (TUYA_TYPE_STRING == dpDataType) {
+ ResponseAppend_P(PSTR(",\"Type3Data\":\"%.*s\""), dpDataLen, dpData);
+ }
+ ResponseAppend_P(PSTR("}"));
+ dpidStart += dpDataLen + 4;
+ }
+ }
+ }
+ ResponseAppend_P(PSTR("}}"));
+
+ // SetOption66 - Enable TuyaMcuReceived messages over Mqtt
+ if (Settings->flag3.tuya_serial_mqtt_publish) {
+ for (uint8_t cmdsID = 0; sizeof(TuyaExcludeCMDsFromMQTT) > cmdsID; cmdsID++){
+ if (TuyaExcludeCMDsFromMQTT[cmdsID] == cmd) {
+ isCmdToSuppress = true;
+ break;
+ }
+ }
+ // SetOption137 - (Tuya) When Set, avoid the (MQTT-) publish of defined Tuya CMDs
+ // (see TuyaExcludeCMDsFromMQTT) if SetOption66 is active
+ if (!(isCmdToSuppress && Settings->flag5.tuya_exclude_from_mqtt)) {
+ MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_TUYA_MCU_RECEIVED));
+ }
+ } else {
+ AddLog(LOG_LEVEL_DEBUG, ResponseData());
+ }
+ XdrvRulesProcess(0);
+
+ if (dpId != 0 && Settings->tuyamcu_topic) { // Publish a /STAT Topic ready to use for any home automation system
+ if (!pTuya->SuspendTopic) {
+ char scommand[13];
+ snprintf_P(scommand, sizeof(scommand), PSTR("DpType%uId%u"), dpDataType, dpId);
+ if (dpDataType != 3 && dpDataType != 5) { Response_P(PSTR("%u"), DataVal); }
+ else { Response_P(PSTR("%s"), DataStr); }
+ MqttPublishPrefixTopic_P(STAT, scommand);
+ }
+ }
+
+ if (!pTuya->low_power_mode) {
+ TuyaNormalPowerModePacketProcess();
+ } else {
+ TuyaLowPowerModePacketProcess();
+ }
+}
+
+// processes one byte of Tuya input.
+// on packet complete with good CS, calls TuyaProcessCommand
+void TuyaProcessByte(unsigned char serial_in_byte){
+
+/* I don't think it's safe to do this with RGB possibly containing 55AA in the message.
+ if ((pTuya->cmd_status != 1) &&
+ (pTuya->lastByte == 0x55) &&
+ (serial_in_byte == 0xAA)){
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: Reset by unexpected 55AA"));
+ TuyaDump(pTuya->buffer, pTuya->byte_counter);
+
+ pTuya->byte_counter = 0;
+ pTuya->buffer[pTuya->byte_counter++] = 0x55;
+ pTuya->cmd_status = 1;
+ pTuya->errorcnt ++;
+ }
+*/
+
+ unsigned int now = millis();
+ if ((pTuya->cmd_status != 0) && (now - pTuya->lastByteTime > TUYA_BYTE_TIMEOUT_MS)){
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: Reset by char timeout %u > %dms"), now - pTuya->lastByteTime, TUYA_BYTE_TIMEOUT_MS);
+ TuyaDump(pTuya->buffer, pTuya->byte_counter);
+ pTuya->cmd_status = 0;
+ pTuya->errorcnt ++;
+ }
+ pTuya->lastByteTime = now;
+
+ switch(pTuya->cmd_status){
+ case 0: {// wait 55
+ if (serial_in_byte == 0x55) { // Start TUYA Packet
+ pTuya->cmd_status = 1;
+ pTuya->byte_counter = 0;
+ pTuya->buffer[pTuya->byte_counter++] = serial_in_byte;
+ } else {
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: E55 0x%02X"), serial_in_byte);
+ pTuya->errorcnt ++;
+ }
+ } break;
+ case 1: {// wait AA
+ if (serial_in_byte == 0xAA) { // Start TUYA Packet
+ pTuya->cmd_status = 2;
+ pTuya->buffer[pTuya->byte_counter++] = serial_in_byte;
+ pTuya->cmd_checksum = 0xFF;
+ } else {
+ // no AA, return to wait for 55
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: EAA 0x%02X"), serial_in_byte);
+ pTuya->errorcnt ++;
+ pTuya->cmd_status = 0;
+ }
+ } break;
+ case 2: {// wait len
+ if (pTuya->byte_counter == 5) { // Get length of data
+ pTuya->data_len = serial_in_byte;
+ pTuya->data_len += pTuya->buffer[4] << 8;
+ if (pTuya->data_len == 0){
+ // straight to CS
+ pTuya->cmd_status = 4;
+ } else {
+ pTuya->cmd_status = 3;
+ }
+ }
+ pTuya->cmd_checksum += serial_in_byte;
+ pTuya->cmd_checksum &= 0xff;
+ pTuya->buffer[pTuya->byte_counter++] = serial_in_byte;
+ } break;
+ case 3: {// wait Data
+ pTuya->buffer[pTuya->byte_counter++] = serial_in_byte;
+ pTuya->cmd_checksum += serial_in_byte;
+ pTuya->cmd_checksum &= 0xff;
+ if (pTuya->byte_counter == (6 + pTuya->data_len)) {
+ pTuya->cmd_status = 4;
+ }
+
+ if (pTuya->byte_counter > TUYA_BUFFER_SIZE-3){
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: input overflow"));
+ TuyaDump(pTuya->buffer, pTuya->byte_counter);
+ pTuya->cmd_status = 0;
+ pTuya->byte_counter = 0;
+ }
+ } break;
+ case 4: {// wait CS
+ pTuya->buffer[pTuya->byte_counter++] = serial_in_byte;
+ pTuya->cmd_checksum &= 0xff;
+ if (pTuya->cmd_checksum == serial_in_byte) { // Compare checksum and process packet
+ TuyaProcessCommand(pTuya->buffer);
+ pTuya->cmd_status = 0;
+ pTuya->byte_counter = 0;
+ } else {
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: Bad CS 0x%02X != 0x%02X"), serial_in_byte, pTuya->cmd_checksum);
+ TuyaDump(pTuya->buffer, pTuya->byte_counter);
+ pTuya->cmd_status = 0;
+ pTuya->byte_counter = 0;
+ pTuya->errorcnt ++;
+ }
+ } break;
+ }
+ pTuya->lastByte = serial_in_byte;
+}
+
+
+void TuyaSerialInput(void)
+{
+ while (TuyaSerial->available()) {
+ yield();
+ uint8_t serial_in_byte = TuyaSerial->read();
+ TuyaProcessByte(serial_in_byte);
+ }
+}
+
+bool TuyaButtonPressed(void)
+{
+ if (!XdrvMailbox.index && ((PRESSED == XdrvMailbox.payload) && (NOT_PRESSED == Button.last_state[XdrvMailbox.index]))) {
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: Reset GPIO triggered"));
+ TuyaResetWifi();
+ return true; // Reset GPIO served here
+ }
+ return false; // Don't serve other buttons
+}
+
+uint8_t TuyaGetTuyaWifiState(void) {
+
+ uint8_t wifi_state = 0x02;
+ switch(WifiState()){
+ case WIFI_MANAGER:
+ wifi_state = 0x01;
+ break;
+ case WIFI_RESTART:
+ wifi_state = 0x03;
+ break;
+ }
+
+ if (MqttIsConnected()) {
+ wifi_state = 0x04;
+ }
+
+ return wifi_state;
+}
+
+#ifdef USE_TUYA_TIME
+void TuyaSetTime(void) {
+ if (!RtcTime.valid) { return; }
+
+ uint16_t payload_len = 8;
+ uint8_t payload_buffer[8];
+ uint8_t tuya_day_of_week;
+ if (RtcTime.day_of_week == 1) {
+ tuya_day_of_week = 7;
+ } else {
+ tuya_day_of_week = RtcTime.day_of_week-1;
+ }
+
+ payload_buffer[0] = 0x01;
+ payload_buffer[1] = RtcTime.year %100;
+ payload_buffer[2] = RtcTime.month;
+ payload_buffer[3] = RtcTime.day_of_month;
+ payload_buffer[4] = RtcTime.hour;
+ payload_buffer[5] = RtcTime.minute;
+ payload_buffer[6] = RtcTime.second;
+ payload_buffer[7] = tuya_day_of_week; //1 for Monday in TUYA Doc
+
+ TuyaSendCmd(TUYA_CMD_SET_TIME, payload_buffer, payload_len);
+}
+#endif //USE_TUYA_TIME
+
+/*********************************************************************************************\
+ * Sensors
+\*********************************************************************************************/
+
+void TuyaSensorsShow(bool json)
+{
+ bool RootName = false;
+ bool added = false;
+ char sname[20];
+ char tempval[5];
+ uint8_t res;
+
+ for (uint8_t sensor = TUYA_MCU_FUNC_TEMP; sensor <= TUYA_MCU_FUNC_TIMER4; sensor++) { // Sensors start from fnId 71
+ if (json) {
+ if (TuyaGetDpId(sensor) != 0) {
+
+ if (!RootName) {
+ ResponseAppend_P(PSTR(",\"TuyaSNS\":{"));
+ RootName = true;
+ }
+ if (added) {
+ ResponseAppend_P(PSTR(","));
+ }
+ if (sensor > 74) {
+ res = 0;
+ } else if (sensor > 72) {
+ res = Settings->flag2.humidity_resolution;
+ } else if (sensor == 72) {
+ res = Settings->mbflag2.temperature_set_res;
+ } else {
+ res = Settings->flag2.temperature_resolution;
+ }
+
+ GetTextIndexed(sname, sizeof(sname), (sensor-71), kTuyaSensors);
+ ResponseAppend_P(PSTR("\"%s\":%s"), sname,
+ (pTuya->SensorsValid[sensor-71] ? dtostrfd(TuyaAdjustedTemperature(pTuya->Sensors[sensor-71], res), res, tempval) : PSTR("null")));
+ added = true;
+ }
+ #ifdef USE_WEBSERVER
+ } else {
+ if (TuyaGetDpId(sensor) != 0) {
+ switch (sensor) {
+ case 71:
+ WSContentSend_Temp("", TuyaAdjustedTemperature(pTuya->Sensors[0], Settings->flag2.temperature_resolution));
+ break;
+ case 72:
+ WSContentSend_PD(PSTR("{s}" D_TEMPERATURE " Set{m}%s " D_UNIT_DEGREE "%c{e}"),
+ dtostrfd(TuyaAdjustedTemperature(pTuya->Sensors[1], Settings->mbflag2.temperature_set_res), Settings->mbflag2.temperature_set_res, tempval), TempUnit());
+ break;
+ case 73:
+ WSContentSend_PD(HTTP_SNS_HUM, "", dtostrfd(TuyaAdjustedTemperature(pTuya->Sensors[2], Settings->flag2.humidity_resolution), Settings->flag2.humidity_resolution, tempval));
+ break;
+ case 74:
+ WSContentSend_PD(PSTR("{s}" D_HUMIDITY " Set{m}%s " D_UNIT_PERCENT "{e}"),
+ dtostrfd(TuyaAdjustedTemperature(pTuya->Sensors[3], Settings->flag2.humidity_resolution), Settings->flag2.humidity_resolution, tempval));
+ break;
+ case 75:
+ WSContentSend_PD(HTTP_SNS_ILLUMINANCE, "", pTuya->Sensors[4]);
+ break;
+ case 76:
+ WSContentSend_PD(PSTR("{s}" D_TVOC "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"), pTuya->Sensors[5]);
+ break;
+ case 77:
+ WSContentSend_PD(HTTP_SNS_CO2, "", pTuya->Sensors[6]);
+ break;
+ case 78:
+ WSContentSend_PD(HTTP_SNS_CO2EAVG, "", pTuya->Sensors[7]);
+ break;
+ case 79:
+ WSContentSend_PD(HTTP_SNS_GAS, "", pTuya->Sensors[8]);
+ break;
+ case 80:
+ WSContentSend_PD(PSTR("{s}" D_ENVIRONMENTAL_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"), pTuya->Sensors[9]);
+ break;
+ case 81:
+ case 82:
+ case 83:
+ case 84:
+ WSContentSend_PD(PSTR("{s}Timer%d{m}%d{e}"), (sensor-80), pTuya->Sensors[sensor-71]); // No UoM for timers since they can be sec or min
+ break;
+ }
+ }
+
+ #endif // USE_WEBSERVER
+ }
+ }
+#ifdef USE_WEBSERVER
+ if (AsModuleTuyaMS()) {
+ WSContentSend_P(PSTR("{s}" D_JSON_IRHVAC_MODE "{m}%d{e}"), pTuya->ModeSet);
+ }
+#endif // USE_WEBSERVER
+
+ if (RootName) { ResponseJsonEnd();}
+}
+
+#ifdef USE_WEBSERVER
+
+void TuyaAddButton(void) {
+ if (AsModuleTuyaMS()) {
+ WSContentSend_P(HTTP_TABLE100);
+ WSContentSend_P(PSTR(""));
+ char stemp[33];
+ snprintf_P(stemp, sizeof(stemp), PSTR("" D_JSON_IRHVAC_MODE ""));
+ WSContentSend_P(HTTP_DEVICE_CONTROL, 26, TasmotaGlobal.devices_present + 1,
+ (strlen(SettingsText(SET_BUTTON1 + TasmotaGlobal.devices_present))) ? SettingsText(SET_BUTTON1 + TasmotaGlobal.devices_present) : stemp, "");
+ WSContentSend_P(PSTR("
"));
+ }
+}
+
+#endif // USE_WEBSERVER
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+#ifdef USE_ENERGY_SENSOR
+
+bool Xnrg32(uint32_t function)
+{
+ bool result = false;
+
+ if (pTuya && pTuya->active) {
+ if (FUNC_PRE_INIT == function) {
+ 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 && TuyaGetDpId(TUYA_MCU_FUNC_POWER_COMBINED) == 0) {
+ Energy.voltage_available = false;
+ }
+ TasmotaGlobal.energy_driver = XNRG_32;
+ }
+ }
+ }
+ return result;
+}
+#endif // USE_ENERGY_SENSOR
+
+bool Xdrv16(uint32_t function) {
+ bool result = false;
+
+ if (FUNC_MODULE_INIT == function) {
+ result = TuyaModuleSelected();
+ if (pTuya) pTuya->active = result;
+ }
+ else if (pTuya && pTuya->active) {
+ switch (function) {
+ case FUNC_LOOP:
+ case FUNC_SLEEP_LOOP:
+ if (TuyaSerial) { TuyaSerialInput(); }
+ break;
+ case FUNC_PRE_INIT:
+ TuyaInit();
+ break;
+ case FUNC_SET_DEVICE_POWER:
+ result = TuyaSetPower();
+#ifdef TUYA_MORE_DEBUG
+ MqttPublishLoggingAsync(false);
+ SyslogAsync(false);
+#endif
+ break;
+ case FUNC_BUTTON_PRESSED:
+ result = TuyaButtonPressed();
+#ifdef TUYA_MORE_DEBUG
+ MqttPublishLoggingAsync(false);
+ SyslogAsync(false);
+#endif
+ break;
+ case FUNC_EVERY_100_MSECOND:
+ if (pTuya->timeout){
+ pTuya->timeout -= 100;
+ if (pTuya->timeout <= 0){
+ Tuya_timeout();
+ }
+ }
+ for (int i = 0; i < 2; i++){
+ if (pTuya->dimDelay_ms[i]){
+ pTuya->dimDelay_ms[i] -= 100;
+ if (pTuya->dimDelay_ms[i] <= 0){
+ pTuya->dimDelay_ms[i] = 0;
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TYA: DimDelay%d->0"), i);
+ }
+ }
+ }
+ Tuya_statemachine();
+ break;
+ case FUNC_EVERY_SECOND:
+ if (pTuya->wifiTimer > 0){
+ pTuya->wifiTimer -= 1000;
+ if (pTuya->wifiTimer <= 0){
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: Wifi reset aborted."));
+ pTuya->wifiTimer = 0;
+ }
+ }
+ // now done in state machine
+ //if (TuyaSerial && pTuya->wifi_state != TuyaGetTuyaWifiState()) { TuyaSetWifiLed(); }
+ if (!pTuya->low_power_mode) {
+ pTuya->heartbeat_timer++;
+ if (pTuya->heartbeat_timer > 10) {
+ pTuya->heartbeat_timer = 0;
+ pTuya->send_heartbeat = 1;
+ }
+#ifdef USE_TUYA_TIME
+ if (!(TasmotaGlobal.uptime % 60)) {
+ // if we have never been asked for time, send it ourselves
+ // as this was the original TAS implementation.
+ // if we DO get asked for time, then send_time & 2 will be set, so we no longer send from here.
+ if (!pTuya->send_time & 2){
+ pTuya->send_time |= 1;
+ }
+ }
+#endif //USE_TUYA_TIME
+ } else {
+ // done in state machine
+ //TuyaSendLowPowerSuccessIfNeeded();
+ }
+ if (pTuya->ignore_topic_timeout < millis()) { pTuya->SuspendTopic = false; }
+ if (pTuya->lasterrorcnt != pTuya->errorcnt){
+ AddLog(LOG_LEVEL_ERROR, PSTR("TYA: Errorcnt %d->%d"), pTuya->lasterrorcnt, pTuya->errorcnt);
+ pTuya->lasterrorcnt = pTuya->errorcnt;
+ }
+ break;
+ case FUNC_SET_CHANNELS:
+ result = TuyaSetChannels();
+#ifdef TUYA_MORE_DEBUG
+ MqttPublishLoggingAsync(false);
+ SyslogAsync(false);
+#endif
+ break;
+ case FUNC_MQTT_INIT:
+ // why here? done as part of startup state machine
+ //TuyaSendCmd(TUYA_CMD_QUERY_PRODUCT);
+ break;
+ case FUNC_COMMAND:
+ result = DecodeCommand(kTuyaCommand, TuyaCommand);
+ break;
+ case FUNC_JSON_APPEND:
+ TuyaSensorsShow(1);
+ break;
+#ifdef USE_WEBSERVER
+ case FUNC_WEB_ADD_MAIN_BUTTON:
+ TuyaAddButton();
+ break;
+ case FUNC_WEB_SENSOR:
+ TuyaSensorsShow(0);
+ break;
+#endif // USE_WEBSERVER
+ }
+ }
+ return result;
+}
+
+#endif // USE_TUYA_MCU
+#endif // USE_LIGHT
\ No newline at end of file
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_17_rcswitch.ino b/tasmota/tasmota_xdrv_driver/xdrv_17_rcswitch.ino
index acf033c85..05c28fa07 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_17_rcswitch.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_17_rcswitch.ino
@@ -180,7 +180,7 @@ void CmndRfSend(void)
for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < 5; str = strtok_r(nullptr, ", ", &p)) {
switch (i++) {
case 0:
- data = strtoul(str, nullptr, 0); // Allow decimal (5246996) and hexadecimal (0x501014) input
+ data = strtoull(str, nullptr, 0); // Allow decimal (5246996) and hexadecimal (0x501014) input
break;
case 1:
bits = atoi(str);
@@ -229,7 +229,7 @@ void CmndRfTimeOut(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv17(uint8_t function)
+bool Xdrv17(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_18_armtronix_dimmers.ino b/tasmota/tasmota_xdrv_driver/xdrv_18_armtronix_dimmers.ino
index 185cb98c0..674ee9b3c 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_18_armtronix_dimmers.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_18_armtronix_dimmers.ino
@@ -164,7 +164,7 @@ void ArmtronixSetWifiLed(void)
* Interface
\*********************************************************************************************/
-bool Xdrv18(uint8_t function)
+bool Xdrv18(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_19_ps16dz_dimmer.ino b/tasmota/tasmota_xdrv_driver/xdrv_19_ps16dz_dimmer.ino
index 9c2d0a23e..d23058b39 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_19_ps16dz_dimmer.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_19_ps16dz_dimmer.ino
@@ -206,7 +206,7 @@ bool PS16DZModuleSelected(void)
* Interface
\*********************************************************************************************/
-bool Xdrv19(uint8_t function)
+bool Xdrv19(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_20_hue.ino b/tasmota/tasmota_xdrv_driver/xdrv_20_hue.ino
index 734b0c0dd..74611fa78 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_20_hue.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_20_hue.ino
@@ -1149,7 +1149,7 @@ void HandleHueApi(String *path)
* Interface
\*********************************************************************************************/
-bool Xdrv20(uint8_t function)
+bool Xdrv20(uint32_t function)
{
bool result = false;
@@ -1162,6 +1162,12 @@ bool Xdrv20(uint8_t function)
case FUNC_WEB_ADD_HANDLER:
WebServer_on(PSTR("/description.xml"), HandleUpnpSetupHue);
break;
+ case FUNC_NETWORK_UP:
+ UdpConnect();
+ break;
+ case FUNC_NETWORK_DOWN:
+ UdpDisconnect();
+ break;
}
}
return result;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_21_wemo.ino b/tasmota/tasmota_xdrv_driver/xdrv_21_wemo.ino
index f0521aeea4..f3fa8ab92 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_21_wemo.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_21_wemo.ino
@@ -130,9 +130,9 @@ const char WEMO_RESPONSE_STATE_SOAP[] PROGMEM = "\x3D\x3C\x79\x93\xE3\x36\x16\x0
"\xD0\xEC\x05\x4C\xFC\xFC\x3D\x0E\xC0\x43\xD8\xCE\xC0\x45\xE1\xA0\xFC\x9C\x29\x1B"
"\x8D";
-//urn:Belkin:device:controllee:1{x1Belkin International Inc.Socket3.1415uuid:{x2{x30urn:Belkin:service:basicevent:1urn:Belkin:serviceId:basicevent1/upnp/control/basicevent1/upnp/event/basicevent1/eventservice.xmlurn:Belkin:service:metainfo:1urn:Belkin:serviceId:metainfo1/upnp/control/metainfo1/upnp/event/metainfo1/metainfoservice.xml\r\n
-//Successfully compressed from 923 to 392 bytes (-57.5%)
-const size_t WEMO_SETUP_XML_SIZE = 923;
+//urn:Belkin:device:controllee:1{x1Belkin International Inc.Socket3.1415uuid:{x2{x3http://{x4:80/0urn:Belkin:service:basicevent:1urn:Belkin:serviceId:basicevent1/upnp/control/basicevent1/upnp/event/basicevent1/eventservice.xmlurn:Belkin:service:metainfo:1urn:Belkin:serviceId:metainfo1/upnp/control/metainfo1/upnp/event/metainfo1/metainfoservice.xml\r\n
+//Successfully compressed from 972 to 426 bytes (-56.2%)
+const size_t WEMO_SETUP_XML_SIZE = 972;
const char WEMO_SETUP_XML[] PROGMEM = "\x3D\x0E\xD1\xB0\x68\x48\xCD\xFF\xDB\x9C\x7C\x3D\x87\x21\xD1\x9E\xC3\xB4\x7E\x1E"
"\x85\xFC\xCA\x46\xC1\xA1\x77\x8F\x87\xB0\x5F\xF8\xF3\x21\xCC\x23\x4D\xE3\xCC\x46"
"\x67\xA1\xB3\xAC\xE4\x3A\xD9\xEC\x3F\x0F\x42\x04\x19\x20\x87\x10\xA8\xC8\x63\x3F"
@@ -143,16 +143,18 @@ const char WEMO_SETUP_XML[] PROGMEM = "\x3D\x0E\xD1\xB0\x68\x48\xCD\xFF\xDB\x9C\
"\x47\xA1\xD8\x08\xB3\x81\x0A\xC8\xB1\xA3\x9F\xCF\xC3\x96\x74\x99\x34\x81\x0E\xD8"
"\x20\xD0\x3D\x08\x59\x08\x5C\x7E\x0B\x17\xA2\x1E\x67\xB4\xD8\x72\x8F\x43\xB0\x88"
"\x59\x08\x5C\x7E\x1E\x9E\x7F\xDB\x04\x3B\xA7\xB4\xD8\x72\xCF\x43\xB0\x81\x22\x71"
- "\xE8\x3B\x7A\xFE\x64\x5E\xAB\xA6\x7E\x1C\x67\xA1\xD8\x40\x8F\x2C\xF4\xF3\xF9\x9E"
- "\x86\xC8\x2D\xF5\x02\x24\x90\x44\x8A\x09\x7C\x46\x82\x15\x33\xCC\x75\xFB\x43\x66"
- "\x6F\xA8\xF3\x39\x0F\x43\xB0\x81\x1F\x09\x04\x3C\x58\xB4\x40\x4E\xC5\x0B\x44\x04"
- "\x6C\x58\x11\x71\x52\xD1\x0F\xC3\xD0\x10\xB8\xE0\x21\x65\xF2\x08\xFC\x3B\x05\x8C"
- "\xE1\x87\x60\x21\x4D\x3B\x01\x23\x0D\x04\x6C\x08\xF4\x66\x6F\xA8\xBC\x2C\x70\x22"
- "\xE1\xEC\xCD\xF5\x02\x4E\x1A\x08\xF8\x09\xE8\x45\xE0\xC6\x08\x2F\xE1\x11\xF8\x08"
- "\x34\x81\x0B\x59\x3A\x1B\x06\x84\x7A\x1D\x80\x87\x5C\x11\x37\x2A\x01\x60\xBC\x34"
- "\x0D\x75\x7B\xC6\x30\x18\x5F\x0C\xC0\x87\x8A\x03\x02\xE1\x90\x11\xB0\xB0\x5F\xE1"
- "\x88\x11\xB0\xB0\x51\xE1\x80\x10\xEE\x82\xDF\x0C\x60\x87\x18\x10\x79\x7D\x04\x2E"
- "\x83\xD1\xF8\x7A\x1D\x9F\xCC\xA3\xF2\x70\xA4\x6E";
+ "\xE8\x33\xEF\xCF\xAA\xEB\x73\x88\x59\x7C\x82\x3F\x05\x55\x0C\x3C\xCE\xC3\xB0\xF6"
+ "\x9B\x0E\x61\xE7\xF6\x76\x1E\x87\x61\x02\x5D\xC3\xD0\x76\xF5\xFC\xC8\xBD\x57\x4C"
+ "\xFC\x38\xCF\x43\xB0\x81\x1E\x59\xE9\xE7\xF3\x3D\x0D\x90\x5B\xEA\x04\x49\x20\x89"
+ "\x14\x12\xF8\xBE\x04\x2A\x2B\x67\x98\xEB\xF6\x86\xCC\xDF\x51\xE6\x72\x1E\x87\x61"
+ "\x02\x3E\x12\x08\x78\xB1\x68\x80\x9D\x8A\x16\x88\x08\xD8\xB0\x22\xE2\xA5\xA2\x1F"
+ "\x87\xA0\x21\x72\x22\x42\xCB\xE4\x11\xF8\x76\x0B\x19\xC3\x0E\xC0\x42\x9A\x76\x02"
+ "\x46\x1A\x08\xD8\x11\xE8\xCC\xDF\x51\x78\x58\xE0\x45\xC3\xD9\x9B\xEA\x04\x9C\x34"
+ "\x11\xF0\x13\xD0\x8B\xC1\x8C\x10\x5F\xC2\x23\xF0\x10\x69\x02\x16\xB2\x74\x36\x0D"
+ "\x08\xF4\x3B\x01\x0E\xB8\x22\x6E\x2A\x01\xC1\x78\x68\x1A\xEA\xF7\x8C\x60\x30\xBE"
+ "\x19\x81\x0F\x14\x06\x05\xC3\x20\x23\x61\x60\xBF\xC3\x10\x23\x61\x60\xA3\xC3\x2A"
+ "\x01\x21\xDD\x05\xBE\x18\xC1\x0E\x30\x20\xF2\xFA\x08\x5D\x0A\xB3\xF0\xF4\x3B\x3F"
+ "\x99\x47\xE4\xE1\x48\xDC";
#else
const char WEMO_EVENTSERVICE_XML[] PROGMEM =
""
@@ -240,6 +242,7 @@ const char WEMO_SETUP_XML[] PROGMEM =
"3.1415"
"uuid:{x2"
"{x3"
+ "http://{x4:80/"
"0"
""
""
@@ -335,6 +338,9 @@ void HandleUpnpSetupWemo(void)
setup_xml.replace("{x1", SettingsText(SET_FRIENDLYNAME1));
setup_xml.replace("{x2", WemoUuid());
setup_xml.replace("{x3", WemoSerialnumber());
+
+ setup_xml.replace("{x4", WiFi.localIP().toString());
+
WSSend(200, CT_XML, setup_xml);
}
@@ -342,7 +348,7 @@ void HandleUpnpSetupWemo(void)
* Interface
\*********************************************************************************************/
-bool Xdrv21(uint8_t function)
+bool Xdrv21(uint32_t function)
{
bool result = false;
@@ -354,6 +360,12 @@ bool Xdrv21(uint8_t function)
WebServer_on(PSTR("/metainfoservice.xml"), HandleUpnpMetaService);
WebServer_on(PSTR("/setup.xml"), HandleUpnpSetupWemo);
break;
+ case FUNC_NETWORK_UP:
+ UdpConnect();
+ break;
+ case FUNC_NETWORK_DOWN:
+ UdpDisconnect();
+ break;
}
}
return result;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_21_wemo_multi.ino b/tasmota/tasmota_xdrv_driver/xdrv_21_wemo_multi.ino
index 145e3e8c5..c6b5f9410 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_21_wemo_multi.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_21_wemo_multi.ino
@@ -93,29 +93,31 @@ const char WEMO_RESPONSE_STATE_SOAP[] PROGMEM = "\x3D\x3C\x79\x93\xE3\x36\x16\x0
"\xD0\xEC\x05\x4C\xFC\xFC\x3D\x0E\xC0\x43\xD8\xCE\xC0\x45\xE1\xA0\xFC\x9C\x29\x1B"
"\x8D";
-//urn:Belkin:device:controllee:1{x1Belkin International Inc.Socket3.1415uuid:{x2{x30urn:Belkin:service:basicevent:1urn:Belkin:serviceId:basicevent1/upnp/control/basicevent1/upnp/event/basicevent1/eventservice.xmlurn:Belkin:service:metainfo:1urn:Belkin:serviceId:metainfo1/upnp/control/metainfo1/upnp/event/metainfo1/metainfoservice.xml\r\n
-//Successfully compressed from 923 to 392 bytes (-57.5%)
-const size_t WEMO_SETUP_XML_SIZE = 923;
+//urn:Belkin:device:controllee:1{x1Belkin International Inc.Socket3.1415uuid:{x2{x3http://{x4:80/0urn:Belkin:service:basicevent:1urn:Belkin:serviceId:basicevent1/upnp/control/basicevent1/upnp/event/basicevent1/eventservice.xmlurn:Belkin:service:metainfo:1urn:Belkin:serviceId:metainfo1/upnp/control/metainfo1/upnp/event/metainfo1/metainfoservice.xml\r\n
+//Successfully compressed from 972 to 426 bytes (-56.2%)
+const size_t WEMO_SETUP_XML_SIZE = 972;
const char WEMO_SETUP_XML[] PROGMEM = "\x3D\x0E\xD1\xB0\x68\x48\xCD\xFF\xDB\x9C\x7C\x3D\x87\x21\xD1\x9E\xC3\xB4\x7E\x1E"
- "\x85\xFC\xCA\x46\xC1\xA1\x77\x8F\x87\xB0\x5F\xF8\xF3\x21\xCC\x23\x4D\xE3\xCC\x46"
- "\x67\xA1\xB3\xAC\xE4\x3A\xD9\xEC\x3F\x0F\x42\x04\x19\x20\x87\x10\xA8\xC8\x63\x3F"
- "\x01\x33\x07\x3C\xC3\xCE\xAF\xE0\x41\x36\x79\x9C\x87\xA1\xD8\x40\x8D\x83\x9E\x86"
- "\x3F\xAF\x84\x08\xC8\xBA\xC6\xB3\xF0\xF6\x9B\x0E\x43\xD0\xEC\x20\x48\x9C\x7A\x0D"
- "\xBE\x16\x62\xC3\xA1\x7F\x7F\x3F\x01\x07\x31\x45\xBD\x4F\xFD\x75\xB9\xD6\x12\x2D"
- "\xE0\xCE\x87\xA1\xD8\x09\x18\x21\xE8\x37\x04\x61\x17\x58\xD6\x7E\x17\xB0\x33\x47"
- "\x47\xA1\xD8\x08\xB3\x81\x0A\xC8\xB1\xA3\x9F\xCF\xC3\x96\x74\x99\x34\x81\x0E\xD8"
- "\x20\xD0\x3D\x08\x59\x08\x5C\x7E\x0B\x17\xA2\x1E\x67\xB4\xD8\x72\x8F\x43\xB0\x88"
- "\x59\x08\x5C\x7E\x1E\x9E\x7F\xDB\x04\x3B\xA7\xB4\xD8\x72\xCF\x43\xB0\x81\x22\x71"
- "\xE8\x3B\x7A\xFE\x64\x5E\xAB\xA6\x7E\x1C\x67\xA1\xD8\x40\x8F\x2C\xF4\xF3\xF9\x9E"
- "\x86\xC8\x2D\xF5\x02\x24\x90\x44\x8A\x09\x7C\x46\x82\x15\x33\xCC\x75\xFB\x43\x66"
- "\x6F\xA8\xF3\x39\x0F\x43\xB0\x81\x1F\x09\x04\x3C\x58\xB4\x40\x4E\xC5\x0B\x44\x04"
- "\x6C\x58\x11\x71\x52\xD1\x0F\xC3\xD0\x10\xB8\xE0\x21\x65\xF2\x08\xFC\x3B\x05\x8C"
- "\xE1\x87\x60\x21\x4D\x3B\x01\x23\x0D\x04\x6C\x08\xF4\x66\x6F\xA8\xBC\x2C\x70\x22"
- "\xE1\xEC\xCD\xF5\x02\x4E\x1A\x08\xF8\x09\xE8\x45\xE0\xC6\x08\x2F\xE1\x11\xF8\x08"
- "\x34\x81\x0B\x59\x3A\x1B\x06\x84\x7A\x1D\x80\x87\x5C\x11\x37\x2A\x01\x60\xBC\x34"
- "\x0D\x75\x7B\xC6\x30\x18\x5F\x0C\xC0\x87\x8A\x03\x02\xE1\x90\x11\xB0\xB0\x5F\xE1"
- "\x88\x11\xB0\xB0\x51\xE1\x80\x10\xEE\x82\xDF\x0C\x60\x87\x18\x10\x79\x7D\x04\x2E"
- "\x83\xD1\xF8\x7A\x1D\x9F\xCC\xA3\xF2\x70\xA4\x6E";
+ "\x85\xFC\xCA\x46\xC1\xA1\x77\x8F\x87\xB0\x5F\xF8\xF3\x21\xCC\x23\x4D\xE3\xCC\x46"
+ "\x67\xA1\xB3\xAC\xE4\x3A\xD9\xEC\x3F\x0F\x42\x04\x19\x20\x87\x10\xA8\xC8\x63\x3F"
+ "\x01\x33\x07\x3C\xC3\xCE\xAF\xE0\x41\x36\x79\x9C\x87\xA1\xD8\x40\x8D\x83\x9E\x86"
+ "\x3F\xAF\x84\x08\xC8\xBA\xC6\xB3\xF0\xF6\x9B\x0E\x43\xD0\xEC\x20\x48\x9C\x7A\x0D"
+ "\xBE\x16\x62\xC3\xA1\x7F\x7F\x3F\x01\x07\x31\x45\xBD\x4F\xFD\x75\xB9\xD6\x12\x2D"
+ "\xE0\xCE\x87\xA1\xD8\x09\x18\x21\xE8\x37\x04\x61\x17\x58\xD6\x7E\x17\xB0\x33\x47"
+ "\x47\xA1\xD8\x08\xB3\x81\x0A\xC8\xB1\xA3\x9F\xCF\xC3\x96\x74\x99\x34\x81\x0E\xD8"
+ "\x20\xD0\x3D\x08\x59\x08\x5C\x7E\x0B\x17\xA2\x1E\x67\xB4\xD8\x72\x8F\x43\xB0\x88"
+ "\x59\x08\x5C\x7E\x1E\x9E\x7F\xDB\x04\x3B\xA7\xB4\xD8\x72\xCF\x43\xB0\x81\x22\x71"
+ "\xE8\x33\xEF\xCF\xAA\xEB\x73\x88\x59\x7C\x82\x3F\x05\x55\x0C\x3C\xCE\xC3\xB0\xF6"
+ "\x9B\x0E\x61\xE7\xF6\x76\x1E\x87\x61\x02\x5D\xC3\xD0\x76\xF5\xFC\xC8\xBD\x57\x4C"
+ "\xFC\x38\xCF\x43\xB0\x81\x1E\x59\xE9\xE7\xF3\x3D\x0D\x90\x5B\xEA\x04\x49\x20\x89"
+ "\x14\x12\xF8\xBE\x04\x2A\x2B\x67\x98\xEB\xF6\x86\xCC\xDF\x51\xE6\x72\x1E\x87\x61"
+ "\x02\x3E\x12\x08\x78\xB1\x68\x80\x9D\x8A\x16\x88\x08\xD8\xB0\x22\xE2\xA5\xA2\x1F"
+ "\x87\xA0\x21\x72\x22\x42\xCB\xE4\x11\xF8\x76\x0B\x19\xC3\x0E\xC0\x42\x9A\x76\x02"
+ "\x46\x1A\x08\xD8\x11\xE8\xCC\xDF\x51\x78\x58\xE0\x45\xC3\xD9\x9B\xEA\x04\x9C\x34"
+ "\x11\xF0\x13\xD0\x8B\xC1\x8C\x10\x5F\xC2\x23\xF0\x10\x69\x02\x16\xB2\x74\x36\x0D"
+ "\x08\xF4\x3B\x01\x0E\xB8\x22\x6E\x2A\x01\xC1\x78\x68\x1A\xEA\xF7\x8C\x60\x30\xBE"
+ "\x19\x81\x0F\x14\x06\x05\xC3\x20\x23\x61\x60\xBF\xC3\x10\x23\x61\x60\xA3\xC3\x2A"
+ "\x01\x21\xDD\x05\xBE\x18\xC1\x0E\x30\x20\xF2\xFA\x08\x5D\x0A\xB3\xF0\xF4\x3B\x3F"
+ "\x99\x47\xE4\xE1\x48\xDC";
#else
const char WEMO_EVENTSERVICE_XML[] PROGMEM =
""
@@ -203,6 +205,7 @@ const char WEMO_SETUP_XML[] PROGMEM =
"3.1415"
"uuid:{x2"
"{x3"
+ "http://{x4:80/"
"0"
""
""
@@ -396,6 +399,9 @@ private:
setup_xml.replace("{x1", SettingsText(SET_FRIENDLYNAME1 + (_deviceId - 1)));
setup_xml.replace("{x2", WemoUuid());
setup_xml.replace("{x3", WemoSerialnumber());
+
+ setup_xml.replace("{x4", WiFi.localIP().toString());
+
InternalWSSend(200, CT_XML, setup_xml);
#ifdef USE_EMULATION_WEMO_DEBUG
AddLog(LOG_LEVEL_DEBUG, PSTR("WMO: Sending device #%d: %s"), _deviceId, setup_xml.c_str());
@@ -427,7 +433,7 @@ void WemoRespondToMSearch(int echo_type) {
* Interface
\*********************************************************************************************/
-bool Xdrv21(uint8_t function)
+bool Xdrv21(uint32_t function)
{
bool result = false;
@@ -453,6 +459,12 @@ bool Xdrv21(uint8_t function)
numOfWemoSwitch++;
}
break;
+ case FUNC_NETWORK_UP:
+ UdpConnect();
+ break;
+ case FUNC_NETWORK_DOWN:
+ UdpDisconnect();
+ break;
}
}
return result;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_22_sonoff_ifan.ino b/tasmota/tasmota_xdrv_driver/xdrv_22_sonoff_ifan.ino
index 992e0a31f..6cf5da0c5 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_22_sonoff_ifan.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_22_sonoff_ifan.ino
@@ -174,7 +174,7 @@ bool SonoffIfanSerialInput(void)
// AA 55 01 04 00 01 04 0A - Light
// AA 55 01 06 00 01 01 09 - Buzzer
// AA 55 01 07 00 01 01 0A - Rf long press - forget RF codes
- AddLogSerial(LOG_LEVEL_DEBUG);
+ AddLogSerial();
uint8_t crc = 0;
for (uint32_t i = 2; i < 7; i++) {
crc += TasmotaGlobal.serial_in_buffer[i];
@@ -244,8 +244,7 @@ void SonoffIfanUpdate(void)
* Interface
\*********************************************************************************************/
-bool Xdrv22(uint8_t function)
-{
+bool Xdrv22(uint32_t function) {
bool result = false;
if (IsModuleIfan()) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_0_constants.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_0_constants.ino
index 9320867e2..38e1e7bac 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_0_constants.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_0_constants.ino
@@ -287,15 +287,28 @@ const char Z_strings[] PROGMEM =
"ConfigStatus" "\x00"
"Contact" "\x00"
"ControlSequenceOfOperation" "\x00"
+ "ControlTemperature" "\x00"
"Coordinate1" "\x00"
"Coordinate2" "\x00"
"Coordinate3" "\x00"
+ "CurrentBlock" "\x00"
+ "CurrentBlockPeriodConsumptionDelivered" "\x00"
"CurrentGroup" "\x00"
+ "CurrentInletEnergyCarrierDemand" "\x00"
+ "CurrentInletEnergyCarrierSummation" "\x00"
+ "CurrentMaxDemandDelivered" "\x00"
+ "CurrentMaxDemandDeliveredTime" "\x00"
+ "CurrentMaxDemandReceived" "\x00"
+ "CurrentMaxDemandReceivedTime" "\x00"
+ "CurrentOutletEnergyCarrierDemand" "\x00"
+ "CurrentOutletEnergyCarrierSummation" "\x00"
"CurrentPositionLift" "\x00"
"CurrentPositionLiftPercentage" "\x00"
"CurrentPositionTilt" "\x00"
"CurrentPositionTiltPercentage" "\x00"
"CurrentScene" "\x00"
+ "CurrentSummationDelivered" "\x00"
+ "CurrentSummationReceived" "\x00"
"CurrentTemperature" "\x00"
"CurrentTemperatureSetPoint" "\x00"
"CurrentZoneSensitivityLevel" "\x00"
@@ -318,10 +331,14 @@ const char Z_strings[] PROGMEM =
"DCVoltageMin" "\x00"
"DCVoltageMultiplier" "\x00"
"DCVoltageOverload" "\x00"
+ "DFTSummation" "\x00"
+ "DailyConsumptionTarget" "\x00"
+ "DailyFreezeTime" "\x00"
"DataQualityID" "\x00"
"DateCode" "\x00"
"DecelerationTimeLift" "\x00"
"DefaultMoveRate" "\x00"
+ "DefaultUpdatePeriod" "\x00"
"DehumidificationCooling" "\x00"
"DehumidificationHysteresis" "\x00"
"DehumidificationLockout" "\x00"
@@ -355,7 +372,6 @@ const char Z_strings[] PROGMEM =
"ElectricalMeasurementType" "\x00"
"EnergyFormatting" "\x00"
"EnergyRemote" "\x00"
- "EnergyTotal" "\x00"
"EnhancedColorMode" "\x00"
"EnhancedCurrentHue" "\x00"
"EurotronicErrors" "\x00"
@@ -364,10 +380,12 @@ const char Z_strings[] PROGMEM =
"FanModeSequence" "\x00"
"FastPollTimeout" "\x00"
"FastPollTimeoutMax" "\x00"
+ "FastPollUpdatePeriod" "\x00"
"Fire" "\x00"
"FlowMaxMeasuredValue" "\x00"
"FlowMinMeasuredValue" "\x00"
"FlowRate" "\x00"
+ "FlowRestriction" "\x00"
"FlowTolerance" "\x00"
"GPHueStop" "\x00"
"GPIdentify" "\x00"
@@ -455,12 +473,14 @@ const char Z_strings[] PROGMEM =
"IlluminanceMinMeasuredValue" "\x00"
"IlluminanceTargetLevel" "\x00"
"IlluminanceTolerance" "\x00"
+ "InletTemperature" "\x00"
"InstalledClosedLimitLift" "\x00"
"InstalledClosedLimitTilt" "\x00"
"InstalledOpenLimitLift" "\x00"
"InstalledOpenLimitTilt" "\x00"
"IntermediateSetpointsLift" "\x00"
"IntermediateSetpointsTilt" "\x00"
+ "IntervalReadReportingPeriod" "\x00"
"IntrinsicBallastFactor" "\x00"
"LampAlarmMode" "\x00"
"LampBurnHours" "\x00"
@@ -610,6 +630,7 @@ const char Z_strings[] PROGMEM =
"OpenPeriod" "\x00"
"OppleMode" "\x00"
"OutdoorTemperature" "\x00"
+ "OutletTemperature" "\x00"
"OverTempTotalDwell" "\x00"
"PICoolingDemand" "\x00"
"PIHeatingDemand" "\x00"
@@ -638,6 +659,7 @@ const char Z_strings[] PROGMEM =
"PowerOnTimer" "\x00"
"PowerSource" "\x00"
"PowerThreshold" "\x00"
+ "PresetReadingTime" "\x00"
"Pressure" "\x00"
"PressureMaxMeasuredValue" "\x00"
"PressureMaxScaledValue" "\x00"
@@ -647,6 +669,7 @@ const char Z_strings[] PROGMEM =
"PressureScaledTolerance" "\x00"
"PressureScaledValue" "\x00"
"PressureTolerance" "\x00"
+ "PreviousBlockPeriodConsumptionDelivered" "\x00"
"Primary1Intensity" "\x00"
"Primary1X" "\x00"
"Primary1Y" "\x00"
@@ -668,6 +691,7 @@ const char Z_strings[] PROGMEM =
"ProductCode" "\x00"
"ProductRevision" "\x00"
"ProductURL" "\x00"
+ "ProfileIntervalPeriod" "\x00"
"ProxyTable" "\x00"
"QualityMeasure" "\x00"
"RGB" "\x00"
@@ -712,6 +736,7 @@ const char Z_strings[] PROGMEM =
"ReactivePower" "\x00"
"ReactivePowerPhB" "\x00"
"ReactivePowerPhC" "\x00"
+ "ReadingSnapShotTime" "\x00"
"RecallScene" "\x00"
"RelativeHumidity" "\x00"
"RelativeHumidityDisplay" "\x00"
@@ -753,6 +778,7 @@ const char Z_strings[] PROGMEM =
"StartUpOnOff" "\x00"
"Status" "\x00"
"StoreScene" "\x00"
+ "SupplyStatus" "\x00"
"SwitchActions" "\x00"
"SwitchType" "\x00"
"SystemMode" "\x00"
@@ -797,6 +823,7 @@ const char Z_strings[] PROGMEM =
"VelocityLift" "\x00"
"ViewGroup" "\x00"
"ViewScene" "\x00"
+ "VolumePerReport" "\x00"
"Water" "\x00"
"WhitePointX" "\x00"
"WhitePointY" "\x00"
@@ -1047,551 +1074,578 @@ enum Z_offsets {
Zo_ConfigStatus = 3878,
Zo_Contact = 3891,
Zo_ControlSequenceOfOperation = 3899,
- Zo_Coordinate1 = 3926,
- Zo_Coordinate2 = 3938,
- Zo_Coordinate3 = 3950,
- Zo_CurrentGroup = 3962,
- Zo_CurrentPositionLift = 3975,
- Zo_CurrentPositionLiftPercentage = 3995,
- Zo_CurrentPositionTilt = 4025,
- Zo_CurrentPositionTiltPercentage = 4045,
- Zo_CurrentScene = 4075,
- Zo_CurrentTemperature = 4088,
- Zo_CurrentTemperatureSetPoint = 4107,
- Zo_CurrentZoneSensitivityLevel = 4134,
- Zo_CustomerName = 4162,
- Zo_DCCurrent = 4175,
- Zo_DCCurrentDivisor = 4185,
- Zo_DCCurrentMax = 4202,
- Zo_DCCurrentMin = 4215,
- Zo_DCCurrentMultiplier = 4228,
- Zo_DCCurrentOverload = 4248,
- Zo_DCOverloadAlarmsMask = 4266,
- Zo_DCPower = 4287,
- Zo_DCPowerDivisor = 4295,
- Zo_DCPowerMax = 4310,
- Zo_DCPowerMin = 4321,
- Zo_DCPowerMultiplier = 4332,
- Zo_DCVoltage = 4350,
- Zo_DCVoltageDivisor = 4360,
- Zo_DCVoltageMax = 4377,
- Zo_DCVoltageMin = 4390,
- Zo_DCVoltageMultiplier = 4403,
- Zo_DCVoltageOverload = 4423,
- Zo_DataQualityID = 4441,
- Zo_DateCode = 4455,
- Zo_DecelerationTimeLift = 4464,
- Zo_DefaultMoveRate = 4485,
- Zo_DehumidificationCooling = 4501,
- Zo_DehumidificationHysteresis = 4525,
- Zo_DehumidificationLockout = 4552,
- Zo_DehumidificationMaxCool = 4576,
- Zo_DeviceEnabled = 4600,
- Zo_DeviceTempAlarmMask = 4614,
- Zo_Dimmer = 4634,
- Zo_DimmerCurrentFrequency = 4641,
- Zo_DimmerDown = 4664,
- Zo_DimmerMaxFrequency = 4675,
- Zo_DimmerMaxLevel = 4694,
- Zo_DimmerMinFrequency = 4709,
- Zo_DimmerMinLevel = 4728,
- Zo_DimmerMove = 4743,
- Zo_DimmerOptions = 4754,
- Zo_DimmerRemainingTime = 4768,
- Zo_DimmerStartUpLevel = 4788,
- Zo_DimmerStep = 4807,
- Zo_DimmerStepDown = 4818,
- Zo_DimmerStepUp = 4833,
- Zo_DimmerStop = 4846,
- Zo_DimmerUp = 4857,
- Zo_DisableLocalConfig = 4866,
- Zo_DoorClosedEvents = 4885,
- Zo_DoorOpenEvents = 4902,
- Zo_DoorState = 4917,
- Zo_DriftCompensation = 4927,
- Zo_DstEnd = 4945,
- Zo_DstShift = 4952,
- Zo_DstStart = 4961,
- Zo_ElectricalMeasurementType = 4970,
- Zo_EnergyFormatting = 4996,
- Zo_EnergyRemote = 5013,
- Zo_EnergyTotal = 5026,
- Zo_EnhancedColorMode = 5038,
- Zo_EnhancedCurrentHue = 5056,
- Zo_EurotronicErrors = 5075,
- Zo_EurotronicHostFlags = 5092,
- Zo_FanMode = 5112,
- Zo_FanModeSequence = 5120,
- Zo_FastPollTimeout = 5136,
- Zo_FastPollTimeoutMax = 5152,
- Zo_Fire = 5171,
- Zo_FlowMaxMeasuredValue = 5176,
- Zo_FlowMinMeasuredValue = 5197,
- Zo_FlowRate = 5218,
- Zo_FlowTolerance = 5227,
- Zo_GPHueStop = 5241,
- Zo_GPIdentify = 5251,
- Zo_GPLevelStop = 5262,
- Zo_GPLockDoor = 5274,
- Zo_GPMoveColor = 5285,
- Zo_GPMoveDown = 5297,
- Zo_GPMoveDownOnOff = 5308,
- Zo_GPMoveHueDown = 5324,
- Zo_GPMoveHueUp = 5338,
- Zo_GPMoveSatDown = 5350,
- Zo_GPMoveSatUp = 5364,
- Zo_GPMoveUp = 5376,
- Zo_GPMoveUpOnOff = 5385,
- Zo_GPOff = 5399,
- Zo_GPOn = 5405,
- Zo_GPPress1of1 = 5410,
- Zo_GPPress1of2 = 5422,
- Zo_GPPress2of2 = 5434,
- Zo_GPRelease = 5446,
- Zo_GPRelease1of1 = 5456,
- Zo_GPRelease1of2 = 5470,
- Zo_GPRelease2of2 = 5484,
- Zo_GPSatStop = 5498,
- Zo_GPScene0 = 5508,
- Zo_GPScene1 = 5517,
- Zo_GPScene10 = 5526,
- Zo_GPScene11 = 5536,
- Zo_GPScene12 = 5546,
- Zo_GPScene13 = 5556,
- Zo_GPScene14 = 5566,
- Zo_GPScene15 = 5576,
- Zo_GPScene2 = 5586,
- Zo_GPScene3 = 5595,
- Zo_GPScene4 = 5604,
- Zo_GPScene5 = 5613,
- Zo_GPScene6 = 5622,
- Zo_GPScene7 = 5631,
- Zo_GPScene8 = 5640,
- Zo_GPScene9 = 5649,
- Zo_GPShortPress1of1 = 5658,
- Zo_GPShortPress1of2 = 5675,
- Zo_GPShortPress2of2 = 5692,
- Zo_GPStepColor = 5709,
- Zo_GPStepDown = 5721,
- Zo_GPStepDownOnOff = 5732,
- Zo_GPStepHueDown = 5748,
- Zo_GPStepHueUp = 5762,
- Zo_GPStepSatDown = 5774,
- Zo_GPStepSatUp = 5788,
- Zo_GPStepUp = 5800,
- Zo_GPStepUpOnOff = 5809,
- Zo_GPToggle = 5823,
- Zo_GPUnlockDoor = 5832,
- Zo_GenericDeviceClass = 5845,
- Zo_GenericDeviceType = 5864,
- Zo_GetAllGroups = 5882,
- Zo_GetGroup = 5895,
- Zo_GetSceneMembership = 5904,
- Zo_GlassBreak = 5923,
- Zo_GroupNameSupport = 5934,
- Zo_HVACSystemTypeConfiguration = 5951,
- Zo_HWVersion = 5979,
- Zo_HarmonicCurrentMultiplier = 5989,
- Zo_HighTempDwellTripPoint = 6015,
- Zo_HighTempThreshold = 6038,
- Zo_Hue = 6056,
- Zo_HueMove = 6060,
- Zo_HueSat = 6068,
- Zo_HueStep = 6075,
- Zo_HueStepDown = 6083,
- Zo_HueStepUp = 6095,
- Zo_Humidity = 6105,
- Zo_HumidityMaxMeasuredValue = 6114,
- Zo_HumidityMinMeasuredValue = 6139,
- Zo_HumidityTolerance = 6164,
- Zo_IASCIEAddress = 6182,
- Zo_Identify = 6196,
- Zo_IdentifyQuery = 6205,
- Zo_IdentifyTime = 6219,
- Zo_Illuminance = 6232,
- Zo_IlluminanceLevelStatus = 6244,
- Zo_IlluminanceLightSensorType = 6267,
- Zo_IlluminanceMaxMeasuredValue = 6294,
- Zo_IlluminanceMinMeasuredValue = 6322,
- Zo_IlluminanceTargetLevel = 6350,
- Zo_IlluminanceTolerance = 6373,
- Zo_InstalledClosedLimitLift = 6394,
- Zo_InstalledClosedLimitTilt = 6419,
- Zo_InstalledOpenLimitLift = 6444,
- Zo_InstalledOpenLimitTilt = 6467,
- Zo_IntermediateSetpointsLift = 6490,
- Zo_IntermediateSetpointsTilt = 6516,
- Zo_IntrinsicBallastFactor = 6542,
- Zo_LampAlarmMode = 6565,
- Zo_LampBurnHours = 6579,
- Zo_LampBurnHoursTripPoint = 6593,
- Zo_LampManufacturer = 6616,
- Zo_LampRatedHours = 6633,
- Zo_LampType = 6648,
- Zo_LastConfiguredBy = 6657,
- Zo_LastMessageLQI = 6674,
- Zo_LastMessageRSSI = 6689,
- Zo_LastSetTime = 6705,
- Zo_LegrandHeatingMode = 6717,
- Zo_LegrandMode = 6736,
- Zo_LegrandOpt1 = 6748,
- Zo_LegrandOpt2 = 6760,
- Zo_LegrandOpt3 = 6772,
- Zo_LidlPower = 6784,
- Zo_LineCurrent = 6794,
- Zo_LineCurrentPhB = 6806,
- Zo_LineCurrentPhC = 6821,
- Zo_LinkKey = 6836,
- Zo_LocalTemperature = 6844,
- Zo_LocalTemperatureCalibration = 6861,
- Zo_LocalTime = 6889,
- Zo_LocationAge = 6899,
- Zo_LocationDescription = 6911,
- Zo_LocationMethod = 6931,
- Zo_LocationPower = 6946,
- Zo_LocationType = 6960,
- Zo_LockAlarmMask = 6973,
- Zo_LockDefaultConfigurationRegister = 6987,
- Zo_LockEnableInsideStatusLED = 7020,
- Zo_LockEnableLocalProgramming = 7046,
- Zo_LockEnableLogging = 7073,
- Zo_LockEnableOneTouchLocking = 7091,
- Zo_LockEnablePrivacyModeButton = 7117,
- Zo_LockKeypadOperationEventMask = 7145,
- Zo_LockKeypadProgrammingEventMask = 7174,
- Zo_LockLEDSettings = 7205,
- Zo_LockLanguage = 7221,
- Zo_LockManualOperationEventMask = 7234,
- Zo_LockOperatingMode = 7263,
- Zo_LockRFIDOperationEventMask = 7281,
- Zo_LockRFIDProgrammingEventMask = 7308,
- Zo_LockRFOperationEventMask = 7337,
- Zo_LockRFProgrammingEventMask = 7362,
- Zo_LockSoundVolume = 7389,
- Zo_LockState = 7405,
- Zo_LockSupportedOperatingModes = 7415,
- Zo_LockType = 7443,
- Zo_LongPollInterval = 7452,
- Zo_LongPollIntervalMin = 7469,
- Zo_LowTempDwellTripPoint = 7489,
- Zo_LowTempThreshold = 7511,
- Zo_MainsAlarmMask = 7528,
- Zo_MainsFrequency = 7543,
- Zo_MainsVoltage = 7558,
- Zo_MainsVoltageDwellTripPoint = 7571,
- Zo_MainsVoltageMaxThreshold = 7598,
- Zo_MainsVoltageMinThreshold = 7623,
- Zo_Manufacturer = 7648,
- Zo_MaxCoolSetpointLimit = 7661,
- Zo_MaxHeatSetpointLimit = 7682,
- Zo_MaxPINCodeLength = 7703,
- Zo_MaxProxyTableEntries = 7720,
- Zo_MaxRFIDCodeLength = 7741,
- Zo_MaxSearchCounter = 7759,
- Zo_MaxSinkTableEntries = 7776,
- Zo_MaxTempExperienced = 7796,
- Zo_Measured11thHarmonicCurrent = 7815,
- Zo_Measured1stHarmonicCurrent = 7843,
- Zo_Measured3rdHarmonicCurrent = 7870,
- Zo_Measured5thHarmonicCurrent = 7897,
- Zo_Measured7thHarmonicCurrent = 7924,
- Zo_Measured9thHarmonicCurrent = 7951,
- Zo_MeasuredPhase11thHarmonicCurrent = 7978,
- Zo_MeasuredPhase1stHarmonicCurrent = 8011,
- Zo_MeasuredPhase3rdHarmonicCurrent = 8043,
- Zo_MeasuredPhase5thHarmonicCurrent = 8075,
- Zo_MeasuredPhase7thHarmonicCurrent = 8107,
- Zo_MeasuredPhase9thHarmonicCurrent = 8139,
- Zo_MeterTypeID = 8171,
- Zo_MinCoolSetpointLimit = 8183,
- Zo_MinHeatSetpointLimit = 8204,
- Zo_MinPINCodeLength = 8225,
- Zo_MinRFIDCodeLength = 8242,
- Zo_MinSetpointDeadBand = 8260,
- Zo_MinTempExperienced = 8280,
- Zo_Mode = 8299,
- Zo_Model = 8304,
- Zo_ModelId = 8310,
- Zo_MotorStepSize = 8318,
- Zo_Movement = 8332,
- Zo_MullerLightMode = 8341,
- Zo_MultiApplicationType = 8357,
- Zo_MultiDescription = 8378,
- Zo_MultiInApplicationType = 8395,
- Zo_MultiInDescription = 8418,
- Zo_MultiInNumberOfStates = 8437,
- Zo_MultiInOutOfService = 8459,
- Zo_MultiInReliability = 8479,
- Zo_MultiInStatusFlags = 8498,
- Zo_MultiInValue = 8517,
- Zo_MultiNumberOfStates = 8530,
- Zo_MultiOutApplicationType = 8550,
- Zo_MultiOutDescription = 8574,
- Zo_MultiOutNumberOfStates = 8594,
- Zo_MultiOutOfService = 8617,
- Zo_MultiOutOutOfService = 8635,
- Zo_MultiOutReliability = 8656,
- Zo_MultiOutRelinquishDefault = 8676,
- Zo_MultiOutStatusFlags = 8702,
- Zo_MultiOutValue = 8722,
- Zo_MultiReliability = 8736,
- Zo_MultiRelinquishDefault = 8753,
- Zo_MultiStatusFlags = 8776,
- Zo_MultiValue = 8793,
- Zo_MultipleScheduling = 8804,
- Zo_NeutralCurrent = 8823,
- Zo_NotificationRetryNumber = 8838,
- Zo_NotificationRetryTimer = 8862,
- Zo_NumberOfDevices = 8885,
- Zo_NumberOfHolidaySchedulesSupported = 8901,
- Zo_NumberOfLogRecordsSupported = 8935,
- Zo_NumberOfPINUsersSupported = 8963,
- Zo_NumberOfPrimaries = 8989,
- Zo_NumberOfRFIDUsersSupported = 9007,
- Zo_NumberOfResets = 9034,
- Zo_NumberOfTotalUsersSupported = 9049,
- Zo_NumberOfWeekDaySchedulesSupportedPerUser = 9077,
- Zo_NumberOfYearDaySchedulesSupportedPerUser = 9118,
- Zo_NumberOfZoneSensitivityLevelsSupported = 9159,
- Zo_NumberRSSIMeasurements = 9198,
- Zo_NumberofActuationsLift = 9221,
- Zo_NumberofActuationsTilt = 9244,
- Zo_Occupancy = 9267,
- Zo_OccupancySensorType = 9277,
- Zo_OccupiedCoolingSetpoint = 9297,
- Zo_OccupiedHeatingSetpoint = 9321,
- Zo_OffTransitionTime = 9345,
- Zo_OffWaitTime = 9363,
- Zo_OnLevel = 9375,
- Zo_OnOff = 9383,
- Zo_OnOffTransitionTime = 9389,
- Zo_OnTime = 9409,
- Zo_OnTransitionTime = 9416,
- Zo_OpenPeriod = 9433,
- Zo_OppleMode = 9444,
- Zo_OutdoorTemperature = 9454,
- Zo_OverTempTotalDwell = 9473,
- Zo_PICoolingDemand = 9492,
- Zo_PIHeatingDemand = 9508,
- Zo_PIROccupiedToUnoccupiedDelay = 9524,
- Zo_PIRUnoccupiedToOccupiedDelay = 9553,
- Zo_PIRUnoccupiedToOccupiedThreshold = 9582,
- Zo_POD = 9615,
- Zo_Panic = 9619,
- Zo_PartNumber = 9625,
- Zo_PathLossExponent = 9636,
- Zo_PersistentMemoryWrites = 9653,
- Zo_PersonalAlarm = 9676,
- Zo_PhaseHarmonicCurrentMultiplier = 9690,
- Zo_PhysicalClosedLimit = 9721,
- Zo_PhysicalClosedLimitLift = 9741,
- Zo_PhysicalClosedLimitTilt = 9765,
- Zo_PhysicalEnvironment = 9789,
- Zo_Power = 9809,
- Zo_PowerDivisor = 9815,
- Zo_PowerFactor = 9828,
- Zo_PowerFactorPhB = 9840,
- Zo_PowerFactorPhC = 9855,
- Zo_PowerMultiplier = 9870,
- Zo_PowerOffEffect = 9886,
- Zo_PowerOnRecall = 9901,
- Zo_PowerOnTimer = 9915,
- Zo_PowerSource = 9928,
- Zo_PowerThreshold = 9940,
- Zo_Pressure = 9955,
- Zo_PressureMaxMeasuredValue = 9964,
- Zo_PressureMaxScaledValue = 9989,
- Zo_PressureMinMeasuredValue = 10012,
- Zo_PressureMinScaledValue = 10037,
- Zo_PressureScale = 10060,
- Zo_PressureScaledTolerance = 10074,
- Zo_PressureScaledValue = 10098,
- Zo_PressureTolerance = 10118,
- Zo_Primary1Intensity = 10136,
- Zo_Primary1X = 10154,
- Zo_Primary1Y = 10164,
- Zo_Primary2Intensity = 10174,
- Zo_Primary2X = 10192,
- Zo_Primary2Y = 10202,
- Zo_Primary3Intensity = 10212,
- Zo_Primary3X = 10230,
- Zo_Primary3Y = 10240,
- Zo_Primary4Intensity = 10250,
- Zo_Primary4X = 10268,
- Zo_Primary4Y = 10278,
- Zo_Primary5Intensity = 10288,
- Zo_Primary5X = 10306,
- Zo_Primary5Y = 10316,
- Zo_Primary6Intensity = 10326,
- Zo_Primary6X = 10344,
- Zo_Primary6Y = 10354,
- Zo_ProductCode = 10364,
- Zo_ProductRevision = 10376,
- Zo_ProductURL = 10392,
- Zo_ProxyTable = 10403,
- Zo_QualityMeasure = 10414,
- Zo_RGB = 10429,
- Zo_RHDehumidificationSetpoint = 10433,
- Zo_RMSCurrent = 10460,
- Zo_RMSCurrentMax = 10471,
- Zo_RMSCurrentMaxPhB = 10485,
- Zo_RMSCurrentMaxPhC = 10502,
- Zo_RMSCurrentMin = 10519,
- Zo_RMSCurrentMinPhB = 10533,
- Zo_RMSCurrentMinPhC = 10550,
- Zo_RMSCurrentPhB = 10567,
- Zo_RMSCurrentPhC = 10581,
- Zo_RMSExtremeOverVoltage = 10595,
- Zo_RMSExtremeOverVoltagePeriod = 10617,
- Zo_RMSExtremeOverVoltagePeriodPhB = 10645,
- Zo_RMSExtremeOverVoltagePeriodPhC = 10676,
- Zo_RMSExtremeUnderVoltage = 10707,
- Zo_RMSExtremeUnderVoltagePeriod = 10730,
- Zo_RMSExtremeUnderVoltagePeriodPhB = 10759,
- Zo_RMSExtremeUnderVoltagePeriodPhC = 10791,
- Zo_RMSVoltage = 10823,
- Zo_RMSVoltageMax = 10834,
- Zo_RMSVoltageMaxPhB = 10848,
- Zo_RMSVoltageMaxPhC = 10865,
- Zo_RMSVoltageMin = 10882,
- Zo_RMSVoltageMinPhB = 10896,
- Zo_RMSVoltageMinPhC = 10913,
- Zo_RMSVoltagePhB = 10930,
- Zo_RMSVoltagePhC = 10944,
- Zo_RMSVoltageSag = 10958,
- Zo_RMSVoltageSagPeriod = 10972,
- Zo_RMSVoltageSagPeriodPhB = 10992,
- Zo_RMSVoltageSagPeriodPhC = 11015,
- Zo_RMSVoltageSwell = 11038,
- Zo_RMSVoltageSwellPeriod = 11054,
- Zo_RMSVoltageSwellPeriodPhB = 11076,
- Zo_RMSVoltageSwellPeriodPhC = 11101,
- Zo_ReactiveCurrent = 11126,
- Zo_ReactiveCurrentPhB = 11142,
- Zo_ReactiveCurrentPhC = 11161,
- Zo_ReactivePower = 11180,
- Zo_ReactivePowerPhB = 11194,
- Zo_ReactivePowerPhC = 11211,
- Zo_RecallScene = 11228,
- Zo_RelativeHumidity = 11240,
- Zo_RelativeHumidityDisplay = 11257,
- Zo_RelativeHumidityMode = 11281,
- Zo_RemainingTime = 11302,
- Zo_RemoteSensing = 11316,
- Zo_RemoveAllGroups = 11330,
- Zo_RemoveAllScenes = 11346,
- Zo_RemoveGroup = 11362,
- Zo_RemoveScene = 11374,
- Zo_ReportingPeriod = 11386,
- Zo_ResetAlarm = 11402,
- Zo_ResetAllAlarms = 11413,
- Zo_SWBuildID = 11428,
- Zo_Sat = 11438,
- Zo_SatMove = 11442,
- Zo_SatStep = 11450,
- Zo_SceneCount = 11458,
- Zo_SceneNameSupport = 11469,
- Zo_SceneValid = 11486,
- Zo_ScheduleMode = 11497,
- Zo_SeaPressure = 11510,
- Zo_SecurityLevel = 11522,
- Zo_ServerActiveFunctionality = 11536,
- Zo_ServerFunctionality = 11562,
- Zo_SharedSecurityKey = 11582,
- Zo_SharedSecurityKeyType = 11600,
- Zo_ShortPollInterval = 11622,
- Zo_Shutter = 11640,
- Zo_ShutterClose = 11648,
- Zo_ShutterLift = 11661,
- Zo_ShutterOpen = 11673,
- Zo_ShutterStop = 11685,
- Zo_ShutterTilt = 11697,
- Zo_SinkTable = 11709,
- Zo_SoftwareRevision = 11719,
- Zo_StackVersion = 11736,
- Zo_StandardTime = 11749,
- Zo_StartUpOnOff = 11762,
- Zo_Status = 11775,
- Zo_StoreScene = 11782,
- Zo_SwitchActions = 11793,
- Zo_SwitchType = 11807,
- Zo_SystemMode = 11818,
- Zo_TRVBoost = 11829,
- Zo_TRVChildProtection = 11838,
- Zo_TRVMirrorDisplay = 11857,
- Zo_TRVMode = 11874,
- Zo_TRVWindowOpen = 11882,
- Zo_TempTarget = 11896,
- Zo_Temperature = 11907,
- Zo_TemperatureDisplayMode = 11919,
- Zo_TemperatureMaxMeasuredValue = 11942,
- Zo_TemperatureMinMeasuredValue = 11970,
- Zo_TemperatureTolerance = 11998,
- Zo_TerncyDuration = 12019,
- Zo_TerncyRotate = 12034,
- Zo_ThSetpoint = 12047,
- Zo_ThermostatAlarmMask = 12058,
- Zo_ThermostatKeypadLockout = 12078,
- Zo_ThermostatOccupancy = 12102,
- Zo_ThermostatRunningMode = 12122,
- Zo_ThermostatScheduleProgrammingVisibility = 12144,
- Zo_Time = 12184,
- Zo_TimeEpoch = 12189,
- Zo_TimeStatus = 12199,
- Zo_TimeZone = 12210,
- Zo_TotalActivePower = 12219,
- Zo_TotalApparentPower = 12236,
- Zo_TotalProfileNum = 12255,
- Zo_TotalReactivePower = 12271,
- Zo_TuyaCalibration = 12290,
- Zo_TuyaCalibrationTime = 12306,
- Zo_TuyaMCUVersion = 12326,
- Zo_TuyaMotorReversal = 12341,
- Zo_TuyaMovingState = 12359,
- Zo_TuyaQuery = 12375,
- Zo_UnoccupiedCoolingSetpoint = 12385,
- Zo_UnoccupiedHeatingSetpoint = 12411,
- Zo_UtilityName = 12437,
- Zo_ValidUntilTime = 12449,
- Zo_ValvePosition = 12464,
- Zo_VelocityLift = 12478,
- Zo_ViewGroup = 12491,
- Zo_ViewScene = 12501,
- Zo_Water = 12511,
- Zo_WhitePointX = 12517,
- Zo_WhitePointY = 12529,
- Zo_WindowCoveringType = 12541,
- Zo_X = 12560,
- Zo_Y = 12562,
- Zo_ZCLVersion = 12564,
- Zo_ZoneID = 12575,
- Zo_ZoneState = 12582,
- Zo_ZoneStatus = 12592,
- Zo_ZoneStatusChange = 12603,
- Zo_ZoneType = 12620,
- Zo__ = 12629,
- Zo_xx = 12631,
- Zo_xx000A00 = 12634,
- Zo_xx0A = 12643,
- Zo_xx0A00 = 12648,
- Zo_xx19 = 12655,
- Zo_xx190A = 12660,
- Zo_xx190A00 = 12667,
- Zo_xxxx = 12676,
- Zo_xxxx00 = 12681,
- Zo_xxxx0A00 = 12688,
- Zo_xxxxyy = 12697,
- Zo_xxxxyyyy = 12704,
- Zo_xxxxyyyy0A00 = 12713,
- Zo_xxxxyyzz = 12726,
- Zo_xxyy = 12735,
- Zo_xxyy0A00 = 12740,
- Zo_xxyyyy = 12749,
- Zo_xxyyyy000000000000 = 12756,
- Zo_xxyyyy0A0000000000 = 12775,
- Zo_xxyyyyzz = 12794,
- Zo_xxyyyyzzzz = 12803,
- Zo_xxyyzzzz = 12814,
+ Zo_ControlTemperature = 3926,
+ Zo_Coordinate1 = 3945,
+ Zo_Coordinate2 = 3957,
+ Zo_Coordinate3 = 3969,
+ Zo_CurrentBlock = 3981,
+ Zo_CurrentBlockPeriodConsumptionDelivered = 3994,
+ Zo_CurrentGroup = 4033,
+ Zo_CurrentInletEnergyCarrierDemand = 4046,
+ Zo_CurrentInletEnergyCarrierSummation = 4078,
+ Zo_CurrentMaxDemandDelivered = 4113,
+ Zo_CurrentMaxDemandDeliveredTime = 4139,
+ Zo_CurrentMaxDemandReceived = 4169,
+ Zo_CurrentMaxDemandReceivedTime = 4194,
+ Zo_CurrentOutletEnergyCarrierDemand = 4223,
+ Zo_CurrentOutletEnergyCarrierSummation = 4256,
+ Zo_CurrentPositionLift = 4292,
+ Zo_CurrentPositionLiftPercentage = 4312,
+ Zo_CurrentPositionTilt = 4342,
+ Zo_CurrentPositionTiltPercentage = 4362,
+ Zo_CurrentScene = 4392,
+ Zo_CurrentSummationDelivered = 4405,
+ Zo_CurrentSummationReceived = 4431,
+ Zo_CurrentTemperature = 4456,
+ Zo_CurrentTemperatureSetPoint = 4475,
+ Zo_CurrentZoneSensitivityLevel = 4502,
+ Zo_CustomerName = 4530,
+ Zo_DCCurrent = 4543,
+ Zo_DCCurrentDivisor = 4553,
+ Zo_DCCurrentMax = 4570,
+ Zo_DCCurrentMin = 4583,
+ Zo_DCCurrentMultiplier = 4596,
+ Zo_DCCurrentOverload = 4616,
+ Zo_DCOverloadAlarmsMask = 4634,
+ Zo_DCPower = 4655,
+ Zo_DCPowerDivisor = 4663,
+ Zo_DCPowerMax = 4678,
+ Zo_DCPowerMin = 4689,
+ Zo_DCPowerMultiplier = 4700,
+ Zo_DCVoltage = 4718,
+ Zo_DCVoltageDivisor = 4728,
+ Zo_DCVoltageMax = 4745,
+ Zo_DCVoltageMin = 4758,
+ Zo_DCVoltageMultiplier = 4771,
+ Zo_DCVoltageOverload = 4791,
+ Zo_DFTSummation = 4809,
+ Zo_DailyConsumptionTarget = 4822,
+ Zo_DailyFreezeTime = 4845,
+ Zo_DataQualityID = 4861,
+ Zo_DateCode = 4875,
+ Zo_DecelerationTimeLift = 4884,
+ Zo_DefaultMoveRate = 4905,
+ Zo_DefaultUpdatePeriod = 4921,
+ Zo_DehumidificationCooling = 4941,
+ Zo_DehumidificationHysteresis = 4965,
+ Zo_DehumidificationLockout = 4992,
+ Zo_DehumidificationMaxCool = 5016,
+ Zo_DeviceEnabled = 5040,
+ Zo_DeviceTempAlarmMask = 5054,
+ Zo_Dimmer = 5074,
+ Zo_DimmerCurrentFrequency = 5081,
+ Zo_DimmerDown = 5104,
+ Zo_DimmerMaxFrequency = 5115,
+ Zo_DimmerMaxLevel = 5134,
+ Zo_DimmerMinFrequency = 5149,
+ Zo_DimmerMinLevel = 5168,
+ Zo_DimmerMove = 5183,
+ Zo_DimmerOptions = 5194,
+ Zo_DimmerRemainingTime = 5208,
+ Zo_DimmerStartUpLevel = 5228,
+ Zo_DimmerStep = 5247,
+ Zo_DimmerStepDown = 5258,
+ Zo_DimmerStepUp = 5273,
+ Zo_DimmerStop = 5286,
+ Zo_DimmerUp = 5297,
+ Zo_DisableLocalConfig = 5306,
+ Zo_DoorClosedEvents = 5325,
+ Zo_DoorOpenEvents = 5342,
+ Zo_DoorState = 5357,
+ Zo_DriftCompensation = 5367,
+ Zo_DstEnd = 5385,
+ Zo_DstShift = 5392,
+ Zo_DstStart = 5401,
+ Zo_ElectricalMeasurementType = 5410,
+ Zo_EnergyFormatting = 5436,
+ Zo_EnergyRemote = 5453,
+ Zo_EnhancedColorMode = 5466,
+ Zo_EnhancedCurrentHue = 5484,
+ Zo_EurotronicErrors = 5503,
+ Zo_EurotronicHostFlags = 5520,
+ Zo_FanMode = 5540,
+ Zo_FanModeSequence = 5548,
+ Zo_FastPollTimeout = 5564,
+ Zo_FastPollTimeoutMax = 5580,
+ Zo_FastPollUpdatePeriod = 5599,
+ Zo_Fire = 5620,
+ Zo_FlowMaxMeasuredValue = 5625,
+ Zo_FlowMinMeasuredValue = 5646,
+ Zo_FlowRate = 5667,
+ Zo_FlowRestriction = 5676,
+ Zo_FlowTolerance = 5692,
+ Zo_GPHueStop = 5706,
+ Zo_GPIdentify = 5716,
+ Zo_GPLevelStop = 5727,
+ Zo_GPLockDoor = 5739,
+ Zo_GPMoveColor = 5750,
+ Zo_GPMoveDown = 5762,
+ Zo_GPMoveDownOnOff = 5773,
+ Zo_GPMoveHueDown = 5789,
+ Zo_GPMoveHueUp = 5803,
+ Zo_GPMoveSatDown = 5815,
+ Zo_GPMoveSatUp = 5829,
+ Zo_GPMoveUp = 5841,
+ Zo_GPMoveUpOnOff = 5850,
+ Zo_GPOff = 5864,
+ Zo_GPOn = 5870,
+ Zo_GPPress1of1 = 5875,
+ Zo_GPPress1of2 = 5887,
+ Zo_GPPress2of2 = 5899,
+ Zo_GPRelease = 5911,
+ Zo_GPRelease1of1 = 5921,
+ Zo_GPRelease1of2 = 5935,
+ Zo_GPRelease2of2 = 5949,
+ Zo_GPSatStop = 5963,
+ Zo_GPScene0 = 5973,
+ Zo_GPScene1 = 5982,
+ Zo_GPScene10 = 5991,
+ Zo_GPScene11 = 6001,
+ Zo_GPScene12 = 6011,
+ Zo_GPScene13 = 6021,
+ Zo_GPScene14 = 6031,
+ Zo_GPScene15 = 6041,
+ Zo_GPScene2 = 6051,
+ Zo_GPScene3 = 6060,
+ Zo_GPScene4 = 6069,
+ Zo_GPScene5 = 6078,
+ Zo_GPScene6 = 6087,
+ Zo_GPScene7 = 6096,
+ Zo_GPScene8 = 6105,
+ Zo_GPScene9 = 6114,
+ Zo_GPShortPress1of1 = 6123,
+ Zo_GPShortPress1of2 = 6140,
+ Zo_GPShortPress2of2 = 6157,
+ Zo_GPStepColor = 6174,
+ Zo_GPStepDown = 6186,
+ Zo_GPStepDownOnOff = 6197,
+ Zo_GPStepHueDown = 6213,
+ Zo_GPStepHueUp = 6227,
+ Zo_GPStepSatDown = 6239,
+ Zo_GPStepSatUp = 6253,
+ Zo_GPStepUp = 6265,
+ Zo_GPStepUpOnOff = 6274,
+ Zo_GPToggle = 6288,
+ Zo_GPUnlockDoor = 6297,
+ Zo_GenericDeviceClass = 6310,
+ Zo_GenericDeviceType = 6329,
+ Zo_GetAllGroups = 6347,
+ Zo_GetGroup = 6360,
+ Zo_GetSceneMembership = 6369,
+ Zo_GlassBreak = 6388,
+ Zo_GroupNameSupport = 6399,
+ Zo_HVACSystemTypeConfiguration = 6416,
+ Zo_HWVersion = 6444,
+ Zo_HarmonicCurrentMultiplier = 6454,
+ Zo_HighTempDwellTripPoint = 6480,
+ Zo_HighTempThreshold = 6503,
+ Zo_Hue = 6521,
+ Zo_HueMove = 6525,
+ Zo_HueSat = 6533,
+ Zo_HueStep = 6540,
+ Zo_HueStepDown = 6548,
+ Zo_HueStepUp = 6560,
+ Zo_Humidity = 6570,
+ Zo_HumidityMaxMeasuredValue = 6579,
+ Zo_HumidityMinMeasuredValue = 6604,
+ Zo_HumidityTolerance = 6629,
+ Zo_IASCIEAddress = 6647,
+ Zo_Identify = 6661,
+ Zo_IdentifyQuery = 6670,
+ Zo_IdentifyTime = 6684,
+ Zo_Illuminance = 6697,
+ Zo_IlluminanceLevelStatus = 6709,
+ Zo_IlluminanceLightSensorType = 6732,
+ Zo_IlluminanceMaxMeasuredValue = 6759,
+ Zo_IlluminanceMinMeasuredValue = 6787,
+ Zo_IlluminanceTargetLevel = 6815,
+ Zo_IlluminanceTolerance = 6838,
+ Zo_InletTemperature = 6859,
+ Zo_InstalledClosedLimitLift = 6876,
+ Zo_InstalledClosedLimitTilt = 6901,
+ Zo_InstalledOpenLimitLift = 6926,
+ Zo_InstalledOpenLimitTilt = 6949,
+ Zo_IntermediateSetpointsLift = 6972,
+ Zo_IntermediateSetpointsTilt = 6998,
+ Zo_IntervalReadReportingPeriod = 7024,
+ Zo_IntrinsicBallastFactor = 7052,
+ Zo_LampAlarmMode = 7075,
+ Zo_LampBurnHours = 7089,
+ Zo_LampBurnHoursTripPoint = 7103,
+ Zo_LampManufacturer = 7126,
+ Zo_LampRatedHours = 7143,
+ Zo_LampType = 7158,
+ Zo_LastConfiguredBy = 7167,
+ Zo_LastMessageLQI = 7184,
+ Zo_LastMessageRSSI = 7199,
+ Zo_LastSetTime = 7215,
+ Zo_LegrandHeatingMode = 7227,
+ Zo_LegrandMode = 7246,
+ Zo_LegrandOpt1 = 7258,
+ Zo_LegrandOpt2 = 7270,
+ Zo_LegrandOpt3 = 7282,
+ Zo_LidlPower = 7294,
+ Zo_LineCurrent = 7304,
+ Zo_LineCurrentPhB = 7316,
+ Zo_LineCurrentPhC = 7331,
+ Zo_LinkKey = 7346,
+ Zo_LocalTemperature = 7354,
+ Zo_LocalTemperatureCalibration = 7371,
+ Zo_LocalTime = 7399,
+ Zo_LocationAge = 7409,
+ Zo_LocationDescription = 7421,
+ Zo_LocationMethod = 7441,
+ Zo_LocationPower = 7456,
+ Zo_LocationType = 7470,
+ Zo_LockAlarmMask = 7483,
+ Zo_LockDefaultConfigurationRegister = 7497,
+ Zo_LockEnableInsideStatusLED = 7530,
+ Zo_LockEnableLocalProgramming = 7556,
+ Zo_LockEnableLogging = 7583,
+ Zo_LockEnableOneTouchLocking = 7601,
+ Zo_LockEnablePrivacyModeButton = 7627,
+ Zo_LockKeypadOperationEventMask = 7655,
+ Zo_LockKeypadProgrammingEventMask = 7684,
+ Zo_LockLEDSettings = 7715,
+ Zo_LockLanguage = 7731,
+ Zo_LockManualOperationEventMask = 7744,
+ Zo_LockOperatingMode = 7773,
+ Zo_LockRFIDOperationEventMask = 7791,
+ Zo_LockRFIDProgrammingEventMask = 7818,
+ Zo_LockRFOperationEventMask = 7847,
+ Zo_LockRFProgrammingEventMask = 7872,
+ Zo_LockSoundVolume = 7899,
+ Zo_LockState = 7915,
+ Zo_LockSupportedOperatingModes = 7925,
+ Zo_LockType = 7953,
+ Zo_LongPollInterval = 7962,
+ Zo_LongPollIntervalMin = 7979,
+ Zo_LowTempDwellTripPoint = 7999,
+ Zo_LowTempThreshold = 8021,
+ Zo_MainsAlarmMask = 8038,
+ Zo_MainsFrequency = 8053,
+ Zo_MainsVoltage = 8068,
+ Zo_MainsVoltageDwellTripPoint = 8081,
+ Zo_MainsVoltageMaxThreshold = 8108,
+ Zo_MainsVoltageMinThreshold = 8133,
+ Zo_Manufacturer = 8158,
+ Zo_MaxCoolSetpointLimit = 8171,
+ Zo_MaxHeatSetpointLimit = 8192,
+ Zo_MaxPINCodeLength = 8213,
+ Zo_MaxProxyTableEntries = 8230,
+ Zo_MaxRFIDCodeLength = 8251,
+ Zo_MaxSearchCounter = 8269,
+ Zo_MaxSinkTableEntries = 8286,
+ Zo_MaxTempExperienced = 8306,
+ Zo_Measured11thHarmonicCurrent = 8325,
+ Zo_Measured1stHarmonicCurrent = 8353,
+ Zo_Measured3rdHarmonicCurrent = 8380,
+ Zo_Measured5thHarmonicCurrent = 8407,
+ Zo_Measured7thHarmonicCurrent = 8434,
+ Zo_Measured9thHarmonicCurrent = 8461,
+ Zo_MeasuredPhase11thHarmonicCurrent = 8488,
+ Zo_MeasuredPhase1stHarmonicCurrent = 8521,
+ Zo_MeasuredPhase3rdHarmonicCurrent = 8553,
+ Zo_MeasuredPhase5thHarmonicCurrent = 8585,
+ Zo_MeasuredPhase7thHarmonicCurrent = 8617,
+ Zo_MeasuredPhase9thHarmonicCurrent = 8649,
+ Zo_MeterTypeID = 8681,
+ Zo_MinCoolSetpointLimit = 8693,
+ Zo_MinHeatSetpointLimit = 8714,
+ Zo_MinPINCodeLength = 8735,
+ Zo_MinRFIDCodeLength = 8752,
+ Zo_MinSetpointDeadBand = 8770,
+ Zo_MinTempExperienced = 8790,
+ Zo_Mode = 8809,
+ Zo_Model = 8814,
+ Zo_ModelId = 8820,
+ Zo_MotorStepSize = 8828,
+ Zo_Movement = 8842,
+ Zo_MullerLightMode = 8851,
+ Zo_MultiApplicationType = 8867,
+ Zo_MultiDescription = 8888,
+ Zo_MultiInApplicationType = 8905,
+ Zo_MultiInDescription = 8928,
+ Zo_MultiInNumberOfStates = 8947,
+ Zo_MultiInOutOfService = 8969,
+ Zo_MultiInReliability = 8989,
+ Zo_MultiInStatusFlags = 9008,
+ Zo_MultiInValue = 9027,
+ Zo_MultiNumberOfStates = 9040,
+ Zo_MultiOutApplicationType = 9060,
+ Zo_MultiOutDescription = 9084,
+ Zo_MultiOutNumberOfStates = 9104,
+ Zo_MultiOutOfService = 9127,
+ Zo_MultiOutOutOfService = 9145,
+ Zo_MultiOutReliability = 9166,
+ Zo_MultiOutRelinquishDefault = 9186,
+ Zo_MultiOutStatusFlags = 9212,
+ Zo_MultiOutValue = 9232,
+ Zo_MultiReliability = 9246,
+ Zo_MultiRelinquishDefault = 9263,
+ Zo_MultiStatusFlags = 9286,
+ Zo_MultiValue = 9303,
+ Zo_MultipleScheduling = 9314,
+ Zo_NeutralCurrent = 9333,
+ Zo_NotificationRetryNumber = 9348,
+ Zo_NotificationRetryTimer = 9372,
+ Zo_NumberOfDevices = 9395,
+ Zo_NumberOfHolidaySchedulesSupported = 9411,
+ Zo_NumberOfLogRecordsSupported = 9445,
+ Zo_NumberOfPINUsersSupported = 9473,
+ Zo_NumberOfPrimaries = 9499,
+ Zo_NumberOfRFIDUsersSupported = 9517,
+ Zo_NumberOfResets = 9544,
+ Zo_NumberOfTotalUsersSupported = 9559,
+ Zo_NumberOfWeekDaySchedulesSupportedPerUser = 9587,
+ Zo_NumberOfYearDaySchedulesSupportedPerUser = 9628,
+ Zo_NumberOfZoneSensitivityLevelsSupported = 9669,
+ Zo_NumberRSSIMeasurements = 9708,
+ Zo_NumberofActuationsLift = 9731,
+ Zo_NumberofActuationsTilt = 9754,
+ Zo_Occupancy = 9777,
+ Zo_OccupancySensorType = 9787,
+ Zo_OccupiedCoolingSetpoint = 9807,
+ Zo_OccupiedHeatingSetpoint = 9831,
+ Zo_OffTransitionTime = 9855,
+ Zo_OffWaitTime = 9873,
+ Zo_OnLevel = 9885,
+ Zo_OnOff = 9893,
+ Zo_OnOffTransitionTime = 9899,
+ Zo_OnTime = 9919,
+ Zo_OnTransitionTime = 9926,
+ Zo_OpenPeriod = 9943,
+ Zo_OppleMode = 9954,
+ Zo_OutdoorTemperature = 9964,
+ Zo_OutletTemperature = 9983,
+ Zo_OverTempTotalDwell = 10001,
+ Zo_PICoolingDemand = 10020,
+ Zo_PIHeatingDemand = 10036,
+ Zo_PIROccupiedToUnoccupiedDelay = 10052,
+ Zo_PIRUnoccupiedToOccupiedDelay = 10081,
+ Zo_PIRUnoccupiedToOccupiedThreshold = 10110,
+ Zo_POD = 10143,
+ Zo_Panic = 10147,
+ Zo_PartNumber = 10153,
+ Zo_PathLossExponent = 10164,
+ Zo_PersistentMemoryWrites = 10181,
+ Zo_PersonalAlarm = 10204,
+ Zo_PhaseHarmonicCurrentMultiplier = 10218,
+ Zo_PhysicalClosedLimit = 10249,
+ Zo_PhysicalClosedLimitLift = 10269,
+ Zo_PhysicalClosedLimitTilt = 10293,
+ Zo_PhysicalEnvironment = 10317,
+ Zo_Power = 10337,
+ Zo_PowerDivisor = 10343,
+ Zo_PowerFactor = 10356,
+ Zo_PowerFactorPhB = 10368,
+ Zo_PowerFactorPhC = 10383,
+ Zo_PowerMultiplier = 10398,
+ Zo_PowerOffEffect = 10414,
+ Zo_PowerOnRecall = 10429,
+ Zo_PowerOnTimer = 10443,
+ Zo_PowerSource = 10456,
+ Zo_PowerThreshold = 10468,
+ Zo_PresetReadingTime = 10483,
+ Zo_Pressure = 10501,
+ Zo_PressureMaxMeasuredValue = 10510,
+ Zo_PressureMaxScaledValue = 10535,
+ Zo_PressureMinMeasuredValue = 10558,
+ Zo_PressureMinScaledValue = 10583,
+ Zo_PressureScale = 10606,
+ Zo_PressureScaledTolerance = 10620,
+ Zo_PressureScaledValue = 10644,
+ Zo_PressureTolerance = 10664,
+ Zo_PreviousBlockPeriodConsumptionDelivered = 10682,
+ Zo_Primary1Intensity = 10722,
+ Zo_Primary1X = 10740,
+ Zo_Primary1Y = 10750,
+ Zo_Primary2Intensity = 10760,
+ Zo_Primary2X = 10778,
+ Zo_Primary2Y = 10788,
+ Zo_Primary3Intensity = 10798,
+ Zo_Primary3X = 10816,
+ Zo_Primary3Y = 10826,
+ Zo_Primary4Intensity = 10836,
+ Zo_Primary4X = 10854,
+ Zo_Primary4Y = 10864,
+ Zo_Primary5Intensity = 10874,
+ Zo_Primary5X = 10892,
+ Zo_Primary5Y = 10902,
+ Zo_Primary6Intensity = 10912,
+ Zo_Primary6X = 10930,
+ Zo_Primary6Y = 10940,
+ Zo_ProductCode = 10950,
+ Zo_ProductRevision = 10962,
+ Zo_ProductURL = 10978,
+ Zo_ProfileIntervalPeriod = 10989,
+ Zo_ProxyTable = 11011,
+ Zo_QualityMeasure = 11022,
+ Zo_RGB = 11037,
+ Zo_RHDehumidificationSetpoint = 11041,
+ Zo_RMSCurrent = 11068,
+ Zo_RMSCurrentMax = 11079,
+ Zo_RMSCurrentMaxPhB = 11093,
+ Zo_RMSCurrentMaxPhC = 11110,
+ Zo_RMSCurrentMin = 11127,
+ Zo_RMSCurrentMinPhB = 11141,
+ Zo_RMSCurrentMinPhC = 11158,
+ Zo_RMSCurrentPhB = 11175,
+ Zo_RMSCurrentPhC = 11189,
+ Zo_RMSExtremeOverVoltage = 11203,
+ Zo_RMSExtremeOverVoltagePeriod = 11225,
+ Zo_RMSExtremeOverVoltagePeriodPhB = 11253,
+ Zo_RMSExtremeOverVoltagePeriodPhC = 11284,
+ Zo_RMSExtremeUnderVoltage = 11315,
+ Zo_RMSExtremeUnderVoltagePeriod = 11338,
+ Zo_RMSExtremeUnderVoltagePeriodPhB = 11367,
+ Zo_RMSExtremeUnderVoltagePeriodPhC = 11399,
+ Zo_RMSVoltage = 11431,
+ Zo_RMSVoltageMax = 11442,
+ Zo_RMSVoltageMaxPhB = 11456,
+ Zo_RMSVoltageMaxPhC = 11473,
+ Zo_RMSVoltageMin = 11490,
+ Zo_RMSVoltageMinPhB = 11504,
+ Zo_RMSVoltageMinPhC = 11521,
+ Zo_RMSVoltagePhB = 11538,
+ Zo_RMSVoltagePhC = 11552,
+ Zo_RMSVoltageSag = 11566,
+ Zo_RMSVoltageSagPeriod = 11580,
+ Zo_RMSVoltageSagPeriodPhB = 11600,
+ Zo_RMSVoltageSagPeriodPhC = 11623,
+ Zo_RMSVoltageSwell = 11646,
+ Zo_RMSVoltageSwellPeriod = 11662,
+ Zo_RMSVoltageSwellPeriodPhB = 11684,
+ Zo_RMSVoltageSwellPeriodPhC = 11709,
+ Zo_ReactiveCurrent = 11734,
+ Zo_ReactiveCurrentPhB = 11750,
+ Zo_ReactiveCurrentPhC = 11769,
+ Zo_ReactivePower = 11788,
+ Zo_ReactivePowerPhB = 11802,
+ Zo_ReactivePowerPhC = 11819,
+ Zo_ReadingSnapShotTime = 11836,
+ Zo_RecallScene = 11856,
+ Zo_RelativeHumidity = 11868,
+ Zo_RelativeHumidityDisplay = 11885,
+ Zo_RelativeHumidityMode = 11909,
+ Zo_RemainingTime = 11930,
+ Zo_RemoteSensing = 11944,
+ Zo_RemoveAllGroups = 11958,
+ Zo_RemoveAllScenes = 11974,
+ Zo_RemoveGroup = 11990,
+ Zo_RemoveScene = 12002,
+ Zo_ReportingPeriod = 12014,
+ Zo_ResetAlarm = 12030,
+ Zo_ResetAllAlarms = 12041,
+ Zo_SWBuildID = 12056,
+ Zo_Sat = 12066,
+ Zo_SatMove = 12070,
+ Zo_SatStep = 12078,
+ Zo_SceneCount = 12086,
+ Zo_SceneNameSupport = 12097,
+ Zo_SceneValid = 12114,
+ Zo_ScheduleMode = 12125,
+ Zo_SeaPressure = 12138,
+ Zo_SecurityLevel = 12150,
+ Zo_ServerActiveFunctionality = 12164,
+ Zo_ServerFunctionality = 12190,
+ Zo_SharedSecurityKey = 12210,
+ Zo_SharedSecurityKeyType = 12228,
+ Zo_ShortPollInterval = 12250,
+ Zo_Shutter = 12268,
+ Zo_ShutterClose = 12276,
+ Zo_ShutterLift = 12289,
+ Zo_ShutterOpen = 12301,
+ Zo_ShutterStop = 12313,
+ Zo_ShutterTilt = 12325,
+ Zo_SinkTable = 12337,
+ Zo_SoftwareRevision = 12347,
+ Zo_StackVersion = 12364,
+ Zo_StandardTime = 12377,
+ Zo_StartUpOnOff = 12390,
+ Zo_Status = 12403,
+ Zo_StoreScene = 12410,
+ Zo_SupplyStatus = 12421,
+ Zo_SwitchActions = 12434,
+ Zo_SwitchType = 12448,
+ Zo_SystemMode = 12459,
+ Zo_TRVBoost = 12470,
+ Zo_TRVChildProtection = 12479,
+ Zo_TRVMirrorDisplay = 12498,
+ Zo_TRVMode = 12515,
+ Zo_TRVWindowOpen = 12523,
+ Zo_TempTarget = 12537,
+ Zo_Temperature = 12548,
+ Zo_TemperatureDisplayMode = 12560,
+ Zo_TemperatureMaxMeasuredValue = 12583,
+ Zo_TemperatureMinMeasuredValue = 12611,
+ Zo_TemperatureTolerance = 12639,
+ Zo_TerncyDuration = 12660,
+ Zo_TerncyRotate = 12675,
+ Zo_ThSetpoint = 12688,
+ Zo_ThermostatAlarmMask = 12699,
+ Zo_ThermostatKeypadLockout = 12719,
+ Zo_ThermostatOccupancy = 12743,
+ Zo_ThermostatRunningMode = 12763,
+ Zo_ThermostatScheduleProgrammingVisibility = 12785,
+ Zo_Time = 12825,
+ Zo_TimeEpoch = 12830,
+ Zo_TimeStatus = 12840,
+ Zo_TimeZone = 12851,
+ Zo_TotalActivePower = 12860,
+ Zo_TotalApparentPower = 12877,
+ Zo_TotalProfileNum = 12896,
+ Zo_TotalReactivePower = 12912,
+ Zo_TuyaCalibration = 12931,
+ Zo_TuyaCalibrationTime = 12947,
+ Zo_TuyaMCUVersion = 12967,
+ Zo_TuyaMotorReversal = 12982,
+ Zo_TuyaMovingState = 13000,
+ Zo_TuyaQuery = 13016,
+ Zo_UnoccupiedCoolingSetpoint = 13026,
+ Zo_UnoccupiedHeatingSetpoint = 13052,
+ Zo_UtilityName = 13078,
+ Zo_ValidUntilTime = 13090,
+ Zo_ValvePosition = 13105,
+ Zo_VelocityLift = 13119,
+ Zo_ViewGroup = 13132,
+ Zo_ViewScene = 13142,
+ Zo_VolumePerReport = 13152,
+ Zo_Water = 13168,
+ Zo_WhitePointX = 13174,
+ Zo_WhitePointY = 13186,
+ Zo_WindowCoveringType = 13198,
+ Zo_X = 13217,
+ Zo_Y = 13219,
+ Zo_ZCLVersion = 13221,
+ Zo_ZoneID = 13232,
+ Zo_ZoneState = 13239,
+ Zo_ZoneStatus = 13249,
+ Zo_ZoneStatusChange = 13260,
+ Zo_ZoneType = 13277,
+ Zo__ = 13286,
+ Zo_xx = 13288,
+ Zo_xx000A00 = 13291,
+ Zo_xx0A = 13300,
+ Zo_xx0A00 = 13305,
+ Zo_xx19 = 13312,
+ Zo_xx190A = 13317,
+ Zo_xx190A00 = 13324,
+ Zo_xxxx = 13333,
+ Zo_xxxx00 = 13338,
+ Zo_xxxx0A00 = 13345,
+ Zo_xxxxyy = 13354,
+ Zo_xxxxyyyy = 13361,
+ Zo_xxxxyyyy0A00 = 13370,
+ Zo_xxxxyyzz = 13383,
+ Zo_xxyy = 13392,
+ Zo_xxyy0A00 = 13397,
+ Zo_xxyyyy = 13406,
+ Zo_xxyyyy000000000000 = 13413,
+ Zo_xxyyyy0A0000000000 = 13432,
+ Zo_xxyyyyzz = 13451,
+ Zo_xxyyyyzzzz = 13460,
+ Zo_xxyyzzzz = 13471,
};
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_1_attributes.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_1_attributes.ino
index 17be8d13f..96216c02c 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_1_attributes.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_1_attributes.ino
@@ -318,8 +318,8 @@ public:
}
uint8_t type; // zigbee type, Zunk by default
- int8_t multiplier; // multiply by x (ignore if 0 or 1)
- int8_t divider; // divide by x (ignore if 0 or 1)
+ uint16_t multiplier; // multiply by x (ignore if 0 or 1)
+ uint16_t divider; // divide by x (ignore if 0 or 1)
int16_t base; // add x (ignore if 0)
uint16_t cluster; // cluster number
uint16_t attribute; // attribute number
@@ -354,8 +354,8 @@ public:
uint16_t attribute; // attribute to match
uint16_t new_cluster; // replace with this cluster
uint16_t new_attribute; // replace with this attribute
- int8_t multiplier; // multiply by x (ignore if 0 or 1)
- int8_t divider; // divide by x (ignore if 0 or 1)
+ uint16_t multiplier; // multiply by x (ignore if 0 or 1)
+ uint16_t divider; // divide by x (ignore if 0 or 1)
int16_t base; // add x (ignore if 0)
};
@@ -732,7 +732,7 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = {
{ Zstring, Cx000F, 0x002E, Z_(BinaryInInactiveText),Cm1, 0 },
{ Zbool, Cx000F, 0x0051, Z_(BinaryInOutOfService),Cm1, 0 },
{ Zenum8, Cx000F, 0x0054, Z_(BinaryInPolarity), Cm1, 0 },
- { Zstring, Cx000F, 0x0055, Z_(BinaryInValue), Cm1, 0 },
+ { Zbool, Cx000F, 0x0055, Z_(BinaryInValue), Cm1, 0 },
// { 0xFF, Cx000F, 0x0057, (BinaryInPriorityArray),Cm1, 0 },
{ Zenum8, Cx000F, 0x0067, Z_(BinaryInReliability), Cm1, 0 },
{ Zmap8, Cx000F, 0x006F, Z_(BinaryInStatusFlags), Cm1, 0 },
@@ -1129,7 +1129,35 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = {
{ Zuint8, Cx0500, 0xFFF0 + ZA_GlassBreak, Z_(GlassBreak),Cm1, 0 },
// Metering (Smart Energy) cluster
- { Zuint48, Cx0702, 0x0000, Z_(EnergyTotal), Cm1, 0 },
+ { Zuint48, Cx0702, 0x0000, Z_(CurrentSummationDelivered),Cm1, 0 },
+ { Zuint48, Cx0702, 0x0001, Z_(CurrentSummationReceived),Cm1, 0 },
+ { Zuint48, Cx0702, 0x0002, Z_(CurrentMaxDemandDelivered),Cm1, 0 },
+ { Zuint48, Cx0702, 0x0003, Z_(CurrentMaxDemandReceived),Cm1, 0 },
+ { Zuint48, Cx0702, 0x0004, Z_(DFTSummation), Cm1, 0 },
+ { Zuint16, Cx0702, 0x0005, Z_(DailyFreezeTime), Cm1, 0 },
+ { Zint8, Cx0702, 0x0006, Z_(PowerFactor), Cm1, 0 },
+ { ZUTC, Cx0702, 0x0007, Z_(ReadingSnapShotTime), Cm1, 0 },
+ { ZUTC, Cx0702, 0x0008, Z_(CurrentMaxDemandDeliveredTime),Cm1, 0 },
+ { ZUTC, Cx0702, 0x0009, Z_(CurrentMaxDemandReceivedTime),Cm1, 0 },
+ { Zuint8, Cx0702, 0x000A, Z_(DefaultUpdatePeriod), Cm1, 0 },
+ { Zuint8, Cx0702, 0x000B, Z_(FastPollUpdatePeriod), Cm1, 0 },
+ { Zuint48, Cx0702, 0x000C, Z_(CurrentBlockPeriodConsumptionDelivered),Cm1, 0 },
+ { Zuint24, Cx0702, 0x000D, Z_(DailyConsumptionTarget),Cm1, 0 },
+ { Zenum8, Cx0702, 0x000E, Z_(CurrentBlock), Cm1, 0 },
+ { Zenum8, Cx0702, 0x000F, Z_(ProfileIntervalPeriod),Cm1, 0 },
+ { Zuint16, Cx0702, 0x0010, Z_(IntervalReadReportingPeriod),Cm1, 0 },
+ { Zuint16, Cx0702, 0x0011, Z_(PresetReadingTime), Cm1, 0 },
+ { Zuint16, Cx0702, 0x0012, Z_(VolumePerReport), Cm1, 0 },
+ { Zuint8, Cx0702, 0x0013, Z_(FlowRestriction), Cm1, 0 },
+ { Zenum8, Cx0702, 0x0014, Z_(SupplyStatus), Cm1, 0 },
+ { Zuint48, Cx0702, 0x0015, Z_(CurrentInletEnergyCarrierSummation),Cm1, 0 },
+ { Zuint48, Cx0702, 0x0016, Z_(CurrentOutletEnergyCarrierSummation),Cm1, 0 },
+ { Zint24, Cx0702, 0x0017, Z_(InletTemperature), Cm1, 0 },
+ { Zint24, Cx0702, 0x0018, Z_(OutletTemperature), Cm1, 0 },
+ { Zint24, Cx0702, 0x0019, Z_(ControlTemperature), Cm1, 0 },
+ { Zint24, Cx0702, 0x001A, Z_(CurrentInletEnergyCarrierDemand),Cm1, 0 },
+ { Zint24, Cx0702, 0x001B, Z_(CurrentOutletEnergyCarrierDemand),Cm1, 0 },
+ { Zuint48, Cx0702, 0x001C, Z_(PreviousBlockPeriodConsumptionDelivered),Cm1, 0 },
// Meter Identification cluster
{ Zstring, Cx0B01, 0x0000, Z_(CompanyName), Cm1, 0 },
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_2_converters.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_2_converters.ino
index 4614011aa..4faa86a39 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_2_converters.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_5_2_converters.ino
@@ -717,20 +717,25 @@ void ZCLFrame::applySynonymAttributes(Z_attribute_list& attr_list) {
Z_attribute_synonym syn = Z_plugin_matchAttributeSynonym(device.modelId, device.manufacturerId,
attr.cluster, attr.attr_id);
if (syn.found()) {
- attr.setKeyId(syn.new_cluster, syn.new_attribute);
- if ((syn.multiplier != 1 && syn.multiplier != 0) || (syn.divider != 1 && syn.divider != 0) || (syn.base != 0)) {
- // we need to change the value
- float fval = attr.getFloat();
- if (syn.multiplier != 1 && syn.multiplier != 0) {
- fval = fval * syn.multiplier;
+ AddLog(LOG_LEVEL_DEBUG, PSTR("ZIG: apply synonym %04X/%04X with %04X/%04X (mul:%i div:%i)"), attr.cluster, attr.attr_id, syn.new_cluster, syn.new_attribute, syn.multiplier, syn.divider);
+ if (syn.new_attribute == 0xFFFF) { // if attr is 0xFFFF, remove attribute
+ attr_list.removeAttribute(&attr);
+ } else {
+ attr.setKeyId(syn.new_cluster, syn.new_attribute);
+ if ((syn.multiplier != 1 && syn.multiplier != 0) || (syn.divider != 1 && syn.divider != 0) || (syn.base != 0)) {
+ // we need to change the value
+ float fval = attr.getFloat();
+ if (syn.multiplier != 1 && syn.multiplier != 0) {
+ fval = fval * syn.multiplier;
+ }
+ if (syn.divider != 1 && syn.divider != 0) {
+ fval = fval / syn.divider;
+ }
+ if (syn.base != 0) {
+ fval = fval + syn.base;
+ }
+ attr.setFloat(fval);
}
- if (syn.divider != 1 && syn.divider != 0) {
- fval = fval / syn.divider;
- }
- if (syn.base != 0) {
- fval = fval + syn.base;
- }
- attr.setFloat(fval);
}
}
}
@@ -757,17 +762,6 @@ void ZCLFrame::computeSyntheticAttributes(Z_attribute_list& attr_list) {
attr_list.addAttribute(0x0001, 0x0021).setUInt(toPercentageCR2032(mv) * 2);
}
break;
- case 0x00010021: // BatteryPercentage
- if (modelId.startsWith(F("TRADFRI")) ||
- modelId.startsWith(F("SYMFONISK"))) {
- attr.setUInt(attr.getUInt() * 2); // bug in IKEA remotes battery, need to double the value
- }
- break;
- case 0x00060000: // "Power" for lumi Door/Window is converted to "Contact"
- if (modelId.startsWith(F("lumi.sensor_magnet"))) {
- attr.setKeyId(0x0500, 0xFFF0 + ZA_Contact); // change cluster and attribute to 0500/FFF0
- }
- break;
case 0x02010008: // Pi Heating Demand - solve Eutotronic bug
case 0x02014008: // Eurotronic Host Flags decoding
{
@@ -1006,8 +1000,8 @@ void ZCLFrame::parseReadConfigAttributes(uint16_t shortaddr, Z_attribute_list& a
}
// find the multiplier
- int8_t multiplier = 1;
- int8_t divider = 1;
+ uint16_t multiplier = 1;
+ uint16_t divider = 1;
int16_t base = 0;
Z_attribute_match matched_attr = Z_findAttributeMatcherById(shortaddr, cluster, attrid, false);
if (matched_attr.found()) {
@@ -1189,9 +1183,6 @@ void ZCLFrame::syntheticAnalogValue(Z_attribute_list &attr_list, class Z_attribu
if (modelId.startsWith(F("lumi.sensor_cube"))) {
attr.setKeyId(0x000C, 0xFF55); // change to AqaraRotate
}
- if (modelId.startsWith(F("lumi.plug"))) {
- attr.setKeyId(0x0702, 0x0000); // change to EnergyTotal
- }
if (modelId.startsWith(F("lumi.ctrl"))) {
attr.setKeyId(0x0B04, 0x050B); // change to ActivePower
}
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_6_flash_fs.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_6_flash_fs.ino
new file mode 100644
index 000000000..034a2ff64
--- /dev/null
+++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_6_flash_fs.ino
@@ -0,0 +1,142 @@
+/*
+ xdrv_23_zigbee_7_6_flash_fs.ino - implement a Flash based read-only triviall file-system
+
+ Copyright (C) 2022 Theo Arends and Stephan Hadinger
+
+ 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_ZIGBEE
+
+#ifdef ESP32
+#include
+#else
+#include "FSImpl.h"
+#endif
+
+/********************************************************************
+** Subfile implementation
+**
+** Takes a string point in Flash and turn it to a read-only file
+********************************************************************/
+
+class FlashFileImpl;
+typedef std::shared_ptr FlashFileImplPtr;
+
+class FlashFileImpl : public FileImpl {
+public:
+
+ FlashFileImpl(const char* str) {
+ _buf = str;
+ _len = strlen_P(str);
+ _seek = 0;
+ }
+
+ virtual ~FlashFileImpl() {}
+
+ size_t write(const uint8_t *buf, size_t size) {
+ return 0; // not accepted
+ }
+
+ size_t read(uint8_t* buf, size_t size) {
+ if (_seek < _len) {
+ if (size + _seek > _len) {
+ size = _len - _seek; // always > 0 because of guarding test
+ }
+ memcpy_P(buf, _buf + _seek, size);
+ _seek += size;
+ return size;
+ }
+ return 0; // abort
+ }
+
+ void flush() {
+ // do nothing
+ }
+
+ bool setBufferSize(size_t size) {
+ return true;
+ }
+
+ bool seek(uint32_t pos, SeekMode mode) {
+ // AddLog(LOG_LEVEL_DEBUG, "ZIP: seek pos=%i mode=%i", pos, mode);
+ if (SeekSet == mode) {
+ if (pos <= _len) {
+ _seek = pos;
+ return true;
+ }
+ } else if (SeekCur == mode) {
+ if (_seek + pos <= _len) {
+ _seek += pos;
+ return true;
+ }
+ } else if (SeekEnd == mode) {
+ _seek = _len;
+ return true;
+ }
+ return false;
+ }
+
+ size_t position() const {
+ return _seek;
+ }
+
+ size_t size() const {
+ return _len;
+ }
+
+ void close() {
+ // do nothing
+ }
+ time_t getLastWrite() {
+ return 0;
+ }
+
+ const char* path() const {
+ return "";
+ }
+
+ const char* name() const {
+ return "";
+ }
+
+ boolean isDirectory(void) {
+ return false; // no directory allowed
+ }
+
+ FileImplPtr openNextFile(const char* mode) {
+ return nullptr; // TODO
+ }
+
+ void rewindDirectory(void) {
+ // ignore
+ }
+
+ operator bool() {
+ return true;
+ }
+
+ // ESP8266 specific?
+ bool truncate(uint32_t size) { return false; }
+ const char* fullName() const { return ""; }
+ bool isFile() const { return true; }
+ bool isDirectory() const { return false; }
+
+protected:
+ const char * _buf;
+ size_t _len;
+ uint32_t _seek;
+};
+
+#endif // USE_ZIGBEE
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_6_plugin.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_7_plugin.ino
similarity index 58%
rename from tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_6_plugin.ino
rename to tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_7_plugin.ino
index 4a1ef2b59..75adbc203 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_6_plugin.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_7_plugin.ino
@@ -125,6 +125,200 @@ bool Zb_readline(class File *f, char* buf, size_t size) {
extern FS *ffsp;
#endif
+bool ZbLoad_inner(const char *filename, File &fp) {
+ char * filename_imported = nullptr;
+ Z_plugin_template * tmpl = nullptr; // current template with matchers and attributes
+ bool new_matchers = false; // indicates that we have finished the current matchers
+ char buf_line[96]; // max line is 96 bytes (comments don't count)
+
+ // read the first 6 chars
+ bool invalid_header = false;
+ static const char Z2T_HEADER_V1[] PROGMEM = "#Z2Tv1";
+ for (uint32_t i = 0; i < 6; i++) {
+ int c = fp.read();
+ if (c < 0) {
+ invalid_header = true;
+ break;
+ }
+ buf_line[i] = c;
+ buf_line[i+1] = 0;
+ }
+ if (!invalid_header) {
+ if (strcmp_P(buf_line, Z2T_HEADER_V1) != 0) {
+ invalid_header = true;
+ }
+ }
+
+ if (invalid_header) {
+ AddLog(LOG_LEVEL_INFO, "ZIG: ZbLoad '%s' invalid header", filename);
+ return false;
+ }
+
+ // parse line by line
+ while (1) {
+ if (!Zb_readline(&fp, buf_line, sizeof(buf_line))) {
+ // EOF
+ break;
+ }
+
+ // at first valid line, we instanciate a new plug-in instance and assign a filemane
+ if (filename_imported == nullptr) {
+ // allocate only once the filename for multiple entries
+ // freed only by `ZbUnload`
+ filename_imported = (char*) malloc(strlen(filename)+1);
+ strcpy(filename_imported, filename);
+ }
+
+ // there is a non-empty line, containing no space/tab/crlf
+ // depending on the first char, parse either device name or cluster/attribute+name
+ if (buf_line[0] == ':') {
+ if (tmpl == nullptr || new_matchers) {
+ tmpl = &g_plugin_templates.addToLast();
+ tmpl->filename = filename_imported;
+ new_matchers = false;
+ }
+ // parse device name
+ char *rest = buf_line + 1; // skip first char ':'
+ char *token = strtok_r(rest, ",", &rest);
+ Z_plugin_matcher & matcher = tmpl->matchers.addToLast();
+ if (token != nullptr) {
+ matcher.setModel(token);
+ }
+ token = strtok_r(rest, ",", &rest);
+ if (token != nullptr) {
+ matcher.setManuf(token);
+ }
+ } else {
+ if (tmpl == nullptr) {
+ continue;
+ }
+ new_matchers = true;
+ char *rest = buf_line;
+ char *token = strtok_r(rest, ",", &rest);
+ if (token == nullptr) {
+ continue;
+ }
+
+ // detect if token contains '=', if yes it is a synonym
+ char * delimiter_equal = strchr(token, '=');
+
+ if (delimiter_equal == nullptr) {
+ // NORMAL ATTRIBUTE
+ // token is of from '0000/0000' or '0000/0000%00'
+ char * delimiter_slash = strchr(token, '/');
+ char * delimiter_percent = strchr(token, '%');
+ if (delimiter_slash == nullptr || (delimiter_percent != nullptr && delimiter_slash > delimiter_percent)) {
+ AddLog(LOG_LEVEL_INFO, "ZIG: ZbLoad '%s' wrong delimiter '%s'", filename, token);
+ }
+
+ uint16_t attr_id = 0xFFFF;
+ uint16_t cluster_id = 0xFFFF;
+ uint8_t type_id = Zunk;
+ int8_t multiplier = 1;
+ int8_t divider = 1;
+ int16_t base = 0;
+ char * name = nullptr;
+ uint16_t manuf = 0;
+
+ cluster_id = strtoul(token, &delimiter_slash, 16);
+ if (!delimiter_percent) {
+ attr_id = strtoul(delimiter_slash+1, nullptr, 16);
+ } else {
+ attr_id = strtoul(delimiter_slash+1, &delimiter_percent, 16);
+ type_id = Z_getTypeByName(delimiter_percent+1);
+ }
+ // NAME of the attribute
+ token = strtok_r(rest, ",", &rest);
+ if (token == nullptr) {
+ AddLog(LOG_LEVEL_INFO, "ZIG: ZbLoad '%s' ignore missing name '%s'", filename, buf_line);
+ continue;
+ }
+ name = token;
+ // ADDITIONAL ELEMENTS?
+ // Ex: `manuf:1037`
+ while (token = strtok_r(rest, ",", &rest)) {
+ char * sub_token;
+ // look for multiplier
+ if (sub_token = Z_subtoken(token, Z_MUL)) {
+ multiplier = strtol(sub_token, nullptr, 10);
+ }
+ // look for divider
+ else if (sub_token = Z_subtoken(token, Z_DIV)) {
+ divider = strtol(sub_token, nullptr, 10); // negative to indicate divider
+ }
+ // look for offset (base)
+ else if (sub_token = Z_subtoken(token, Z_ADD)) {
+ base = strtol(sub_token, nullptr, 10); // negative to indicate divider
+ }
+ // look for `manuf:HHHH`
+ else if (sub_token = Z_subtoken(token, Z_MANUF)) {
+ manuf = strtoul(sub_token, nullptr, 16);
+ }
+ else {
+ AddLog(LOG_LEVEL_DEBUG, "ZIG: ZbLoad unrecognized modifier '%s'", token);
+ }
+ }
+
+ // token contains the name of the attribute
+ Z_plugin_attribute & plugin_attr = tmpl->attributes.addToLast();
+ plugin_attr.cluster = cluster_id;
+ plugin_attr.attribute = attr_id;
+ plugin_attr.type = type_id;
+ plugin_attr.setName(name);
+ plugin_attr.multiplier = multiplier;
+ plugin_attr.divider = divider;
+ plugin_attr.base = base;
+ plugin_attr.manuf = manuf;
+ } else {
+ // ATTRIBUTE SYNONYM
+ // token is of from '0000/0000=0000/0000,1'
+ char * rest2 = token;
+ char * tok2 = strtok_r(rest2, "=", &rest2);
+ char * delimiter_slash = strchr(tok2, '/');
+ uint16_t cluster_id = strtoul(tok2, &delimiter_slash, 16);
+ uint16_t attr_id = strtoul(delimiter_slash+1, nullptr, 16);
+ tok2 = strtok_r(rest2, "=", &rest2);
+ char * delimiter_slash2 = strchr(tok2, '/');
+ uint16_t new_cluster_id = strtoul(tok2, &delimiter_slash2, 16);
+ uint16_t new_attr_id = strtoul(delimiter_slash2+1, nullptr, 16);
+ int8_t multiplier = 1;
+ int8_t divider = 1;
+ int16_t base = 0;
+
+ // ADDITIONAL ELEMENTS?
+ while (token = strtok_r(rest, ",", &rest)) {
+ char * sub_token;
+ // look for multiplier
+ if (sub_token = Z_subtoken(token, Z_MUL)) {
+ multiplier = strtol(sub_token, nullptr, 10);
+ }
+ // look for divider
+ else if (sub_token = Z_subtoken(token, Z_DIV)) {
+ divider = strtol(sub_token, nullptr, 10); // negative to indicate divider
+ }
+ // look for offset (base)
+ else if (sub_token = Z_subtoken(token, Z_ADD)) {
+ base = strtol(sub_token, nullptr, 10); // negative to indicate divider
+ }
+ else {
+ AddLog(LOG_LEVEL_DEBUG, "ZIG: ZbLoad unrecognized modifier '%s'", token);
+ }
+ }
+ // create the synonym
+ Z_attribute_synonym & syn = tmpl->synonyms.addToLast();
+ syn.cluster = cluster_id;
+ syn.attribute = attr_id;
+ syn.new_cluster = new_cluster_id;
+ syn.new_attribute = new_attr_id;
+ syn.multiplier = multiplier;
+ syn.divider = divider;
+ syn.base = base;
+ }
+ }
+ }
+ return true;
+}
+
// load a file from filesystem
// returns `true` if success
bool ZbLoad(const char *filename_raw) {
@@ -147,196 +341,7 @@ bool ZbLoad(const char *filename_raw) {
return false;
}
- char * filename_imported = nullptr;
- Z_plugin_template * tmpl = nullptr; // current template with matchers and attributes
- bool new_matchers = false; // indicates that we have finished the current matchers
- char buf_line[96]; // max line is 96 bytes (comments don't count)
-
- // read the first 6 chars
- bool invalid_header = false;
- static const char Z2T_HEADER_V1[] PROGMEM = "#Z2Tv1";
- for (uint32_t i = 0; i < 6; i++) {
- int c = fp.read();
- if (c < 0) {
- invalid_header = true;
- break;
- }
- buf_line[i] = c;
- buf_line[i+1] = 0;
- }
- if (!invalid_header) {
- if (strcmp_P(buf_line, Z2T_HEADER_V1) != 0) {
- invalid_header = true;
- }
- }
-
- if (invalid_header) {
- AddLog(LOG_LEVEL_INFO, "ZIG: ZbLoad '%s' invalid header", filename_raw);
- return false;
- }
-
- // parse line by line
- while (1) {
- if (!Zb_readline(&fp, buf_line, sizeof(buf_line))) {
- // EOF
- break;
- }
-
- // at first valid line, we instanciate a new plug-in instance and assign a filemane
- if (filename_imported == nullptr) {
- // allocate only once the filename for multiple entries
- // freed only by `ZbUnload`
- filename_imported = (char*) malloc(strlen(filename.c_str())+1);
- strcpy(filename_imported, filename.c_str());
- }
-
- // there is a non-empty line, containing no space/tab/crlf
- // depending on the first char, parse either device name or cluster/attribute+name
- if (buf_line[0] == ':') {
- if (tmpl == nullptr || new_matchers) {
- tmpl = &g_plugin_templates.addToLast();
- tmpl->filename = filename_imported;
- new_matchers = false;
- }
- // parse device name
- char *rest = buf_line + 1; // skip first char ':'
- char *token = strtok_r(rest, ",", &rest);
- Z_plugin_matcher & matcher = tmpl->matchers.addToLast();
- if (token != nullptr) {
- matcher.setModel(token);
- }
- token = strtok_r(rest, ",", &rest);
- if (token != nullptr) {
- matcher.setManuf(token);
- }
- } else {
- if (tmpl == nullptr) {
- continue;
- }
- new_matchers = true;
- char *rest = buf_line;
- char *token = strtok_r(rest, ",", &rest);
- if (token == nullptr) {
- continue;
- }
-
- // detect if token contains '=', if yes it is a synonym
- char * delimiter_equal = strchr(token, '=');
-
- if (delimiter_equal == nullptr) {
- // NORMAL ATTRIBUTE
- // token is of from '0000/0000' or '0000/0000%00'
- char * delimiter_slash = strchr(token, '/');
- char * delimiter_percent = strchr(token, '%');
- if (delimiter_slash == nullptr || (delimiter_percent != nullptr && delimiter_slash > delimiter_percent)) {
- AddLog(LOG_LEVEL_INFO, "ZIG: ZbLoad '%s' wrong delimiter '%s'", filename_raw, token);
- }
-
- uint16_t attr_id = 0xFFFF;
- uint16_t cluster_id = 0xFFFF;
- uint8_t type_id = Zunk;
- int8_t multiplier = 1;
- int8_t divider = 1;
- int16_t base = 0;
- char * name = nullptr;
- uint16_t manuf = 0;
-
- cluster_id = strtoul(token, &delimiter_slash, 16);
- if (!delimiter_percent) {
- attr_id = strtoul(delimiter_slash+1, nullptr, 16);
- } else {
- attr_id = strtoul(delimiter_slash+1, &delimiter_percent, 16);
- type_id = Z_getTypeByName(delimiter_percent+1);
- }
- // NAME of the attribute
- token = strtok_r(rest, ",", &rest);
- if (token == nullptr) {
- AddLog(LOG_LEVEL_INFO, "ZIG: ZbLoad '%s' ignore missing name '%s'", filename_raw, buf_line);
- continue;
- }
- name = token;
- // ADDITIONAL ELEMENTS?
- // Ex: `manuf:1037`
- while (token = strtok_r(rest, ",", &rest)) {
- char * sub_token;
- // look for multiplier
- if (sub_token = Z_subtoken(token, Z_MUL)) {
- multiplier = strtol(sub_token, nullptr, 10);
- }
- // look for divider
- else if (sub_token = Z_subtoken(token, Z_DIV)) {
- divider = strtol(sub_token, nullptr, 10); // negative to indicate divider
- }
- // look for offset (base)
- else if (sub_token = Z_subtoken(token, Z_ADD)) {
- base = strtol(sub_token, nullptr, 10); // negative to indicate divider
- }
- // look for `manuf:HHHH`
- else if (sub_token = Z_subtoken(token, Z_MANUF)) {
- manuf = strtoul(sub_token, nullptr, 16);
- }
- else {
- AddLog(LOG_LEVEL_DEBUG, "ZIG: ZbLoad unrecognized modifier '%s'", token);
- }
- }
-
- // token contains the name of the attribute
- Z_plugin_attribute & plugin_attr = tmpl->attributes.addToLast();
- plugin_attr.cluster = cluster_id;
- plugin_attr.attribute = attr_id;
- plugin_attr.type = type_id;
- plugin_attr.setName(name);
- plugin_attr.multiplier = multiplier;
- plugin_attr.divider = divider;
- plugin_attr.base = base;
- plugin_attr.manuf = manuf;
- } else {
- // ATTRIBUTE SYNONYM
- // token is of from '0000/0000=0000/0000,1'
- char * rest2 = token;
- char * tok2 = strtok_r(rest2, "=", &rest2);
- char * delimiter_slash = strchr(tok2, '/');
- uint16_t cluster_id = strtoul(tok2, &delimiter_slash, 16);
- uint16_t attr_id = strtoul(delimiter_slash+1, nullptr, 16);
- tok2 = strtok_r(rest2, "=", &rest2);
- char * delimiter_slash2 = strchr(tok2, '/');
- uint16_t new_cluster_id = strtoul(tok2, &delimiter_slash2, 16);
- uint16_t new_attr_id = strtoul(delimiter_slash2+1, nullptr, 16);
- int8_t multiplier = 1;
- int8_t divider = 1;
- int16_t base = 0;
-
- // ADDITIONAL ELEMENTS?
- while (token = strtok_r(rest, ",", &rest)) {
- char * sub_token;
- // look for multiplier
- if (sub_token = Z_subtoken(token, Z_MUL)) {
- multiplier = strtol(sub_token, nullptr, 10);
- }
- // look for divider
- else if (sub_token = Z_subtoken(token, Z_DIV)) {
- divider = strtol(sub_token, nullptr, 10); // negative to indicate divider
- }
- // look for offset (base)
- else if (sub_token = Z_subtoken(token, Z_ADD)) {
- base = strtol(sub_token, nullptr, 10); // negative to indicate divider
- }
- else {
- AddLog(LOG_LEVEL_DEBUG, "ZIG: ZbLoad unrecognized modifier '%s'", token);
- }
- }
- // create the synonym
- Z_attribute_synonym & syn = tmpl->synonyms.addToLast();
- syn.cluster = cluster_id;
- syn.attribute = attr_id;
- syn.new_cluster = new_cluster_id;
- syn.new_attribute = new_attr_id;
- syn.multiplier = multiplier;
- syn.divider = divider;
- syn.base = base;
- }
- }
- }
+ return ZbLoad_inner(filename.c_str(), fp);
} else {
AddLog(LOG_LEVEL_ERROR, "ZIG: filesystem not enabled");
}
@@ -381,7 +386,7 @@ bool ZbUnload(const char *filename_raw) {
}
// append modifiers like mul/div/manuf
-void Z_AppendModifiers(char * buf, size_t buf_len, int8_t multiplier, int8_t divider, int16_t base, uint16_t manuf) {
+void Z_AppendModifiers(char * buf, size_t buf_len, uint16_t multiplier, uint16_t divider, int16_t base, uint16_t manuf) {
if (multiplier != 0 && multiplier != 1) {
ext_snprintf_P(buf, buf_len, "%s,%s%i", buf, Z_MUL, multiplier);
}
@@ -447,6 +452,7 @@ void ZbLoadDump(void) {
// Auto-load all files ending with '.zb'
void ZbAutoload(void) {
+ ZbAutoLoadFromFlash();
#ifdef USE_UFILESYS
if (ffsp) {
File dir = ffsp->open("/", "r");
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_8_default_plugin.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_8_default_plugin.ino
new file mode 100644
index 000000000..62e9f167f
--- /dev/null
+++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_7_8_default_plugin.ino
@@ -0,0 +1,53 @@
+/*
+ xdrv_23_zigbee_7_8_default_plugin.ino - default plugin stored in Flash
+
+ Copyright (C) 2021 Theo Arends and Stephan Hadinger
+
+ 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_ZIGBEE
+
+/********************************************************************
+** Default plugin
+**
+** Below is a the template loaded at boot
+** We simulate a read-only file from the filesystem
+********************************************************************/
+
+const char Z_DEF_PLUGIN[] PROGMEM =
+ "#Z2Tv1" "\n"
+
+ // bug in IKEA remotes battery, need to double the value
+ ":TRADFRI*," "\n"
+ ":SYMFONISK*," "\n"
+ "0001/0021=0001/0021,mul:2" "\n" // BatteryPercentage
+
+ // "Power" for lumi Door/Window is converted to "Contact"
+ ":lumi.sensor_magnet*," "\n"
+ "0006/0000=0500/FFF2" "\n" // 0xFFF0 + ZA_Contact
+;
+
+/********************************************************************
+** Load from flash
+********************************************************************/
+void ZbAutoLoadFromFlash(void) {
+ FlashFileImplPtr fp = FlashFileImplPtr(new FlashFileImpl(Z_DEF_PLUGIN));
+ File f = File(fp);
+ if (ZbLoad_inner(PSTR(""), f)) {
+ AddLog(LOG_LEVEL_INFO, "ZIG: ZbLoad '%s' loaded successfully", PSTR(""));
+ }
+}
+
+#endif // USE_ZIGBEE
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_8_parsers.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_8_parsers.ino
index db21e801f..dda38daf8 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_8_parsers.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_8_parsers.ino
@@ -1773,17 +1773,19 @@ void Z_IncomingMessage(class ZCLFrame &zcl_received) {
callBerryZigbeeDispatcher("attributes_refined", &zcl_received, &attr_list, srcaddr);
#endif // USE_BERRY
- if (defer_attributes) {
- // Prepare for publish
- if (zigbee_devices.jsonIsConflict(srcaddr, attr_list)) {
- // there is conflicting values, force a publish of the previous message now and don't coalesce
- zigbee_devices.jsonPublishFlush(srcaddr);
+ if (!attr_list.isEmpty()) {
+ if (defer_attributes) {
+ // Prepare for publish
+ if (zigbee_devices.jsonIsConflict(srcaddr, attr_list)) {
+ // there is conflicting values, force a publish of the previous message now and don't coalesce
+ zigbee_devices.jsonPublishFlush(srcaddr);
+ }
+ zigbee_devices.jsonAppend(srcaddr, attr_list);
+ zigbee_devices.setTimer(srcaddr, 0 /* groupaddr */, USE_ZIGBEE_COALESCE_ATTR_TIMER, 0 /*clusterid*/, srcendpoint, Z_CAT_READ_ATTR, 0, &Z_PublishAttributes);
+ } else {
+ // Publish immediately
+ zigbee_devices.jsonPublishNow(srcaddr, attr_list);
}
- zigbee_devices.jsonAppend(srcaddr, attr_list);
- zigbee_devices.setTimer(srcaddr, 0 /* groupaddr */, USE_ZIGBEE_COALESCE_ATTR_TIMER, clusterid, srcendpoint, Z_CAT_READ_ATTR, 0, &Z_PublishAttributes);
- } else {
- // Publish immediately
- zigbee_devices.jsonPublishNow(srcaddr, attr_list);
}
}
}
@@ -2307,6 +2309,9 @@ void ZCLFrame::autoResponder(const uint16_t *attr_list_ids, size_t attr_len) {
zcl.clusterSpecific = false; /* not cluster specific */
zcl.needResponse = false; /* noresponse */
zcl.direct = true; /* direct response */
+ if (localShortAddr == 0x0000) {
+ zcl.direction = 1; // if we are coordinator, then response is from client to server
+ }
zcl.setTransac(transactseq);
zcl.payload.addBuffer(buf);
zigbeeZCLSendCmd(zcl);
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino
index f3ab5af77..46f3b7023 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_23_zigbee_A_impl.ino
@@ -21,6 +21,8 @@
#define XDRV_23 23
+// #define ZIGBEE_DOC // enable special functions used for Zigbee documentation generation - generally not useful
+
#include "UnishoxStrings.h"
const char kZbCommands[] PROGMEM = D_PRFX_ZB "|" // prefix
@@ -41,6 +43,9 @@ const char kZbCommands[] PROGMEM = D_PRFX_ZB "|" // prefix
D_CMND_ZIGBEE_RESTORE "|" D_CMND_ZIGBEE_BIND_STATE "|" D_CMND_ZIGBEE_MAP "|" D_CMND_ZIGBEE_LEAVE "|"
D_CMND_ZIGBEE_CONFIG "|" D_CMND_ZIGBEE_DATA "|" D_CMND_ZIGBEE_SCAN "|" D_CMND_ZIGBEE_ENROLL "|" D_CMND_ZIGBEE_CIE "|"
D_CMND_ZIGBEE_LOAD "|" D_CMND_ZIGBEE_UNLOAD "|" D_CMND_ZIGBEE_LOADDUMP
+#ifdef ZIGBEE_DOC
+ "|" D_CMND_ZIGBEE_ATTRDUMP
+#endif // ZIGBEE_DOC
;
SO_SYNONYMS(kZbSynonyms,
@@ -64,6 +69,9 @@ void (* const ZigbeeCommand[])(void) PROGMEM = {
&CmndZbConfig, &CmndZbData, &CmndZbScan,
&CmndZbenroll, &CmndZbcie,
&CmndZbLoad, &CmndZbUnload, &CmndZbLoadDump,
+#ifdef ZIGBEE_DOC
+ &CmndZbAttrDump,
+#endif // ZIGBEE_DOC
};
/********************************************************************************************/
@@ -1119,8 +1127,16 @@ void CmndZbProbe(void) {
//
void CmndZbProbeOrPing(boolean probe) {
if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; }
- uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, nullptr, nullptr, XdrvMailbox.payload).shortaddr;
- if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE)); return; }
+ uint16_t parsed_shortaddr = BAD_SHORTADDR;
+ uint16_t shortaddr = zigbee_devices.parseDeviceFromName(XdrvMailbox.data, &parsed_shortaddr, nullptr, XdrvMailbox.payload).shortaddr;
+ if (BAD_SHORTADDR == shortaddr) {
+ if (BAD_SHORTADDR == parsed_shortaddr) { // second chance if we provided 0x.... address for a device not in the list
+ ResponseCmndChar_P(PSTR(D_ZIGBEE_UNKNOWN_DEVICE));
+ return;
+ } else {
+ shortaddr = parsed_shortaddr;
+ }
+ }
// set a timer for Reachable - 2s default value
zigbee_devices.setTimer(shortaddr, 0, Z_CAT_REACHABILITY_TIMEOUT, 0, 0, Z_CAT_REACHABILITY, 0 /* value */, &Z_Unreachable);
@@ -1417,6 +1433,45 @@ void CmndZbLoadDump(void) {
ResponseCmndDone();
}
+#ifdef ZIGBEE_DOC
+// Command `ZbAttrDump`
+// Dump all the attribute aliases for documentation purpose
+//
+void CmndZbAttrDump(void) {
+ // does not require Zigbee to actually run
+ AddLog(LOG_LEVEL_INFO, PSTR("Alias|Cluster|Attribute|Type"));
+ AddLog(LOG_LEVEL_INFO, PSTR(":---|:---|:---|:---"));
+ for (uint32_t i = 0; i < nitems(Z_PostProcess); i++) {
+ const Z_AttributeConverter *converter = &Z_PostProcess[i];
+ if (0 == pgm_read_word(&converter->name_offset)) { continue; }
+ const char * alias = Z_strings + pgm_read_word(&converter->name_offset);
+ uint16_t cluster = CxToCluster(pgm_read_byte(&converter->cluster_short));
+ uint16_t attrid = pgm_read_word(&converter->attribute);
+ uint8_t attrtype = pgm_read_byte(&converter->type);
+ char type_name[16];
+ Z_getTypeByNumber(type_name, sizeof(type_name), attrtype);
+ AddLog(LOG_LEVEL_INFO, PSTR("`%s`|0x%04X|0x%04X|%%%02X - %s"), alias, cluster, attrid, attrtype, type_name);
+ }
+ AddLog(LOG_LEVEL_INFO, PSTR(""));
+
+ AddLog(LOG_LEVEL_INFO, PSTR("Alias|Cluster|Command"));
+ AddLog(LOG_LEVEL_INFO, PSTR(":---|:---|:---"));
+ for (uint32_t i = 0; i < sizeof(Z_Commands) / sizeof(Z_Commands[0]); i++) {
+ const Z_CommandConverter *conv = &Z_Commands[i];
+ const char * alias = Z_strings + pgm_read_word(&conv->tasmota_cmd_offset);
+ uint16_t cluster = pgm_read_word(&conv->cluster);
+ uint8_t direction = pgm_read_byte(&conv->direction);
+ uint8_t cmd = pgm_read_byte(&conv->cmd);
+ if (direction & 0x01) { // only coordinator to device
+ AddLog(LOG_LEVEL_INFO, PSTR("`%s`|0x%04X|0x%02X"), alias, cluster, cmd);
+ }
+ }
+ AddLog(LOG_LEVEL_INFO, PSTR(""));
+
+ ResponseCmndDone();
+}
+#endif // ZIGBEE_DOC
+
//
// Command `ZbScan`
// Run an energy scan
@@ -2377,7 +2432,7 @@ void ZigbeeShowMap(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv23(uint8_t function) {
+bool Xdrv23(uint32_t function) {
if (TasmotaGlobal.gpio_optiona.enable_ccloader) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_24_buzzer.ino b/tasmota/tasmota_xdrv_driver/xdrv_24_buzzer.ino
index 3921589f3..81dcc1dc7 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_24_buzzer.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_24_buzzer.ino
@@ -229,7 +229,7 @@ void CmndBuzzer(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv24(uint8_t function) {
+bool Xdrv24(uint32_t function) {
bool result = false;
if (Buzzer.active) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_25_A4988_Stepper.ino b/tasmota/tasmota_xdrv_driver/xdrv_25_A4988_Stepper.ino
index 50e9997b1..ca8a2a421 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_25_A4988_Stepper.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_25_A4988_Stepper.ino
@@ -119,7 +119,7 @@ void CmndSetRPM(void) {
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
-bool Xdrv25(uint8_t function)
+bool Xdrv25(uint32_t function)
{
bool result = false;
if (PinUsed(GPIO_A4988_DIR) && PinUsed(GPIO_A4988_STP)) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_26_ariluxrf.ino b/tasmota/tasmota_xdrv_driver/xdrv_26_ariluxrf.ino
index 50441c1c8..8cad4cf56 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_26_ariluxrf.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_26_ariluxrf.ino
@@ -170,7 +170,7 @@ void AriluxRfDisable(void)
* Interface
\*********************************************************************************************/
-bool Xdrv26(uint8_t function)
+bool Xdrv26(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino
index d92d82025..20971efe0 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino
@@ -67,7 +67,7 @@ const char kShutterCommands[] PROGMEM = D_PRFX_SHUTTER "|"
D_CMND_SHUTTER_SETHALFWAY "|" D_CMND_SHUTTER_SETCLOSE "|" D_CMND_SHUTTER_SETOPEN "|" D_CMND_SHUTTER_INVERT "|" D_CMND_SHUTTER_CLIBRATION "|"
D_CMND_SHUTTER_MOTORDELAY "|" D_CMND_SHUTTER_FREQUENCY "|" D_CMND_SHUTTER_BUTTON "|" D_CMND_SHUTTER_LOCK "|" D_CMND_SHUTTER_ENABLEENDSTOPTIME "|" D_CMND_SHUTTER_INVERTWEBBUTTONS "|"
D_CMND_SHUTTER_STOPOPEN "|" D_CMND_SHUTTER_STOPCLOSE "|" D_CMND_SHUTTER_STOPTOGGLE "|" D_CMND_SHUTTER_STOPTOGGLEDIR "|" D_CMND_SHUTTER_STOPPOSITION "|" D_CMND_SHUTTER_INCDEC "|"
- D_CMND_SHUTTER_UNITTEST "|" D_CMND_SHUTTER_TILTCONFIG "|" D_CMND_SHUTTER_SETTILT "|" D_CMND_SHUTTER_TILTINCDEC "|";
+ D_CMND_SHUTTER_UNITTEST "|" D_CMND_SHUTTER_TILTCONFIG "|" D_CMND_SHUTTER_SETTILT "|" D_CMND_SHUTTER_TILTINCDEC;
void (* const ShutterCommand[])(void) PROGMEM = {
&CmndShutterOpen, &CmndShutterClose, &CmndShutterToggle, &CmndShutterToggleDir, &CmndShutterStop, &CmndShutterPosition,
@@ -391,18 +391,30 @@ void ShutterReportPosition(bool always, uint32_t index)
uint32_t i = 0;
uint32_t n = TasmotaGlobal.shutters_present;
uint8_t shutter_running = 0;
+ for (i; i < n; i++) {
+ if (Shutter[i].direction != 0) {
+ shutter_running++;
+ }
+ }
+
+ // Allow function exit if nothing to report (99.9% use case)
+ if (!always && !shutter_running) return;
+
if( index != MAX_SHUTTERS) {
i = index;
n = index+1;
+ } else {
+ i = 0;
}
for (i; i < n; i++) {
//AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d Real Pos %d"), i+1,Shutter[i].real_position);
- uint32_t position = ShutterRealToPercentPosition(Shutter[i].real_position, i);
+
if (Shutter[i].direction != 0) {
ShutterLogPos(i);
shutter_running++;
}
if (i && index == MAX_SHUTTERS) { ResponseAppend_P(PSTR(",")); }
+ uint32_t position = ShutterRealToPercentPosition(Shutter[i].real_position, i);
uint32_t target = ShutterRealToPercentPosition(Shutter[i].target_position, i);
ResponseAppend_P(JSON_SHUTTER_POS, i+1, (Settings->shutter_options[i] & 1) ? 100-position : position, Shutter[i].direction,(Settings->shutter_options[i] & 1) ? 100-target : target, Shutter[i].tilt_real_pos );
}
@@ -587,8 +599,7 @@ void ShutterUpdatePosition(void)
Shutter[i].start_position = Shutter[i].real_position;
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Pre: Tilt not match %d -> %d, moving: %d"),Shutter[i].tilt_real_pos,Shutter[i].tilt_target_pos,Shutter[i].tiltmoving);
- if (abs(Shutter[i].tilt_real_pos - Shutter[i].tilt_target_pos) > Shutter[i].min_TiltChange && Shutter[i].tiltmoving == 0
- && Settings->shutter_position[i] > 0 && Settings->shutter_position[i] < 100) {
+ if (abs(Shutter[i].tilt_real_pos - Shutter[i].tilt_target_pos) > Shutter[i].min_TiltChange && Shutter[i].tiltmoving == 0) {
AddLog(LOG_LEVEL_INFO, PSTR("SHT: Tilt not match %d -> %d"),Shutter[i].tilt_real_pos,Shutter[i].tilt_target_pos);
char databuf[1] = "";
XdrvMailbox.data = databuf;
@@ -679,8 +690,8 @@ void ShutterStartInit(uint32_t i, int32_t direction, int32_t target_pos)
ShutterGlobal.start_reported = 0;
Shutter[i].tilt_real_pos = tmax(tmin(Shutter[i].tilt_real_pos,Shutter[i].tilt_config[1]),Shutter[i].tilt_config[0]);
Shutter[i].tilt_start_pos = Shutter[i].tilt_real_pos;
- if (Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0] != 0) {
- Shutter[i].venetian_delay = (direction > 0 ? Shutter[i].tilt_config[1]-Shutter[i].tilt_real_pos : Shutter[i].tilt_real_pos-Shutter[i].tilt_config[0]) * Shutter[i].tilt_config[2] / (Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0]);
+ if (Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0] != 0) {
+ Shutter[i].venetian_delay = SHT_DIV_ROUND((direction > 0 ? Shutter[i].tilt_config[1]-Shutter[i].tilt_real_pos : Shutter[i].tilt_real_pos-Shutter[i].tilt_config[0]) * Shutter[i].tilt_config[2], Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0]);
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: real %d, start %d, counter %d,freq_max %d, dir %d, freq %d"),Shutter[i].real_position, Shutter[i].start_position ,RtcSettings.pulse_counter[i],ShutterGlobal.open_velocity_max , direction ,ShutterGlobal.open_velocity_max );
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: VenetianDelay: %d, Pos: %d, Dir: %d, Delta: %d, Dur: %d, StartP: %d, TgtP: %d"),
Shutter[i].venetian_delay, Shutter[i].tilt_real_pos,direction,(Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0]), Shutter[i].tilt_config[2],Shutter[i].tilt_start_pos,Shutter[i].tilt_target_pos);
@@ -853,7 +864,7 @@ void ShutterButtonHandler(void)
}
if (NOT_PRESSED == button) {
- if (Shutter[shutter_index].direction && Button.hold_timer[button_index] > 0) {
+ if (Shutter[shutter_index].direction && (Button.hold_timer[button_index] > 0 && (!Settings->flag.button_single || Button.hold_timer[button_index] > 20))) {
XdrvMailbox.index = shutter_index +1;
XdrvMailbox.payload = XdrvMailbox.index;
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d, Button %d, hold %d, dir %d, index %d, payload %d"), shutter_index+1, button_index+1, Button.hold_timer[button_index],Shutter[shutter_index].direction,XdrvMailbox.index,XdrvMailbox.payload);
@@ -1200,6 +1211,10 @@ void CmndShutterPosition(void)
}
}
+ // if position is either 0 or 100 reset the tilt to avoid tilt moving at the end
+ if (XdrvMailbox.payload == 0 && ShutterRealToPercentPosition(Shutter[index].real_position, index) > 0 ) {Shutter[index].tilt_target_pos = Shutter[index].tilt_config[4];}
+ if (XdrvMailbox.payload == 100 && ShutterRealToPercentPosition(Shutter[index].real_position, index) < 100) {Shutter[index].tilt_target_pos = Shutter[index].tilt_config[3];}
+
int8_t target_pos_percent = (XdrvMailbox.payload < 0) ? (XdrvMailbox.payload == -99 ? ShutterRealToPercentPosition(Shutter[index].real_position, index) : 0) : ((XdrvMailbox.payload > 100) ? 100 : XdrvMailbox.payload);
// webgui still send also on inverted shutter the native position.
target_pos_percent = ((Settings->shutter_options[index] & 1) && (SRC_WEBGUI != TasmotaGlobal.last_source)) ? 100 - target_pos_percent : target_pos_percent;
@@ -1718,7 +1733,7 @@ void CmndShutterTiltIncDec(void)
* Interface
\*********************************************************************************************/
-bool Xdrv27(uint8_t function)
+bool Xdrv27(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574.ino b/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574.ino
index 7954acd62..25e0018fc 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_28_pcf8574.ino
@@ -308,7 +308,7 @@ void Pcf8574SaveSettings(void)
* Interface
\*********************************************************************************************/
-bool Xdrv28(uint8_t function)
+bool Xdrv28(uint32_t function)
{
if (!I2cEnabled(XI2C_02)) { return false; }
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_29_deepsleep.ino b/tasmota/tasmota_xdrv_driver/xdrv_29_deepsleep.ino
index 81f7b3a3e..a607fa0e9 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_29_deepsleep.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_29_deepsleep.ino
@@ -118,11 +118,14 @@ void DeepSleepPrepare(void)
RtcSettings.deepsleep_slip = tmin(tmax(RtcSettings.deepsleep_slip, 9000), 11000);
}
+// AddLog(LOG_LEVEL_DEBUG, PSTR("DSL: Time %ld, next %ld, slip %ld"), timeslip, RtcSettings.nextwakeup, RtcSettings.deepsleep_slip );
// It may happen that wakeup in just <5 seconds in future
// In this case also add deepsleep to nextwakeup
if (RtcSettings.nextwakeup <= (LocalTime() + DEEPSLEEP_MIN_TIME)) {
- // ensure nextwakeup is at least in the future
+ // ensure nextwakeup is at least in the future, and add 5%
RtcSettings.nextwakeup += (((LocalTime() + DEEPSLEEP_MIN_TIME - RtcSettings.nextwakeup) / Settings->deepsleep) + 1) * Settings->deepsleep;
+ RtcSettings.nextwakeup += Settings->deepsleep * 0.05;
+// AddLog(LOG_LEVEL_DEBUG, PSTR("DSL: Time too short: time %ld, next %ld, slip %ld"), timeslip, RtcSettings.nextwakeup, RtcSettings.deepsleep_slip);
}
String dt = GetDT(RtcSettings.nextwakeup); // 2017-03-07T11:08:02
@@ -202,7 +205,7 @@ void CmndDeepsleepTime(void)
* Interface
\*********************************************************************************************/
-bool Xdrv29(uint8_t function)
+bool Xdrv29(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_30_exs_dimmer.ino b/tasmota/tasmota_xdrv_driver/xdrv_30_exs_dimmer.ino
index 7b3f4bcd2..597f3b9e6 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_30_exs_dimmer.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_30_exs_dimmer.ino
@@ -124,8 +124,7 @@ void ExsSerialSend(const uint8_t data[] = nullptr, uint16_t len = 0)
char rc;
#ifdef EXS_DEBUG
- AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("EXS: Tx Packet:"));
- AddLogBuffer(LOG_LEVEL_DEBUG_MORE, (uint8_t *)data, len);
+ AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("EXS: Tx Packet %*_H"), len, (uint8_t *)data);
#endif
while (retries)
@@ -363,8 +362,7 @@ bool ExsModuleSelected(void)
bool ExsSetChannels(void)
{
#ifdef EXS_DEBUG
- AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("EXS: SetChannels:"));
- AddLogBuffer(LOG_LEVEL_DEBUG_MORE, (uint8_t *)XdrvMailbox.data, XdrvMailbox.data_len);
+ AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("EXS: SetChannels %*_H"), XdrvMailbox.data_len, (uint8_t *)XdrvMailbox.data);
#endif
Exs.dimm[0] = ((uint8_t *)XdrvMailbox.data)[0];
@@ -456,8 +454,7 @@ void ExsSerialInput(void)
Exs.cmd_status = 0;
#ifdef EXS_DEBUG
- AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("EXS: CRC: 0x%02x, RX Packet:"), crc);
- AddLogBuffer(LOG_LEVEL_DEBUG_MORE, (uint8_t *)Exs.buffer, Exs.byte_counter);
+ AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("EXS: CRC 0x%02x, RX Packet %*_H"), crc, Exs.byte_counter, (uint8_t *)Exs.buffer);
#endif
if (Exs.buffer[0] == crc)
@@ -585,7 +582,7 @@ void CmndExsState(void)
* Interface
*/
-bool Xdrv30(uint8_t function)
+bool Xdrv30(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_31_tasmota_client.ino b/tasmota/tasmota_xdrv_driver/xdrv_31_tasmota_client.ino
index d47f39b43..d15900189 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_31_tasmota_client.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_31_tasmota_client.ino
@@ -238,15 +238,13 @@ uint8_t TasmotaClient_receiveData(char* buffer, int size) {
}
if (255 == index) { index = 0; }
-// AddLog(LOG_LEVEL_DEBUG, PSTR("TCL: ReceiveData"));
-// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t*)buffer, index);
+// AddLog(LOG_LEVEL_DEBUG, PSTR("TCL: ReceiveData %*_H"), index, (uint8_t*)buffer);
return index;
}
uint8_t TasmotaClient_sendBytes(uint8_t* bytes, int count) {
-// AddLog(LOG_LEVEL_DEBUG, PSTR("TCL: SendBytes"));
-// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t*)&bytes, count);
+// AddLog(LOG_LEVEL_DEBUG, PSTR("TCL: SendBytes %*_H"), count, (uint8_t*)&bytes);
TasmotaClient_Serial->write(bytes, count);
TasmotaClient_waitForSerialData(2, TASMOTA_CLIENT_TIMEOUT);
@@ -334,7 +332,7 @@ uint32_t TasmotaClient_Flash(uint8_t* data, size_t size) {
memcpy(flash_buffer, data + read, sizeof(flash_buffer));
read = read + sizeof(flash_buffer);
-// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t*)flash_buffer, 32);
+// AddLog(LOG_LEVEL_DEBUG, PSTR("TCL: Flash %32_H"), (uint8_t*)flash_buffer);
for (uint32_t ca = 0; ca < sizeof(flash_buffer); ca++) {
processed++;
@@ -401,6 +399,9 @@ void TasmotaClient_Init(void) {
if (TasmotaClient_Serial->hardwareSerial()) {
ClaimSerial();
}
+#ifdef ESP32
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TCL: Serial UART%d"), TasmotaClient_Serial->getUart());
+#endif
if (PinUsed(GPIO_TASMOTACLIENT_RST_INV)) {
SetPin(Pin(GPIO_TASMOTACLIENT_RST_INV), AGPIO(GPIO_TASMOTACLIENT_RST));
TClient.inverted = HIGH;
@@ -456,8 +457,7 @@ void TasmotaClient_sendCmnd(uint8_t cmnd, uint8_t param) {
memcpy(&buffer[1], &TClientCommand, sizeof(TClientCommand));
buffer[sizeof(TClientCommand)+1] = CMND_END;
-// AddLog(LOG_LEVEL_DEBUG, PSTR("TCL: SendCmnd"));
-// AddLogBuffer(LOG_LEVEL_DEBUG, (uint8_t*)&buffer, sizeof(buffer));
+// AddLog(LOG_LEVEL_DEBUG, PSTR("TCL: SendCmnd %*_H"), sizeof(buffer), (uint8_t*)&buffer);
for (uint32_t ca = 0; ca < sizeof(buffer); ca++) {
TasmotaClient_Serial->write(buffer[ca]);
@@ -531,7 +531,7 @@ void TasmotaClient_ProcessIn(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv31(uint8_t function) {
+bool Xdrv31(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_32_hotplug.ino b/tasmota/tasmota_xdrv_driver/xdrv_32_hotplug.ino
index 8a055911a..d5dba3b3c 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_32_hotplug.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_32_hotplug.ino
@@ -80,7 +80,7 @@ void CmndHotPlugTime(void)
* Interface
\*********************************************************************************************/
-bool Xdrv32(uint8_t function)
+bool Xdrv32(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_33_nrf24l01.ino b/tasmota/tasmota_xdrv_driver/xdrv_33_nrf24l01.ino
index dfe690de2..83381d203 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_33_nrf24l01.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_33_nrf24l01.ino
@@ -80,7 +80,7 @@ void NRF24Detect(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv33(uint8_t function) {
+bool Xdrv33(uint32_t function) {
bool result = false;
if (FUNC_INIT == function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_34_wemos_motor_v1.ino b/tasmota/tasmota_xdrv_driver/xdrv_34_wemos_motor_v1.ino
index b38a863e1..4b25b714d 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_34_wemos_motor_v1.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_34_wemos_motor_v1.ino
@@ -268,7 +268,7 @@ void WMotorV2command(uint8_t *data, uint8_t len) // process V2 request
* Interface
\*********************************************************************************************/
-bool Xdrv34(uint8_t function)
+bool Xdrv34(uint32_t function)
{
if (!I2cEnabled(XI2C_44)) { return false; }
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_35_pwm_dimmer.ino b/tasmota/tasmota_xdrv_driver/xdrv_35_pwm_dimmer.ino
index 4a8587dc8..5ce566548 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_35_pwm_dimmer.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_35_pwm_dimmer.ino
@@ -790,7 +790,7 @@ void CmndPWMDimmerPWMs(void)
* Interface
\*********************************************************************************************/
-bool Xdrv35(uint8_t function)
+bool Xdrv35(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_36_keeloq.ino b/tasmota/tasmota_xdrv_driver/xdrv_36_keeloq.ino
index 1ea0f3bfc..13b700920 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_36_keeloq.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_36_keeloq.ino
@@ -261,7 +261,7 @@ void KeeloqInit()
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
-bool Xdrv36(uint8_t function)
+bool Xdrv36(uint32_t function)
{
if (!PinUsed(GPIO_CC1101_GDO0) || !PinUsed(GPIO_CC1101_GDO2)) { return false; }
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_37_sonoff_d1.ino b/tasmota/tasmota_xdrv_driver/xdrv_37_sonoff_d1.ino
index a153f3351..fde6dc1c9 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_37_sonoff_d1.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_37_sonoff_d1.ino
@@ -99,7 +99,7 @@ bool SonoffD1SerialInput(void)
// aa 55 01 04 00 0a 00 64 ff ff ff ff ff ff ff ff 6b - Power Off (with last dimmer 100%)
// aa 55 01 04 00 0a 01 64 ff ff ff ff ff ff ff ff 6c - Power On (with last dimmer 100%)
- AddLogSerial(LOG_LEVEL_DEBUG);
+ AddLogSerial();
uint8_t crc = 0;
for (uint32_t i = 2; i < SnfD1.receive_len -1; i++) {
crc += TasmotaGlobal.serial_in_buffer[i];
@@ -173,7 +173,7 @@ bool SonoffD1ModuleSelected(void)
* Interface
\*********************************************************************************************/
-bool Xdrv37(uint8_t function)
+bool Xdrv37(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_38_ping.ino b/tasmota/tasmota_xdrv_driver/xdrv_38_ping.ino
index 4390bd1d9..25cbce72d 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_38_ping.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_38_ping.ino
@@ -131,12 +131,7 @@ extern "C" {
if ((p->len == p->tot_len) && (p->next == nullptr)) {
ip_addr_t ping_target;
struct icmp_echo_hdr *iecho;
-#ifdef ESP8266
- ping_target.addr = ping->ip;
-#endif // ESP8266
-#ifdef ESP32
ip_addr_set_ip4_u32(&ping_target, ping->ip);
-#endif // ESP32
iecho = (struct icmp_echo_hdr *) p->payload;
t_ping_prepare_echo(iecho, ping_size, ping);
@@ -171,12 +166,7 @@ extern "C" {
// Reveived packet
//
static uint8_t ICACHE_FLASH_ATTR t_ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) {
-#ifdef ESP8266
- Ping_t *ping = t_ping_find(addr->addr);
-#endif // ESP8266
-#ifdef ESP32
- Ping_t *ping = t_ping_find(addr->u_addr.ip4.addr);
-#endif // ESP32
+ Ping_t *ping = t_ping_find(ip_addr_get_ip4_u32(addr));
if (nullptr == ping) { // unknown source address
return 0; // don't eat the packet and ignore it
@@ -365,7 +355,7 @@ void CmndPing(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv38(uint8_t function)
+bool Xdrv38(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_39_thermostat.ino b/tasmota/tasmota_xdrv_driver/xdrv_39_thermostat.ino
index 4d341fd4d..ed721bb22 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_39_thermostat.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_39_thermostat.ino
@@ -428,6 +428,14 @@ void ThermostatCtrState(uint8_t ctr_output)
break;
// Ramp-up controller (predictive)
case CTR_RAMP_UP:
+ // If ramp-up off time counter has been initialized
+ // AND ramp-up off time counter value reached
+ if ((Thermostat[ctr_output].time_ctr_checkpoint != 0) &&
+ (TasmotaGlobal.uptime >= Thermostat[ctr_output].time_ctr_checkpoint)) {
+ // Reset times
+ Thermostat[ctr_output].time_ctr_checkpoint = 0;
+ Thermostat[ctr_output].timestamp_rampup_start = TasmotaGlobal.uptime;
+ }
break;
#ifdef USE_PI_AUTOTUNING
// PI autotune
@@ -2084,7 +2092,7 @@ void ThermostatShow(uint8_t ctr_output, bool json)
* Interface
\*********************************************************************************************/
-bool Xdrv39(uint8_t function)
+bool Xdrv39(uint32_t function)
{
bool result = false;
uint8_t ctr_output;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_40_telegram.ino b/tasmota/tasmota_xdrv_driver/xdrv_40_telegram.ino
index 56d0d882d..a511cdf2d 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_40_telegram.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_40_telegram.ino
@@ -476,7 +476,7 @@ void CmndTmSend(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv40(uint8_t function)
+bool Xdrv40(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_41_tcp_bridge.ino b/tasmota/tasmota_xdrv_driver/xdrv_41_tcp_bridge.ino
index d0b3de1f9..b5c4a0789 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_41_tcp_bridge.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_41_tcp_bridge.ino
@@ -277,7 +277,7 @@ void CmndTCPConnect(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv41(uint8_t function)
+bool Xdrv41(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_42_0_i2s_audio.ino b/tasmota/tasmota_xdrv_driver/xdrv_42_0_i2s_audio.ino
index 26ad5412c..e6031ce31 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_42_0_i2s_audio.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_42_0_i2s_audio.ino
@@ -679,7 +679,7 @@ void i2s_mp3_loop(void);
void i2s_mp3_init(void);
void MP3ShowStream(void);
-bool Xdrv42(uint8_t function) {
+bool Xdrv42(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_43_mlx90640.ino b/tasmota/tasmota_xdrv_driver/xdrv_43_mlx90640.ino
index 833340c90..d13dd4416 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_43_mlx90640.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_43_mlx90640.ino
@@ -591,7 +591,7 @@ void MLX90640Show(uint8_t json)
* Interface
\*********************************************************************************************/
-bool Xdrv43(uint8_t function)
+bool Xdrv43(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_44_miel_hvac.ino b/tasmota/tasmota_xdrv_driver/xdrv_44_miel_hvac.ino
index e5f37fbc1..60ea83e5a 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_44_miel_hvac.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_44_miel_hvac.ino
@@ -1285,7 +1285,7 @@ static void (*const miel_hvac_cmnds[])(void) PROGMEM = {
#endif
};
-bool Xdrv44(uint8_t function) {
+bool Xdrv44(uint32_t function) {
bool result = false;
struct miel_hvac_softc *sc = miel_hvac_sc;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_45_shelly_dimmer.ino b/tasmota/tasmota_xdrv_driver/xdrv_45_shelly_dimmer.ino
index d1f317bfc..4b157ac6e 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_45_shelly_dimmer.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_45_shelly_dimmer.ino
@@ -268,8 +268,7 @@ bool ShdSerialSend(const uint8_t data[] = nullptr, uint16_t len = 0)
int retries = 3;
#ifdef SHELLY_DIMMER_DEBUG
- AddLog(LOG_LEVEL_DEBUG_MORE, PSTR(SHD_LOGNAME "Tx Packet:"));
- AddLogBuffer(LOG_LEVEL_DEBUG_MORE, (uint8_t*)data, len);
+ AddLog(LOG_LEVEL_DEBUG_MORE, PSTR(SHD_LOGNAME "Tx Packet %*_H"), len, (uint8_t*)data);
#endif // SHELLY_DIMMER_DEBUG
while (retries--)
@@ -694,8 +693,7 @@ bool ShdSerialInput(void)
// finished
#ifdef SHELLY_DIMMER_DEBUG
Shd.byte_counter++;
- AddLog(LOG_LEVEL_DEBUG_MORE, PSTR(SHD_LOGNAME "Rx Packet:"));
- AddLogBuffer(LOG_LEVEL_DEBUG_MORE, Shd.buffer, Shd.byte_counter);
+ AddLog(LOG_LEVEL_DEBUG_MORE, PSTR(SHD_LOGNAME "Rx Packet %*_H"), Shd.byte_counter, Shd.buffer);
#endif // SHELLY_DIMMER_DEBUG
Shd.byte_counter = 0;
@@ -707,9 +705,8 @@ bool ShdSerialInput(void)
{
// wrong data
#ifdef SHELLY_DIMMER_DEBUG
- AddLog(LOG_LEVEL_DEBUG, PSTR(SHD_LOGNAME "Byte %i of received data frame is invalid. Rx Packet:"), Shd.byte_counter);
- Shd.byte_counter++;
- AddLogBuffer(LOG_LEVEL_DEBUG_MORE, Shd.buffer, Shd.byte_counter);
+ AddLog(LOG_LEVEL_DEBUG, PSTR(SHD_LOGNAME "Byte %i of received data frame is invalid. Rx Packet %*_H"),
+ Shd.byte_counter, Shd.byte_counter +1, Shd.buffer);
#endif // SHELLY_DIMMER_DEBUG
Shd.byte_counter = 0;
}
@@ -739,8 +736,7 @@ bool ShdModuleSelected(void) {
bool ShdSetChannels(void)
{
#ifdef SHELLY_DIMMER_DEBUG
- AddLog(LOG_LEVEL_DEBUG_MORE, PSTR(SHD_LOGNAME "SetChannels:"));
- AddLogBuffer(LOG_LEVEL_DEBUG_MORE, (uint8_t *)XdrvMailbox.data, XdrvMailbox.data_len);
+ AddLog(LOG_LEVEL_DEBUG_MORE, PSTR(SHD_LOGNAME "SetChannels %*_H"), XdrvMailbox.data_len, (uint8_t *)XdrvMailbox.data);
#endif // SHELLY_DIMMER_DEBUG
uint16_t brightness = ((uint32_t *)XdrvMailbox.data)[0];
@@ -831,7 +827,7 @@ void CmndShdWarmupTime(void)
\*********************************************************************************************/
#ifdef USE_ENERGY_SENSOR
-bool Xnrg31(uint8_t function) {
+bool Xnrg31(uint32_t function) {
bool result = false;
if (Shd.present) {
@@ -852,7 +848,7 @@ bool Xnrg31(uint8_t function) {
* Driver Interface
\*********************************************************************************************/
-bool Xdrv45(uint8_t function) {
+bool Xdrv45(uint32_t function) {
bool result = false;
if (FUNC_MODULE_INIT == function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_46_ccloader.ino b/tasmota/tasmota_xdrv_driver/xdrv_46_ccloader.ino
index e8986df36..ab37d271a 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_46_ccloader.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_46_ccloader.ino
@@ -671,7 +671,7 @@ void CCLoadershow(bool json) {
* Interface
\*********************************************************************************************/
-bool Xdrv46(uint8_t function) {
+bool Xdrv46(uint32_t function) {
if (!TasmotaGlobal.gpio_optiona.enable_ccloader) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_47_ftc532.ino b/tasmota/tasmota_xdrv_driver/xdrv_47_ftc532.ino
index 2e1e26ac7..220ab6078 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_47_ftc532.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_47_ftc532.ino
@@ -215,7 +215,7 @@ void ftc532_publish(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv47(uint8_t function) {
+bool Xdrv47(uint32_t function) {
bool result = false;
if (FUNC_INIT == function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_48_timeprop.ino b/tasmota/tasmota_xdrv_driver/xdrv_48_timeprop.ino
index 934501079..ab11f6c52 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_48_timeprop.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_48_timeprop.ino
@@ -224,7 +224,7 @@ bool TimepropCommand()
#define XDRV_48 48
-bool Xdrv48(byte function) {
+bool Xdrv48(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_49_pid.ino b/tasmota/tasmota_xdrv_driver/xdrv_49_pid.ino
index 581016470..dcc226cd2 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_49_pid.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_49_pid.ino
@@ -420,7 +420,7 @@ void PIDRun(void) {
#define XDRV_49 49
-bool Xdrv49(byte function) {
+bool Xdrv49(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino b/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino
index ab66a5bec..db60d2e74 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino
@@ -1109,7 +1109,7 @@ void UfsEditorUpload(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv50(uint8_t function) {
+bool Xdrv50(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_51_bs814a2.ino b/tasmota/tasmota_xdrv_driver/xdrv_51_bs814a2.ino
index aa1abc4bb..5199b3919 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_51_bs814a2.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_51_bs814a2.ino
@@ -166,7 +166,7 @@ void bs814_publish(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv51(uint8_t function) {
+bool Xdrv51(uint32_t function) {
bool result = false;
if (FUNC_INIT == function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino
index f89ed23c6..2c89fb30a 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_crypto.ino
@@ -19,7 +19,6 @@
#ifdef USE_BERRY
-#ifdef USE_ALEXA_AVS
#include
#include "be_mem.h"
@@ -34,6 +33,7 @@ extern "C" {
// `AES_GCM.init(secret_key:bytes(32), iv:bytes(12)) -> instance`
int32_t m_aes_gcm_init(struct bvm *vm);
int32_t m_aes_gcm_init(struct bvm *vm) {
+#ifdef USE_BERRY_CRYPTO_AES_GCM
int32_t argc = be_top(vm); // Get the number of arguments
if (argc >= 3 && be_isinstance(vm, 2) && be_isinstance(vm, 3)) {
do {
@@ -77,11 +77,15 @@ extern "C" {
} while (0);
}
be_raise(vm, kTypeError, nullptr);
+#else // USE_BERRY_CRYPTO_AES_GCM
+ be_raise(vm, "Not implemented", nullptr);
+#endif // USE_BERRY_CRYPTO_AES_GCM
}
int32_t m_aes_gcm_encryt(bvm *vm);
int32_t m_aes_gcm_decryt(bvm *vm);
int32_t m_aes_gcm_encrypt_or_decryt(bvm *vm, int encrypt) {
+#ifdef USE_BERRY_CRYPTO_AES_GCM
int32_t argc = be_top(vm); // Get the number of arguments
if (argc >= 2 && be_isinstance(vm, 2)) {
do {
@@ -111,15 +115,27 @@ extern "C" {
} while (0);
}
be_raise(vm, kTypeError, nullptr);
+#else // USE_BERRY_CRYPTO_AES_GCM
+ be_raise(vm, "Not implemented", nullptr);
+#endif // USE_BERRY_CRYPTO_AES_GCM
}
int32_t m_aes_gcm_encryt(bvm *vm) {
+#ifdef USE_BERRY_CRYPTO_AES_GCM
return m_aes_gcm_encrypt_or_decryt(vm, 1);
+#else // USE_BERRY_CRYPTO_AES_GCM
+ be_raise(vm, "Not implemented", nullptr);
+#endif // USE_BERRY_CRYPTO_AES_GCM
}
int32_t m_aes_gcm_decryt(bvm *vm) {
+#ifdef USE_BERRY_CRYPTO_AES_GCM
return m_aes_gcm_encrypt_or_decryt(vm, 0);
+#else // USE_BERRY_CRYPTO_AES_GCM
+ be_raise(vm, "Not implemented", nullptr);
+#endif // USE_BERRY_CRYPTO_AES_GCM
}
int32_t m_aes_gcm_tag(bvm *vm) {
+#ifdef USE_BERRY_CRYPTO_AES_GCM
do {
be_getglobal(vm, "bytes"); /* get the bytes class */ /* TODO eventually replace with be_getbuiltin */
@@ -137,6 +153,9 @@ extern "C" {
// success
} while (0);
be_raise(vm, kTypeError, nullptr);
+#else // USE_BERRY_CRYPTO_AES_GCM
+ be_raise(vm, "Not implemented", nullptr);
+#endif // USE_BERRY_CRYPTO_AES_GCM
}
}
@@ -151,6 +170,7 @@ extern "C" {
// Computes the public key from a completely random private key of 32 bytes
int32_t m_ec_c25519_pubkey(bvm *vm);
int32_t m_ec_c25519_pubkey(bvm *vm) {
+#ifdef USE_BERRY_CRYPTO_EC_C25519
int32_t argc = be_top(vm); // Get the number of arguments
if (argc >= 2 && be_isbytes(vm, 2)) {
size_t buf_len = 0;
@@ -173,12 +193,16 @@ extern "C" {
be_raise(vm, "value_error", "invalid input");
}
be_raise(vm, kTypeError, nullptr);
+#else // USE_BERRY_CRYPTO_EC_C25519
+ be_raise(vm, "Not implemented", nullptr);
+#endif // USE_BERRY_CRYPTO_EC_C25519
}
// crypto.EC_C25519().shared_key(my_private_key:bytes(32), their_public_key:bytes(32)) -> bytes(32)
// Computes the shared pre-key. Normally this shared pre-key is hashed with another algorithm.
int32_t m_ec_c25519_sharedkey(bvm *vm);
int32_t m_ec_c25519_sharedkey(bvm *vm) {
+#ifdef USE_BERRY_CRYPTO_EC_C25519
int32_t argc = be_top(vm); // Get the number of arguments
if (argc >= 3 && be_isbytes(vm, 2) && be_isbytes(vm, 3)) {
size_t sk_len = 0;
@@ -204,8 +228,10 @@ extern "C" {
be_raise(vm, "value_error", "invalid input");
}
be_raise(vm, kTypeError, nullptr);
+#else // USE_BERRY_CRYPTO_EC_C25519
+ be_raise(vm, "Not implemented", nullptr);
+#endif // USE_BERRY_CRYPTO_EC_C25519
}
}
-#endif // USE_ALEXA_AVS
#endif // USE_BERRY
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_leds.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_leds.ino
index 54c6c2c15..3d6b8f86b 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_leds.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_leds.ino
@@ -151,19 +151,11 @@ extern "C" {
break;
case 6: // # 06 : Pixels void -> bytes() (mapped to the buffer)
{
- size_t pixels_bytes;
- if (s_ws2812_grb) pixels_bytes = s_ws2812_grb->PixelsSize();
- if (s_sk6812_grbw) pixels_bytes = s_sk6812_grbw->PixelsSize();
-
uint8_t * pixels;
if (s_ws2812_grb) pixels = s_ws2812_grb->Pixels();
if (s_sk6812_grbw) pixels = s_sk6812_grbw->Pixels();
- be_getbuiltin(vm, "bytes");
be_pushcomptr(vm, pixels);
- be_pushint(vm, pixels_bytes);
- be_call(vm, 2);
- be_pop(vm, 2);
}
break;
case 7: // # 07 : PixelSize void -> int
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino
index 31206442d..c42f6e003 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota.ino
@@ -214,16 +214,21 @@ extern "C" {
if (Settings->flag4.network_wifi) {
int32_t rssi = WiFi.RSSI();
bool show_rssi = false;
-#if LWIP_IPV6
+#ifdef USE_IPV6
String ipv6_addr = WifiGetIPv6();
if (ipv6_addr != "") {
be_map_insert_str(vm, "ip6", ipv6_addr.c_str());
show_rssi = true;
}
-#endif
+ ipv6_addr = WifiGetIPv6LinkLocal();
+ if (ipv6_addr != "") {
+ be_map_insert_str(vm, "ip6local", ipv6_addr.c_str());
+ show_rssi = true;
+ }
+#endif // USE_IPV6
if (static_cast(WiFi.localIP()) != 0) {
be_map_insert_str(vm, "mac", WiFi.macAddress().c_str());
- be_map_insert_str(vm, "ip", WiFi.localIP().toString().c_str());
+ be_map_insert_str(vm, "ip", IPAddress((uint32_t)WiFi.localIP()).toString().c_str()); // quick fix for IPAddress bug
show_rssi = true;
}
if (show_rssi) {
@@ -247,15 +252,33 @@ extern "C" {
#ifdef USE_ETHERNET
if (static_cast(EthernetLocalIP()) != 0) {
be_map_insert_str(vm, "mac", EthernetMacAddress().c_str());
- be_map_insert_str(vm, "ip", EthernetLocalIP().toString().c_str());
+ be_map_insert_str(vm, "ip", IPAddress((uint32_t)EthernetLocalIP()).toString().c_str()); // quick fix for IPAddress bug
}
-#endif
+#ifdef USE_IPV6
+ String ipv6_addr = EthernetGetIPv6();
+ if (ipv6_addr != "") {
+ be_map_insert_str(vm, "ip6", ipv6_addr.c_str());
+ }
+ ipv6_addr = EthernetGetIPv6LinkLocal();
+ if (ipv6_addr != "") {
+ be_map_insert_str(vm, "ip6local", ipv6_addr.c_str());
+ }
+#endif // USE_IPV6
+#endif // USE_ETHERNET
be_pop(vm, 1);
be_return(vm);
}
be_raise(vm, kTypeError, nullptr);
}
+ // Berry: tasmota.hostname() -> string
+ //
+ int32_t l_hostname(struct bvm *vm);
+ int32_t l_hostname(struct bvm *vm) {
+ be_pushstring(vm, NetworkHostname());
+ be_return(vm);
+ }
+
static void l_push_time(bvm *vm, struct tm *t, const char *unparsed) {
be_newobject(vm, "map");
be_map_insert_int(vm, "year", t->tm_year + 1900);
@@ -325,6 +348,19 @@ extern "C" {
be_raise(vm, kTypeError, nullptr);
}
+ // Berry: tasmota.delay_microseconds(timer:int) -> nil
+ //
+ int32_t l_delay_microseconds(struct bvm *vm);
+ int32_t l_delay_microseconds(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);
+ delayMicroseconds(timer);
+ be_return_nil(vm); // Return
+ }
+ be_raise(vm, kTypeError, nullptr);
+ }
+
// Berry: `yield() -> nil`
// ESP object
int32_t l_yield(bvm *vm);
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota_global.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota_global.ino
index 417bac186..854b3522c 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota_global.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_tasmota_global.ino
@@ -36,6 +36,7 @@ extern "C" {
4, /* number of elements */
nullptr,
(const be_ctypes_structure_item_t[4]) {
+ // Warning: fields below need to be in alphabetical order
{ "devices_present", offsetof(TasmotaGlobal_t, devices_present), 0, 0, ctypes_u8, 0 },
{ "fast_loop_enabled", offsetof(TasmotaGlobal_t, berry_fast_loop_enabled), 0, 0, ctypes_u8, 0 },
{ "restart_flag", offsetof(TasmotaGlobal_t, restart_flag), 0, 0, ctypes_u8, 0 },
@@ -47,10 +48,11 @@ extern "C" {
2, /* number of elements */
nullptr,
(const be_ctypes_structure_item_t[2]) {
+ // Warning: fields below need to be in alphabetical order
{ "bootcount", offsetof(TSettings, bootcount), 0, 0, ctypes_u16, 0 },
{ "sleep", offsetof(TSettings, sleep), 0, 0, ctypes_u8, 0 },
}};
}
-#endif // USE_BERRY
\ No newline at end of file
+#endif // USE_BERRY
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_ulp.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_ulp.ino
index 4dbc24b3c..9d154a8da 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_ulp.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_ulp.ino
@@ -1,5 +1,5 @@
/*
- xdrv_52_3_berry_ulp.ino - Berry scripting language, ULP support for ESP32
+ xdrv_52_3_berry_ulp.ino - Berry scripting language, ULP support for ESP32, ESP32S2, ESP32S3
Copyright (C) 2021 Stephan Hadinger & Christian Baars, Berry language by Guan Wenliang https://github.com/Skiars/berry
@@ -21,9 +21,21 @@
#ifdef USE_BERRY_ULP
#include
-#if defined(USE_BERRY_ULP) && defined(CONFIG_IDF_TARGET_ESP32)
+#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3)
+#if defined(CONFIG_IDF_TARGET_ESP32)
#include "esp32/ulp.h"
+#endif // esp32
+#if defined(CONFIG_IDF_TARGET_ESP32S2)
+#include "esp32s2/ulp.h"
+#include "esp32s2/ulp_riscv.h"
+#include "esp32s2/ulp_riscv_adc.h"
+#endif // s2
+#if defined(CONFIG_IDF_TARGET_ESP32S3)
+#include "esp32s3/ulp.h"
+#include "esp32s3/ulp_riscv.h"
+#include "esp32s3/ulp_riscv_adc.h"
+#endif //s3
#include "driver/rtc_io.h"
#include "driver/gpio.h"
#include "driver/adc.h"
@@ -36,7 +48,11 @@ extern "C" {
//
// `ULP.run() -> nil`
void be_ULP_run(int32_t entry) {
+#if defined(CONFIG_IDF_TARGET_ESP32)
ulp_run(entry); // entry point should be at the beginning of program
+#else // S2 or S3
+ ulp_riscv_run();
+#endif
}
// `ULP.wake_period(period_index:int, period_us:int) -> nil`
@@ -52,7 +68,11 @@ extern "C" {
// `ULP.get_mem(position:int) -> int`
int32_t be_ULP_get_mem(int32_t pos) {
- return RTC_SLOW_MEM[pos] & 0xFFFF; // only low 16 bits are used
+#if defined(CONFIG_IDF_TARGET_ESP32)
+ return RTC_SLOW_MEM[pos] & 0xFFFF; // only low 16 bits are used
+#else
+ return RTC_SLOW_MEM[pos]; // full 32bit for RISCV ULP
+#endif
}
// `ULP.gpio_init(pin:int, mode:int) -> rtc_pin:int`
@@ -70,25 +90,40 @@ extern "C" {
// `ULP.adc_config(channel:int, attenuation:int, width:int) -> nil`
//
// enums: channel 0-7, attenuation 0-3, width 0-3
- void be_ULP_adc_config(struct bvm *vm, adc1_channel_t channel, adc_atten_t attenuation, adc_bits_width_t width) {
- esp_err_t err = adc1_config_channel_atten(channel, attenuation);
- err += adc1_config_width(width);
+ void be_ULP_adc_config(struct bvm *vm, int32_t channel, int32_t attenuation, int32_t width) {
+#if defined(CONFIG_IDF_TARGET_ESP32)
+ esp_err_t err = adc1_config_channel_atten((adc1_channel_t)channel, (adc_atten_t)attenuation);
+ err += adc1_config_width((adc_bits_width_t)width);
if (err != ESP_OK) {
be_raisef(vm, "ulp_adc_config_error", "ULP: invalid code err=%i", err);
} else {
adc1_ulp_enable();
}
+#else // S2 or S3
+ ulp_riscv_adc_cfg_t cfg = {
+ .channel = (adc_channel_t)channel,
+ .atten = (adc_atten_t)attenuation,
+ .width = (adc_bits_width_t)width
+ };
+ esp_err_t err = ulp_riscv_adc_init(&cfg);
+ if (err != ESP_OK) {
+ be_raisef(vm, "ulp_adc_config_error", "ULP: invalid code err=%i", err);
+ }
+#endif
}
/**
* @brief Load a Berry byte buffer containing a ULP program as raw byte data
*
* @param vm as `ULP.load(code:bytes) -> nil`
- * @return void
+ * @return void for ESP32 or binary type as int32_t on RISCV capable SOC's
*/
void be_ULP_load(struct bvm *vm, const uint8_t *buf, size_t size) {
- // AddLog(LOG_LEVEL_INFO, "ULP: load addr=%p size=%i %*_H", buf, size/4, size, buf);
- esp_err_t err = ulp_load_binary(0, buf, size / 4);
+#if defined(CONFIG_IDF_TARGET_ESP32)
+ esp_err_t err = ulp_load_binary(0, buf, size / 4); // FSM type only, specific header, size in long words
+#else // S2 or S3
+ esp_err_t err = ulp_riscv_load_binary(buf, size); // there are no header bytes, just load and hope for a valid binary - size in bytes
+#endif // defined(CONFIG_IDF_TARGET_ESP32)
if (err != ESP_OK) {
be_raisef(vm, "ulp_load_error", "ULP: invalid code err=%i", err);
}
@@ -109,10 +144,9 @@ extern "C" {
esp_deep_sleep_start();
}
-
} //extern "C"
-#endif //CONFIG_IDF_TARGET_ESP32
+#endif //CONFIG_IDF_TARGET_ESP32 .. S2 .. S3
#endif // USE_BERRY_ULP
-#endif // USE_BERRY
\ No newline at end of file
+#endif // USE_BERRY
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webclient.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webclient.ino
index 1b9773bb5..09a0d0b91 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webclient.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_webclient.ino
@@ -76,9 +76,9 @@ String wc_UrlEncode(const String& text) {
/*********************************************************************************************\
* Native functions mapped to Berry functions
- *
+ *
* import webclient
- *
+ *
\*********************************************************************************************/
extern "C" {
// Berry: ``
@@ -428,6 +428,75 @@ extern "C" {
be_raise(vm, kTypeError, nullptr);
}
+ // wc.PUT(string | bytes) -> httpCode:int
+ int32_t wc_PUT(struct bvm *vm);
+ int32_t wc_PUT(struct bvm *vm) {
+ int32_t argc = be_top(vm);
+ if (argc >= 2 && (be_isstring(vm, 2) || be_isbytes(vm, 2))) {
+ HTTPClientLight * cl = wc_getclient(vm);
+ const char * buf = nullptr;
+ size_t buf_len = 0;
+ if (be_isstring(vm, 2)) { // string
+ buf = be_tostring(vm, 2);
+ buf_len = strlen(buf);
+ } else { // bytes
+ buf = (const char*) be_tobytes(vm, 2, &buf_len);
+ }
+ uint32_t http_connect_time = millis();
+ int32_t httpCode = cl->PUT((uint8_t*)buf, buf_len);
+ wc_errorCodeMessage(httpCode, http_connect_time);
+ be_pushint(vm, httpCode);
+ be_return(vm); /* return code */
+ }
+ be_raise(vm, kTypeError, nullptr);
+ }
+
+ // wc.PATCH(string | bytes) -> httpCode:int
+ int32_t wc_PATCH(struct bvm *vm);
+ int32_t wc_PATCH(struct bvm *vm) {
+ int32_t argc = be_top(vm);
+ if (argc >= 2 && (be_isstring(vm, 2) || be_isbytes(vm, 2))) {
+ HTTPClientLight * cl = wc_getclient(vm);
+ const char * buf = nullptr;
+ size_t buf_len = 0;
+ if (be_isstring(vm, 2)) { // string
+ buf = be_tostring(vm, 2);
+ buf_len = strlen(buf);
+ } else { // bytes
+ buf = (const char*) be_tobytes(vm, 2, &buf_len);
+ }
+ uint32_t http_connect_time = millis();
+ int32_t httpCode = cl->PATCH((uint8_t*)buf, buf_len);
+ wc_errorCodeMessage(httpCode, http_connect_time);
+ be_pushint(vm, httpCode);
+ be_return(vm); /* return code */
+ }
+ be_raise(vm, kTypeError, nullptr);
+ }
+
+ // wc.DELETE(string | bytes) -> httpCode:int
+ int32_t wc_DELETE(struct bvm *vm);
+ int32_t wc_DELETE(struct bvm *vm) {
+ int32_t argc = be_top(vm);
+ if (argc >= 2 && (be_isstring(vm, 2) || be_isbytes(vm, 2))) {
+ HTTPClientLight * cl = wc_getclient(vm);
+ const char * buf = nullptr;
+ size_t buf_len = 0;
+ if (be_isstring(vm, 2)) { // string
+ buf = be_tostring(vm, 2);
+ buf_len = strlen(buf);
+ } else { // bytes
+ buf = (const char*) be_tobytes(vm, 2, &buf_len);
+ }
+ uint32_t http_connect_time = millis();
+ int32_t httpCode = cl->DELETE((uint8_t*)buf, buf_len);
+ wc_errorCodeMessage(httpCode, http_connect_time);
+ be_pushint(vm, httpCode);
+ be_return(vm); /* return code */
+ }
+ be_raise(vm, kTypeError, nullptr);
+ }
+
int32_t wc_getstring(struct bvm *vm);
int32_t wc_getstring(struct bvm *vm) {
HTTPClientLight * cl = wc_getclient(vm);
@@ -547,7 +616,7 @@ extern "C" {
be_raisef(vm, "internal_error", "failed, written %i bytes vs %i", written, size);
}
AddLog(LOG_LEVEL_DEBUG, D_LOG_UPLOAD "flash writing succesful");
-
+
be_pushint(vm, written);
be_return(vm); /* return code */
}
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_9_berry.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_9_berry.ino
index 36ac8b4e0..7bb20821c 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_52_9_berry.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_52_9_berry.ino
@@ -231,6 +231,7 @@ void BerryObservability(bvm *vm, int event...) {
slots_used_before_gc, slots_allocated_before_gc,
slots_used_after_gc, slots_allocated_after_gc);
+#ifdef UBE_BERRY_DEBUG_GC
// Add more in-deptch metrics
AddLog(LOG_LEVEL_DEBUG_MORE, D_LOG_BERRY "GC timing (us) 1:%i 2:%i 3:%i 4:%i 5:%i total:%i",
vm->micros_gc1 - vm->micros_gc0,
@@ -254,6 +255,7 @@ void BerryObservability(bvm *vm, int event...) {
vm->gc_mark_module,
vm->gc_mark_comobj
);
+#endif
// make new threshold tighter when we reach high memory usage
if (!UsePSRAM() && vm->gc.threshold > 20*1024) {
vm->gc.threshold = vm->gc.usage + 10*1024; // increase by only 10 KB
@@ -713,7 +715,7 @@ void HandleBerryConsole(void)
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
-bool Xdrv52(uint8_t function)
+bool Xdrv52(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_53_projector_ctrl.ino b/tasmota/tasmota_xdrv_driver/xdrv_53_projector_ctrl.ino
index be0af2e5a..dc31523df 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_53_projector_ctrl.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_53_projector_ctrl.ino
@@ -439,7 +439,7 @@ projector_ctrl_set_power(struct projector_ctrl_softc_s *sc)
* Interface
\*********************************************************************************************/
-bool Xdrv53(uint8_t function) {
+bool Xdrv53(uint32_t function) {
bool result;
struct projector_ctrl_softc_s *sc;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_54_lvgl.ino b/tasmota/tasmota_xdrv_driver/xdrv_54_lvgl.ino
index 3c6ad507a..26fa7bbcb 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_54_lvgl.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_54_lvgl.ino
@@ -433,7 +433,7 @@ void start_lvgl(const char * uconfig) {
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
-bool Xdrv54(uint8_t function)
+bool Xdrv54(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_55_touch.ino b/tasmota/tasmota_xdrv_driver/xdrv_55_touch.ino
index 7ce4b1fed..3a23b965e 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_55_touch.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_55_touch.ino
@@ -459,7 +459,7 @@ void TS_RotConvert(int16_t *x, int16_t *y) {
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
-bool Xdrv55(uint8_t function) {
+bool Xdrv55(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino b/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino
index 0de267656..01de30b39 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_56_rtc_chips.ino
@@ -432,7 +432,7 @@ void CmndRtcNtpServer(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv56(uint8_t function) {
+bool Xdrv56(uint32_t function) {
bool result = false;
#ifdef RTC_NTP_SERVER
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_57_1_tasmesh_support.ino b/tasmota/tasmota_xdrv_driver/xdrv_57_1_tasmesh_support.ino
index 5c3718adc..c2d70c61d 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_57_1_tasmesh_support.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_57_1_tasmesh_support.ino
@@ -218,7 +218,7 @@ void MESHsendPeerList(void) { // We send this list only to the peers, that
MESH.sendPacket.chunks = 1;
MESH.sendPacket.chunkSize = _idx;
MESH.sendPacket.TTL = 1;
-// AddLogBuffer(LOG_LEVEL_INFO, MESH.sendPacket.payload, MESH.sendPacket.chunkSize);
+// AddLog(LOG_LEVEL_INFO, PSTR("MSH: %*_H"), MESH.sendPacket.chunkSize, MESH.sendPacket.payload);
MESHsendPacket(&MESH.sendPacket);
}
@@ -342,8 +342,7 @@ bool MESHencryptPayload(mesh_packet_t *_packet, int _encrypt) {
size_t _size = _packet->chunkSize;
char _tag[16];
-// AddLog(LOG_LEVEL_DEBUG, PSTR("cc: %u, _size: %u"), _counter,_size);
-// AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t*)_tag,16);
+// AddLog(LOG_LEVEL_DEBUG, PSTR("MSH: cc %u, _size %u, _tag %16_H"), _counter,_size,(uint8_t*)_tag);
br_chacha20_run bc = br_chacha20_ct_run;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_57_9_tasmesh.ino b/tasmota/tasmota_xdrv_driver/xdrv_57_9_tasmesh.ino
index d309b4d59..bfd52766d 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_57_9_tasmesh.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_57_9_tasmesh.ino
@@ -65,8 +65,7 @@ void CB_MESHDataReceived(const uint8_t *MAC, const uint8_t *packet, int len) {
MESHencryptPayload(_recvPacket, 0); //decrypt it and check
if (memcmp(_recvPacket->payload, MESH.broker, 6) == 0) {
MESHaddPeer((uint8_t*)MAC);
-// AddLog(LOG_LEVEL_INFO, PSTR("MSH: Rcvd topic %s"), (char*)_recvPacket->payload + 6);
-// AddLogBuffer(LOG_LEVEL_INFO,(uint8_t *)&MESH.packetToConsume.front().payload,MESH.packetToConsume.front().chunkSize+5);
+// AddLog(LOG_LEVEL_INFO, PSTR("MSH: Rcvd topic %s, payload %*_H"), (char*)_recvPacket->payload + 6, MESH.packetToConsume.front().chunkSize+5, (uint8_t *)&MESH.packetToConsume.front().payload);
for (auto &_peer : MESH.peers) {
if (memcmp(_peer.MAC, _recvPacket->sender, 6) == 0) {
strcpy(_peer.topic, (char*)_recvPacket->payload + 6);
@@ -340,8 +339,7 @@ bool MESHrouteMQTTtoMESH(const char* _topic, char* _data, bool _retained) {
}
MESH.sendPacket.chunkSize += _byteLeftInChunk;
MESH.packetToResend.push(MESH.sendPacket);
-// AddLog(LOG_LEVEL_INFO, PSTR("MSH: chunk:%u, size: %u"),MESH.sendPacket.chunk,MESH.sendPacket.chunkSize);
-// AddLogBuffer(LOG_LEVEL_INFO, (uint8_t*)MESH.sendPacket.payload, MESH.sendPacket.chunkSize);
+// AddLog(LOG_LEVEL_INFO, PSTR("MSH: chunk %u, size %u, payload %*_H"),MESH.sendPacket.chunk,MESH.sendPacket.chunkSize,MESH.sendPacket.chunkSize,(uint8_t*)MESH.sendPacket.payload);
if (MESH.sendPacket.chunk == MESH.sendPacket.chunks) {
// AddLog(LOG_LEVEL_INFO, PSTR("MSH: Too many chunks %u"), MESH.sendPacket.chunk +1);
}
@@ -454,11 +452,9 @@ void MESHevery50MSecond(void) {
// // pass the packets
// }
if (MESH.packetToConsume.size() > 0) {
-// AddLog(LOG_LEVEL_DEBUG, PSTR("_"));
-// AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t *)&MESH.packetToConsume.front(), 15);
+// AddLog(LOG_LEVEL_DEBUG, PSTR("MSH: _ %15_H"), (uint8_t *)&MESH.packetToConsume.front());
for (auto &_headerBytes : MESH.packetsAlreadyReceived) {
-// AddLog(LOG_LEVEL_DEBUG, PSTR("."));
-// AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t *)_headerBytes.raw, 15);
+// AddLog(LOG_LEVEL_DEBUG, PSTR("MSH: . %15_H"), (uint8_t *)_headerBytes.raw);
if (memcmp(MESH.packetToConsume.front().sender, _headerBytes.raw, 15) == 0) {
MESH.packetToConsume.pop();
return;
@@ -467,21 +463,20 @@ void MESHevery50MSecond(void) {
mesh_first_header_bytes _bytes;
memcpy(_bytes.raw, &MESH.packetToConsume.front(), 15);
MESH.packetsAlreadyReceived.push_back(_bytes);
-// AddLog(LOG_LEVEL_DEBUG, PSTR("..."));
-// AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t *)_bytes.raw, 15);
+// AddLog(LOG_LEVEL_DEBUG, PSTR("MSH: ... %15_H"), (uint8_t *)_bytes.raw);
if (MESH.packetsAlreadyReceived.size() > MESH_MAX_PACKETS) {
MESH.packetsAlreadyReceived.erase(MESH.packetsAlreadyReceived.begin());
// AddLog(LOG_LEVEL_DEBUG, PSTR("MSH: Erase received data"));
}
// do something on the node
- // AddLogBuffer(LOG_LEVEL_DEBUG,(uint8_t *)&MESH.packetToConsume.front(), 30);
+ // AddLog(LOG_LEVEL_DEBUG, PSTR("MSH: %30_H), (uint8_t *)&MESH.packetToConsume.front());
MESHencryptPayload(&MESH.packetToConsume.front(), 0);
switch (MESH.packetToConsume.front().type) {
// case PACKET_TYPE_REGISTER_NODE:
// AddLog(LOG_LEVEL_INFO, PSTR("MSH: received topic: %s"), (char*)MESH.packetToConsume.front().payload + 6);
- // // AddLogBuffer(LOG_LEVEL_INFO,(uint8_t *)&MESH.packetToConsume.front().payload,MESH.packetToConsume.front().chunkSize+5);
+ // // AddLog(LOG_LEVEL_INFO, PSTR("MSH: %*_H), MESH.packetToConsume.front().chunkSize+5, (uint8_t *)&MESH.packetToConsume.front().payload);
// for(auto &_peer : MESH.peers){
// if(memcmp(_peer.MAC,MESH.packetToConsume.front().sender,6)==0){
// strcpy(_peer.topic,(char*)MESH.packetToConsume.front().payload+6);
@@ -534,7 +529,7 @@ void MESHevery50MSecond(void) {
}
} else {
// AddLog(LOG_LEVEL_INFO, PSTR("MSH: chunk: %u size: %u"), MESH.packetToConsume.front().chunk, MESH.packetToConsume.front().chunkSize);
-// if (MESH.packetToConsume.front().chunk==0) AddLogBuffer(LOG_LEVEL_INFO,(uint8_t *)&MESH.packetToConsume.front().payload,MESH.packetToConsume.front().chunkSize);
+// if (MESH.packetToConsume.front().chunk==0) AddLog(LOG_LEVEL_INFO, PSTR("MSH: %*_H), MESH.packetToConsume.front().chunkSize, (uint8_t *)&MESH.packetToConsume.front().payload);
char * _data = (char*)MESH.packetToConsume.front().payload + strlen((char*)MESH.packetToConsume.front().payload) +1;
// AddLog(LOG_LEVEL_DEBUG, PSTR("MSH: Publish packet"));
MqttPublishPayload((char*)MESH.packetToConsume.front().payload, _data);
@@ -548,7 +543,7 @@ void MESHevery50MSecond(void) {
}
idx++;
}
-// AddLogBuffer(LOG_LEVEL_INFO,(uint8_t *)&MESH.packetToConsume.front().payload,MESH.packetToConsume.front().chunkSize);
+// AddLog(LOG_LEVEL_INFO, PSTR("MSH: %*_H), MESH.packetToConsume.front().chunkSize, (uint8_t *)&MESH.packetToConsume.front().payload);
}
break;
default:
@@ -814,7 +809,7 @@ void CmndMeshInterval(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv57(uint8_t function) {
+bool Xdrv57(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_58_range_extender.ino b/tasmota/tasmota_xdrv_driver/xdrv_58_range_extender.ino
index 7fb999063..3868dde46 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_58_range_extender.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_58_range_extender.ino
@@ -35,10 +35,13 @@ CONFIG_LWIP_IP_FORWARD option set, and optionally CONFIG_LWIP_IPV4_NAPT.
If you want to support NAPT (removing the need for routes on a core router):
#define USE_WIFI_RANGE_EXTENDER_NAPT
+List AP clients (MAC, IP and RSSI) with command RgxClients on ESP32
+
An example full static configuration:
#define USE_WIFI_RANGE_EXTENDER
#define USE_WIFI_RANGE_EXTENDER_NAPT
+#define USE_WIFI_RANGE_EXTENDER_CLIENTS
#define WIFI_RGX_STATE 1
#define WIFI_RGX_NAPT 1
#define WIFI_RGX_SSID "rangeextender"
@@ -91,7 +94,11 @@ const char kDrvRgxCommands[] PROGMEM = "Rgx|" // Prefix
#ifdef USE_WIFI_RANGE_EXTENDER_NAPT
"|"
"NAPT"
+ "|"
+ "Port"
#endif // USE_WIFI_RANGE_EXTENDER_NAPT
+ "|"
+ "Clients"
"|"
"Address"
"|"
@@ -103,7 +110,9 @@ void (*const DrvRgxCommand[])(void) PROGMEM = {
&CmndRgxPassword,
#ifdef USE_WIFI_RANGE_EXTENDER_NAPT
&CmndRgxNAPT,
+ &CmndRgxPort,
#endif // USE_WIFI_RANGE_EXTENDER_NAPT
+ &CmndRgxClients,
&CmndRgxAddresses,
&CmndRgxAddresses,
};
@@ -114,7 +123,6 @@ void (*const DrvRgxCommand[])(void) PROGMEM = {
#endif // ESP8266
#endif // USE_WIFI_RANGE_EXTENDER_NAPT
-#include
#include
#ifdef ESP8266
#include
@@ -122,6 +130,7 @@ void (*const DrvRgxCommand[])(void) PROGMEM = {
#ifdef ESP32
#include "lwip/lwip_napt.h"
#include
+#include "esp_wifi.h"
#endif // ESP32
#define RGX_NOT_CONFIGURED 0
@@ -133,7 +142,6 @@ void (*const DrvRgxCommand[])(void) PROGMEM = {
typedef struct
{
uint8_t status = RGX_NOT_CONFIGURED;
- uint16_t lastlinkcount = 0;
#ifdef USE_WIFI_RANGE_EXTENDER_NAPT
bool napt_enabled = false;
#endif // USE_WIFI_RANGE_EXTENDER_NAPT
@@ -141,6 +149,12 @@ typedef struct
TRgxSettings RgxSettings;
+// externalize to be able to protect Rgx AP from teardown
+bool RgxApUp()
+{
+ return RgxSettings.status == RGX_CONFIGURED || RgxSettings.status == RGX_SETUP_NAPT;
+}
+
// Check the current configuration is complete, updating RgxSettings.status
void RgxCheckConfig(void)
{
@@ -161,6 +175,41 @@ void RgxCheckConfig(void)
}
}
+void CmndRgxClients(void)
+{
+ Response_P(PSTR("{\"RgxClients\":{"));
+ const char *sep = "";
+
+#if defined(ESP32)
+ wifi_sta_list_t wifi_sta_list = {0};
+ tcpip_adapter_sta_list_t adapter_sta_list = {0};
+
+ esp_wifi_ap_get_sta_list(&wifi_sta_list);
+ tcpip_adapter_get_sta_list(&wifi_sta_list, &adapter_sta_list);
+
+ for (int i=0; ibssid;
+ ResponseAppend_P(PSTR("%s\"%02X%02X%02X%02X%02X%02X\":{\"" D_CMND_IPADDRESS "\":\"%_I\"}"),
+ sep, m[0], m[1], m[2], m[3], m[4], m[5], station->ip.addr);
+ sep = ",";
+ station = STAILQ_NEXT(station, next);
+ }
+ wifi_softap_free_station_info();
+#endif
+
+ ResponseAppend_P(PSTR("}}"));
+}
+
void CmndRgxState(void)
{
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1))
@@ -238,7 +287,91 @@ void CmndRgxNAPT(void)
}
}
ResponseCmndStateText(Settings->sbflag1.range_extender_napt);
-};
+}
+
+// CmndRgxPort helper: Do port map and set response if successful
+void CmndRgxPortMap(uint8_t proto, uint16_t gw_port, uint32_t dst_ip, uint16_t dst_port)
+{
+ uint32_t gw_ip = (uint32_t)WiFi.localIP();
+ if (ip_portmap_add(proto, gw_ip, gw_port, dst_ip, dst_port))
+ {
+ Response_P(PSTR("OK %s %_I:%u -> %_I:%u"),
+ (proto == IP_PROTO_TCP) ? "TCP" : "UDP", gw_ip, gw_port, dst_ip, dst_port);
+ }
+}
+
+// CmndRgxPort helper: If mac from esp list and mac from command parameters are the same try port map and return true
+bool CmndRgxPortMapCheck(const uint8_t *mac, const char *parm_mac, uint8_t proto, uint16_t gw_port, uint32_t dst_ip, uint16_t dst_port)
+{
+ char list_mac[13];
+ snprintf(list_mac, sizeof(list_mac), PSTR("%02X%02X%02X%02X%02X%02X"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ if (strcasecmp(list_mac, parm_mac) == 0)
+ {
+ CmndRgxPortMap(proto, gw_port, dst_ip, dst_port);
+ return true;
+ }
+ return false;
+}
+
+void CmndRgxPort(void)
+{
+ char *tok, *state, *parm_addr;
+ uint16_t gw, dst;
+ uint8_t proto = 0;
+
+ Response_P(PSTR("ERROR"));
+
+ // Parameter parsing
+ if (ArgC()!=4) return;
+ if ((tok = strtok_r(XdrvMailbox.data, ", ", &state)) == 0) return;
+ if (strcasecmp("TCP", tok) == 0) proto = IP_PROTO_TCP;
+ if (strcasecmp("UDP", tok) == 0) proto = IP_PROTO_UDP;
+ if (!proto) return;
+ if ((tok = strtok_r(0, ", ", &state)) == 0) return;
+ if ((gw = strtoul(tok, nullptr, 0)) == 0) return;
+ if ((parm_addr = strtok_r(0, ", ", &state)) == 0) return;
+ if ((tok = strtok_r(0, ", ", &state)) == 0) return;
+ if ((dst = strtoul(tok, nullptr, 0)) == 0) return;
+
+ // If forward address is an ip, then just do it...
+ // Useful for static IPs not used by the range extender dhcp server
+ // On ESP8266 the default dhcp ip range to avoid is .100-.200
+ // On ESP32 the default dhcp ip range to avoid is .2-.11
+ IPAddress ip;
+ if (ip.fromString(parm_addr))
+ {
+ CmndRgxPortMap(proto, gw, (uint32_t)ip, dst);
+ return;
+ }
+
+ // Forward address is a mac, find the associated ip...
+#if defined(ESP32)
+ wifi_sta_list_t wifi_sta_list = {0};
+ tcpip_adapter_sta_list_t adapter_sta_list = {0};
+
+ esp_wifi_ap_get_sta_list(&wifi_sta_list);
+ tcpip_adapter_get_sta_list(&wifi_sta_list, &adapter_sta_list);
+
+ for (int i=0; ibssid, parm_addr, proto, gw, station->ip.addr, dst))
+ {
+ break;
+ }
+ station = STAILQ_NEXT(station, next);
+ }
+ wifi_softap_free_station_info();
+#endif // ESP8266
+}
#endif // USE_WIFI_RANGE_EXTENDER_NAPT
void ResponseRgxConfig(void)
@@ -281,7 +414,6 @@ void rngxSetup()
WiFi.softAP(SettingsText(SET_RGX_SSID), SettingsText(SET_RGX_PASSWORD));
AddLog(LOG_LEVEL_INFO, PSTR("RGX: WiFi Extender AP Enabled with SSID: %s"), WiFi.softAPSSID().c_str());
RgxSettings.status = RGX_SETUP_NAPT;
- RgxSettings.lastlinkcount = Wifi.link_count;
}
void rngxSetupNAPT(void)
@@ -344,7 +476,7 @@ void rngxSetupNAPT(void)
* Interface
\*********************************************************************************************/
-bool Xdrv58(uint8_t function)
+bool Xdrv58(uint32_t function)
{
bool result = false;
@@ -384,17 +516,11 @@ bool Xdrv58(uint8_t function)
}
else if (RgxSettings.status == RGX_CONFIGURED)
{
- if (Wifi.status != WL_CONNECTED)
+ if (Wifi.status == WL_CONNECTED && WiFi.getMode() != WIFI_AP_STA)
{
- // No longer connected, need to setup again
- AddLog(LOG_LEVEL_INFO, PSTR("RGX: No longer connected, prepare to reconnect WiFi AP..."));
- RgxSettings.status = RGX_NOT_CONFIGURED;
- }
- else if (RgxSettings.lastlinkcount != Wifi.link_count && WiFi.getMode() != WIFI_AP_STA)
- {
- // Assume WiFi has reconnected and been reconfigured, prepare to reconnect
- AddLog(LOG_LEVEL_INFO, PSTR("RGX: Link count now: %d, WiFi.getMode(): %d, unconfigure..."), Wifi.link_count, WiFi.getMode());
- RgxSettings.status = RGX_NOT_CONFIGURED;
+ // Should not happen... our AP is gone and only a restart will get it back properly
+ AddLog(LOG_LEVEL_INFO, PSTR("RGX: WiFi mode is %d not %d. Restart..."), WiFi.getMode(), WIFI_AP_STA);
+ TasmotaGlobal.restart_flag = 2;
}
}
break;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_59_influxdb.ino b/tasmota/tasmota_xdrv_driver/xdrv_59_influxdb.ino
index d98011399..ea95998ea 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_59_influxdb.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_59_influxdb.ino
@@ -561,7 +561,7 @@ void CmndInfluxDbPeriod(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv59(uint8_t function) {
+bool Xdrv59(uint32_t function) {
bool result = false;
if (FUNC_PRE_INIT == function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_60_shift595.ino b/tasmota/tasmota_xdrv_driver/xdrv_60_shift595.ino
index 4e816fc7e..d18410afb 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_60_shift595.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_60_shift595.ino
@@ -98,7 +98,7 @@ void CmndShift595Devices(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv60(uint8_t function) {
+bool Xdrv60(uint32_t function) {
bool result = false;
if (FUNC_PRE_INIT == function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_61_ds3502.ino b/tasmota/tasmota_xdrv_driver/xdrv_61_ds3502.ino
index a8d05f6b4..0b158bdef 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_61_ds3502.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_61_ds3502.ino
@@ -73,7 +73,7 @@ void CmndWiper(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv61(uint8_t function) {
+bool Xdrv61(uint32_t function) {
if (!I2cEnabled(XI2C_67)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_62_improv.ino b/tasmota/tasmota_xdrv_driver/xdrv_62_improv.ino
index 6dc0abb68..4b3a15154 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_62_improv.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_62_improv.ino
@@ -340,7 +340,7 @@ void ImprovInit(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv62(uint8_t function) {
+bool Xdrv62(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_63_modbus_bridge.ino b/tasmota/tasmota_xdrv_driver/xdrv_63_modbus_bridge.ino
index 479ea560b..6c3c33d4e 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_63_modbus_bridge.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_63_modbus_bridge.ino
@@ -35,10 +35,10 @@
*
* -- Write multiple coils --
* ModbusSend {"deviceaddress": 1, "functioncode": 15, "startaddress": 1, "type":"bit", "count":4, "values":[1,0,1,1]}
- *
- * Info for modbusBridgeTCPServer:
+ *
+ * Info for modbusBridgeTCPServer:
* https://ipc2u.com/articles/knowledge-base/detailed-description-of-the-modbus-tcp-protocol-with-command-examples/
- *
+ *
* Info for modbus serial communications:
* https://ozeki.hu/p_5879-mobdbus-function-code-4-read-input-registers.html
* https://www.modbustools.com/modbus.html
@@ -102,7 +102,7 @@ ModbusBridgeTCP modbusBridgeTCP;
#endif
#include
-TasmotaModbus *tasmotaModbus = nullptr;
+TasmotaModbus *modbusBridgeModbus = nullptr;
enum class ModbusBridgeError
{
@@ -172,22 +172,18 @@ ModbusBridge modbusBridge;
/********************************************************************************************/
//
-// Helper functions for data conversion between little and big endian
+// Helper functions
//
-uint16_t swap_endian16(uint16_t num)
+uint16_t ModbusBridgeSwapEndian16(uint16_t num)
{
return (num>>8) | (num<<8);
}
-uint32_t swap_endian32(uint32_t num)
+void ModbusBridgeAllocError(const char* s)
{
- return ((num>>24)&0xff) | // move byte 3 to byte 0
- ((num<<8)&0xff0000) | // move byte 1 to byte 2
- ((num>>8)&0xff00) | // move byte 2 to byte 1
- ((num<<24)&0xff000000); // byte 0 to byte 3
+ AddLog(LOG_LEVEL_ERROR, PSTR("MBS: could not allocate %s buffer"), s);
}
-
/********************************************************************************************/
//
// Applies serial configuration to modbus serial port
@@ -199,7 +195,7 @@ bool ModbusBridgeBegin(void)
if (Settings->modbus_sconfig > TS_SERIAL_8O2)
Settings->modbus_sconfig = TS_SERIAL_8N1;
- int result = tasmotaModbus->Begin(Settings->modbus_sbaudrate * 300, ConvertSerialConfig(Settings->modbus_sconfig)); // Reinitialize modbus port with new baud rate
+ int result = modbusBridgeModbus->Begin(Settings->modbus_sbaudrate * 300, ConvertSerialConfig(Settings->modbus_sconfig)); // Reinitialize modbus port with new baud rate
if (result)
{
if (2 == result)
@@ -211,7 +207,7 @@ bool ModbusBridgeBegin(void)
return result;
}
-void SetModbusBridgeConfig(uint32_t serial_config)
+void ModbusBridgeSetConfig(uint32_t serial_config)
{
if (serial_config > TS_SERIAL_8O2)
{
@@ -224,7 +220,7 @@ void SetModbusBridgeConfig(uint32_t serial_config)
}
}
-void SetModbusBridgeBaudrate(uint32_t baudrate)
+void ModbusBridgeSetBaudrate(uint32_t baudrate)
{
if ((baudrate >= 300) && (baudrate <= 115200))
{
@@ -242,14 +238,19 @@ void SetModbusBridgeBaudrate(uint32_t baudrate)
//
void ModbusBridgeHandle(void)
{
- bool data_ready = tasmotaModbus->ReceiveReady();
+ bool data_ready = modbusBridgeModbus->ReceiveReady();
if (data_ready)
{
uint8_t *buffer;
if (modbusBridge.byteCount == 0) modbusBridge.byteCount = modbusBridge.dataCount * 2;
buffer = (uint8_t *)malloc(9 + modbusBridge.byteCount); // Addres(1), Function(1), Length(1), Data(1..n), CRC(2)
+ if (nullptr == buffer)
+ {
+ ModbusBridgeAllocError(PSTR("read"));
+ return;
+ }
memset(buffer, 0, 9 + modbusBridge.byteCount);
- uint32_t error = tasmotaModbus->ReceiveBuffer(buffer, 0, modbusBridge.byteCount);
+ uint32_t error = modbusBridgeModbus->ReceiveBuffer(buffer, 0, modbusBridge.byteCount);
#ifdef USE_MODBUS_BRIDGE_TCP
for (uint32_t i = 0; i < nitems(modbusBridgeTCP.client_tcp); i++)
@@ -257,7 +258,7 @@ void ModbusBridgeHandle(void)
WiFiClient &client = modbusBridgeTCP.client_tcp[i];
if (client)
{
- uint8_t header[8];
+ uint8_t header[9];
uint8_t nrOfBytes = 8;
header[0] = modbusBridgeTCP.tcp_transaction_id >> 8;
header[1] = modbusBridgeTCP.tcp_transaction_id;
@@ -274,7 +275,7 @@ void ModbusBridgeHandle(void)
nrOfBytes += 1;
client.write(header, 9);
}
- else if (buffer[1] <= 2)
+ else if (buffer[1] <= 2)
{
header[4] = modbusBridge.byteCount >> 8;
header[5] = modbusBridge.byteCount + 3;
@@ -284,7 +285,7 @@ void ModbusBridgeHandle(void)
client.write(buffer + 3, modbusBridge.byteCount); // Don't send CRC
nrOfBytes += modbusBridge.byteCount;
}
- else if (buffer[1] <= 4)
+ else if (buffer[1] <= 4)
{
header[4] = modbusBridge.byteCount >> 8;
header[5] = modbusBridge.byteCount + 3;
@@ -358,10 +359,10 @@ void ModbusBridgeHandle(void)
if (modbusBridge.type == ModbusBridgeType::mb_raw)
{
Response_P(PSTR("{\"" D_JSON_MODBUS_RECEIVED "\":{\"RAW\":["));
- for (uint8_t i = 0; i < tasmotaModbus->ReceiveCount(); i++)
+ for (uint8_t i = 0; i < modbusBridgeModbus->ReceiveCount(); i++)
{
ResponseAppend_P(PSTR("%d"), buffer[i]);
- if (i < tasmotaModbus->ReceiveCount() - 1)
+ if (i < modbusBridgeModbus->ReceiveCount() - 1)
ResponseAppend_P(PSTR(","));
}
ResponseAppend_P(PSTR("]}"));
@@ -371,10 +372,10 @@ void ModbusBridgeHandle(void)
else if (modbusBridge.type == ModbusBridgeType::mb_hex)
{
Response_P(PSTR("{\"" D_JSON_MODBUS_RECEIVED "\":{\"HEX\":["));
- for (uint8_t i = 0; i < tasmotaModbus->ReceiveCount(); i++)
+ for (uint8_t i = 0; i < modbusBridgeModbus->ReceiveCount(); i++)
{
ResponseAppend_P(PSTR("0x%02X"), buffer[i]);
- if (i < tasmotaModbus->ReceiveCount() - 1)
+ if (i < modbusBridgeModbus->ReceiveCount() - 1)
ResponseAppend_P(PSTR(","));
}
ResponseAppend_P(PSTR("]}"));
@@ -396,7 +397,7 @@ void ModbusBridgeHandle(void)
ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_START_ADDRESS "\":%d,"), (buffer[2] << 8) + buffer[3]);
dataOffset = 4;
}
- ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_LENGTH "\":%d,"), tasmotaModbus->ReceiveCount());
+ ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_LENGTH "\":%d,"), modbusBridgeModbus->ReceiveCount());
ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_COUNT "\":%d,"), modbusBridge.count);
ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_VALUES "\":["));
@@ -530,7 +531,7 @@ void ModbusBridgeHandle(void)
ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_DEVICE_ADDRESS "\":%d,"), buffer[0]);
ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_FUNCTION_CODE "\":%d,"), buffer[1]);
ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_START_ADDRESS "\":%d,"), (buffer[2] << 8) + buffer[3]);
- ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_LENGTH "\":%d,"), tasmotaModbus->ReceiveCount());
+ ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_LENGTH "\":%d,"), modbusBridgeModbus->ReceiveCount());
ResponseAppend_P(PSTR("\"" D_JSON_MODBUS_COUNT "\":%d"), (buffer[4] << 8) + buffer[5]);
ResponseAppend_P(PSTR("}"));
ResponseJsonEnd();
@@ -557,14 +558,14 @@ void ModbusBridgeInit(void)
{
if (PinUsed(GPIO_MBR_RX) && PinUsed(GPIO_MBR_TX))
{
- tasmotaModbus = new TasmotaModbus(Pin(GPIO_MBR_RX), Pin(GPIO_MBR_TX));
+ modbusBridgeModbus = new TasmotaModbus(Pin(GPIO_MBR_RX), Pin(GPIO_MBR_TX), Pin(GPIO_MBR_TX_ENA));
ModbusBridgeBegin();
#ifdef USE_MODBUS_BRIDGE_TCP
// If TCP bridge is enabled allocate a TCP receive buffer
modbusBridgeTCP.tcp_buf = (uint8_t *)malloc(MODBUS_BRIDGE_TCP_BUF_SIZE);
- if (!modbusBridgeTCP.tcp_buf)
+ if (nullptr == modbusBridgeTCP.tcp_buf)
{
- AddLog(LOG_LEVEL_ERROR, PSTR("MBS: MBRTCP could not allocate buffer"));
+ ModbusBridgeAllocError(PSTR("TCP"));
return;
}
#endif
@@ -582,7 +583,7 @@ void ModbusTCPHandle(void)
bool busy; // did we transfer some data?
int32_t buf_len;
- if (!tasmotaModbus)
+ if (!modbusBridgeModbus)
return;
// check for a new client connection
@@ -656,8 +657,8 @@ void ModbusTCPHandle(void)
if (mbfunctioncode <= 2)
{
count = (uint16_t)((((uint16_t)modbusBridgeTCP.tcp_buf[10]) << 8) | ((uint16_t)modbusBridgeTCP.tcp_buf[11]));
- modbusBridge.byteCount = ((count - 1) >> 3) + 1;
- modbusBridge.dataCount = ((count - 1) >> 4) + 1;
+ modbusBridge.byteCount = ((count - 1) >> 3) + 1;
+ modbusBridge.dataCount = ((count - 1) >> 4) + 1;
}
else if (mbfunctioncode <= 4)
{
@@ -667,17 +668,22 @@ void ModbusTCPHandle(void)
}
else
{
- // For functioncode 15 & 16 ignore bytecount, tasmotaModbus does calculate this
+ // For functioncode 15 & 16 ignore bytecount, modbusBridgeModbus does calculate this
uint8_t dataStartByte = mbfunctioncode <= 6 ? 10 : 13;
uint16_t byteCount = (buf_len - dataStartByte);
modbusBridge.byteCount = 2;
modbusBridge.dataCount = 1;
writeData = (uint16_t *)malloc((byteCount / 2)+1);
-
+ if (nullptr == writeData)
+ {
+ ModbusBridgeAllocError(PSTR("write"));
+ return;
+ }
+
if ((mbfunctioncode == 15) || (mbfunctioncode == 16)) count = (uint16_t)((((uint16_t)modbusBridgeTCP.tcp_buf[10]) << 8) | ((uint16_t)modbusBridgeTCP.tcp_buf[11]));
else count = 1;
-
+
for (uint16_t dataPointer = 0; dataPointer < byteCount; dataPointer++)
{
if (dataPointer % 2 == 0)
@@ -685,7 +691,7 @@ void ModbusTCPHandle(void)
writeData[dataPointer / 2] = (uint16_t)(((uint16_t)modbusBridgeTCP.tcp_buf[dataStartByte + dataPointer]) << 8);
}
else
- {
+ {
writeData[dataPointer / 2] |= ((uint16_t)modbusBridgeTCP.tcp_buf[dataStartByte + dataPointer]);
}
}
@@ -694,7 +700,7 @@ void ModbusTCPHandle(void)
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: MBRTCP to Modbus TransactionId:%d, deviceAddress:%d, functionCode:%d, startAddress:%d, count:%d, recvCount:%d, recvBytes:%d"),
modbusBridgeTCP.tcp_transaction_id, mbdeviceaddress, mbfunctioncode, mbstartaddress, count, modbusBridge.dataCount, modbusBridge.byteCount);
- tasmotaModbus->Send(mbdeviceaddress, mbfunctioncode, mbstartaddress, count, writeData);
+ modbusBridgeModbus->Send(mbdeviceaddress, mbfunctioncode, mbstartaddress, count, writeData);
free(writeData);
}
@@ -860,6 +866,11 @@ void CmndModbusBridgeSend(void)
else
{
writeData = (uint16_t *)malloc(modbusBridge.dataCount);
+ if (nullptr == writeData)
+ {
+ ModbusBridgeAllocError(PSTR("write"));
+ return;
+ }
for (uint8_t jsonDataArrayPointer = 0; jsonDataArrayPointer < writeDataSize; jsonDataArrayPointer++)
{
@@ -889,7 +900,7 @@ void CmndModbusBridgeSend(void)
writeData[jsonDataArrayPointer / 2] = (int8_t)jsonDataArray[jsonDataArrayPointer / 2].getInt(0) << 8;
if (modbusBridge.dataCount != writeDataSize / 2) errorcode = ModbusBridgeError::wrongcount;
break;
-
+
case ModbusBridgeType::mb_hex:
case ModbusBridgeType::mb_raw:
case ModbusBridgeType::mb_uint8:
@@ -899,31 +910,31 @@ void CmndModbusBridgeSend(void)
writeData[jsonDataArrayPointer / 2] = (uint8_t)jsonDataArray[jsonDataArrayPointer].getUInt(0) << 8;
if (modbusBridge.dataCount != writeDataSize / 2) errorcode = ModbusBridgeError::wrongcount;
break;
-
+
case ModbusBridgeType::mb_int16:
- writeData[jsonDataArrayPointer] = bitMode ? swap_endian16(jsonDataArray[jsonDataArrayPointer].getInt(0))
+ writeData[jsonDataArrayPointer] = bitMode ? ModbusBridgeSwapEndian16(jsonDataArray[jsonDataArrayPointer].getInt(0))
: (int16_t)jsonDataArray[jsonDataArrayPointer].getInt(0);
break;
-
+
case ModbusBridgeType::mb_uint16:
- writeData[jsonDataArrayPointer] = bitMode ? swap_endian16(jsonDataArray[jsonDataArrayPointer].getUInt(0))
+ writeData[jsonDataArrayPointer] = bitMode ? ModbusBridgeSwapEndian16(jsonDataArray[jsonDataArrayPointer].getUInt(0))
: (int16_t)jsonDataArray[jsonDataArrayPointer].getUInt(0);
break;
-
+
case ModbusBridgeType::mb_int32:
- writeData[(jsonDataArrayPointer * 2)] = bitMode ? swap_endian16(jsonDataArray[jsonDataArrayPointer].getInt(0))
+ writeData[(jsonDataArrayPointer * 2)] = bitMode ? ModbusBridgeSwapEndian16(jsonDataArray[jsonDataArrayPointer].getInt(0))
: (int16_t)(jsonDataArray[jsonDataArrayPointer].getInt(0) >> 16);
- writeData[(jsonDataArrayPointer * 2) + 1] = bitMode ? swap_endian16(jsonDataArray[jsonDataArrayPointer].getInt(0) >> 16)
+ writeData[(jsonDataArrayPointer * 2) + 1] = bitMode ? ModbusBridgeSwapEndian16(jsonDataArray[jsonDataArrayPointer].getInt(0) >> 16)
: (uint16_t)(jsonDataArray[jsonDataArrayPointer].getInt(0));
break;
-
+
case ModbusBridgeType::mb_uint32:
- writeData[(jsonDataArrayPointer * 2)] = bitMode ? swap_endian16(jsonDataArray[jsonDataArrayPointer].getUInt(0))
+ writeData[(jsonDataArrayPointer * 2)] = bitMode ? ModbusBridgeSwapEndian16(jsonDataArray[jsonDataArrayPointer].getUInt(0))
: (uint16_t)(jsonDataArray[jsonDataArrayPointer].getUInt(0) >> 16);
- writeData[(jsonDataArrayPointer * 2) + 1] = bitMode ? swap_endian16(jsonDataArray[jsonDataArrayPointer].getUInt(0) >> 16)
+ writeData[(jsonDataArrayPointer * 2) + 1] = bitMode ? ModbusBridgeSwapEndian16(jsonDataArray[jsonDataArrayPointer].getUInt(0) >> 16)
: (uint16_t)(jsonDataArray[jsonDataArrayPointer].getUInt(0));
break;
-
+
case ModbusBridgeType::mb_float:
// TODO
default:
@@ -952,20 +963,20 @@ void CmndModbusBridgeSend(void)
if ((modbusBridge.functionCode == ModbusBridgeFunctionCode::mb_writeSingleCoil) || (modbusBridge.functionCode == ModbusBridgeFunctionCode::mb_writeSingleRegister))
modbusBridge.dataCount = 1;
- uint8_t error = tasmotaModbus->Send(modbusBridge.deviceAddress, (uint8_t)modbusBridge.functionCode, modbusBridge.startAddress, modbusBridge.dataCount, writeData);
+ uint8_t error = modbusBridgeModbus->Send(modbusBridge.deviceAddress, (uint8_t)modbusBridge.functionCode, modbusBridge.startAddress, modbusBridge.dataCount, writeData);
free(writeData);
-
+
if (error)
{
AddLog(LOG_LEVEL_DEBUG, PSTR("MBS: MBR Driver send error %u"), error);
return;
- }
+ }
ResponseCmndDone();
}
void CmndModbusBridgeSetBaudrate(void)
{
- SetModbusBridgeBaudrate(XdrvMailbox.payload);
+ ModbusBridgeSetBaudrate(XdrvMailbox.payload);
ResponseCmndNumber(Settings->modbus_sbaudrate * 300);
}
@@ -981,7 +992,7 @@ void CmndModbusBridgeSetConfig(void)
{ // Use 0..23 as serial config option
if ((XdrvMailbox.payload >= TS_SERIAL_5N1) && (XdrvMailbox.payload <= TS_SERIAL_8O2))
{
- SetModbusBridgeConfig(XdrvMailbox.payload);
+ ModbusBridgeSetConfig(XdrvMailbox.payload);
}
}
else if ((XdrvMailbox.payload >= 5) && (XdrvMailbox.payload <= 8))
@@ -989,7 +1000,7 @@ void CmndModbusBridgeSetConfig(void)
int8_t serial_config = ParseSerialConfig(XdrvMailbox.data);
if (serial_config >= 0)
{
- SetModbusBridgeConfig(serial_config);
+ ModbusBridgeSetConfig(serial_config);
}
}
}
@@ -1004,7 +1015,7 @@ void CmndModbusBridgeSetConfig(void)
void CmndModbusTCPStart(void)
{
- if (!tasmotaModbus)
+ if (!modbusBridgeModbus)
{
return;
}
@@ -1057,7 +1068,7 @@ void CmndModbusTCPConnect(void)
{
int32_t tcp_port = XdrvMailbox.payload;
- if (!tasmotaModbus)
+ if (!modbusBridgeModbus)
{
return;
}
@@ -1108,7 +1119,7 @@ void CmndModbusTCPConnect(void)
* Interface
\*********************************************************************************************/
-bool Xdrv63(uint8_t function)
+bool Xdrv63(uint32_t function)
{
bool result = false;
@@ -1116,7 +1127,7 @@ bool Xdrv63(uint8_t function)
{
ModbusBridgeInit();
}
- else if (tasmotaModbus)
+ else if (modbusBridgeModbus)
{
switch (function)
{
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_79_esp32_ble.ino b/tasmota/tasmota_xdrv_driver/xdrv_79_esp32_ble.ino
index 196c53d27..7060671a6 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_79_esp32_ble.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_79_esp32_ble.ino
@@ -3583,7 +3583,7 @@ int ExtRestartBLEIfEnabled(){
return 0;
}
-bool Xdrv79(uint8_t function)
+bool Xdrv79(uint32_t function)
{
//if (!Settings->flag5.mi32_enable) { return false; } // SetOption115 - Enable ESP32 BLE BLE
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_81_esp32_webcam.ino b/tasmota/tasmota_xdrv_driver/xdrv_81_esp32_webcam.ino
index ba4dbab50..c03031c56 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_81_esp32_webcam.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_81_esp32_webcam.ino
@@ -191,8 +191,9 @@ bool WcPinUsed(void) {
}
if (!PinUsed(GPIO_WEBCAM_XCLK) || !PinUsed(GPIO_WEBCAM_PCLK) ||
!PinUsed(GPIO_WEBCAM_VSYNC) || !PinUsed(GPIO_WEBCAM_HREF) ||
- !PinUsed(GPIO_WEBCAM_SIOD) || !PinUsed(GPIO_WEBCAM_SIOC)) {
- pin_used = false;
+ ((!PinUsed(GPIO_WEBCAM_SIOD) || !PinUsed(GPIO_WEBCAM_SIOC)) && !TasmotaGlobal.i2c_enabled_2) // preferred option is to reuse and share I2Cbus 2
+ ) {
+ pin_used = false;
}
return pin_used;
}
@@ -341,8 +342,14 @@ uint32_t WcSetup(int32_t fsiz) {
config.pin_pclk = Pin(GPIO_WEBCAM_PCLK); // PCLK_GPIO_NUM;
config.pin_vsync = Pin(GPIO_WEBCAM_VSYNC); // VSYNC_GPIO_NUM;
config.pin_href = Pin(GPIO_WEBCAM_HREF); // HREF_GPIO_NUM;
- config.pin_sscb_sda = Pin(GPIO_WEBCAM_SIOD); // SIOD_GPIO_NUM;
- config.pin_sscb_scl = Pin(GPIO_WEBCAM_SIOC); // SIOC_GPIO_NUM;
+ config.pin_sccb_sda = Pin(GPIO_WEBCAM_SIOD); // SIOD_GPIO_NUM; - unset to use shared I2C bus 2
+ config.pin_sccb_scl = Pin(GPIO_WEBCAM_SIOC); // SIOC_GPIO_NUM;
+ if(TasmotaGlobal.i2c_enabled_2){ // configure SIOD and SIOC as SDA,2 and SCL,2
+ config.sccb_i2c_port = 1; // reuse initialized bus 2, can be shared now
+ if(config.pin_sccb_sda < 0){ // GPIO_WEBCAM_SIOD must not be set to really make it happen
+ AddLog(LOG_LEVEL_INFO, PSTR("CAM: use I2C bus 2"));
+ }
+ }
config.pin_pwdn = Pin(GPIO_WEBCAM_PWDN); // PWDN_GPIO_NUM;
config.pin_reset = Pin(GPIO_WEBCAM_RESET); // RESET_GPIO_NUM;
AddLog(LOG_LEVEL_DEBUG, PSTR("CAM: Template pin config"));
@@ -1415,7 +1422,7 @@ void WcStatsShow(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv81(uint8_t function) {
+bool Xdrv81(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino b/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino
index 525e878cc..406d3f94f 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_82_esp32_ethernet.ino
@@ -85,19 +85,29 @@
char eth_hostname[sizeof(TasmotaGlobal.hostname)];
uint8_t eth_config_change;
-void EthernetEvent(WiFiEvent_t event) {
- switch (event) {
+void EthernetEvent(arduino_event_t *event);
+void EthernetEvent(arduino_event_t *event) {
+ switch (event->event_id) {
case ARDUINO_EVENT_ETH_START:
- AddLog(LOG_LEVEL_DEBUG, PSTR("ETH: " D_ATTEMPTING_CONNECTION));
+ AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ETH D_ATTEMPTING_CONNECTION));
ETH.setHostname(eth_hostname);
break;
+
case ARDUINO_EVENT_ETH_CONNECTED:
- AddLog(LOG_LEVEL_INFO, PSTR("ETH: " D_CONNECTED " at %dMbps%s"),
- ETH.linkSpeed(), (ETH.fullDuplex()) ? " Full Duplex" : "");
+#ifdef USE_IPV6
+ ETH.enableIpV6(); // enable Link-Local
+#endif // USE_IPV6
+ AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ETH D_CONNECTED " at %dMbps%s, Mac %s, Hostname %s"),
+ ETH.linkSpeed(), (ETH.fullDuplex()) ? " Full Duplex" : "",
+ ETH.macAddress().c_str(), eth_hostname
+ );
+
+ // AddLog(LOG_LEVEL_DEBUG, D_LOG_ETH "ETH.enableIpV6() -> %i", ETH.enableIpV6());
break;
+
case ARDUINO_EVENT_ETH_GOT_IP:
- AddLog(LOG_LEVEL_DEBUG, PSTR("ETH: Mac %s, IPAddress %_I, Hostname %s"),
- ETH.macAddress().c_str(), (uint32_t)ETH.localIP(), eth_hostname);
+ // AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ETH "Mac %s, IPAddress %_I, Hostname %s"),
+ // ETH.macAddress().c_str(), (uint32_t)ETH.localIP(), eth_hostname);
Settings->eth_ipv4_address[1] = (uint32_t)ETH.gatewayIP();
Settings->eth_ipv4_address[2] = (uint32_t)ETH.subnetMask();
if (0 == Settings->eth_ipv4_address[0]) { // At this point ETH.dnsIP() are NOT correct unless DHCP
@@ -107,15 +117,18 @@ void EthernetEvent(WiFiEvent_t event) {
TasmotaGlobal.rules_flag.eth_connected = 1;
TasmotaGlobal.global_state.eth_down = 0;
break;
+
case ARDUINO_EVENT_ETH_DISCONNECTED:
- AddLog(LOG_LEVEL_INFO, PSTR("ETH: Disconnected"));
+ AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_ETH "Disconnected"));
TasmotaGlobal.rules_flag.eth_disconnected = 1;
TasmotaGlobal.global_state.eth_down = 1;
break;
+
case ARDUINO_EVENT_ETH_STOP:
- AddLog(LOG_LEVEL_DEBUG, PSTR("ETH: Stopped"));
+ AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ETH "Stopped"));
TasmotaGlobal.global_state.eth_down = 1;
break;
+
default:
break;
}
@@ -130,10 +143,23 @@ void EthernetSetIp(void) {
Settings->eth_ipv4_address[4]); // IPAddress dns2
}
+#ifdef USE_IPV6
+// Returns only IPv6 global address (no loopback and no link-local)
+String EthernetGetIPv6(void)
+{
+ return WifiFindIPv6(false, "en");
+}
+
+String EthernetGetIPv6LinkLocal(void)
+{
+ return WifiFindIPv6(true, "en");
+}
+#endif // USE_IPV6
+
void EthernetInit(void) {
if (!Settings->flag4.network_ethernet) { return; }
if (!PinUsed(GPIO_ETH_PHY_MDC) && !PinUsed(GPIO_ETH_PHY_MDIO)) {
- AddLog(LOG_LEVEL_DEBUG, PSTR("ETH: No ETH MDC and/or ETH MDIO GPIO defined"));
+ AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ETH "No ETH MDC and/or ETH MDIO GPIO defined"));
return;
}
@@ -180,7 +206,7 @@ void EthernetInit(void) {
delay(1);
#endif // CONFIG_IDF_TARGET_ESP32
if (!ETH.begin(Settings->eth_address, eth_power, eth_mdc, eth_mdio, (eth_phy_type_t)Settings->eth_type, (eth_clock_mode_t)Settings->eth_clk_mode)) {
- AddLog(LOG_LEVEL_DEBUG, PSTR("ETH: Bad PHY type or init error"));
+ AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_ETH "Bad PHY type or init error"));
return;
};
@@ -297,7 +323,7 @@ void CmndEthSetIpConfig(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv82(uint8_t function) {
+bool Xdrv82(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_83_esp32_watch.ino b/tasmota/tasmota_xdrv_driver/xdrv_83_esp32_watch.ino
index 14ce4eb12..e318d2251 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_83_esp32_watch.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_83_esp32_watch.ino
@@ -434,7 +434,7 @@ bool TTGO_button(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv83(uint8_t function) {
+bool Xdrv83(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_85_esp32_ble_eq3_trv.ino b/tasmota/tasmota_xdrv_driver/xdrv_85_esp32_ble_eq3_trv.ino
index 0af5add13..4ab03c605 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_85_esp32_ble_eq3_trv.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_85_esp32_ble_eq3_trv.ino
@@ -32,6 +32,7 @@ trv 001A22092EE0 settemp 22.5
trvperiod n - set polling period in seconds (default teleperiod at boot)
trvonlyaliased *0/1 - only hear devices with BLEAlias set
+trvretries n - set the number of retries (default 4 at boot)
trvMatchPrefix 0/*1 - if set, then it will add trvs to the seen list which have mac starting with :
macs in macprefixes, currently only 001a22
Note: anything with BLEAlias starting "EQ3" will be added to the seen list.
@@ -147,6 +148,7 @@ namespace EQ3_ESP32 {
void CmndTrv(void);
void CmndTrvPeriod(void);
+void CmndTrvRetries(void);
void CmndTrvOnlyAliased(void);
void CmndTrvMatchPrefix(void);
void CmndTrvMinRSSI(void);
@@ -155,6 +157,7 @@ void CmndTrvHideFailedPoll(void);
const char kEQ3_Commands[] PROGMEM = D_CMND_EQ3"|"
"|"
"period|"
+ "retries|"
"onlyaliased|"
"MatchPrefix|"
"MinRSSI|"
@@ -163,6 +166,7 @@ const char kEQ3_Commands[] PROGMEM = D_CMND_EQ3"|"
void (*const EQ3_Commands[])(void) PROGMEM = {
&CmndTrv,
&CmndTrvPeriod,
+ &CmndTrvRetries,
&CmndTrvOnlyAliased,
&CmndTrvMatchPrefix,
&CmndTrvMinRSSI,
@@ -234,6 +238,7 @@ eq3_device_tag EQ3Devices[EQ3_NUM_DEVICESLOTS];
SemaphoreHandle_t EQ3mutex = nullptr;
int EQ3Period = 300;
+int EQ3Retries = 4;
uint8_t EQ3OnlyAliased = 0;
uint8_t EQ3MatchPrefix = 1;
uint8_t opInProgress = 0;
@@ -365,7 +370,7 @@ int EQ3DoOp(){
if (!opInProgress){
if (opQueue.size()){
op_t* op = opQueue[0];
- if (EQ3Operation(op->addr, op->towrite, op->writelen, op->cmdtype, 4)){
+ if (EQ3Operation(op->addr, op->towrite, op->writelen, op->cmdtype, EQ3Retries)){
opQueue.pop_front();
opInProgress = 1;
AddLog(LOG_LEVEL_DEBUG, PSTR("EQ3 %s:Op dequeued len now %d"), addrStr(op->addr, (op->cmdtype & 0x80)), opQueue.size());
@@ -480,16 +485,18 @@ int EQ3ParseOp(BLE_ESP32::generic_sensor_t *op, bool success, int retries){
ResponseAppend_P(PSTR(",\"hassmode\":"));
do {
+ //HASS allowed modes [“auto”, “off”, “cool”, “heat”, “dry”, “fan_only”]
//0201283B042A
- // its in auto
+ // If its in auto or holiday, set to auto
if ((stat & 3) == 0) { ResponseAppend_P(PSTR("\"auto\"")); break; }
- // it's set to 'OFF'
+ // If its in manual and 4.5°C, set to off
if (((stat & 3) == 1) && (status[5] == 9)) { ResponseAppend_P(PSTR("\"off\"")); break; }
- // it's actively heating (valve open)
+ // If its in manual above 4.5°C and valve is open, set to heat
if (((stat & 3) == 1) && (status[5] > 9) && (status[3] > 0)) { ResponseAppend_P(PSTR("\"heat\"")); break; }
- // it's achieved temp (valve closed)
- if (((stat & 3) == 1) && (status[5] > 9)) { ResponseAppend_P(PSTR("\"idle\"")); break; }
- ResponseAppend_P(PSTR("\"idle\""));
+ // If its in manual above 4.5°C and valve is closed, set to off
+ if (((stat & 3) == 1) && (status[5] > 9)) { ResponseAppend_P(PSTR("\"off\"")); break; }
+ //Fallback off
+ ResponseAppend_P(PSTR("\"off\""));
break;
} while (0);
@@ -1271,16 +1278,16 @@ int EQ3Send(const uint8_t* addr, const char *cmd, char* param, char* param2, int
if (!strcmp(param, "auto")){
d[1] = 0x00;
}
- if (!strcmp(param, "manual")){
+ if (!strcmp(param, "manual") || !strcmp(param, "heat" )){
d[1] = 0x40;
}
- if (!strcmp(param, "on") || !strcmp(param, "heat")) {
+ if (!strcmp(param, "on")) {
int res = EQ3Send(addr, "manual", nullptr, nullptr, useAlias);
char tmp[] = "30";
int res2 = EQ3Send(addr, "settemp", tmp, nullptr, useAlias);
return res2;
}
- if (!strcmp(param, "off") || !strcmp(param, "cool")) {
+ if (!strcmp(param, "off") || !strcmp(param, "cool") || !strcmp(param, "fan_only")) {
int res = EQ3Send(addr, "manual", nullptr, nullptr, useAlias);
char tmp[] = "4.5";
int res2 = EQ3Send(addr, "settemp", tmp, nullptr, useAlias);
@@ -1486,6 +1493,13 @@ void CmndTrvPeriod(void) {
ResponseCmndNumber(EQ3Period);
}
+void CmndTrvRetries(void) {
+ if (XdrvMailbox.data_len > 0) {
+ EQ3Retries = XdrvMailbox.payload;
+ }
+ ResponseCmndNumber(EQ3Retries);
+}
+
void CmndTrvOnlyAliased(void){
if (XdrvMailbox.data_len > 0) {
EQ3OnlyAliased = XdrvMailbox.payload;
@@ -1745,7 +1759,7 @@ void EQ3DiscoveryOneEQ3(){
* Interface
\*********************************************************************************************/
-bool Xdrv85(uint8_t function)
+bool Xdrv85(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_86_esp32_sonoff_spm.ino b/tasmota/tasmota_xdrv_driver/xdrv_86_esp32_sonoff_spm.ino
index 4b568da3a..058f83813 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_86_esp32_sonoff_spm.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_86_esp32_sonoff_spm.ino
@@ -128,7 +128,7 @@
// From ESP to ARM
#define SSPM_FUNC_FIND 0 // 0x00
-#define SSPM_FUNC_SET_OPS 3 // 0x03 - Overload Protection
+#define SSPM_FUNC_SET_OPS 3 // 0x03 - Overload Protection (OPS)
#define SSPM_FUNC_GET_OPS 4 // 0x04
#define SSPM_FUNC_SET_RELAY 8 // 0x08
#define SSPM_FUNC_GET_MODULE_STATE 9 // 0x09 - State of four channels
@@ -138,7 +138,7 @@
#define SSPM_FUNC_IAMHERE 13 // 0x0D
#define SSPM_FUNC_INIT_SCAN 16 // 0x10
#define SSPM_FUNC_UPLOAD_HEADER 20 // 0x14 - SPI Upload header
-#define SSPM_FUNC_UNITS 21 // 0x15
+#define SSPM_FUNC_GET_MAIN_VERSION 21 // 0x15 - Read main ARM firmware version
#define SSPM_FUNC_GET_ENERGY_TOTAL 22 // 0x16
#define SSPM_FUNC_GET_ENERGY 24 // 0x18
#define SSPM_FUNC_GET_LOG 26 // 0x1A
@@ -148,14 +148,14 @@
#define SSPM_FUNC_UPLOAD_DONE 33 // 0x21 - SPI Finish upload
#define SSPM_FUNC_34 34 // 0x22 - v1.2.0
#define SSPM_FUNC_GET_OPS_DEFAULTS 35 // 0x23 - v1.2.0 - Get Overload protection defaults
-#define SSPM_FUNC_SET_POS 36 // 0x24 - v1.2.0 - Save power on relay state
-#define SSPM_FUNC_GET_POS 37 // 0x25 - v1.2.0 - Read power on relay state
+#define SSPM_FUNC_SET_POS 36 // 0x24 - v1.2.0 - Save power on relay state (POS)
+#define SSPM_FUNC_GET_POS 37 // 0x25 - v1.2.0 - Read power on relay state (POS)
// From ARM to ESP
#define SSPM_FUNC_ENERGY_RESULT 6 // 0x06
#define SSPM_FUNC_KEY_PRESS 7 // 0x07
#define SSPM_FUNC_SCAN_START 15 // 0x0F
-#define SSPM_FUNC_SCAN_RESULT 19 // 0x13
+#define SSPM_FUNC_SCAN_RESULT 19 // 0x13 - Provide 4relay ARM firmware version, module type and OPS limits
#define SSPM_FUNC_SCAN_DONE 25 // 0x19
#define SSPM_FUNC_UPLOAD_DONE_ACK 30 // 0x1E - Restart ARM
@@ -177,26 +177,27 @@
#define SSPM_VERSION_1_0_0 0x00010000
#define SSPM_VERSION_1_2_0 0x00010200
+#define SSPM_VERSION_1_4_0 0x00010400
/*********************************************************************************************/
-#define SSPM_TOTAL_MODULES 32 // Max number of SPM-4RELAY units for a total of 128 relays
+#define SSPM_TOTAL_MODULES 32 // Max number of SPM-4RELAY units for a total of 128 relays
-enum SspmMachineStates { SPM_NONE, // Do nothing
- SPM_WAIT, // Wait 100ms
- SPM_RESET, // Toggle ARM reset pin
- SPM_POLL_ARM, // Wait for first acknowledge from ARM after reset
+enum SspmMachineStates { SPM_NONE, // Do nothing
+ SPM_WAIT, // Wait 100ms
+ SPM_RESET, // Toggle ARM reset pin
+ SPM_POLL_ARM, // Wait for first acknowledge from ARM after reset
// Removed to accomodate v1.2.0 too
-// SPM_POLL_ARM_SPI, // Wait for first acknowledge from ARM SPI after reset
-// SPM_POLL_ARM_2, // Wait for second acknowledge from ARM after reset
-// SPM_POLL_ARM_3, // Wait for second acknowledge from ARM after reset
- SPM_SEND_FUNC_UNITS, // Get number of units
- SPM_START_SCAN, // Start module scan sequence
- SPM_WAIT_FOR_SCAN, // Wait for scan sequence to complete
- SPM_SCAN_COMPLETE, // Scan complete
- SPM_STALL_MIDNIGHT, // Stall energy totals around midnight
- SPM_GET_ENERGY_TOTALS, // Init available Energy totals registers
- SPM_UPDATE_CHANNELS // Update Energy for powered on channels
+// SPM_POLL_ARM_SPI, // Wait for first acknowledge from ARM SPI after reset
+// SPM_POLL_ARM_2, // Wait for second acknowledge from ARM after reset
+// SPM_POLL_ARM_3, // Wait for second acknowledge from ARM after reset
+ SPM_SEND_FUNC_GET_MAIN_VERSION, // Get main ARM firmware version
+ SPM_START_SCAN, // Start module scan sequence
+ SPM_WAIT_FOR_SCAN, // Wait for scan sequence to complete
+ SPM_SCAN_COMPLETE, // Scan complete
+ SPM_STALL_MIDNIGHT, // Stall energy totals around midnight
+ SPM_GET_ENERGY_TOTALS, // Init available Energy totals registers
+ SPM_UPDATE_CHANNELS // Update Energy for powered on channels
};
enum SspmDisplayModes { SPM_DISPLAY_ROTATE, SPM_DISPLAY_ROTATE_POWERED_ON, SPM_DISPLAY_TABS, SPM_DISPLAY_MAX_OPTION };
@@ -1233,7 +1234,7 @@ void SSPMHandleReceivedData(void) {
AA 55 01 ff ff ff ff ff ff ff ff ff ff ff ff 80 10 00 01 00 02 e5 03
*/
break;
- case SSPM_FUNC_UNITS:
+ case SSPM_FUNC_GET_MAIN_VERSION:
/* 0x15
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 80 15 00 04 00 01 00 00 01 81 b1
@@ -1479,8 +1480,10 @@ void SSPMHandleReceivedData(void) {
P4 - Relay4 power on state (0 = On, 1 = Off, 2 = Laststate)
*/
Sspm->module_selected--;
- for (uint32_t i = 0; i < 4; i++) {
- Sspm->poweron_state[Sspm->module_selected][i] = (!status && (expected_bytes >= 0x05)) ? SspmBuffer[20 +i] : 1;
+ if (!status && (expected_bytes >= 0x05)) {
+ for (uint32_t i = 0; i < 4; i++) {
+ Sspm->poweron_state[Sspm->module_selected][i] = SspmBuffer[20 +i];
+ }
}
if (Sspm->module_selected > 0) {
SSPMSendGetModuleState(Sspm->module_selected -1);
@@ -1617,10 +1620,12 @@ void SSPMHandleReceivedData(void) {
case SSPM_FUNC_SCAN_RESULT:
/* 0x13
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
- AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 13 00 24 6b 7e 32 37 39 37 34 13 4b 35 36 37 04 00 00 00 82 01 00 00 14 00 00 0a 00 f0 00 00 00 0a 11 30 00 00 00 0a 02 8f cd
- AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 13 00 24 8b 34 32 37 39 37 34 13 4b 35 36 37 04 00 00 00 82 01 00 00 14 00 00 0a 00 f0 00 00 00 0a 11 30 00 00 00 0a 02 a0 6f
Marker | |Ac|Cm|Size |Module id |Ch| |Ty|FwVersio|Max I|Min I|Max U |Min U |Max P |Min P |Ix|Chksm|
+ AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 13 00 24 6b 7e 32 37 39 37 34 13 4b 35 36 37 04 00 00 00 82 01 00 00 14 00 00 0a 00 f0 00 00 00 0a 11 30 00 00 00 0a 02 8f cd - v1.0.0
+ AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 13 00 24 8b 34 32 37 39 37 34 13 4b 35 36 37 04 00 00 00 82 01 00 00 14 00 00 0a 00 f0 00 00 00 0a 11 30 00 00 00 0a 02 a0 6f - v1.0.0
|130| 1.0.0|20.0A|0.10A| 240.00V| 0.10V|4400.00W| 0.10W|
+ AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 13 00 24 8B 34 32 37 39 37 34 13 4B 35 36 37 04 00 00 00 82 01 02 00 14 00 00 0A 01 08 00 00 5A 00 12 C0 00 00 00 0A 02 6B 93 - v1.2.0
+ |130| 1.2.0|20.0A|0.10A| 264.00V| 90V|4800.00W| 0.10W|
Ty = Type of sub-device. 130: Four-channel sub-device
*/
if (0x24 == expected_bytes) {
@@ -1931,6 +1936,11 @@ void SSPMInit(void) {
#endif
#endif
+ for (uint32_t module = 0; module < Sspm->module_max; module++) {
+ for (uint32_t relay = 0; relay < 4; relay++) {
+ Sspm->poweron_state[module][relay] = 1; // Set default power on state to Off ( = Sonoff 1)
+ }
+ }
Sspm->relay_version = 0xFFFFFFFF; // Find lowest supported relay version
Sspm->overload_relay = 255; // Disable display overload settings
Sspm->history_relay = 255; // Disable display energy history
@@ -1964,7 +1974,7 @@ void SSPMEvery100ms(void) {
}
// Fix race condition if the ARM doesn't respond
- if ((Sspm->mstate > SPM_NONE) && (Sspm->mstate < SPM_SEND_FUNC_UNITS)) {
+ if ((Sspm->mstate > SPM_NONE) && (Sspm->mstate < SPM_SEND_FUNC_GET_MAIN_VERSION)) {
Sspm->counter++;
if (Sspm->counter > 30) {
Sspm->mstate = SPM_NONE;
@@ -2003,9 +2013,9 @@ void SSPMEvery100ms(void) {
// Wait for second acknowledge from ARM after reset
break;
*/
- case SPM_SEND_FUNC_UNITS:
- // Get number of units
- SSPMSendCmnd(SSPM_FUNC_UNITS);
+ case SPM_SEND_FUNC_GET_MAIN_VERSION:
+ // Get main version number
+ SSPMSendCmnd(SSPM_FUNC_GET_MAIN_VERSION);
break;
case SPM_START_SCAN:
// Start scan module sequence
@@ -2397,7 +2407,8 @@ void CmndSpmEnergyYesterday(void) {
void CmndSSPMOverload(void) {
// Get / Set overload
// SspmOverload 0 - Reset overload detection parameters
- // SspmOverload {"Delay":0,"Set":00000,"MinPower":0.10,"MaxPower":4400.00,"MinVoltage":0.10,"MaxVoltage":240.00,"MaxCurrent":20.00}
+ // SspmOverload {"Delay":0,"Set":00000,"MinPower":0.10,"MaxPower":4400.00,"MinVoltage":0.10,"MaxVoltage":240.00,"MaxCurrent":20.00} - v1.0.0
+ // SspmOverload {"Delay":0,"Set":00000,"MinPower":0.10,"MaxPower":4800.00,"MinVoltage":90,"MaxVoltage":264.00,"MaxCurrent":20.00} - v1.2.0
// SspmOverload ,,,,
// SspmOverload 10,0.10,4400.00,0.10,240.00,20.00
// SspmOverload 10 0.10 4400.00 0.10 240.00 20.00
@@ -2590,26 +2601,29 @@ void CmndSSPMSend(void) {
void CmndSSPMPowerOnState(void) {
// SspmPowerOnState2 0|1|2 - Set relay2 power on state (0 = Off, 1 = On, 2 = Saved)
- uint32_t max_index = Sspm->module_max *4;
- if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= max_index)) {
- uint32_t module = (XdrvMailbox.index -1) >>2;
- uint32_t relay = (XdrvMailbox.index -1) &3;
- if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) {
- if (XdrvMailbox.payload < 2) { XdrvMailbox.payload = !XdrvMailbox.payload; } // Swap Tasmota power off (0) with Sonoff (1)
- Sspm->poweron_state[module][relay] = XdrvMailbox.payload;
- SSPMSendSetPowerOnState(module);
- }
- Response_P(PSTR("{\"%s\":["), XdrvMailbox.command);
- bool more = false;
- for (uint32_t module = 0; module < Sspm->module_max; module++) {
- for (uint32_t relay = 0; relay < 4; relay++) {
- uint32_t poweron_state = Sspm->poweron_state[module][relay];
- if (poweron_state < 2) { poweron_state = !poweron_state; } // Swap Sonoff power off (1) with Tasmota (0)
- ResponseAppend_P(PSTR("%s%d"), (more)?",":"", poweron_state);
- more = true;
+ // Needs both main and 4relay at v1.2.0
+ if (Sspm->main_version > SSPM_VERSION_1_0_0) {
+ uint32_t max_index = Sspm->module_max *4;
+ if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= max_index)) {
+ uint32_t module = (XdrvMailbox.index -1) >>2;
+ uint32_t relay = (XdrvMailbox.index -1) &3;
+ if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 2)) {
+ if (XdrvMailbox.payload < 2) { XdrvMailbox.payload = !XdrvMailbox.payload; } // Swap Tasmota power off (0) with Sonoff (1)
+ Sspm->poweron_state[module][relay] = XdrvMailbox.payload;
+ SSPMSendSetPowerOnState(module);
}
+ Response_P(PSTR("{\"%s\":["), XdrvMailbox.command);
+ bool more = false;
+ for (uint32_t module = 0; module < Sspm->module_max; module++) {
+ for (uint32_t relay = 0; relay < 4; relay++) {
+ uint32_t poweron_state = Sspm->poweron_state[module][relay];
+ if (poweron_state < 2) { poweron_state = !poweron_state; } // Swap Sonoff power off (1) with Tasmota (0)
+ ResponseAppend_P(PSTR("%s%d"), (more)?",":"", poweron_state);
+ more = true;
+ }
+ }
+ ResponseAppend_P(PSTR("]}"));
}
- ResponseAppend_P(PSTR("]}"));
}
}
@@ -2617,7 +2631,7 @@ void CmndSSPMPowerOnState(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv86(uint8_t function) {
+bool Xdrv86(uint32_t function) {
bool result = false;
if (FUNC_INIT == function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino b/tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino
index b0e9fe188..70926f5ff 100644
--- a/tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino
+++ b/tasmota/tasmota_xdrv_driver/xdrv_87_esp32_sonoff_tm1621.ino
@@ -334,8 +334,7 @@ void TM1621Init(void) {
uint32_t TM1621GetSensors(bool refresh) {
if (refresh) {
ResponseClear();
- XsnsCall(FUNC_JSON_APPEND);
- XdrvCall(FUNC_JSON_APPEND);
+ XsnsXdrvCall(FUNC_JSON_APPEND);
ResponseJsonStart(); // Overwrite first comma
ResponseJsonEnd(); // Append }
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("TM1: Sensors %s"), ResponseData());
@@ -567,7 +566,7 @@ void CmndDspSpeed(void) {
* Interface
\*********************************************************************************************/
-bool Xdrv87(uint8_t function) {
+bool Xdrv87(uint32_t function) {
bool result = false;
if (FUNC_INIT == function) {
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino
new file mode 100644
index 000000000..9642163ce
--- /dev/null
+++ b/tasmota/tasmota_xdrv_driver/xdrv_88_esp32_shelly_pro.ino
@@ -0,0 +1,176 @@
+/*
+ xdrv_88_shelly_pro.ino - Shelly pro family support for Tasmota
+
+ Copyright (C) 2022 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 ESP32
+#ifdef USE_SPI
+#ifdef USE_SHELLY_PRO
+/*********************************************************************************************\
+ * Shelly Pro support
+ *
+ * {"NAME":"Shelly Pro 1","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"}
+ * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"}
+ * {"NAME":"Shelly Pro 2","GPIO":[0,1,0,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,0,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350;AdcParam2 2,10000,10000,3350"}
+ * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350;AdcParam2 2,10000,10000,3350"}
+ *
+ * Shelly Pro uses SPI to control one 74HC595 for relays/leds and one ADE7953 (1PM) or two ADE7953 (2PM) for energy monitoring
+\*********************************************************************************************/
+
+#define XDRV_88 88
+
+struct SPro {
+ uint32_t last_update;
+ uint8_t pin_shift595_rclk;
+ uint8_t ledlink;
+ uint8_t power;
+ bool detected;
+} SPro;
+
+void ShellyProUpdate(void) {
+ // Shelly Pro 595 register
+ // bit 0 = relay/led 1
+ // bit 1 = relay/led 2
+ // bit 2 = wifi led blue
+ // bit 3 = wifi led green
+ // bit 4 = wifi led red
+ // bit 5 - 7 = nc
+ // OE is connected to Gnd with 470 ohm resistor R62 AND a capacitor C81 to 3V3
+ // - this inhibits output of signals (also relay state) during power on for a few seconds
+ uint8_t val = SPro.power | SPro.ledlink;
+ SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
+ SPI.transfer(val); // Write 74HC595 shift register
+ SPI.endTransaction();
+// delayMicroseconds(2); // Wait for SPI clock to stop
+ digitalWrite(SPro.pin_shift595_rclk, 1); // Latch data
+ delayMicroseconds(1); // Shelly 10mS
+ digitalWrite(SPro.pin_shift595_rclk, 0);
+}
+
+void ShellyProPreInit(void) {
+ if ((SPI_MOSI_MISO == TasmotaGlobal.spi_enabled) &&
+ PinUsed(GPIO_SPI_CS) &&
+ TasmotaGlobal.gpio_optiona.shelly_pro) { // Option_A7
+
+ if (PinUsed(GPIO_SWT1) || PinUsed(GPIO_KEY1)) {
+ TasmotaGlobal.devices_present++; // Shelly Pro 1
+ if (PinUsed(GPIO_SWT1, 1) || PinUsed(GPIO_KEY1, 1)) {
+ TasmotaGlobal.devices_present++; // Shelly Pro 2
+ }
+
+ SPro.pin_shift595_rclk = Pin(GPIO_SPI_CS);
+ digitalWrite(SPro.pin_shift595_rclk, 0);
+ pinMode(SPro.pin_shift595_rclk, OUTPUT);
+ // Does nothing if SPI is already initiated (by ADE7953) so no harm done
+ SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1);
+
+ SPro.ledlink = 0x18; // Blue led on - set by first call ShellyProPower()
+ SPro.detected = true;
+ }
+ }
+}
+
+void ShellyProInit(void) {
+ int pin_lan_reset = 5; // GPIO5 = LAN8720 nRST
+// delay(30); // (t-purstd) This pin must be brought low for a minimum of 25 mS after power on
+ digitalWrite(pin_lan_reset, 0);
+ pinMode(pin_lan_reset, OUTPUT);
+ delay(1); // (t-rstia) This pin must be brought low for a minimum of 100 uS
+ digitalWrite(pin_lan_reset, 1);
+
+ AddLog(LOG_LEVEL_INFO, PSTR("HDW: Shelly Pro %d%s initialized"),
+ TasmotaGlobal.devices_present, (PinUsed(GPIO_ADE7953_CS))?"PM":"");
+}
+
+void ShellyProPower(void) {
+ SPro.power = XdrvMailbox.index &3;
+ ShellyProUpdate();
+}
+
+void ShellyProUpdateLedLink(uint32_t ledlink) {
+ if (ledlink != SPro.ledlink) {
+ SPro.ledlink = ledlink;
+ ShellyProUpdate();
+ }
+}
+
+void ShellyProLedLink(void) {
+ /*
+ bit 2 = blue, 3 = green, 4 = red
+ Shelly Pro documentation
+ - Blue light indicator will be on if in AP mode.
+ - Red light indicator will be on if in STA mode and not connected to a Wi-Fi network.
+ - Yellow light indicator will be on if in STA mode and connected to a Wi-Fi network.
+ - Green light indicator will be on if in STA mode and connected to a Wi-Fi network and to the Shelly Cloud.
+ - The light indicator will be flashing Red/Blue if OTA update is in progress.
+ Tasmota behaviour
+ - Blue light indicator will blink if no wifi or mqtt.
+ - Green light indicator will be on if in STA mode and connected to a Wi-Fi network.
+ */
+ SPro.last_update = TasmotaGlobal.uptime;
+ uint32_t ledlink = 0x1C; // All leds off
+ if (XdrvMailbox.index) {
+ ledlink &= 0xFB; // Blue blinks if wifi/mqtt lost
+ }
+ else if (!TasmotaGlobal.global_state.wifi_down) {
+ ledlink &= 0xF7; // Green On
+ }
+
+ ShellyProUpdateLedLink(ledlink);
+}
+
+void ShellyProLedLinkWifiOff(void) {
+ /*
+ bit 2 = blue, 3 = green, 4 = red
+ - Green light indicator will be on if in STA mode and connected to a Wi-Fi network.
+ */
+ if (SPro.last_update +1 < TasmotaGlobal.uptime) {
+ ShellyProUpdateLedLink((TasmotaGlobal.global_state.wifi_down) ? 0x1C : 0x14); // Green off if wifi OFF
+ }
+}
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xdrv88(uint32_t function) {
+ bool result = false;
+
+ if (FUNC_PRE_INIT == function) {
+ ShellyProPreInit();
+ } else if (SPro.detected) {
+ switch (function) {
+ case FUNC_EVERY_SECOND:
+ ShellyProLedLinkWifiOff();
+ break;
+ case FUNC_SET_POWER:
+ ShellyProPower();
+ break;
+ case FUNC_LED_LINK:
+ ShellyProLedLink();
+ break;
+ case FUNC_INIT:
+ ShellyProInit();
+ break;
+ }
+ }
+ return result;
+}
+
+#endif // USE_SHELLY_PRO
+#endif // USE_SPI
+#endif // ESP32
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_89_esp32_dali.ino b/tasmota/tasmota_xdrv_driver/xdrv_89_esp32_dali.ino
new file mode 100644
index 000000000..d1fbeee5c
--- /dev/null
+++ b/tasmota/tasmota_xdrv_driver/xdrv_89_esp32_dali.ino
@@ -0,0 +1,583 @@
+/*
+ xdrv_89_esp32_dali.ino - DALI support for Tasmota
+
+ Copyright (C) 2022 Andrei Kazmirtsuk aka eeak
+
+ 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 .
+
+ --------------------------------------------------------------------------------------------
+ Version yyyymmdd Action Description
+ --------------------------------------------------------------------------------------------
+ 0.0.0.1 20221027 publish - initial version
+*/
+
+#ifdef ESP32
+#ifdef USE_DALI
+
+/*********************************************************************************************\
+ * DALI support for Tasmota
+\*********************************************************************************************/
+
+#define XDRV_89 89
+
+#ifndef DALI_TIMER
+ #define DALI_TIMER 0 // Default timer
+#endif
+
+#define BROADCAST_DP 0b11111110 // 0xFE
+#define DALI_TOPIC "DALI"
+
+enum
+{
+ DALI_NO_ACTION,
+ DALI_SENDING_DATA,
+ DALI_RECEIVING_DATA,
+ DALI_ERROR
+};
+
+// http and json defines
+#define D_NAME_DALI "DALI"
+
+const char S_JSON_DALI_COMMAND_NVALUE[] PROGMEM = "{\"" D_NAME_DALI "\":{\"%s\":%d}}";
+const char kDALI_Commands[] PROGMEM = D_CMND_DALI_POWER "|" D_CMND_DALI_DIMMER;
+
+enum DALI_Commands { // commands for Console
+ CMND_DALI_PWR,
+ CMND_DALI_DIM,
+};
+
+struct DALI {
+ uint16_t send_dali_data; // data to send to DALI bus
+ uint16_t received_dali_data; // data received from DALI bus
+ uint8_t flag; // DALI status flag
+ uint8_t bit_count; // nr of rec/send bits
+ uint16_t tick_count; // nr of ticks of the timer
+ bool former_val; // bit value in previous tick of timer
+ hw_timer_t *timer; // hardware timer
+} *Dali = nullptr;
+
+
+
+/*********************************************************************************************\
+ * DALI low level
+\*********************************************************************************************/
+
+/**
+* @brief This function handles hardware timer Handler.
+* @param None
+* @retval None
+*/
+void IRAM_ATTR DALI_Tick_Handler(void)
+{
+ if (getDaliFlag() == DALI_RECEIVING_DATA)
+ {
+ receive_tick();
+ }
+ else if (getDaliFlag() == DALI_SENDING_DATA)
+ {
+ send_tick();
+ }
+}
+
+/**
+* @brief This function enable data transfer start interrupt.
+* @param None
+* @retval None
+*/
+void enableDaliRxInterrupt() {
+ Dali->flag = DALI_NO_ACTION;
+ timerAlarmDisable(Dali->timer);
+ attachInterrupt(Pin(GPIO_DALI_RX), receiveDaliData, FALLING);
+}
+
+/**
+* @brief This function disable data transfer start interrupt.
+* @param None
+* @retval None
+*/
+void disableRxInterrupt() {
+ timerAlarmEnable(Dali->timer);
+ detachInterrupt(Pin(GPIO_DALI_RX));
+}
+
+/**
+* @brief receiving flag status
+* @param None
+* @retval uint8_t flag
+*/
+uint8_t getDaliFlag(void)
+{
+ return Dali->flag;
+}
+
+/**
+* @brief DALI data received callback
+* @param None
+* @retval uint8_t flag
+*/
+void DataReceivedCallback() {
+ AddLog(LOG_LEVEL_DEBUG, PSTR("DLI: Received: %d %d"), Dali->received_dali_data>>9, Dali->received_dali_data&0xff);
+}
+
+/*************** R E C E I V E * P R O C E D U R E S *******/
+
+/**
+* @brief receive data from DALI bus
+* @param None
+* @retval None
+*/
+void receiveDaliData()
+{
+ // null variables
+ Dali->received_dali_data = 0;
+ Dali->bit_count = 0;
+ Dali->tick_count = 0;
+ Dali->former_val = true;
+
+ Dali->flag = DALI_RECEIVING_DATA;
+
+ disableRxInterrupt();
+}
+
+/**
+* @brief Get state of DALIIN pin
+* @param None
+* @retval bool status
+*/
+bool get_DALIIN(void)
+{
+ bool dali_read = digitalRead(Pin(GPIO_DALI_RX));
+ return (false == DALI_IN_INVERT) ? dali_read : !dali_read;
+}
+
+/**
+* @brief receiving data from DALI bus
+* @param None
+* @retval None
+*
+* |--------|----|---------------------------|----|
+* 0 24 32 160 176
+* wait start data stop
+*/
+void receive_tick(void)
+{
+ // four ticks per bit
+ bool actual_val = get_DALIIN();
+ Dali->tick_count++;
+
+ // edge detected
+ if(actual_val != Dali->former_val)
+ {
+ switch(Dali->bit_count)
+ {
+ case 0:
+ if (Dali->tick_count > 2)
+ {
+ Dali->tick_count = 0;
+ Dali->bit_count = 1; // start bit
+ }
+ break;
+ case 17: // 1st stop bit
+ if(Dali->tick_count > 6) { // stop bit error, no edge should exist
+ Dali->flag = DALI_ERROR;
+ }
+ break;
+ default: // other bits
+ if(Dali->tick_count > 6)
+ {
+ Dali->received_dali_data |= (actual_val << (16-Dali->bit_count));
+ Dali->bit_count++;
+ Dali->tick_count = 0;
+ }
+ break;
+ }
+ }else // voltage level stable
+ {
+ switch(Dali->bit_count)
+ {
+ case 0:
+ if(Dali->tick_count==8) { // too long start bit
+ Dali->flag = DALI_ERROR;
+ }
+ break;
+ case 17:
+ // First stop bit
+ if (Dali->tick_count==8)
+ {
+ if (actual_val==0) // wrong level of stop bit
+ {
+ Dali->flag = DALI_ERROR;
+ }
+ else
+ {
+ Dali->bit_count++;
+ Dali->tick_count = 0;
+ }
+ }
+ break;
+ case 18:
+ // Second stop bit
+ if (Dali->tick_count==8)
+ {
+ enableDaliRxInterrupt();
+ DataReceivedCallback();
+
+ }
+ break;
+ default: // normal bits
+ if(Dali->tick_count==10)
+ { // too long delay before edge
+ Dali->flag = DALI_ERROR;
+ }
+ break;
+ }
+ }
+ Dali->former_val = actual_val;
+ if(getDaliFlag() == DALI_ERROR)
+ {
+ enableDaliRxInterrupt();
+ }
+}
+
+
+/*************** S E N D * P R O C E D U R E S *************/
+
+/**
+* @brief Set value to the DALIOUT pin
+* @param bool
+* @retval None
+*/
+void set_DALIOUT(bool pin_value)
+{
+ digitalWrite(Pin(GPIO_DALI_TX), pin_value == DALI_OUT_INVERT ? LOW : HIGH);
+}
+
+/**
+* @brief gets state of the DALIOUT pin
+* @param None
+* @retval bool state of the DALIOUT pin
+*/
+bool get_DALIOUT(void)
+{
+ bool dali_read = digitalRead(Pin(GPIO_DALI_TX));
+ return (false == DALI_OUT_INVERT) ? dali_read : !dali_read;
+}
+
+/**
+* @brief Send data to DALI bus
+* @param byteToSend
+* @retval None
+*/
+void sendDaliData(uint8_t firstByte, uint8_t secondByte)
+{
+ Dali->send_dali_data = firstByte << 8;
+ Dali->send_dali_data += secondByte & 0xff;
+ Dali->bit_count = 0;
+ Dali->tick_count = 0;
+
+ Dali->flag = DALI_SENDING_DATA;
+
+ disableRxInterrupt();
+}
+
+/**
+* @brief DALI protocol physical layer for slave device
+* @param None
+* @retval None
+*
+* |--------|----|---------------------------|----|
+* 0 24 32 160 176
+* wait start data stop
+*/
+void send_tick(void)
+{
+ // access to the routine just every 4 ticks = every half bit
+ if ((Dali->tick_count & 0x03) == 0)
+ {
+ if (Dali->tick_count < 160)
+ {
+ // settling time between forward and backward frame
+ if (Dali->tick_count < 24)
+ {
+ Dali->tick_count++;
+ return;
+ }
+
+ // start of the start bit
+ if (Dali->tick_count == 24)
+ {
+ // GPIOB->ODR ^= GPIO_ODR_7;
+ set_DALIOUT(false);
+ Dali->tick_count++;
+ return;
+ }
+
+ // edge of the start bit
+ // 28 ticks = 28/9600 = 2,92ms = delay between forward and backward message frame
+ if (Dali->tick_count == 28)
+ {
+ set_DALIOUT(true);
+ Dali->tick_count++;
+ return;
+ }
+
+ // bit value (edge) selection
+ bool bit_value = (bool)((Dali->send_dali_data >> (15 - Dali->bit_count)) & 0x01);
+
+ // Every half bit -> Manchester coding
+ if (!((Dali->tick_count - 24) & 0x0007))
+ { // div by 8
+ if (get_DALIOUT() == bit_value) // former value of bit = new value of bit
+ set_DALIOUT((bool)(1 - bit_value));
+ }
+
+ // Generate edge for actual bit
+ if (!((Dali->tick_count - 28) & 0x0007))
+ {
+ set_DALIOUT(bit_value);
+ Dali->bit_count++;
+ }
+ }
+ else
+ { // end of data byte, start of stop bits
+ if (Dali->tick_count == 160)
+ {
+ set_DALIOUT(true); // start of stop bit
+ }
+
+ // end of stop bits, no settling time
+ if (Dali->tick_count == 176)
+ {
+ enableDaliRxInterrupt();
+ }
+ }
+ }
+ Dali->tick_count++;
+
+ return;
+}
+
+/***********************************************************/
+
+void DaliPreInit() {
+ if (!PinUsed(GPIO_DALI_TX) || !PinUsed(GPIO_DALI_RX)) { return; }
+ AddLog(LOG_LEVEL_INFO, PSTR("DLI: Init - RX-pin: %d, TX-pin: %d"), Pin(GPIO_DALI_RX), Pin(GPIO_DALI_TX));
+ // pinMode(LED, OUTPUT);
+ pinMode(Pin(GPIO_DALI_TX), OUTPUT);
+ digitalWrite(Pin(GPIO_DALI_TX), HIGH);
+ pinMode(Pin(GPIO_DALI_RX), INPUT);
+
+ Dali = (DALI*)calloc(1,sizeof(DALI));
+ if (!Dali) {
+ AddLog(LOG_LEVEL_INFO, PSTR("DLI: Memory allocation error"));
+ return;
+ }
+ Dali->timer = timerBegin(DALI_TIMER, 13, true);
+ timerAttachInterrupt(Dali->timer, &DALI_Tick_Handler, true);
+ timerAlarmWrite(Dali->timer, 641, true);
+
+ attachInterrupt(Pin(GPIO_DALI_RX), receiveDaliData, FALLING);
+ enableDaliRxInterrupt();
+}
+
+void DaliPwr(uint8_t val){
+ sendDaliData(BROADCAST_DP, val);
+}
+
+bool DaliCmd(void)
+{
+ char command[CMDSZ];
+ uint8_t name_len = strlen(D_NAME_DALI);
+ if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_NAME_DALI), name_len))
+ {
+ uint32_t command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + name_len, kDALI_Commands);
+ switch (command_code)
+ {
+ case CMND_DALI_PWR:
+ if (XdrvMailbox.data_len)
+ {
+ if (254 >= XdrvMailbox.payload)
+ {
+ DaliPwr(XdrvMailbox.payload);
+ }
+ }
+ Response_P(S_JSON_DALI_COMMAND_NVALUE, command, XdrvMailbox.payload);
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+bool DaliMqtt()
+{
+ char stopic[TOPSZ];
+ strncpy(stopic, XdrvMailbox.topic, TOPSZ);
+ XdrvMailbox.topic[TOPSZ - 1] = 0;
+
+ char *items[10];
+ char *p = stopic;
+ int cnt = 0;
+ do
+ {
+ items[cnt] = strtok(p, "/");
+ cnt++;
+ p = nullptr;
+ } while (items[cnt - 1]);
+ cnt--; // repreents the number of items
+
+ if (cnt < 3)
+ { // not for us?
+ AddLog(LOG_LEVEL_INFO,PSTR("cnt: %d < 3"), cnt);
+ return false;
+ }
+
+ int DALIindex = 0;
+ int ADRindex = 0;
+ int CMDindex = 0;
+ uint8_t DALIaddr = BROADCAST_DP;
+ if (strcasecmp_P(items[cnt - 3], PSTR(DALI_TOPIC)) != 0)
+ {
+ if (strcasecmp_P(items[cnt - 2], PSTR(DALI_TOPIC)) != 0)
+ {
+ if (strcasecmp_P(items[cnt - 1], PSTR(DALI_TOPIC)) != 0)
+ {
+ return false; // not for us
+ }
+ else
+ {
+ if (true == DaliJsonParse()) { return true; }
+ }
+ }
+ else
+ {
+ DALIindex = cnt - 2;
+ CMDindex = cnt - 1;
+ }
+ }
+ else
+ {
+ DALIindex = cnt - 3;
+ CMDindex = cnt - 2;
+ ADRindex = cnt - 1;
+ DALIaddr = ((int)CharToFloat(items[ADRindex])) << 1;
+
+ }
+
+ uint8_t level;
+ uint8_t value = (uint8_t)CharToFloat(XdrvMailbox.data);
+ if (strcasecmp_P(items[CMDindex], PSTR("percent")) == 0) {
+ float percent = (float)(254 * value * 0.01);
+ level = (uint8_t)percent;
+ }
+ else if (strcasecmp_P(items[CMDindex], PSTR("level")) == 0) {
+ level = value;
+ }
+ else {
+ AddLog(LOG_LEVEL_INFO,PSTR("command not recognized: %s"), items[CMDindex]);
+ return false; // not for us
+ }
+
+ AddLog(LOG_LEVEL_INFO,PSTR("Dali value %d on address %d"), value, DALIaddr);
+ sendDaliData(DALIaddr, level);
+
+ return true;
+}
+
+bool DaliJsonParse()
+{
+ bool served = false;
+ JsonParser parser((char *)XdrvMailbox.data);
+ JsonParserObject root = parser.getRootObject();
+ if (root)
+ {
+ int DALIindex = 0;
+ int ADRindex = 0;
+ int8_t DALIdim = -1;
+ uint8_t DALIaddr = BROADCAST_DP;
+
+ JsonParserToken val = root[PSTR("cmd")];
+ if (val)
+ {
+ uint8_t cmd = val.getUInt();
+ val = root[PSTR("addr")];
+ if (val)
+ {
+ uint8_t addr = val.getUInt();
+ AddLog(LOG_LEVEL_DEBUG, PSTR("DLI: cmd = %d, addr = %d"), cmd, addr);
+ sendDaliData(addr, cmd);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ val = root[PSTR("addr")];
+ if (val)
+ {
+ uint8_t addr = val.getUInt();
+ if ((addr >= 0) && (addr < 64))
+ DALIaddr = addr << 1;
+ }
+ val = root[PSTR("dim")];
+ if (val)
+ {
+ uint8_t dim = val.getUInt();
+ if (dim < 255)
+ DALIdim = dim;
+ }
+
+ sendDaliData(DALIaddr, DALIdim);
+ served = true;
+ }
+
+ return served;
+}
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xdrv89(uint32_t function)
+{
+ bool result = false;
+
+ if (FUNC_INIT == function)
+ {
+ DaliPreInit();
+ }
+ else if (Dali)
+ {
+ switch (function)
+ {
+ case FUNC_MQTT_DATA:
+ result = DaliMqtt();
+ break;
+ case FUNC_COMMAND:
+ result = DaliCmd();
+ break;
+ }
+ }
+ return result;
+}
+
+#endif // USE_DALI
+#endif // ESP32
\ No newline at end of file
diff --git a/tasmota/tasmota_xdrv_driver/xdrv_90_esp32_dingtian_relay.ino b/tasmota/tasmota_xdrv_driver/xdrv_90_esp32_dingtian_relay.ino
new file mode 100644
index 000000000..5ef54642b
--- /dev/null
+++ b/tasmota/tasmota_xdrv_driver/xdrv_90_esp32_dingtian_relay.ino
@@ -0,0 +1,210 @@
+/*
+ xdrv_90_esp32_dingtian_relay.ino - Dingtian 8, 16, 24 and 32 relays board based on 74x595+74x165
+
+ Copyright (C) 2021 Barbudor
+
+ 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 ESP32
+#ifdef USE_DINGTIAN_RELAY
+
+#define XDRV_90 90
+
+/********************************************************************************************************
+ * Global private data
+ */
+
+struct DINGTIAN_DATA {
+ uint32_t outputs; // keep ouputs state
+ uint32_t last_inputs; // previous inputs state
+ uint8_t count; // number of relay and input (8 * numver of shift registers)
+ uint8_t first; // index of 1st Tasmota relay assigned to 1st Dingtian relays
+ // pins
+ uint8_t pin_clk, pin_sdi, pin_q7, pin_pl, pin_rck;
+} *Dingtian = nullptr;
+
+
+/********************************************************************************************************
+ * Low level operations
+ */
+
+uint32_t DingtianReadWrite(uint32_t outputs)
+{
+ uint32_t inputs = 0;
+ uint32_t in_bit = 1;
+
+ // setup
+ digitalWrite(Dingtian->pin_rck, 0); // rclk and clkinh to 0
+ digitalWrite(Dingtian->pin_pl, 1); // load inputs in '165, ready for shift-in (side effect '595 in tri-state)
+ for ( int i = Dingtian->count ; i > 0 ; i-- ) {
+ // relay out to '595
+ digitalWrite(Dingtian->pin_sdi, outputs & 1);
+ outputs >>= 1;
+ // input from '165
+ inputs |= digitalRead(Dingtian->pin_q7) ? in_bit : 0;
+ in_bit <<= 1;
+ // generate CLK pulse
+ digitalWrite(Dingtian->pin_clk, 1);
+ digitalWrite(Dingtian->pin_clk, 0);
+ }
+ // ending
+ digitalWrite(Dingtian->pin_rck, 1); // rclk pulse to load '595 into output registers
+ digitalWrite(Dingtian->pin_pl, 0); // re-enable '595 ouputs
+
+ return inputs;
+}
+
+/********************************************************************************************************
+ * Driver initialisation
+ */
+
+#define DINGTIAN_SET_OUTPUT(pin,value) { pinMode((pin), OUTPUT); digitalWrite((pin), (value)); }
+#define DINGTIAN_SET_INPUT(pin) { pinMode((pin), INPUT); }
+
+void DingtianInit(void) {
+ if (PinUsed(GPIO_DINGTIAN_CLK, GPIO_ANY) && PinUsed(GPIO_DINGTIAN_SDI) && PinUsed(GPIO_DINGTIAN_Q7)
+ && PinUsed(GPIO_DINGTIAN_PL) && PinUsed(GPIO_DINGTIAN_RCK)) {
+ // allocate Dingtian data structure
+ Dingtian = (struct DINGTIAN_DATA*)calloc(1, sizeof(struct DINGTIAN_DATA));
+ if (Dingtian) {
+ // get pins
+ Dingtian->pin_clk = Pin(GPIO_DINGTIAN_CLK, GPIO_ANY); // shift clock : 595's SCLK & 165's CLK
+ Dingtian->pin_sdi = Pin(GPIO_DINGTIAN_SDI); // Serial out : 595's SER
+ Dingtian->pin_q7 = Pin(GPIO_DINGTIAN_Q7); // Serial in : 165's Q7
+ Dingtian->pin_pl = Pin(GPIO_DINGTIAN_PL); // Input load : 595's nOE & 165's PL (or SH/LD on some datasheet)
+ Dingtian->pin_rck = Pin(GPIO_DINGTIAN_RCK); // Output load : 595's RCLK & 165's CLKINH
+ // number of shift registers is the CLK index
+ Dingtian->count = ((GetPin(Dingtian->pin_clk) - AGPIO(GPIO_DINGTIAN_CLK)) + 1) * 8;
+
+ AddLog(LOG_LEVEL_DEBUG, PSTR("DNGT: clk:%d, sdi:%d, q7:%d, pl:%d, rck:%d, count:%d"),
+ Dingtian->pin_clk, Dingtian->pin_sdi, Dingtian->pin_q7, Dingtian->pin_pl, Dingtian->pin_rck, Dingtian->count);
+
+ DINGTIAN_SET_OUTPUT(Dingtian->pin_clk, 0);
+ DINGTIAN_SET_OUTPUT(Dingtian->pin_sdi, 0);
+ DINGTIAN_SET_INPUT( Dingtian->pin_q7);
+ DINGTIAN_SET_OUTPUT(Dingtian->pin_pl, 0);
+ DINGTIAN_SET_OUTPUT(Dingtian->pin_rck, 0);
+
+ Dingtian->first = TasmotaGlobal.devices_present;
+ TasmotaGlobal.devices_present += Dingtian->count;
+ if (TasGlobal.devices_present > POWER_SIZE) {
+ TasGlobal.devices_present = POWER_SIZE;
+ }
+ AddLog(LOG_LEVEL_DEBUG, PSTR("DNGT: Dingtian relays: POWER%d to POWER%d"), Dingtian->first + 1, TasGlobal.devices_present);
+ }
+ }
+}
+
+/********************************************************************************************************
+ * Driver operations
+ */
+
+void DingtianLoop()
+{
+ uint32_t inputs = DingtianReadWrite(Dingtian->outputs);
+ uint32_t last_inputs = Dingtian->last_inputs;
+ Dingtian->last_inputs = inputs;
+ if (inputs != last_inputs) {
+ AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("DNGT: inputs=0x%08X, last=0x%08X"), inputs, last_inputs);
+ bool first_done = false;
+ ResponseTime_P(PSTR(",\"DINGTIAN_CHG\":{"));
+ for (int i = 0 ; i < Dingtian->count ; i++, last_inputs>>=1, inputs>>=1) {
+ if ((last_inputs & 1) != (inputs & 1)) {
+ if (first_done) ResponseAppend_P(PSTR(","));
+ ResponseAppend_P(PSTR("\"IN%d\":%d"), i +1, (inputs & 1));
+ //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("\"IN%d\":%d"), i +1, (inputs & 1));
+ first_done = true;
+ }
+ }
+ ResponseAppend_P(PSTR("}}"));
+ if (first_done) {
+ MqttPublishPrefixTopicRulesProcess_P(STAT, PSTR("DINGTIAN_CHG"));
+ }
+ }
+}
+
+void DingtianSetPower(void)
+{
+ // store relay status in structure
+ Dingtian->outputs = (XdrvMailbox.index >> Dingtian->first) & ~(0xFFFFFFFF << Dingtian->count);
+ //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("DNGT: outputs=0x%08X"), Dingtian->outputs);
+ DingtianLoop();
+}
+
+/********************************************************************************************************
+ * Driver Results
+ */
+
+const char HTTP_DINGTIAN_INPUTS[] PROGMEM = "{s}DINGTIAN " D_SENSOR_INPUT "%d.." D_SENSOR_INPUT "%d{m}%s{e}";
+
+void DingtianShow(bool json)
+{
+ if (json) {
+ bool first_done = false;
+ ResponseAppend_P(PSTR(",\"DINGTIAN\":{"));
+ for (int i = 0 ; i < Dingtian->count ; i++) {
+ if (first_done) ResponseAppend_P(PSTR(","));
+ ResponseAppend_P(PSTR("\"IN%d\":%d"), i +1, bitRead(Dingtian->last_inputs, i));
+ first_done = true;
+ }
+ ResponseAppend_P(PSTR("}"));
+ }
+#ifdef USE_WEBSERVER
+ else {
+ char input_str[9];
+ for (int block_input = 0 ; block_input < Dingtian->count ; block_input += 8 ) {
+ for (int i = 0 ; i < 8 ; i++ )
+ input_str[i] = '0' + bitRead(Dingtian->last_inputs, block_input +i);
+ input_str[8] = '\0';
+ WSContentSend_P(HTTP_DINGTIAN_INPUTS, block_input, block_input +7, input_str);
+ }
+ }
+#endif
+}
+
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xdrv90(uint32_t function) {
+ bool result = false;
+
+ if (FUNC_PRE_INIT == function) {
+ DingtianInit();
+ } else if (Dingtian) {
+ switch (function) {
+ case FUNC_SET_POWER:
+ DingtianSetPower();
+ break;
+ case FUNC_EVERY_50_MSECOND:
+ //case FUNC_EVERY_250_MSECOND:
+ DingtianLoop();
+ break;
+ case FUNC_JSON_APPEND:
+ DingtianShow(1);
+ break;
+#ifdef USE_WEBSERVER
+ case FUNC_WEB_SENSOR:
+ DingtianShow(0);
+ break;
+#endif // USE_WEBSERVER
+ }
+ }
+ return result;
+}
+
+#endif // USE_DINGTIAN_RELAY
+#endif // ESP32
diff --git a/tasmota/tasmota_xdsp_display/xdsp_01_lcd.ino b/tasmota/tasmota_xdsp_display/xdsp_01_lcd.ino
index d7ec6ac2a..2dff946f2 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_01_lcd.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_01_lcd.ino
@@ -197,7 +197,7 @@ void LcdRefresh(void) // Every second
* Interface
\*********************************************************************************************/
-bool Xdsp01(uint8_t function)
+bool Xdsp01(uint32_t function)
{
if (!I2cEnabled(XI2C_03)) { return false; }
diff --git a/tasmota/tasmota_xdsp_display/xdsp_02_ssd1306.ino b/tasmota/tasmota_xdsp_display/xdsp_02_ssd1306.ino
index 0d1fc27e2..5f9657069 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_02_ssd1306.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_02_ssd1306.ino
@@ -167,8 +167,7 @@ void Ssd1306Refresh(void) // Every second
* Interface
\*********************************************************************************************/
-bool Xdsp02(byte function)
-{
+bool Xdsp02(uint32_t function) {
if (!I2cEnabled(XI2C_04)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xdsp_display/xdsp_03_matrix.ino b/tasmota/tasmota_xdsp_display/xdsp_03_matrix.ino
index 09d8b8587..c314d4982 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_03_matrix.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_03_matrix.ino
@@ -333,7 +333,7 @@ void MatrixRefresh(void) // Every second
* Interface
\*********************************************************************************************/
-bool Xdsp03(uint8_t function)
+bool Xdsp03(uint32_t function)
{
if (!I2cEnabled(XI2C_05)) { return false; }
diff --git a/tasmota/tasmota_xdsp_display/xdsp_04_ili9341.ino b/tasmota/tasmota_xdsp_display/xdsp_04_ili9341.ino
index 3b6a8de9f..96dae6558 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_04_ili9341.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_04_ili9341.ino
@@ -366,7 +366,7 @@ void ILI9341_Refresh(void) { // Every second
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
-bool Xdsp04(uint8_t function)
+bool Xdsp04(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdsp_display/xdsp_05_epaper_29.ino b/tasmota/tasmota_xdsp_display/xdsp_05_epaper_29.ino
index 54a3eac8a..46f8dabe2 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_05_epaper_29.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_05_epaper_29.ino
@@ -178,7 +178,7 @@ void EpdRefresh29(void) // Every second
* Interface
\*********************************************************************************************/
-bool Xdsp05(uint8_t function)
+bool Xdsp05(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdsp_display/xdsp_06_epaper_42.ino b/tasmota/tasmota_xdsp_display/xdsp_06_epaper_42.ino
index d0baef8ab..f8f59bd7f 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_06_epaper_42.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_06_epaper_42.ino
@@ -118,7 +118,7 @@ void EpdRefresh42() // Every second
* Interface
\*********************************************************************************************/
-bool Xdsp06(uint8_t function)
+bool Xdsp06(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdsp_display/xdsp_07_sh1106.ino b/tasmota/tasmota_xdsp_display/xdsp_07_sh1106.ino
index a8434f820..689e2273c 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_07_sh1106.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_07_sh1106.ino
@@ -165,7 +165,7 @@ void SH1106Refresh(void) // Every second
* Interface
\*********************************************************************************************/
-bool Xdsp07(uint8_t function)
+bool Xdsp07(uint32_t function)
{
if (!I2cEnabled(XI2C_06)) { return false; }
diff --git a/tasmota/tasmota_xdsp_display/xdsp_09_SSD1351.ino b/tasmota/tasmota_xdsp_display/xdsp_09_SSD1351.ino
index 8a30ad2c8..ffb47f425 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_09_SSD1351.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_09_SSD1351.ino
@@ -153,7 +153,7 @@ void SSD1351Refresh(void) { // Every second
* Interface
\*********************************************************************************************/
-bool Xdsp09(uint8_t function) {
+bool Xdsp09(uint32_t function) {
bool result = false;
if (FUNC_DISPLAY_INIT_DRIVER == function) {
diff --git a/tasmota/tasmota_xdsp_display/xdsp_10_RA8876.ino b/tasmota/tasmota_xdsp_display/xdsp_10_RA8876.ino
index 80c5b4f0f..33b4fc438 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_10_RA8876.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_10_RA8876.ino
@@ -297,7 +297,7 @@ Serial.print("Text test took "); Serial.print(elapsedtime); Serial.println(" ms"
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
-bool Xdsp10(uint8_t function)
+bool Xdsp10(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdsp_display/xdsp_11_sevenseg.ino b/tasmota/tasmota_xdsp_display/xdsp_11_sevenseg.ino
index f2c48adb9..bb8792259 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_11_sevenseg.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_11_sevenseg.ino
@@ -422,7 +422,7 @@ void SevensegRefresh(void) // Every second
* Interface
\*********************************************************************************************/
-bool Xdsp11(uint8_t function)
+bool Xdsp11(uint32_t function)
{
if (!I2cEnabled(XI2C_47)) { return false; }
diff --git a/tasmota/tasmota_xdsp_display/xdsp_12_ST7789.ino b/tasmota/tasmota_xdsp_display/xdsp_12_ST7789.ino
index 6553fc6a1..2b3c818ae 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_12_ST7789.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_12_ST7789.ino
@@ -176,7 +176,7 @@ st7789_ctouch_counter++;
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
-bool Xdsp12(uint8_t function)
+bool Xdsp12(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdsp_display/xdsp_14_SSD1331.ino b/tasmota/tasmota_xdsp_display/xdsp_14_SSD1331.ino
index 3d531d229..e455a66ce 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_14_SSD1331.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_14_SSD1331.ino
@@ -169,7 +169,7 @@ void SSD1331Refresh(void) { // Every second
* Interface
\*********************************************************************************************/
-bool Xdsp14(uint8_t function) {
+bool Xdsp14(uint32_t function) {
bool result = false;
if (FUNC_DISPLAY_INIT_DRIVER == function) {
diff --git a/tasmota/tasmota_xdsp_display/xdsp_15_tm1637.ino b/tasmota/tasmota_xdsp_display/xdsp_15_tm1637.ino
index a7daf61bf..0deb8d4a8 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_15_tm1637.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_15_tm1637.ino
@@ -987,9 +987,12 @@ bool CmndTM1637Clock(void)
\*********************************************************************************************/
void TM1637ShowTime()
{
- uint8_t hr = RtcTime.hour;
- uint8_t mn = RtcTime.minute;
- uint8_t sc = RtcTime.second;
+ struct TIME_T t = RtcTime;
+ BreakNanoTime(Rtc.local_time, Rtc.nanos + (millis() - Rtc.millis) * 1000000, t);
+ uint8_t hr = t.hour;
+ uint8_t mn = t.minute;
+ uint8_t sc = t.second;
+ uint16_t ms = t.nanos / 1000000;
if (!TM1637Data.clock_24)
{
@@ -1009,12 +1012,14 @@ void TM1637ShowTime()
if (TM1637 == TM1637Data.display_type)
{
+ uint8_t colon = ms > 500? 0: 128;
uint8_t rawBytes[1];
- for (uint32_t i = 0; i < 4; i++)
+ uint8_t width = Settings->display_width >= 6? 6: 4;
+ for (uint32_t i = 0; i < width; i++)
{
rawBytes[0] = tm1637display->encode(tm[i]);
- if ((millis() % 1000) > 500 && (i == 1))
- rawBytes[0] = rawBytes[0] | 128;
+ if (i == 1 || (i == 3 && width > 4))
+ rawBytes[0] = rawBytes[0] | colon;
tm1637display->printRaw(rawBytes, 1, TM1637Data.digit_order[i]);
}
}
@@ -1279,7 +1284,7 @@ void TM1637Refresh(void)
* Interface
\*********************************************************************************************/
-bool Xdsp15(uint8_t function)
+bool Xdsp15(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdsp_display/xdsp_16_esp32_epaper_47.ino b/tasmota/tasmota_xdsp_display/xdsp_16_esp32_epaper_47.ino
index bc6473efe..15b79955c 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_16_esp32_epaper_47.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_16_esp32_epaper_47.ino
@@ -278,7 +278,7 @@ void EPD47_CheckTouch(void) {
* Interface
\*********************************************************************************************/
-bool Xdsp16(uint8_t function)
+bool Xdsp16(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino b/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino
index 6a1f970da..3a24870d4 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_17_universal.ino
@@ -481,7 +481,7 @@ void UDISP_Refresh(void) // Every second
* Interface
\*********************************************************************************************/
-bool Xdsp17(uint8_t function) {
+bool Xdsp17(uint32_t function) {
bool result = false;
if (FUNC_DISPLAY_INIT_DRIVER == function) {
diff --git a/tasmota/tasmota_xdsp_display/xdsp_18_berry_display.ino b/tasmota/tasmota_xdsp_display/xdsp_18_berry_display.ino
index 11875692e..98ace0f0c 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_18_berry_display.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_18_berry_display.ino
@@ -26,7 +26,7 @@
* Interface
\*********************************************************************************************/
-bool Xdsp18(uint8_t function) {
+bool Xdsp18(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xdsp_display/xdsp_19_max7219_matrix.ino b/tasmota/tasmota_xdsp_display/xdsp_19_max7219_matrix.ino
index 3e1a5c258..fca13278b 100644
--- a/tasmota/tasmota_xdsp_display/xdsp_19_max7219_matrix.ino
+++ b/tasmota/tasmota_xdsp_display/xdsp_19_max7219_matrix.ino
@@ -305,7 +305,7 @@ bool MAX7291Matrix_showTime()
#endif // USE_DISPLAY_MODES1TO5
-bool Xdsp19(uint8_t function)
+bool Xdsp19(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xlgt_light/xlgt_01_ws2812.ino b/tasmota/tasmota_xlgt_light/xlgt_01_ws2812.ino
index 715851e4c..c0f7ff7e5 100644
--- a/tasmota/tasmota_xlgt_light/xlgt_01_ws2812.ino
+++ b/tasmota/tasmota_xlgt_light/xlgt_01_ws2812.ino
@@ -669,20 +669,37 @@ void Ws2812ShowScheme(void)
}
}
-void Ws2812ModuleSelected(void)
+bool Ws2812ReinitStrip(void)
{
+ if (strip != nullptr) {
+ Ws2812Clear();
+ if (!strip->CanShow()) {
+ // we're doing DMA, so wait for a decent amount of time
+ delay(10);
+ }
+ delete strip;
+ strip = nullptr;
+ }
+
#if (USE_WS2812_HARDWARE == NEO_HW_P9813)
if (PinUsed(GPIO_P9813_CLK) && PinUsed(GPIO_P9813_DAT)) { // RGB led
- strip = new NeoPixelBus(WS2812_MAX_LEDS, Pin(GPIO_P9813_CLK), Pin(GPIO_P9813_DAT));
+ strip = new NeoPixelBus(Settings->light_pixels, Pin(GPIO_P9813_CLK), Pin(GPIO_P9813_DAT));
#else
if (PinUsed(GPIO_WS2812)) { // RGB led
// For DMA, the Pin is ignored as it uses GPIO3 due to DMA hardware use.
- strip = new NeoPixelBus(WS2812_MAX_LEDS, Pin(GPIO_WS2812));
+ strip = new NeoPixelBus(Settings->light_pixels, Pin(GPIO_WS2812));
#endif // NEO_HW_P9813
strip->Begin();
Ws2812Clear();
+ return true;
+ }
+ return false;
+}
+void Ws2812ModuleSelected(void)
+{
+ if (Ws2812ReinitStrip()) {
Ws2812.scheme_offset = Light.max_scheme +1;
Light.max_scheme += WS2812_SCHEMES;
@@ -725,7 +742,7 @@ void CmndPixels(void)
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= WS2812_MAX_LEDS)) {
Settings->light_pixels = XdrvMailbox.payload;
Settings->light_rotation = 0;
- Ws2812Clear();
+ Ws2812ReinitStrip();
Light.update = true;
}
ResponseCmndNumber(Settings->light_pixels);
@@ -735,7 +752,7 @@ void CmndStepPixels(void)
{
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 255)) {
Settings->light_step_pixels = (XdrvMailbox.payload > WS2812_MAX_LEDS) ? WS2812_MAX_LEDS : XdrvMailbox.payload;
- Ws2812Clear();
+ Ws2812ReinitStrip();
Light.update = true;
}
ResponseCmndNumber(Settings->light_step_pixels);
@@ -767,11 +784,38 @@ void CmndWidth(void)
}
}
+/*********************************************************************************************\
+ * Internal calls for ArtNet
+\*********************************************************************************************/
+// check is the Neopixel strip is configured
+bool Ws2812StripConfigured(void) {
+ return strip != nullptr;
+}
+size_t Ws2812StripGetPixelSize(void) {
+ return strip->PixelSize();
+}
+// return true if strip was dirty and an actual refresh was triggered
+bool Ws2812StripRefresh(void) {
+ if (strip->IsDirty()) {
+ strip->Show();
+ return true;
+ } else {
+ return false;
+ }
+}
+void Ws2812CopyPixels(const uint8_t *buf, size_t len, size_t offset_in_matrix) {
+ uint8_t *pixels = strip->Pixels();
+ memmove(&pixels[offset_in_matrix], buf, len);
+ strip->Dirty();
+}
+
+
+
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
-bool Xlgt01(uint8_t function)
+bool Xlgt01(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xlgt_light/xlgt_02_my92x1.ino b/tasmota/tasmota_xlgt_light/xlgt_02_my92x1.ino
index ef23c3c9c..ec72df8d8 100644
--- a/tasmota/tasmota_xlgt_light/xlgt_02_my92x1.ino
+++ b/tasmota/tasmota_xlgt_light/xlgt_02_my92x1.ino
@@ -148,7 +148,7 @@ void My92x1ModuleSelected(void)
* Interface
\*********************************************************************************************/
-bool Xlgt02(uint8_t function)
+bool Xlgt02(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xlgt_light/xlgt_03_sm16716.ino b/tasmota/tasmota_xlgt_light/xlgt_03_sm16716.ino
index b1d4207b8..407ed67b9 100644
--- a/tasmota/tasmota_xlgt_light/xlgt_03_sm16716.ino
+++ b/tasmota/tasmota_xlgt_light/xlgt_03_sm16716.ino
@@ -170,7 +170,7 @@ void Sm16716ModuleSelected(void)
* Interface
\*********************************************************************************************/
-bool Xlgt03(uint8_t function)
+bool Xlgt03(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xlgt_light/xlgt_04_sm2135.ino b/tasmota/tasmota_xlgt_light/xlgt_04_sm2135.ino
index a9f49c3d1..0c9b86ef0 100644
--- a/tasmota/tasmota_xlgt_light/xlgt_04_sm2135.ino
+++ b/tasmota/tasmota_xlgt_light/xlgt_04_sm2135.ino
@@ -70,7 +70,7 @@ enum Sm2135Color { SM2135_WCGRB, // 1 (4064) - Action LSC GRB (20mA) an
SM2135_WCBGR15W, // 6 (4069) - BGR (45mA) and CW (60mA)
SM2135_WCBRG_SETALL, // 7 (4070) - Fitop 10W RGBCCT BRG (15mA) and CW (40mA)
SM2135_RESERVED_8, // 8 (4071) - Reserved - currently fallsback to 2
- SM2135_WCGRB_ALL, // 9 (4072) - GRB (20mA) and CW (15mA) like 1 but reset either RGB or CW
+ SM2135_WCGRB_ALL, // 9 (4072) - Qualitel GRB (20mA) and CW (15mA) like 1 but reset either RGB or CW
SM2135_WCBGR_ALL // 10 (4073) - BGR (20mA) and CW (15mA) like 2 but reset either RGB or CW
};
@@ -227,7 +227,7 @@ void Sm2135ModuleSelected(void)
Sm2135.clk = Pin(GPIO_SM2135_CLK);
Sm2135.data = Pin(GPIO_SM2135_DAT, GPIO_ANY);
- // See #define MAX_SM2135_DAT 7 in tasmota_template.h
+ // See #define MAX_SM2135_DAT 10 in tasmota_template.h
Sm2135.model = GetPin(Sm2135.data) - AGPIO(GPIO_SM2135_DAT); // 0 .. 9
// Legacy support of model selection
@@ -271,7 +271,7 @@ void Sm2135ModuleSelected(void)
* Interface
\*********************************************************************************************/
-bool Xlgt04(uint8_t function)
+bool Xlgt04(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xlgt_light/xlgt_05_sonoff_l1.ino b/tasmota/tasmota_xlgt_light/xlgt_05_sonoff_l1.ino
index 080bc9c7a..8e793761f 100644
--- a/tasmota/tasmota_xlgt_light/xlgt_05_sonoff_l1.ino
+++ b/tasmota/tasmota_xlgt_light/xlgt_05_sonoff_l1.ino
@@ -399,7 +399,7 @@ void CmndMusicSync(void) {
* Interface
\*********************************************************************************************/
-bool Xlgt05(uint8_t function)
+bool Xlgt05(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xlgt_light/xlgt_06_electriq_moodl.ino b/tasmota/tasmota_xlgt_light/xlgt_06_electriq_moodl.ino
index f6bef1ff5..da984ab05 100644
--- a/tasmota/tasmota_xlgt_light/xlgt_06_electriq_moodl.ino
+++ b/tasmota/tasmota_xlgt_light/xlgt_06_electriq_moodl.ino
@@ -82,7 +82,7 @@ void ElectriqMoodLModuleSelected(void)
* Interface
\*********************************************************************************************/
-bool Xlgt06(uint8_t function)
+bool Xlgt06(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xlgt_light/xlgt_07_lsc_mcsl.ino b/tasmota/tasmota_xlgt_light/xlgt_07_lsc_mcsl.ino
index d7c9bbfd2..75bbd7102 100644
--- a/tasmota/tasmota_xlgt_light/xlgt_07_lsc_mcsl.ino
+++ b/tasmota/tasmota_xlgt_light/xlgt_07_lsc_mcsl.ino
@@ -294,7 +294,7 @@ void LscMcWebGetArg(void) {
* Interface
\*********************************************************************************************/
-bool Xlgt07(uint8_t function)
+bool Xlgt07(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xlgt_light/xlgt_08_bp5758d.ino b/tasmota/tasmota_xlgt_light/xlgt_08_bp5758d.ino
index f0035180f..8bcee5894 100644
--- a/tasmota/tasmota_xlgt_light/xlgt_08_bp5758d.ino
+++ b/tasmota/tasmota_xlgt_light/xlgt_08_bp5758d.ino
@@ -114,6 +114,7 @@ bool Bp5758dSetChannels(void) {
if (cur_col_10[0]==0 && cur_col_10[1]==0 && cur_col_10[2]==0 && cur_col_10[3]==0 && cur_col_10[4]==0) {
Bp5758dStart(BP5758D_ADDR_SETUP);
Bp5758dWrite(BP5758D_DISABLE_OUTPUTS_ALL);
+ Bp5758dStop();
Bp5758dStart(BP5758D_ADDR_SLEEP);
Bp5758dStop();
bIsSleeping = true;
@@ -186,7 +187,7 @@ void Bp5758dModuleSelected(void)
* Interface
\*********************************************************************************************/
-bool Xlgt08(uint8_t function)
+bool Xlgt08(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xlgt_light/xlgt_09_sm2335.ino b/tasmota/tasmota_xlgt_light/xlgt_09_sm2335.ino
index eb4c8f035..9d09f2068 100644
--- a/tasmota/tasmota_xlgt_light/xlgt_09_sm2335.ino
+++ b/tasmota/tasmota_xlgt_light/xlgt_09_sm2335.ino
@@ -157,7 +157,7 @@ void SM2335ModuleSelected(void)
* Interface
\*********************************************************************************************/
-bool Xlgt09(uint8_t function)
+bool Xlgt09(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xlgt_light/xlgt_10_bp1658cj.ino b/tasmota/tasmota_xlgt_light/xlgt_10_bp1658cj.ino
new file mode 100644
index 000000000..d9ec3e194
--- /dev/null
+++ b/tasmota/tasmota_xlgt_light/xlgt_10_bp1658cj.ino
@@ -0,0 +1,179 @@
+/*
+ xlgt_10_bp1658cj.ino - bp1658cj five channel led support for Tasmota
+
+ Copyright (C) 2022 Theo Arends and Cossid
+
+ 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_LIGHT
+#ifdef USE_BP1658CJ
+/*********************************************************************************************\
+ * BP1658CJ RGBCW Led bulbs like the Orein OS0100411267 Bulb
+ *
+ * Orein OS0100411267 Bulb
+ *
+ *
+ * FIXME
+ * {"NAME":"Orein OS0100411267 Bulb","GPIO":[0,0,0,0,9129,9088,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":1}
+\*********************************************************************************************/
+
+#define XLGT_10 10
+
+// 10 = identification | 00 = Standby | 0000 = start at OUT1/5
+#define BP1658CJ_ADDR_STANDBY 0x80 // 10000000 0x80
+// 10 = identification | 01 = 3 channels (RGB) | 0000 = start at OUT1/5
+//#define BP1658CJ_ADDR_START_3CH 0x90 // 10010000 0xC8
+// 10 = identification | 10 = 2 channels (CW) | 0000 = start at OUT1/5
+//#define BP1658CJ_ADDR_START_2CH 0xA0 // 10100000 0xA0
+// 10 = identification | 11 = 5 channels (RGB+CW) | 0000 = start at OUT1/5
+#define BP1658CJ_ADDR_START_5CH 0xB0 // 10110000 0xB0
+
+// Current values
+// 0x0 // 0000 RGB 0mA | CW 0mA
+// 0x1 // 0001 RGB 10mA | CW 5mA
+// 0x2 // 0010 RGB 20mA | CW 10mA
+// 0x3 // 0011 RGB 30mA | CW 15mA
+// 0x4 // 0100 RGB 40mA | CW 20mA
+// 0x5 // 0101 RGB 50mA | CW 25mA
+// 0x6 // 0110 RGB 60mA | CW 30mA
+// 0x7 // 0111 RGB 70mA | CW 35mA
+// 0x8 // 1000 RGB 80mA | CW 40mA
+// 0x9 // 1001 RGB 900mA | CW 45mA
+// 0xA // 1010 RGB 100mA | CW 50mA
+// 0xB // 1011 RGB 110mA | CW 55mA
+// 0xC // 1100 RGB 120mA | CW 60mA
+// 0xD // 1101 RGB 130mA | CW 65mA
+// 0xE // 1110 RGB 140mA | CW 70mA
+// 0xF // 1111 RGB 150mA | CW 75mA
+
+struct BP1658CJ {
+ uint8_t clk = 0;
+ uint8_t data = 0;
+ uint8_t current;
+} Bp1658cj;
+
+/*********************************************************************************************\
+ * BP1658CJ code - inspired by Bp5758d/SM2335
+\*********************************************************************************************/
+const uint8_t BP1658CJ_DELAY = 2;
+
+void BP1658CJInit(void) {
+ pinMode(Bp1658cj.data, OUTPUT);
+ pinMode(Bp1658cj.clk, OUTPUT);
+ BP1658CJStop();
+}
+
+void BP1658CJWrite(uint8_t value) {
+ for (int bit_idx = 7; bit_idx >= 0; bit_idx--) {
+ bool bit = bitRead(value, bit_idx);
+ digitalWrite(Bp1658cj.data, bit);
+ delayMicroseconds(BP1658CJ_DELAY);
+ digitalWrite(Bp1658cj.clk, HIGH);
+ delayMicroseconds(BP1658CJ_DELAY);
+ digitalWrite(Bp1658cj.clk, LOW);
+ delayMicroseconds(BP1658CJ_DELAY);
+ }
+ // Wait for ACK
+ pinMode(Bp1658cj.data, INPUT);
+ digitalWrite(Bp1658cj.clk, HIGH);
+ delayMicroseconds(BP1658CJ_DELAY);
+ digitalWrite(Bp1658cj.clk, LOW);
+ delayMicroseconds(BP1658CJ_DELAY);
+ pinMode(Bp1658cj.data, OUTPUT);
+}
+
+void BP1658CJStart(uint8_t addr) {
+ digitalWrite(Bp1658cj.data, LOW);
+ delayMicroseconds(BP1658CJ_DELAY);
+ digitalWrite(Bp1658cj.clk, LOW);
+ delayMicroseconds(BP1658CJ_DELAY);
+ BP1658CJWrite(addr);
+}
+
+void BP1658CJStop(void) {
+ digitalWrite(Bp1658cj.clk, HIGH);
+ delayMicroseconds(BP1658CJ_DELAY);
+ digitalWrite(Bp1658cj.data, HIGH);
+ delayMicroseconds(BP1658CJ_DELAY);
+}
+
+/********************************************************************************************/
+
+bool BP1658CJSetChannels(void) {
+ uint16_t *cur_col_10 = (uint16_t*)XdrvMailbox.command;
+
+ // If we receive 0 for all channels, we'll assume that the lightbulb is off, and activate BP1658CJ's standby mode.
+ if (cur_col_10[0] == 0 && cur_col_10[1] == 0 && cur_col_10[2] == 0 && cur_col_10[3] == 0 && cur_col_10[4] == 0) {
+ BP1658CJStart(BP1658CJ_ADDR_STANDBY);
+ // Clear all remaining data. This clears out Current, Red, Green, Blue, Cold White, Warm White.
+ for (int i = 0; i < 11; i++) {
+ BP1658CJWrite(0);
+ }
+ BP1658CJStop();
+ return true;
+ }
+
+ // Write the header activating all 5 channels
+ BP1658CJStart(BP1658CJ_ADDR_START_5CH);
+ // Set the current defined in ModuleSelected.
+ BP1658CJWrite(Bp1658cj.current);
+ // Set RGB and CW grayscale.
+ for (int i = 0; i < 5; i++) {
+ BP1658CJWrite((uint8_t)(cur_col_10[i] & 0x1F));
+ BP1658CJWrite((uint8_t)(cur_col_10[i] >> 5));
+ }
+ BP1658CJStop();
+ return true;
+}
+
+void BP1658CJModuleSelected(void)
+{
+ if (PinUsed(GPIO_BP1658CJ_CLK) && PinUsed(GPIO_BP1658CJ_DAT, GPIO_ANY)) {
+ Bp1658cj.clk = Pin(GPIO_BP1658CJ_CLK);
+ Bp1658cj.data = Pin(GPIO_BP1658CJ_DAT, GPIO_ANY);
+ // See #define MAX_BP1658CJ_DAT 16 in tasmota_template.h
+ int currentDat = GetPin(Bp1658cj.data) - AGPIO(GPIO_BP1658CJ_DAT); // 0 .. 15
+ // Split RGB and CW current.
+ Bp1658cj.current = (currentDat << 4) | currentDat;
+
+ BP1658CJInit();
+
+ TasmotaGlobal.light_type = LT_RGBWC;
+ TasmotaGlobal.light_driver = XLGT_10;
+ AddLog(LOG_LEVEL_DEBUG, PSTR("LGT: BP1658CJ Found"));
+ }
+}
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xlgt10(uint32_t function)
+{
+ bool result = false;
+
+ switch (function) {
+ case FUNC_SET_CHANNELS:
+ result = BP1658CJSetChannels();
+ break;
+ case FUNC_MODULE_INIT:
+ BP1658CJModuleSelected();
+ break;
+ }
+ return result;
+}
+
+#endif // USE_BP1658CJ
+#endif // USE_LIGHT
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_01_hlw8012.ino b/tasmota/tasmota_xnrg_energy/xnrg_01_hlw8012.ino
index 883dfdbb2..cfbd76d94 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_01_hlw8012.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_01_hlw8012.ino
@@ -290,17 +290,17 @@ bool HlwCommand(void) {
}
else if (CMND_POWERSET == Energy.command_code) {
if (XdrvMailbox.data_len && Hlw.cf_power_pulse_length ) {
- Settings->energy_power_calibration = ((uint32_t)(CharToFloat(XdrvMailbox.data) * 10) * Hlw.cf_power_pulse_length ) / Hlw.power_ratio;
+ XdrvMailbox.payload = ((uint32_t)(CharToFloat(XdrvMailbox.data) * 10) * Hlw.cf_power_pulse_length ) / Hlw.power_ratio;
}
}
else if (CMND_VOLTAGESET == Energy.command_code) {
if (XdrvMailbox.data_len && Hlw.cf1_voltage_pulse_length ) {
- Settings->energy_voltage_calibration = ((uint32_t)(CharToFloat(XdrvMailbox.data) * 10) * Hlw.cf1_voltage_pulse_length ) / Hlw.voltage_ratio;
+ XdrvMailbox.payload = ((uint32_t)(CharToFloat(XdrvMailbox.data) * 10) * Hlw.cf1_voltage_pulse_length ) / Hlw.voltage_ratio;
}
}
else if (CMND_CURRENTSET == Energy.command_code) {
if (XdrvMailbox.data_len && Hlw.cf1_current_pulse_length) {
- Settings->energy_current_calibration = ((uint32_t)(CharToFloat(XdrvMailbox.data)) * Hlw.cf1_current_pulse_length) / Hlw.current_ratio;
+ XdrvMailbox.payload = ((uint32_t)(CharToFloat(XdrvMailbox.data)) * Hlw.cf1_current_pulse_length) / Hlw.current_ratio;
}
}
else serviced = false; // Unknown command
@@ -312,7 +312,7 @@ bool HlwCommand(void) {
* Interface
\*********************************************************************************************/
-bool Xnrg01(uint8_t function) {
+bool Xnrg01(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino b/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino
index 296bd6520..fd2ccc11e 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_02_cse7766.ino
@@ -63,7 +63,8 @@ void CseReceived(void) {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
// F2 5A 02 F7 60 00 03 61 00 40 10 05 72 40 51 A6 58 63 10 1B E1 7F 4D 4E - F2 = Power cycle exceeds range - takes too long - No load
// 55 5A 02 F7 60 00 03 5A 00 40 10 04 8B 9F 51 A6 58 18 72 75 61 AC A1 30 - 55 = Ok, 61 = Power not valid (load below 5W)
- // 55 5A 02 F7 60 00 03 AB 00 40 10 02 60 5D 51 A6 58 03 E9 EF 71 0B 7A 36 - 55 = Ok, 71 = Ok
+ // 55 5A 02 F7 60 00 03 AB 00 40 10 02 60 5D 51 A6 58 03 E9 EF 71 0B 7A 36 - 55 = Ok, 71 = Ok, F1 = CF overflow, no problem
+ // 55 5A 02 F1 E8 00 07 9D 00 3F 3E 00 35 F8 50 DB 38 00 B2 A2 F1 D6 97 3E - CF overflow
// 55 5A 02 DB 40 00 03 25 00 3D 18 03 8E CD 4F 0A 60 2A 56 85 61 01 02 1A - OK voltage
// 55 5A 02 DB 40 07 17 1D 00 3D 18 03 8E CD 4F 0A 60 2B EF EA 61 01 02 2C - Wrong voltage
@@ -256,17 +257,17 @@ bool CseCommand(void) {
if (CMND_POWERSET == Energy.command_code) {
if (XdrvMailbox.data_len && Cse.power_cycle) {
- Settings->energy_power_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.power_cycle) / CSE_PREF;
+ XdrvMailbox.payload = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.power_cycle) / CSE_PREF;
}
}
else if (CMND_VOLTAGESET == Energy.command_code) {
if (XdrvMailbox.data_len && Cse.voltage_cycle) {
- Settings->energy_voltage_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.voltage_cycle) / CSE_UREF;
+ XdrvMailbox.payload = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.voltage_cycle) / CSE_UREF;
}
}
else if (CMND_CURRENTSET == Energy.command_code) {
if (XdrvMailbox.data_len && Cse.current_cycle) {
- Settings->energy_current_calibration = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.current_cycle) / 1000;
+ XdrvMailbox.payload = (unsigned long)(CharToFloat(XdrvMailbox.data) * Cse.current_cycle) / 1000;
}
}
else serviced = false; // Unknown command
@@ -278,7 +279,7 @@ bool CseCommand(void) {
* Interface
\*********************************************************************************************/
-bool Xnrg02(uint8_t function) {
+bool Xnrg02(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_03_pzem004t.ino b/tasmota/tasmota_xnrg_energy/xnrg_03_pzem004t.ino
index a9df4cd0b..7e6dc699b 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_03_pzem004t.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_03_pzem004t.ino
@@ -279,7 +279,7 @@ bool PzemCommand(void)
* Interface
\*********************************************************************************************/
-bool Xnrg03(uint8_t function)
+bool Xnrg03(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_04_mcp39f501.ino b/tasmota/tasmota_xnrg_energy/xnrg_04_mcp39f501.ino
index 7601731a4..631fe9919 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_04_mcp39f501.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_04_mcp39f501.ino
@@ -602,7 +602,7 @@ bool McpCommand(void)
if (XdrvMailbox.data_len && mcp_active_power) {
value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 100);
if ((value > 100) && (value < 200000)) { // Between 1W and 2000W
- Settings->energy_power_calibration = value;
+ XdrvMailbox.payload = value;
mcp_calibrate |= MCP_CALIBRATE_POWER;
McpGetCalibration();
}
@@ -612,7 +612,7 @@ bool McpCommand(void)
if (XdrvMailbox.data_len && mcp_voltage_rms) {
value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 10);
if ((value > 1000) && (value < 2600)) { // Between 100V and 260V
- Settings->energy_voltage_calibration = value;
+ XdrvMailbox.payload = value;
mcp_calibrate |= MCP_CALIBRATE_VOLTAGE;
McpGetCalibration();
}
@@ -622,7 +622,7 @@ bool McpCommand(void)
if (XdrvMailbox.data_len && mcp_current_rms) {
value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 10);
if ((value > 100) && (value < 80000)) { // Between 10mA and 8A
- Settings->energy_current_calibration = value;
+ XdrvMailbox.payload = value;
mcp_calibrate |= MCP_CALIBRATE_CURRENT;
McpGetCalibration();
}
@@ -632,7 +632,7 @@ bool McpCommand(void)
if (XdrvMailbox.data_len && mcp_line_frequency) {
value = (unsigned long)(CharToFloat(XdrvMailbox.data) * 1000);
if ((value > 45000) && (value < 65000)) { // Between 45Hz and 65Hz
- Settings->energy_frequency_calibration = value;
+ XdrvMailbox.payload = value;
mcp_calibrate |= MCP_CALIBRATE_FREQUENCY;
McpGetFrequency();
}
@@ -647,7 +647,7 @@ bool McpCommand(void)
* Interface
\*********************************************************************************************/
-bool Xnrg04(uint8_t function)
+bool Xnrg04(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_05_pzem_ac.ino b/tasmota/tasmota_xnrg_energy/xnrg_05_pzem_ac.ino
index 21c50a4ff..e07fcb566 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_05_pzem_ac.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_05_pzem_ac.ino
@@ -114,7 +114,7 @@ void PzemAcEverySecond(void)
void PzemAcSnsInit(void)
{
- PzemAcModbus = new TasmotaModbus(Pin(GPIO_PZEM016_RX), Pin(GPIO_PZEM0XX_TX));
+ PzemAcModbus = new TasmotaModbus(Pin(GPIO_PZEM016_RX), Pin(GPIO_PZEM0XX_TX), Pin(GPIO_NRG_MBS_TX_ENA));
uint8_t result = PzemAcModbus->Begin(9600);
if (result) {
if (2 == result) { ClaimSerial(); }
@@ -149,7 +149,7 @@ bool PzemAcCommand(void)
* Interface
\*********************************************************************************************/
-bool Xnrg05(uint8_t function)
+bool Xnrg05(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_06_pzem_dc.ino b/tasmota/tasmota_xnrg_energy/xnrg_06_pzem_dc.ino
index 1c6841154..06dcf3bb8 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_06_pzem_dc.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_06_pzem_dc.ino
@@ -111,7 +111,7 @@ void PzemDcEverySecond(void)
void PzemDcSnsInit(void)
{
- PzemDcModbus = new TasmotaModbus(Pin(GPIO_PZEM017_RX), Pin(GPIO_PZEM0XX_TX));
+ PzemDcModbus = new TasmotaModbus(Pin(GPIO_PZEM017_RX), Pin(GPIO_PZEM0XX_TX), Pin(GPIO_NRG_MBS_TX_ENA));
uint8_t result = PzemDcModbus->Begin(9600, SERIAL_8N2);
if (result) {
if (2 == result) { ClaimSerial(); }
@@ -147,7 +147,7 @@ bool PzemDcCommand(void)
* Interface
\*********************************************************************************************/
-bool Xnrg06(uint8_t function)
+bool Xnrg06(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino
index 6b01b4b61..f30619274 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_07_ade7953.ino
@@ -17,29 +17,40 @@
along with this program. If not, see .
*/
-#ifdef USE_I2C
+#if defined(ESP32) && defined(USE_SPI)
+#define USE_ESP32_SPI
+#endif
+#if defined(USE_I2C) || defined(USE_ESP32_SPI)
#ifdef USE_ENERGY_SENSOR
#ifdef USE_ADE7953
/*********************************************************************************************\
- * ADE7953 - Energy used in Shelly 2.5 (model 1), Shelly EM (model 2) and Shelly Plus 2PM (model 3)
+ * ADE7953 - Energy used in Shelly 2.5 (model 1), Shelly EM (model 2), Shelly Plus 2PM (model 3), Shelly Pro 1PM (model 4) and Shelly Pro 2PM (model 5)
*
* {"NAME":"Shelly 2.5","GPIO":[320,0,32,0,224,193,0,0,640,192,608,225,3456,4736],"FLAG":0,"BASE":18}
* {"NAME":"Shelly EM","GPIO":[0,0,0,0,0,0,0,0,640,3457,608,224,8832,1],"FLAG":0,"BASE":18}
* {"NAME":"Shelly Plus 2PM PCB v0.1.5","GPIO":[320,0,192,0,0,0,1,1,225,224,0,0,0,0,193,0,0,0,0,0,0,608,3840,32,0,0,0,0,0,640,0,0,3458,4736,0,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,32000,40000,3350"}
* {"NAME":"Shelly Plus 2PM PCB v0.1.9","GPIO":[320,0,0,0,32,192,0,0,225,224,0,0,0,0,193,0,0,0,0,0,0,608,640,3458,0,0,0,0,0,9472,0,4736,0,0,0,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"}
+ * {"NAME":"Shelly Pro 1PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,0,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3459,0,0,32,4736,0,160,0],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350"}
+ * {"NAME":"Shelly Pro 2PM","GPIO":[9568,1,9472,1,768,0,0,0,672,704,736,9569,0,0,5600,6214,0,0,0,5568,0,0,0,0,0,0,0,0,3460,0,0,32,4736,4737,160,161],"FLAG":0,"BASE":1,"CMND":"AdcParam1 2,10000,10000,3350;AdcParam2 2,10000,10000,3350"}
*
* Based on datasheet from https://www.analog.com/en/products/ade7953.html
*
* Model differences:
- * Function Model1 Model2 Model3 Remark
- * ------------------------------ ------ ------ ------- -------------------------------------------------
- * Shelly 2.5 EM Plus2PM
- * Current measurement device shunt CT shunt CT = Current Transformer
- * Swapped channel A/B Yes No No Defined by hardware design - Fixed by Tasmota
- * Support Export Active No Yes No Only EM supports correct negative value detection
- * Show negative (reactive) power No Yes No Only EM supports correct negative value detection
- * Default phase calibration 0 200 0 CT needs different phase calibration than shunts
- * Default reset pin on ESP8266 - 16 - Legacy support. Replaced by GPIO ADE7953RST
+ * Function Model1 Model2 Model3 Model4 Model5 Remark
+ * ------------------------------ ------- ------- ------- ------ ------ -------------------------------------------------
+ * Shelly 2.5 EM Plus2PM Pro1PM Pro2PM
+ * Processor ESP8266 ESP8266 ESP32 ESP32 ESP32
+ * Interface I2C I2C I2C SPI SPI Interface type used
+ * Number of ADE9753 chips 1 1 1 1 2 Count of ADE9753 chips
+ * ADE9753 IRQ 1 2 3 4 5 Index defines model number
+ * Current measurement device shunt CT shunt shunt shunt CT = Current Transformer
+ * Common voltage Yes Yes Yes No No Show common voltage in GUI/JSON
+ * Common frequency Yes Yes Yes No No Show common frequency in GUI/JSON
+ * Swapped channel A/B Yes No No No No Defined by hardware design - Fixed by Tasmota
+ * Support Export Active No Yes No No No Only EM supports correct negative value detection
+ * Show negative (reactive) power No Yes No No No Only EM supports correct negative value detection
+ * Default phase calibration 0 200 0 0 0 CT needs different phase calibration than shunts
+ * Default reset pin on ESP8266 - 16 - - - Legacy support. Replaced by GPIO ADE7953RST
*
* I2C Address: 0x38
*********************************************************************************************
@@ -58,6 +69,8 @@
/*********************************************************************************************/
+#define ADE7953_ACCU_ENERGY // Use accumulating energy instead of instant power
+
//#define ADE7953_DUMP_REGS
#define ADE7953_PREF 1540 // 4194304 / (1540 / 1000) = 2723574 (= WGAIN, VAGAIN and VARGAIN)
@@ -66,11 +79,10 @@
// Default calibration parameters can be overridden by a rule as documented above.
#define ADE7953_GAIN_DEFAULT 4194304 // = 0x400000 range 2097152 (min) to 6291456 (max)
-
#define ADE7953_PHCAL_DEFAULT 0 // = range -383 to 383 - Default phase calibration for Shunts
#define ADE7953_PHCAL_DEFAULT_CT 200 // = range -383 to 383 - Default phase calibration for Current Transformers (Shelly EM)
-enum Ade7953Models { ADE7953_SHELLY_25, ADE7953_SHELLY_EM, ADE7953_SHELLY_PLUS_2PM };
+enum Ade7953Models { ADE7953_SHELLY_25, ADE7953_SHELLY_EM, ADE7953_SHELLY_PLUS_2PM, ADE7953_SHELLY_PRO_1PM, ADE7953_SHELLY_PRO_2PM };
enum Ade7953_8BitRegisters {
// Register Name Addres R/W Bt Ty Default Description
@@ -175,57 +187,50 @@ enum Ade7953_32BitRegisters {
};
enum Ade7953CalibrationRegisters {
- ADE7953_CAL_AVGAIN,
- ADE7953_CAL_BVGAIN,
- ADE7953_CAL_AIGAIN,
- ADE7953_CAL_BIGAIN,
- ADE7953_CAL_AWGAIN,
- ADE7953_CAL_BWGAIN,
- ADE7953_CAL_AVAGAIN,
- ADE7953_CAL_BVAGAIN,
- ADE7953_CAL_AVARGAIN,
- ADE7953_CAL_BVARGAIN,
- ADE7943_CAL_PHCALA,
- ADE7943_CAL_PHCALB
+ ADE7953_CAL_VGAIN,
+ ADE7953_CAL_IGAIN,
+ ADE7953_CAL_WGAIN,
+ ADE7953_CAL_VAGAIN,
+ ADE7953_CAL_VARGAIN,
+ ADE7943_CAL_PHCAL
};
-const uint16_t Ade7953CalibRegs[] {
- ADE7953_AVGAIN,
- ADE7953_BVGAIN,
- ADE7953_AIGAIN,
- ADE7953_BIGAIN,
- ADE7953_AWGAIN,
- ADE7953_BWGAIN,
- ADE7953_AVAGAIN,
- ADE7953_BVAGAIN,
- ADE7953_AVARGAIN,
- ADE7953_BVARGAIN,
- ADE7943_PHCALA,
- ADE7943_PHCALB
+const uint8_t ADE7953_CALIBREGS = 6;
+const uint16_t Ade7953CalibRegs[2][ADE7953_CALIBREGS] {
+ { ADE7953_AVGAIN, ADE7953_AIGAIN, ADE7953_AWGAIN, ADE7953_AVAGAIN, ADE7953_AVARGAIN, ADE7943_PHCALA },
+ { ADE7953_BVGAIN, ADE7953_BIGAIN, ADE7953_BWGAIN, ADE7953_BVAGAIN, ADE7953_BVARGAIN, ADE7943_PHCALB }
};
-const uint16_t Ade7953Registers[] {
- ADE7953_IRMSA, // IRMSA - RMS current channel A
- ADE7953_AWATT, // AWATT - Active power channel A
- ADE7953_AVA, // AVA - Apparent power channel A
- ADE7953_AVAR, // AVAR - Reactive power channel A
- ADE7953_IRMSB, // IRMSB - RMS current channel B
- ADE7953_BWATT, // BWATT - Active power channel B
- ADE7953_BVA, // BVA - Apparent power channel B
- ADE7953_BVAR, // BVAR - Reactive power channel B
- ADE7953_VRMS, // VRMS - RMS voltage (Both channels)
- ADE7943_Period, // Period - 16-bit unsigned period register
- ADE7953_ACCMODE // ACCMODE - Accumulation mode
+const uint8_t ADE7953_REGISTERS = 6;
+const uint16_t Ade7953Registers[2][ADE7953_REGISTERS] {
+#ifdef ADE7953_ACCU_ENERGY
+ { ADE7953_IRMSA, ADE7953_AENERGYA, ADE7953_APENERGYA, ADE7953_RENERGYA, ADE7953_VRMS, ADE7943_Period },
+ { ADE7953_IRMSB, ADE7953_AENERGYB, ADE7953_APENERGYB, ADE7953_RENERGYB, ADE7953_VRMS, ADE7943_Period }
+#else // No ADE7953_ACCU_ENERGY
+ { ADE7953_IRMSA, ADE7953_AWATT, ADE7953_AVA, ADE7953_AVAR, ADE7953_VRMS, ADE7943_Period },
+ { ADE7953_IRMSB, ADE7953_BWATT, ADE7953_BVA, ADE7953_BVAR, ADE7953_VRMS, ADE7943_Period }
+#endif // ADE7953_ACCU_ENERGY
};
+#ifdef ADE7953_ACCU_ENERGY
+const float ADE7953_LSB_PER_WATTSECOND = 2.5;
+const float ADE7953_POWER_CORRECTION = 23.41494; // See https://github.com/arendst/Tasmota/pull/16941
+#else // No ADE7953_ACCU_ENERGY
+const float ADE7953_LSB_PER_WATTSECOND = 44;
+#endif // ADE7953_ACCU_ENERGY
+
struct Ade7953 {
- uint32_t voltage_rms = 0;
- uint32_t period = 0;
+ uint32_t voltage_rms[2] = { 0, 0 };
uint32_t current_rms[2] = { 0, 0 };
uint32_t active_power[2] = { 0, 0 };
- int32_t calib_data[sizeof(Ade7953CalibRegs)/sizeof(uint16_t)];
+ int32_t calib_data[2][ADE7953_CALIBREGS];
uint8_t init_step = 0;
- uint8_t model = 0; // 0 = Shelly 2.5, 1 = Shelly EM, 2 = Shelly Plus 2PM
+ uint8_t model = 0; // 0 = Shelly 2.5, 1 = Shelly EM, 2 = Shelly Plus 2PM, 3 = Shelly Pro 1PM, 4 = Shelly Pro 2PM
+ uint8_t cs_index;
+#ifdef USE_ESP32_SPI
+ SPISettings spi_settings;
+ int8_t pin_cs[2];
+#endif // USE_ESP32_SPI
} Ade7953;
int Ade7953RegSize(uint16_t reg) {
@@ -248,131 +253,216 @@ int Ade7953RegSize(uint16_t reg) {
void Ade7953Write(uint16_t reg, uint32_t val) {
int size = Ade7953RegSize(reg);
if (size) {
- Wire.beginTransmission(ADE7953_ADDR);
- Wire.write((reg >> 8) & 0xFF);
- Wire.write(reg & 0xFF);
- while (size--) {
- Wire.write((val >> (8 * size)) & 0xFF); // Write data, MSB first
+
+// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Write %08X"), val);
+
+#ifdef USE_ESP32_SPI
+ if (Ade7953.pin_cs[0] >= 0) {
+ digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 0);
+ delayMicroseconds(1); // CS 1uS to SCLK edge
+ SPI.beginTransaction(Ade7953.spi_settings);
+ SPI.transfer16(reg);
+ SPI.transfer(0x00); // Write
+ while (size--) {
+ SPI.transfer((val >> (8 * size)) & 0xFF); // Write data, MSB first
+ }
+ SPI.endTransaction();
+ delayMicroseconds(2); // CS high 1.2uS after SCLK edge (when writing to COMM_LOCK bit)
+ digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 1);
+ } else {
+#endif // USE_ESP32_SPI
+ Wire.beginTransmission(ADE7953_ADDR);
+ Wire.write((reg >> 8) & 0xFF);
+ Wire.write(reg & 0xFF);
+ while (size--) {
+ Wire.write((val >> (8 * size)) & 0xFF); // Write data, MSB first
+ }
+ Wire.endTransmission();
+ delayMicroseconds(5); // Bus-free time minimum 4.7us
+#ifdef USE_ESP32_SPI
}
- Wire.endTransmission();
- delayMicroseconds(5); // Bus-free time minimum 4.7us
+#endif // USE_ESP32_SPI
}
}
int32_t Ade7953Read(uint16_t reg) {
- uint32_t response = 0;
+ uint32_t response = 0;
int size = Ade7953RegSize(reg);
if (size) {
- Wire.beginTransmission(ADE7953_ADDR);
- Wire.write((reg >> 8) & 0xFF);
- Wire.write(reg & 0xFF);
- Wire.endTransmission(0);
- Wire.requestFrom(ADE7953_ADDR, size);
- if (size <= Wire.available()) {
- for (uint32_t i = 0; i < size; i++) {
- response = response << 8 | Wire.read(); // receive DATA (MSB first)
+#ifdef USE_ESP32_SPI
+ if (Ade7953.pin_cs[0] >= 0) {
+ digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 0);
+ delayMicroseconds(1); // CS 1uS to SCLK edge
+ SPI.beginTransaction(Ade7953.spi_settings);
+ SPI.transfer16(reg);
+ SPI.transfer(0x80); // Read
+ while (size--) {
+ response = response << 8 | SPI.transfer(0); // receive DATA (MSB first)
}
+ SPI.endTransaction();
+ digitalWrite(Ade7953.pin_cs[Ade7953.cs_index], 1);
+ } else {
+#endif // USE_ESP32_SPI
+ Wire.beginTransmission(ADE7953_ADDR);
+ Wire.write((reg >> 8) & 0xFF);
+ Wire.write(reg & 0xFF);
+ Wire.endTransmission(0);
+ Wire.requestFrom(ADE7953_ADDR, size);
+ if (size <= Wire.available()) {
+ for (uint32_t i = 0; i < size; i++) {
+ response = response << 8 | Wire.read(); // receive DATA (MSB first)
+ }
+ }
+#ifdef USE_ESP32_SPI
}
+#endif // USE_ESP32_SPI
}
- return response;
+ return response;
}
#ifdef ADE7953_DUMP_REGS
void Ade7953DumpRegs(void) {
- AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: SAGCYC DISNOLD Resrvd Resrvd LCYCMOD Resrvd Resrvd PGAV PGAIA PGAIB"));
+ AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: *** SAGCYC DISNOLD Resrvd Resrvd LCYCMOD Resrvd Resrvd PGAV PGAIA PGAIB"));
char data[200] = { 0 };
for (uint32_t i = 0; i < 10; i++) {
int32_t value = Ade7953Read(ADE7953_SAGCYC + i);
snprintf_P(data, sizeof(data), PSTR("%s %02X"), data, value); // 8-bit regs
}
- AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: Regs 0x000..009%s"), data);
- AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: ZXTOUT LINECYC CONFIG CF1DEN CF2DEN Resrvd Resrvd CFMODE PHCALA PHCALB PFA PFB ANGLEA ANGLEB Period"));
+ AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: *** 0x000..009%s"), data);
+ AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: *** ZXTOUT LINECYC CONFIG CF1DEN CF2DEN Resrvd Resrvd CFMODE PHCALA PHCALB PFA PFB ANGLEA ANGLEB Period"));
data[0] = '\0';
for (uint32_t i = 0; i < 15; i++) {
int32_t value = Ade7953Read(ADE7953_ZXTOUT + i);
snprintf_P(data, sizeof(data), PSTR("%s %04X"), data, value); // 16-bit regs
}
- AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: Regs 0x100..10E%s"), data);
- AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: IGAIN VGAIN WGAIN VARGAIN VAGAIN Resrvd IRMSOS Resrvd VRMSOS WATTOS VAROS VAOS"));
+ AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: *** 0x100..10E%s"), data);
+ AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: *** IGAIN VGAIN WGAIN VARGAIN VAGAIN Resrvd IRMSOS Resrvd VRMSOS WATTOS VAROS VAOS"));
data[0] = '\0';
for (uint32_t i = 0; i < 12; i++) {
int32_t value = Ade7953Read(ADE7953_AIGAIN + i);
snprintf_P(data, sizeof(data), PSTR("%s %06X"), data, value); // 24-bit regs
}
- AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: Regs 0x380..38B%s"), data);
+ AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: *** 0x380..38B%s"), data);
data[0] = '\0';
for (uint32_t i = 0; i < 12; i++) {
int32_t value = Ade7953Read(ADE7953_BIGAIN + i);
snprintf_P(data, sizeof(data), PSTR("%s %06X"), data, value); // 24-bit regs
}
- AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: Regs 0x38C..397%s"), data);
+ AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: *** 0x38C..397%s"), data);
}
#endif // ADE7953_DUMP_REGS
+void Ade7953SetCalibration(uint32_t regset, uint32_t calibset) {
+ Ade7953.cs_index = calibset;
+ for (uint32_t i = 0; i < ADE7953_CALIBREGS; i++) {
+ int32_t value = Ade7953.calib_data[calibset][i];
+ if (ADE7943_CAL_PHCAL == i) {
+// if (ADE7953_PHCAL_DEFAULT == value) { continue; } // ADE7953 reset does NOT always reset all registers
+ if (value < 0) {
+ value = abs(value) + 0x200; // Add sign magnitude
+ }
+ }
+// if (ADE7953_GAIN_DEFAULT == value) { continue; } // ADE7953 reset does NOT always reset all registers
+ Ade7953Write(Ade7953CalibRegs[regset][i], value);
+ }
+}
+
void Ade7953Init(void) {
+ uint32_t chips = 1;
+#ifdef USE_ESP32_SPI
+ chips = (Ade7953.pin_cs[1] >= 0) ? 2 : 1;
+#endif // USE_ESP32_SPI
+ for (uint32_t chip = 0; chip < chips; chip++) {
+ Ade7953.cs_index = chip;
+
#ifdef ADE7953_DUMP_REGS
- Ade7953DumpRegs();
+ Ade7953DumpRegs();
#endif // ADE7953_DUMP_REGS
- Ade7953Write(ADE7953_CONFIG, 0x0004); // Locking the communication interface (Clear bit COMM_LOCK), Enable HPF
- Ade7953Write(0x0FE, 0x00AD); // Unlock register 0x120
- Ade7953Write(0x120, 0x0030); // Configure optimum setting
+ Ade7953Write(ADE7953_CONFIG, 0x0004); // Locking the communication interface (Clear bit COMM_LOCK), Enable HPF
+ Ade7953Write(0x0FE, 0x00AD); // Unlock register 0x120
+ Ade7953Write(0x120, 0x0030); // Configure optimum setting
+#ifdef USE_ESP32_SPI
+// int32_t value = Ade7953Read(0x702); // Silicon version
+// AddLog(LOG_LEVEL_DEBUG, PSTR("ADE: Chip%d version %d"), chip +1, value);
+#endif // USE_ESP32_SPI
+ }
- for (uint32_t i = 0; i < sizeof(Ade7953CalibRegs)/sizeof(uint16_t); i++) {
- if (i >= ADE7943_CAL_PHCALA) {
- int16_t phasecal = Ade7953.calib_data[i];
- if (phasecal < 0) {
- phasecal = abs(phasecal) + 0x200; // Add sign magnitude
- }
- Ade7953Write(Ade7953CalibRegs[i], phasecal);
- } else {
- Ade7953Write(Ade7953CalibRegs[i], Ade7953.calib_data[i]);
- }
+ Ade7953SetCalibration(0, 0); // First ADE7953 A registers set with calibration set 0
+#ifdef USE_ESP32_SPI
+ if (Ade7953.pin_cs[1] >= 0) { // Second ADE7953 using SPI
+ Ade7953SetCalibration(0, 1); // Second ADE7953 A registers set with calibration set 1
}
- int32_t regs[sizeof(Ade7953CalibRegs)/sizeof(uint16_t)];
- for (uint32_t i = 0; i < sizeof(Ade7953CalibRegs)/sizeof(uint16_t); i++) {
- regs[i] = Ade7953Read(Ade7953CalibRegs[i]);
- if (i >= ADE7943_CAL_PHCALA) {
- if (regs[i] >= 0x0200) {
- regs[i] &= 0x01FF; // Clear sign magnitude
- regs[i] *= -1; // Make negative
+ else if (Ade7953.pin_cs[0] == -1) // No first ADE7953 using SPI so set register set B
+#endif // USE_ESP32_SPI
+ Ade7953SetCalibration(1, 1); // First ADE7953 B register set with calibration set 1
+
+ int32_t regs[ADE7953_CALIBREGS];
+ for (uint32_t chip = 0; chip < chips; chip++) {
+ Ade7953.cs_index = chip;
+ for (uint32_t channel = 0; channel < 2; channel++) {
+ for (uint32_t i = 0; i < ADE7953_CALIBREGS; i++) {
+ regs[i] = Ade7953Read(Ade7953CalibRegs[channel][i]);
+ if (ADE7943_CAL_PHCAL == i) {
+ if (regs[i] >= 0x0200) {
+ regs[i] &= 0x01FF; // Clear sign magnitude
+ regs[i] *= -1; // Make negative
+ }
+ }
}
+#ifdef USE_ESP32_SPI
+ AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: Chip%d CalibRegs%c V %d, I %d, W %d, VA %d, VAr %d, Ph %d"), chip +1, 'A'+channel, regs[0], regs[1], regs[2], regs[3], regs[4], regs[5]);
+#else
+ AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: CalibRegs%c V %d, I %d, W %d, VA %d, VAr %d, Ph %d"), 'A'+channel, regs[0], regs[1], regs[2], regs[3], regs[4], regs[5]);
+#endif // USE_ESP32_SPI
}
- }
- AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: CalibRegs aV %d, bV %d, aI %d, bI %d, aW %d, bW %d, aVA %d, bVA %d, aVAr %d, bVAr %d, aP %d, bP %d"),
- regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7], regs[8], regs[9], regs[10], regs[11]);
+
#ifdef ADE7953_DUMP_REGS
- Ade7953DumpRegs();
+ Ade7953DumpRegs();
#endif // ADE7953_DUMP_REGS
+ }
}
void Ade7953GetData(void) {
- uint32_t acc_mode;
- int32_t reg[2][4];
- for (uint32_t i = 0; i < sizeof(Ade7953Registers)/sizeof(uint16_t); i++) {
- int32_t value = Ade7953Read(Ade7953Registers[i]);
- if (8 == i) {
- Ade7953.voltage_rms = value; // RMS voltage (both channels)
- } else if (9 == i) {
- Ade7953.period = value; // Period
- } else if (10 == i) {
- acc_mode = value; // Accumulation mode
- } else {
- uint32_t reg_index = i >> 2; // 0 or 1
- reg[(ADE7953_SHELLY_25 == Ade7953.model) ? !reg_index : reg_index][i &3] = value; // IRMS, WATT, VA, VAR
+ uint32_t acc_mode = 0;
+ int32_t reg[2][ADE7953_REGISTERS];
+
+#ifdef USE_ESP32_SPI
+ if (Ade7953.pin_cs[0] >= 0) {
+ for (uint32_t chip = 0; chip < 2; chip++) {
+ if (Ade7953.pin_cs[chip] < 0) { continue; }
+ Ade7953.cs_index = chip;
+ for (uint32_t i = 0; i < ADE7953_REGISTERS; i++) {
+ reg[chip][i] = Ade7953Read(Ade7953Registers[0][i]); // IRMS, WATT, VA, VAR, VRMS, Period
+ }
}
+ } else {
+#endif // USE_ESP32_SPI
+ for (uint32_t channel = 0; channel < 2; channel++) {
+ uint32_t channel_swap = (ADE7953_SHELLY_25 == Ade7953.model) ? !channel : channel;
+ for (uint32_t i = 0; i < ADE7953_REGISTERS; i++) {
+ reg[channel_swap][i] = Ade7953Read(Ade7953Registers[channel][i]);
+ }
+ }
+ acc_mode = Ade7953Read(ADE7953_ACCMODE); // Accumulation mode
+#ifdef USE_ESP32_SPI
}
- AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: ACCMODE 0x%06X, VRMS %d, Period %d, IRMS %d, %d, WATT %d, %d, VA %d, %d, VAR %d, %d"),
- acc_mode, Ade7953.voltage_rms, Ade7953.period,
+#endif // USE_ESP32_SPI
+ AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("ADE: ACCMODE 0x%06X, VRMS %d, %d, Period %d, %d, IRMS %d, %d, WATT %d, %d, VA %d, %d, VAR %d, %d"),
+ acc_mode, reg[0][4], reg[1][4], reg[0][5], reg[1][5],
reg[0][0], reg[1][0], reg[0][1], reg[1][1], reg[0][2], reg[1][2], reg[0][3], reg[1][3]);
+ // If the device is initializing, we read the energy registers to reset them, but don't report the values as the first read may be inaccurate
+ if (Ade7953.init_step) { return; }
+
uint32_t apparent_power[2] = { 0, 0 };
uint32_t reactive_power[2] = { 0, 0 };
for (uint32_t channel = 0; channel < 2; channel++) {
+ Ade7953.voltage_rms[channel] = reg[channel][4];
Ade7953.current_rms[channel] = reg[channel][0];
- if (Ade7953.current_rms[channel] < 2000) { // No load threshold (20mA)
+ if (Ade7953.current_rms[channel] < 2000) { // No load threshold (20mA)
Ade7953.current_rms[channel] = 0;
Ade7953.active_power[channel] = 0;
} else {
@@ -385,53 +475,55 @@ void Ade7953GetData(void) {
}
}
- if (Energy.power_on) { // Powered on
- float divider = (Ade7953.calib_data[ADE7953_CAL_AVGAIN] != ADE7953_GAIN_DEFAULT) ? 10000 : Settings->energy_voltage_calibration;
- Energy.voltage[0] = (float)Ade7953.voltage_rms / divider;
- Energy.frequency[0] = 223750.0f / ((float)Ade7953.period + 1);
-
+ if (Energy.power_on) { // Powered on
+ float divider;
for (uint32_t channel = 0; channel < 2; channel++) {
Energy.data_valid[channel] = 0;
- divider = (Ade7953.calib_data[ADE7953_CAL_AWGAIN + channel] != ADE7953_GAIN_DEFAULT) ? 44 : (Settings->energy_power_calibration / 10);
+
+ float power_calibration = (float)EnergyGetCalibration(channel, ENERGY_POWER_CALIBRATION) / 10;
+#ifdef ADE7953_ACCU_ENERGY
+ power_calibration /= ADE7953_POWER_CORRECTION;
+#endif // ADE7953_ACCU_ENERGY
+ float voltage_calibration = (float)EnergyGetCalibration(channel, ENERGY_VOLTAGE_CALIBRATION);
+ float current_calibration = (float)EnergyGetCalibration(channel, ENERGY_CURRENT_CALIBRATION) * 10;
+
+ Energy.frequency[channel] = 223750.0f / ((float)reg[channel][5] + 1);
+ divider = (Ade7953.calib_data[channel][ADE7953_CAL_VGAIN] != ADE7953_GAIN_DEFAULT) ? 10000 : voltage_calibration;
+ Energy.voltage[channel] = (float)Ade7953.voltage_rms[channel] / divider;
+ divider = (Ade7953.calib_data[channel][ADE7953_CAL_WGAIN + channel] != ADE7953_GAIN_DEFAULT) ? ADE7953_LSB_PER_WATTSECOND : power_calibration;
Energy.active_power[channel] = (float)Ade7953.active_power[channel] / divider;
- divider = (Ade7953.calib_data[ADE7953_CAL_AVARGAIN + channel] != ADE7953_GAIN_DEFAULT) ? 44 : (Settings->energy_power_calibration / 10);
+ divider = (Ade7953.calib_data[channel][ADE7953_CAL_VARGAIN + channel] != ADE7953_GAIN_DEFAULT) ? ADE7953_LSB_PER_WATTSECOND : power_calibration;
Energy.reactive_power[channel] = (float)reactive_power[channel] / divider;
if (ADE7953_SHELLY_EM == Ade7953.model) {
- if (bitRead(acc_mode, 10 +channel)) { // APSIGN
+ if (bitRead(acc_mode, 10 +channel)) { // APSIGN
Energy.active_power[channel] *= -1;
}
- if (bitRead(acc_mode, 12 +channel)) { // VARSIGN
+ if (bitRead(acc_mode, 12 +channel)) { // VARSIGN
Energy.reactive_power[channel] *= -1;
}
}
- divider = (Ade7953.calib_data[ADE7953_CAL_AVAGAIN + channel] != ADE7953_GAIN_DEFAULT) ? 44 : (Settings->energy_power_calibration / 10);
+ divider = (Ade7953.calib_data[channel][ADE7953_CAL_VAGAIN + channel] != ADE7953_GAIN_DEFAULT) ? ADE7953_LSB_PER_WATTSECOND : power_calibration;
Energy.apparent_power[channel] = (float)apparent_power[channel] / divider;
if (0 == Energy.active_power[channel]) {
Energy.current[channel] = 0;
} else {
- divider = (Ade7953.calib_data[ADE7953_CAL_AIGAIN + channel] != ADE7953_GAIN_DEFAULT) ? 100000 : (Settings->energy_current_calibration * 10);
+ divider = (Ade7953.calib_data[channel][ADE7953_CAL_IGAIN + channel] != ADE7953_GAIN_DEFAULT) ? 100000 : current_calibration;
Energy.current[channel] = (float)Ade7953.current_rms[channel] / divider;
Energy.kWhtoday_delta[channel] += Energy.active_power[channel] * 1000 / 36;
}
}
EnergyUpdateToday();
-/*
- } else { // Powered off
- Energy.data_valid[0] = ENERGY_WATCHDOG;
- Energy.data_valid[1] = ENERGY_WATCHDOG;
-*/
}
}
void Ade7953EnergyEverySecond(void) {
- if (Ade7953.init_step) {
- if (1 == Ade7953.init_step) {
- Ade7953Init();
- }
+ if (Ade7953.init_step) {
+ if (2 == Ade7953.init_step) { Ade7953Init(); }
+ if (1 == Ade7953.init_step) { Ade7953GetData(); } // Read registers but do not display yet
Ade7953.init_step--;
- } else {
- Ade7953GetData();
- }
+ } else {
+ Ade7953GetData();
+ }
}
/*********************************************************************************************/
@@ -439,11 +531,12 @@ void Ade7953EnergyEverySecond(void) {
bool Ade7953SetDefaults(const char* json) {
// {"angles":{"angle0":180,"angle1":176}}
// {"rms":{"current_a":4194303,"current_b":4194303,"voltage":1613194},"angles":{"angle0":0,"angle1":0},"powers":{"totactive":{"a":2723574,"b":2723574},"apparent":{"a":2723574,"b":2723574},"reactive":{"a":2723574,"b":2723574}}}
+ // {"rms":{"current_a":21865738,"current_b":1558533,"voltage_a":1599149,"voltage_b":1597289},"angles":{"angle0":0,"angle1":0},"powers":{"totactive":{"a":106692616,"b":3540894}}}
uint32_t len = strlen(json) +1;
- if (len < 7) { return false; } // Too short
+ if (len < 7) { return false; } // Too short
char json_buffer[len];
- memcpy(json_buffer, json, len); // Keep original safe
+ memcpy(json_buffer, json, len); // Keep original safe
JsonParser parser(json_buffer);
JsonParserObject root = parser.getRootObject();
if (!root) {
@@ -457,57 +550,64 @@ bool Ade7953SetDefaults(const char* json) {
if (rms) {
val = rms[PSTR("voltage")];
if (val) {
- Ade7953.calib_data[ADE7953_CAL_AVGAIN] = val.getInt();
- Ade7953.calib_data[ADE7953_CAL_BVGAIN] = Ade7953.calib_data[ADE7953_CAL_AVGAIN];
+ Ade7953.calib_data[0][ADE7953_CAL_VGAIN] = val.getInt();
+ Ade7953.calib_data[1][ADE7953_CAL_VGAIN] = Ade7953.calib_data[0][ADE7953_CAL_VGAIN];
}
+#ifdef USE_ESP32_SPI
+ val = rms[PSTR("voltage_a")];
+ if (val) { Ade7953.calib_data[0][ADE7953_CAL_VGAIN] = val.getInt(); }
+ val = rms[PSTR("voltage_b")];
+ if (val) { Ade7953.calib_data[1][ADE7953_CAL_VGAIN] = val.getInt(); }
+#endif // USE_ESP32_SPI
val = rms[PSTR("current_a")];
- if (val) { Ade7953.calib_data[ADE7953_CAL_AIGAIN] = val.getInt(); }
+ if (val) { Ade7953.calib_data[0][ADE7953_CAL_IGAIN] = val.getInt(); }
val = rms[PSTR("current_b")];
- if (val) { Ade7953.calib_data[ADE7953_CAL_BIGAIN] = val.getInt(); }
+ if (val) { Ade7953.calib_data[1][ADE7953_CAL_IGAIN] = val.getInt(); }
}
JsonParserObject angles = root[PSTR("angles")].getObject();
if (angles) {
val = angles[PSTR("angle0")];
- if (val) { Ade7953.calib_data[ADE7943_CAL_PHCALA] = val.getInt(); }
+ if (val) { Ade7953.calib_data[0][ADE7943_CAL_PHCAL] = val.getInt(); }
val = angles[PSTR("angle1")];
- if (val) { Ade7953.calib_data[ADE7943_CAL_PHCALB] = val.getInt(); }
+ if (val) { Ade7953.calib_data[1][ADE7943_CAL_PHCAL] = val.getInt(); }
}
JsonParserObject powers = root[PSTR("powers")].getObject();
if (powers) {
JsonParserObject totactive = powers[PSTR("totactive")].getObject();
if (totactive) {
val = totactive[PSTR("a")];
- if (val) { Ade7953.calib_data[ADE7953_CAL_AWGAIN] = val.getInt(); }
+ if (val) { Ade7953.calib_data[0][ADE7953_CAL_WGAIN] = val.getInt(); }
val = totactive[PSTR("b")];
- if (val) { Ade7953.calib_data[ADE7953_CAL_BWGAIN] = val.getInt(); }
+ if (val) { Ade7953.calib_data[1][ADE7953_CAL_WGAIN] = val.getInt(); }
}
JsonParserObject apparent = powers[PSTR("apparent")].getObject();
if (apparent) {
val = apparent[PSTR("a")];
- if (val) { Ade7953.calib_data[ADE7953_CAL_AVAGAIN] = val.getInt(); }
+ if (val) { Ade7953.calib_data[0][ADE7953_CAL_VAGAIN] = val.getInt(); }
val = apparent[PSTR("b")];
- if (val) { Ade7953.calib_data[ADE7953_CAL_BVAGAIN] = val.getInt(); }
+ if (val) { Ade7953.calib_data[1][ADE7953_CAL_VAGAIN] = val.getInt(); }
}
JsonParserObject reactive = powers[PSTR("reactive")].getObject();
if (reactive) {
val = reactive[PSTR("a")];
- if (val) { Ade7953.calib_data[ADE7953_CAL_AVARGAIN] = val.getInt(); }
+ if (val) { Ade7953.calib_data[0][ADE7953_CAL_VARGAIN] = val.getInt(); }
val = reactive[PSTR("b")];
- if (val) { Ade7953.calib_data[ADE7953_CAL_BVARGAIN] = val.getInt(); }
+ if (val) { Ade7953.calib_data[1][ADE7953_CAL_VARGAIN] = val.getInt(); }
}
}
return true;
}
void Ade7953Defaults(void) {
- for (uint32_t i = 0; i < sizeof(Ade7953CalibRegs)/sizeof(uint16_t); i++) {
- if (i < sizeof(Ade7953CalibRegs)/sizeof(uint16_t) -2) {
- Ade7953.calib_data[i] = ADE7953_GAIN_DEFAULT;
- } else {
- Ade7953.calib_data[i] = (ADE7953_SHELLY_EM == Ade7953.model) ? ADE7953_PHCAL_DEFAULT_CT : ADE7953_PHCAL_DEFAULT;
+ for (uint32_t channel = 0; channel < 2; channel++) {
+ for (uint32_t i = 0; i < ADE7953_CALIBREGS; i++) {
+ if (ADE7943_CAL_PHCAL == i) {
+ Ade7953.calib_data[channel][i] = (ADE7953_SHELLY_EM == Ade7953.model) ? ADE7953_PHCAL_DEFAULT_CT : ADE7953_PHCAL_DEFAULT;
+ } else {
+ Ade7953.calib_data[channel][i] = ADE7953_GAIN_DEFAULT;
+ }
}
}
-
#ifdef USE_RULES
// rule3 on file#calib.dat do {"angles":{"angle0":180,"angle1":176}} endon
String calib = RuleLoadFile("CALIB.DAT");
@@ -519,12 +619,13 @@ void Ade7953Defaults(void) {
}
void Ade7953DrvInit(void) {
- if (PinUsed(GPIO_ADE7953_IRQ, GPIO_ANY)) { // Irq on GPIO16 is not supported...
+ if (PinUsed(GPIO_ADE7953_IRQ, GPIO_ANY)) { // Irq is not supported...
uint32_t pin_irq = Pin(GPIO_ADE7953_IRQ, GPIO_ANY);
- pinMode(pin_irq, INPUT); // Related to resetPins() - Must be set to input
- Ade7953.model = GetPin(pin_irq) - AGPIO(GPIO_ADE7953_IRQ); // 0 (1 = Shelly 2.5), 1 (2 = Shelly EM), 2 (3 = Shelly Plus 2PM)
+ pinMode(pin_irq, INPUT); // Related to resetPins() - Must be set to input
+ // 0 (1 = Shelly 2.5), 1 (2 = Shelly EM), 2 (3 = Shelly Plus 2PM), 3 (4 = Shelly Pro 1PM), 4 (5 = Shelly Pro 2PM)
+ Ade7953.model = GetPin(pin_irq) - AGPIO(GPIO_ADE7953_IRQ);
- int pin_reset = Pin(GPIO_ADE7953_RST); // -1 if not defined
+ int pin_reset = Pin(GPIO_ADE7953_RST); // -1 if not defined
#ifdef ESP8266
if (ADE7953_SHELLY_EM == Ade7953.model) {
if (-1 == pin_reset) {
@@ -532,35 +633,80 @@ void Ade7953DrvInit(void) {
}
}
#endif
- if (pin_reset > -1) {
- pinMode(pin_reset, OUTPUT); // Reset pin ADE7953
+ if (pin_reset >= 0) {
digitalWrite(pin_reset, 0);
- delay(1);
+ pinMode(pin_reset, OUTPUT); // Reset pin ADE7953
+ delay(1); // To initiate a hardware reset, this pin must be brought low for a minimum of 10 μs.
digitalWrite(pin_reset, 1);
- pinMode(pin_reset, INPUT);
+ if (Ade7953.model < ADE7953_SHELLY_PRO_1PM) {
+ pinMode(pin_reset, INPUT);
+ }
}
+ delay(100); // Need 100mS to init ADE7953
- delay(100); // Need 100mS to init ADE7953
- if (I2cSetDevice(ADE7953_ADDR)) {
- if (HLW_PREF_PULSE == Settings->energy_power_calibration) {
- Settings->energy_power_calibration = ADE7953_PREF;
- Settings->energy_voltage_calibration = ADE7953_UREF;
- Settings->energy_current_calibration = ADE7953_IREF;
+#ifdef USE_ESP32_SPI
+ Ade7953.pin_cs[0] = -1;
+ Ade7953.pin_cs[1] = -1;
+ if (Ade7953.model >= ADE7953_SHELLY_PRO_1PM) { // SPI
+ if (PinUsed(GPIO_ADE7953_CS)) { // ADE7953 CS1 enabled (Pro 1PM/2PM)
+ Ade7953.pin_cs[0] = Pin(GPIO_ADE7953_CS);
+ digitalWrite(Ade7953.pin_cs[0], 1); // ADE7953 CS1 enabled (Pro 2PM)
+ pinMode(Ade7953.pin_cs[0], OUTPUT);
+ Ade7953.pin_cs[1] = Pin(GPIO_ADE7953_CS, 1);
+ if (Ade7953.pin_cs[1] > -1) { // ADE7953 CS2 enabled (Pro 2PM)
+ digitalWrite(Ade7953.pin_cs[1], 1);
+ pinMode(Ade7953.pin_cs[1], OUTPUT);
+ } else {
+ Ade7953.model = ADE7953_SHELLY_PRO_1PM;
+ }
+ Ade7953.cs_index = 0;
+ SPI.begin(Pin(GPIO_SPI_CLK), Pin(GPIO_SPI_MISO), Pin(GPIO_SPI_MOSI), -1);
+ Ade7953.spi_settings = SPISettings(1000000, MSBFIRST, SPI_MODE0); // Set up SPI at 1MHz, MSB first, Capture at rising edge
+ AddLog(LOG_LEVEL_INFO, PSTR("SPI: ADE7953 found"));
+ } else {
+ return; // No CS pin defined
+ }
+ } else {
+#endif // USE_ESP32_SPI
+ if (!I2cSetDevice(ADE7953_ADDR)) {
+ return;
}
I2cSetActiveFound(ADE7953_ADDR, "ADE7953");
-
- Ade7953Defaults();
-
- Ade7953.init_step = 2;
- Energy.phase_count = 2; // Handle two channels as two phases
- Energy.voltage_common = true; // Use common voltage
- Energy.frequency_common = true; // Use common frequency
- Energy.use_overtemp = true; // Use global temperature for overtemp detection
- if (ADE7953_SHELLY_EM == Ade7953.model) {
- Energy.local_energy_active_export = true;
- }
- TasmotaGlobal.energy_driver = XNRG_07;
+#ifdef USE_ESP32_SPI
}
+#endif // USE_ESP32_SPI
+
+ if (HLW_PREF_PULSE == Settings->energy_power_calibration) {
+ Settings->energy_power_calibration = ADE7953_PREF;
+ Settings->energy_voltage_calibration = ADE7953_UREF;
+ Settings->energy_current_calibration = ADE7953_IREF;
+ Settings->energy_power_calibration2 = ADE7953_PREF;
+ Settings->energy_voltage_calibration2 = ADE7953_UREF;
+ Settings->energy_current_calibration2 = ADE7953_IREF;
+ }
+
+ Ade7953Defaults();
+
+ Ade7953.init_step = 3;
+
+// Energy.phase_count = 1;
+// Energy.voltage_common = false;
+// Energy.frequency_common = false;
+// Energy.use_overtemp = false;
+ if (ADE7953_SHELLY_PRO_1PM == Ade7953.model) {
+ } else {
+ Energy.phase_count = 2; // Handle two channels as two phases
+ if (ADE7953_SHELLY_PRO_2PM == Ade7953.model) {
+ } else {
+ Energy.voltage_common = true; // Use common voltage
+ Energy.frequency_common = true; // Use common frequency
+ }
+ }
+ Energy.use_overtemp = true; // Use global temperature for overtemp detection
+ if (ADE7953_SHELLY_EM == Ade7953.model) {
+ Energy.local_energy_active_export = true;
+ }
+ TasmotaGlobal.energy_driver = XNRG_07;
}
}
@@ -584,26 +730,32 @@ bool Ade7953Command(void) {
}
else if (CMND_POWERSET == Energy.command_code) {
if (XdrvMailbox.data_len && Ade7953.active_power[channel]) {
- if ((value > 100) && (value < 200000)) { // Between 1W and 2000W
- Settings->energy_power_calibration = (Ade7953.active_power[channel] * 1000) / value; // 0.00 W
+ if ((value > 100) && (value < 200000)) { // Between 1W and 2000W
+#ifdef ADE7953_ACCU_ENERGY
+ float power_calibration = (float)(Ade7953.active_power[channel] * 1000) / value; // 0.00 W
+ power_calibration *= ADE7953_POWER_CORRECTION;
+ XdrvMailbox.payload = (uint32_t)power_calibration; // 0.00 W
+#else // No ADE7953_ACCU_ENERGY
+ XdrvMailbox.payload = (Ade7953.active_power[channel] * 1000) / value; // 0.00 W
+#endif // ADE7953_ACCU_ENERGY
}
}
}
else if (CMND_VOLTAGESET == Energy.command_code) {
- if (XdrvMailbox.data_len && Ade7953.voltage_rms) {
- if ((value > 10000) && (value < 26000)) { // Between 100V and 260V
- Settings->energy_voltage_calibration = (Ade7953.voltage_rms * 100) / value; // 0.00 V
+ if (XdrvMailbox.data_len && Ade7953.voltage_rms[channel]) {
+ if ((value > 10000) && (value < 26000)) { // Between 100V and 260V
+ XdrvMailbox.payload = (Ade7953.voltage_rms[channel] * 100) / value; // 0.00 V
}
}
}
else if (CMND_CURRENTSET == Energy.command_code) {
if (XdrvMailbox.data_len && Ade7953.current_rms[channel]) {
- if ((value > 2000) && (value < 1000000)) { // Between 20mA and 10A
- Settings->energy_current_calibration = ((Ade7953.current_rms[channel] * 100) / value) * 100; // 0.00 mA
+ if ((value > 2000) && (value < 1000000)) { // Between 20mA and 10A
+ XdrvMailbox.payload = ((Ade7953.current_rms[channel] * 100) / value) * 100; // 0.00 mA
}
}
}
- else serviced = false; // Unknown command
+ else serviced = false; // Unknown command
return serviced;
}
@@ -612,8 +764,8 @@ bool Ade7953Command(void) {
* Interface
\*********************************************************************************************/
-bool Xnrg07(uint8_t function) {
- if (!I2cEnabled(XI2C_07)) { return false; }
+bool Xnrg07(uint32_t function) {
+ if (!I2cEnabled(XI2C_07) && (SPI_MOSI_MISO != TasmotaGlobal.spi_enabled)) { return false; }
bool result = false;
@@ -633,4 +785,4 @@ bool Xnrg07(uint8_t function) {
#endif // USE_ADE7953
#endif // USE_ENERGY_SENSOR
-#endif // USE_I2C
+#endif // USE_I2C or USE_ESP_SPI
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_08_sdm120.ino b/tasmota/tasmota_xnrg_energy/xnrg_08_sdm120.ino
index 5a54e1083..d4591aa85 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_08_sdm120.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_08_sdm120.ino
@@ -177,7 +177,7 @@ void SDM120Every250ms(void)
void Sdm120SnsInit(void)
{
- Sdm120Modbus = new TasmotaModbus(Pin(GPIO_SDM120_RX), Pin(GPIO_SDM120_TX));
+ Sdm120Modbus = new TasmotaModbus(Pin(GPIO_SDM120_RX), Pin(GPIO_SDM120_TX), Pin(GPIO_NRG_MBS_TX_ENA));
uint8_t result = Sdm120Modbus->Begin(SDM120_SPEED);
if (result) {
if (2 == result) { ClaimSerial(); }
@@ -261,7 +261,7 @@ void Sdm220Show(bool json) {
* Interface
\*********************************************************************************************/
-bool Xnrg08(uint8_t function)
+bool Xnrg08(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_09_dds2382.ino b/tasmota/tasmota_xnrg_energy/xnrg_09_dds2382.ino
index 885f966d6..1c5e55a30 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_09_dds2382.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_09_dds2382.ino
@@ -90,7 +90,7 @@ void Dds2382EverySecond(void)
void Dds2382SnsInit(void)
{
- Dds2382Modbus = new TasmotaModbus(Pin(GPIO_DDS2382_RX), Pin(GPIO_DDS2382_TX));
+ Dds2382Modbus = new TasmotaModbus(Pin(GPIO_DDS2382_RX), Pin(GPIO_DDS2382_TX), Pin(GPIO_NRG_MBS_TX_ENA));
uint8_t result = Dds2382Modbus->Begin(DDS2382_SPEED);
if (result) {
if (2 == result) { ClaimSerial(); }
@@ -110,7 +110,7 @@ void Dds2382DrvInit(void)
* Interface
\*********************************************************************************************/
-bool Xnrg09(uint8_t function)
+bool Xnrg09(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_10_sdm630.ino b/tasmota/tasmota_xnrg_energy/xnrg_10_sdm630.ino
index 717ded0e8..f6848707d 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_10_sdm630.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_10_sdm630.ino
@@ -213,7 +213,7 @@ void SDM630Every250ms(void)
void Sdm630SnsInit(void)
{
- Sdm630Modbus = new TasmotaModbus(Pin(GPIO_SDM630_RX), Pin(GPIO_SDM630_TX));
+ Sdm630Modbus = new TasmotaModbus(Pin(GPIO_SDM630_RX), Pin(GPIO_SDM630_TX), Pin(GPIO_NRG_MBS_TX_ENA));
uint8_t result = Sdm630Modbus->Begin(SDM630_SPEED);
if (result) {
if (2 == result) { ClaimSerial(); }
@@ -235,7 +235,7 @@ void Sdm630DrvInit(void)
* Interface
\*********************************************************************************************/
-bool Xnrg10(uint8_t function)
+bool Xnrg10(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_11_ddsu666.ino b/tasmota/tasmota_xnrg_energy/xnrg_11_ddsu666.ino
index cad411916..ab629c106 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_11_ddsu666.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_11_ddsu666.ino
@@ -132,7 +132,7 @@ void DDSU666Every250ms(void)
void Ddsu666SnsInit(void)
{
- Ddsu666Modbus = new TasmotaModbus(Pin(GPIO_DDSU666_RX), Pin(GPIO_DDSU666_TX));
+ Ddsu666Modbus = new TasmotaModbus(Pin(GPIO_DDSU666_RX), Pin(GPIO_DDSU666_TX), Pin(GPIO_NRG_MBS_TX_ENA));
uint8_t result = Ddsu666Modbus->Begin(DDSU666_SPEED);
if (result) {
if (2 == result) { ClaimSerial(); }
@@ -152,7 +152,7 @@ void Ddsu666DrvInit(void)
* Interface
\*********************************************************************************************/
-bool Xnrg11(uint8_t function)
+bool Xnrg11(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino b/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino
index f454b1c06..c57fdd8d2 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_12_solaxX1.ino
@@ -582,7 +582,7 @@ void solaxX1_Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xnrg12(uint8_t function)
+bool Xnrg12(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_13_fif_le01mr.ino b/tasmota/tasmota_xnrg_energy/xnrg_13_fif_le01mr.ino
index a064a5178..1ec4f7698 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_13_fif_le01mr.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_13_fif_le01mr.ino
@@ -214,7 +214,7 @@ void FifLEEvery250ms(void)
void FifLESnsInit(void)
{
- FifLEModbus = new TasmotaModbus(Pin(GPIO_LE01MR_RX), Pin(GPIO_LE01MR_TX));
+ FifLEModbus = new TasmotaModbus(Pin(GPIO_LE01MR_RX), Pin(GPIO_LE01MR_TX), Pin(GPIO_NRG_MBS_TX_ENA));
uint8_t result = FifLEModbus->Begin(LE01MR_SPEED);
if (result) {
if (2 == result) { ClaimSerial(); }
@@ -282,7 +282,7 @@ void FifLEShow(bool json) {
* Interface
\*********************************************************************************************/
-bool Xnrg13(uint8_t function)
+bool Xnrg13(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino b/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino
index f73a276b8..9287bab21 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_14_bl09xx.ino
@@ -193,9 +193,11 @@ void Bl09XXUpdateEnergy() {
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: U %2_f, T %2_f"), &Energy.voltage[0], &Bl09XX.temperature);
#endif
for (uint32_t chan = 0; chan < Energy.phase_count; chan++) {
- if (Bl09XX.power[chan] > Settings->energy_power_calibration) { // We need at least 1W
- Energy.active_power[chan] = (float)Bl09XX.power[chan] / Settings->energy_power_calibration;
- Energy.current[chan] = (float)Bl09XX.current[chan] / Settings->energy_current_calibration;
+ uint32_t power_calibration = EnergyGetCalibration(chan, ENERGY_POWER_CALIBRATION);
+ uint32_t current_calibration = EnergyGetCalibration(chan, ENERGY_CURRENT_CALIBRATION);
+ if (Bl09XX.power[chan] > power_calibration) { // We need at least 1W
+ Energy.active_power[chan] = (float)Bl09XX.power[chan] / power_calibration;
+ Energy.current[chan] = (float)Bl09XX.current[chan] / current_calibration;
} else {
Energy.active_power[chan] = 0;
Energy.current[chan] = 0;
@@ -289,6 +291,9 @@ void Bl09XXInit(void) {
Settings->energy_voltage_calibration = bl09xx_uref[Bl09XX.model];
Settings->energy_current_calibration = bl09xx_iref[Bl09XX.model];
Settings->energy_power_calibration = bl09xx_pref[Bl09XX.model];
+ Settings->energy_voltage_calibration2 = bl09xx_uref[Bl09XX.model];
+ Settings->energy_current_calibration2 = bl09xx_iref[Bl09XX.model];
+ Settings->energy_power_calibration2 = bl09xx_pref[Bl09XX.model];
}
if ((BL0940_MODEL == Bl09XX.model) && (Settings->energy_current_calibration < (BL0940_IREF / 20))) {
Settings->energy_current_calibration *= 100;
@@ -357,17 +362,17 @@ bool Bl09XXCommand(void) {
if (CMND_POWERSET == Energy.command_code) {
if (XdrvMailbox.data_len && Bl09XX.power[channel]) {
- Settings->energy_power_calibration = (Bl09XX.power[channel] * 100) / value;
+ XdrvMailbox.payload = (Bl09XX.power[channel] * 100) / value;
}
}
else if (CMND_VOLTAGESET == Energy.command_code) {
if (XdrvMailbox.data_len && Bl09XX.voltage) {
- Settings->energy_voltage_calibration = (Bl09XX.voltage * 100) / value;
+ XdrvMailbox.payload = (Bl09XX.voltage * 100) / value;
}
}
else if (CMND_CURRENTSET == Energy.command_code) {
if (XdrvMailbox.data_len && Bl09XX.current[channel]) {
- Settings->energy_current_calibration = (Bl09XX.current[channel] * 100) / value;
+ XdrvMailbox.payload = (Bl09XX.current[channel] * 100) / value;
}
}
else serviced = false; // Unknown command
@@ -399,7 +404,7 @@ void Bl09XXShow(bool json) {
* Interface
\*********************************************************************************************/
-bool Xnrg14(uint8_t function) {
+bool Xnrg14(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_15_teleinfo.ino b/tasmota/tasmota_xnrg_energy/xnrg_15_teleinfo.ino
index 86d74d9d4..f04b5f730 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_15_teleinfo.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_15_teleinfo.ino
@@ -77,7 +77,7 @@ const char kContratName[] PROGMEM =
// Received current contract value for legacy, standard mode has in clear text
const char kContratValue[] PROGMEM =
- "|BASE|HC..|EJP.|BBR"
+ "|BASE|HC..|EJP|BBR"
;
// all tariff type for legacy, standard mode has in clear text
@@ -106,14 +106,16 @@ const char kTarifName[] PROGMEM =
"|Pleines Bleu|Pleines Blanc|Pleines Rouges"
;
-// contract name for standard mode
+// contract name for standard mode LGTF
#define TELEINFO_STD_CONTRACT_BASE PSTR("BASE")
-#define TELEINFO_STD_CONTRACT_HCHP PSTR("H CREUSE/PLEINE")
+#define TELEINFO_STD_CONTRACT_HCHP PSTR("HC")
+#define TELEINFO_STD_CONTRACT_BBR PSTR("BBR")
+#define TELEINFO_STD_CONTRACT_EJP PSTR("EJP")
-// tariff values for standard mode
-#define TELEINFO_STD_TARIFF_BASE PSTR("BASE")
-#define TELEINFO_STD_TARIFF_HC PSTR("HEURE CREUSE")
-#define TELEINFO_STD_TARIFF_HP PSTR("HEURE PLEINE")
+// current tariff values for standard mode (Tarif en cours)
+//#define TELEINFO_STD_TARIFF_BASE PSTR("BASE")
+//#define TELEINFO_STD_TARIFF_HC PSTR("CREUSE")
+//#define TELEINFO_STD_TARIFF_HP PSTR("PLEINE")
// Label used to do some post processing and/or calculation
@@ -121,22 +123,26 @@ enum TInfoLabel{
LABEL_BASE = 1,
LABEL_ADCO, LABEL_ADSC,
LABEL_HCHC, LABEL_HCHP, LABEL_EAST, LABEL_EASF01, LABEL_EASF02,
+ LABEL_HCJB,LABEL_HPJB,LABEL_HCJW,LABEL_HPJW,LABEL_HCJR,LABEL_HPJR,
+ LABEL_EASF03, LABEL_EASF04, LABEL_EASF05, LABEL_EASF06,
LABEL_OPTARIF, LABEL_NGTF, LABEL_ISOUSC, LABEL_PREF, LABEL_PTEC, LABEL_LTARF, LABEL_NTARF,
LABEL_PAPP, LABEL_SINSTS, LABEL_IINST, LABEL_IINST1, LABEL_IINST2, LABEL_IINST3, LABEL_IRMS1, LABEL_IRMS2, LABEL_IRMS3,
LABEL_TENSION, LABEL_URMS1, LABEL_URMS2, LABEL_URMS3,
LABEL_IMAX, LABEL_IMAX1, LABEL_IMAX2, LABEL_IMAX3, LABEL_PMAX, LABEL_SMAXSN,
- LABEL_DEMAIN,
+ LABEL_DEMAIN,LABEL_MSG1,LABEL_MSG2,LABEL_STGE,
LABEL_END
};
const char kLabel[] PROGMEM =
"|BASE|ADCO|ADSC"
"|HCHC|HCHP|EAST|EASF01|EASF02"
+ "|BBRHCJB|BBRHPJB|BBRHCJW|BBRHPJW|BBRHCJR|BBRHPJR"
+ "|EASF03|EASF04|EASF05|EASF06"
"|OPTARIF|NGTF|ISOUSC|PREF|PTEC|LTARF|NTARF"
"|PAPP|SINSTS|IINST|IINST1|IINST2|IINST3|IRMS1|IRMS2|IRMS3"
"|TENSION|URMS1|URMS2|URMS3"
"|IMAX|IMAX1|IMAX2|IMAX3|PMAX|SMAXSN"
- "|DEMAIN"
+ "|DEMAIN|MSG1|MSG2|STGE"
;
// Blacklisted label from telemetry
@@ -152,7 +158,7 @@ PROGMEM
"|"
;
-#define TELEINFO_SERIAL_BUFFER_STANDARD 512 // Receive buffer size for Standard mode
+#define TELEINFO_SERIAL_BUFFER_STANDARD 1536 // Receive buffer size for Standard mode
#define TELEINFO_SERIAL_BUFFER_HISTORIQUE 512 // Receive buffer size for Legacy mode
#define TELEINFO_PROCESS_BUFFER 32 // Local processing buffer
@@ -163,12 +169,37 @@ uint8_t tic_rx_pin = NOT_A_PIN;
char serialNumber[13] = ""; // Serial number is 12 char long
bool tinfo_found = false;
int serial_buffer_size;
+uint32_t total_wh;
+uint32_t status_register;
int contrat;
int tarif;
int isousc;
int raw_skip;
/*********************************************************************************************/
+#ifdef USE_WEBSERVER
+const char HTTP_ENERGY_ID_TELEINFO[] PROGMEM = "{s}ID{m}%s{e}" ;
+const char HTTP_ENERGY_INDEX_TELEINFO[] PROGMEM = "{s}%s{m}%s " D_UNIT_WATTHOUR "{e}" ;
+const char HTTP_ENERGY_INDEX_TELEINFO_SELECT[] PROGMEM = "{s}%s{m}%s " D_UNIT_WATTHOUR "%c{e}" ;
+const char HTTP_ENERGY_PAPP_TELEINFO[] PROGMEM = "{s}" D_POWERUSAGE "{m}%d " D_UNIT_WATT "{e}" ;
+//const char HTTP_ENERGY_IINST_TELEINFO[] PROGMEM = "{s}" D_CURRENT "%s{m}%d " D_UNIT_AMPERE "{e}" ;
+const char HTTP_ENERGY_TARIF_TELEINFO_STD[] PROGMEM = "{s}" D_CURRENT_TARIFF "{m}%s{e}" ;
+const char HTTP_ENERGY_TARIF_TELEINFO_HISTO[] PROGMEM = "{s}" D_CURRENT_TARIFF "{m}Heures %s{e}" ;
+const char HTTP_ENERGY_MSG_TELEINFO_STD[] PROGMEM = "{s}Message %d{m}%s{e}" ;
+const char HTTP_ENERGY_CONTRAT_TELEINFO[] PROGMEM = "{s}" D_CONTRACT "{m}%s %d" D_UNIT_AMPERE "{e}" ;
+const char HTTP_ENERGY_LOAD_TELEINFO[] PROGMEM = "{s}" D_POWER_LOAD "{m}%d" D_UNIT_PERCENT "{e}" ;
+const char HTTP_ENERGY_IMAX_TELEINFO[] PROGMEM = "{s}" D_MAX_CURRENT "{m}%d" D_UNIT_AMPERE "{e}" ;
+const char HTTP_ENERGY_IMAX3_TELEINFO[] PROGMEM = "{s}" D_MAX_CURRENT "{m}%d / %d / %d " D_UNIT_AMPERE "{e}" ;
+const char HTTP_ENERGY_PMAX_TELEINFO[] PROGMEM = "{s}" D_MAX_POWER "{m}%d" D_UNIT_WATT "{e}" ;
+const char HTTP_ENERGY_PMAX3_TELEINFO[] PROGMEM = "{s}" D_MAX_POWER "{m}%d / %d / %d " D_UNIT_WATT "{e}" ;
+const char HTTP_ENERGY_LABEL_VALUE[] PROGMEM = "{s}%s{m}%s{e}" ;
+const char HTTP_ENERGY_LOAD_BAR[] PROGMEM = "
";
+#endif // USE_WEBSERVER
+
+
/* ======================================================================
Function: getValueFromLabelIndex
@@ -179,11 +210,23 @@ Comments: -
====================================================================== */
char * getValueFromLabelIndex(int labelIndex, char * value)
{
- char labelName[16];
+ if (!value) {
+ return nullptr;
+ }
+ char labelName[17];
+ *value = '\0';
+
// Get the label name
GetTextIndexed(labelName, sizeof(labelName), labelIndex, kLabel);
// Get value of label name
- return tinfo.valueGet(labelName, value) ;
+ tinfo.valueGet(labelName, value) ;
+
+ // Standard mode has values with space before/after
+ if (tinfo_mode==TINFO_MODE_STANDARD) {
+ Trim(value);
+ }
+
+ return *value ? value : nullptr;
}
/* ======================================================================
@@ -306,13 +349,6 @@ void DataCallback(struct _ValueList * me, uint8_t flags)
// Current tariff (standard)
else if (ilabel == LABEL_LTARF)
{
- if (!strcmp_P(me->value, TELEINFO_STD_TARIFF_BASE)) {
- tarif = TARIF_TH;
- } else if (!strcmp_P(me->value, TELEINFO_STD_TARIFF_HC)) {
- tarif = TARIF_HC;
- } else if (!strcmp_P(me->value, TELEINFO_STD_TARIFF_HP)) {
- tarif = TARIF_HP;
- }
AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Tariff name changed, now '%s'"), me->value);
}
// Current tariff index (standard)
@@ -329,12 +365,11 @@ void DataCallback(struct _ValueList * me, uint8_t flags)
char value[32];
uint32_t hc = 0;
uint32_t hp = 0;
- uint32_t total = 0;
// Base, un seul index
if (ilabel == LABEL_BASE) {
- total = atol(me->value);
- AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Base:%ld"), total);
+ total_wh = atol(me->value);
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Base:%ld"), total_wh);
// Heures creuses/pleines calculer total
} else {
// Heures creuses get heures pleines
@@ -352,15 +387,17 @@ void DataCallback(struct _ValueList * me, uint8_t flags)
}
}
if (hc>0 && hp>0) {
- total = hc + hp;
+ total_wh = hc + hp;
}
- AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: HC:%ld HP:%ld Total:%ld"), hc, hp, total);
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: HC:%ld HP:%ld Total:%ld"), hc, hp, total_wh);
}
- AddLog (LOG_LEVEL_INFO, PSTR ("TIC: Total counter updated to %ld Wh"), total);
- if (total>0) {
- Energy.import_active[0] = (float)total/1000.0f;
- EnergyUpdateTotal();
+ AddLog (LOG_LEVEL_INFO, PSTR ("TIC: Total counter updated to %ld Wh"), total_wh);
+ if (total_wh>0) {
+ Energy.total[0] = (float) total_wh / 1000.0f;
+ Energy.import_active[0] = Energy.total[0];
+ //Energy.import_active[0] = (float)total/1000.0f;
+ //EnergyUpdateTotal();
AddLog (LOG_LEVEL_DEBUG_MORE, PSTR ("TIC: import_active[0]=%.3fKWh"), Energy.import_active[0] );
}
}
@@ -368,10 +405,10 @@ void DataCallback(struct _ValueList * me, uint8_t flags)
// Wh total index (all contract)
else if ( ilabel == LABEL_EAST)
{
- uint32_t total = atol(me->value);
- Energy.import_active[0] = (float)total/1000.0f;
- EnergyUpdateTotal();
- AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Total:%ldWh"), total);
+ total_wh = atol(me->value);
+ Energy.total[0] = (float) total_wh / 1000.0f;
+ Energy.import_active[0] = Energy.total[0];
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Total:%ldWh"), total_wh);
}
// Wh indexes (standard)
@@ -391,7 +428,7 @@ void DataCallback(struct _ValueList * me, uint8_t flags)
// Find the contract index
for (contrat = CONTRAT_BAS ; contrat < CONTRAT_END ; contrat++) {
GetTextIndexed(contrat_value, sizeof(contrat_value), contrat, kContratValue);
- if (!strcmp(contrat_value, me->value)) {
+ if (strstr(me->value, contrat_value)) {
break;
}
}
@@ -400,28 +437,48 @@ void DataCallback(struct _ValueList * me, uint8_t flags)
// Contract subscribed (standard is in clear text in value)
else if (ilabel == LABEL_NGTF)
{
- if (!strcmp_P(me->value, TELEINFO_STD_CONTRACT_BASE)) {
+ if (strstr(me->value, TELEINFO_STD_CONTRACT_BASE)) {
contrat = CONTRAT_BAS;
- } else if (!strcmp_P(me->value, TELEINFO_STD_CONTRACT_HCHP)) {
+ } else if (strstr(me->value, TELEINFO_STD_CONTRACT_HCHP)) {
contrat = CONTRAT_HC;
+ } else if (strstr(me->value, TELEINFO_STD_CONTRACT_BBR)) {
+ contrat = CONTRAT_BBR;
+ } else if (strstr(me->value, TELEINFO_STD_CONTRACT_EJP)) {
+ contrat = CONTRAT_EJP;
}
AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: Contract changed, now '%s'"), me->value);
}
- // Contract subscribed (Power)
- else if (ilabel == LABEL_ISOUSC || ilabel == LABEL_PREF)
+ // Contract subscribed (I Max)
+ else if (ilabel == LABEL_ISOUSC)
{
isousc = atoi( me->value);
AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: ISousc set to %d"), isousc);
}
+ // Contract subscribed (Power in KVA)
+ else if (ilabel == LABEL_PREF)
+ {
+ // Convert KVA to A
+ isousc = atoi( me->value) * 5 ;
+
+ AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: ISousc set to %d"), isousc);
+ }
+
// Serial Number of device
else if (ilabel == LABEL_ADCO || ilabel == LABEL_ADSC)
{
strcpy(serialNumber, me->value);
AddLog(LOG_LEVEL_DEBUG, PSTR("TIC: %s set to %s"), me->name, serialNumber);
}
+ // Status
+ else if (ilabel == LABEL_STGE)
+ {
+ status_register = strtol(me->value, nullptr, 16);
+ AddLog(LOG_LEVEL_DEBUG, PSTR("Status Resister : %s set to %08X"), me->name, status_register);
+ }
+
}
}
}
@@ -447,7 +504,7 @@ bool isBlacklistedLabel(char * name)
}
/* ======================================================================
-Function: responseDumpTInfo
+Function: ResponseAppendTInfo
Purpose : add teleinfo values into JSON response
Input : 1st separator space if begining of JSON, else comma
: select if append all data or just changed one
@@ -501,7 +558,15 @@ bool ResponseAppendTInfo(char sep, bool all)
}
if (!isNumber) {
- ResponseAppend_P( PSTR("\"%s\""), me->value );
+ // Some values contains space
+ if (strcmp(me->name, "NGTF")==0 || strcmp(me->name, "LTARF")==0 || strcmp(me->name, "MSG1")==0) {
+ char trimmed_value[strlen(me->value)+1];
+ strcpy(trimmed_value, me->value);
+ ResponseAppend_P( PSTR("\"%s\""), Trim(trimmed_value) );
+ } else {
+ ResponseAppend_P( PSTR("\"%s\""), me->value );
+ }
+
} else {
ResponseAppend_P( PSTR("%ld"), atol(me->value));
}
@@ -529,7 +594,7 @@ void NewFrameCallback(struct _ValueList * me)
Energy.data_valid[0] = 0;
// Deprecated see setOption108
- // send teleinfo raw data only if setup like that
+ // send teleinfo MQTT raw data only if setup like that
if (Settings->teleinfo.raw_send) {
// Do we need to skip this frame
if (raw_skip == 0 ) {
@@ -569,6 +634,7 @@ void TInfoDrvInit(void) {
Energy.voltage_available = false;
Energy.phase_count = 1;
// init hardware energy counters
+ total_wh = 0;
Settings->flag3.hardware_energy_total = true;
}
}
@@ -664,6 +730,25 @@ void TInfoInit(void)
}
}
+//
+/* ======================================================================
+Function: TInfoSaveBeforeRestart
+Purpose : Save data before ESP restart
+Input : -
+Output : -
+Comments: -
+====================================================================== */
+void TInfoSaveBeforeRestart()
+{
+ // if teleinfo enabled, set it low
+ if (PinUsed (GPIO_TELEINFO_ENABLE)) {
+ digitalWrite( Pin(GPIO_TELEINFO_ENABLE), LOW);
+ }
+
+ // update energy total (in kwh)
+ EnergyUpdateTotal();
+
+}
/* ======================================================================
Function: TInfoCmd
@@ -833,6 +918,7 @@ Comments: -
void TInfoProcess(void)
{
static char buff[TELEINFO_PROCESS_BUFFER];
+ static uint32_t tick_update = 0;
#ifdef MEASURE_PERF
static unsigned long max_time = 0;
unsigned long duration = millis();
@@ -863,8 +949,147 @@ void TInfoProcess(void)
if (duration > max_time) { max_time = duration; AddLog(LOG_LEVEL_INFO,PSTR("TIC: max_time=%lu"), max_time); }
if (tmp_size > max_size) { max_size = tmp_size; AddLog(LOG_LEVEL_INFO,PSTR("TIC: max_size=%d"), max_size); }
#endif
+
+ // if needed, update energy total every hour
+ if (tick_update++ > 3600 * 4) {
+ EnergyUpdateTotal();
+ AddLog (LOG_LEVEL_INFO, PSTR ("TIC: Total counter updated to %lu Wh"), total_wh);
+ tick_update = 0;
+ }
+
}
+#ifdef USE_WEBSERVER
+/* ======================================================================
+Function: TInfoShowBASE
+Purpose : Display Base contract on WEB Interface
+====================================================================== */
+void TInfoShowBASE(void)
+{
+ char name[17];
+ char value[17];
+ if ( tinfo_mode==TINFO_MODE_HISTORIQUE ) {
+ if (getValueFromLabelIndex(LABEL_BASE, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_BASE, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
+ }
+ } else {
+ if (getValueFromLabelIndex(LABEL_EAST, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_EAST, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
+ }
+ }
+}
+
+/* ======================================================================
+Function: TInfoShowHC
+Purpose : Display HC/HP contract on WEB Interface
+====================================================================== */
+void TInfoShowHC(void)
+{
+ char name[17];
+ char value[17];
+ if ( tinfo_mode==TINFO_MODE_HISTORIQUE ) {
+ if (getValueFromLabelIndex(LABEL_HCHC, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_HCHC, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
+ }
+ if (getValueFromLabelIndex(LABEL_HCHP, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_HCHP, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
+ }
+ } else {
+ int index = 0;
+ if (getValueFromLabelIndex(LABEL_NTARF, value) ) {
+ index = atoi(value);
+ }
+ if (getValueFromLabelIndex(LABEL_EAST, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_EAST, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
+ }
+ if (getValueFromLabelIndex(LABEL_EASF01, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_EASF01, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO_SELECT, name, value, index==1?'*':' ');
+ }
+ if (getValueFromLabelIndex(LABEL_EASF02, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_EASF02, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO_SELECT, name, value, index==2?'*':' ');
+ //WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
+ }
+ }
+}
+/* ======================================================================
+Function: TInfoShowBBR
+Purpose : Display Bleu Blanc Rouge contract on WEB Interface
+====================================================================== */
+void TInfoShowBBR(void)
+{
+ char name[17];
+ char value[17];
+ if ( tinfo_mode==TINFO_MODE_HISTORIQUE ) {
+ // Contrat Tempo BBR
+ if (getValueFromLabelIndex(LABEL_HCJB, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_HCJB, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
+ }
+ if (getValueFromLabelIndex(LABEL_HPJB, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_HPJB, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
+ }
+ if (getValueFromLabelIndex(LABEL_HCJW, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_HCJW, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
+ }
+ if (getValueFromLabelIndex(LABEL_HPJW, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_HPJW, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
+ }
+ if (getValueFromLabelIndex(LABEL_HCJR, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_HCJR, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
+ }
+ if (getValueFromLabelIndex(LABEL_HPJR, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_HPJR, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
+ }
+ if (getValueFromLabelIndex(LABEL_DEMAIN, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_DEMAIN, kLabel);
+ WSContentSend_P(HTTP_ENERGY_LABEL_VALUE, name, value);
+ }
+ } else {
+ int index = 0;
+ if (getValueFromLabelIndex(LABEL_NTARF, value) ) {
+ index = atoi(value);
+ }
+ if (getValueFromLabelIndex(LABEL_EASF01, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_EASF01, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO_SELECT, name, value, index==1?'*':' ');
+ }
+ if (getValueFromLabelIndex(LABEL_EASF02, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_EASF02, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO_SELECT, name, value, index==2?'*':' ');
+ }
+ if (getValueFromLabelIndex(LABEL_EASF03, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_EASF03, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO_SELECT, name, value, index==3?'*':' ');
+ }
+ if (getValueFromLabelIndex(LABEL_EASF04, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_EASF04, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO_SELECT, name, value, index==4?'*':' ');
+ }
+ if (getValueFromLabelIndex(LABEL_EASF05, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_EASF05, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO_SELECT, name, value, index==5?'*':' ');
+ }
+ if (getValueFromLabelIndex(LABEL_EASF06, value) ) {
+ GetTextIndexed(name, sizeof(name), LABEL_EASF06, kLabel);
+ WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO_SELECT, name, value, index==6?'*':' ');
+ }
+ }
+
+}
+#endif
+
/* ======================================================================
Function: TInfoShow
Purpose : Tasmota callback executed to send telemetry or WEB display
@@ -872,24 +1097,6 @@ Input : -
Output : -
Comments: -
====================================================================== */
-#ifdef USE_WEBSERVER
-const char HTTP_ENERGY_ID_TELEINFO[] PROGMEM = "{s}ID{m}%s{e}" ;
-const char HTTP_ENERGY_INDEX_TELEINFO[] PROGMEM = "{s}%s{m}%s " D_UNIT_WATTHOUR "{e}" ;
-const char HTTP_ENERGY_PAPP_TELEINFO[] PROGMEM = "{s}" D_POWERUSAGE "{m}%d " D_UNIT_WATT "{e}" ;
-//const char HTTP_ENERGY_IINST_TELEINFO[] PROGMEM = "{s}" D_CURRENT "%s{m}%d " D_UNIT_AMPERE "{e}" ;
-const char HTTP_ENERGY_TARIF_TELEINFO[] PROGMEM = "{s}" D_CURRENT_TARIFF "{m}Heures %s{e}" ;
-const char HTTP_ENERGY_CONTRAT_TELEINFO[] PROGMEM = "{s}" D_CONTRACT "{m}%s %d" D_UNIT_AMPERE "{e}" ;
-const char HTTP_ENERGY_LOAD_TELEINFO[] PROGMEM = "{s}" D_POWER_LOAD "{m}%d" D_UNIT_PERCENT "{e}" ;
-const char HTTP_ENERGY_IMAX_TELEINFO[] PROGMEM = "{s}" D_MAX_CURRENT "{m}%d" D_UNIT_AMPERE "{e}" ;
-const char HTTP_ENERGY_IMAX3_TELEINFO[] PROGMEM = "{s}" D_MAX_CURRENT "{m}%d / %d / %d " D_UNIT_AMPERE "{e}" ;
-const char HTTP_ENERGY_PMAX_TELEINFO[] PROGMEM = "{s}" D_MAX_POWER "{m}%d" D_UNIT_WATT "{e}" ;
-const char HTTP_ENERGY_PMAX3_TELEINFO[] PROGMEM = "{s}" D_MAX_POWER "{m}%d / %d / %d " D_UNIT_WATT "{e}" ;
-const char HTTP_ENERGY_LOAD_BAR[] PROGMEM = "
";
-#endif // USE_WEBSERVER
-
void TInfoShow(bool json)
{
// Since it's an Energy device , current, voltage and power are
@@ -933,19 +1140,16 @@ void TInfoShow(bool json)
}
}
+ // Show indexes depending on contract
+ if ( contrat == CONTRAT_BAS ) {
+ TInfoShowBASE();
+ } else if ( contrat == CONTRAT_HC ) {
+ TInfoShowHC();
+ } else if ( contrat == CONTRAT_BBR || contrat == CONTRAT_EJP ) {
+ TInfoShowBBR();
+ }
+
if (tinfo_mode==TINFO_MODE_HISTORIQUE ) {
- if (getValueFromLabelIndex(LABEL_BASE, value) ) {
- GetTextIndexed(name, sizeof(name), LABEL_BASE, kLabel);
- WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
- }
- if (getValueFromLabelIndex(LABEL_HCHC, value) ) {
- GetTextIndexed(name, sizeof(name), LABEL_HCHC, kLabel);
- WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
- }
- if (getValueFromLabelIndex(LABEL_HCHP, value) ) {
- GetTextIndexed(name, sizeof(name), LABEL_HCHP, kLabel);
- WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
- }
if (Energy.phase_count==3) {
int imax[3];
for (int i=LABEL_IMAX1; i<=LABEL_IMAX3; i++) {
@@ -960,14 +1164,17 @@ void TInfoShow(bool json)
}
}
-
if (getValueFromLabelIndex(LABEL_PMAX, value) ) {
WSContentSend_P(HTTP_ENERGY_PMAX_TELEINFO, atoi(value));
}
if (tarif) {
GetTextIndexed(name, sizeof(name), tarif-1, kTarifName);
- WSContentSend_P(HTTP_ENERGY_TARIF_TELEINFO, name);
+ if (tinfo_mode==TINFO_MODE_STANDARD ) {
+ WSContentSend_P(HTTP_ENERGY_TARIF_TELEINFO_STD, name);
+ } else {
+ WSContentSend_P(HTTP_ENERGY_TARIF_TELEINFO_HISTO, name);
+ }
}
if (contrat && isousc) {
int percent = (int) ((Energy.current[0]*100.0f) / isousc) ;
@@ -977,27 +1184,47 @@ void TInfoShow(bool json)
}
} else if (tinfo_mode==TINFO_MODE_STANDARD ) {
- if (getValueFromLabelIndex(LABEL_EAST, value) ) {
- GetTextIndexed(name, sizeof(name), LABEL_EAST, kLabel);
- WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
- }
- if (getValueFromLabelIndex(LABEL_EASF01, value) ) {
- GetTextIndexed(name, sizeof(name), LABEL_EASF01, kLabel);
- WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
- }
- if (getValueFromLabelIndex(LABEL_EASF02, value) ) {
- GetTextIndexed(name, sizeof(name), LABEL_EASF02, kLabel);
- WSContentSend_P(HTTP_ENERGY_INDEX_TELEINFO, name, value);
- }
if (getValueFromLabelIndex(LABEL_SMAXSN, value) ) {
WSContentSend_P(HTTP_ENERGY_PMAX_TELEINFO, atoi(value));
}
if (getValueFromLabelIndex(LABEL_LTARF, value) ) {
- WSContentSend_P(HTTP_ENERGY_TARIF_TELEINFO, value);
+ WSContentSend_P(HTTP_ENERGY_TARIF_TELEINFO_STD, Trim(value));
}
if (getValueFromLabelIndex(LABEL_NGTF, value) ) {
if (isousc) {
- WSContentSend_P(HTTP_ENERGY_CONTRAT_TELEINFO, value, isousc);
+ WSContentSend_P(HTTP_ENERGY_CONTRAT_TELEINFO, Trim(value), isousc);
+ }
+ }
+ if (getValueFromLabelIndex(LABEL_MSG1, value) ) {
+ WSContentSend_P(HTTP_ENERGY_LABEL_VALUE, PSTR("Message 1"), Trim(value));
+ }
+ if (getValueFromLabelIndex(LABEL_MSG2, value) ) {
+ WSContentSend_P(HTTP_ENERGY_LABEL_VALUE, PSTR("Message 2"), Trim(value));
+ }
+ WSContentSend_P(HTTP_ENERGY_LABEL_VALUE, PSTR("Contact Sec"), status_register & 0x01 ? "Ouvert":"Fermé");
+ if (status_register & 0x08) {
+ WSContentSend_P(HTTP_ENERGY_LABEL_VALUE, PSTR("ADPS"), "En cours");
+ }
+ if (status_register >> 24) {
+ char txt[32];
+ uint8_t sr = status_register >> 24;
+ uint8_t val = sr & 0x03;
+ if (val) {
+ WSContentSend_P(HTTP_ENERGY_LABEL_VALUE, PSTR("Jour"), val==1?"Bleu":val==2?"Blanc":"Rouge");
+ }
+ val = (sr >> 2) & 0x03;
+ if (val) {
+ WSContentSend_P(HTTP_ENERGY_LABEL_VALUE, PSTR("Demain"), val==1?"Bleu":val==2?"Blanc":"Rouge");
+ }
+ val = (sr >> 4) & 0x03;
+ if (val) {
+ sprintf_P(txt, PSTR("Pointe mobile %d"), val);
+ WSContentSend_P(HTTP_ENERGY_LABEL_VALUE, PSTR("Préavis"), txt);
+ }
+ val = (sr >> 6) & 0x03;
+ if (val) {
+ sprintf_P(txt, PSTR("En cours %d"), val);
+ WSContentSend_P(HTTP_ENERGY_LABEL_VALUE, PSTR("Pointe mobile"), txt);
}
}
}
@@ -1014,7 +1241,7 @@ void TInfoShow(bool json)
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
-bool Xnrg15(uint8_t function)
+bool Xnrg15(uint32_t function)
{
bool result = false;
switch (function)
@@ -1022,6 +1249,9 @@ bool Xnrg15(uint8_t function)
case FUNC_INIT:
TInfoInit();
break;
+ case FUNC_SAVE_BEFORE_RESTART:
+ if (tinfo_found) { TInfoSaveBeforeRestart(); }
+ break;
case FUNC_PRE_INIT:
TInfoDrvInit();
break;
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_16_iem3000.ino b/tasmota/tasmota_xnrg_energy/xnrg_16_iem3000.ino
index 10e3a5de1..10f15afb1 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_16_iem3000.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_16_iem3000.ino
@@ -148,15 +148,15 @@ void IEM3000Every250ms(void)
break;
case 10:
- Energy.import_active[0] = value;
+ Energy.import_active[0] = value64/1000.0;
break;
case 11:
- Energy.import_active[1] = value;
+ Energy.import_active[1] = value64/1000.0;
break;
case 12:
- Energy.import_active[2] = value;
+ Energy.import_active[2] = value64/1000.0;
break;
case 13:
@@ -181,7 +181,7 @@ void IEM3000Every250ms(void)
void Iem3000SnsInit(void)
{
- Iem3000Modbus = new TasmotaModbus(Pin(GPIO_IEM3000_RX), Pin(GPIO_IEM3000_TX));
+ Iem3000Modbus = new TasmotaModbus(Pin(GPIO_IEM3000_RX), Pin(GPIO_IEM3000_TX), Pin(GPIO_NRG_MBS_TX_ENA));
uint8_t result = Iem3000Modbus->Begin(IEM3000_SPEED);
if (result) {
if (2 == result) { ClaimSerial(); }
@@ -203,7 +203,7 @@ void Iem3000DrvInit(void)
* Interface
\*********************************************************************************************/
-bool Xnrg16(uint8_t function)
+bool Xnrg16(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino b/tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino
index 53c748ea2..2a115712d 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_17_ornowe517.ino
@@ -185,7 +185,7 @@ void WE517Every250ms(void)
void We517SnsInit(void)
{
- We517Modbus = new TasmotaModbus(Pin(GPIO_WE517_RX), Pin(GPIO_WE517_TX));
+ We517Modbus = new TasmotaModbus(Pin(GPIO_WE517_RX), Pin(GPIO_WE517_TX), Pin(GPIO_NRG_MBS_TX_ENA));
uint8_t result = We517Modbus->Begin(WE517_SPEED);
if (result) {
if (2 == result) {
@@ -211,7 +211,7 @@ void We517DrvInit(void)
* Interface
\*********************************************************************************************/
-bool Xnrg17(uint8_t function)
+bool Xnrg17(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino b/tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino
index d93732386..bde9d90df 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_18_sdm72.ino
@@ -130,7 +130,7 @@ void Sdm72Every250ms(void)
void Sdm72SnsInit(void)
{
- Sdm72Modbus = new TasmotaModbus(Pin(GPIO_SDM72_RX), Pin(GPIO_SDM72_TX));
+ Sdm72Modbus = new TasmotaModbus(Pin(GPIO_SDM72_RX), Pin(GPIO_SDM72_TX), Pin(GPIO_NRG_MBS_TX_ENA));
uint8_t result = Sdm72Modbus->Begin(SDM72_SPEED);
if (result) {
if (2 == result) {
@@ -207,7 +207,7 @@ void Sdm72Show(bool json) {
* Interface
\*********************************************************************************************/
-bool Xnrg18(uint8_t function)
+bool Xnrg18(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino b/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino
index ec6647a76..71e675e1b 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_19_cse7761.ino
@@ -226,6 +226,8 @@ bool Cse7761ChipInit(void) {
Settings->energy_voltage_calibration = Cse7761Ref(RmsUC);
Settings->energy_current_calibration = Cse7761Ref(RmsIAC);
Settings->energy_power_calibration = Cse7761Ref(PowerPAC);
+ Settings->energy_current_calibration2 = Settings->energy_current_calibration;
+ Settings->energy_power_calibration2 = Settings->energy_power_calibration;
}
// Just to fix intermediate users
if (Settings->energy_frequency_calibration < CSE7761_FREF / 2) {
@@ -466,15 +468,17 @@ void Cse7761GetData(void) {
for (uint32_t channel = 0; channel < 2; channel++) {
Energy.data_valid[channel] = 0;
+ uint32_t power_calibration = EnergyGetCalibration(channel, ENERGY_POWER_CALIBRATION);
// Active power = PowerPA * PowerPAC * 1000 / 0x80000000
// Energy.active_power[channel] = (float)(((uint64_t)CSE7761Data.active_power[channel] * CSE7761Data.coefficient[PowerPAC + channel] * 1000) >> 31) / 1000; // W
- Energy.active_power[channel] = (float)CSE7761Data.active_power[channel] / Settings->energy_power_calibration; // W
+ Energy.active_power[channel] = (float)CSE7761Data.active_power[channel] / power_calibration; // W
if (0 == Energy.active_power[channel]) {
Energy.current[channel] = 0;
} else {
+ uint32_t current_calibration = EnergyGetCalibration(channel, ENERGY_CURRENT_CALIBRATION);
// Current = RmsIA * RmsIAC / 0x800000
// Energy.current[channel] = (float)(((uint64_t)CSE7761Data.current_rms[channel] * CSE7761Data.coefficient[RmsIAC + channel]) >> 23) / 1000; // A
- Energy.current[channel] = (float)CSE7761Data.current_rms[channel] / Settings->energy_current_calibration; // A
+ Energy.current[channel] = (float)CSE7761Data.current_rms[channel] / current_calibration; // A
CSE7761Data.energy[channel] += Energy.active_power[channel];
CSE7761Data.energy_update[channel]++;
}
@@ -616,7 +620,7 @@ bool Cse7761Command(void) {
else if (CMND_POWERSET == Energy.command_code) {
if (XdrvMailbox.data_len && CSE7761Data.active_power[channel]) {
if ((value > 100) && (value < 200000)) { // Between 1W and 2000W
- Settings->energy_power_calibration = ((CSE7761Data.active_power[channel]) / value) * 100;
+ XdrvMailbox.payload = ((CSE7761Data.active_power[channel]) / value) * 100;
}
}
}
@@ -627,7 +631,7 @@ bool Cse7761Command(void) {
else if (CMND_VOLTAGESET == Energy.command_code) {
if (XdrvMailbox.data_len && CSE7761Data.voltage_rms) {
if ((value > 10000) && (value < 26000)) { // Between 100V and 260V
- Settings->energy_voltage_calibration = (CSE7761Data.voltage_rms * 100) / value;
+ XdrvMailbox.payload = (CSE7761Data.voltage_rms * 100) / value;
}
}
}
@@ -638,7 +642,7 @@ bool Cse7761Command(void) {
else if (CMND_CURRENTSET == Energy.command_code) {
if (XdrvMailbox.data_len && CSE7761Data.current_rms[channel]) {
if ((value > 1000) && (value < 1000000)) { // Between 10mA and 10A
- Settings->energy_current_calibration = ((CSE7761Data.current_rms[channel] * 100) / value) * 1000;
+ XdrvMailbox.payload = ((CSE7761Data.current_rms[channel] * 100) / value) * 1000;
}
}
}
@@ -650,7 +654,7 @@ bool Cse7761Command(void) {
else if (CMND_FREQUENCYSET == Energy.command_code) {
if (XdrvMailbox.data_len && CSE7761Data.frequency) {
if ((value > 4500) && (value < 6500)) { // Between 45.00Hz and 65.00Hz
- Settings->energy_frequency_calibration = (CSE7761Data.frequency * 8 * value) / 100;
+ XdrvMailbox.payload = (CSE7761Data.frequency * 8 * value) / 100;
}
}
}
@@ -664,7 +668,7 @@ bool Cse7761Command(void) {
* Interface
\*********************************************************************************************/
-bool Xnrg19(uint8_t function) {
+bool Xnrg19(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_21_sdm230.ino b/tasmota/tasmota_xnrg_energy/xnrg_21_sdm230.ino
index 1c34c893d..90f16f566 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_21_sdm230.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_21_sdm230.ino
@@ -188,7 +188,7 @@ void SDM230Every250ms(void)
void Sdm230SnsInit(void)
{
- Sdm230Modbus = new TasmotaModbus(Pin(GPIO_SDM230_RX), Pin(GPIO_SDM230_TX));
+ Sdm230Modbus = new TasmotaModbus(Pin(GPIO_SDM230_RX), Pin(GPIO_SDM230_TX), Pin(GPIO_NRG_MBS_TX_ENA));
uint8_t result = Sdm230Modbus->Begin(SDM230_SPEED);
if (result) {
if (2 == result) { ClaimSerial(); }
@@ -267,7 +267,7 @@ void Sdm230Show(bool json) {
* Interface
\*********************************************************************************************/
-bool Xnrg21(uint8_t function)
+bool Xnrg21(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_22_bl6523.ino b/tasmota/tasmota_xnrg_energy/xnrg_22_bl6523.ino
index f9714b052..2bdd3eff4 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_22_bl6523.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_22_bl6523.ino
@@ -22,24 +22,24 @@
/*********************************************************************************************\
* Chinese BL6523 based Watt hour meter
*
- * This meter provides accurate Voltage, Frequency, Ampere, Wattage, Power Factor, KWh
+ * This meter provides accurate Voltage, Frequency, Ampere, Wattage, Power Factor, KWh
* To use Tasmota the user needs to add an ESP8266 or ESP32
* Three lines need to be connected via 1KOhh resistors to ESP from the main board(RX,TX GND)
- *
+ *
* Connection Eg (ESP8266) - Non - Isolated:
* BL6523 RX ->1KOhm-> ESP IO4(D2) (Should be Input Capable)
* BL6523 TX ->1KOhm-> ESP IO5(D1) (Should be Input Capable)
* BL6523 GND -> ESP GND
- *
+ *
* Connection Eg (ESP32) - Non - Isolated:
* BL6523 RX ->1KOhm-> ESP IO4 (Should be Input Capable)
* BL6523 TX ->1KOhm-> ESP IO5 (Should be Input Capable)
* BL6523 GND -> ESP GND
- *
+ *
* To build add the below to user_config_override.h
* #define USE_ENERGY_SENSOR // Enable Energy sensor framework
* #define USE_BL6523 // Add support for Chinese BL6523 based Watt hour meter (+1k code)¸
- *
+ *
* After Installation use the below template sample:
* {"NAME":"BL6523 Smart Meter","GPIO":[0,0,0,0,7488,7520,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
\*********************************************************************************************/
@@ -106,7 +106,7 @@ bool Bl6523ReadData(void)
Bl6523RxSerial->flush(); // Make room for another burst
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, rx_buffer, BL6523_RX_DATASET_SIZE);
-
+
i=0;
while (Bl6523TxSerial->available() < BL6523_TX_DATASET_SIZE)
{
@@ -116,15 +116,15 @@ bool Bl6523ReadData(void)
break;
}
}
-
+
uint8_t tx_buffer[BL6523_TX_DATASET_SIZE];
Bl6523TxSerial->readBytes(tx_buffer, BL6523_TX_DATASET_SIZE);
Bl6523TxSerial->flush(); // Make room for another burst
-
+
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, tx_buffer, BL6523_TX_DATASET_SIZE);
-
+
/* Checksum: (Addr+Data_L+Data_M+Data_H) & 0xFF, then byte invert */
uint8_t crc = rx_buffer[1]; //Addr
for (uint32_t i = 0; i < (BL6523_TX_DATASET_SIZE - 1); i++)
@@ -136,15 +136,15 @@ bool Bl6523ReadData(void)
if (crc != tx_buffer[BL6523_TX_DATASET_SIZE - 1])
{
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL6:" D_CHECKSUM_FAILURE));
- Bl6523TxSerial->flush();
- Bl6523RxSerial->flush();
+ Bl6523TxSerial->flush();
+ Bl6523RxSerial->flush();
return false;
}
/* WRITE DATA (format: command(write->0xCA) address data_low data_mid data_high checksum )
WRITE Sample(RX):
RX: CA 3E 55 00 00 6C (WRPROT - allow)
-RX: CA 14 00 00 10 DB (MODE)
+RX: CA 14 00 00 10 DB (MODE)
RX: CA 15 04 00 00 E6 (GAIN - IB 16x gain )
RX: CA 19 08 00 00 DE (WA_CFDIV )
RX: CA 3E AA 00 00 17 (WRPROT - disable)
@@ -154,8 +154,8 @@ RX: CA 3E AA 00 00 17 (WRPROT - disable)
READ Sample(RX-TX) Data:
RX: 35 05 TX: E4 00 00 16 (IA rms )
RX: 35 07 TX: D5 A3 2E 52 (V rms )
-RX: 35 09 TX: F0 FB 02 09 (FREQ)
-RX: 35 0A TX: 00 00 00 F5 (WATT)
+RX: 35 09 TX: F0 FB 02 09 (FREQ)
+RX: 35 0A TX: 00 00 00 F5 (WATT)
RX: 35 08 TX: 00 00 00 F7 (PF)
RX: 35 0C TX: 00 00 00 F3 (WATT_HR)
*/
@@ -169,7 +169,7 @@ switch(rx_buffer[1]) {
break;
case BL6523_REG_FREQ :
Energy.frequency[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_frequency_calibration; // 50.0 Hz
- break;
+ break;
case BL6523_REG_WATTS :
Energy.active_power[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / Settings->energy_power_calibration; // -196.3 W
break;
@@ -181,7 +181,7 @@ switch(rx_buffer[1]) {
powf_buf = ((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]);
powf_word = (powf_buf >> 23) ? ~(powf_buf & 0x7fffff) : powf_buf & 0x7fffff; //Extract the 23 bits and invert if sign bit(24) is set
for (int i = 0; i < 23; i++){ // Accumulate powf from 23 bits
- powf += ((powf_word >> (22-i)) * pow(2,(0-(i+1))));
+ powf += ((powf_word >> (22-i)) * pow(2,(0-(i+1))));
powf_word = powf_word & (0x7fffff >> (1+i));
}
powf = (powf_buf >> 23) ? (0.0f - (powf)) : powf; // Negate if sign bit(24) is set
@@ -190,8 +190,8 @@ switch(rx_buffer[1]) {
case BL6523_REG_WATTHR :
Energy.import_active[SINGLE_PHASE] = (float)((tx_buffer[2] << 16) | (tx_buffer[1] << 8) | tx_buffer[0]) / ( Settings->energy_power_calibration - BL6523_PWHRREF_D ); // 6.216 kWh => used in EnergyUpdateTotal()
break;
- default :
- break;
+ default :
+ break;
}
Energy.data_valid[SINGLE_PHASE] = 0;
EnergyUpdateTotal();
@@ -201,7 +201,7 @@ switch(rx_buffer[1]) {
Bl6523.discovery_triggered = true;
}
return true;
-
+
}
/*********************************************************************************************/
@@ -216,7 +216,7 @@ void Bl6523Update(void)
{
if (Bl6523.valid) {
Bl6523.valid--;
- }
+ }
}
}
@@ -224,7 +224,7 @@ void Bl6523Update(void)
void Bl6523Init(void)
{
-
+
Bl6523.type = 0;
Bl6523RxSerial = new TasmotaSerial(Pin(GPIO_BL6523_RX), -1, 1);
Bl6523TxSerial = new TasmotaSerial(Pin(GPIO_BL6523_TX), -1, 1);
@@ -247,7 +247,7 @@ void Bl6523Init(void)
AddLog(LOG_LEVEL_DEBUG, PSTR("BL6:Init Failure!" ));
TasmotaGlobal.energy_driver = ENERGY_NONE;
}
-
+
}
bool Bl6523Command(void) {
@@ -262,28 +262,28 @@ bool Bl6523Command(void) {
else if (CMND_POWERSET == Energy.command_code) {
if (XdrvMailbox.data_len) {
if ((abs_value > 100) && (abs_value < 200000)) { // Between 1.00 and 2000.00 W
- Settings->energy_power_calibration = abs_value;
+ XdrvMailbox.payload = abs_value;
}
}
}
else if (CMND_VOLTAGESET == Energy.command_code) {
if (XdrvMailbox.data_len) {
if ((abs_value > 10000) && (abs_value < 26000)) { // Between 100.00 and 260.00 V
- Settings->energy_voltage_calibration = abs_value;
+ XdrvMailbox.payload = abs_value;
}
}
}
else if (CMND_CURRENTSET == Energy.command_code) {
if (XdrvMailbox.data_len) {
if ((abs_value > 1000) && (abs_value < 1000000)) { // Between 10.00 mA and 10.00000 A
- Settings->energy_current_calibration = abs_value;
+ XdrvMailbox.payload = abs_value;
}
}
}
else if (CMND_FREQUENCYSET == Energy.command_code) {
if (XdrvMailbox.data_len) {
if ((abs_value > 4500) && (abs_value < 6500)) { // Between 45.00 and 65.00 Hz
- Settings->energy_frequency_calibration = abs_value;
+ XdrvMailbox.payload = abs_value;
}
}
}
@@ -323,17 +323,17 @@ void Bl6523DrvInit(void)
AddLog(LOG_LEVEL_DEBUG, PSTR("BL6:PreInit Failure!" ));
TasmotaGlobal.energy_driver = ENERGY_NONE;
}
-
+
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
-bool Xnrg22(uint8_t function)
+bool Xnrg22(uint32_t function)
{
bool result = false;
-
+
switch (function)
{
case FUNC_EVERY_250_MSECOND:
@@ -341,7 +341,7 @@ bool Xnrg22(uint8_t function)
break;
case FUNC_COMMAND:
result = Bl6523Command();
- break;
+ break;
case FUNC_INIT:
Bl6523Init();
break;
@@ -349,7 +349,7 @@ bool Xnrg22(uint8_t function)
Bl6523DrvInit();
break;
}
-
+
return result;
}
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino b/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino
index 08e987f0c..37d157d16 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_23_ade7880.ino
@@ -536,7 +536,6 @@ void Ade7880Cycle(void) {
void Ade7880Service0(void) {
// Poll sequence
- SkipSleep(false);
Ade7880Cycle();
Ade7880.watchdog = 0;
Ade7880.irq0_state = 0;
@@ -546,7 +545,6 @@ void IRAM_ATTR Ade7880Isr0(void) {
// Poll sequence
if (!Ade7880.irq0_state) {
Ade7880.irq0_state = 1;
- SkipSleep(true);
}
}
@@ -755,7 +753,7 @@ void Ade7880Show(bool json) {
* Interface
\*********************************************************************************************/
-bool Xnrg23(uint8_t function) {
+bool Xnrg23(uint32_t function) {
if (!I2cEnabled(XI2C_65)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino
index c4abc1154..7f155d7c2 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_29_modbus.ino
@@ -104,7 +104,7 @@
*
* Restrictions:
* - Supports Modbus floating point registers
- * - Max number of uer defined registers is defined by one rule buffer (511 characters uncompressed, around 800 characters compressed)
+ * - Max number of user defined registers is defined by one rule buffer (511 characters uncompressed, around 800 characters compressed)
*
* To do:
* - Support all three rule slots
@@ -663,7 +663,7 @@ bool EnergyModbusRegisters(void) {
void EnergyModbusSnsInit(void) {
if (EnergyModbusRegisters()) {
- EnergyModbus = new TasmotaModbus(Pin(GPIO_NRG_MBS_RX), Pin(GPIO_NRG_MBS_TX));
+ EnergyModbus = new TasmotaModbus(Pin(GPIO_NRG_MBS_RX), Pin(GPIO_NRG_MBS_TX), Pin(GPIO_NRG_MBS_TX_ENA));
uint8_t result = EnergyModbus->Begin(NrgMbsParam.serial_bps, NrgMbsParam.serial_config);
if (result) {
if (2 == result) { ClaimSerial(); }
@@ -750,18 +750,19 @@ void EnergyModbusShow(bool json) {
values[j] = NrgMbsUser[i].data[j];
}
uint32_t resolution = EnergyModbusResolution(NrgMbsUser[i].resolution);
+ uint32_t single = (!isnan(NrgMbsUser[i].data[1]) && !isnan(NrgMbsUser[i].data[2])) ? 0 : 1;
#ifdef ENERGY_MODBUS_DEBUG_SHOW
AddLog(LOG_LEVEL_DEBUG, PSTR("NRG: resolution %d -> %d"), NrgMbsUser[i].resolution, resolution);
#endif
if (json) {
- ResponseAppend_P(PSTR(",\"%s\":%s"), NrgMbsUser[i].json_name, EnergyFormat(value_chr, values, resolution));
+ ResponseAppend_P(PSTR(",\"%s\":%s"), NrgMbsUser[i].json_name, EnergyFormat(value_chr, values, resolution, single));
#ifdef USE_WEBSERVER
} else {
WSContentSend_PD(PSTR("{s}%s{m}%s %s{e}"),
NrgMbsUser[i].gui_name,
- WebEnergyFormat(value_chr, values, resolution),
+ WebEnergyFormat(value_chr, values, resolution, single),
NrgMbsUser[i].gui_unit);
#endif // USE_WEBSERVER
}
@@ -773,7 +774,7 @@ void EnergyModbusShow(bool json) {
* Interface
\*********************************************************************************************/
-bool Xnrg29(uint8_t function) {
+bool Xnrg29(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino b/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino
index 065c909af..8a1abd304 100644
--- a/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino
+++ b/tasmota/tasmota_xnrg_energy/xnrg_30_dummy.ino
@@ -55,14 +55,20 @@ struct {
void NrgDummyEverySecond(void) {
if (Energy.power_on) { // Powered on
for (uint32_t channel = 0; channel < Energy.phase_count; channel++) {
- Energy.voltage[channel] = ((float)Settings->energy_voltage_calibration / 100); // V
- Energy.frequency[channel] = ((float)Settings->energy_frequency_calibration / 100); // Hz
- if (bitRead(TasmotaGlobal.power, channel)) { // Emulate power read only if device is powered on
- Energy.active_power[channel] = (NrgDummy.power[channel]) ? ((float)NrgDummy.power[channel] / 1000) : ((float)Settings->energy_power_calibration / 100); // W
+
+ float power_calibration = (float)EnergyGetCalibration(channel, ENERGY_POWER_CALIBRATION) / 100;
+ float voltage_calibration = (float)EnergyGetCalibration(channel, ENERGY_VOLTAGE_CALIBRATION) / 100;
+ float current_calibration = (float)EnergyGetCalibration(channel, ENERGY_CURRENT_CALIBRATION) / 100000;
+ float frequency_calibration = (float)EnergyGetCalibration(channel, ENERGY_FREQUENCY_CALIBRATION) / 100;
+
+ Energy.voltage[channel] = power_calibration; // V
+ Energy.frequency[channel] = frequency_calibration; // Hz
+ if (bitRead(TasmotaGlobal.power, channel)) { // Emulate power read only if device is powered on
+ Energy.active_power[channel] = (NrgDummy.power[channel]) ? ((float)NrgDummy.power[channel] / 1000) : voltage_calibration; // W
if (0 == Energy.active_power[channel]) {
Energy.current[channel] = 0;
} else {
- Energy.current[channel] = (NrgDummy.current[channel]) ? ((float)NrgDummy.current[channel] / 1000) : ((float)Settings->energy_current_calibration / 100000); // A
+ Energy.current[channel] = (NrgDummy.current[channel]) ? ((float)NrgDummy.current[channel] / 1000) : current_calibration; // A
Energy.kWhtoday_delta[channel] += Energy.active_power[channel] * 1000 / 36;
}
Energy.data_valid[channel] = 0;
@@ -84,28 +90,28 @@ bool NrgDummyCommand(void) {
else if (CMND_POWERSET == Energy.command_code) {
if (XdrvMailbox.data_len) {
if ((abs_value >= 100) && (abs_value <= 16000000)) { // Between 1.00 and 160000.00 W
- Settings->energy_power_calibration = abs_value;
+ XdrvMailbox.payload = abs_value;
}
}
}
else if (CMND_VOLTAGESET == Energy.command_code) {
if (XdrvMailbox.data_len) {
if ((abs_value >= 10000) && (abs_value <= 40000)) { // Between 100.00 and 400.00 V
- Settings->energy_voltage_calibration = abs_value;
+ XdrvMailbox.payload = abs_value;
}
}
}
else if (CMND_CURRENTSET == Energy.command_code) {
if (XdrvMailbox.data_len) {
if ((abs_value >= 1000) && (abs_value <= 40000000)) { // Between 10.00 mA and 400.00000 A
- Settings->energy_current_calibration = abs_value;
+ XdrvMailbox.payload = abs_value;
}
}
}
else if (CMND_FREQUENCYSET == Energy.command_code) {
if (XdrvMailbox.data_len) {
if ((abs_value >= 4500) && (abs_value <= 6500)) { // Between 45.00 and 65.00 Hz
- Settings->energy_frequency_calibration = abs_value;
+ XdrvMailbox.payload = abs_value;
}
}
}
@@ -134,6 +140,9 @@ void NrgDummyDrvInit(void) {
Settings->energy_voltage_calibration = NRG_DUMMY_UREF;
Settings->energy_current_calibration = NRG_DUMMY_IREF;
Settings->energy_power_calibration = NRG_DUMMY_PREF;
+ Settings->energy_voltage_calibration2 = NRG_DUMMY_UREF;
+ Settings->energy_current_calibration2 = NRG_DUMMY_IREF;
+ Settings->energy_power_calibration2 = NRG_DUMMY_PREF;
}
Energy.phase_count = (TasmotaGlobal.devices_present < ENERGY_MAX_PHASES) ? TasmotaGlobal.devices_present : ENERGY_MAX_PHASES;
@@ -150,7 +159,7 @@ void NrgDummyDrvInit(void) {
* Interface
\*********************************************************************************************/
-bool Xnrg30(uint8_t function) {
+bool Xnrg30(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_01_counter.ino b/tasmota/tasmota_xsns_sensor/xsns_01_counter.ino
index 20c0ecc81..42ac79295 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_01_counter.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_01_counter.ino
@@ -277,7 +277,7 @@ void SyncACDimmer(void)
// reset trigger for PWM sync
ac_zero_cross_dimmer.startReSync = false;
// calculate timeoffset to fire PWM based on Dimmer
- phaseStart_ToBeClockCycles = (ac_zero_cross_dimmer.tobe_cycle_timeClockCycles * (1024 - (Light.fade_running ? Light.fade_cur_10[i] : Light.fade_start_10[i]))) / 1024;
+ phaseStart_ToBeClockCycles = (ac_zero_cross_dimmer.tobe_cycle_timeClockCycles * (1024 - ac_zero_cross_power(Light.fade_running ? Light.fade_cur_10[i] : Light.fade_start_10[i]))) / 1024;
// Limit range to avoid overshoot and undershoot
phaseStart_ToBeClockCycles = tmin(tmax(phaseStart_ToBeClockCycles, 160000), 0.95* ac_zero_cross_dimmer.tobe_cycle_timeClockCycles);
@@ -322,9 +322,8 @@ void SyncACDimmer(void)
#endif // ESP32
- AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("CNT: [%d], shift: %d, dimm_time_CCs %d, phaseShift_CCs %d, currentPWMcylce: %lu, current_cycle_CC: %lu, lastcc %lu, currentSteps %lu, currDIM %lu, last delta:%lu"),
- i, ac_zero_cross_dimmer.currentShiftClockCycle[i], phaseStart_ToBeClockCycles,phaseShift_ClockCycles,ac_zero_cross_dimmer.currentPWMCycleCount[i],ac_zero_cross_dimmer.current_cycle_ClockCycles , ac_zero_cross_dimmer.lastCycleCount, ac_zero_cross_dimmer.currentSteps, Light.fade_cur_10[i],phaseStart_ActualClockCycles);
- // Light fading
+ AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("CNT: [%d], shift: %d, dimm_time_CCs %d, phaseShift_CCs %d, currentPWMcylce: %lu, current_cycle_CC: %lu, lastcc %lu, currentSteps %lu, currDIM %lu, last delta:%lu"),
+ i, ac_zero_cross_dimmer.currentShiftClockCycle[i], phaseStart_ToBeClockCycles,phaseShift_ClockCycles,ac_zero_cross_dimmer.currentPWMCycleCount[i],ac_zero_cross_dimmer.current_cycle_ClockCycles , ac_zero_cross_dimmer.lastCycleCount, ac_zero_cross_dimmer.currentSteps, Light.fade_cur_10[i],phaseStart_ActualClockCycles); // Light fading
//AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("CNT: [%d], curr: %d, final: %d, fading: %d, phase-shift: %d, ON/OFF: %d"),i, Light.fade_cur_10[i], Light.fade_start_10[i], Light.fade_running, phaseStart_ToBeClockCycles,ac_zero_cross_dimmer.PWM_ON[i]);
} // do sync onchannel
@@ -395,7 +394,7 @@ void CmndCounterDebounceHigh(void)
* Interface
\*********************************************************************************************/
-bool Xsns01(uint8_t function)
+bool Xsns01(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_02_analog.ino b/tasmota/tasmota_xsns_sensor/xsns_02_analog.ino
index 81f562584..8c6464aea 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_02_analog.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_02_analog.ino
@@ -841,7 +841,7 @@ void CmndAdcParam(void) {
* Interface
\*********************************************************************************************/
-bool Xsns02(uint8_t function) {
+bool Xsns02(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_04_snfsc.ino b/tasmota/tasmota_xsns_sensor/xsns_04_snfsc.ino
index 545c39e7a..16bc77212 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_04_snfsc.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_04_snfsc.ino
@@ -148,7 +148,7 @@ void SonoffScShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns04(uint8_t function)
+bool Xsns04(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_05_ds18x20.ino b/tasmota/tasmota_xsns_sensor/xsns_05_ds18x20.ino
index 96f5b5882..74ccc478e 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_05_ds18x20.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_05_ds18x20.ino
@@ -1,7 +1,7 @@
/*
xsns_05_ds18x20.ino - DS18x20 temperature sensor support for Tasmota
- Copyright (C) 2021 Theo Arends
+ Copyright (C) 2021 Theo Arends and md5sum-as (https://github.com/md5sum-as)
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
@@ -26,11 +26,11 @@
#define XSNS_05 5
//#define USE_DS18x20_RECONFIGURE // When sensor is lost keep retrying or re-configure
-//#define DS18x20_USE_ID_AS_NAME // Use last 3 bytes for naming of sensors
-
+//#define DS18x20_USE_ID_AS_NAME // Use last 3 bytes for naming of sensors
+
/* #define DS18x20_USE_ID_ALIAS in my_user_config.h or user_config_override.h
* Use alias for fixed sensor name in scripts by autoexec. Command: DS18Alias XXXXXXXXXXXXXXXX,N where XXXXXXXXXXXXXXXX full serial and N number 1-255
- * Result in JSON: "DS18Alias_2":{"Id":"000003287CD8","Temperature":26.3} (example with N=2)
+ * Result in JSON: "DS18Sens_2":{"Id":"000003287CD8","Temperature":26.3} (example with N=2)
* add 8 bytes used memory
*/
@@ -45,7 +45,7 @@
#define W1_WRITE_SCRATCHPAD 0x4E
#define W1_READ_SCRATCHPAD 0xBE
-#ifndef DS18X20_MAX_SENSORS // DS18X20_MAX_SENSORS fallback to 8 if not defined in user_config_override.h
+#ifndef DS18X20_MAX_SENSORS // DS18X20_MAX_SENSORS fallback to 8 if not defined in user_config_override.h
#define DS18X20_MAX_SENSORS 8
#endif
@@ -60,18 +60,26 @@ struct {
uint8_t address[8];
uint8_t index;
uint8_t valid;
+ int8_t pins_id;
#ifdef DS18x20_USE_ID_ALIAS
uint8_t alias;
-#endif //DS18x20_USE_ID_ALIAS
+#endif // DS18x20_USE_ID_ALIAS
} ds18x20_sensor[DS18X20_MAX_SENSORS];
+struct {
+ int8_t pin = 0; // Shelly GPIO3 input only
+ int8_t pin_out = 0; // Shelly GPIO00 output only
+ bool dual_mode = false; // Single pin mode
+} ds18x20_gpios[MAX_DSB];
+
struct {
#ifdef W1_PARASITE_POWER
uint32_t w1_power_until = 0;
uint8_t current_sensor = 0;
#endif
char name[17];
- uint8_t sensors = 0;
+ uint8_t sensors;
+ uint8_t gpios; // Count of GPIO found
uint8_t input_mode = 0; // INPUT or INPUT_PULLUP (=2)
int8_t pin = 0; // Shelly GPIO3 input only
int8_t pin_out = 0; // Shelly GPIO00 output only
@@ -301,45 +309,62 @@ bool OneWireCrc8(uint8_t *addr) {
/********************************************************************************************/
void Ds18x20Init(void) {
- DS18X20Data.pin = Pin(GPIO_DSB);
- DS18X20Data.input_mode = Settings->flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT; // SetOption74 - Enable internal pullup for single DS18x20 sensor
+ DS18X20Data.gpios = 0;
+ for (uint32_t pins = 0; pins < MAX_DSB; pins++) {
+ if (PinUsed(GPIO_DSB, pins)) {
+ ds18x20_gpios[pins].pin = Pin(GPIO_DSB, pins);
- if (PinUsed(GPIO_DSB_OUT)) {
- DS18X20Data.pin_out = Pin(GPIO_DSB_OUT);
- DS18X20Data.dual_mode = true; // Dual pins mode as used by Shelly
- pinMode(DS18X20Data.pin_out, OUTPUT);
- pinMode(DS18X20Data.pin, DS18X20Data.input_mode);
- }
-
- onewire_last_discrepancy = 0;
- onewire_last_device_flag = false;
- onewire_last_family_discrepancy = 0;
- for (uint32_t i = 0; i < 8; i++) {
- onewire_rom_id[i] = 0;
+ if (PinUsed(GPIO_DSB_OUT, pins)) {
+ ds18x20_gpios[pins].dual_mode = true;
+ ds18x20_gpios[pins].pin_out = Pin(GPIO_DSB_OUT, pins);
+ }
+ DS18X20Data.gpios++;
+ }
}
uint64_t ids[DS18X20_MAX_SENSORS];
DS18X20Data.sensors = 0;
- while (DS18X20Data.sensors < DS18X20_MAX_SENSORS) {
- if (!OneWireSearch(ds18x20_sensor[DS18X20Data.sensors].address)) {
- break;
+ DS18X20Data.input_mode = Settings->flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT; // SetOption74 - Enable internal pullup for single DS18x20 sensor
+
+ for (uint32_t pins = 0; pins < DS18X20Data.gpios; pins++) {
+ DS18X20Data.pin = ds18x20_gpios[pins].pin;
+ DS18X20Data.dual_mode = ds18x20_gpios[pins].dual_mode;
+ if (ds18x20_gpios[pins].dual_mode) {
+ DS18X20Data.pin_out = ds18x20_gpios[pins].pin_out;
+ pinMode(DS18X20Data.pin_out, OUTPUT);
+ pinMode(DS18X20Data.pin, DS18X20Data.input_mode);
}
- if (OneWireCrc8(ds18x20_sensor[DS18X20Data.sensors].address) &&
- ((ds18x20_sensor[DS18X20Data.sensors].address[0] == DS18S20_CHIPID) ||
- (ds18x20_sensor[DS18X20Data.sensors].address[0] == DS1822_CHIPID) ||
- (ds18x20_sensor[DS18X20Data.sensors].address[0] == DS18B20_CHIPID) ||
- (ds18x20_sensor[DS18X20Data.sensors].address[0] == MAX31850_CHIPID))) {
- ds18x20_sensor[DS18X20Data.sensors].index = DS18X20Data.sensors;
- ids[DS18X20Data.sensors] = ds18x20_sensor[DS18X20Data.sensors].address[0]; // Chip id
- for (uint32_t j = 6; j > 0; j--) {
- ids[DS18X20Data.sensors] = ids[DS18X20Data.sensors] << 8 | ds18x20_sensor[DS18X20Data.sensors].address[j];
+
+ onewire_last_discrepancy = 0;
+ onewire_last_device_flag = false;
+ onewire_last_family_discrepancy = 0;
+ for (uint32_t i = 0; i < 8; i++) {
+ onewire_rom_id[i] = 0;
+ }
+
+ while (DS18X20Data.sensors < DS18X20_MAX_SENSORS) {
+ if (!OneWireSearch(ds18x20_sensor[DS18X20Data.sensors].address)) {
+ break;
}
-#ifdef DS18x20_USE_ID_ALIAS
- ds18x20_sensor[DS18X20Data.sensors].alias=0;
+ if (OneWireCrc8(ds18x20_sensor[DS18X20Data.sensors].address) &&
+ ((ds18x20_sensor[DS18X20Data.sensors].address[0] == DS18S20_CHIPID) ||
+ (ds18x20_sensor[DS18X20Data.sensors].address[0] == DS1822_CHIPID) ||
+ (ds18x20_sensor[DS18X20Data.sensors].address[0] == DS18B20_CHIPID) ||
+ (ds18x20_sensor[DS18X20Data.sensors].address[0] == MAX31850_CHIPID))) {
+ ds18x20_sensor[DS18X20Data.sensors].index = DS18X20Data.sensors;
+ ids[DS18X20Data.sensors] = ds18x20_sensor[DS18X20Data.sensors].address[0]; // Chip id
+ for (uint32_t j = 6; j > 0; j--) {
+ ids[DS18X20Data.sensors] = ids[DS18X20Data.sensors] << 8 | ds18x20_sensor[DS18X20Data.sensors].address[j];
+ }
+#ifdef DS18x20_USE_ID_ALIAS
+ ds18x20_sensor[DS18X20Data.sensors].alias=0;
#endif
- DS18X20Data.sensors++;
+ ds18x20_sensor[DS18X20Data.sensors].pins_id = pins;
+ DS18X20Data.sensors++;
+ }
}
}
+
for (uint32_t i = 0; i < DS18X20Data.sensors; i++) {
for (uint32_t j = i + 1; j < DS18X20Data.sensors; j++) {
if (ids[ds18x20_sensor[i].index] > ids[ds18x20_sensor[j].index]) { // Sort ascending
@@ -347,21 +372,27 @@ void Ds18x20Init(void) {
}
}
}
+
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSORS_FOUND " %d"), DS18X20Data.sensors);
}
void Ds18x20Convert(void) {
- OneWireReset();
+ for (uint8_t i = 0; i < DS18X20Data.gpios; i++) {
+ DS18X20Data.pin = ds18x20_gpios[i].pin;
+ DS18X20Data.dual_mode = ds18x20_gpios[i].dual_mode;
+ DS18X20Data.pin_out = ds18x20_gpios[i].pin_out;
+ OneWireReset();
#ifdef W1_PARASITE_POWER
- // With parasite power address one sensor at a time
- if (++DS18X20Data.current_sensor >= DS18X20Data.sensors)
- DS18X20Data.current_sensor = 0;
- OneWireSelect(ds18x20_sensor[DS18X20Data.current_sensor].address);
+ // With parasite power address one sensor at a time
+ if (++DS18X20Data.current_sensor >= DS18X20Data.sensors)
+ DS18X20Data.current_sensor = 0;
+ OneWireSelect(ds18x20_sensor[DS18X20Data.current_sensor].address);
#else
- OneWireWrite(W1_SKIP_ROM); // Address all Sensors on Bus
+ OneWireWrite(W1_SKIP_ROM); // Address all Sensors on Bus
#endif
- OneWireWrite(W1_CONVERT_TEMP); // start conversion, no parasite power on at the end
-// delay(750); // 750ms should be enough for 12bit conv
+ OneWireWrite(W1_CONVERT_TEMP); // start conversion, no parasite power on at the end
+// delay(750); // 750ms should be enough for 12bit conv
+ }
}
bool Ds18x20Read(uint8_t sensor) {
@@ -370,6 +401,9 @@ bool Ds18x20Read(uint8_t sensor) {
int8_t sign = 1;
uint8_t index = ds18x20_sensor[sensor].index;
+ DS18X20Data.pin = ds18x20_gpios[ds18x20_sensor[index].pins_id].pin;
+ DS18X20Data.pin_out = ds18x20_gpios[ds18x20_sensor[index].pins_id].pin_out;
+ DS18X20Data.dual_mode = ds18x20_gpios[ds18x20_sensor[index].pins_id].dual_mode;
if (ds18x20_sensor[index].valid) { ds18x20_sensor[index].valid--; }
for (uint32_t retry = 0; retry < 3; retry++) {
OneWireReset();
@@ -446,15 +480,14 @@ void Ds18x20Name(uint8_t sensor) {
}
snprintf_P(DS18X20Data.name, sizeof(DS18X20Data.name), PSTR("%s%c%s"), DS18X20Data.name, IndexSeparator(), address);
#else
+uint8_t print_ind = sensor +1;
#ifdef DS18x20_USE_ID_ALIAS
if (ds18x20_sensor[sensor].alias) {
- snprintf_P(DS18X20Data.name, sizeof(DS18X20Data.name), PSTR("DS18Alias%c%d"), IndexSeparator(), ds18x20_sensor[sensor].alias);
- } else {
-#endif
- snprintf_P(DS18X20Data.name, sizeof(DS18X20Data.name), PSTR("%s%c%d"), DS18X20Data.name, IndexSeparator(), sensor +1);
-#ifdef DS18x20_USE_ID_ALIAS
+ snprintf_P(DS18X20Data.name, sizeof(DS18X20Data.name), PSTR("DS18Sens"));
+ print_ind = ds18x20_sensor[sensor].alias;
}
#endif
+ snprintf_P(DS18X20Data.name, sizeof(DS18X20Data.name), PSTR("%s%c%d"), DS18X20Data.name, IndexSeparator(), print_ind);
#endif
}
}
@@ -545,7 +578,7 @@ void CmndDSAlias(void) {
uint8_t sensor=255;
char argument[XdrvMailbox.data_len];
char address[17];
-
+
if (ArgC()==2) {
tmp=atoi(ArgV(argument, 2));
ArgV(argument,1);
@@ -578,10 +611,10 @@ void CmndDSAlias(void) {
* Interface
\*********************************************************************************************/
-bool Xsns05(uint8_t function) {
+bool Xsns05(uint32_t function) {
bool result = false;
- if (PinUsed(GPIO_DSB)) {
+ if (PinUsed(GPIO_DSB, GPIO_ANY)) {
switch (function) {
case FUNC_INIT:
Ds18x20Init();
diff --git a/tasmota/tasmota_xsns_sensor/xsns_05_esp32_ds18x20.ino b/tasmota/tasmota_xsns_sensor/xsns_05_esp32_ds18x20.ino
index dd6bc33ea..2113f1aed 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_05_esp32_ds18x20.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_05_esp32_ds18x20.ino
@@ -1,7 +1,7 @@
/*
xsns_05_esp32_ds18x20.ino - DS18x20 temperature sensor support for ESP32 Tasmota
- Copyright (C) 2021 Heiko Krupp and Theo Arends
+ Copyright (C) 2021 Heiko Krupp, Theo Arends and md5sum-as (https://github.com/md5sum-as)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,7 +17,6 @@
along with this program. If not, see .
*/
-
#ifdef ESP32
#ifdef USE_DS18x20
/*********************************************************************************************\
@@ -26,7 +25,7 @@
#define XSNS_05 5
-//#define DS18x20_USE_ID_AS_NAME // Use last 3 bytes for naming of sensors
+//#define DS18x20_USE_ID_AS_NAME // Use last 3 bytes for naming of sensors
/* #define DS18x20_USE_ID_ALIAS in my_user_config.h or user_config_override.h
* Use alias for fixed sensor name in scripts by autoexec. Command: DS18Alias XXXXXXXXXXXXXXXX,N where XXXXXXXXXXXXXXXX full serial and N number 1-255
@@ -43,7 +42,7 @@
#define W1_CONVERT_TEMP 0x44
#define W1_READ_SCRATCHPAD 0xBE
-#ifndef DS18X20_MAX_SENSORS // DS18X20_MAX_SENSORS fallback to 8 if not defined in user_config_override.h
+#ifndef DS18X20_MAX_SENSORS // DS18X20_MAX_SENSORS fallback to 8 if not defined in user_config_override.h
#define DS18X20_MAX_SENSORS 8
#endif
@@ -52,56 +51,71 @@ const char kDs18x20Types[] PROGMEM = "DS18x20|DS18S20|DS1822|DS18B20|MAX31850";
uint8_t ds18x20_chipids[] = { 0, DS18S20_CHIPID, DS1822_CHIPID, DS18B20_CHIPID, MAX31850_CHIPID };
struct {
+#ifdef W1_PARASITE_POWER
+ float temperature;
+#endif
float temp_sum;
uint16_t numread;
uint8_t address[8];
uint8_t index;
uint8_t valid;
+ int8_t pins_id;
#ifdef DS18x20_USE_ID_ALIAS
uint8_t alias;
-#endif //DS18x20_USE_ID_ALIAS
+#endif //DS18x20_USE_ID_ALIAS
} ds18x20_sensor[DS18X20_MAX_SENSORS];
+#include
+OneWire *ds = nullptr;
+OneWire *ds18x20_gpios[MAX_DSB];
+
struct {
char name[17];
- uint8_t sensors = 0;
+ uint8_t sensors;
+ uint8_t gpios; // Count of GPIO found
} DS18X20Data;
/********************************************************************************************/
-#include
-
-OneWire *ds = nullptr;
-
void Ds18x20Init(void) {
- ds = new OneWire(Pin(GPIO_DSB));
-
+ DS18X20Data.gpios = 0;
+ for (uint32_t pins = 0; pins < MAX_DSB; pins++) {
+ if (PinUsed(GPIO_DSB, pins)) {
+ ds18x20_gpios[pins] = new OneWire(Pin(GPIO_DSB, pins));
+ DS18X20Data.gpios++;
+ }
+ }
Ds18x20Search();
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSORS_FOUND " %d"), DS18X20Data.sensors);
}
void Ds18x20Search(void) {
- uint8_t num_sensors=0;
+ uint8_t num_sensors = 0;
uint8_t sensor = 0;
- ds->reset_search();
- for (num_sensors = 0; num_sensors < DS18X20_MAX_SENSORS; num_sensors) {
- if (!ds->search(ds18x20_sensor[num_sensors].address)) {
- ds->reset_search();
- break;
- }
- // If CRC Ok and Type DS18S20, DS1822, DS18B20 or MAX31850
- if ((OneWire::crc8(ds18x20_sensor[num_sensors].address, 7) == ds18x20_sensor[num_sensors].address[7]) &&
- ((ds18x20_sensor[num_sensors].address[0] == DS18S20_CHIPID) ||
- (ds18x20_sensor[num_sensors].address[0] == DS1822_CHIPID) ||
- (ds18x20_sensor[num_sensors].address[0] == DS18B20_CHIPID) ||
- (ds18x20_sensor[num_sensors].address[0] == MAX31850_CHIPID))) {
-#ifdef DS18x20_USE_ID_ALIAS
- ds18x20_sensor[num_sensors].alias=0;
+ for (uint8_t pins = 0; pins < DS18X20Data.gpios; pins++) {
+ ds = ds18x20_gpios[pins];
+ ds->reset_search();
+ for (num_sensors; num_sensors < DS18X20_MAX_SENSORS; num_sensors) {
+ if (!ds->search(ds18x20_sensor[num_sensors].address)) {
+ ds->reset_search();
+ break;
+ }
+ // If CRC Ok and Type DS18S20, DS1822, DS18B20 or MAX31850
+ if ((OneWire::crc8(ds18x20_sensor[num_sensors].address, 7) == ds18x20_sensor[num_sensors].address[7]) &&
+ ((ds18x20_sensor[num_sensors].address[0] == DS18S20_CHIPID) ||
+ (ds18x20_sensor[num_sensors].address[0] == DS1822_CHIPID) ||
+ (ds18x20_sensor[num_sensors].address[0] == DS18B20_CHIPID) ||
+ (ds18x20_sensor[num_sensors].address[0] == MAX31850_CHIPID))) {
+#ifdef DS18x20_USE_ID_ALIAS
+ ds18x20_sensor[num_sensors].alias=0;
#endif
- num_sensors++;
+ ds18x20_sensor[num_sensors].pins_id = pins;
+ num_sensors++;
+ }
}
}
+
for (uint32_t i = 0; i < num_sensors; i++) {
ds18x20_sensor[i].index = i;
}
@@ -116,10 +130,19 @@ void Ds18x20Search(void) {
}
void Ds18x20Convert(void) {
- ds->reset();
- ds->write(W1_SKIP_ROM); // Address all Sensors on Bus
- ds->write(W1_CONVERT_TEMP); // start conversion, no parasite power on at the end
-// delay(750); // 750ms should be enough for 12bit conv
+ for (uint32_t i = 0; i < DS18X20Data.gpios; i++) {
+ ds = ds18x20_gpios[i];
+ ds->reset();
+#ifdef W1_PARASITE_POWER
+ // With parasite power held wire high at the end for parasitically powered devices
+ ds->write(W1_SKIP_ROM, 1); // Address all Sensors on Bus
+ ds->write(W1_CONVERT_TEMP, 1); // start conversion, no parasite power on at the end
+#else
+ ds->write(W1_SKIP_ROM); // Address all Sensors on Bus
+ ds->write(W1_CONVERT_TEMP); // start conversion, no parasite power on at the end
+#endif
+// delay(750); // 750ms should be enough for 12bit conv
+ }
}
bool Ds18x20Read(uint8_t sensor, float &t) {
@@ -130,10 +153,15 @@ bool Ds18x20Read(uint8_t sensor, float &t) {
uint8_t index = ds18x20_sensor[sensor].index;
if (ds18x20_sensor[index].valid) { ds18x20_sensor[index].valid--; }
-
+ ds = ds18x20_gpios[ds18x20_sensor[index].pins_id];
ds->reset();
ds->select(ds18x20_sensor[index].address);
+#ifdef W1_PARASITE_POWER
+ // With parasite power held wire high at the end for parasitically powered devices
+ ds->write(W1_READ_SCRATCHPAD, 1); // Read Scratchpad
+#else
ds->write(W1_READ_SCRATCHPAD); // Read Scratchpad
+#endif
for (uint32_t i = 0; i < 9; i++) {
data[i] = ds->read();
@@ -143,6 +171,9 @@ bool Ds18x20Read(uint8_t sensor, float &t) {
case DS18S20_CHIPID: {
int16_t tempS = (((data[1] << 8) | (data[0] & 0xFE)) << 3) | ((0x10 - data[6]) & 0x0F);
t = ConvertTemp(tempS * 0.0625f - 0.250f);
+#ifdef W1_PARASITE_POWER
+ ds18x20_sensor[index].temperature = t;
+#endif
ds18x20_sensor[index].valid = SENSOR_MAX_MISS;
return true;
}
@@ -154,12 +185,18 @@ bool Ds18x20Read(uint8_t sensor, float &t) {
sign = -1;
}
t = ConvertTemp(sign * temp12 * 0.0625f); // Divide by 16
+#ifdef W1_PARASITE_POWER
+ ds18x20_sensor[index].temperature = t;
+#endif
ds18x20_sensor[index].valid = SENSOR_MAX_MISS;
return true;
}
case MAX31850_CHIPID: {
int16_t temp14 = (data[1] << 8) + (data[0] & 0xFC);
t = ConvertTemp(temp14 * 0.0625f); // Divide by 16
+#ifdef W1_PARASITE_POWER
+ ds18x20_sensor[index].temperature = t;
+#endif
ds18x20_sensor[index].valid = SENSOR_MAX_MISS;
return true;
}
@@ -185,15 +222,14 @@ void Ds18x20Name(uint8_t sensor) {
}
snprintf_P(DS18X20Data.name, sizeof(DS18X20Data.name), PSTR("%s%c%s"), DS18X20Data.name, IndexSeparator(), address);
#else
+uint8_t print_ind = sensor +1;
#ifdef DS18x20_USE_ID_ALIAS
if (ds18x20_sensor[sensor].alias) {
- snprintf_P(DS18X20Data.name, sizeof(DS18X20Data.name), PSTR("DS18Alias%c%d"), IndexSeparator(), ds18x20_sensor[sensor].alias);
- } else {
-#endif
- snprintf_P(DS18X20Data.name, sizeof(DS18X20Data.name), PSTR("%s%c%d"), DS18X20Data.name, IndexSeparator(), sensor +1);
-#ifdef DS18x20_USE_ID_ALIAS
+ snprintf_P(DS18X20Data.name, sizeof(DS18X20Data.name), PSTR("DS18Sens"));
+ print_ind = ds18x20_sensor[sensor].alias;
}
#endif
+ snprintf_P(DS18X20Data.name, sizeof(DS18X20Data.name), PSTR("%s%c%d"), DS18X20Data.name, IndexSeparator(), print_ind);
#endif
}
}
@@ -231,7 +267,13 @@ void Ds18x20Show(bool json) {
uint8_t dsxflg = 0;
for (uint32_t i = 0; i < DS18X20Data.sensors; i++) {
+#ifdef W1_PARASITE_POWER
+ // With parasite power read one sensor at a time
+ if (ds18x20_sensor[i].valid) {
+ t = ds18x20_sensor[i].temperature;
+#else
if (Ds18x20Read(i, t)) { // Check if read failed
+#endif
Ds18x20Name(i);
if (json) {
@@ -279,7 +321,7 @@ void CmndDSAlias(void) {
uint8_t sensor=255;
char argument[XdrvMailbox.data_len];
char address[17];
-
+
if (ArgC()==2) {
tmp=atoi(ArgV(argument, 2));
ArgV(argument,1);
@@ -312,10 +354,10 @@ void CmndDSAlias(void) {
* Interface
\*********************************************************************************************/
-bool Xsns05(uint8_t function) {
+bool Xsns05(uint32_t function) {
bool result = false;
- if (PinUsed(GPIO_DSB)) {
+ if (PinUsed(GPIO_DSB, GPIO_ANY)) {
switch (function) {
case FUNC_INIT:
Ds18x20Init();
diff --git a/tasmota/tasmota_xsns_sensor/xsns_06_dht_v5.ino b/tasmota/tasmota_xsns_sensor/xsns_06_dht_v5.ino
index bfcda401e..bab1efaec 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_06_dht_v5.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_06_dht_v5.ino
@@ -35,7 +35,9 @@
#define XSNS_06 6
+#ifndef DHT_MAX_SENSORS
#define DHT_MAX_SENSORS 4
+#endif
#define DHT_MAX_RETRY 8
uint8_t dht_data[5];
@@ -294,7 +296,7 @@ void DhtShow(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns06(uint8_t function) {
+bool Xsns06(uint32_t function) {
bool result = false;
if (dht_active) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_06_dht_v6.ino b/tasmota/tasmota_xsns_sensor/xsns_06_dht_v6.ino
index 45f3c361a..c2160b512 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_06_dht_v6.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_06_dht_v6.ino
@@ -26,7 +26,9 @@
#define XSNS_06 6
+#ifndef DHT_MAX_SENSORS
#define DHT_MAX_SENSORS 4
+#endif
#define DHT_MAX_RETRY 8
uint32_t dht_maxcycles;
@@ -369,7 +371,7 @@ void DhtShow(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns06(uint8_t function) {
+bool Xsns06(uint32_t function) {
bool result = false;
if (dht_active) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_06_esp32_dht.ino b/tasmota/tasmota_xsns_sensor/xsns_06_esp32_dht.ino
index 66ee0f782..eb902577a 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_06_esp32_dht.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_06_esp32_dht.ino
@@ -31,7 +31,9 @@
#define XSNS_06 6
+#ifndef DHT_MAX_SENSORS
#define DHT_MAX_SENSORS 4
+#endif
#define DHT_MAX_RETRY 8
#include
@@ -128,7 +130,7 @@ void DhtShow(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns06(uint8_t function) {
+bool Xsns06(uint32_t function) {
bool result = false;
if (dht_active) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_07_sht1x.ino b/tasmota/tasmota_xsns_sensor/xsns_07_sht1x.ino
index 4d571960c..e420eea1b 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_07_sht1x.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_07_sht1x.ino
@@ -184,7 +184,7 @@ void ShtShow(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns07(uint8_t function) {
+bool Xsns07(uint32_t function) {
if (!I2cEnabled(XI2C_08)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_08_htu21.ino b/tasmota/tasmota_xsns_sensor/xsns_08_htu21.ino
index 0b9c652ae..c9b535ffd 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_08_htu21.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_08_htu21.ino
@@ -255,7 +255,7 @@ void HtuShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns08(uint8_t function)
+bool Xsns08(uint32_t function)
{
if (!I2cEnabled(XI2C_09)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino b/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino
index 6846af7ae..503b8ff3e 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_09_bmp.ino
@@ -645,7 +645,7 @@ void BMP_EnterSleep(void)
* Interface
\*********************************************************************************************/
-bool Xsns09(uint8_t function)
+bool Xsns09(uint32_t function)
{
if (!I2cEnabled(XI2C_10)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_100_ina3221.ino b/tasmota/tasmota_xsns_sensor/xsns_100_ina3221.ino
index 2b3571946..3ea91a9a2 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_100_ina3221.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_100_ina3221.ino
@@ -418,7 +418,7 @@ void Ina3221Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns100(uint8_t function)
+bool Xsns100(uint32_t function)
{
if (!I2cEnabled(XI2C_72)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_101_hmc5883l.ino b/tasmota/tasmota_xsns_sensor/xsns_101_hmc5883l.ino
new file mode 100644
index 000000000..f460b9ba4
--- /dev/null
+++ b/tasmota/tasmota_xsns_sensor/xsns_101_hmc5883l.ino
@@ -0,0 +1,253 @@
+/*
+ xsns_101_hmc5883l.ino - HMC5883L 3-Axis Digital Compass sensor support for Tasmota
+
+ Copyright (C) 2022 Andreas Achtzehn (inspired by Helge Scheunemann)
+
+ 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_HMC5883L
+/*********************************************************************************************\
+ * HMC5883L is 3-Axis Digital Compass sensor
+ *
+ * Datasheet: https://cdn-shop.adafruit.com/datasheets/HMC5883L_3-Axis_Digital_Compass_IC.pdf
+ * I2C Address: 0x1E
+\*********************************************************************************************/
+
+// Define driver ID
+#define XSNS_101 101
+#define XI2C_73 73 // See I2CDEVICES.md
+
+/* The default I2C address of this chip */
+#define HMC5883L_ADDR 0x1E
+
+/* Register locations */
+#define HMC5883L_X_LSB 0x04
+#define HMC5883L_X_MSB 0x03
+#define HMC5883L_Y_LSB 0x08
+#define HMC5883L_Y_MSB 0x07
+#define HMC5883L_Z_LSB 0x06
+#define HMC5883L_Z_MSB 0x05
+#define HMC5883L_STATUS 0x09
+#define HMC5883L_CONFIG_A 0x00
+#define HMC5883L_CONFIG_B 0x01
+#define HMC5883L_MODE 0x02
+#define HMC5883L_CHIP_ID_A 0x0A
+#define HMC5883L_CHIP_ID_B 0x0B
+#define HMC5883L_CHIP_ID_C 0x0C
+
+/* Bit values for the STATUS register */
+const uint8_t HMC5883L_STATUS_RDY = 0b00000001;
+const uint8_t HMC5883L_STATUS_LOCK = 0b00000010;
+
+/* Modes for the sampling in the MODE register */
+const uint8_t HMC5883L_MODE_CONT = 0b00000000;
+const uint8_t HMC5883L_MODE_SINGLE = 0b00000001;
+const uint8_t HMC5883L_MODE_IDLE = 0b00000010;
+
+/* Gain value mask for CONFIG B register */
+const uint8_t HMC5883L_CONFIG_B_GAIN_MASK = 0b11100000; // shift operation, values 0-7
+const uint8_t HMC5883L_CONFIG_B_GAIN_SHIFT = 5;
+
+/* Averaging value for CONFIG A register: pow(2,N) */
+const uint8_t HMC5883L_CONFIG_A_AVG_MASK = 0b01100000;
+const uint8_t HMC5883L_CONFIG_A_AVG_SHIFT = 5;
+
+/* Data output rate */
+const uint8_t HMC5883L_CONFIG_A_RATE_MASK = 0b00011100;
+const uint8_t HMC5883L_CONFIG_A_RATE_SHIFT = 2;
+
+/* Data measurement mode */
+const uint8_t HMC5883L_CONFIG_A_MMODE_NORM = 0;
+const uint8_t HMC5883L_CONFIG_A_MMODE_POSBIAS = 1;
+const uint8_t HMC5883L_CONFIG_A_MMODE_NEGBIAS = 2;
+const uint8_t HMC5883L_CONFIG_A_MMODE_MASK = 0b00000011;
+const uint8_t HMC5883L_CONFIG_A_MMODE_SHIFT = 0;
+
+/* Data output X register A contains the MSB from the measurement result,
+and data output X register B contains the LSB from the measurement result. The value stored in these two registers is a
+16-bit value in 2’s complement form, whose range is 0xF800 to 0x07FF. */
+
+
+
+ // data field
+struct HMC5883L_s {
+ int16_t MX, MY, MZ;
+ uint16_t magnitude;
+ int8_t measurement_mode;
+ int8_t data_rate;
+ int8_t average_mode;
+ int8_t gain;
+ int8_t mode;
+} *HMC5883L = nullptr;
+
+
+// Change configuration registers of the device
+bool HMC5883L_SetConfig() {
+ if ( HMC5883L == nullptr ) { return false; }
+
+ uint8_t cfgA = (( (HMC5883L->measurement_mode) << HMC5883L_CONFIG_A_MMODE_SHIFT ) & HMC5883L_CONFIG_A_MMODE_MASK ) |
+ (( (HMC5883L->data_rate ) << HMC5883L_CONFIG_A_RATE_SHIFT ) & HMC5883L_CONFIG_A_RATE_MASK ) |
+ (( (HMC5883L->average_mode ) << HMC5883L_CONFIG_A_AVG_SHIFT ) & HMC5883L_CONFIG_A_AVG_MASK );
+
+ uint8_t cfgB = (( (HMC5883L->gain ) << HMC5883L_CONFIG_B_GAIN_SHIFT ) & HMC5883L_CONFIG_B_GAIN_MASK );
+
+ AddLog(LOG_LEVEL_INFO,"HMC: CONFIG A: %#X CONFIG B: %#X MODE: %#X", cfgA, cfgB, HMC5883L->mode);
+
+ if (I2cWrite8(HMC5883L_ADDR, HMC5883L_CONFIG_A, cfgA ) == false) {
+ AddLog(LOG_LEVEL_INFO,"HMC: Setting CONFIG A failed");
+ return false;
+ }
+ if (I2cWrite8(HMC5883L_ADDR, HMC5883L_CONFIG_B, cfgB ) == false) {
+ AddLog(LOG_LEVEL_INFO,"HMC: Setting CONFIG B failed");
+ return false;
+ }
+ if (HMC5883L->mode == HMC5883L_MODE_CONT) {
+ if (I2cWrite8(HMC5883L_ADDR, HMC5883L_MODE, HMC5883L_MODE_CONT ) == false) {
+ AddLog(LOG_LEVEL_INFO,"HMC: Setting continuous mode failed");
+ return false;
+ }
+ }
+ return true;
+}
+
+// Initialize the device
+void HMC5883L_Init() {
+ if (!I2cSetDevice(HMC5883L_ADDR)) { return; }
+
+ HMC5883L = (HMC5883L_s *)calloc(1, sizeof(struct HMC5883L_s));
+ // standard configuration
+ HMC5883L->gain = 5;
+ HMC5883L->average_mode = 3;
+ HMC5883L->data_rate = 2;
+ HMC5883L->measurement_mode = HMC5883L_CONFIG_A_MMODE_NORM;
+ HMC5883L->mode = HMC5883L_MODE_SINGLE;
+
+ HMC5883L_SetConfig();
+
+ I2cSetActiveFound(HMC5883L_ADDR, "HMC5883L");
+}
+
+//Read the magnetic data
+void HMC5883L_ReadData(void) {
+ if (HMC5883L->mode == HMC5883L_MODE_SINGLE) {
+ if (I2cWrite8(HMC5883L_ADDR, HMC5883L_MODE, HMC5883L_MODE_SINGLE ) == false) { return; }
+ }
+
+ uint32_t timeout = millis() + 20;
+ while (!(I2cRead8(HMC5883L_ADDR, HMC5883L_STATUS) & HMC5883L_STATUS_RDY)) {
+ if (millis() > timeout) { return; } // Chip not yet ready, next round try again
+ }
+
+ HMC5883L->MX = I2cReadS16(HMC5883L_ADDR, HMC5883L_X_MSB); // Select starting with MSB register
+ HMC5883L->MY = I2cReadS16(HMC5883L_ADDR, HMC5883L_Y_MSB);
+ HMC5883L->MZ = I2cReadS16(HMC5883L_ADDR, HMC5883L_Z_MSB);
+
+ // calculate magnetic induction magnitude
+ HMC5883L->magnitude = SqrtInt((HMC5883L->MX * HMC5883L->MX) + (HMC5883L->MY * HMC5883L->MY) + (HMC5883L->MZ * HMC5883L->MZ));
+}
+
+/*********************************************************************************************\
+ * Presentation
+\*********************************************************************************************/
+
+#ifdef USE_WEBSERVER
+const char HTTP_SNS_HMC5883L[] PROGMEM =
+ "{s}HMC5883L " D_MX "{m}%d " D_UNIT_MICROTESLA "{e}" // {s} = , {m} = | , {e} = |
+ "{s}HMC5883L " D_MY "{m}%d " D_UNIT_MICROTESLA "{e}" // {s} = , {m} = | , {e} = |
+ "{s}HMC5883L " D_MZ "{m}%d " D_UNIT_MICROTESLA "{e}" // {s} = , {m} = | , {e} = |
+ "{s}HMC5883L " D_MAGNETICFLD "{m}%d " D_UNIT_MICROTESLA "{e}"; // {s} = , {m} = | , {e} = |
+#endif
+
+void HMC5883L_Show(uint8_t json) {
+ if (json) {
+ ResponseAppend_P(PSTR(",\"HMC5883L\":{\"" D_JSON_MX "\":%d,\"" D_JSON_MY "\":%d,\"" D_JSON_MZ "\":%d,\"" D_JSON_MAGNETICFLD "\":%u}"),
+ HMC5883L->MX, HMC5883L->MY, HMC5883L->MZ, HMC5883L->magnitude);
+#ifdef USE_WEBSERVER
+ } else {
+ WSContentSend_PD(HTTP_SNS_HMC5883L, HMC5883L->MX, HMC5883L->MY, HMC5883L->MZ, HMC5883L->magnitude);
+#endif
+ }
+}
+
+// Process configuration commands
+bool HMC5883L_Command() {
+ bool commandKnown = false;
+ char cmd[20];
+ char ss2[20];
+
+ subStr(cmd, XdrvMailbox.data, ",", 1);
+ int8_t value = atoi(subStr(ss2, XdrvMailbox.data, ",", 2));
+
+ if (strcmp(cmd,"GAIN")) {
+ HMC5883L->gain = value;
+ commandKnown = true;
+ }
+ if (strcmp(cmd,"AVG")) {
+ HMC5883L->average_mode = value;
+ commandKnown = true;
+ }
+ if (strcmp(cmd,"RATE")) {
+ HMC5883L->data_rate = value;
+ commandKnown = true;
+ }
+ if (strcmp(cmd,"MMODE")) {
+ HMC5883L->measurement_mode = value;
+ commandKnown = true;
+ }
+
+ //AddLog(LOG_LEVEL_INFO,PSTR(D_LOG_I2C "HMC: cmd: (%s) value: %d cmdKnown: %d"), cmd, value,commandKnown);
+
+ if (commandKnown == false) { return false; }
+
+ AddLog(LOG_LEVEL_INFO,PSTR(D_LOG_I2C "HMC: Reconfiguring."));
+
+ return HMC5883L_SetConfig();
+}
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xsns101(uint32_t function) {
+ if (!I2cEnabled(XI2C_73)) { return false; }
+
+ if (FUNC_INIT == function) {
+ HMC5883L_Init();
+ }
+ else if (HMC5883L != nullptr) {
+ switch (function) {
+ case FUNC_COMMAND_SENSOR:
+ if (XSNS_101 == XdrvMailbox.index) {
+ return HMC5883L_Command(); // Return true on success
+ }
+ break;
+ case FUNC_JSON_APPEND:
+ HMC5883L_Show(1);
+ break;
+ case FUNC_EVERY_SECOND:
+ HMC5883L_ReadData();
+ break;
+#ifdef USE_WEBSERVER
+ case FUNC_WEB_SENSOR:
+ HMC5883L_Show(0);
+ break;
+#endif // USE_WEBSERVER
+ }
+ }
+ return true;
+}
+#endif // USE_HMC5883L
+#endif // USE_I2C
diff --git a/tasmota/tasmota_xsns_sensor/xsns_102_ld2410.ino b/tasmota/tasmota_xsns_sensor/xsns_102_ld2410.ino
new file mode 100644
index 000000000..b21a9b03a
--- /dev/null
+++ b/tasmota/tasmota_xsns_sensor/xsns_102_ld2410.ino
@@ -0,0 +1,547 @@
+/*
+ xsns_102_ld2410.ino - HLK-LD2410 24GHz smart wave motion sensor support for Tasmota
+
+ SPDX-FileCopyrightText: 2022 Theo Arends
+
+ SPDX-License-Identifier: GPL-3.0-only
+*/
+
+#ifdef USE_LD2410
+/*********************************************************************************************\
+ * HLK-LD2410 24GHz smart wave motion sensor
+ *
+ * LD2410Duration 0 - Set factory default settings
+ * LD2410Duration 1..65535 - Set no-one duration in seconds (default 5)
+ * LD2410MovingSens 50,50,40,30,20,15,15,15,15 - Set moving distance sensitivity for up to 9 gates (at 0.75 meter interval)
+ * LD2410StaticSens 0,0,40,40,30,30,20,20,20 - Set static distance sensitivity for up to 9 gates (at 0.75 meter interval)
+ *
+ * Inspiration:
+ * https://community.home-assistant.io/t/mmwave-wars-one-sensor-module-to-rule-them-all/453260/2
+ * Resources:
+ * https://drive.google.com/drive/folders/1p4dhbEJA3YubyIjIIC7wwVsSo8x29Fq-?spm=a2g0o.detail.1000023.17.93465697yFwVxH
+ *
+ * Internal info:
+ * - After a LD2410 serial command a response takes about 10mS
+ * - After a LD2410 restart it takes at least 1000mS before commands are allowed
+\*********************************************************************************************/
+
+#define XSNS_102 102
+
+#define LD2410_BUFFER_SIZE TM_SERIAL_BUFFER_SIZE // 64
+#define LD2410_MAX_GATES 8 // 0 to 8 (= 9) - DO NOT CHANGE
+
+#define LD2410_CMND_START_CONFIGURATION 0xFF
+#define LD2410_CMND_END_CONFIGURATION 0xFE
+#define LD2410_CMND_SET_DISTANCE 0x60
+#define LD2410_CMND_READ_PARAMETERS 0x61
+#define LD2410_CMND_START_ENGINEERING 0x62
+#define LD2410_CMND_END_ENGINEERING 0x63
+#define LD2410_CMND_SET_SENSITIVITY 0x64
+#define LD2410_CMND_GET_FIRMWARE 0xA0
+#define LD2410_CMND_SET_BAUDRATE 0xA1
+#define LD2410_CMND_FACTORY_RESET 0xA2
+#define LD2410_CMND_REBOOT 0xA3
+#define LD2410_CMND_SET_BLUETOOTH 0xA4
+#define LD2410_CMND_GET_BLUETOOTH_MAC 0xA5
+
+const uint8_t LD2410_config_header[4] = {0xFD, 0xFC, 0xFB, 0xFA};
+const uint8_t LD2410_config_footer[4] = {0x04, 0x03, 0x02, 0x01};
+const uint8_t LD2410_target_header[4] = {0xF4, 0xF3, 0xF2, 0xF1};
+const uint8_t LD2410_target_footer[4] = {0xF8, 0xF7, 0xF6, 0xF5};
+
+#include
+TasmotaSerial *LD2410Serial = nullptr;
+
+struct {
+ uint8_t *buffer;
+ uint16_t moving_distance;
+ uint16_t static_distance;
+ uint16_t detect_distance;
+ uint16_t no_one_duration;
+ uint8_t moving_sensitivity[LD2410_MAX_GATES +1];
+ uint8_t static_sensitivity[LD2410_MAX_GATES +1];
+ uint8_t max_moving_distance_gate;
+ uint8_t max_static_distance_gate;
+ uint8_t moving_energy;
+ uint8_t static_energy;
+ uint8_t step;
+ uint8_t retry;
+ uint8_t settings;
+ uint8_t byte_counter;
+ bool valid_response;
+} LD2410;
+
+/********************************************************************************************/
+
+uint32_t ToBcd(uint32_t value) {
+ return ((value >> 4) * 10) + (value & 0xF);
+}
+
+/********************************************************************************************/
+
+void Ld1410HandleTargetData(void) {
+ if ((0x0D == LD2410.buffer[4]) && (0x55 == LD2410.buffer[17])) { // Add bad reception detection
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
+ // F4 F3 F2 F1 0D 00 02 AA 00 00 00 00 00 00 37 00 00 55 00 F8 F7 F6 F5 - No target
+ // F4 F3 F2 F1 0D 00 02 AA 00 45 00 3E 00 00 3A 00 00 55 00 F8 F7 F6 F5 - No target
+ // F4 F3 F2 F1 0D 00 02 AA 03 46 00 34 00 00 3C 00 00 55 00 F8 F7 F6 F5 - Movement and Stationary target
+ // F4 F3 F2 F1 0D 00 02 AA 02 54 00 00 00 00 64 00 00 55 00 F8 F7 F6 F5 - Stationary target
+ // F4 F3 F2 F1 0D 00 02 AA 02 96 00 00 00 00 36 00 00 55 00 F8 F7 F6 F5 - Stationary target
+ // F4 F3 F2 F1 0D 00 02 AA 03 2A 00 64 00 00 64 00 00 55 00 F8 F7 F6 F5 - Movement and Stationary target
+ // header |len |dt|hd|st|movin|me|stati|se|detec|tr|ck|trailer
+ if (LD2410.buffer[8] != 0x00) { // Movement and/or Stationary target
+ LD2410.moving_distance = LD2410.buffer[10] << 8 | LD2410.buffer[9];
+ LD2410.moving_energy = LD2410.buffer[11];
+ LD2410.static_distance = LD2410.buffer[13] << 8 | LD2410.buffer[12];
+ LD2410.static_energy = LD2410.buffer[14];
+ LD2410.detect_distance = LD2410.buffer[16] << 8 | LD2410.buffer[15];
+ /*
+ AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("LD2: Type %d, State %d, Moving %d/%d%%, Static %d/%d%%, Detect %d"),
+ LD2410.buffer[6], LD2410.buffer[8],
+ LD2410.moving_distance, LD2410.moving_energy,
+ LD2410.static_distance, LD2410.static_energy,
+ LD2410.detect_distance);
+ */
+ if (0x01 == LD2410.buffer[6]) { // Engineering mode data
+ // Adds 22 extra bytes of data
+
+ }
+ } else {
+ LD2410.moving_distance = 0;
+ LD2410.moving_energy = 0;
+ LD2410.static_distance = 0;
+ LD2410.static_energy = 0;
+ LD2410.detect_distance = 0;
+ }
+ }
+}
+
+void Ld1410HandleConfigData(void) {
+ if (LD2410_CMND_READ_PARAMETERS == LD2410.buffer[6]) { // 0x61
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
+ // FD FC FB FA 1C 00 61 01 00 00 AA 08 08 08 32 32 28 1E 14 0F 0F 0F 0F 00 00 28 28 1E 1E 14 14 14 05 00 04 03 02 01 - Default
+ // header |len |cw cv|ack |hd|dd|md|sd|moving sensitivity 0..8 |static sensitivity 0..8 |timed|trailer
+ // | 28| | 0| | 8| 8| 8|50 50 40 30 20 15 15 15 15| 0 0 40 40 30 30 20 20 20| 5|
+ LD2410.max_moving_distance_gate = LD2410.buffer[12];
+ LD2410.max_static_distance_gate = LD2410.buffer[13];
+ for (uint32_t i = 0; i <= LD2410_MAX_GATES; i++) {
+ LD2410. moving_sensitivity[i] = LD2410.buffer[14 +i];
+ LD2410.static_sensitivity[i] = LD2410.buffer[23 +i];
+ }
+ LD2410.no_one_duration = LD2410.buffer[33] << 8 | LD2410.buffer[32];
+ }
+ else if (LD2410_CMND_START_CONFIGURATION == LD2410.buffer[6]) { // 0xFF
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
+ // FD FC FB FA 08 00 FF 01 00 00 01 00 40 00 04 03 02 01
+ // header |len |ty |ack |protv|bsize|trailer
+ // | 8| | 0| 1| 64|
+ LD2410.valid_response = true;
+ }
+ else if (LD2410_CMND_GET_FIRMWARE == LD2410.buffer[6]) { // 0xA0
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
+ // FD FC FB FA 0C 00 A0 01 00 00 00 01 07 01 16 15 09 22 04 03 02 01
+ // header |len |ty|hd|ack |ftype|major|minor |trailer
+ // | 12| | 1| 0| 256| 1.7| 22091516|
+ AddLog(LOG_LEVEL_INFO, PSTR("LD2: Firmware version V%d.%02d.%02d%02d%02d%02d"), // Firmware version V1.07.22091516
+ ToBcd(LD2410.buffer[13]), ToBcd(LD2410.buffer[12]),
+ ToBcd(LD2410.buffer[17]), ToBcd(LD2410.buffer[16]), ToBcd(LD2410.buffer[15]), ToBcd(LD2410.buffer[14]));
+ }
+}
+
+bool Ld2410Match(const uint8_t *header, uint32_t offset) {
+ for (uint32_t i = 0; i < 4; i++) {
+ if (LD2410.buffer[offset +i] != header[i]) { return false; }
+ }
+ return true;
+}
+
+void Ld2410Input(void) {
+/*
+ // Works with TasmotaSerial as SoftwareSerial but fails with HardwareSerial
+ uint32_t size = LD2410Serial->read(LD2410.buffer, LD2410_BUFFER_SIZE);
+ if (size) {
+ AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("LD2: Rcvd %*_H"), size, LD2410.buffer);
+
+ bool target_header = (Ld2410Match(LD2410_target_header, 0)); // F4F3F2F1
+ bool config_header = (Ld2410Match(LD2410_config_header, 0)); // FDFCFBFA
+ if (target_header || config_header) {
+ uint32_t len = LD2410.buffer[4] +10; // Total packet size
+ if (size >= len) { // Handle only the first entry (if there are more)
+ if (target_header) { // F4F3F2F1
+ if (Ld2410Match(LD2410_target_footer, len -4)) { // F8F7F6F5
+ Ld1410HandleTargetData();
+ }
+ }
+ else if (config_header) { // FDFCFBFA
+ if (Ld2410Match(LD2410_config_footer, len -4)) { // 04030201
+ Ld1410HandleConfigData();
+ }
+ }
+ }
+ }
+ }
+*/
+ // Works with TasmotaSerial and HardwareSerial
+ while (LD2410Serial->available()) {
+ yield(); // Fix watchdogs
+
+ LD2410.buffer[LD2410.byte_counter++] = LD2410Serial->read();
+ if (LD2410.byte_counter < 4) { continue; } // Need first four header bytes
+
+ uint32_t header_start = LD2410.byte_counter -4; // Fix interrupted header transmits
+ bool target_header = (Ld2410Match(LD2410_target_header, header_start)); // F4F3F2F1
+ bool config_header = (Ld2410Match(LD2410_config_header, header_start)); // FDFCFBFA
+ if ((target_header || config_header) && (header_start != 0)) {
+ memmove(LD2410.buffer, LD2410.buffer + header_start, 4); // Sync buffer with header
+ LD2410.byte_counter = 4;
+ }
+ if (LD2410.byte_counter < 6) { continue; } // Need packet size bytes
+
+ target_header = (Ld2410Match(LD2410_target_header, 0)); // F4F3F2F1
+ config_header = (Ld2410Match(LD2410_config_header, 0)); // FDFCFBFA
+ if (target_header || config_header) {
+ uint32_t len = LD2410.buffer[4] +10; // Total packet size
+ if (len > LD2410_BUFFER_SIZE) {
+ LD2410.byte_counter = 0; // Invalid data
+ break; // Exit loop to satisfy yields
+ }
+ if (LD2410.byte_counter < len) { continue; } // Need complete packet
+
+ AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("LD2: Rcvd %*_H"), len, LD2410.buffer);
+
+ if (target_header) { // F4F3F2F1
+
+// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("LD2: Rcvd %*_H"), len, LD2410.buffer);
+
+ if (Ld2410Match(LD2410_target_footer, len -4)) { // F8F7F6F5
+ Ld1410HandleTargetData();
+ }
+ }
+ else if (config_header) { // FDFCFBFA
+
+// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("LD2: Rcvd %*_H"), len, LD2410.buffer);
+
+ if (Ld2410Match(LD2410_config_footer, len -4)) { // 04030201
+ Ld1410HandleConfigData();
+ LD2410Serial->setReadChunkMode(0); // Disable chunk mode fixing Hardware Watchdogs
+ }
+ }
+ }
+ LD2410.byte_counter = 0; // Finished or bad received footer
+ break; // Exit loop to satisfy yields
+ }
+ // If here then LD2410.byte_counter could still be partial correct for next loop
+}
+
+void Ld2410SendCommand(uint32_t command, uint8_t *val = nullptr, uint32_t val_len = 0);
+void Ld2410SendCommand(uint32_t command, uint8_t *val, uint32_t val_len) {
+ uint32_t len = val_len +12;
+ uint8_t buffer[len];
+ buffer[0] = 0xFD;
+ buffer[1] = 0xFC;
+ buffer[2] = 0xFB;
+ buffer[3] = 0xFA;
+ buffer[4] = val_len +2;
+ buffer[5] = 0x00;
+ buffer[6] = command;
+ buffer[7] = 0x00;
+ if (val) {
+ for (uint32_t i = 0; i < val_len; i++) {
+ buffer[8 +i] = val[i];
+ }
+ }
+ buffer[8 +val_len] = 0x04;
+ buffer[9 +val_len] = 0x03;
+ buffer[10 +val_len] = 0x02;
+ buffer[11 +val_len] = 0x01;
+
+ AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("LD2: Send %*_H"), len, buffer);
+
+ LD2410Serial->setReadChunkMode(1); // Enable chunk mode introducing possible Hardware Watchdogs
+ LD2410Serial->flush();
+ LD2410Serial->write(buffer, len);
+}
+
+void Ld2410SetConfigMode(void) { // 0xFF
+ uint8_t value[2] = { 0x01, 0x00 };
+ Ld2410SendCommand(LD2410_CMND_START_CONFIGURATION, value, sizeof(value));
+}
+
+void Ld2410SetMaxDistancesAndNoneDuration(uint32_t max_moving_distance_range, uint32_t max_static_distance_range, uint32_t no_one_duration) { // 0x60
+ // Distance range value can be set from 1 to 8 (distance gates of 0.75 meter)
+ // No-one duration value can be set from 1 to 65535 (seconds)
+ // 00 00 08 00 00 00 01 00 08 00 00 00 02 00 05 00 00 00
+ // motio| 8|stati| 8|durat|seconds
+ uint8_t lsb_nd = no_one_duration & 0xFF;
+ uint8_t msb_nd = (no_one_duration >> 8) & 0xFF;
+ uint8_t value[18] = { 0x00, 0x00, (uint8_t)max_moving_distance_range, 0x00, 0x00, 0x00, 0x01, 0x00, (uint8_t)max_static_distance_range, 0x00, 0x00, 0x00, 0x02, 0x00, lsb_nd, msb_nd, 0x00, 0x00 };
+ Ld2410SendCommand(LD2410_CMND_SET_DISTANCE, value, sizeof(value));
+}
+
+void Ld2410SetGateSensitivity(uint32_t gate, uint32_t moving_sensitivity, uint32_t static_sensitivity) { // 0x64
+ // Sensitivity value can be set from 0 to 100 (%) for gates 0 to 8
+ // 00 00 03 00 00 00 01 00 28 00 00 00 02 00 28 00 00 00
+ // gate | 3|motio| 40|stati| 40
+ uint8_t value[18] = { 0x00, 0x00, (uint8_t)gate, 0x00, 0x00, 0x00, 0x01, 0x00, (uint8_t)moving_sensitivity, 0x00, 0x00, 0x00, 0x02, 0x00, (uint8_t)static_sensitivity, 0x00, 0x00, 0x00 };
+ Ld2410SendCommand(LD2410_CMND_SET_SENSITIVITY, value, sizeof(value));
+}
+
+void Ld2410SetAllSensitivity(uint32_t sensitivity) { // 0x64
+ // Sensitivity value can be set from 0 to 100
+ // 00 00 FF FF 00 00 01 00 28 00 00 00 02 00 28 00 00 00
+ // gate |all gates |motio| 40|stati| 40
+ uint8_t value[18] = { 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, (uint8_t)sensitivity, 0x00, 0x00, 0x00, 0x02, 0x00, (uint8_t)sensitivity, 0x00, 0x00, 0x00 };
+ Ld2410SendCommand(LD2410_CMND_SET_SENSITIVITY, value, sizeof(value));
+}
+
+void Ld2410SetBaudrate(uint32_t index) { // 0xA1
+ uint8_t value[2] = { (uint8_t)index, 0x00 };
+ Ld2410SendCommand(LD2410_CMND_SET_BAUDRATE, value, sizeof(value));
+}
+
+/********************************************************************************************/
+
+void Ld2410Every100MSecond(void) {
+ if (LD2410.step) {
+ LD2410.step--;
+ switch (LD2410.step) {
+ // case 60: Set default settings
+ case 59:
+ Ld2410SetConfigMode(); // Stop running mode
+ break;
+ case 57:
+ Ld2410SendCommand(LD2410_CMND_FACTORY_RESET);
+ break;
+ case 56:
+ Ld2410SendCommand(LD2410_CMND_REBOOT); // Wait at least 1 second
+ break;
+ case 51:
+ LD2410.step = 12;
+ AddLog(LOG_LEVEL_DEBUG, PSTR("LD2: Settings factory reset"));
+ break;
+
+ // case 40: Save settings
+ case 39:
+ Ld2410SetConfigMode(); // Stop running mode
+ break;
+ case 37:
+ Ld2410SetMaxDistancesAndNoneDuration(8, 8, LD2410.no_one_duration);
+ break;
+ case 28 ... 36: {
+ uint32_t index = LD2410.step -28;
+ Ld2410SetGateSensitivity(index, LD2410.moving_sensitivity[index], LD2410.static_sensitivity[index]);
+ }
+ break;
+ case 27:
+ LD2410.step = 3;
+ AddLog(LOG_LEVEL_DEBUG, PSTR("LD2: Settings saved"));
+ break;
+/*
+ // case 24: pre-POC using 57600 bps instead of default 256000 bps
+ case 23:
+ AddLog(LOG_LEVEL_DEBUG, PSTR("LD2: Switch to 57600 bps"));
+ LD2410Serial->flush();
+ LD2410Serial->begin(256000);
+ break;
+ case 21:
+ Ld2410SetConfigMode(); // Stop running mode
+ break;
+ case 19:
+ Ld2410SetBaudrate(4); // 57600 bps
+ break;
+ case 18:
+ Ld2410SendCommand(LD2410_CMND_REBOOT); // Wait at least 1 second
+ LD2410Serial->flush();
+ LD2410Serial->begin(57600);
+ break;
+*/
+ // case 12: Init
+ case 5:
+ Ld2410SetConfigMode(); // Stop running mode
+ break;
+ case 3:
+ if (!LD2410.valid_response && LD2410.retry) {
+ LD2410.retry--;
+ if (LD2410.retry) {
+// LD2410.step = 24; // Change baudrate
+ LD2410.step = 7; // Retry
+ } else {
+ LD2410.step = 0;
+ AddLog(LOG_LEVEL_DEBUG, PSTR("LD2: Not detected"));
+ }
+ } else {
+ Ld2410SendCommand(LD2410_CMND_GET_FIRMWARE);
+ }
+ break;
+ case 2:
+ Ld2410SendCommand(LD2410_CMND_READ_PARAMETERS);
+ break;
+ case 1:
+ Ld2410SendCommand(LD2410_CMND_END_CONFIGURATION);
+ break;
+ }
+ } else {
+ if (1 == LD2410.settings) {
+ LD2410.settings = 0;
+ LD2410.step = 40;
+ }
+ else if (2 == LD2410.settings) {
+ LD2410.settings = 0;
+ LD2410.step = 60;
+ }
+ }
+}
+
+void Ld2410EverySecond(void) {
+ if (LD2410.moving_energy) {
+ // Send state change to be captured by rules
+ // {"Time":"2022-11-26T10:48:16","Switch1":"ON","LD2410":{"Distance":[125.0,0.0,0.0],"Energy":[0,100]}}
+ MqttPublishSensor();
+ }
+}
+
+void Ld2410Detect(void) {
+ if (PinUsed(GPIO_LD2410_RX) && PinUsed(GPIO_LD2410_TX)) {
+ LD2410.buffer = (uint8_t*)malloc(LD2410_BUFFER_SIZE); // Default 64
+ if (!LD2410.buffer) { return; }
+ LD2410Serial = new TasmotaSerial(Pin(GPIO_LD2410_RX), Pin(GPIO_LD2410_TX), 2);
+ if (LD2410Serial->begin(256000)) {
+ if (LD2410Serial->hardwareSerial()) { ClaimSerial(); }
+
+ LD2410.retry = 4;
+ LD2410.step = 12;
+ }
+ }
+}
+
+/*********************************************************************************************\
+ * Commands
+\*********************************************************************************************/
+
+const char kLd2410Commands[] PROGMEM = "LD2410|" // Prefix
+ "Duration|MovingSens|StaticSens";
+
+void (* const Ld2410Command[])(void) PROGMEM = {
+ &CmndLd2410Duration, &CmndLd2410MovingSensitivity, &CmndLd2410StaticSensitivity };
+
+void Ld2410Response(void) {
+ Response_P(PSTR("{\"LD2410\":{\"Duration\":%d,\"Moving\":{\"Gates\":%d,\"Sensitivity\":["),
+ LD2410.no_one_duration, LD2410.max_moving_distance_gate);
+ for (uint32_t i = 0; i <= LD2410_MAX_GATES; i++) {
+ ResponseAppend_P(PSTR("%s%d"), (i==0)?"":",", LD2410.moving_sensitivity[i]);
+ }
+ ResponseAppend_P(PSTR("]},\"Static\":{\"Gates\":%d,\"Sensitivity\":["), LD2410.max_static_distance_gate);
+ for (uint32_t i = 0; i <= LD2410_MAX_GATES; i++) {
+ ResponseAppend_P(PSTR("%s%d"), (i==0)?"":",", LD2410.static_sensitivity[i]);
+ }
+ ResponseAppend_P(PSTR("]}}}"));
+}
+
+void CmndLd2410Duration(void) {
+ // LD2410Duration 0 - Set default settings
+ if (0 == XdrvMailbox.payload) {
+ LD2410.settings = 2;
+ }
+ // LD2410Duration 5
+ else if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 65535)) {
+ LD2410.no_one_duration = XdrvMailbox.payload;
+ LD2410.settings = 1;
+ }
+ Ld2410Response();
+}
+
+void CmndLd2410MovingSensitivity(void) {
+ // LD2410MovingSens 50,50,40,30,20,15,15,15,15
+ uint32_t parm[LD2410_MAX_GATES +1] = { 0 };
+ uint32_t count = ParseParameters(LD2410_MAX_GATES +1, parm);
+ if (count) {
+ for (uint32_t i = 0; i < count; i++) {
+ if ((parm[i] >= 0) && (parm[i] <= 100)) {
+ LD2410.moving_sensitivity[i] = parm[i];
+ }
+ }
+ LD2410.settings = 1;
+ }
+ Ld2410Response();
+}
+
+void CmndLd2410StaticSensitivity(void) {
+ // LD2410StaticSens 0,0,40,40,30,30,20,20,20
+ uint32_t parm[LD2410_MAX_GATES +1] = { 0 };
+ uint32_t count = ParseParameters(LD2410_MAX_GATES +1, parm);
+ if (count) {
+ for (uint32_t i = 0; i < count; i++) {
+ if ((parm[i] >= 0) && (parm[i] <= 100)) {
+ LD2410.static_sensitivity[i] = parm[i];
+ }
+ }
+ LD2410.settings = 1;
+ }
+ Ld2410Response();
+}
+
+/*********************************************************************************************\
+ * Presentation
+\*********************************************************************************************/
+
+#ifdef USE_WEBSERVER
+const char HTTP_SNS_LD2410_CM[] PROGMEM =
+ "{s}LD2410 " D_MOVING_DISTANCE "{m}%1_f " D_UNIT_CENTIMETER "{e}"
+ "{s}LD2410 " D_STATIC_DISTANCE "{m}%1_f " D_UNIT_CENTIMETER "{e}"
+ "{s}LD2410 " D_DETECT_DISTANCE "{m}%1_f " D_UNIT_CENTIMETER "{e}";
+#endif
+
+void Ld2410Show(bool json) {
+ float moving_distance = LD2410.moving_distance;
+ float static_distance = LD2410.static_distance;
+ float detect_distance = LD2410.detect_distance;
+ if (json) {
+ // cm cm cm % %
+ ResponseAppend_P(PSTR(",\"LD2410\":{\"" D_JSON_DISTANCE "\":[%1_f,%1_f,%1_f],\"" D_JSON_ENERGY "\":[%d,%d]}"),
+ &moving_distance, &static_distance, &detect_distance, LD2410.moving_energy, LD2410.static_energy);
+#ifdef USE_WEBSERVER
+ } else {
+ WSContentSend_PD(HTTP_SNS_LD2410_CM, &moving_distance, &static_distance, &detect_distance);
+#endif
+ }
+}
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xsns102(uint32_t function) {
+ bool result = false;
+
+ if (FUNC_INIT == function) {
+ Ld2410Detect();
+ }
+ else if (LD2410Serial) {
+ switch (function) {
+ case FUNC_LOOP:
+ case FUNC_SLEEP_LOOP:
+ Ld2410Input();
+ break;
+ case FUNC_EVERY_100_MSECOND:
+ Ld2410Every100MSecond();
+ break;
+ case FUNC_EVERY_SECOND:
+ Ld2410EverySecond();
+ break;
+ case FUNC_JSON_APPEND:
+ Ld2410Show(1);
+ break;
+#ifdef USE_WEBSERVER
+ case FUNC_WEB_SENSOR:
+ Ld2410Show(0);
+ break;
+#endif // USE_WEBSERVER
+ case FUNC_COMMAND:
+ result = DecodeCommand(kLd2410Commands, Ld2410Command);
+ break;
+ }
+ }
+ return result;
+}
+
+#endif // USE_LD2410
diff --git a/tasmota/tasmota_xsns_sensor/xsns_10_bh1750.ino b/tasmota/tasmota_xsns_sensor/xsns_10_bh1750.ino
index c67b0e24e..521defe68 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_10_bh1750.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_10_bh1750.ino
@@ -193,7 +193,7 @@ void Bh1750Show(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns10(uint8_t function) {
+bool Xsns10(uint32_t function) {
if (!I2cEnabled(XI2C_11)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_11_veml6070.ino b/tasmota/tasmota_xsns_sensor/xsns_11_veml6070.ino
index cb24554ad..343ff4852 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_11_veml6070.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_11_veml6070.ino
@@ -1,7 +1,7 @@
/*
xsns_11_veml6070.ino - VEML6070 ultra violet light sensor support for Tasmota
- Copyright (C) 2021 Theo Arends
+ Copyright (C) 2021 Mike2Nl
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
@@ -294,7 +294,7 @@ void Veml6070Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns11(uint8_t function)
+bool Xsns11(uint32_t function)
{
if (!I2cEnabled(XI2C_12)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_127_esp32_sensors.ino b/tasmota/tasmota_xsns_sensor/xsns_127_esp32_sensors.ino
index 6da0baaca..c50d9a82d 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_127_esp32_sensors.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_127_esp32_sensors.ino
@@ -126,7 +126,7 @@ void Esp32SensorShow(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns127(uint8_t function) {
+bool Xsns127(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_12_ads1115.ino b/tasmota/tasmota_xsns_sensor/xsns_12_ads1115.ino
index 052625249..0610ca9d0 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_12_ads1115.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_12_ads1115.ino
@@ -1,7 +1,7 @@
/*
xsns_12_ads1115_ada.ino - ADS1115 A/D Converter support for Tasmota
- Copyright (C) 2021 Theo Arends
+ Copyright (C) 2021 Syssi, stefanbode
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
@@ -176,7 +176,7 @@ void Ads1115Detect(void)
// Set default mode and range
Ads1115.channels = ADS1115_SINGLE_CHANNELS;
Ads1115.range = ADS1115_REG_CONFIG_PGA_6_144V;
-
+
for (uint32_t i = 0; i < sizeof(Ads1115.addresses); i++) {
if (!Ads1115.found[i]) {
Ads1115.address = Ads1115.addresses[i];
@@ -331,7 +331,7 @@ bool ADS1115_Command(void)
* Interface
\*********************************************************************************************/
-bool Xsns12(uint8_t function)
+bool Xsns12(uint32_t function)
{
if (!I2cEnabled(XI2C_13)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_13_ina219.ino b/tasmota/tasmota_xsns_sensor/xsns_13_ina219.ino
index 50e9a39e5..92a679e92 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_13_ina219.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_13_ina219.ino
@@ -369,7 +369,7 @@ void Ina219Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns13(uint8_t function)
+bool Xsns13(uint32_t function)
{
if (!I2cEnabled(XI2C_14)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_14_sht3x.ino b/tasmota/tasmota_xsns_sensor/xsns_14_sht3x.ino
index b073020e8..24dd17394 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_14_sht3x.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_14_sht3x.ino
@@ -155,7 +155,7 @@ void Sht3xShow(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns14(uint8_t function) {
+bool Xsns14(uint32_t function) {
if (!I2cEnabled(XI2C_15)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_15_mhz19.ino b/tasmota/tasmota_xsns_sensor/xsns_15_mhz19.ino
index 67745ddb4..3d89ff470 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_15_mhz19.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_15_mhz19.ino
@@ -362,7 +362,7 @@ void MhzShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns15(uint8_t function)
+bool Xsns15(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_16_tsl2561.ino b/tasmota/tasmota_xsns_sensor/xsns_16_tsl2561.ino
index d0674c522..357522cfb 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_16_tsl2561.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_16_tsl2561.ino
@@ -116,7 +116,7 @@ void Tsl2561Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns16(uint8_t function)
+bool Xsns16(uint32_t function)
{
if (!I2cEnabled(XI2C_16)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_17_senseair.ino b/tasmota/tasmota_xsns_sensor/xsns_17_senseair.ino
index ea6ba683b..a2a20196c 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_17_senseair.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_17_senseair.ino
@@ -70,7 +70,7 @@ void Senseair250ms(void) // Every 250 mSec
if (data_ready) {
uint8_t error = SenseairModbus->Receive16BitRegister(&value);
if (error) {
- AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "SenseAir response error %d"), error);
+ AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "SenseAir read register %02X gave response error %d"), (uint16_t)start_addresses[senseair_read_state], error);
} else {
switch(senseair_read_state) {
case 0: // 0x1A (26) READ_TYPE_LOW - S8: fe 04 02 01 77 ec 92
@@ -104,15 +104,16 @@ void Senseair250ms(void) // Every 250 mSec
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "SenseAir temp adjustment %d"), value);
break;
}
- }
- senseair_read_state++;
- if (2 == senseair_type) { // S8
- if (3 == senseair_read_state) {
- senseair_read_state = 1;
- }
- } else { // K30, K70
- if (sizeof(start_addresses) == senseair_read_state) {
- senseair_read_state = 1;
+
+ senseair_read_state++;
+ if (2 == senseair_type) { // S8
+ if (3 == senseair_read_state) {
+ senseair_read_state = 1;
+ }
+ } else { // K30, K70
+ if (sizeof(start_addresses) == senseair_read_state) {
+ senseair_read_state = 1;
+ }
}
}
}
@@ -172,7 +173,7 @@ void SenseairShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns17(uint8_t function)
+bool Xsns17(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_18_pms5003.ino b/tasmota/tasmota_xsns_sensor/xsns_18_pms5003.ino
index b1cac1a81..7a403fdb6 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_18_pms5003.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_18_pms5003.ino
@@ -26,6 +26,7 @@
* Hardware Serial will be selected if GPIO3 = [PMS5003]
* You can either support PMS3003 or PMS5003-7003 at one time. To enable the PMS3003 support
* you must enable the define PMS_MODEL_PMS3003 on your configuration file.
+ * For PMSx003T models that report temperature and humidity define PMS_MODEL_PMS5003T
\*********************************************************************************************/
#define XSNS_18 18
@@ -75,7 +76,12 @@ struct pmsX003data {
#ifdef PMS_MODEL_PMS3003
uint16_t reserved1, reserved2, reserved3;
#else
- uint16_t particles_03um, particles_05um, particles_10um, particles_25um, particles_50um, particles_100um;
+ uint16_t particles_03um, particles_05um, particles_10um, particles_25um;
+#ifdef PMS_MODEL_PMS5003T
+ uint16_t temperature10x, humidity10x;
+#else
+ uint16_t particles_50um, particles_100um;
+#endif // PMS_MODEL_PMS5003T
uint16_t unused;
#endif // PMS_MODEL_PMS3003
uint16_t checksum;
@@ -289,24 +295,40 @@ const char HTTP_PMS5003_SNS[] PROGMEM =
"{s}PMS5003 " D_PARTICALS_BEYOND " 0.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"
"{s}PMS5003 " D_PARTICALS_BEYOND " 1 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"
"{s}PMS5003 " D_PARTICALS_BEYOND " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"
+#ifdef PMS_MODEL_PMS5003T
+ "{s}PMS5003 " D_TEMPERATURE "{m}%*_f " D_UNIT_DEGREE "%c{e}"
+ "{s}PMS5003 " D_HUMIDITY "{m}%*_f " D_UNIT_PERCENT "{e}";
+#else
"{s}PMS5003 " D_PARTICALS_BEYOND " 5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"
"{s}PMS5003 " D_PARTICALS_BEYOND " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_PARTS_PER_DECILITER "{e}"; // {s} = , {m} = | , {e} = |
+#endif // PMS_MODEL_PMS5003T
#endif // PMS_MODEL_PMS3003
#endif // USE_WEBSERVER
void PmsShow(bool json)
{
if (Pms.valid) {
+#ifdef PMS_MODEL_PMS5003T
+ float temperature = ConvertTemp(pms_data.temperature10x/10.0);
+ float humidity = ConvertHumidity(pms_data.humidity10x/10.0);
+#endif // PMS_MODEL_PMS5003T
if (json) {
#ifdef PMS_MODEL_PMS3003
ResponseAppend_P(PSTR(",\"PMS3003\":{\"CF1\":%d,\"CF2.5\":%d,\"CF10\":%d,\"PM1\":%d,\"PM2.5\":%d,\"PM10\":%d}"),
pms_data.pm10_standard, pms_data.pm25_standard, pms_data.pm100_standard,
pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env);
#else
- ResponseAppend_P(PSTR(",\"PMS5003\":{\"CF1\":%d,\"CF2.5\":%d,\"CF10\":%d,\"PM1\":%d,\"PM2.5\":%d,\"PM10\":%d,\"PB0.3\":%d,\"PB0.5\":%d,\"PB1\":%d,\"PB2.5\":%d,\"PB5\":%d,\"PB10\":%d}"),
+ ResponseAppend_P(PSTR(",\"PMS5003\":{\"CF1\":%d,\"CF2.5\":%d,\"CF10\":%d,\"PM1\":%d,\"PM2.5\":%d,\"PM10\":%d,\"PB0.3\":%d,\"PB0.5\":%d,\"PB1\":%d,\"PB2.5\":%d,"),
pms_data.pm10_standard, pms_data.pm25_standard, pms_data.pm100_standard,
pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env,
- pms_data.particles_03um, pms_data.particles_05um, pms_data.particles_10um, pms_data.particles_25um, pms_data.particles_50um, pms_data.particles_100um);
+ pms_data.particles_03um, pms_data.particles_05um, pms_data.particles_10um, pms_data.particles_25um);
+#ifdef PMS_MODEL_PMS5003T
+ ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "\":%*_f,\"" D_JSON_HUMIDITY "\":%*_f}"),
+ Settings->flag2.temperature_resolution, &temperature, Settings->flag2.humidity_resolution, &humidity);
+#else
+ ResponseAppend_P(PSTR("\"PB5\":%d,\"PB10\":%d}"),
+ pms_data.particles_50um, pms_data.particles_100um);
+#endif // PMS_MODEL_PMS5003T
#endif // PMS_MODEL_PMS3003
#ifdef USE_DOMOTICZ
if (0 == TasmotaGlobal.tele_period) {
@@ -322,6 +344,10 @@ void PmsShow(bool json)
WSContentSend_PD(HTTP_PMS3003_SNS,
// pms_data.pm10_standard, pms_data.pm25_standard, pms_data.pm100_standard,
pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env);
+#elif defined(PMS_MODEL_PMS5003T)
+ WSContentSend_PD(HTTP_PMS5003_SNS,
+ pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env,
+ pms_data.particles_03um, pms_data.particles_05um, pms_data.particles_10um, pms_data.particles_25um, Settings->flag2.temperature_resolution, &temperature, TempUnit(), Settings->flag2.humidity_resolution, &humidity);
#else
WSContentSend_PD(HTTP_PMS5003_SNS,
// pms_data.pm10_standard, pms_data.pm25_standard, pms_data.pm100_standard,
@@ -337,7 +363,7 @@ void PmsShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns18(uint8_t function)
+bool Xsns18(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_19_mgs.ino b/tasmota/tasmota_xsns_sensor/xsns_19_mgs.ino
index 5334c5c48..519c48b0a 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_19_mgs.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_19_mgs.ino
@@ -89,7 +89,7 @@ void MGSShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns19(uint8_t function)
+bool Xsns19(uint32_t function)
{
if (!I2cEnabled(XI2C_17)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_20_novasds.ino b/tasmota/tasmota_xsns_sensor/xsns_20_novasds.ino
index 71a4b1c77..a0c773923 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_20_novasds.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_20_novasds.ino
@@ -1,7 +1,7 @@
/*
xsns_20_novasds.ino - Nova SDS011/SDS021 particle concentration sensor support for Tasmota
- Copyright (C) 2021 Theo Arends
+ Copyright (C) 2021 Norbert Richter
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -249,7 +249,7 @@ void NovaSdsShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns20(uint8_t function)
+bool Xsns20(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_21_sgp30.ino b/tasmota/tasmota_xsns_sensor/xsns_21_sgp30.ino
index a2509da94..54a7a77b5 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_21_sgp30.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_21_sgp30.ino
@@ -1,7 +1,7 @@
/*
xsns_21_sgp30.ino - SGP30 gas and air quality sensor support for Tasmota
- Copyright (C) 2021 Theo Arends
+ Copyright (C) 2021 Gerhard Mutz
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -143,7 +143,7 @@ void Sgp30Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns21(uint8_t function)
+bool Xsns21(uint32_t function)
{
if (!I2cEnabled(XI2C_18)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_22_sr04.ino b/tasmota/tasmota_xsns_sensor/xsns_22_sr04.ino
index 85c13a97b..01f5a22a9 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_22_sr04.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_22_sr04.ino
@@ -190,19 +190,16 @@ void Sr04TReading(void) {
void Sr04Show(bool json) {
if (SR04.valid) { // Check if read failed
- char distance_chr[33];
- dtostrfd(SR04.distance, 3, distance_chr);
-
if(json) {
- ResponseAppend_P(PSTR(",\"SR04\":{\"" D_JSON_DISTANCE "\":%s}"), distance_chr);
+ ResponseAppend_P(PSTR(",\"SR04\":{\"" D_JSON_DISTANCE "\":%1_f}"), &SR04.distance);
#ifdef USE_DOMOTICZ
if (0 == TasmotaGlobal.tele_period) {
- DomoticzSensor(DZ_COUNT, distance_chr); // Send distance as Domoticz Counter value
+ DomoticzFloatSensor(DZ_COUNT, SR04.distance); // Send distance as Domoticz Counter value
}
#endif // USE_DOMOTICZ
#ifdef USE_WEBSERVER
} else {
- WSContentSend_PD(HTTP_SNS_DISTANCE_CM, "SR04", distance_chr);
+ WSContentSend_PD(HTTP_SNS_F_DISTANCE_CM, "SR04", &SR04.distance);
#endif // USE_WEBSERVER
}
}
@@ -212,7 +209,7 @@ void Sr04Show(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns22(uint8_t function) {
+bool Xsns22(uint32_t function) {
bool result = false;
if (SR04.type) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_24_si1145.ino b/tasmota/tasmota_xsns_sensor/xsns_24_si1145.ino
index 393211a9b..0f4df82e5 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_24_si1145.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_24_si1145.ino
@@ -369,7 +369,7 @@ void Si1145Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns24(uint8_t function)
+bool Xsns24(uint32_t function)
{
if (!I2cEnabled(XI2C_19)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_26_lm75ad.ino b/tasmota/tasmota_xsns_sensor/xsns_26_lm75ad.ino
index 03501b9a1..b8c271180 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_26_lm75ad.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_26_lm75ad.ino
@@ -100,7 +100,7 @@ void LM75ADShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns26(uint8_t function)
+bool Xsns26(uint32_t function)
{
if (!I2cEnabled(XI2C_20)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_27_apds9960.ino b/tasmota/tasmota_xsns_sensor/xsns_27_apds9960.ino
index 6c868a4be..64b6864a6 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_27_apds9960.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_27_apds9960.ino
@@ -1992,7 +1992,7 @@ bool APDS9960CommandSensor(void) {
* Interface
\*********************************************************************************************/
-bool Xsns27(uint8_t function) {
+bool Xsns27(uint32_t function) {
if (!I2cEnabled(XI2C_21)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_28_tm1638.ino b/tasmota/tasmota_xsns_sensor/xsns_28_tm1638.ino
index 2c3e32707..8a0cdb8f8 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_28_tm1638.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_28_tm1638.ino
@@ -198,7 +198,7 @@ void TmShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns28(uint8_t function)
+bool Xsns28(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_29_mcp230xx.ino b/tasmota/tasmota_xsns_sensor/xsns_29_mcp230xx.ino
index 64d5b1700..f158b79f6 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_29_mcp230xx.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_29_mcp230xx.ino
@@ -903,7 +903,7 @@ void MCP230xx_SwitchRelay() {
Interface
\*********************************************************************************************/
-bool Xsns29(uint8_t function)
+bool Xsns29(uint32_t function)
{
if (!I2cEnabled(XI2C_22)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_30_mpr121.ino b/tasmota/tasmota_xsns_sensor/xsns_30_mpr121.ino
index 24a0cbdd7..015b121a6 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_30_mpr121.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_30_mpr121.ino
@@ -386,7 +386,7 @@ void Mpr121Show(struct mpr121 *pS, uint8_t function)
}
} // if->running
} // for-loop i
-} // void Mpr121Show(uint8_t function)
+} // void Mpr121Show(uint32_t function)
/*********************************************************************************************\
* Interface
@@ -407,7 +407,7 @@ void Mpr121Show(struct mpr121 *pS, uint8_t function)
* @post None.
*
*/
-bool Xsns30(uint8_t function)
+bool Xsns30(uint32_t function)
{
if (!I2cEnabled(XI2C_23)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_31_ccs811.ino b/tasmota/tasmota_xsns_sensor/xsns_31_ccs811.ino
index c0525a909..4b59c99b1 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_31_ccs811.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_31_ccs811.ino
@@ -105,7 +105,7 @@ void CCS811Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns31(uint8_t function)
+bool Xsns31(uint32_t function)
{
if (!I2cEnabled(XI2C_24)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_31_ccs811_v2.ino b/tasmota/tasmota_xsns_sensor/xsns_31_ccs811_v2.ino
index 735ebdbf9..2f16406f7 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_31_ccs811_v2.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_31_ccs811_v2.ino
@@ -306,7 +306,7 @@ void CCS811Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns31(uint8_t function)
+bool Xsns31(uint32_t function)
{
if (!I2cEnabled(XI2C_24)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_32_mpu6050.ino b/tasmota/tasmota_xsns_sensor/xsns_32_mpu6050.ino
index eaa4018ac..0aa43ea10 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_32_mpu6050.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_32_mpu6050.ino
@@ -248,7 +248,7 @@ void MPU_6050Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns32(uint8_t function)
+bool Xsns32(uint32_t function)
{
if (!I2cEnabled(XI2C_25)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_33_qmc5883l.ino b/tasmota/tasmota_xsns_sensor/xsns_33_qmc5883l.ino
index 7c640a737..f024da374 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_33_qmc5883l.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_33_qmc5883l.ino
@@ -283,7 +283,7 @@ void QMC5883L_Show(uint8_t json) {
* Interface
\*********************************************************************************************/
-bool Xsns33(byte function) {
+bool Xsns33(uint32_t function) {
if (!I2cEnabled(XI2C_71)) { return false; }
if (FUNC_INIT == function) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_34_hx711.ino b/tasmota/tasmota_xsns_sensor/xsns_34_hx711.ino
index 8a051949a..a12cce716 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_34_hx711.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_34_hx711.ino
@@ -574,7 +574,7 @@ void HandleHxAction(void) {
* Interface
\*********************************************************************************************/
-bool Xsns34(uint8_t function) {
+bool Xsns34(uint32_t function) {
bool result = false;
if (Hx.type) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_35_tx20.ino b/tasmota/tasmota_xsns_sensor/xsns_35_tx20.ino
index 3e1cfd25b..a128f2fe3 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_35_tx20.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_35_tx20.ino
@@ -581,7 +581,7 @@ void Tx2xShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns35(uint8_t function)
+bool Xsns35(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_36_mgc3130.ino b/tasmota/tasmota_xsns_sensor/xsns_36_mgc3130.ino
index 73961c753..39e84608a 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_36_mgc3130.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_36_mgc3130.ino
@@ -599,7 +599,7 @@ bool MGC3130CommandSensor()
* Interface
\*********************************************************************************************/
-bool Xsns36(uint8_t function)
+bool Xsns36(uint32_t function)
{
if (!I2cEnabled(XI2C_27)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_37_rfsensor.ino b/tasmota/tasmota_xsns_sensor/xsns_37_rfsensor.ino
index 25db41a0c..aa3d8b6d1 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_37_rfsensor.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_37_rfsensor.ino
@@ -649,7 +649,7 @@ void RfSnsShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns37(uint8_t function)
+bool Xsns37(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_38_az7798.ino b/tasmota/tasmota_xsns_sensor/xsns_38_az7798.ino
index 1aed89816..1869ed76f 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_38_az7798.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_38_az7798.ino
@@ -1,7 +1,7 @@
/*
xsns_38_az7798.ino - AZ_Instrument 7798 CO2/temperature/humidity meter support for Tasmota
- Copyright (C) 2021 Theo Arends
+ Copyright (C) 2021 adebeun
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
@@ -297,7 +297,7 @@ void AzShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns38(uint8_t function)
+bool Xsns38(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_39_max31855.ino b/tasmota/tasmota_xsns_sensor/xsns_39_max31855.ino
index 1b7bca1b3..13b0450b2 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_39_max31855.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_39_max31855.ino
@@ -169,7 +169,7 @@ void MAX31855_Show(bool Json) {
* Interface
\*********************************************************************************************/
-bool Xsns39(uint8_t function)
+bool Xsns39(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_40_pn532.ino b/tasmota/tasmota_xsns_sensor/xsns_40_pn532.ino
index 03eba20c7..dee669dd5 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_40_pn532.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_40_pn532.ino
@@ -1,7 +1,7 @@
/*
xsns_40_pn532.ino - Support for PN532 (HSU) NFC Tag Reader on Tasmota
- Copyright (C) 2021 Andre Thomas and Theo Arends
+ Copyright (C) 2021 Andre Thomas, Theo Arends and md5sum-as (https://github.com/md5sum-as)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -47,24 +47,48 @@ TasmotaSerial *PN532_Serial;
#define PN532_COMMAND_SAMCONFIGURATION 0x14
#define PN532_COMMAND_RFCONFIGURATION 0x32
#define PN532_COMMAND_INDATAEXCHANGE 0x40
+#define PN532_COMMAND_INCOMMUNICATETHRU 0x42
#define PN532_COMMAND_INLISTPASSIVETARGET 0x4A
-
+#define PN532_COMMAND_INRELEASE 0x52
+#define PN532_COMMAND_INSELECT 0x54
#define PN532_MIFARE_ISO14443A 0x00
#define MIFARE_CMD_READ 0x30
#define MIFARE_CMD_AUTH_A 0x60
#define MIFARE_CMD_AUTH_B 0x61
#define MIFARE_CMD_WRITE 0xA0
+#define NTAG21X_CMD_GET_VERSION 0x60
+#define NTAG2XX_CMD_READ 0x30
+#define NTAG21X_CMD_FAST_READ 0x3A
+#define NTAG21X_CMD_PWD_AUTH 0x1B
+#define NTAG2XX_CMD_WRITE 0xA2
+
+const struct {
+ uint8_t version[6];
+ uint8_t confPage;
+} NTAG[] PROGMEM ={
+ {.version={0x04, 0x02, 0x01, 0x00, 0x0f, 0x03},.confPage=0x29}, /* NTAG213 */
+ {.version={0x04, 0x02, 0x01, 0x00, 0x11, 0x03},.confPage=0x83}, /* NTAG215 */
+ {.version={0x04, 0x02, 0x01, 0x00, 0x13, 0x03},.confPage=0xe3}, /* NTAG216 */
+ {.version={0x04, 0x05, 0x02, 0x02, 0x13, 0x03},.confPage=0xe3}, /* NT3H2111 */
+ {.version={0x04, 0x05, 0x02, 0x02, 0x15, 0x03},.confPage=0xe3}, /* NT3H2211 */
+};
+#define NTAG_CNT (sizeof(NTAG)/7) // num records in NTAG array
+
struct PN532 {
char uids[21]; // Number of bytes in the UID. 4, 7 or 10
uint8_t packetbuffer[64]; // Global buffer used to store packet
uint8_t command = 0; // Carry command code between functions
uint8_t scantimer = 0; // Prevent multiple successful reads within 2 second window
bool present = false; // Maintain detection flag
+ uint16_t atqa;
#ifdef USE_PN532_DATA_FUNCTION
uint8_t newdata[16];
uint8_t function = 0;
- uint8_t newdata_len = 0;
+ uint32_t pwd_auth;
+ uint16_t pwd_pack;
+ uint32_t pwd_auth_new;
+ uint16_t pwd_pack_new;
#endif // USE_PN532_DATA_FUNCTION
} Pn532;
@@ -82,6 +106,10 @@ void PN532_Init(void) {
PN532_SAMConfig();
AddLog(LOG_LEVEL_INFO,"NFC: PN532 NFC Reader detected v%u.%u",(ver>>16) & 0xFF, (ver>>8) & 0xFF);
Pn532.present = true;
+#ifdef USE_PN532_DATA_FUNCTION
+ Pn532.pwd_auth=Settings->pn532_password;
+ Pn532.pwd_pack=Settings->pn532_pack;
+#endif
}
}
}
@@ -273,9 +301,9 @@ bool PN532_readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidL
return 0;
}
- uint16_t sens_res = Pn532.packetbuffer[2];
- sens_res <<= 8;
- sens_res |= Pn532.packetbuffer[3];
+ Pn532.atqa = Pn532.packetbuffer[2];
+ Pn532.atqa <<= 8;
+ Pn532.atqa |= Pn532.packetbuffer[3];
/* Card appears to be Mifare Classic */
*uidLength = Pn532.packetbuffer[5];
@@ -310,9 +338,27 @@ bool PN532_SAMConfig(void) {
return (0 < PN532_readResponse(Pn532.packetbuffer, sizeof(Pn532.packetbuffer)));
}
+/* void PN532_inSelect(void) {
+ Pn532.packetbuffer[0] = PN532_COMMAND_INSELECT;
+ Pn532.packetbuffer[1] = 1;
+ if (PN532_writeCommand(Pn532.packetbuffer, 2)) {
+ return ;
+ }
+ int16_t res = PN532_readResponse(Pn532.packetbuffer, sizeof(Pn532.packetbuffer));
+} */
+
#ifdef USE_PN532_DATA_FUNCTION
-uint8_t mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData) {
+void PN532_inRelease(void) {
+ Pn532.packetbuffer[0] = PN532_COMMAND_INRELEASE;
+ Pn532.packetbuffer[1] = 1;
+ if (PN532_writeCommand(Pn532.packetbuffer, 2)) {
+ return;
+ }
+ PN532_readResponse(Pn532.packetbuffer, sizeof(Pn532.packetbuffer));
+}
+
+uint8_t PN532_mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData) {
uint8_t i;
uint8_t _key[6];
uint8_t _uid[7];
@@ -349,7 +395,7 @@ uint8_t mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t
return 1;
}
-uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data) {
+uint8_t PN532_mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data) {
/* Prepare the command */
Pn532.packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
Pn532.packetbuffer[1] = 1; /* Card number */
@@ -376,7 +422,7 @@ uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data) {
return 1;
}
-uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data) {
+uint8_t PN532_mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data) {
/* Prepare the first command */
Pn532.packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
Pn532.packetbuffer[1] = 1; /* Card number */
@@ -393,73 +439,181 @@ uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data) {
return (0 < PN532_readResponse(Pn532.packetbuffer, sizeof(Pn532.packetbuffer)));
}
+uint8_t PN532_ntag21x_probe (void) {
+ uint8_t result=0;
+
+ Pn532.packetbuffer[0] = PN532_COMMAND_INCOMMUNICATETHRU;
+ Pn532.packetbuffer[1] = NTAG21X_CMD_GET_VERSION;
+
+ if (PN532_writeCommand(Pn532.packetbuffer, 2)) {
+ return result;
+ }
+
+ if (PN532_readResponse(Pn532.packetbuffer, sizeof(Pn532.packetbuffer))<9){
+ return result;
+ }
+
+ if (Pn532.packetbuffer[3] != 4) { // not NTAG type
+ return result;
+ }
+
+ for (uint8_t i=0; i0) {
+ /* NTAG EV1 found*/
+ str_pwd=PWD_NONE;
+ if (!PN532_ntag2xx_read16(4, card_datas)) {
+ if (PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, nuid, &nuid_len)) {
+ if (memcmp(uid, nuid, sizeof(uid))==0) {
+ if (PN532_ntag21x_auth()) {
+ str_pwd=PWD_OK;
+ if (Pn532.function == 3) { /* new password */
+ success = PN532_ntag21x_set_password(confPage, false);
+ }
+ if (Pn532.function == 4) { /* clear password */
+ success = PN532_ntag21x_set_password(confPage, true);
+ }
+ } else {
+ str_pwd=PWD_NOK;
+ }
+ if (!PN532_ntag2xx_read16(4, card_datas)) card_datas[0]=0;
+ }
+ }
+ } else {
+ if (Pn532.function == 3) { /* new password */
+ success = PN532_ntag21x_set_password(confPage, false);
+ }
+ }
+ } else {
+ if (PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, nuid, &nuid_len)) {
+ if (memcmp(uid, nuid, sizeof(uid))==0) {
+ if (!PN532_ntag2xx_read16(4, card_datas)) card_datas[0]=0;
+ }
+ }
+ }
+ if ((Pn532.function == 1) || (Pn532.function == 2)) {
+ success = PN532_ntag2xx_write16(4, (char *)Pn532.newdata);
+ if (!PN532_ntag2xx_read16(4, card_datas)) card_datas[0]=0;
+ }
+ }
+ else if (uid_len == 4) { // Lets try to read blocks 1 & 2 of the mifare classic card for more information
uint8_t keyuniversal[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
- if (mifareclassic_AuthenticateBlock (uid, uid_len, 1, 1, keyuniversal)) {
- uint8_t card_data[16];
- if (mifareclassic_ReadDataBlock(1, card_data)) {
-#ifdef USE_PN532_DATA_RAW
- memcpy(&card_datas,&card_data,sizeof(card_data));
-#else
- for (uint32_t i = 0;i < sizeof(card_data);i++) {
- if ((isalpha(card_data[i])) || ((isdigit(card_data[i])))) {
- card_datas[i] = char(card_data[i]);
- } else {
- card_datas[i] = '\0';
- }
- }
-#endif // USE_PN532_DATA_RAW
+ if (PN532_mifareclassic_AuthenticateBlock (uid, uid_len, 1, 1, keyuniversal)) {
+ if ((Pn532.function == 1) || (Pn532.function == 2)) {
+ success=PN532_mifareclassic_WriteDataBlock(1, Pn532.newdata);
}
- if (Pn532.function == 1) { // erase block 1 of card
- for (uint32_t i = 0;i<16;i++) {
- card_data[i] = 0x00;
- }
- if (mifareclassic_WriteDataBlock(1, card_data)) {
- erase_success = true;
- AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Erase success"));
- memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string
- }
- }
- if (Pn532.function == 2) {
-#ifdef USE_PN532_DATA_RAW
- memcpy(&card_data,&Pn532.newdata,sizeof(card_data));
- if (mifareclassic_WriteDataBlock(1, card_data)) {
- set_success = true;
- AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Data write successful"));
- memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string
- }
-#else
- bool IsAlphaNumeric = true;
- for (uint32_t i = 0;i < Pn532.newdata_len;i++) {
- if ((!isalpha(Pn532.newdata[i])) && (!isdigit(Pn532.newdata[i]))) {
- IsAlphaNumeric = false;
+ if (PN532_mifareclassic_ReadDataBlock(1, (uint8_t *)card_datas)) {
+ for (uint32_t i = 0; i < 16; i++) {
+ if (!isprint(card_datas[i])) {
+ // do not output non-printable characters to the console
+ card_datas[i] = 0;
}
}
- if (IsAlphaNumeric) {
- memcpy(&card_data,&Pn532.newdata,Pn532.newdata_len);
- card_data[Pn532.newdata_len] = '\0'; // Enforce null termination
- if (mifareclassic_WriteDataBlock(1, card_data)) {
- set_success = true;
- AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Data write successful"));
- memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string
- }
- } else {
- AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Data must be alphanumeric"));
- }
-#endif // USE_PN532_DATA_RAW
+ } else {
+ card_datas[0] = 0;
}
} else {
sprintf_P(card_datas, PSTR("AUTHFAIL"));
@@ -467,19 +621,50 @@ void PN532_ScanForTag(void) {
}
switch (Pn532.function) {
case 0x01:
- if (!erase_success) {
- AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Erase fail - exiting erase mode"));
+ if (success) {
+ AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Erase success"));
+ } else {
+ AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Erase fail - exiting erase mode"));
}
break;
case 0x02:
- if (!set_success) {
- AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Write failed - exiting set mode"));
+ if (success) {
+ AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Data write successful"));
+ } else{
+ AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Write failed - exiting set mode"));
}
+ break;
+ case 0x03:
+ if (success) {
+ AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Set password successful"));
+ } else{
+ AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Set password failed - exiting set mode"));
+ }
+ break;
+ case 0x04:
+ if (success) {
+ AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Unset password successful"));
+ } else{
+ AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Unset password failed - exiting set mode"));
+ }
+ break;
default:
break;
}
Pn532.function = 0;
- ResponseTime_P(PSTR(",\"PN532\":{\"UID\":\"%s\",\"" D_JSON_DATA "\":\"%s\"}}"), Pn532.uids, card_datas);
+ card_datas[16] = 0;
+ ResponseTime_P(PSTR(",\"PN532\":{\"UID\":\"%s\",\"" D_JSON_DATA "\":\"%s\""), Pn532.uids, card_datas);
+ if (str_pwd == PWD_NONE) {
+ ResponseAppend_P(PSTR(",\"Auth\":\"None\""));
+ } else
+ if (str_pwd == PWD_OK) {
+ ResponseAppend_P(PSTR(",\"Auth\":\"Ok\""));
+ } else
+ if (str_pwd == PWD_NOK) {
+ ResponseAppend_P(PSTR(",\"Auth\":\"NOk\""));
+ }
+ ResponseAppend_P(PSTR("}}"));
+ PN532_inRelease();
#else
ResponseTime_P(PSTR(",\"PN532\":{\"UID\":\"%s\"}}"), Pn532.uids);
#endif // USE_PN532_DATA_FUNCTION
@@ -492,44 +677,73 @@ void PN532_ScanForTag(void) {
#ifdef USE_PN532_DATA_FUNCTION
bool PN532_Command(void) {
- bool serviced = true;
- uint8_t paramcount = 0;
- if (XdrvMailbox.data_len > 0) {
- paramcount=1;
- } else {
- serviced = false;
+ bool serviced = false;
+ char command[10];
+ char log[70];
+ if (ArgC() < 1) {
return serviced;
}
+
char argument[XdrvMailbox.data_len];
- for (uint32_t ca=0;ca 1) {
- if (XdrvMailbox.data[XdrvMailbox.data_len-1] == ',') {
- serviced = false;
- return serviced;
- }
+ if (!strcmp_P(argument,PSTR("WRITE"))) {
+ if (ArgC() > 1) {
ArgV(argument, 2);
- Pn532.newdata_len = strlen(argument);
- if (Pn532.newdata_len > 15) { Pn532.newdata_len = 15; }
- memcpy(&Pn532.newdata,&argument,Pn532.newdata_len);
- Pn532.newdata[Pn532.newdata_len] = 0x00; // Null terminate the string
+ memset(Pn532.newdata,0,sizeof(Pn532.newdata));
+ strncpy((char *)Pn532.newdata,argument,sizeof(Pn532.newdata));
+ if (strlen(argument)>16) argument[16]=0;
Pn532.function = 2;
- AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 NFC - Next scanned tag data block 1 will be set to '%s'"), Pn532.newdata);
- ResponseTime_P(PSTR(",\"PN532\":{\"COMMAND\":\"S\"}}"));
- return serviced;
+ snprintf_P(log, sizeof(log), PSTR("data block 1 (4-7 for NTAG) will be set to '%s'"), argument);
+ serviced = true;
}
}
- return false;
+ if (!strcmp_P(argument,PSTR("AUTH"))) {
+ if (ArgC() > 1) {
+ Pn532.pwd_auth=strtoul(ArgV(argument,2),nullptr,0);
+ }
+ if (ArgC() > 2) {
+ Pn532.pwd_pack=strtoul(ArgV(argument,3),nullptr,0);
+ }
+ Settings->pn532_password=Pn532.pwd_auth;
+ Settings->pn532_pack=Pn532.pwd_pack;
+
+ serviced = true;
+ }
+ if (!strcmp_P(argument,PSTR("SET_PWD"))) {
+ snprintf_P(log, sizeof(log), PSTR("will be protected"));
+ Pn532.pwd_auth_new=Pn532.pwd_auth;
+ Pn532.pwd_pack_new=Pn532.pwd_pack;
+ if (ArgC() > 1) {
+ Pn532.pwd_auth_new=strtoul(ArgV(argument,2),nullptr,0);
+ }
+ if (ArgC() > 2) {
+ Pn532.pwd_pack_new=strtoul(ArgV(argument,3),nullptr,0);
+ }
+ Pn532.function = 3;
+ serviced = true;
+ }
+ if (!strcmp_P(argument,PSTR("UNSET_PWD"))) {
+ snprintf_P(log, sizeof(log), PSTR("will be unprotected"));
+ Pn532.function = 4;
+ serviced = true;
+ }
+ if (!strcmp_P(argument,PSTR("CANCEL"))) {
+ AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Job canceled"));
+ Pn532.function = 0;
+ serviced = true;
+ } else {
+ AddLog(LOG_LEVEL_INFO, PSTR("NFC: PN532 - Next scanned tag %s"), log);
+ }
+ if (serviced) ResponseTime_P(PSTR(",\"PN532\":{\"COMMAND\":\"%s\"}}"),command);
+ return serviced;
}
#endif // USE_PN532_DATA_FUNCTION
@@ -544,7 +758,7 @@ void PN532_Show(void) {
* Interface
\*********************************************************************************************/
-bool Xsns40(uint8_t function) {
+bool Xsns40(uint32_t function) {
bool result = false;
if (FUNC_INIT == function) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_41_max44009.ino b/tasmota/tasmota_xsns_sensor/xsns_41_max44009.ino
index 0b1a4fb5a..a4a001f41 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_41_max44009.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_41_max44009.ino
@@ -1,7 +1,7 @@
/*
xsns_41_max44009.ino - MAX44009 ambient light sensor support for Tasmota
- Copyright (C) 2021 Theo Arends
+ Copyright (C) 2021 llagendijk
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
@@ -139,7 +139,7 @@ void Max4409Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns41(uint8_t function)
+bool Xsns41(uint32_t function)
{
if (!I2cEnabled(XI2C_28)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_42_scd30.ino b/tasmota/tasmota_xsns_sensor/xsns_42_scd30.ino
index 60057b2b1..f67416bd2 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_42_scd30.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_42_scd30.ino
@@ -320,7 +320,7 @@ void Scd30Show(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns42(byte function) {
+bool Xsns42(uint32_t function) {
if (!I2cEnabled(XI2C_29)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_43_hre.ino b/tasmota/tasmota_xsns_sensor/xsns_43_hre.ino
index 6ceddf43c..a288de135 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_43_hre.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_43_hre.ino
@@ -257,7 +257,7 @@ void hreShow(boolean json)
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
-bool Xsns43(byte function)
+bool Xsns43(uint32_t function)
{
// If we don't have pins assigned give up quickly.
if (!PinUsed(GPIO_HRE_CLOCK) || !PinUsed(GPIO_HRE_DATA)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_44_sps30.ino b/tasmota/tasmota_xsns_sensor/xsns_44_sps30.ino
index 1af0a7127..016f7ef9b 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_44_sps30.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_44_sps30.ino
@@ -284,7 +284,7 @@ bool SPS30_cmd(void)
* Interface
\*********************************************************************************************/
-bool Xsns44(byte function)
+bool Xsns44(uint32_t function)
{
if (!I2cEnabled(XI2C_30)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_45_vl53l0x.ino b/tasmota/tasmota_xsns_sensor/xsns_45_vl53l0x.ino
index 63b10b55c..55882066c 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_45_vl53l0x.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_45_vl53l0x.ino
@@ -190,53 +190,38 @@ void Vl53l0Every_250MSecond(void) {
void Vl53l0Every_Second(void) {
if (abs(Vl53l0x_data[0].distance - Vl53l0x_data[0].distance_prev) > 8) {
Vl53l0x_data[0].distance_prev = Vl53l0x_data[0].distance;
- DomoticzSensor(DZ_ILLUMINANCE, Vl53l0x_data[0].distance);
+ float distance = (float)Vl53l0x_data[0].distance / 10; // cm
+ DomoticzFloatSensor(DZ_ILLUMINANCE, distance);
}
}
#endif // USE_DOMOTICZ
void Vl53l0Show(boolean json) {
for (uint32_t i = 0; i < VL53LXX_MAX_SENSORS; i++) {
- if (PinUsed(GPIO_VL53LXX_XSHUT1, i) || (!VL53L0X_xshut)) {
- if (json) {
- if (Vl53l0x_data[i].distance == 9999) {
- if (VL53L0X_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 (VL53L0X_xshut) {
- ResponseAppend_P(PSTR(",\"VL53L0X_%d\":{\"" D_JSON_DISTANCE "\":%d}"), i+1, Vl53l0x_data[i].distance);
- } else {
- ResponseAppend_P(PSTR(",\"VL53L0X\":{\"" D_JSON_DISTANCE "\":%d}"), Vl53l0x_data[i].distance); // For backwards compatibility when not using XSHUT GPIOs
- }
- }
-#ifdef USE_WEBSERVER
- } else {
- if (Vl53l0x_data[i].distance == 9999) {
- if (VL53L0X_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 (VL53L0X_xshut) {
- WSContentSend_PD("{s}%s_%d " D_DISTANCE "{m}%d " D_UNIT_MILLIMETER "{e}", PSTR("VL53L0X"), i+1, Vl53l0x_data[i].distance);
- } else {
- WSContentSend_PD(HTTP_SNS_DISTANCE, PSTR("VL53L0X"), Vl53l0x_data[i].distance); // For backwards compatibility when not using XSHUT GPIOs
- }
- }
-#endif
- }
+ char types[12] = "VL53L0X";
+ if (VL53L0X_xshut) {
+ snprintf_P(types, sizeof(types), PSTR("VL53L0X%c%d"), IndexSeparator(), i +1);
+ }
+ if (PinUsed(GPIO_VL53LXX_XSHUT1, i) || (!VL53L0X_xshut)) {
+ float distance = (Vl53l0x_data[i].distance == 9999) ? NAN : (float)Vl53l0x_data[i].distance / 10; // cm
+ if (json) {
+ ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_DISTANCE "\":%1_f}"), types, &distance);
+#ifdef USE_WEBSERVER
+ } else {
+ WSContentSend_PD(HTTP_SNS_F_DISTANCE_CM, types, &distance);
+#endif
+ }
+ }
+ if (VL53L0X_device[i].timeoutOccurred()) {
+ AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_I2C "Timeout waiting for %s"), types);
}
- if (VL53L0X_device[i].timeoutOccurred()) { AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_I2C D_TIMEOUT_WAITING_FOR D_SENSOR " VL53L0X %d"), i+1); }
if (!VL53L0X_xshut) { break; }
}
#ifdef USE_DOMOTICZ
- if ((json) && (0 == TasmotaGlobal.tele_period)){
- DomoticzSensor(DZ_ILLUMINANCE, Vl53l0x_data[0].distance);
- }
+ if (json && (0 == TasmotaGlobal.tele_period)){
+ float distance = (float)Vl53l0x_data[0].distance / 10; // cm
+ DomoticzFloatSensor(DZ_ILLUMINANCE, distance);
+ }
#endif // USE_DOMOTICZ
}
@@ -244,7 +229,7 @@ void Vl53l0Show(boolean json) {
* Interface
\*********************************************************************************************/
-bool Xsns45(byte function) {
+bool Xsns45(uint32_t function) {
if (!I2cEnabled(XI2C_31)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_46_MLX90614.ino b/tasmota/tasmota_xsns_sensor/xsns_46_MLX90614.ino
index 5cb7f65cf..c93ec08b5 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_46_MLX90614.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_46_MLX90614.ino
@@ -137,7 +137,7 @@ uint8_t MLX90614_crc8(uint8_t *addr, uint8_t len)
* Interface
\*********************************************************************************************/
-bool Xsns46(byte function)
+bool Xsns46(uint32_t function)
{
if (!I2cEnabled(XI2C_32)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_47_max31865.ino b/tasmota/tasmota_xsns_sensor/xsns_47_max31865.ino
index efbd27179..6388f311c 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_47_max31865.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_47_max31865.ino
@@ -1,5 +1,5 @@
/*
- xsns_39_MAX31865.ino - MAX31865 thermocouple sensor support for Tasmota
+ xsns_47_max31865.ino - MAX31865 thermocouple sensor support for Tasmota
Copyright (C) 2021 Alberto Lopez Siemens
@@ -387,7 +387,7 @@ void MAX31865_Show(bool Json) {
* Interface
\*********************************************************************************************/
-bool Xsns47(uint8_t function)
+bool Xsns47(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_48_chirp.ino b/tasmota/tasmota_xsns_sensor/xsns_48_chirp.ino
index b5e3db4e2..1782a59df 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_48_chirp.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_48_chirp.ino
@@ -519,7 +519,7 @@ bool ChirpCmd(void) {
* Interface
\*********************************************************************************************/
-bool Xsns48(uint8_t function)
+bool Xsns48(uint32_t function)
{
if (!I2cEnabled(XI2C_33)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_50_paj7620.ino b/tasmota/tasmota_xsns_sensor/xsns_50_paj7620.ino
index 8a8db26c5..4374476bd 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_50_paj7620.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_50_paj7620.ino
@@ -422,7 +422,7 @@ bool PAJ7620CommandSensor(void)
* Interface
\*********************************************************************************************/
-bool Xsns50(uint8_t function)
+bool Xsns50(uint32_t function)
{
if (!I2cEnabled(XI2C_34)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_51_rdm6300.ino b/tasmota/tasmota_xsns_sensor/xsns_51_rdm6300.ino
index a277e7d65..5a929524d 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_51_rdm6300.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_51_rdm6300.ino
@@ -145,7 +145,7 @@ void RDM6300Show(void) {
* Interface
\*********************************************************************************************/
-bool Xsns51(byte function) {
+bool Xsns51(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_52_esp32_ibeacon_ble.ino b/tasmota/tasmota_xsns_sensor/xsns_52_esp32_ibeacon_ble.ino
index e68cd9013..9a96ea794 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_52_esp32_ibeacon_ble.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_52_esp32_ibeacon_ble.ino
@@ -562,7 +562,7 @@ void ibeacon_mqtt(const char *mac,const char *rssi,const char *uid,const char *m
* Interface
\*********************************************************************************************/
-bool Xsns52(byte function)
+bool Xsns52(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_52_ibeacon.ino b/tasmota/tasmota_xsns_sensor/xsns_52_ibeacon.ino
index 473d2e05d..411e82e21 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_52_ibeacon.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_52_ibeacon.ino
@@ -969,7 +969,7 @@ void ibeacon_mqtt(const char *mac,const char *rssi,const char *uid,const char *m
* Interface
\*********************************************************************************************/
-bool Xsns52(byte function)
+bool Xsns52(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino
index 62e06f3ac..2cf934c57 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_53_sml.ino
@@ -80,6 +80,14 @@
#define DJ_VAVG "Volt_avg"
#define DJ_COUNTER "Count"
+typedef union {
+ uint8_t data;
+ struct {
+ uint8_t trxenpol : 1; // string or number
+ uint8_t trxen : 1;
+ uint8_t trxenpin : 6;
+ };
+} TRX_EN_TYPE;
struct METER_DESC {
int8_t srcpin;
@@ -94,6 +102,7 @@ struct METER_DESC {
uint8_t max_index;
char *script_str;
uint8_t sopt;
+ TRX_EN_TYPE trx_en;
#ifdef USE_SML_SPECOPT
uint32_t so_obis1;
uint32_t so_obis2;
@@ -543,7 +552,11 @@ char meter_id[MAX_METERS][METER_ID_SIZE];
uint8_t sml_send_blocks;
uint8_t sml_100ms_cnt;
uint8_t sml_desc_cnt;
-uint8_t sml_json_enable = 1;
+
+#define SML_OPTIONS_JSON_ENABLE 1
+#define SML_OPTIONS_OBIS_LINE 2
+uint8_t sml_options = SML_OPTIONS_JSON_ENABLE;
+
#ifdef USE_SML_MEDIAN_FILTER
// median filter, should be odd size
@@ -1613,11 +1626,19 @@ void sml_empty_receiver(uint32_t meters) {
void sml_shift_in(uint32_t meters,uint32_t shard) {
uint32_t count;
-#ifndef SML_OBIS_LINE
- if (meter_desc_p[meters].type != 'e' && meter_desc_p[meters].type != 'k' && meter_desc_p[meters].type != 'm' && meter_desc_p[meters].type != 'M' && meter_desc_p[meters].type != 'p' && meter_desc_p[meters].type != 'R' && meter_desc_p[meters].type != 'v') {
-#else
- if (meter_desc_p[meters].type!= 'o' && meter_desc_p[meters].type != 'e' && meter_desc_p[meters].type != 'k' && meter_desc_p[meters].type != 'm' && meter_desc_p[meters].type != 'M' && meter_desc_p[meters].type != 'p' && meter_desc_p[meters].type != 'R' && meter_desc_p[meters].type != 'v') {
+
+#ifdef SML_OBIS_LINE
+ sml_options |= SML_OPTIONS_OBIS_LINE;
#endif
+
+ bool shift;
+ if (!(sml_options & SML_OPTIONS_OBIS_LINE)) {
+ shift = (meter_desc_p[meters].type != 'e' && meter_desc_p[meters].type != 'k' && meter_desc_p[meters].type != 'm' && meter_desc_p[meters].type != 'M' && meter_desc_p[meters].type != 'p' && meter_desc_p[meters].type != 'R' && meter_desc_p[meters].type != 'v');
+ } else {
+ shift = (meter_desc_p[meters].type != 'o' && meter_desc_p[meters].type != 'e' && meter_desc_p[meters].type != 'k' && meter_desc_p[meters].type != 'm' && meter_desc_p[meters].type != 'M' && meter_desc_p[meters].type != 'p' && meter_desc_p[meters].type != 'R' && meter_desc_p[meters].type != 'v');
+ }
+
+ if (shift) {
// shift in
for (count = 0; count < SML_BSIZ - 1; count++) {
smltbuf[meters][count] = smltbuf[meters][count + 1];
@@ -1626,20 +1647,20 @@ void sml_shift_in(uint32_t meters,uint32_t shard) {
uint8_t iob = (uint8_t)meter_ss[meters]->read();
if (meter_desc_p[meters].type == 'o') {
-#ifndef SML_OBIS_LINE
- smltbuf[meters][SML_BSIZ-1] = iob & 0x7f;
-#else
- iob &= 0x7f;
- smltbuf[meters][meter_spos[meters]] = iob;
- meter_spos[meters]++;
- if (meter_spos[meters] >= SML_BSIZ) {
- meter_spos[meters] = 0;
+ if (!(sml_options & SML_OPTIONS_OBIS_LINE)) {
+ smltbuf[meters][SML_BSIZ-1] = iob & 0x7f;
+ } else {
+ iob &= 0x7f;
+ smltbuf[meters][meter_spos[meters]] = iob;
+ meter_spos[meters]++;
+ if (meter_spos[meters] >= SML_BSIZ) {
+ meter_spos[meters] = 0;
+ }
+ if ((iob == 0x0a) || (iob == 0x0d)) {
+ SML_Decode(meters);
+ meter_spos[meters] = 0;
+ }
}
- if ((iob == 0x0a) || (iob == 0x0d)) {
- SML_Decode(meters);
- meter_spos[meters] = 0;
- }
-#endif
} else if (meter_desc_p[meters].type=='s') {
smltbuf[meters][SML_BSIZ-1]=iob;
} else if (meter_desc_p[meters].type=='r') {
@@ -1683,7 +1704,7 @@ void sml_shift_in(uint32_t meters,uint32_t shard) {
meter_spos[meters] = 0;
}
// modbus
- if (meter_spos[meters] >= 8) {
+ if (meter_spos[meters] >= 3) {
uint32_t mlen = smltbuf[meters][2] + 5;
if (mlen > SML_BSIZ) mlen = SML_BSIZ;
if (meter_spos[meters] >= mlen) {
@@ -1750,11 +1771,10 @@ void sml_shift_in(uint32_t meters,uint32_t shard) {
}
}
sb_counter++;
-#ifndef SML_OBIS_LINE
- if (meter_desc_p[meters].type != 'e' && meter_desc_p[meters].type != 'm' && meter_desc_p[meters].type != 'M' && meter_desc_p[meters].type != 'k' && meter_desc_p[meters].type != 'p' && meter_desc_p[meters].type != 'R' && meter_desc_p[meters].type != 'v') SML_Decode(meters);
-#else
- if (meter_desc_p[meters].type != 'o' && meter_desc_p[meters].type != 'e' && meter_desc_p[meters].type != 'm' && meter_desc_p[meters].type != 'M' && meter_desc_p[meters].type != 'k' && meter_desc_p[meters].type != 'p' && meter_desc_p[meters].type != 'R' && meter_desc_p[meters].type != 'v') SML_Decode(meters);
-#endif
+
+ if (shift) {
+ SML_Decode(meters);
+ }
}
@@ -2930,11 +2950,36 @@ dddef_exit:
}
if (*lp == ',') {
lp++;
+ // get TRX pin
script_meter_desc[index].trxpin = strtol(lp, &lp, 10);
if (Gpio_used(script_meter_desc[index].trxpin)) {
AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX in meter number %d"), script_meter_desc[index].trxpin, index + 1);
goto dddef_exit;
}
+ // optional transmit enable pin
+ if (*lp == '(') {
+ lp++;
+ if (*lp == 'i') {
+ lp++;
+ script_meter_desc[index].trx_en.trxenpol = 1;
+ } else {
+ script_meter_desc[index].trx_en.trxenpol = 0;
+ }
+ script_meter_desc[index].trx_en.trxenpin = strtol(lp, &lp, 10);
+ if (*lp != ')') {
+ goto dddef_exit;
+ }
+ lp++;
+ if (Gpio_used(script_meter_desc[index].trx_en.trxenpin)) {
+ AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX enable in meter number %d"), script_meter_desc[index].trx_en.trxenpin, index + 1);
+ goto dddef_exit;
+ }
+ script_meter_desc[index].trx_en.trxen = 1;
+ pinMode(script_meter_desc[index].trx_en.trxenpin, OUTPUT);
+ digitalWrite(script_meter_desc[index].trx_en.trxenpin, script_meter_desc[index].trx_en.trxenpol);
+ } else {
+ script_meter_desc[index].trx_en.trxen = 0;
+ }
if (*lp != ',') goto next_line;
lp++;
script_meter_desc[index].tsecs = strtol(lp, &lp, 10);
@@ -3600,8 +3645,18 @@ void SML_Send_Seq(uint32_t meter,char *seq) {
slen += 6;
}
+ if (script_meter_desc[meter].trx_en.trxen) {
+ digitalWrite(script_meter_desc[meter].trx_en.trxenpin, script_meter_desc[meter].trx_en.trxenpol ^ 1);
+ }
meter_ss[meter]->flush();
meter_ss[meter]->write(sbuff, slen);
+
+ if (script_meter_desc[meter].trx_en.trxen) {
+ // must wait for all data sent
+ meter_ss[meter]->flush();
+ digitalWrite(script_meter_desc[meter].trx_en.trxenpin, script_meter_desc[meter].trx_en.trxenpol);
+ }
+
if (dump2log) {
#ifdef SML_DUMP_OUT_ALL
Hexdump(sbuff, slen);
@@ -3785,7 +3840,7 @@ void SML_CounterSaveState(void) {
* Interface
\*********************************************************************************************/
-bool Xsns53(byte function) {
+bool Xsns53(uint32_t function) {
bool result = false;
switch (function) {
case FUNC_INIT:
@@ -3810,7 +3865,7 @@ bool Xsns53(byte function) {
break;
#endif // USE_SCRIPT
case FUNC_JSON_APPEND:
- if (sml_json_enable) {
+ if (sml_options & SML_OPTIONS_JSON_ENABLE) {
SML_Show(1);
}
break;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_54_ina226.ino b/tasmota/tasmota_xsns_sensor/xsns_54_ina226.ino
index 4961de5bd..9df7e9b15 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_54_ina226.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_54_ina226.ino
@@ -529,7 +529,7 @@ void Ina226Show(bool json)
* @post None.
*
*/
-bool Xsns54(byte callback_id)
+bool Xsns54(uint32_t callback_id)
{
if (!I2cEnabled(XI2C_35)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_55_hih_series.ino b/tasmota/tasmota_xsns_sensor/xsns_55_hih_series.ino
index 4f6cc0648..df866a5ed 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_55_hih_series.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_55_hih_series.ino
@@ -104,7 +104,7 @@ void Hih6Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns55(uint8_t function)
+bool Xsns55(uint32_t function)
{
if (!I2cEnabled(XI2C_36)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_56_hpma.ino b/tasmota/tasmota_xsns_sensor/xsns_56_hpma.ino
index c400fba1e..65b1fe6b9 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_56_hpma.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_56_hpma.ino
@@ -1,7 +1,6 @@
/*
xsns_56_hpma.ino - Honeywell HPMA115S0 particle concentration sensor support for Tasmota
- Copyright (C) 2021 Theo Arends
Copyright (C) 2021 David Hunt
This program is free software: you can redistribute it and/or modify
@@ -113,7 +112,7 @@ void HpmaShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns56(uint8_t function)
+bool Xsns56(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_57_tsl2591.ino b/tasmota/tasmota_xsns_sensor/xsns_57_tsl2591.ino
index 1ec7a6838..57d70f992 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_57_tsl2591.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_57_tsl2591.ino
@@ -94,7 +94,7 @@ void Tsl2591Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns57(uint8_t function)
+bool Xsns57(uint32_t function)
{
if (!I2cEnabled(XI2C_40)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_58_dht12.ino b/tasmota/tasmota_xsns_sensor/xsns_58_dht12.ino
index 559d9931b..dec917b9c 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_58_dht12.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_58_dht12.ino
@@ -98,7 +98,7 @@ void Dht12Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns58(uint8_t function)
+bool Xsns58(uint32_t function)
{
if (!I2cEnabled(XI2C_41)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_59_ds1624.ino b/tasmota/tasmota_xsns_sensor/xsns_59_ds1624.ino
index 6f62b8540..de9f9d1d2 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_59_ds1624.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_59_ds1624.ino
@@ -203,7 +203,7 @@ void DS1624Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns59(uint8_t function)
+bool Xsns59(uint32_t function)
{
if (!I2cEnabled(XI2C_42)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_60_GPS.ino b/tasmota/tasmota_xsns_sensor/xsns_60_GPS.ino
index edf3d9c81..0bf0b5e9e 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_60_GPS.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_60_GPS.ino
@@ -878,7 +878,7 @@ bool UBXCmd(void)
* Interface
\*********************************************************************************************/
-bool Xsns60(uint8_t function)
+bool Xsns60(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_61_MI_NRF24.ino b/tasmota/tasmota_xsns_sensor/xsns_61_MI_NRF24.ino
index f5f61e4e3..e6e4b60ec 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_61_MI_NRF24.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_61_MI_NRF24.ino
@@ -1966,7 +1966,7 @@ void MINRFShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns61(uint8_t function)
+bool Xsns61(uint32_t function)
{
bool result = false;
if (NRF24.chipType) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_62_MI_HM10.ino b/tasmota/tasmota_xsns_sensor/xsns_62_MI_HM10.ino
index 0e5a3bc03..b9334cf96 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_62_MI_HM10.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_62_MI_HM10.ino
@@ -2302,7 +2302,7 @@ void HM10Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns62(uint8_t function)
+bool Xsns62(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino
index 035e5a354..0b8c2eb26 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi.ino
@@ -615,7 +615,6 @@ void MI32PreInit(void) {
MI32.option.noSummary = 0;
MI32.option.minimalSummary = 0;
MI32.option.directBridgeMode = 0;
- MI32.option.showRSSI = 1;
MI32.option.ignoreBogusBattery = 1; // from advertisements
MI32loadCfg();
@@ -640,7 +639,7 @@ void MI32Init(void) {
}
}
- if(MI32.mode.didGetConfig){
+ if(MI32.mode.didGetConfig && !Settings->flag5.zigbee_hide_bridge_topic){ // borrow SO125 1 to turn off HomeKit
MI32.mode.didStartHAP = 0;
#ifdef USE_MI_HOMEKIT
MI32getSetupCodeFromMAC(MI32.hk_setup_code);
@@ -1910,6 +1909,14 @@ void MI32sendEnergyWidget(){
}
}
#endif //USE_MI_ESP32_ENERGY
+#ifdef USE_WEBCAM
+void MI32sendCamWidget(){
+ if (Wc.CamServer && Wc.up) {
+ WSContentSend_P(PSTR("
"),
+ (uint32_t)WiFi.localIP());
+ }
+}
+#endif //USE_WEBCAM
void MI32sendWidget(uint32_t slot){
auto _sensor = MIBLEsensors[slot];
@@ -2044,6 +2051,9 @@ void MI32InitGUI(void){
#ifdef USE_MI_ESP32_ENERGY
MI32sendEnergyWidget();
#endif //USE_MI_ESP32_ENERGY
+#ifdef USE_WEBCAM
+ MI32sendCamWidget();
+#endif //USE_WEBCAM
WSContentSend_P(PSTR(""));
WSContentSpaceButton(BUTTON_MAIN);
WSContentStop();
@@ -2085,6 +2095,7 @@ void MI32Show(bool json)
if(!MI32.mode.triggeredTele){
if(MI32.option.noSummary) return; // no message at TELEPERIOD
}
+ if(TasmotaGlobal.masterlog_level == LOG_LEVEL_DEBUG_MORE) return; // we want to announce sensors unlinked to the ESP, check for LOG_LEVEL_DEBUG_MORE is medium-safe
MI32suspendScanTask();
for (uint32_t i = 0; i < MIBLEsensors.size(); i++) {
if(MI32.mode.triggeredTele && MIBLEsensors[i].eventType.raw == 0) continue;
@@ -2217,10 +2228,9 @@ void MI32Show(bool json)
}
}
}
- if (MI32.option.showRSSI) {
- MI32ShowContinuation(&commaflg);
- ResponseAppend_P(PSTR("\"RSSI\":%d"), MIBLEsensors[i].RSSI);
- }
+ MI32ShowContinuation(&commaflg);
+ ResponseAppend_P(PSTR("\"RSSI\":%d"), MIBLEsensors[i].RSSI);
+
ResponseJsonEnd();
MIBLEsensors[i].eventType.raw = 0;
@@ -2308,6 +2318,7 @@ int ExtStopBLE(){
MI32Scan->stop();
MI32.mode.deleteScanTask = 1;
AddLog(LOG_LEVEL_INFO,PSTR("M32: stop BLE"));
+ while (MI32.mode.runningScan) yield();
}
#ifdef USE_MI_HOMEKIT
if(MI32.mode.didStartHAP) {
@@ -2322,7 +2333,7 @@ int ExtStopBLE(){
* Interface
\*********************************************************************************************/
-bool Xsns62(uint8_t function)
+bool Xsns62(uint32_t function)
{
if (!Settings->flag5.mi32_enable) { return false; } // SetOption115 - Enable ESP32 MI32 BLE
@@ -2360,7 +2371,7 @@ bool Xsns62(uint8_t function)
break;
#ifdef USE_MI_EXT_GUI
case FUNC_WEB_ADD_MAIN_BUTTON:
- if (MI32.mode.didGetConfig) WSContentSend_P(HTTP_BTN_MENU_MI32);
+ if (Settings->flag5.mi32_enable) WSContentSend_P(HTTP_BTN_MENU_MI32);
break;
case FUNC_WEB_ADD_HANDLER:
WebServer_on(PSTR("/m32"), MI32HandleWebGUI);
diff --git a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi_ble.ino b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi_ble.ino
index 0104dd58e..d1a0ebcb6 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi_ble.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi_ble.ino
@@ -3530,7 +3530,7 @@ void MI32Show(bool json)
\*********************************************************************************************/
#define WEB_HANDLE_MI32 "mikey"
-bool Xsns62(uint8_t function)
+bool Xsns62(uint32_t function)
{
// if (!Settings->flag5.mi32_enable) { return false; } // SetOption115 - Enable ESP32 MI32 BLE
// return false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_63_aht1x.ino b/tasmota/tasmota_xsns_sensor/xsns_63_aht1x.ino
index 315930c0b..7a9397f0e 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_63_aht1x.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_63_aht1x.ino
@@ -188,7 +188,7 @@ void AHT1XShow(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns63(uint8_t function)
+bool Xsns63(uint32_t function)
{
if (!I2cEnabled(XI2C_43)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_64_hrxl.ino b/tasmota/tasmota_xsns_sensor/xsns_64_hrxl.ino
index be78b49ec..727778fe1 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_64_hrxl.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_64_hrxl.ino
@@ -25,71 +25,55 @@
* Hardware Serial will be selected if GPIO1 = [HRXL Rx]
\*********************************************************************************************/
-#define XSNS_64 64
-
-#include
+#define XSNS_64 64
#define HRXL_READ_TIMEOUT 400 // us; enough for 6 bytes@9600bps
+#include
TasmotaSerial *HRXLSerial = nullptr;
uint32_t hrxl_distance_mm = 0; // distance, mm
-bool hrxl_found = false;
/*********************************************************************************************/
-void HRXLInit(void)
-{
- hrxl_found = false;
- if (PinUsed(GPIO_HRXL_RX))
- {
- HRXLSerial = new TasmotaSerial(Pin(GPIO_HRXL_RX), -1, 1);
- if (HRXLSerial->begin(9600))
- {
- if (HRXLSerial->hardwareSerial())
- ClaimSerial();
- hrxl_found = true;
- HRXLSerial->setTimeout(HRXL_READ_TIMEOUT);
- }
+void HRXLInit(void) {
+ if (PinUsed(GPIO_HRXL_RX)) {
+ HRXLSerial = new TasmotaSerial(Pin(GPIO_HRXL_RX), -1, 1);
+ if (HRXLSerial->begin(9600)) {
+ if (HRXLSerial->hardwareSerial()) {
+ ClaimSerial();
+ }
+ HRXLSerial->setTimeout(HRXL_READ_TIMEOUT);
}
+ }
}
-void HRXLEverySecond(void)
-{
- if (!hrxl_found)
- return;
-
- int num_read=0;
- int sum=0;
- while (HRXLSerial->available()>5)
- {
- if (HRXLSerial->read() != 'R')
- continue;
-
- int d = HRXLSerial->parseInt();
- if (d >= 30 && d<=5000)
- {
- sum += d;
- num_read++;
- }
+void HRXLEverySecond(void) {
+ int num_read = 0;
+ int sum = 0;
+ while (HRXLSerial->available() > 5) {
+ if (HRXLSerial->read() != 'R') {
+ continue;
}
- if (num_read>1)
- hrxl_distance_mm = int(sum / num_read);
-
+ int d = HRXLSerial->parseInt();
+ if (d >= 30 && d <= 5000) {
+ sum += d;
+ num_read++;
+ }
+ }
+ if (num_read > 1) {
+ hrxl_distance_mm = int(sum / num_read); // mm
+ }
}
-
-void HRXLShow(bool json)
-{
+void HRXLShow(bool json) {
char types[5] = "HRXL";
- if (json)
- {
- ResponseAppend_P(PSTR(",\"%s\":{\"" D_DISTANCE "\":%d}"), types, hrxl_distance_mm);
+ float distance = (float)hrxl_distance_mm / 10; // cm
+ if (json) {
+ ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_DISTANCE "\":%1_f}"), types, &distance);
#ifdef USE_WEBSERVER
- }
- else
- {
- WSContentSend_PD(HTTP_SNS_RANGE, types, hrxl_distance_mm);
+ } else {
+ WSContentSend_PD(HTTP_SNS_F_DISTANCE_CM, types, &distance);
#endif // USE_WEBSERVER
}
}
@@ -98,15 +82,12 @@ void HRXLShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns64(uint8_t function)
-{
- if (!PinUsed(GPIO_HRXL_RX)) { return false; }
-
- switch (function)
- {
- case FUNC_INIT:
- HRXLInit();
- break;
+bool Xsns64(uint32_t function) {
+ if (FUNC_INIT == function) {
+ HRXLInit();
+ }
+ else if (HRXLSerial) {
+ switch (function) {
case FUNC_EVERY_SECOND:
HRXLEverySecond();
break;
@@ -118,8 +99,9 @@ bool Xsns64(uint8_t function)
HRXLShow(0);
break;
#endif // USE_WEBSERVER
- }
- return false;
+ }
+ }
+ return false;
}
#endif // USE_HRXL
diff --git a/tasmota/tasmota_xsns_sensor/xsns_65_hdc1080.ino b/tasmota/tasmota_xsns_sensor/xsns_65_hdc1080.ino
index 96a7be484..3d0f5ef29 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_65_hdc1080.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_65_hdc1080.ino
@@ -277,7 +277,7 @@ void HdcShow(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns65(uint8_t function)
+bool Xsns65(uint32_t function)
{
if (!I2cEnabled(XI2C_45)) {
// AddLog(LOG_LEVEL_DEBUG, PSTR("Xsns65: I2C driver not enabled for this device."));
diff --git a/tasmota/tasmota_xsns_sensor/xsns_66_iAQ.ino b/tasmota/tasmota_xsns_sensor/xsns_66_iAQ.ino
index 0cbf17276..55b391a3a 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_66_iAQ.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_66_iAQ.ino
@@ -124,7 +124,7 @@ void IAQ_Show(uint8_t json)
* Interface
\*********************************************************************************************/
-bool Xsns66(byte function)
+bool Xsns66(uint32_t function)
{
if (!I2cEnabled(XI2C_46)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_67_as3935.ino b/tasmota/tasmota_xsns_sensor/xsns_67_as3935.ino
index 766ae77c3..2ae4d49a9 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_67_as3935.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_67_as3935.ino
@@ -826,7 +826,7 @@ void AH3935Show(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns67(uint8_t function) {
+bool Xsns67(uint32_t function) {
if (!I2cEnabled(XI2C_48)) { return false; }
bool result = false;
if (FUNC_INIT == function) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_68_windmeter.ino b/tasmota/tasmota_xsns_sensor/xsns_68_windmeter.ino
index 2768b5eaf..81bd3f2ff 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_68_windmeter.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_68_windmeter.ino
@@ -314,7 +314,7 @@ bool Xsns68Cmnd(void)
* Interface
\*********************************************************************************************/
-bool Xsns68(uint8_t function)
+bool Xsns68(uint32_t function)
{
bool result = false;
if (PinUsed(GPIO_WINDMETER_SPEED)) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_69_opentherm.ino b/tasmota/tasmota_xsns_sensor/xsns_69_opentherm.ino
index e8960de76..d18f51635 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_69_opentherm.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_69_opentherm.ino
@@ -581,7 +581,7 @@ void sns_opentherm_blor_cmd(void)
* Interface
\*********************************************************************************************/
-bool Xsns69(uint8_t function)
+bool Xsns69(uint32_t function)
{
bool result = false;
if (FUNC_INIT == function)
diff --git a/tasmota/tasmota_xsns_sensor/xsns_70_veml6075.ino b/tasmota/tasmota_xsns_sensor/xsns_70_veml6075.ino
index 69fd074f5..e26e72b77 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_70_veml6075.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_70_veml6075.ino
@@ -272,7 +272,7 @@ void VEML6075Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns70(uint8_t function)
+bool Xsns70(uint32_t function)
{
if (!I2cEnabled(XI2C_49)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_71_veml7700.ino b/tasmota/tasmota_xsns_sensor/xsns_71_veml7700.ino
index a4bf12905..e78488dcf 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_71_veml7700.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_71_veml7700.ino
@@ -171,7 +171,7 @@ bool VEML7700Cmd(void) {
* Interface
\*********************************************************************************************/
-bool Xsns71(uint8_t function)
+bool Xsns71(uint32_t function)
{
if (!I2cEnabled(XI2C_50)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_72_mcp9808.ino b/tasmota/tasmota_xsns_sensor/xsns_72_mcp9808.ino
index 95716f9e9..0f864bac4 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_72_mcp9808.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_72_mcp9808.ino
@@ -103,7 +103,7 @@ void MCP9808Show(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns72(uint8_t function)
+bool Xsns72(uint32_t function)
{
if (!I2cEnabled(XI2C_51)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_73_hp303b.ino b/tasmota/tasmota_xsns_sensor/xsns_73_hp303b.ino
index 1ee39f0ca..2df3d1f91 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_73_hp303b.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_73_hp303b.ino
@@ -1,7 +1,7 @@
/*
xsns_72_hp303b.ino - HP303B digital barometric air pressure sensor support for Tasmota
- Copyright (C) 2021 Theo Arends
+ Copyright (C) 2021 @rjaakke
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
@@ -142,7 +142,7 @@ void HP303B_Show(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns73(uint8_t function)
+bool Xsns73(uint32_t function)
{
if (!I2cEnabled(XI2C_52)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_74_lmt01.ino b/tasmota/tasmota_xsns_sensor/xsns_74_lmt01.ino
index eade01b2d..edfa00d3b 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_74_lmt01.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_74_lmt01.ino
@@ -108,7 +108,7 @@ void LMT01_Show(bool Json) {
* Interface
\*********************************************************************************************/
-bool Xsns74(uint8_t function)
+bool Xsns74(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_75_prometheus.ino b/tasmota/tasmota_xsns_sensor/xsns_75_prometheus.ino
index f08c730b0..56b507c61 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_75_prometheus.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_75_prometheus.ino
@@ -1,7 +1,7 @@
/*
xsns_75_prometheus.ino - Web based information for Tasmota
- Copyright (C) 2021 Theo Arends
+ Copyright (C) 2021 @marius, @mhansen, @hansmi
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
@@ -298,7 +298,7 @@ void HandleMetrics(void) {
JsonParserObject Object3 = value2.getObject();
for (auto key3 : Object3) {
const char *value = key3.getValue().getStr(nullptr);
- if (value != nullptr && (isdigit(value[0]) || (value[0] == '-') || (value[0] == '.'))) {
+ if (value != nullptr && isdigit(value[0])) {
String sensor = FormatMetricName(key2.getStr());
String type = FormatMetricName(key3.getStr());
@@ -311,7 +311,7 @@ void HandleMetrics(void) {
}
} else {
const char *value = value2.getStr(nullptr);
- if (value != nullptr && (isdigit(value[0]) || (value[0] == '-') || (value[0] == '.'))) {
+ if (value != nullptr && isdigit(value[0])) {
String sensor = FormatMetricName(key1.getStr());
String type = FormatMetricName(key2.getStr());
if (strcmp(type.c_str(), "totalstarttime") != 0) { // this metric causes Prometheus of fail
@@ -336,7 +336,7 @@ void HandleMetrics(void) {
const char *value = value1.getStr(nullptr);
String sensor = FormatMetricName(key1.getStr());
- if (value != nullptr && (isdigit(value[0]) || (value[0] == '-') || (value[0] == '.')) && strcmp(sensor.c_str(), "time") != 0) { //remove false 'time' metric
+ if (value != nullptr && isdigit(value[0] && strcmp(sensor.c_str(), "time") != 0)) { //remove false 'time' metric
WritePromMetricStr(PSTR("sensors"), kPromMetricGauge, value,
PSTR("sensor"), sensor.c_str(),
nullptr);
@@ -352,7 +352,7 @@ void HandleMetrics(void) {
* Interface
\*********************************************************************************************/
-bool Xsns75(uint8_t function) {
+bool Xsns75(uint32_t function) {
bool result = false;
switch (function) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_76_dyp.ino b/tasmota/tasmota_xsns_sensor/xsns_76_dyp.ino
index 0c4506502..9aa3ecaa2 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_76_dyp.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_76_dyp.ino
@@ -18,7 +18,6 @@
*/
#ifdef USE_DYP
-
/*********************************************************************************************\
* DYP ME007 ultrasonic distance sensor (300...4000mm), serial version
*
@@ -28,13 +27,11 @@
* 300...4000 for measured distance
* 4999 for distance above 4000mm
* 5999 for not connected sensor
- *
\*********************************************************************************************/
-#define XSNS_76 76
+#define XSNS_76 76
#include
-
TasmotaSerial *DYPSerial = nullptr;
#define DYP_CRCERROR -1
@@ -44,27 +41,22 @@ TasmotaSerial *DYPSerial = nullptr;
#define DYP_ABOVEMAX 4999
#define DYP_NOSENSOR 5999
-uint16_t DYPDistance = 0; // distance in milimeters
-bool DYPSensor = false; // sensor available
+uint16_t DYPDistance = 0; // distance in millimeters
/*********************************************************************************************/
void DYPInit(void) {
- DYPSensor = false;
if (PinUsed(GPIO_DYP_RX)) {
DYPSerial = new TasmotaSerial(Pin(GPIO_DYP_RX), -1, 1);
if (DYPSerial->begin(9600)) {
if (DYPSerial->hardwareSerial()) {
ClaimSerial();
}
- DYPSensor = true;
}
}
}
void DYPEverySecond(void) {
- if (!DYPSensor) { return; }
-
// check for serial data
if (DYPSerial->available() < 6) {
DYPDistance = DYP_NOSENSOR;
@@ -95,7 +87,7 @@ void DYPEverySecond(void) {
if (data > DYP_MAX) {
data = DYP_ABOVEMAX;
}
- DYPDistance = data;
+ DYPDistance = data; // mm
} else {
DYPDistance = DYP_CRCERROR;
}
@@ -104,12 +96,13 @@ void DYPEverySecond(void) {
}
void DYPShow(bool json) {
- char types[5] = "DYP";
+ char types[4] = "DYP";
+ float distance = (float)DYPDistance / 10; // cm
if (json) {
- ResponseAppend_P(PSTR(",\"%s\":{\"" D_DISTANCE "\":%d}"), types, DYPDistance);
+ ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_DISTANCE "\":%1_f}"), types, &distance);
#ifdef USE_WEBSERVER
} else {
- WSContentSend_PD(HTTP_SNS_RANGE, types, DYPDistance);
+ WSContentSend_PD(HTTP_SNS_F_DISTANCE_CM, types, &distance);
#endif // USE_WEBSERVER
}
}
@@ -118,24 +111,24 @@ void DYPShow(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns76(uint8_t function) {
- if (!PinUsed(GPIO_DYP_RX)) { return false; }
-
- switch (function) {
- case FUNC_INIT:
- DYPInit();
- break;
- case FUNC_EVERY_SECOND:
- DYPEverySecond();
- break;
- case FUNC_JSON_APPEND:
- DYPShow(1);
- break;
+bool Xsns76(uint32_t function) {
+ if (FUNC_INIT == function) {
+ DYPInit();
+ }
+ else if (DYPSerial) {
+ switch (function) {
+ case FUNC_EVERY_SECOND:
+ DYPEverySecond();
+ break;
+ case FUNC_JSON_APPEND:
+ DYPShow(1);
+ break;
#ifdef USE_WEBSERVER
- case FUNC_WEB_SENSOR:
- DYPShow(0);
- break;
+ case FUNC_WEB_SENSOR:
+ DYPShow(0);
+ break;
#endif // USE_WEBSERVER
+ }
}
return false;
}
diff --git a/tasmota/tasmota_xsns_sensor/xsns_77_vl53l1x.ino b/tasmota/tasmota_xsns_sensor/xsns_77_vl53l1x.ino
index 810eaa229..9138875b0 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_77_vl53l1x.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_77_vl53l1x.ino
@@ -1,5 +1,5 @@
/*
- xsns_77_vl53l1x_device[0].ino - VL53L1X sensor support for Tasmota
+ xsns_77_vl53l1x.ino - VL53L1X sensor support for Tasmota
Copyright (C) 2021 Theo Arends, Rui Marinho and Johann Obermeier
@@ -123,39 +123,30 @@ void Vl53l1Every_250MSecond(void) {
#ifdef USE_DOMOTICZ
void Vl53l1Every_Second(void) {
- char distance[FLOATSZ];
- dtostrfd((float)vl53l1x_data[0].distance / 10, 1, distance);
- DomoticzSensor(DZ_ILLUMINANCE, distance);
+ float distance = (float)vl53l1x_data[0].distance / 10; // cm
+ DomoticzFloatSensor(DZ_ILLUMINANCE, distance);
}
#endif // USE_DOMOTICZ
void Vl53l1Show(bool json) {
uint32_t i, xshut;
for (i = 0, xshut = 1 ; i < VL53LXX_MAX_SENSORS ; i++, xshut <<= 1) {
+ char types[12] = "VL53L1X";
+ if (VL53L1X_xshut) {
+ snprintf_P(types, sizeof(types), PSTR("VL53L1X%c%d"), IndexSeparator(), i +1);
+ }
+ float distance = (float)vl53l1x_data[i].distance / 10; // cm
if (xshut & VL53L1X_detected) {
if (json) {
- if (0 == VL53L1X_xshut) {
- ResponseAppend_P(PSTR(",\"VL53L1X\":{\"" D_JSON_DISTANCE "\":%d}"), vl53l1x_data[i].distance);
- }
- else {
- ResponseAppend_P(PSTR(",\"VL53L1X%c%d\":{\"" D_JSON_DISTANCE "\":%d}"), IndexSeparator(), i+1, vl53l1x_data[i].distance);
- }
+ ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_DISTANCE "\":%1_f}"), types, &distance);
#ifdef USE_DOMOTICZ
if (0 == TasmotaGlobal.tele_period) {
Vl53l1Every_Second();
}
#endif // USE_DOMOTICZ
#ifdef USE_WEBSERVER
- }
- else {
- if (0 == VL53L1X_xshut) {
- WSContentSend_PD(HTTP_SNS_DISTANCE, PSTR("VL53L1X"), vl53l1x_data[i].distance);
- }
- else {
- char tmpstr[12];
- sprintf(tmpstr, PSTR("VL53L1X%c%d"), IndexSeparator(), i+1);
- WSContentSend_PD(HTTP_SNS_DISTANCE, tmpstr, vl53l1x_data[i].distance);
- }
+ } else {
+ WSContentSend_PD(HTTP_SNS_F_DISTANCE_CM, types, &distance);
#endif
}
} // if detected
@@ -167,7 +158,7 @@ void Vl53l1Show(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns77(uint8_t function) {
+bool Xsns77(uint32_t function) {
if (!I2cEnabled(XI2C_54)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_78_xezo.ino b/tasmota/tasmota_xsns_sensor/xsns_78_xezo.ino
index 60b3cd8e4..488ba78c2 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_78_xezo.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_78_xezo.ino
@@ -306,7 +306,7 @@ private:
// The main driver is the same for all devices.
// What changes is the implementation of the class itself
-bool Xsns78(uint8_t function)
+bool Xsns78(uint32_t function)
{
if (!I2cEnabled(XI2C_55)) {
return false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_79_as608.ino b/tasmota/tasmota_xsns_sensor/xsns_79_as608.ino
index fba9e8afc..4b8115d1d 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_79_as608.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_79_as608.ino
@@ -294,7 +294,7 @@ void CmndFpCount(void) {
* Interface
\*********************************************************************************************/
-bool Xsns79(uint8_t function) {
+bool Xsns79(uint32_t function) {
bool result = false;
if (FUNC_INIT == function) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_80_mfrc522.ino b/tasmota/tasmota_xsns_sensor/xsns_80_mfrc522.ino
index 3ad92f4d9..7cb2daf93 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_80_mfrc522.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_80_mfrc522.ino
@@ -160,7 +160,7 @@ bool RC522Command(void) {
* Interface
\*********************************************************************************************/
-bool Xsns80(uint8_t function) {
+bool Xsns80(uint32_t function) {
bool result = false;
if (FUNC_INIT == function) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_81_seesaw_soil.ino b/tasmota/tasmota_xsns_sensor/xsns_81_seesaw_soil.ino
index 15a8bff66..429c43856 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_81_seesaw_soil.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_81_seesaw_soil.ino
@@ -328,7 +328,7 @@ void seeSoilName(int no, char *name, int len) // generates a sensor name
* Interface
\*********************************************************************************************/
-bool Xsns81(uint8_t function)
+bool Xsns81(uint32_t function)
{
if (!I2cEnabled(XI2C_56)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_82_wiegand.ino b/tasmota/tasmota_xsns_sensor/xsns_82_wiegand.ino
index 9908e7a55..e0247ead3 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_82_wiegand.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_82_wiegand.ino
@@ -617,7 +617,7 @@ const char kWiegandCommands[] PROGMEM = "Wie|" // No prefix
* Interface
\*********************************************************************************************/
-bool Xsns82(byte function) {
+bool Xsns82(uint32_t function) {
bool result = false;
if (FUNC_INIT == function) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_83_neopool.ino b/tasmota/tasmota_xsns_sensor/xsns_83_neopool.ino
index e2171bcfb..6e40008fd 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_83_neopool.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_83_neopool.ino
@@ -117,7 +117,7 @@ enum NeoPoolRegister {
MBF_CELL_RUNTIME_HIGH, // 0x0207* undocumented - cell runtime (32 bit) - high word
MBF_CELL_RUNTIME_PART_LOW, // 0x0208* undocumented - cell part runtime (32 bit) - low word
MBF_CELL_RUNTIME_PART_HIGH, // 0x0209* undocumented - cell part runtime (32 bit) - high word
- MBF_CELL_BOOST = 0x020C, // 0x020C* undocumented - 0x0000 = Boost Off, 0x05A0 = Boost with redox ctrl, 0x85A0 = Boost without redox ctrl
+ MBF_CELL_BOOST = 0x020C, // 0x020C* mask undocumented - 0x0000 = Boost Off, 0x05A0 = Boost with redox ctrl, 0x85A0 = Boost without redox ctrl
MBF_CELL_RUNTIME_POLA_LOW = 0x0214, // 0x0214* undocumented - cell runtime polarity A (32 bit) - low word
MBF_CELL_RUNTIME_POLA_HIGH, // 0x0215* undocumented - cell runtime polarity A (32 bit) - high word
MBF_CELL_RUNTIME_POLB_LOW, // 0x0216* undocumented - cell runtime polarity B (32 bit) - low word
@@ -126,7 +126,9 @@ enum NeoPoolRegister {
MBF_CELL_RUNTIME_POL_CHANGES_HIGH, // 0x0219* undocumented - cell runtime polarity changes (32 bit) - high word
MBF_HIDRO_MODULE_VERSION = 0x0280, // 0x0280 undocumented - Hydrolysis module version
MBF_HIDRO_MODULE_CONNECTIVITY = 0x0281, // 0x0281 undocumented - Hydrolysis module connection quality (in myriad: 0..10000)
- MBF_SET_MANUAL_CTRL = 0x0289, // 0x0289 undocumented - write a 1 before manual control MBF_RELAY_STATE, after done write 0 and do MBF_EXEC
+ MBF_SET_COUNTDOWN_KEY_AUX_OFF = 0x0287, // 0x0287 mask undocumented - switch AUX1-4 OFF - only for AUX which is assigned as AUX and set to MBV_PAR_CTIMER_COUNTDOWN_KEY_* mode - see MBV_PAR_CTIMER_COUNTDOWN_KEY_AUX*
+ MBF_SET_COUNTDOWN_KEY_AUX_ON, // 0x0288 mask undocumented - switch AUX1-4 ON - only for AUX which is assigned as AUX and set to MBV_PAR_CTIMER_COUNTDOWN_KEY_* mode - see MBV_PAR_CTIMER_COUNTDOWN_KEY_AUX*
+ MBF_SET_MANUAL_CTRL, // 0x0289 undocumented - write a 1 before manual control MBF_RELAY_STATE, after done write 0 and do MBF_EXEC
MBF_ESCAPE = 0x0297, // 0x0297 undocumented - A write operation to this register is the same as using the ESC button on main screen - clears error
MBF_SAVE_TO_EEPROM = 0x02F0, // 0x02F0 A write operation to this register starts a EEPROM storage operation immediately. During the EEPROM storage procedure, the system may be unresponsive to MODBUS requests. The operation will last always less than 1 second.
MBF_EXEC = 0x02F5, // 0x02F5 undocumented - immediately take over settings - a write operation to this register take over the previous written data
@@ -278,28 +280,12 @@ enum NeoPoolConstAndBitMask {
MBMSK_PH_STATUS_ALARM = 0x000F, // PH alarm. The possible alarm values are depending on the regulation model:
// Valid alarm values for pH regulation with acid and base:
MBV_PH_ACID_BASE_ALARM0 = 0, // no alarm
- MBV_PH_ACID_BASE_ALARM1 = 1, // pH too high; the pH value is 0.8 points higher than the setpoint value set in PH1
- MBV_PH_ACID_BASE_ALARM2 = 2, // pH too low: the pH value is 0.8 points lower than the set point value set in PH2
- MBV_PH_ACID_BASE_ALARM3 = 3, // pH pump (acid or base, it does not matter) has exceeded the working time set by the MBF_PAR_RELAY_PH_MAX_TIME parameter and has stopped.
- MBV_PH_ACID_BASE_ALARM4 = 4, // pH higher than the set point indicated in PH1
- MBV_PH_ACID_BASE_ALARM5 = 5, // pH lower than the set point indicated in PH2
- MBV_PH_ACID_BASE_ALARM6 = 6, // undocumented - acid tank level alarm
- // Valid alarm values for pH regulation with acid only:
- MBV_PH_ACID_ALARM0 = 0, // no alarm
- MBV_PH_ACID_ALARM1 = 1, // pH too high; the pH value is 0.8 points higher than the setpoint value set in PH1
- MBV_PH_ACID_ALARM2 = 2, // pH too low: the pH value is 0.8 points lower than the setpoint value set in PH1
- MBV_PH_ACID_ALARM3 = 3, // pH pump acid has exceeded the working time set by the MBF_PAR_RELAY_PH_MAX_TIME parameter and has stopped.
- MBV_PH_ACID_ALARM4 = 4, // pH higher than the setpoint indicated in PH1 by 0.1
- MBV_PH_ACID_ALARM5 = 5, // pH lower than the set point indicated in PH1 by 0.3
- MBV_PH_ACID_ALARM6 = 6, // undocumented - acid tank level alarm
- // Valid alarm values for pH regulation with base only:
- MBV_PH_BASE_ALARM0 = 0, // no alarm
- MBV_PH_BASE_ALARM1 = 1, // pH too high; the pH value is 0.8 points higher than the set point value set in PH2
- MBV_PH_BASE_ALARM2 = 2, // pH too low: the pH value is 0.8 points lower than the set point value set in PH2
- MBV_PH_BASE_ALARM3 = 3, // pH pump has exceeded the working time set by the MBF_PAR_RELAY_PH_MAX_TIME parameter and has stopped.
- MBV_PH_BASE_ALARM4 = 4, // pH higher than the set point indicated in PH2 by 0.1
- MBV_PH_BASE_ALARM5 = 5, // pH lower than the set point indicated in PH2 by 0.3
- MBV_PH_BASE_ALARM6 = 6, // undocumented - acid tank level alarm
+ MBV_PH_ACID_BASE_ALARM1 = 1, // pH too high; the pH value is 0.8 points higher than the setpoint (PH1 on acid systems, PH2 on base systems, PH1 on acid+base systems)
+ MBV_PH_ACID_BASE_ALARM2 = 2, // pH too low: the pH value is 0.8 points lower than the set point value set in (PH1 on acid systems, PH2 on base systems, PH2 on acid+base systems)
+ MBV_PH_ACID_BASE_ALARM3 = 3, // pH pump has exceeded the working time set by the MBF_PAR_RELAY_PH_MAX_TIME parameter and has stopped.
+ MBV_PH_ACID_BASE_ALARM4 = 4, // pH higher than the set point (PH1 + 0.1 on acid systems, PH2 + 0.1 on base systems, PH1 on acid+base systems)
+ MBV_PH_ACID_BASE_ALARM5 = 5, // pH lower than the set point (PH1 - 0.3 on acid systems, PH2 - 0.3 on base systems, PH2 on acid+base systems)
+ MBV_PH_ACID_BASE_ALARM6 = 6, // undocumented - tank level alarm
MBMSK_PH_STATUS_CTRL_BY_FL = 0x0400, // 10 Control status of the pH module by flow detection (if enabled by MBF_PAR_HIDRO_ION_CAUDAL)
MBMSK_PH_STATUS_ACID_PUMP_ACTIVE = 0x0800, // 11 Acid pH pump relay on (pump on)
@@ -374,6 +360,11 @@ enum NeoPoolConstAndBitMask {
MBMSK_NOTIF_USER_CHANGED = 0x0010, // 4 User page changed
MBMSK_NOTIF_MISC_CHANGED = 0x0020, // 5 Misc page changed
+ // MBF_CELL_BOOST
+ MBMSK_CELL_BOOST_REDOX_CTL = 0x8000, // undocumented - Disable redox ctrl
+ MBMSK_CELL_BOOST_STATE = 0x0500, // undocumented - Boost
+ MBMSK_CELL_BOOST_START = 0x00A0, // undocumented - Start boost
+
// MBF_PAR_MODEL
MBMSK_MODEL_ION = 0x0001, // 0 The equipment includes ionization control
MBMSK_MODEL_HIDRO = 0x0002, // 1 The equipment includes hydrolysis or electrolysis
@@ -512,18 +503,27 @@ enum NeoPoolConstAndBitMask {
MBV_PAR_CTIMER_ENABLED_LINKED = 2, // Timer enabled and linked to relay from timer 0
MBV_PAR_CTIMER_ALWAYS_ON = 3, // Relay assigned to this timer always on
MBV_PAR_CTIMER_ALWAYS_OFF = 4, // Relay assigned to this timer always off
- MBV_PAR_CTIMER_COUNTDOWN = 5, // Timer in countdown mode
+ MBV_PAR_CTIMER_COUNTDOWN_KEY_PLUS = 0x0105, // Timer in countdown mode using + key
+ MBV_PAR_CTIMER_COUNTDOWN_KEY_MINUS = 0x0205, // Timer in countdown mode using - key
+ MBV_PAR_CTIMER_COUNTDOWN_KEY_ARROWDOWN = 0x0405, // Timer in countdown mode using arrow-down key
+
+ // MBF_SET_COUNTDOWN_KEY_AUX_* mask:
+ MBV_PAR_CTIMER_COUNTDOWN_KEY_AUX1 = 0x0100, // Aux1 ON/OFF, when MBV_TIMER_OFFMB_TIMER_ENABLE is set to MBV_PAR_CTIMER_COUNTDOWN_KEY_*
+ MBV_PAR_CTIMER_COUNTDOWN_KEY_AUX2 = 0x0200, // Aux2 ON/OFF, when MBV_TIMER_OFFMB_TIMER_ENABLE is set to MBV_PAR_CTIMER_COUNTDOWN_KEY_*
+ MBV_PAR_CTIMER_COUNTDOWN_KEY_AUX3 = 0x0400, // Aux3 ON/OFF, when MBV_TIMER_OFFMB_TIMER_ENABLE is set to MBV_PAR_CTIMER_COUNTDOWN_KEY_*
+ MBV_PAR_CTIMER_COUNTDOWN_KEY_AUX4 = 0x0800, // Aux4 ON/OFF, when MBV_TIMER_OFFMB_TIMER_ENABLE is set to MBV_PAR_CTIMER_COUNTDOWN_KEY_*
+
// MBV_TIMER_OFFMB_TIMER_FUNCTION codes:
MBV_PAR_CTIMER_FCT_FILTRATION = 0x0001, // Filtration function of the system
MBV_PAR_CTIMER_FCT_LIGHTING = 0x0002, // Lighting function of the system
MBV_PAR_CTIMER_FCT_HEATING = 0x0004, // Heating function of the system
- MBV_PAR_CTIMER_FCT_AUXREL1 = 0x0100, // Auxiliary function assigned to relay 1
- MBV_PAR_CTIMER_FCT_AUXREL2 = 0x0200, // Auxiliary function assigned to relay 2
- MBV_PAR_CTIMER_FCT_AUXREL3 = 0x0400, // Auxiliary function assigned to relay 3
- MBV_PAR_CTIMER_FCT_AUXREL4 = 0x0800, // Auxiliary function assigned to relay 4
- MBV_PAR_CTIMER_FCT_AUXREL5 = 0x1000, // Auxiliary function assigned to relay 5
- MBV_PAR_CTIMER_FCT_AUXREL6 = 0x2000, // Auxiliary function assigned to relay 6
- MBV_PAR_CTIMER_FCT_AUXREL7 = 0x4000, // Auxiliary function assigned to relay 7
+ MBV_PAR_CTIMER_FCT_AUXREL1 = 0x0100, // Function assigned to relay 1 (Filtration)
+ MBV_PAR_CTIMER_FCT_AUXREL2 = 0x0200, // Function assigned to relay 2 (Light)
+ MBV_PAR_CTIMER_FCT_AUXREL3 = 0x0400, // Function assigned to relay 3 (Heating)
+ MBV_PAR_CTIMER_FCT_AUXREL4 = 0x0800, // Function assigned to relay 4 (AUX1)
+ MBV_PAR_CTIMER_FCT_AUXREL5 = 0x1000, // Function assigned to relay 5 (AUX2)
+ MBV_PAR_CTIMER_FCT_AUXREL6 = 0x2000, // Function assigned to relay 6 (AUX3)
+ MBV_PAR_CTIMER_FCT_AUXREL7 = 0x4000, // Function assigned to relay 7 (AUX4)
// MBF_PAR_UICFG_SOUND
MBMSK_PAR_SOUND_CLICK = 0x0001, // 0 Click sounds every time a key is pressed
@@ -654,6 +654,55 @@ NeoPoolResMBitfield neopool_resolution {
#define D_NEOPOOL_NAME "NeoPool"
+#define D_NEOPOOL_JSON_FILTRATION_NONE ""
+#define D_NEOPOOL_JSON_FILTRATION_MANUAL "Manual"
+#define D_NEOPOOL_JSON_FILTRATION_AUTO "Auto"
+#define D_NEOPOOL_JSON_FILTRATION_HEATING "Heating"
+#define D_NEOPOOL_JSON_FILTRATION_SMART "Smart"
+#define D_NEOPOOL_JSON_FILTRATION_INTELLIGENT "Intelligent"
+#define D_NEOPOOL_JSON_FILTRATION_BACKWASH "Backwash"
+#define D_NEOPOOL_JSON_MODULES "Modules"
+#define D_NEOPOOL_JSON_CHLORINE "Chlorine"
+#define D_NEOPOOL_JSON_CONDUCTIVITY "Conductivity"
+#define D_NEOPOOL_JSON_FILTRATION "Filtration"
+#define D_NEOPOOL_JSON_FILTRATION_MODE "Mode"
+#define D_NEOPOOL_JSON_FILTRATION_SPEED "Speed"
+#define D_NEOPOOL_JSON_HYDROLYSIS "Hydrolysis"
+#define D_NEOPOOL_JSON_CELL_RUNTIME "Runtime"
+#define D_NEOPOOL_JSON_CELL_RUNTIME_TOTAL "Total"
+#define D_NEOPOOL_JSON_CELL_RUNTIME_PART "Part"
+#define D_NEOPOOL_JSON_CELL_RUNTIME_POL1 "Pol1"
+#define D_NEOPOOL_JSON_CELL_RUNTIME_POL2 "Pol2"
+#define D_NEOPOOL_JSON_CELL_RUNTIME_CHANGES "Changes"
+#define D_NEOPOOL_JSON_IONIZATION "Ionization"
+#define D_NEOPOOL_JSON_LIGHT "Light"
+#define D_NEOPOOL_JSON_LIGHT_MODE "Mode"
+#define D_NEOPOOL_JSON_REDOX "Redox"
+#define D_NEOPOOL_JSON_RELAY "Relay"
+#define D_NEOPOOL_JSON_RELAY_PH_ACID "Acid"
+#define D_NEOPOOL_JSON_RELAY_PH_BASE "Base"
+#define D_NEOPOOL_JSON_RELAY_RX "Redox"
+#define D_NEOPOOL_JSON_RELAY_CL "Chlorine"
+#define D_NEOPOOL_JSON_RELAY_CD "Conductivity"
+#define D_NEOPOOL_JSON_RELAY_HEATING "Heating"
+#define D_NEOPOOL_JSON_RELAY_UV "UV"
+#define D_NEOPOOL_JSON_RELAY_FILTVALVE "Valve"
+#define D_NEOPOOL_JSON_AUX "Aux"
+#define D_NEOPOOL_JSON_STATE "State"
+#define D_NEOPOOL_JSON_TYPE "Type"
+#define D_NEOPOOL_JSON_UNIT "Unit"
+#define D_NEOPOOL_JSON_COVER "Cover"
+#define D_NEOPOOL_JSON_SHOCK "Boost"
+#define D_NEOPOOL_JSON_LOW "Low"
+#define D_NEOPOOL_JSON_SETPOINT "Setpoint"
+#define D_NEOPOOL_JSON_MIN "Min"
+#define D_NEOPOOL_JSON_MAX "Max"
+#define D_NEOPOOL_JSON_PHPUMP "Pump"
+#define D_NEOPOOL_JSON_FLOW1 "FL1"
+#define D_NEOPOOL_JSON_TANK "Tank"
+#define D_NEOPOOL_JSON_BIT "Bit"
+#define D_NEOPOOL_JSON_NODE_ID "NodeID"
+
const char kNeoPoolMachineNames[] PROGMEM =
D_NEOPOOL_MACH_NONE "|"
D_NEOPOOL_MACH_HIDROLIFE "|"
@@ -677,6 +726,14 @@ const char kNeoPoolFiltrationMode[] PROGMEM =
D_NEOPOOL_FILTRATION_INTELLIGENT "|"
D_NEOPOOL_FILTRATION_BACKWASH
;
+const char kNeoPoolFiltrationModeCmnd[] PROGMEM =
+ D_NEOPOOL_JSON_FILTRATION_MANUAL "|"
+ D_NEOPOOL_JSON_FILTRATION_AUTO "|"
+ D_NEOPOOL_JSON_FILTRATION_HEATING "|"
+ D_NEOPOOL_JSON_FILTRATION_SMART "|"
+ D_NEOPOOL_JSON_FILTRATION_INTELLIGENT "|"
+ D_NEOPOOL_JSON_FILTRATION_BACKWASH
+ ;
const uint8_t sNeoPoolFiltrationMode[] PROGMEM = {
MBV_PAR_FILT_MANUAL,
MBV_PAR_FILT_AUTO,
@@ -732,8 +789,11 @@ const char HTTP_SNS_NEOPOOL_STATUS_ACTIVE[] PROGMEM = "filter:invert(1)";
* Commands
*
* NPFiltration { {speed}}
- * get/set manual filtration (state = 0|1, speed = 1..3)
+ * get/set manual filtration (state = 0..2, speed = 1..3)
* get filtration state if is omitted, otherwise set new state
+ * 0 - switch filtration pump off
+ * 1 - switch filtration pump on
+ * 2 - toggle filtration pump
* for non-standard filtration types additional speed control is possible
*
* NPFiltrationMode {}
@@ -1417,48 +1477,6 @@ bool NeoPoolIsIonization(void)
/*********************************************************************************************/
-#define D_NEOPOOL_JSON_MODULES "Modules"
-#define D_NEOPOOL_JSON_CHLORINE "Chlorine"
-#define D_NEOPOOL_JSON_CONDUCTIVITY "Conductivity"
-#define D_NEOPOOL_JSON_FILTRATION "Filtration"
-#define D_NEOPOOL_JSON_FILTRATION_MODE "Mode"
-#define D_NEOPOOL_JSON_FILTRATION_SPEED "Speed"
-#define D_NEOPOOL_JSON_HYDROLYSIS "Hydrolysis"
-#define D_NEOPOOL_JSON_CELL_RUNTIME "Runtime"
-#define D_NEOPOOL_JSON_CELL_RUNTIME_TOTAL "Total"
-#define D_NEOPOOL_JSON_CELL_RUNTIME_PART "Part"
-#define D_NEOPOOL_JSON_CELL_RUNTIME_POL1 "Pol1"
-#define D_NEOPOOL_JSON_CELL_RUNTIME_POL2 "Pol2"
-#define D_NEOPOOL_JSON_CELL_RUNTIME_CHANGES "Changes"
-#define D_NEOPOOL_JSON_IONIZATION "Ionization"
-#define D_NEOPOOL_JSON_LIGHT "Light"
-#define D_NEOPOOL_JSON_LIGHT_MODE "Mode"
-#define D_NEOPOOL_JSON_REDOX "Redox"
-#define D_NEOPOOL_JSON_RELAY "Relay"
-#define D_NEOPOOL_JSON_RELAY_PH_ACID "Acid"
-#define D_NEOPOOL_JSON_RELAY_PH_BASE "Base"
-#define D_NEOPOOL_JSON_RELAY_RX "Redox"
-#define D_NEOPOOL_JSON_RELAY_CL "Chlorine"
-#define D_NEOPOOL_JSON_RELAY_CD "Conductivity"
-#define D_NEOPOOL_JSON_RELAY_HEATING "Heating"
-#define D_NEOPOOL_JSON_RELAY_UV "UV"
-#define D_NEOPOOL_JSON_RELAY_FILTVALVE "Valve"
-#define D_NEOPOOL_JSON_AUX "Aux"
-#define D_NEOPOOL_JSON_STATE "State"
-#define D_NEOPOOL_JSON_TYPE "Type"
-#define D_NEOPOOL_JSON_UNIT "Unit"
-#define D_NEOPOOL_JSON_COVER "Cover"
-#define D_NEOPOOL_JSON_SHOCK "Boost"
-#define D_NEOPOOL_JSON_LOW "Low"
-#define D_NEOPOOL_JSON_SETPOINT "Setpoint"
-#define D_NEOPOOL_JSON_MIN "Min"
-#define D_NEOPOOL_JSON_MAX "Max"
-#define D_NEOPOOL_JSON_PHPUMP "Pump"
-#define D_NEOPOOL_JSON_FLOW1 "FL1"
-#define D_NEOPOOL_JSON_TANK "Tank"
-#define D_NEOPOOL_JSON_BIT "Bit"
-#define D_NEOPOOL_JSON_NODE_ID "NodeID"
-
void NeoPoolAppendModules(void)
{
ResponseAppend_P(PSTR("\"" D_NEOPOOL_JSON_MODULES "\":"));
@@ -1640,7 +1658,7 @@ void NeoPoolShow(bool json)
// S2
ResponseAppend_P(PSTR(",\"" D_NEOPOOL_JSON_COVER "\":%d"), (NeoPoolGetData(MBF_HIDRO_STATUS) & MBMSK_HIDRO_STATUS_COVER) ? 1 : 0 );
// S3
- ResponseAppend_P(PSTR(",\"" D_NEOPOOL_JSON_SHOCK "\":%d"), (NeoPoolGetData(MBF_HIDRO_STATUS) & MBMSK_HIDRO_STATUS_SHOCK_ENABLED) ? ((NeoPoolGetData(MBF_CELL_BOOST) & 0x8000) ? 1 : 2) : 0 );
+ ResponseAppend_P(PSTR(",\"" D_NEOPOOL_JSON_SHOCK "\":%d"), (NeoPoolGetData(MBF_HIDRO_STATUS) & MBMSK_HIDRO_STATUS_SHOCK_ENABLED) ? ((NeoPoolGetData(MBF_CELL_BOOST) & MBMSK_CELL_BOOST_REDOX_CTL) ? 1 : 2) : 0 );
// S4
ResponseAppend_P(PSTR(",\"" D_NEOPOOL_JSON_LOW "\":%d"), (NeoPoolGetData(MBF_HIDRO_STATUS) & MBMSK_HIDRO_STATUS_LOW) ? 1 : 0 );
@@ -1764,7 +1782,7 @@ void NeoPoolShow(bool json)
WSContentSend_PD(PSTR(" "));
// S3
if (NeoPoolGetData(MBF_HIDRO_STATUS) & MBMSK_HIDRO_STATUS_SHOCK_ENABLED) {
- if ((NeoPoolGetData(MBF_CELL_BOOST) & 0x8000) == 0) {
+ if ((NeoPoolGetData(MBF_CELL_BOOST) & MBMSK_CELL_BOOST_REDOX_CTL) == 0) {
WSContentSend_PD(HTTP_SNS_NEOPOOL_STATUS, bg_color, HTTP_SNS_NEOPOOL_STATUS_ACTIVE, PSTR(D_NEOPOOL_SHOCK "+" D_NEOPOOL_REDOX));
} else {
WSContentSend_PD(HTTP_SNS_NEOPOOL_STATUS, bg_color, HTTP_SNS_NEOPOOL_STATUS_ACTIVE, PSTR(D_NEOPOOL_SHOCK));
@@ -1807,7 +1825,7 @@ void NeoPoolShow(bool json)
WSContentSend_PD(HTTP_SNS_NEOPOOL_STATUS, bg_color, HTTP_SNS_NEOPOOL_STATUS_ACTIVE, PSTR(D_NEOPOOL_STATUS_TANK));
} else if (NeoPoolGetData(MBF_PH_STATUS) & (MBMSK_PH_STATUS_ACID_PUMP_ACTIVE | MBMSK_PH_STATUS_BASE_PUMP_ACTIVE)) {
WSContentSend_PD(HTTP_SNS_NEOPOOL_STATUS, bg_color, HTTP_SNS_NEOPOOL_STATUS_ACTIVE, PSTR(D_NEOPOOL_STATUS_ON));
- } else if (MBV_PH_ACID_ALARM0 != (NeoPoolGetData(MBF_PH_STATUS) & MBMSK_PH_STATUS_ALARM)) {
+ } else if (MBV_PH_ACID_BASE_ALARM0 != (NeoPoolGetData(MBF_PH_STATUS) & MBMSK_PH_STATUS_ALARM)) {
WSContentSend_PD(HTTP_SNS_NEOPOOL_STATUS, bg_color, HTTP_SNS_NEOPOOL_STATUS_NORMAL, PSTR(D_NEOPOOL_STATUS_WAIT));
}
} else {
@@ -1852,9 +1870,9 @@ void NeoPoolShow(bool json)
// Ionization
if (NeoPoolIsIonization()) {
char spol[100];
- snprintf_P(spol, sizeof(spol), PSTR(" " D_NEOPOOL_POLARIZATION "%d"), (NeoPoolGetData(MBF_ION_STATUS) & 0x6000) >> 13);
+ snprintf_P(spol, sizeof(spol), PSTR(" " D_NEOPOOL_POLARIZATION "%d"), (NeoPoolGetData(MBF_ION_STATUS) & (MBMSK_ION_STATUS_POL1 | MBMSK_ION_STATUS_POL2)) >> 13);
snprintf_P(stemp, sizeof(stemp), PSTR("%s%s%s"),
- (NeoPoolGetData(MBF_ION_STATUS) & 0x6000) >> 13 ? spol : PSTR(""),
+ (NeoPoolGetData(MBF_ION_STATUS) & (MBMSK_ION_STATUS_POL1 | MBMSK_ION_STATUS_POL2)) ? spol : PSTR(""),
NeoPoolGetData(MBF_ION_STATUS) & MBMSK_ION_STATUS_ON_TARGET ? PSTR(" " D_NEOPOOL_SETPOINT_OK) : PSTR(""),
NeoPoolGetData(MBF_ION_STATUS) & MBMSK_ION_STATUS_PROGTIME_EXCEEDED ? PSTR(" " D_NEOPOOL_PR_OFF) : PSTR("")
);
@@ -1862,7 +1880,7 @@ void NeoPoolShow(bool json)
WSContentSend_PD(HTTP_SNS_NEOPOOL_IONIZATION, neopool_type,
neopool_resolution.ion, &fvalue,
stemp,
- NeoPoolGetData(MBF_ION_STATUS)&0x0002?PSTR(" " D_NEOPOOL_LOW):PSTR("")
+ NeoPoolGetData(MBF_ION_STATUS) & MBMSK_ION_STATUS_LOW ? PSTR(" " D_NEOPOOL_LOW) : PSTR("")
);
}
@@ -2129,12 +2147,19 @@ void CmndNeopoolFiltration(void)
return;
}
}
- if (value[0] >= 0 && value[0] <= 1) {
+ if (value[0] >= 0 && value[0] <= 2) {
// Set MBF_PAR_FILT_MODE
if (NEOPOOL_MODBUS_OK != NeoPoolWriteRegisterWord(MBF_PAR_FILT_MODE, MBV_PAR_FILT_MANUAL)) {
NeopoolResponseError();
return;
}
+ if (2 == value[0]) {
+ if (NEOPOOL_MODBUS_OK != NeoPoolReadRegister(MBF_PAR_FILTRATION_STATE, &data, 1)) {
+ NeopoolResponseError();
+ return;
+ }
+ value[0] = data ? 0 : 1;
+ }
// Set filtration mode to manual
if (NEOPOOL_MODBUS_OK != NeoPoolWriteRegisterWord(MBF_PAR_FILT_MANUAL_STATE, value[0])) {
NeopoolResponseError();
@@ -2169,7 +2194,7 @@ void CmndNeopoolFiltrationMode(void)
if (XdrvMailbox.data_len) {
char command[CMDSZ];
- int mode = GetCommandCode(command, sizeof(command), XdrvMailbox.data, kNeoPoolFiltrationMode);
+ int mode = GetCommandCode(command, sizeof(command), XdrvMailbox.data, kNeoPoolFiltrationModeCmnd);
if (mode >= 0) {
XdrvMailbox.payload = pgm_read_byte(sNeoPoolFiltrationMode + mode);
}
@@ -2189,7 +2214,7 @@ void CmndNeopoolFiltrationMode(void)
NeopoolResponseError();
return;
}
- ResponseCmndChar(GetTextIndexed(stemp, sizeof(stemp), data < MBV_PAR_FILT_INTELLIGENT ? data : nitems(kNeoPoolFiltrationMode)-1, kNeoPoolFiltrationMode));
+ ResponseCmndChar(GetTextIndexed(stemp, sizeof(stemp), data < MBV_PAR_FILT_INTELLIGENT ? data : nitems(kNeoPoolFiltrationModeCmnd)-1, kNeoPoolFiltrationMode));
}
@@ -2534,7 +2559,7 @@ void CmndNeopoolIONRes(void)
* Interface
\*********************************************************************************************/
-bool Xsns83(uint8_t function)
+bool Xsns83(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_84_tof10120.ino b/tasmota/tasmota_xsns_sensor/xsns_84_tof10120.ino
index 233a8cde8..8292f67b7 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_84_tof10120.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_84_tof10120.ino
@@ -84,15 +84,15 @@ void Tof10120Every_250MSecond(void) {
#ifdef USE_DOMOTICZ
void Tof10120Every_Second(void) {
- char distance[FLOATSZ];
- dtostrfd((float)tof10120_sensor.distance / 10, 1, distance);
- DomoticzSensor(DZ_ILLUMINANCE, distance);
+ float distance = (float)tof10120_sensor.distance / 10; // cm
+ DomoticzFloatSensor(DZ_ILLUMINANCE, distance);
}
#endif // USE_DOMOTICZ
void Tof10120Show(bool json) {
+ float distance = (float)tof10120_sensor.distance / 10; // cm
if (json) {
- ResponseAppend_P(PSTR(",\"TOF10120\":{\"" D_JSON_DISTANCE "\":%d}"), tof10120_sensor.distance);
+ ResponseAppend_P(PSTR(",\"TOF10120\":{\"" D_JSON_DISTANCE "\":%1_f}"), &distance);
#ifdef USE_DOMOTICZ
if (0 == TasmotaGlobal.tele_period) {
Tof10120Every_Second();
@@ -100,7 +100,7 @@ void Tof10120Show(bool json) {
#endif // USE_DOMOTICZ
#ifdef USE_WEBSERVER
} else {
- WSContentSend_PD(HTTP_SNS_DISTANCE, PSTR("TOF10120"), tof10120_sensor.distance);
+ WSContentSend_PD(HTTP_SNS_F_DISTANCE_CM, PSTR("TOF10120"), &distance);
#endif
}
}
@@ -109,7 +109,7 @@ void Tof10120Show(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns84(uint8_t function) {
+bool Xsns84(uint32_t function) {
if (!I2cEnabled(XI2C_57)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_85_mpu6886.ino b/tasmota/tasmota_xsns_sensor/xsns_85_mpu6886.ino
index 5b650a198..a3c64b360 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_85_mpu6886.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_85_mpu6886.ino
@@ -1,5 +1,5 @@
/*
- xsns_84_tof10120.ino -MPU6886/MPU9250 accelerometer support for Tasmota
+ xsns_85_mpu6886.ino - MPU6886/MPU9250 accelerometer support for Tasmota
Copyright (C) 2021 Stephan Hadinger and Theo Arends
@@ -103,7 +103,7 @@ void MPU_Every_Second(void) {
* Interface
\*********************************************************************************************/
-bool Xsns85(uint8_t function) {
+bool Xsns85(uint32_t function) {
if (!I2cEnabled(XI2C_58)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_86_tfminiplus.ino b/tasmota/tasmota_xsns_sensor/xsns_86_tfminiplus.ino
index 0f31032e0..ea32fcb22 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_86_tfminiplus.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_86_tfminiplus.ino
@@ -185,24 +185,22 @@ const char HTTP_SNS_SIGNALSTRENGTH[] PROGMEM = "{s}%s " D_SIGNALSTRENGTH "{m}%d{
const char HTTP_SNS_CHIPTEMPERATURE[] PROGMEM = "{s}%s " D_CHIPTEMPERATURE "{m}%d " D_UNIT_DEGREE "%c{e}";
#endif // USE_WEBSERVER
-void TfmpShow(bool json)
-{
+void TfmpShow(bool json) {
char sensor_name[12];
strcpy_P(sensor_name, "TFminiPlus");
- char distance_chr[FLOATSZ];
- dtostrfd(tfminiplus_sensor.distance, 3, distance_chr);
+ float distance = (float)tfminiplus_sensor.distance; // cm
if (json) {
- ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_DISTANCE "\":\"%s\",\"" D_JSON_SIGNALSTRENGTH "\":\"%d\",\"" D_JSON_CHIPTEMPERATURE "\":%d}"),
- sensor_name, distance_chr, tfminiplus_sensor.sigstrength, tfminiplus_sensor.chiptemp);
+ ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_DISTANCE "\":\"%1_f\",\"" D_JSON_SIGNALSTRENGTH "\":\"%d\",\"" D_JSON_CHIPTEMPERATURE "\":%d}"),
+ sensor_name, &distance, tfminiplus_sensor.sigstrength, tfminiplus_sensor.chiptemp);
#ifdef USE_DOMOTICZ
if (0 == TasmotaGlobal.tele_period) {
- DomoticzSensor(DZ_COUNT, distance_chr);
+ DomoticzFloatSensor(DZ_COUNT, distance);
}
#endif // USE_DOMOTICZ
#ifdef USE_WEBSERVER
} else {
- WSContentSend_P(HTTP_SNS_DISTANCE_CM, sensor_name, distance_chr);
+ WSContentSend_P(HTTP_SNS_F_DISTANCE_CM, sensor_name, &distance);
WSContentSend_P(HTTP_SNS_SIGNALSTRENGTH, sensor_name, tfminiplus_sensor.sigstrength);
WSContentSend_P(HTTP_SNS_CHIPTEMPERATURE, sensor_name, tfminiplus_sensor.chiptemp, TempUnit());
#endif // USE_WEBSERVER
@@ -213,7 +211,7 @@ void TfmpShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns86(byte callback_id)
+bool Xsns86(uint32_t callback_id)
{
bool result = false;
if (FUNC_INIT == callback_id)
diff --git a/tasmota/tasmota_xsns_sensor/xsns_87_can_sniffer.ino b/tasmota/tasmota_xsns_sensor/xsns_87_can_sniffer.ino
index 6d4f733be..db4c62c3e 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_87_can_sniffer.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_87_can_sniffer.ino
@@ -191,7 +191,7 @@ void MCP2515_Read() {
* Interface
\*********************************************************************************************/
-bool Xsns87(uint8_t function) {
+bool Xsns87(uint32_t function) {
bool result = false;
if (FUNC_INIT == function) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_87_mcp2515.ino b/tasmota/tasmota_xsns_sensor/xsns_87_mcp2515.ino
index ceb3cce07..3fe523ad4 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_87_mcp2515.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_87_mcp2515.ino
@@ -407,7 +407,7 @@ void MCP2515_Show(bool Json) {
* Interface
\*********************************************************************************************/
-bool Xsns87(uint8_t function)
+bool Xsns87(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_88_am2320.ino b/tasmota/tasmota_xsns_sensor/xsns_88_am2320.ino
index cb177987b..2d07d2061 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_88_am2320.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_88_am2320.ino
@@ -166,7 +166,7 @@ void Am2320Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns88(uint8_t function)
+bool Xsns88(uint32_t function)
{
if (!I2cEnabled(XI2C_60)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_89_t67xx.ino b/tasmota/tasmota_xsns_sensor/xsns_89_t67xx.ino
index 8b018f88c..34f4787a3 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_89_t67xx.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_89_t67xx.ino
@@ -297,7 +297,7 @@ T67XX t67xx;
* Interface
\*********************************************************************************************/
-bool Xsns89(uint8_t function)
+bool Xsns89(uint32_t function)
{
uint16_t ppm = 0;
if (!I2cEnabled(XI2C_61))
diff --git a/tasmota/tasmota_xsns_sensor/xsns_90_hrg15.ino b/tasmota/tasmota_xsns_sensor/xsns_90_hrg15.ino
index 0743d8902..0f062c6ed 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_90_hrg15.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_90_hrg15.ino
@@ -218,7 +218,7 @@ bool Rg15Command(void) {
* Interface
\*********************************************************************************************/
-bool Xsns90(uint8_t function) {
+bool Xsns90(uint32_t function) {
bool result = false;
if (FUNC_INIT == function) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_91_vindriktning.ino b/tasmota/tasmota_xsns_sensor/xsns_91_vindriktning.ino
index 8e88bb596..3248ea7f6 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_91_vindriktning.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_91_vindriktning.ino
@@ -165,7 +165,7 @@ void VindriktningShow(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns91(uint8_t function) {
+bool Xsns91(uint32_t function) {
bool result = false;
if (Vindriktning.type) {
diff --git a/tasmota/tasmota_xsns_sensor/xsns_92_scd40.ino b/tasmota/tasmota_xsns_sensor/xsns_92_scd40.ino
index 252914d31..9689585d3 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_92_scd40.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_92_scd40.ino
@@ -459,7 +459,7 @@ void Scd40Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns92(byte function)
+bool Xsns92(uint32_t function)
{
if (!I2cEnabled(XI2C_62)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_93_hm330x.ino b/tasmota/tasmota_xsns_sensor/xsns_93_hm330x.ino
index a64141507..e18ae6de8 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_93_hm330x.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_93_hm330x.ino
@@ -322,7 +322,7 @@ void HM330XShow(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns93(byte function)
+bool Xsns93(uint32_t function)
{
if (!I2cEnabled(XI2C_63)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_94_hdc2010.ino b/tasmota/tasmota_xsns_sensor/xsns_94_hdc2010.ino
index 8717b6d90..197bed50b 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_94_hdc2010.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_94_hdc2010.ino
@@ -175,7 +175,7 @@ void Hdc2010SetMeasurementConfig() {
* Interface
\*********************************************************************************************/
-bool Xsns94(uint8_t function)
+bool Xsns94(uint32_t function)
{
if (!I2cEnabled(XI2C_64)) {
return false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_95_cm110x.ino b/tasmota/tasmota_xsns_sensor/xsns_95_cm110x.ino
index 17c090c10..c71a91093 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_95_cm110x.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_95_cm110x.ino
@@ -1,7 +1,7 @@
/*
XSNS_95_cm1107.ino - CM1107(B) CO2 sensor support for Tasmota
- Copyright (C) 2021 Theo Arends
+ Copyright (C) 2022 Maksim
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 @@
* Filter usage
*
* Select filter usage on low stability readings
- *
+ *
* *******************************************************************************************
* Some CM11 models has manual or continuos modes - this logic not implemented.
\*********************************************************************************************/
@@ -42,8 +42,8 @@ enum CM11FilterOptions {CM1107_FILTER_OFF, CM1107_FILTER_FAST, CM1107_FILTER_MED
#endif
/*********************************************************************************************\
* Source: https://en.gassensor.com.cn/CO2Sensor/list.html (pdf for 1106/1107/1109 sensors)
- *
- *
+ *
+ *
* Automatic Baseline Correction (ABC logic function) is enabled by default but may be disabled with command
* Sensor95 0
* and enabled again with command
@@ -137,7 +137,7 @@ size_t CM11SendCmd(uint8_t command_id)
memcpy_P(&cm11_send[1], kCM11Commands[command_id], (len+1) * sizeof(uint8_t));
cm11_send[len+2] = CM11CalculateChecksum(cm11_send,0, len+2);
-
+
#ifdef DEBUG_TASMOTA_SENSOR
char cmdFull[len+30];// = {0};
memset( cmdFull, 0, (len+3)*sizeof(char) );
@@ -175,7 +175,7 @@ bool CM11CheckAndApplyFilter(uint16_t ppm, uint8_t drift)
}else {
difference >>=cm11_filter;
}
-
+
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "CM11 diff: %d"),difference);
cm11_last_ppm = static_cast(cm11_last_ppm + difference);
return true;
@@ -243,7 +243,7 @@ void CM11EverySecond(void)
if (cm11_response[2]==cmd_read[1]){ //0x01 - read command
uint16_t ppm = (cm11_response[3] << 8) | cm11_response[4];
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "CM11 PPM: %u"),ppm);
- if (ppm ==550) { // Preheating mode, fixed value.
+ if (ppm ==550) { // Preheating mode, fixed value.
//DOCs says that preheating is cm11_response[5] & (1 << 0)) ==1 (first bit ==1), but mine sensor (CM1107, sw V1.07.0.02 )
// set first bit 0 when preheating at switch to 1 then finished.
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "CM11 preheating"));
@@ -294,7 +294,7 @@ void CM11EverySecond(void)
sprintf_P(cm11_serial_number+i*2,"%04u", v); //print int value to result str
}
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_DEBUG "Serial number: %s"),cm11_serial_number);
- }
+ }
}
}
@@ -328,7 +328,7 @@ bool CM11CommandSensor(void)
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_95, CM11_ABC_ENABLED);
break;
case 2:
- CM11SendCmd(CM11_CMND_ZEROPOINT);
+ CM11SendCmd(CM11_CMND_ZEROPOINT);
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_95, D_JSON_ZERO_POINT_CALIBRATION);
break;
case 3:
@@ -432,7 +432,7 @@ void CM11Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns95(uint8_t function)
+bool Xsns95(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_96_flowratemeter.ino b/tasmota/tasmota_xsns_sensor/xsns_96_flowratemeter.ino
index 16a635e9e..e1c5fb6dd 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_96_flowratemeter.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_96_flowratemeter.ino
@@ -347,7 +347,7 @@ bool FlowRateMeterCommand(void) {
* Interface
\*********************************************************************************************/
-bool Xsns96(uint8_t function)
+bool Xsns96(uint32_t function)
{
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_97_hyt.ino b/tasmota/tasmota_xsns_sensor/xsns_97_hyt.ino
index c8b84320e..8bdcbe782 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_97_hyt.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_97_hyt.ino
@@ -98,7 +98,7 @@ void HYT_Show(bool json) {
* Interface
\*********************************************************************************************/
-bool Xsns97(uint8_t function) {
+bool Xsns97(uint32_t function) {
if (!I2cEnabled(XI2C_68)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xsns_sensor/xsns_98_sgp40.ino b/tasmota/tasmota_xsns_sensor/xsns_98_sgp40.ino
index 093136626..e40df3f07 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_98_sgp40.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_98_sgp40.ino
@@ -1,7 +1,7 @@
/*
xsns_98_sgp40.ino - SGP40 gas and air quality sensor support for Tasmota
- Copyright (C) 2021 Theo Arends
+ Copyright (C) 2022 Jean-Pierre Deschamps
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
@@ -139,7 +139,7 @@ void Sgp40Show(bool json)
* Interface
\*********************************************************************************************/
-bool Xsns98(uint8_t function)
+bool Xsns98(uint32_t function)
{
if (!I2cEnabled(XI2C_69)) { return false; }
diff --git a/tasmota/tasmota_xsns_sensor/xsns_99_luxv30b.ino b/tasmota/tasmota_xsns_sensor/xsns_99_luxv30b.ino
index 3c3cd89e9..d299e485d 100644
--- a/tasmota/tasmota_xsns_sensor/xsns_99_luxv30b.ino
+++ b/tasmota/tasmota_xsns_sensor/xsns_99_luxv30b.ino
@@ -121,7 +121,7 @@ class LuxV30b {
void Detect();
bool Found();
void Read();
- void Show(uint8_t function);
+ void Show(uint32_t function);
private:
float Lux();
bool _found;
@@ -164,7 +164,7 @@ float LuxV30b::Lux() {
return ((float)_lux * 1.4) / 1000;
}
-void LuxV30b::Show(uint8_t function) {
+void LuxV30b::Show(uint32_t function) {
// if (0 < Lux()) {
if (_lux) {
char lux[FLOATSZ];
@@ -190,7 +190,7 @@ LuxV30b Luxv30b;
* Interface
\*********************************************************************************************/
-bool Xsns99(uint8_t function) {
+bool Xsns99(uint32_t function) {
if (!I2cEnabled(XI2C_70)) { return false; }
bool result = false;
diff --git a/tasmota/tasmota_xx2c_global/xdrv_interface.ino b/tasmota/tasmota_xx2c_global/xdrv_interface.ino
index dcf763935..247e7adb2 100644
--- a/tasmota/tasmota_xx2c_global/xdrv_interface.ino
+++ b/tasmota/tasmota_xx2c_global/xdrv_interface.ino
@@ -18,9 +18,9 @@
*/
#ifdef XFUNC_PTR_IN_ROM
-bool (* const xdrv_func_ptr[])(uint8_t) PROGMEM = { // Driver Function Pointers
+bool (* const xdrv_func_ptr[])(uint32_t) PROGMEM = { // Driver Function Pointers
#else
-bool (* const xdrv_func_ptr[])(uint8_t) = { // Driver Function Pointers
+bool (* const xdrv_func_ptr[])(uint32_t) = { // Driver Function Pointers
#endif
#ifdef XDRV_01
@@ -1063,8 +1063,7 @@ const uint8_t kXdrvList[] = {
/*********************************************************************************************/
-void XsnsDriverState(void)
-{
+void XsnsDriverState(void) {
ResponseAppend_P(PSTR(",\"Drivers\":\"")); // Use string for future enable/disable signal
for (uint32_t i = 0; i < sizeof(kXdrvList); i++) {
#ifdef XFUNC_PTR_IN_ROM
@@ -1099,8 +1098,7 @@ bool XdrvRulesProcess(bool teleperiod) {
}
#ifdef USE_DEBUG_DRIVER
-void ShowFreeMem(const char *where)
-{
+void ShowFreeMem(const char *where) {
char stemp[30];
snprintf_P(stemp, sizeof(stemp), where);
XdrvMailbox.data = stemp;
@@ -1112,8 +1110,7 @@ void ShowFreeMem(const char *where)
* Function call to single xdrv
\*********************************************************************************************/
-bool XdrvCallDriver(uint32_t driver, uint8_t Function)
-{
+bool XdrvCallDriver(uint32_t driver, uint32_t function) {
for (uint32_t x = 0; x < xdrv_present; x++) {
#ifdef XFUNC_PTR_IN_ROM
uint32_t listed = pgm_read_byte(kXdrvList + x);
@@ -1121,7 +1118,7 @@ bool XdrvCallDriver(uint32_t driver, uint8_t Function)
uint32_t listed = kXdrvList[x];
#endif
if (driver == listed) {
- return xdrv_func_ptr[x](Function);
+ return xdrv_func_ptr[x](function);
}
}
return false;
@@ -1131,11 +1128,10 @@ bool XdrvCallDriver(uint32_t driver, uint8_t Function)
* Function call to all xdrv
\*********************************************************************************************/
-bool XdrvCall(uint8_t Function)
-{
+bool XdrvCall(uint32_t function) {
bool result = false;
-// DEBUG_TRACE_LOG(PSTR("DRV: %d"), Function);
+// DEBUG_TRACE_LOG(PSTR("DRV: %d"), function);
uint32_t profile_driver_start = millis();
@@ -1143,7 +1139,7 @@ bool XdrvCall(uint8_t Function)
uint32_t profile_function_start = millis();
- result = xdrv_func_ptr[x](Function);
+ result = xdrv_func_ptr[x](function);
#ifdef USE_PROFILE_FUNCTION
#ifdef XFUNC_PTR_IN_ROM
@@ -1151,25 +1147,25 @@ bool XdrvCall(uint8_t Function)
#else
uint32_t index = kXdrvList[x];
#endif
- PROFILE_FUNCTION("drv", index, Function, profile_function_start);
+ PROFILE_FUNCTION("drv", index, function, profile_function_start);
#endif // USE_PROFILE_FUNCTION
- if (result && ((FUNC_COMMAND == Function) ||
- (FUNC_COMMAND_DRIVER == Function) ||
- (FUNC_MQTT_DATA == Function) ||
- (FUNC_RULES_PROCESS == Function) ||
- (FUNC_BUTTON_PRESSED == Function) ||
- (FUNC_SERIAL == Function) ||
- (FUNC_MODULE_INIT == Function) ||
- (FUNC_SET_CHANNELS == Function) ||
- (FUNC_PIN_STATE == Function) ||
- (FUNC_SET_DEVICE_POWER == Function)
+ if (result && ((FUNC_COMMAND == function) ||
+ (FUNC_COMMAND_DRIVER == function) ||
+ (FUNC_MQTT_DATA == function) ||
+ (FUNC_RULES_PROCESS == function) ||
+ (FUNC_BUTTON_PRESSED == function) ||
+ (FUNC_SERIAL == function) ||
+ (FUNC_MODULE_INIT == function) ||
+ (FUNC_SET_CHANNELS == function) ||
+ (FUNC_PIN_STATE == function) ||
+ (FUNC_SET_DEVICE_POWER == function)
)) {
break;
}
}
- PROFILE_DRIVER("drv", Function, profile_driver_start);
+ PROFILE_DRIVER("drv", function, profile_driver_start);
return result;
}
diff --git a/tasmota/tasmota_xx2c_global/xdsp_interface.ino b/tasmota/tasmota_xx2c_global/xdsp_interface.ino
index d404e169e..06808ca18 100644
--- a/tasmota/tasmota_xx2c_global/xdsp_interface.ino
+++ b/tasmota/tasmota_xx2c_global/xdsp_interface.ino
@@ -20,9 +20,9 @@
#ifdef USE_DISPLAY
#ifdef XFUNC_PTR_IN_ROM
-bool (* const xdsp_func_ptr[])(uint8_t) PROGMEM = { // Display Function Pointers
+bool (* const xdsp_func_ptr[])(uint32_t) PROGMEM = { // Display Function Pointers
#else
-bool (* const xdsp_func_ptr[])(uint8_t) = { // Display Function Pointers
+bool (* const xdsp_func_ptr[])(uint32_t) = { // Display Function Pointers
#endif
#ifdef XDSP_01
@@ -177,21 +177,19 @@ const uint8_t xdsp_present = sizeof(xdsp_func_ptr) / sizeof(xdsp_func_ptr[0]);
* FUNC_DISPLAY_DRAW_STRING
\*********************************************************************************************/
-uint8_t XdspPresent(void)
-{
+uint8_t XdspPresent(void) {
return xdsp_present;
}
-bool XdspCall(uint8_t Function)
-{
+bool XdspCall(uint32_t function) {
bool result = false;
- DEBUG_TRACE_LOG(PSTR("DSP: %d"), Function);
+ DEBUG_TRACE_LOG(PSTR("DSP: %d"), function);
for (uint32_t x = 0; x < xdsp_present; x++) {
- result = xdsp_func_ptr[x](Function);
+ result = xdsp_func_ptr[x](function);
- if (result && (FUNC_DISPLAY_MODEL == Function)) {
+ if (result && (FUNC_DISPLAY_MODEL == function)) {
break;
}
}
diff --git a/tasmota/tasmota_xx2c_global/xlgt_interface.ino b/tasmota/tasmota_xx2c_global/xlgt_interface.ino
index 4ef1928f8..f96cda4df 100644
--- a/tasmota/tasmota_xx2c_global/xlgt_interface.ino
+++ b/tasmota/tasmota_xx2c_global/xlgt_interface.ino
@@ -20,9 +20,9 @@
#ifdef USE_LIGHT
#ifdef XFUNC_PTR_IN_ROM
-bool (* const xlgt_func_ptr[])(uint8_t) PROGMEM = { // Light driver Function Pointers
+bool (* const xlgt_func_ptr[])(uint32_t) PROGMEM = { // Light driver Function Pointers
#else
-bool (* const xlgt_func_ptr[])(uint8_t) = { // Light driver Function Pointers
+bool (* const xlgt_func_ptr[])(uint32_t) = { // Light driver Function Pointers
#endif
#ifdef XLGT_01
@@ -94,8 +94,7 @@ const uint8_t xlgt_present = sizeof(xlgt_func_ptr) / sizeof(xlgt_func_ptr[0]);
uint8_t xlgt_active = 0;
-bool XlgtCall(uint8_t function)
-{
+bool XlgtCall(uint32_t function) {
DEBUG_TRACE_LOG(PSTR("LGT: %d"), function);
if (FUNC_MODULE_INIT == function) {
diff --git a/tasmota/tasmota_xx2c_global/xnrg_interface.ino b/tasmota/tasmota_xx2c_global/xnrg_interface.ino
index de019675c..60c45a5d1 100644
--- a/tasmota/tasmota_xx2c_global/xnrg_interface.ino
+++ b/tasmota/tasmota_xx2c_global/xnrg_interface.ino
@@ -20,9 +20,9 @@
#ifdef USE_ENERGY_SENSOR
#ifdef XFUNC_PTR_IN_ROM
-bool (* const xnrg_func_ptr[])(uint8_t) PROGMEM = { // Energy driver Function Pointers
+bool (* const xnrg_func_ptr[])(uint32_t) PROGMEM = { // Energy driver Function Pointers
#else
-bool (* const xnrg_func_ptr[])(uint8_t) = { // Energy driver Function Pointers
+bool (* const xnrg_func_ptr[])(uint32_t) = { // Energy driver Function Pointers
#endif
#ifdef XNRG_01
@@ -158,8 +158,7 @@ const uint8_t xnrg_present = sizeof(xnrg_func_ptr) / sizeof(xnrg_func_ptr[0]);
uint8_t xnrg_active = 0;
-bool XnrgCall(uint8_t function)
-{
+bool XnrgCall(uint32_t function) {
DEBUG_TRACE_LOG(PSTR("NRG: %d"), function);
if (FUNC_PRE_INIT == function) {
diff --git a/tasmota/tasmota_xx2c_global/xsns_interface.ino b/tasmota/tasmota_xx2c_global/xsns_interface.ino
index c4477447a..71f3dceb4 100644
--- a/tasmota/tasmota_xx2c_global/xsns_interface.ino
+++ b/tasmota/tasmota_xx2c_global/xsns_interface.ino
@@ -18,9 +18,9 @@
*/
#ifdef XFUNC_PTR_IN_ROM
-bool (* const xsns_func_ptr[])(uint8_t) PROGMEM = { // Sensor Function Pointers for simple implementation of sensors
+bool (* const xsns_func_ptr[])(uint32_t) PROGMEM = { // Sensor Function Pointers for simple implementation of sensors
#else
-bool (* const xsns_func_ptr[])(uint8_t) = { // Sensor Function Pointers for simple implementation of sensors
+bool (* const xsns_func_ptr[])(uint32_t) = { // Sensor Function Pointers for simple implementation of sensors
#endif
#ifdef XSNS_01
@@ -1094,7 +1094,7 @@ void XsnsSensorState(uint32_t sensor_list) {
* Function call to all xsns
\*********************************************************************************************/
-bool XsnsNextCall(uint8_t Function, uint8_t &xsns_index) {
+bool XsnsNextCall(uint32_t function, uint8_t &xsns_index) {
if (0 == xsns_present) {
xsns_index = 0;
return false;
@@ -1103,28 +1103,28 @@ bool XsnsNextCall(uint8_t Function, uint8_t &xsns_index) {
xsns_index++;
if (xsns_index == xsns_present) { xsns_index = 0; }
uint32_t max_disabled = xsns_present;
- while ((!XsnsEnabled(0, xsns_index) || ((FUNC_WEB_SENSOR == Function) && !XsnsEnabled(1, xsns_index))) && max_disabled--) { // Perform at least one sensor
+ while ((!XsnsEnabled(0, xsns_index) || ((FUNC_WEB_SENSOR == function) && !XsnsEnabled(1, xsns_index))) && max_disabled--) { // Perform at least one sensor
xsns_index++;
if (xsns_index == xsns_present) { xsns_index = 0; }
}
- return xsns_func_ptr[xsns_index](Function);
+ return xsns_func_ptr[xsns_index](function);
}
-bool XsnsCall(uint8_t Function) {
+bool XsnsCall(uint32_t function) {
bool result = false;
-// DEBUG_TRACE_LOG(PSTR("SNS: %d"), Function);
+// DEBUG_TRACE_LOG(PSTR("SNS: %d"), function);
uint32_t profile_driver_start = millis();
for (uint32_t x = 0; x < xsns_present; x++) {
if (XsnsEnabled(0, x)) { // Skip disabled sensor
- if ((FUNC_WEB_SENSOR == Function) && !XsnsEnabled(1, x)) { continue; } // Skip web info for disabled sensors
+ if ((FUNC_WEB_SENSOR == function) && !XsnsEnabled(1, x)) { continue; } // Skip web info for disabled sensors
uint32_t profile_function_start = millis();
- result = xsns_func_ptr[x](Function);
+ result = xsns_func_ptr[x](function);
#ifdef USE_PROFILE_FUNCTION
#ifdef XFUNC_PTR_IN_ROM
@@ -1132,19 +1132,19 @@ bool XsnsCall(uint8_t Function) {
#else
uint32_t index = kXsnsList[x];
#endif
- PROFILE_FUNCTION("sns", index, Function, profile_function_start);
+ PROFILE_FUNCTION("sns", index, function, profile_function_start);
#endif // USE_PROFILE_FUNCTION
- if (result && ((FUNC_COMMAND == Function) ||
- (FUNC_PIN_STATE == Function) ||
- (FUNC_COMMAND_SENSOR == Function)
+ if (result && ((FUNC_COMMAND == function) ||
+ (FUNC_PIN_STATE == function) ||
+ (FUNC_COMMAND_SENSOR == function)
)) {
break;
}
}
}
- PROFILE_DRIVER("sns", Function, profile_driver_start);
+ PROFILE_DRIVER("sns", function, profile_driver_start);
return result;
}
diff --git a/tasmota/tasmota_xx2c_global/xx2c_interface.ino b/tasmota/tasmota_xx2c_global/xx2c_interface.ino
index 5827c259b..33e7041d3 100644
--- a/tasmota/tasmota_xx2c_global/xx2c_interface.ino
+++ b/tasmota/tasmota_xx2c_global/xx2c_interface.ino
@@ -412,13 +412,11 @@ const uint8_t kI2cList[] = {
/*********************************************************************************************/
-bool I2cEnabled(uint32_t i2c_index)
-{
+bool I2cEnabled(uint32_t i2c_index) {
return (TasmotaGlobal.i2c_enabled && bitRead(Settings->i2c_drivers[i2c_index / 32], i2c_index % 32));
}
-void I2cDriverState(void)
-{
+void I2cDriverState(void) {
ResponseAppend_P(PSTR("\"")); // Use string for enable/disable signal
for (uint32_t i = 0; i < sizeof(kI2cList); i++) {
#ifdef XFUNC_PTR_IN_ROM
diff --git a/tasmota/zigbee/Aqara_plug.zb b/tasmota/zigbee/Aqara_plug.zb
new file mode 100644
index 000000000..a9c2d9720
--- /dev/null
+++ b/tasmota/zigbee/Aqara_plug.zb
@@ -0,0 +1,6 @@
+#Z2Tv1
+# Aqara Smart Plug EU
+# https://zigbee.blakadder.com/Aqara_SP-EUC01.html
+:lumi.plug.*,LUMI
+0B04/050B=0B04/FFFF # ignore the original ActivePower since it returns always zero
+000C/0055=0B04/050B
diff --git a/tasmota/zigbee/Tuya_KCTW1Z.zb b/tasmota/zigbee/Tuya_KCTW1Z.zb
new file mode 100644
index 000000000..f778cc983
--- /dev/null
+++ b/tasmota/zigbee/Tuya_KCTW1Z.zb
@@ -0,0 +1,5 @@
+#Z2Tv1
+# Tuya fix humidity by 10
+# https://zigbee.blakadder.com/Tuya_KCTW1Z.html
+:TS0201,_TZ3000_ywagc4rj
+0405/0000=0405/0000,mul:10
diff --git a/tools/decode-status.py b/tools/decode-status.py
index d076f11a2..06cab64e5 100755
--- a/tools/decode-status.py
+++ b/tools/decode-status.py
@@ -97,8 +97,8 @@ a_setoption = [[
"(Rotary) Rotary step boundary (default 10)",
"(IR) Base tolerance percentage for matching incoming IR messages (default 25, max 100)",
"(Bistable) Pulse time in milliseconds for two coil bistable latching relays (default 40)",
- "(not used) Tuya MCU power Id",
- "(not used) Energy Tariff1 start hour",
+ "(PowerOn) Add delay of 10 x value milliseconds at power on",
+ "(PowerOn) Add delay of value seconds at power on before activating relays",
"(not used) Energy Tariff2 start hour",
"",
],[
@@ -287,8 +287,8 @@ a_features = [[
"USE_BP5758D","USE_HYT","USE_SM2335","USE_DISPLAY_TM1621_SONOFF"
],[
"USE_SGP40","USE_LUXV30B","USE_CANSNIFFER","USE_QMC5883L",
- "USE_MODBUS_ENERGY","","","",
- "","","","",
+ "USE_MODBUS_ENERGY","USE_SHELLY_PRO","USE_DALI","USE_BP1658CJ",
+ "USE_DINGTIAN_RELAY","USE_HMC5883L","USE_LD2410","",
"","","","",
"","","","",
"","","","",
@@ -321,7 +321,7 @@ else:
obj = json.load(fp)
def StartDecode():
- print ("\n*** decode-status.py v12.1.1.4 by Theo Arends and Jacek Ziolkowski ***")
+ print ("\n*** decode-status.py v12.2.0.5 by Theo Arends and Jacek Ziolkowski ***")
# print("Decoding\n{}".format(obj))
diff --git a/tools/fw_SonoffZigbeeBridgePro_router_only_cc2652/SonoffZBPro_router_20220125.hex b/tools/fw_SonoffZigbeeBridgePro_router_only_cc2652/SonoffZBPro_router_20220125.hex
new file mode 100644
index 000000000..19bb38b64
--- /dev/null
+++ b/tools/fw_SonoffZigbeeBridgePro_router_only_cc2652/SonoffZBPro_router_20220125.hex
@@ -0,0 +1,5722 @@
+:20000000003A0120D924020039FB021039FB021039FB021039FB021039FB021039FB0210E2
+:1C00200039FB021039FB021039FB021039FB021039FB021039FB021011FB021002
+:200040002DE9F04FAB4EC34C05460121ADF1540DAF78327894F842000E91297845293FDC6F
+:20006000452900F0078728291EDC282901F03980002901F0F982891E01F0E382491E01F064
+:200080005583491E01F04E83C91E01F0CF82491E01F07882491E01F06B82DFF8C0C2C91F5E
+:2000A000122952D901F0F0BA2A3901F00980491E00F0FF87DFF8A0C2491E00F098870E398F
+:2000C00000F03887491E01F01883491E01F01183491F00F00287891E00F0EE8601F0D4BA27
+:2000E000D8291CDCD82900F007814A3900F0A886491E00F08F86491E00F08286491E00F0CB
+:2001000074865339242935D92D3901F0C982491E00F0B283093900F01F8201F0B5BAE13983
+:2001200001F0B882C91E01F0B182891E00F0C680491F00F09880BC4A0E397CD0491E46D026
+:20014000491E3ED0491E01F09FBADFE811F0070AC709A9099D0AE60A910982099D0A600952
+:200160003F099D0A0A09DB089D0AE20ADF0ADA0AAE08DB07DFE811F0B90AB50AB10A320665
+:20018000AD0AA90AA50A2D069E0A1006D305A20577056605560546053A0530052705990A06
+:2001A0001E050405DC04A2047E047104FE03F203E703880A880A880ABC039C03880A880A7E
+:2001C0008A036868002801F0998000F00BBE6868002801F093801146097831F0010140F0B0
+:2001E00001860488466802208DF820003146ADF8224009A829F0E4FD08A815F0EDFB012888
+:2002000015D14FF6FE70A0420BD0304628F00CFC28B9002120460A4626F074F808E00020B0
+:2002200006E0002130460A4621F084FA00E00E980F95139055E1696891B11046007830F05E
+:20024000010040F0CF85084600218DF820100990022108A88DF821101DF080FE01F01EB980
+:200260000F9501F04BB86868007878B9002027F0D1FE26F0F1FF0E980DA98DF834005220DA
+:2002800025F0CAF928F0A0FA01F054BA4FF6FF7027F0C0FE30784FF4807122F041F830787D
+:2002A0004FF4807120F03AFE00200DF135018DF83500522025F0B0F901F03CBA68680028A5
+:2002C00001F03882A34C01886180807A60B929F0D8FE40F28A21B0FBF1F220780821521D7D
+:2002E00029F039FF01F026BA708F0E9928F0EEFE01F020BAE4FA002068680F95002800F0DD
+:20030000FD8700681090807E27F06EFF061C00F0B0821098C76900252C464FF00309387821
+:20032000A04200F3FF800F2410FB04F0401CC0B240191CF08FFC5FEA000800F0988224F00A
+:20034000B7F9002840F0EC800025139588F800504CE0C0464CFF002098FD00201C030120FA
+:200360001099032315FB03F6BA1991F81AA0B1F80C9052880F2015FB00845046494625F073
+:20038000EDFBBA195288834608AB504623F0E4FB641CBBF1FF0F1AD0C8B1A6489DF827304D
+:2003A0000168D80838BF8C2012D39DF826001623207103FB0B10C18800F10E02A4F80510D3
+:2003C0000189C4F80B201398A4F8071000E086202070B8194078BB1960705888608098F8BB
+:2003E00000006D1CEDB2401C88F800003878A842B6DC1098817E474600F10E064FF00F093D
+:2004000085893A78109190F80AA01196139912950C468A4267DC204629F03EFF061C5BD0E5
+:20042000139D024641E0C046ADFE002015FB09F0391838184078491C02F8010B487802F84B
+:20044000010B887802F8010B4888001202F8010B0B7843BB4B78F3B9087902F8010B48796A
+:2004600002F8010BB1F80500001202F8010BC87902F8010BB1F80700001202F8010B087920
+:20048000834628F09AFE70B1D1F80B10584617F0EFFA024607E0487A02F8010BB1F80900A7
+:2004A000001202F8010B6D1CEDB23878A842BDDC139900910E98019002900391CDF810A0BA
+:2004C0000594129A069610980791119909230FF0EFFE304629F020FE384624F05DFB28F08A
+:2004E000C3FC1398C6E111FB09F3F818FB185E78241DA4B2401C86B9467866B90079834699
+:2005000028F05BFE641DA4B238B158461CF018FE001984B201E0A41CA4B2491CC9B278E765
+:200520004046A2E114FB0972109930785288898908AB23F011FB50B19DF82600014628F0FE
+:200540003CFE20B108461CF0FBFD2D18EDB2641CE4B2E4E69C03012068680F95002800F02E
+:20056000CD8600681090807E27F03EFE002800F080811098D0F81C8098F80000002800F002
+:2005800078818000401C1CF065FB0028119000F06E8129F08FFB24F08BF8002840F06481FB
+:2005A00000261396129698F80000B04200F3E4801398012840F08C80CC4DA878EA68162119
+:2005C00011FB00F081B2562029F018FD05F10C0640B9A8783268162111FB00F081B25620B1
+:2005E00029F012FD6078802121F09AFE2F78B8001CF030FBB8465FEA000B69D02E78B8F141
+:20060000000F0CD005F11800594642784A70428810F8144B4A807F1E01F8044BF5D1002EFA
+:200620003CD037464FF000094FF0140AA6B305F1180411E0FC0C0120002808BF4E4607D0AD
+:2006400041680668216124F0A7FA207B401E2073304624F0A1FA2E7820690028ECD1761EF3
+:20066000F6B216FB0AF2A0184188618041786170C188E1808188A18001890C30218109C8CC
+:2006800004F10C0181E80900105D2070A318C3F8109083F80C902E707F1EC7D10FF06AFC84
+:2006A000B8F1000F11D018355C4647466078618825F042FEFF2804D02678810001EB0011F8
+:2006C0006E547F1E04F10404F0D1584624F064FA12981199087018B9002048700E9F0F704C
+:2006E000109890F81AA00C4600F10E098689857A2078042110FB01F0804629F0CDFD071C23
+:200700001ED0014600202278824222DC012A03D164780CB9DDF83880002000900E99019112
+:200720000291039004953246CDF81480072306974946079050460FF0BBFD384629F0ECFC70
+:20074000119824F029FA28F08FFB26F0BFFA002090E08200A3185B780B70A3189B784B70A4
+:20076000A318DB78A2188B70B2F80320401CC0B21212CA70091DC6E7109B9F890E2016FBD8
+:2007800000856D1C93F81AA0B5F80190394650464A4625F0E3F9834608AB504623F0DCF938
+:2007A000BBF1FF0F48D0002846D02F78002F58D19DF82600E97888423CD19DF82700C008B3
+:2007C00036D3BD480168A8884FF6FF72824201D1EF88B7B1162202FB0B17F880E88838814F
+:2007E000E87828F0EAFC00B30E370021042238461EF0ACF8E8781CF0A3FCD5F80A100246F2
+:2008000010E0162000FB0B156889E880A889042205F10E070021288138461EF097F80422D1
+:2008200005F11201384628F035FD0E98139018E08C2002E08D2000E08720129BDDF844C05E
+:2008400099000CEB0102507028780CEB01075B1CB8700CEB0102DFB21297B5F80110A2F87B
+:200860000310761CF6B29EE6119824F095F9102000E002200F9DB6E26868002800F03E853B
+:200880006868006825F072FD00F008BEAF68002F00F0348500246C7040B12046014604F065
+:2008A00019FB002808BF201C00F0B8810E98B5E16868002800F022850020696868700978BB
+:2008C00061B984F8460094F82100401E84F821000E98014625F07AF900F02CBF29F058FBD8
+:2008E0000E98014607F08EFE00F024BFF00C01206868002800F002850678476800210822B1
+:2009000008A81EF023F8E7B1CD4800210170AEB1761E0ED0761E0AD0761E03D0761E10D1A4
+:200920000E990170384608A918F0F8FEC2E20E990170384608A924F04FFABBE222F09EFDE0
+:20094000B8E20220B6E26868002800F0D784686800F1120124F040FA00F0A0BD6868002899
+:2009600000F0CC846A6810785188928817F05AF900F094BD6868002800F0C08490F800900B
+:2009800046888188B0F806B0B0F808A00A301090C94807790F91002F00F03D81C5490F6865
+:2009A000002F00F0AB8480467868007881454FD128F048FB00284BD0037C002B48D04469D8
+:2009C000002C45D000200C22834240F3978410FB02F1615A8E4238D10E201CF03BF9071C52
+:2009E00000F01981002407F10A0004235B1E00F8014BFBD1BC80FF2038704FF6FF737B80E2
+:200A00003C81FC8087F800900F9A7E801099BA8007F10A00A7F806B00422A7F808A028F028
+:200A200039FC08201CF016F9D8F8141018B9384624F0B2F8EFE007604160C8F8140098F802
+:200A40001000401C88F8100067E1401CC0B2BBE73F68002FA8D100F051BC6868002800F0AE
+:200A60004D840020687068681FF000F9A968088000F060BEA868002800F040840021697048
+:200A8000AD68267860786F1C002E08BF29700ED0402124F061F84FF47A710F2300F2E7309D
+:200AA000B0FBF1F116FB03100F3828702678002F00F040863046B2E0FC0C0120AF68A18FAB
+:200AC00094F83F2094F83E3094F84060D4F838C094F841E094F8438094F8449094F845A074
+:200AE00094F846B0002F00F0098400276F70AF683981A968CA72A9688B72A9680E73A968F3
+:200B00008873A868C0F804C0A86880F80DE0606BA9680860A86880F80F80A86880F8109056
+:200B2000A86880F811A0A86880F812B000F002BE6F68002F00F0E283002068706868077DDB
+:200B400017B1C07C84F845006868877D17B1417D84F84610077C17B1C089A0876868077B97
+:200B600017B18068A0636868877C1FB1407C84F84100686807790FB10068606300F0DABDE4
+:200B80000021697070B194F83F0080090AD208A808221DF0DBFE28F0C3FF08A81AF084FD35
+:200BA00000F0C8BD28F0BCFF4FF4FA7027F0FCFD00F0C0BDA868002800F0A0830020687080
+:200BC00029F040FA2AE0D948A9680078002900F095830021697021E06868002800F08E83E9
+:200BE0006868007822F088FE00F058BC6868002800F08483002068706868007806F0E8F90B
+:200C000000F098BDA868002800F078830020687023F09CF908B90E98E5E00078AF68387069
+:200C200000F088BD6868002800F068830020687069680888897822F057F800F07BBDC046C3
+:200C400054FE00206868002800F05883B84C6968082204F10C0028F01DFB686801896180F4
+:200C6000807A2070B3E06868002800F047830188ADF830104088ADF832000CA9532024F05C
+:200C8000CBFC50200DF1320124F0C6FCE1200DF1360127F021F868689DF8361000798842C2
+:200CA00000F095808DF836000DF13601E12024F0B3FC8CE024050120F00C012068680028B0
+:200CC00000F01C83007825F033FA686896F83C104078884213D086F83C000DF13701E120CB
+:200CE00026F0FAFF68689DF837104078884206D08DF837000DF13701E12024F08DFC686881
+:200D00000E9F407807FA00F0F06428F04BF80024A6F89440384621F063FC204663E06F68CA
+:200D2000002F00F0EB82387886F84A007C887487387A86F83C007B89F3877A68F264B9894C
+:200D4000A6F84810B87B86F85C00F87B86F82900387C86F827007C697465B86996F896100A
+:200D6000B065387F884201D025F0E2F9696806F15D001D3129F010FA96F84A0006F124048F
+:200D8000082824D121207421224629F03DF90020022125F0F7F81AE06968002900F0AE8246
+:200DA0000888498825F034FC70B9696808880E9A498823F049FD69680888498825F028FCC6
+:200DC000002808BFC8200ED0696809794170002009E06868002800F0918203E0686800287B
+:200DE00000F08C8212202C465BE26868002800F049846A6810889178D27825F083FA4DE3E0
+:200E00006868002800F03E846868017A427A20F091FC43E36868002800F0348441788DF880
+:200E2000201081788DF82110007828F001F8002800F064820C3008A9022228F02BFAC6E751
+:200E40006968002900F01E84A868002800F01A84087808A927F063FB6868A96800780870C9
+:200E60009DF82000A96848709DF82100A968887000F025BC6868002800F004840A3007783B
+:200E8000002F0CBF00220E9A47780FB142F0020287780FB142F00402C7780FB142F00802A7
+:200EA000007908B142F04002696808880023891C24F000FE044630E76868002800F0E283A3
+:200EC00002206F688DF828003988ADF82010FA78B97808A821F0D4FAE0E26868002800F0FA
+:200EE000D18302218DF8281001884FF6FF70884205D0821E8A4202D0C01E88420BD128F008
+:200F0000D5FFADF820006868C27A837A811C08A823F08AFB687068680188ADF82010C27A08
+:200F2000837A811C08A823F07FFBB7E2DC02012094FF00206C68002C00F0A48302208DF8D1
+:200F400028002188ADF8201063462279B4F80680267AD4F80CB0277CD4F814A061880F92A0
+:200F60001A1D14680346F21912FB03F00F305FFA80F9B9F1500F00F3198128F097FF88424B
+:200F800033D121700812607028F054F9A41C0146204629F001F904460F98207084F801806F
+:200FA0004FEA2823A370E670241D66B15846A41E017804F8021F30F8021B761E4FEA2121A2
+:200FC0006170F5D1A41C27705FB1641E5046017804F8021F30F8021B7F1E4FEA2121617037
+:200FE000F5D1C74820224B465EE01846FBE66C68002C00F0478302218DF828102088E14663
+:20100000ADF820006288A388A679D4F80880277BD4F810E0D9F80400F41914FB01F1891D9C
+:201020005FFA81FCBCF1500F42DC9DF828100F2918BF022908D1BDF820404FF6FF71A14223
+:2010400004BF891EADF820104FF6FF71914208BF8A1E00F8012B111200F8011B00F8013BCB
+:201060001C1200F8014B00F8016B66B14146801E0A7800F8022F31F8022B761E4FEA22224C
+:201080004270F5D1801C07705FB1401E71460A7800F8022F31F8022B7F1E4FEA22224270D3
+:2010A000F5D148460622634608A91FF037FD9AE67CE06868002800F0E5820220052216E0AD
+:2010C0006868002800F0DE8202206F688DF828003988ADF820103A79798808A827F094FB82
+:2010E00081E66868002800F0CD82022002468DF8280068680188ADF82010418808A827F07D
+:201100007BFECBE12C466368002B00F0CC80187D27F0E2FE002800F0C6809D691C331F7830
+:20112000002F0CBF002002205F780FB140F010009F780FB140F00800DF780FB140F0200026
+:201140001F790FB140F040005F790FB140F0800083466068007D28F0A5FD5FEA000800F076
+:20116000A2806168887A8DF829008889ADF82A00087802288DF828000CD001280AD00F2887
+:2011800008D0032809D1891C08A8082228F082F8616802E04888ADF820008F7B002F72D0A6
+:2011A00078001BF057FD061C02D1254610201AE600216068877B8F425FDCC18A838CCDF8B2
+:2011C0003C80826A13950C2F109190F822901193BDF8208012924ADA404620F03FFD0C28E2
+:2011E00014D14FF6FE7020F039FD0C280ED1BA4A0E9992F8D4500020DC3212F8083B9D424B
+:20120000C4BF1D1C081C491C0C29F6DBC24D4FF6FE7305EBC00568686B8018B123F0BCFCBA
+:201220000020686077B14FEA470A50461BF012FD6860002808BF10201AD0686831465246B4
+:2012400028F028F8A5F80280C3486F70129B0078139F28700F990093109A019708A8CDF8EC
+:2012600008B0119BCDF80C900DF06AFA00E002206070304623F090FC5CE200694A00105A06
+:20128000491CB05295E7886A00900195CDF808B091F822000390CA8A8B8C08A841460DF0F9
+:2012A0004FFA2546FAE0254628E0686830B3007827F012FE071C21D0387B22F0F7FA0028E9
+:2012C000687040F03782AE4845683E46002D00F031822F46002117B9BE4202D02AE2BE4212
+:2012E00009D1B54219BF3068086031684160304628F00AFF1EE239463F68ECE7022072E502
+:2013000098FD00206868002800F0BC81A868002800F0B881002108221DF018FB69680878D6
+:20132000498826F0CDF8071C19D00020A968687038880880A968B8788870AC68A078002817
+:2013400000F0F8811BF086FC6060AA685068002800F0F0819278F91C27F09CFFEAE1B12017
+:201360009CE06F68002F00F08D81AF68002F00F089810024664668686C70376801782046B3
+:201380003FB13A79914204BF401CC0B23F68002FF7D1A9680870A868007840001BF05AFCF6
+:2013A000A968376848606868A96800784968002F00F0C0813A79904204D1FA88661C21F8F4
+:2013C0001420F4B23F68002FF4D1B3E16F68002F00F058816868002764466F7006782068AF
+:2013E00090B101798E420BD1002F04BF0568256002D001683960056823F0CEFB284601E036
+:20140000074600680028ECD123F0C6FC92E102206F686870002F00F08D81644639787A888F
+:201420002068002800F0868100270379994202D1C3889A4204D0074600680028F5D179E1BC
+:2014400007B967460168396023F0A6FB23F0A4FC35E16868002800F01581807800280CBF37
+:2014600000220E9A68680E9900881FF0E5F815E06968002900F00681887828B1C878002810
+:201480000CBF0E99032100E000216A68107908B141F040011088527913F01AFC687049E1B1
+:2014A0006868002800F0EE80696808A80822091D27F0F0FE032027F071FF6868C07B24F037
+:2014C00007FF6868817B009102788389418808A815F076FEE2E7C046200100206868002829
+:2014E00000F0D080384627F0E9FC041C16D11C201BF0B0FB041C00F01D8100211C221DF01F
+:2015000025FA2771204624F07DFB38B9204623F043FBD120C2E7C046F4010020E08887498D
+:2015200040F00800E08040F00400E080022028F017FD8349032028F013FD68680168089148
+:2015400000798DF824000E9F8DF825708DF8267008A820F05FF8A1E7C6FE0020686800280C
+:2015600000F0908068680088002103F0B3FCE1E06868002800F086806868007870709EE0FB
+:20158000281A00206F486F680478002F7AD0686800212A2269701DF0D9F9708F6968088019
+:2015A0006868B6F84870847269688F81F08F6968C8826868082206F1240707F139010E30F8
+:2015C00027F068FE27F036FE014668680822801C27F060FE6868082207F11C01183027F083
+:2015E00059FE96F83C10686880F823100E986968554C81F8210021784A0824BF6A6882F873
+:2016000024008A0824BF6A6882F82500CA0824BF6A6882F826000A0924BF6A6882F8270030
+:20162000C90924BF696881F8280083E0686848B390F90000044627F0EDFBA86800B104704E
+:201640003DE06868F0B100200E9F687069680F7069684F7068680226867068680624C4705B
+:20166000696803230B7165E0686858B1407818B1FF20032124F086FC28F024FC0E98334925
+:201680000860FEE7022009E7122007E729461DF0EFFB4EE000202E496870EF780F7049E0B9
+:2016A000002068701CF0CEFA44E00020687025F01DFF3FE010464FF4807120F073FA0020CB
+:2016C000ECE629461FF02EFB33E0294613F0B0FC2FE0294618F034FF2BE0294628F002FB18
+:2016E00027E0294621F018FF23E0294621F0CDFB1FE029461EF0D0FB1BE0294619F096FEB3
+:2017000017E0384629460EF08FFA12E027F06AFEC4E6294620F040FC0BE03846294607F0B9
+:20172000E5FB06E0294607F0EDF802E0294607F065FA0E900E9815B0BDE8F08FD1480200A9
+:20174000519A020034FD0020E61201207C052043481900202DE9F04704464FF6FE70ADF1E5
+:20176000600D217AADF85400606808AA13F0A4FF002800F072849DF822000228B4BF0127BE
+:2017800000279DF824000228A8BF0027BDF82A104FF000084FF6F87088420ED04FF6FE7073
+:2017A000401F884209D04FF6FE70001F884204D04FF6FE70C01E884200D1474628F070FB7B
+:2017C0009DF82310884240F04884002F00F04584208D9DF82660678EDFF80093ADF84C007B
+:2017E000ADF82E70D6B161689DF821209DF83C30012027F0A3FD002840F02F844846001DF1
+:20180000007801280AD1208D28F066FC30B1417901F0EF01417141F0080141719DF82570E1
+:201820004546002F4BD19DF83D00474658BBBDF82A00034623F050F94646022808BF012638
+:20184000002E9DF8226018BF0127B9F83A10994208BF47F0020727B1002E14BF40202020EE
+:201860000743184623F038F9012808BF47F00107002E3DD01298007828F01CF9012818BFC3
+:2018800027F0010734E09DF8411041B1FF2906D09DF84000119A24F001FD50B128E0B9F8F3
+:2018A0003A00BDF82A10884205D099F84A0004281ED101251CE09DF82660222721E0BDF82E
+:2018C0002A10FF2025F0FCFD002804BF3E1C082708D09DF8250047F001062C2740F00100D9
+:2018E0008DF8250006F00306012E08BF47F011079DF8266007F002012846084308BF47F02E
+:20190000800796B999F82F0078B107F0220022280BD007F04200422840F09F8312980078B3
+:20192000062818BF072840F09883B8111690F80956D399F832001299BDF82A2080080AD2BE
+:201940000878C01E01282CD9001F2AD0C01E28D0801E26D003E00878401E0A2821D9B8F1E2
+:20196000000F1ED1B9F83A00904240F076830D780520BDF82C408DF8110004A826F044FE1E
+:20198000002800F06A830269032313271370511C0F704C7022128A70CD7044800AF06CF9BE
+:2019A0005BE3169840081BD30878032802D148780D2815D09DF8280038B1BDF82C000E997F
+:2019C00011F0CCF9012800F044839DF8270038B1BDF82A000D9911F0C1F9012800F03683AA
+:2019E000B9F84800B4F84410884209D1CDF80080208DB4F8421094F84620434613F0E2FEFC
+:201A00009DF82600002846D0208DB4F8421024F0FFFD9DF85150061C25D19DB999F890004D
+:201A200001283AD112980078062802D11698400833D2BDF82E104FF6FE70401C884240F058
+:201A4000B6800AE3042026F048FD011C00F005836420087001274F70208D488099F8000066
+:201A600021F01AFEF9E29DF82130606819184A7BF1788A4203D0F270404670606068C0185E
+:201A80000421401C26F0DFFF7168814200F2E582401C706001E09DF8515099F8320080084E
+:201AA000C0F0DB820DB3BDF82C0027F09FFBB8B9BB49BC4CBDF82C000B6822699901A1EB45
+:201AC00083019047012840F0C8826169BDF82C008847A168BDF82C008847BEE2E4FA002037
+:201AE0006168487800F0DF0048709DF8320038B161688879401E8871C0B28DF8320008B91B
+:201B000007F07F07380924D39DF82500F9084FF4805814D279091AD3811011F0070F01F04C
+:201B2000070604D0072E1CBF761EF6B20EB907F07F0700F0E30040EA8600C0B205E020F04A
+:201B40001C00C11021F0030108438DF825006168087299F84A00042800F00082092800F0B1
+:201B6000FD8117F0610F40F0E6809DF82200012811D112980078052800F0D68003280AD17D
+:201B8000BDF82A0027F032FB28B1218D08A815AA002300F0FBFE9DF8320068B99DF8220081
+:201BA000012804D112980078032800F0568208A8214620F041FD50E226F0AEFF002840F060
+:201BC0004C829DF83D0000286DD19DF82400BDF82A10FD100028ADF854102ED13A0930D2D5
+:201BE0009DF82220012A28D0084600211DF000FC002620B14079012816D0022814D0BDF8F1
+:201C00005400B4F8441024F003FD28B1807826F097FC08B1082807DBBDF82C0027F0E6FA3F
+:201C200018B104208DF824000126BDF82A10301C08BF022272D09DF824006A0838BF00233A
+:201C400000D340230DF13D021DF00CFC30B16168087848F0200800F03F0008709DF83D00F9
+:201C600040B1BDF82A1010A822F016FF48F04008ADF854009DF82200012806D0BDF82A0097
+:201C8000BDF82C1000221AF01BF868082CBF40220022BDF82C10BDF82A0016F0EDFB08B1BE
+:201CA00048F0200833E09DF840009DF84110119A24F0F4FA00282ED09DF8410038B9BDF8A7
+:201CC0002A00ADF8540028F007FA00BB1DE011999DF8286001EB400030F8020C002EADF814
+:201CE00054000CBF082010209DF827600EB10830C0B29DF82560002106B1012140186168B3
+:201D0000401CC2B2505C401E505448F0400826F0C9F91690A3E0BDF82A100B22BDF82C00C7
+:201D200000231DF01DF998E1218D08A815AA002300F02CFE91E10020169078086AD3B4F8E9
+:201D400028A09DF833C0B74D1E211698EA79944506D1BDF82C302A88934201D1AE782EB9B8
+:201D6000491E05F1080500F10100EFD11E2826D0AE790EB3B9F84810504625F0A9FC08B111
+:201D8000761EAE71B64833210279FF2A02D00288924509D0491E00F12400F5D107E0C0465F
+:201DA0006CBC0200ECFB0020A879401EA871A8796628A4BF1698A87127F060072AE026F0E3
+:201DC00071F916909DF8320028B9BDF82C00218D814202D11EE0BDF82C00B9F83A10884282
+:201DE00002D199F80600A8B1218D169A08A812F06DF858B1380932BFBDF82A004FF6F870E4
+:201E0000C01D48F00408ADF8540003E0002027F020071690B8094FEAA71510D394F8460056
+:201E200094F8476094F948308DF81000E26B8DF8116004A98DF8123008A804F0DBFC680833
+:201E40000DD3218D169B08A815AA00F09FFD169028B112980078012808BF48F01008BDF8B2
+:201E600054104FF6FE70884204BF002016907E481B30007801282BD1618E4FF6F870C01DD1
+:201E8000884225D0218D884222D0BDF82A204FF6F870401C90421BDDBDF82C00884217D0B5
+:201EA00028F01AF9A0B10179012918BF02290FD101218DF810104088ADF81C0004A821F013
+:201EC0000DF828B105A820F095FD08B125F0C8FE37F07F0000F0C1801698002800F0BD8067
+:201EE00020891AF0B7FE071C00F0B7806168228927F0D0F9002605969DF822008DF81000CF
+:201F00001699009104ADCDF80480B046CDF80880BDF854100395228D237A384617F05CFC6A
+:201F2000C0B999F80100002800F09780BDF82A00ADF81A0045468DF81E508DF81D50BDF8A4
+:201F40002C70ADF81870169E8DF81C6006A827F0F1FA82E0384622F01FFE7EE04149BDF8A7
+:201F60002A000988814209D022F0B6FD022805D09DF8250000F0030001286ED19DF822007A
+:201F8000002851D012980178042903D19DF83C10022942D00178072905D19DF83C2099F8B5
+:201FA0000000042A06D0032957D108A8002115F0E7F952E04FF4806120F0B2F9092089F858
+:201FC0004A0029484178022904BF0021817727F031F901460D9827F00BF801283DD11020D8
+:201FE00026F07BFA07460E991298002F00F1010033D002223A704378027802EB03227A8085
+:20200000807878704A2023F007FB9DF8260010B9164905200870394620E5002008A90DF08F
+:2020200017F81AE0CC02002094F8460094F8477094F948608DF81000E26B8DF8117004A9CA
+:202040008DF8126008A804F0D5FB06E0BDF82A0001E0BDF82C0021F021F918B0BDE8F0877F
+:20206000E40D00201EFB0020ACFE002034FD0020C64A2DE9F04FADF14C0D10780F91090C62
+:2020800080F058840F99890B80F025840F99890980F054830F99490980F0D6820F98DFF8DE
+:2020A0000093C00980F060820F98000A06D321F09DFD0F9880F0800000F05BBC0F98DFF821
+:2020C000D8B2DFF8D882DFF8DCA2400A80F0DC800F98000B80F0C28010460F99C078490BEC
+:2020E00080F0B2805C460F99606AC90B80F096800F992078890863D20F98E188800A40D21E
+:202100000F98000907D3114601200F9F887187F0080000F02EBC0F98C00A0AD31046B0F871
+:202120004800012122F05EFA0F9880F4806000F020BC0F98400C38BF0020C0F01A84544612
+:20214000332501262434207980B105280EDA607900090BD28DF804606088ADF8100001A8DB
+:2021600020F0BCFE10B102A820F044FC6D1E04F12404E8D1854900200F9F087187F4803039
+:20218000F7E310461746B0F84850A7F848105020A11D23F041FAE6883227444660898542FE
+:2021A00005D0864204D0204626F0EBFF00E066817F1E04F11C04F1D10F9880F40070D8E3C7
+:2021C00040B301A827F08CFF27F05EFE49460546032091F8228091F823608DF80D0003A8DD
+:2021E00026F012FA071C15D038690B2100F8011B00F8018B06700126BE7727F01BF878627A
+:202200007D807E7701A838620023BE763846237009F032FD0F9880F00200AAE380B1494693
+:202220001431097801290BD18047A06A00B18047564800784FF480414FF47A7227F088FFA2
+:202240000F9880F4804094E320B100201146C87022F062F90F9880F480508AE322F05CF980
+:202260004946087A01280BD1497A49B1474800784FF47A7212FB01F24FF4006127F068FF33
+:202280000F9880F4006074E327F010FE4FF6FE71814200F06581104690F832008008C0F0B2
+:2022A0005F8100252C46284625F03AFC071C1AD03879012817D0022815D0F879334E411CC2
+:2022C000F97196F88B1081420DDABC727C72388824F03CFC388801A925F03DFE01A820F026
+:2022E00089FB25F0BDFC6D1C332DDCDBA8F11C0632274FF6FE75119436F81C0F85420DD07E
+:20230000307B224C411C317394F88B10814205DA1198B0747074308824F018FC7F1EEBD1F0
+:202320005C46032104F1380010F8047F0FB17F1E0770491EF8D15446332605F1010934F8FC
+:20234000240F81451FD001208DF804006788ADF8107001A820F0C2FDA8B1A8F11C053227F3
+:2023600035F81C0F2188814208D0BDF80610814204D002A8A91C26F03BFE10B1284626F05C
+:2023800000FF7F1EECD1761ED9D101E0E4FA0020119D2C4608E0C046ECFB00206C0800201E
+:2023A000ACFE0020C00D0020284625F0B9FB48B1017931F0040105D1807A26F0C1F808B13E
+:2023C000641CE4B26D1C332DEEDB25F0D3FF119E5FEA00080ED03546284625F08FF928B111
+:2023E000807C26F0ADF808B1761CF6B26D1CEDB2A845F1DCA019C7B2002F41D0B8001AF01D
+:2024000029FC1090002808BF119F3BD0BA00FF211CF09CFA119E3546B44218DD284625F039
+:202420007FFB031C10D0187930F004000CD1987A26F086F8011C07D0009718885A7A109B41
+:202440001BF06BF9761CF6B26D1C332DE4DBB8F1000F17D0119C204625F050F9061C0AD01F
+:20246000B07C26F06DF8011C05D00097109B3088727C1BF052F9641CE4B2A045EBDC01E0E2
+:2024800011981090BB4890F83000002808BF4FF0620805D026F046FFC0F154005FFA80F89A
+:2024A0000320B8F1600F98FBF0FAA8BF4FF01F0ADDF840904FF6FE7BABF1020BB8F1000FD1
+:2024C0000EBF119D2025DDF84480BA45A6BF3C1C45F040055446032014FB00F0801C8DF890
+:2024E000050001A826F090F84E46031C26D01869082104F01F02017045EA02014170801C38
+:20250000A4B12246C01E361F16F8041F00F8031F318809124170B17801F0070CF178521EF5
+:2025200001F0070141EA0C118170EDD1A3F802B001209876184609F09FFB00E00120E9094B
+:2025400006D2641EE4B20CB109EB84093F1BFFB205F040052843B1D0109808B122F01CFB92
+:202560000F9880F4807004E2B64C1E25002106264FF00408A078002840D0401EC3B2607991
+:20258000A37026F0FDFC071C37D05BB9787B022808BF7E7331D07E733868407BF02121F097
+:2025A000D1FD2AE0A3791BB9787B032813D024E0237913B3E078401EC3B2E370EBB96D4815
+:2025C00090F82500E0702079401EC3B22371787B032812D123B92046394622F03DFB0CE006
+:2025E00087F80D8027F04DFD624B00F00F00401C3881187820211FF0D5FA01216D1E04F15C
+:202600000804B7D15B48007801290FD040211FF087FE494691F82900012811D1002081F828
+:20262000290018F0C3FD25F01BFB09E0402122F093FA28B94F4800784021642227F088FD22
+:202640000F9880F0400094E1102122F085FA30B94848007810214FF47A7227F079FDB34813
+:20266000DFF8CC82417808F52774491ECFB217BB012141700020052126F076F9071C1BD07E
+:2026800006253846052126F06FF90646388978B1401E80B2388158B97889C00802D3387B0C
+:2026A00024F03CFA7D733868407BF02121F04AFD371CE6D100E0477096274FF6FE760025E0
+:2026C0002079A0B1FF2812D0401E2071C0B270B96079032805D16088218802221EF082FC62
+:2026E0006079012803D0268066806571A5717F1E04F10804E4D108F184040827207A401E92
+:202700002072C0B230B99C48214624F06FFB90B9668025707F1E04F10A04EFD1974A0C21D1
+:2027200012F8080F08B1401E1070491EF8D10F9880F010001DE121F09DF9E4E7202122F0C7
+:202740000BFA28B90B480069002808BF01261BD027F0CAFE044627F08BFB8B4F4FF47A7108
+:202760006043B0FBF1F13869002808BF002008D002E0C046E4FA002088428CBF4FF0FF3038
+:20278000081A460869D0FFE70020042126F0ECF8071C62D04FF00009FF254FF0FF3B062407
+:2027A0004FF0010A3846042126F0DEF810903889864204D8801B83B23B8113B14AE0A7F822
+:2027C0000890BB7B012B02D17889C0083CD3ABB38DF804508DF805508DF806B03968086AF5
+:2027E000C97F02AA12F068FFC846012808BFD0465FEA08001DD0788A40F08000ADF836009D
+:20280000B87B8DF838007889000908D3BDF8360040F48070ADF83600387B8DF83A007B69A3
+:2028200013B1187BADF8180001A94A4602A803F0E1FF7C73387B1BF0D5FD0BE087F80DA037
+:2028400008E0C046CC0200207C733868407BB72121F078FC109F002FA4D10FF0FFF84A481A
+:2028600003780121002026F07FF818B1184620211FF098F90020042126F076F8B3B278B1AF
+:20288000414A0789147826F06FF8F8B9BB42AEBF0027FF1ABFB2204627B920211FF082F937
+:2028A00000200DE07A00202127F055FC27F01CFE044627F0DDFA4FF47A716043B0FBF1F022
+:2028C000314908610F9880F0200052E00289BA42D8BF171CD7E727F079FC294C0546201D14
+:2028E0000068074698B1284857F80C1C007821B94FF400511EF012FB03E04FF400511FF06C
+:2029000051F9204639460022001D23F04FFF284627F0E6FD2FB13846FEF71CFF384625F07F
+:20292000C3FE0F9880F4005023E0C046D4130120200100201FF008F9071C17D01149203154
+:202940000A78FF2A0FD03C780B460020944207D0401CC0B2C200D1189A5CFF2AF6D102E0DA
+:20296000496838468847384625F09EFE0F9880F4004013B0BDE8F08F39430200EC0100205D
+:2029800038050120E0B80200E4FA00202DE9F04F064693460020ADF13C0DABF80000B06A03
+:2029A000099303460078884627F084F848B17089044622F091F8022804BFABF80040B36A95
+:2029C00001D0002009901878C84DDFF82493401E0A2800F20984DFE810F02D03B1020A0473
+:2029E0009E028D0151010704BE00880066000B00BD4C207D012840F0F7835B1CB06913F881
+:202A0000015B1F7827F098FB002800F0F5830379002B00F0F183032B80F2EE830E2D1CDC3A
+:202A2000DFB9D04907752DB901EB85010A6BC261096B0AE001EB85010B6B9A01A2EB830286
+:202A4000C2610A6B9101A1EB82018161012180F8201025F005F9002500E001250320B689F1
+:202A6000A47F8DF8190006A825F0CEFD071C00F0C38338690C2100F8011B00F8015B047004
+:202A80000124BC7726F0D6FB786204A9304625F062FA10B17C7704A838627E80BC763846E1
+:202AA00009F0EAF8A8E35C1C207820F01F0700F01F00012840F09883641C04A8214627F03D
+:202AC0006BFB284604A95D3026F092FA002800F08B83002F40F088830834A27861782078EF
+:202AE00001EB022123F06EF986E3688F7189884240F07A835C1C14F8016B04A8214627F0E2
+:202B00004BFB284604A95D3026F072FA06F01F0726F01F06002800F06F83002E40F06C8397
+:202B200078001AF097F8011C00F0668367B184460834384663782278401E04F1020402EB37
+:202B400003222CF8022BF5D100910AF03AFD084622F022F850E35C789A1C34F07F0704F0A2
+:202B60001F0E40F04983377F03201EFB00F0801CC1B2B94240F04083002714F01F0F04BF31
+:202B80004FF6FE7C614618D0D9789B7870464D4603EB012C5378117812F802EF01EB0321C0
+:202BA0003EF0770340F028832B888B4208BF0EF00707521C401EEDD1BFB960464FF6FE72E2
+:202BC000824212D004F06002602A0ED04D462A88A30907D2E30902D2904203DD0CE3904294
+:202BE00003DD09E39142C0F20783B08927F074FA002836D1B0894FF6FF7124F069FD041C85
+:202C000014D123F0EBFC041C00F0F68200211C221BF09CFEB0894D460E3520802888608109
+:202C2000AA23A3740622227401216174207C0C2805DB0620072F2074BCBF7F1CFFB26774B9
+:202C400000202073A01C25F0EFFE002840F0D482307A002800F0D082B169A01C27F09CFABE
+:202C6000CAE20021C171017A0C2905DB0621072F0172BCBF7F1CFFB24772BDE2484671894E
+:202C80000088884240F0B082307F022840F0AC82A94C201D00884FF6FE71814240F0AC82BA
+:202CA000162025F01AFC071C00F0A68201213970B07900280CBF081C02207870B06A407891
+:202CC000B872000902D2B08922F096FDB169B81C27F062FA0020F8742878394620F0DCFC1B
+:202CE000B089A08088E2C046ACFE0020E4FA00201EFB0020708921F0EFFE002840F07482C5
+:202D00005F78B84987B10C2F03F1020380F274828C463D465A7818786D1E03F1020300EBE1
+:202D200002202CF8020BF5D1484675890488DFF8D492AC4200F0B180B37C002B00F05C82EE
+:202D40003B1C0A974FF0000811D0A64A38464146921E32F8023F9C4206D0401E01F101013D
+:202D6000F7D104E018BC02000A914FF00108284600211CF03DFB00280B907DD04079012829
+:202D80007AD10B98807910F0180F75D00B984188384626F003F910B9B8F1010F6CD109F22A
+:202DA0004C704FF6FE754FF000080C97B6F80CB008904FF0010A0D95C14611E0B8F1010F16
+:202DC00008BF4FF0010908D027F05BF9C0B290FBF8F101FB08F1A0EB01094FF00008C246E1
+:202DE000089D32271C3D35F81C4F4FF6FE70A04213D0A34511D00C98214626F0CFF860B9A2
+:202E00006B7C53B1072B08DA08F10100BAF1000F5FFA80F801D1C14521DD7F1EE3D1B34D07
+:202E2000332735F8244F0D98A0421AD0A34518D00C98214626F0B2F898B96B7A8BB1072BE8
+:202E40000FDA287901280CD002280AD008F10100BAF1000F5FFA80F803D1C14501DC0D9402
+:202E600007E07F1EDDD1B8F1000F02D0B9F1000FA4D00D980B994880B37C5A4C581EB074E9
+:202E8000F77C00970A9D0195029401220392B189B269708918F098F8AEE1B4890C2F80F23E
+:202EA000AB818846ADF81040BC488DF812700168CDF8148009B104A8884720461EF0CEFEE1
+:202EC0000C2803D14FF6FE701EF0C8FE0C2880F2938109EBC005D435686808B121F05CFEF3
+:202EE0002FB1780019F0B6FE686010B984E1002068606C80C2486F700078287068780028F2
+:202F000000F07A816868002800F076817A00414626F0C0F970E1307F022840F06581099836
+:202F200028B94D4671892888884240F06581099831460CF08DF85EE1ECFB0020B5F84810AF
+:202F4000404623F065FBA846074608202FB17D781DB90621397007257D70B16A0A79CC789F
+:202F60008B794D7891F802A0CF7904EB02244A7902EB03296A0928BF1020AA0924BF0830CC
+:202F8000C0B235F0700340F03781327F904240F0338105F07005680938BF002006D306A85F
+:202FA000083127F0F9F825F010050820A90907D3B16A091804A8083127F0EEF825F020059A
+:202FC0002046514624F0A0F908280DDA8D4B410001EBC001C9188879B84240F30D818F71CD
+:202FE000002002E0360100200420B8F83A10A14219D048B9B189484601222B4610F0CCFE67
+:2030000028B1F9E020010020042840F0F58006A804AE009049463A465346019620460295C0
+:2030200013F090FEE8E0B189484601222B4610F0B3FEE1E0B5F84810404623F0E9FA4FF0A9
+:203040000609041C03D06078002800F0CD80B06A817847780891C378017900F1050A03EB23
+:2030600001200990404620F063FB9AF8001009185FFA81FAB80928BF4FF00E0937F078006E
+:2030800040F0B28007F01800182800F0AD80307F814540F0A9804FF00009CDF80090089956
+:2030A000B089524643461CF017FA032800F09C80002807F078074DD117F0180F18D195F802
+:2030C000310028B1B089414601223B4610F064FE09984FF6FE714A463B4610F05DFE002837
+:2030E00038D14FF6FF70ABF8000039E0C00D002047F00107780928BF47F00207B0893946CB
+:203100001CF076F990B1817911F0180F0ED0417901290BD154B14088B5F8481023F078FADC
+:2031200020B1437813B1607898425DDCB089414601223B4610F030FE60B94FF6FF70347A47
+:20314000ABF80000002C0CBF4946B169B089524625F044FEBBF800104FF6FF70884243D1AF
+:20316000012000900899B089524643461CF0B4F90998394622F0D8F9698F81422ED109988C
+:2031800026F0AAFF60B10079012818BF022807D1099804A924F0DFFE08E0C04674FD002026
+:2031A00026F048F8014604A826F0F6FF307A012803D1B16906A826F0EFFF06A8009004AF57
+:2031C0000197B06A407840F0300002900999089BB0894A4613F0B6FD48460CE0B06A80F8C3
+:2031E00005A024F05FFF06E04FF00009F4E70999304614F0C5F8099009980FB0BDE8F08FB9
+:20320000C6FE0020A40100202DE9F04FC24C04F128000768ADF14C0D17B1002087F8450073
+:20322000DFF8F082002517F148030BD0BF6DB84E73612FB940460068D0F84C05804773695A
+:203240005868706026F0C2FF1190082016F03CFC1CF09CFC464610B1B2A027F03DF91FF061
+:20326000E3F8684626F040FB042069468DF80000284626F007FDE06326F08CFA09A826F0EE
+:2032800061FC042009A98DF82400284626F062FC606326F089FA0DA826F064FC04200DA90F
+:2032A0008DF83400284626F065FC616BA06319B9A4A027F011F9A06B10B9A7A027F00CF933
+:2032C000E06B10B9A9A027F007F93068D0F8E00380473068D0F8180280473068D0F8F002DD
+:2032E0008047404600682F460726A03001687B5823B11846804740460068A030761E07F128
+:203300000407F3D1D0F8B8028047EB2026F0D4FDA06A2F4670B105A8FF2108221BF016FBF0
+:20332000A06A05A9082225F0AFF904F12806012818BF3768924A0CCA05A8391C80E80C0004
+:2033400021D1082019F086FC5FEA000856D0A8F10206032726F095FE06F8020F7F1E4FEAF8
+:2033600020207070F6D12020F82706F8020F4146082204F1440088F8077025F08BFF4046F2
+:2033800021F00AFC04E004F14400082225F082FF0120082105AA26F031FE04F14406002894
+:2033A00018BF092826D124F022FE80081DD205A8FF2108221BF0CAFA07AFFF21082238461F
+:2033C0001BF0C4FA0120294608223B4626F004FB80B9384605A9082225F056F928B930468A
+:2033E0003946082225F056FF04E001200821324626F00AFEE220314622F00EF924F0F7FD5C
+:20340000400834BF2E1C0126CA4F5520012107F1420226F0F3FD18B916B1284624F07CF880
+:20342000C54FE22007F1440124F056FC30461FF0D9FC05A8294610221BF088FA3846407868
+:2034400030F001000FD1BD4F05A91022384625F01BF928B905A83946102225F01BFF02E088
+:2034600005A823F003FC6220102105AA26F0C6FD28B926B16220102105AA26F0C5FD05A8B3
+:20348000294610221BF062FA304614F04DFE304622F086F8304615F0BFF81EB128460121C8
+:2034A00022F070FD242019F0D5FB0028206400F0A481E06A216B221D1DF0F8F915490968CD
+:2034C000D1F84C138847216C201D0860E06A216B04F108021DF0EAF910F05EFF216C04F11F
+:2034E00008004860E06A216B04F10C021DF0DEF904F1300904F12C08D24ED34F3070D9F855
+:203500000010D8F800C0266C2B4607F1100005E0DCFF002014010020D4DB002006F1080E0F
+:2035200034E0C04652616E646F6D5F736565644175746F6D617469632829206661696C65F7
+:203540006400C04641455343434D206F70656E206661696C656400C0414553454342206F0C
+:2035600070656E206661696C656400C054524E47206F70656E206661696C656400C046C06B
+:2035800004BF020040F823505B1CDBB2002BF9D07D61CEF80020604604F110021DF086F9C6
+:2035A000C54F654EB870308EB880C24831463D703C3126F0F1FD04F110033046216C90F8F4
+:2035C0002500CB60D9F80010787006F14C00F860D8F8000004F114021DF068F904F1180AD7
+:2035E000B649B84AB64E0870B74BBE60206C7A6204F11406D9F800100661D8F80000BB6282
+:2036000052461DF053F9B14EF071022286F824204FF6FE70B08325F00DFEAD48A54906F193
+:20362000140B0560584626F0B7FDAA48FF2138221BF08CF9A848AA4B8360AA4AC260A749D4
+:2036400041600570A84B0361A84A4261AA493961A74B8361A74AC261A84B7B61A84ABA6115
+:20366000AA48A84BA84AFB61AA491061A84FD16006F13000976015F067F909270BF12C00B0
+:203680007F1E40F8045BFBD1F07948F2010120F0CDFBF0794FF4004120F0C8FBF079212142
+:2036A00020F0C4FBF079222120F0C0FB206CD9F80010C0F814A0D8F8000004F11C021DF0FB
+:2036C000F5F8954E48F21501307020F0AFFB3078382120F0ABFB924F0222F760914B86F803
+:2036E00028208E483361216C70614FF6FE7704F11C0304F12002D8F800008B61D9F8001038
+:2037000037841DF0D3F8884AD580D5609570556101271574064615700648177148F202016A
+:203720004670304620F082FB48F20101304620F07DFB05E04CFF0020ACFE002028BC020096
+:20374000304648F2040120F071FB784E78483D49784B3061784A4B60084604F12003826023
+:20376000D9F80010226CD8F80000D36104F124021DF09CF8714B207071499870284626F088
+:20378000EFFB7049384626F0EBFB6F49042026F0E7FB6E49062026F0E3FB6D49072026F074
+:2037A000DFFB6C49082026F0DBFB98784FF6FE71491C20F03BFB68487949684B8862684A36
+:2037C0005A606848684A98600B46DA621846674A83F84670664F0263674BB760654A674FC0
+:2037E0001848674E1360674AC76003461F461E61206C7A6104F12406066213F080FF14F0C8
+:2038000067FD119826F06CFE11F0BCFD24F046FD64480068D0F8D40090F8430024F050FD2E
+:2038200060480068D0F8582429460120904726F0A1F855485B4F05707868C068007860B9C9
+:2038400004E0C0469C0301204819002038460068D0F8582428460146904719F093FE4C4F52
+:203860003D704A48058145818581C581058245828582C58205832B464583464E8583072150
+:203880000360464A43604448357024F0ADF919F055F921F0A3FE22F062F8434840780228C5
+:2038A00004D14FF40040012117F0EAFA13B0BDE8F08FC046E0000120AC000120DC040120E7
+:2038C00065490100F1AB0100859B020034FD00209CFF00206C010020FC0201207DA40000A1
+:2038E000A98802004D0A02007B67020081800200C9600200A9850200058E010001770100ED
+:203900003980020009C3000034040120D5650100D9DE0100E95B0100E80001207D5A0200AD
+:20392000E5730200897C0200F00C012020040120619902005B9F0000DD390200281A002054
+:20394000A19A0200659A0200799A02008D9A0200B5960200CD960200B5350200DC0201204E
+:20396000D94902002D2F020085530200C543020057490200F0FA0020D5410200FD8101009E
+:20398000311A0200AD420200061401208C110120FF130120FE130120EC0000205DA202007E
+:2039A0004CFF002014010020ACFE00202DE9F04FCA4CCB4DDFF838B3DFF838930F46380C1D
+:2039C000ADF11C0D80F05782DFF81883780880F0FD81C64EB80880F0C181B80980F0AA8115
+:2039E000DFF804A3F80B80F04E81BB480668780980F02981380928BF87F0080080F05A8307
+:203A0000780A80F0BA80F80880F0AD802069F90980F09080380A63D2B80A5CD2C44C380B18
+:203A20002BD2F80A27D3142019F014F9061C1FD00025A846207A012813D10096042029464F
+:203A40004246142321F0F6FE58B92068306060682946142233467060042022F0F3FD84F821
+:203A600008806D1C0C34032DE4DB304621F094F887F480601EE300201CE3182019F0EAF855
+:203A8000061C25D000252434A846207A012813D10096062029464246182321F0CBFE58B924
+:203AA0002068306160682946182233467061062022F0C8FD84F808806D1C0C34032DE4DB79
+:203AC0003046414618221AF041FF304621F064F887F40060EEE219F0ADFF87F40070E9E26C
+:203AE0001CF04CFF2078052818D1E07904211EF017FCE07904211DF011FA062025F04EFC07
+:203B0000287800F00700022801D026F083F824F0A7F819F08FFF23F04FFC01E024F0A0F84D
+:203B2000012023F0F9FC0320012104F06BFD87F08000BFE2A0B117F089FB206906682069C7
+:203B400021F02AF826615EB1F28802E0F088801AF0803668002EF9D1E079402126F0FBFA63
+:203B600087F04000A6E2FF20032122F00BFA26F0A9F9C34901200860FEE7424692F84A001E
+:203B8000082818BF04285BD124322120742126F03BFABC4D6868298800241BE0A30003EB15
+:203BA000C403C65C36F07F0212D016F07F06C654034405D101A8FF210C221AF0C7FE01AB5F
+:203BC000012021460C2222F03DFD284629884068641CA4B2A142E1DCB94C4FF0FF085546C0
+:203BE0000026E06995F8211080291FD169798DF809102A798DF808206B88ADF806302888B1
+:203C0000ADF8040085F82180297D8DF80C10EA798DF80B20AB798DF80A30A8690490314684
+:203C2000102201AB032022F00DFDE069761C2435332ED7DB00B180470020022122F0A2F9B8
+:203C400087F4807036E24EB17168087818B1486800781BF0D7FD3668002EF5D126F026F9F2
+:203C60001C34208025F0E6FA484608300078012806D1444620784FF40061642226F06BFA5A
+:203C800087F0100016E20120022123F035FFC4B294B3E00018F0DEFF5FEA00082ED0834680
+:203CA0004FF00109554633262879012818BF02280DD18DF804906888ADF8100001A81FF0A8
+:203CC0000DF920B102A9584626F066FA8346761E05F12405E8D111E02405012034FD00208D
+:203CE000E4120120E4FA0020E40D0020C0FE0020E0120120ACFE00204FF00008B8F1000FE4
+:203D000012D074B10F204FF6FC768DF80C001F25ADF8046001A922464346B148009516F0A9
+:203D200043F8404620F038FF87F48040C2E1C04664FE0020207A50B92078062802D10720B2
+:203D400025F02CFB3078012801D124F03DFDE07910211DF027FF87F02000ABE1207A00BB01
+:203D60002178E07908291AD124F004FF092025F015FBB9480078052806D0072809D1072024
+:203D8000012104F03FFC04E0012023F0F5FF1CF0F5FD3078012816D124F016FD13E01021C5
+:203DA0000FE026F077F8EF2803DB002023F0E4FF09E026F06FF81030C0B226F07DF8E07988
+:203DC00001211DF0EFFE87F0020073E1012025F0E5FA5D466678287900F00701122001296F
+:203DE00018BF02293DD1E6B1032E1AD0012E38D1012936D10A2025F0D1FA444620784FF429
+:203E000080611EF08DFA502005A923F065FFBDF81400A4F84800BDF81400002120F0E2FB13
+:203E200026E025F0B7FE002818BF032E15D1022025F0B4FAA149E06809781FF0C7F8A97914
+:203E400009090ED270B99E4A5178491CC9B20429517004BF9B49E16003E026F012F913F0D9
+:203E60001FFA28B1E07901214FF47A7226F073F987F001001EE1DFF854924FF0000A10E1B6
+:203E80007C052043300501204146934823780E784278701E00F0E280401E13D0183800F04A
+:203EA000FA80B93800F0F3802A3840F0EC8086480168002900F0F28040468847EEE0C0464B
+:203EC000FC020120012A18BF022A40F0E78099F820004E46072818BF082805D1227A1AB93E
+:203EE000012104F08FFB2378032B7BD00A2B11D0042B14D00D2B12D00E2B10D00C2B0ED09D
+:203F0000002B00F0CB8023F057FAE07910211DF049FEC3E0287800F00700012862D0237AC7
+:203F200060785BBB84F80BA05046307120F038FBE0B120780D2819D00E2817D0062025F053
+:203F40002DFA9BF806000BF10406000904D34FF40040012116F094FF307800F007000228B4
+:203F600001D025F057FE23F027FA97E0052025F015FA42F2107024F017FC8FE0012819D1B5
+:203F8000E07A401CC0B20428E07204DB5048007801280DD00EE04F4800884FF6FF71814201
+:203FA00006D003206070012666710423A37201E084F801A022F032FF22F0A0F80BF1060011
+:203FC0000078000903D34448007D012866D16078032863D10820012116F052FF5EE0C04605
+:203FE00098FD0020237A002B33D1E07910211DF0D9FD20F0D5FA28B320780A2808D12978D5
+:2040000001F00701022903D032490822891C0A7003280CD123F0D0F996F82000022806D152
+:20402000012023F079FA0220012104F0EBFA062025F0B4F9287800F0070002282ED025F000
+:20404000E9FD2BE0052025F0A9F9012020F0E4FE24E05046FAE7C0466CFF0020022B1DD159
+:20406000012A18BF022A19D125F08CFF10B116F0AFF898B125F0BCFF00280CBF5046012057
+:2040800021F006FB0AE040461CF026F906E0404616F05AFD02E0404610F0A8FA404624F006
+:2040A00003FBE0791DF050FD5FEA00087FF4ECAE87F4004007B0BDE8F08FC0468DFF0020A9
+:2040C00094FF002000F8FF07F40001204CFF0020AD0001202CFB0020ACFE00202DE9F04F7B
+:2040E000B54CDFF8D8C294F8207088465FEAD800ADF1140D80F092825FEA184006D3DFF8AF
+:2041000004B34FF6FF7AAAF1010A59E1604600785FEA5831A0F1020080F03181B84DA91DDA
+:2041200009885FEA182280F0EA805FEA980180F0D1805FEA183028BF88F4006080F0558352
+:204140005FEAD81080F0A280E7685FEA98305DD2A0695FEAD83138BF0020C0F04683A74932
+:2041600028C96A4628C209881180676938B9384625F0E4FAA061C0B997B90B2011E0017BFE
+:20418000FF2906D031F07F000FD101F07C0104290BDBE06940B9384625F0D0FAA06120B9A7
+:2041A000002025F08FFD2EE0A06160784FF4804143F2C82225F0CFFF94F82010A06908295B
+:2041C00019D00188ADF80010017A8DF80810017B491CC9B231F07F07017306D10188427A0D
+:2041E000684624F011FBA06909E0008800210A4622F088F8F7E7017B41F04001017340698B
+:2042000025F09CFAE06188F48040EEE2DFF8C0B200264FF0030AB14687B96078012E04D0D9
+:204220004FF400511EF07CF805E04FF400514FF47A7225F090FF88F40050D6E27D68287813
+:2042400010B3F02820DC51464A466B461FF084FCD0B1029803889BB984F83E908DF80DA0AA
+:204260008DF80C9003AB0A204946524620F042FADBF8001084F83E9031B12878884703E071
+:2042800001880126491E01803F68C5E71FF05EFE07462078BFB1401EC0B22070A0B16078EA
+:2042A0004FF4804120F058FC30B9606925F046FA10B938781DF06EFA6078402143F6982275
+:2042C00025F049FF207810B90B2025F0FBFC88F040008AE2B0F1FF3F18BF00280CD168465C
+:2042E000002108221AF032FB684617F0DDF918B1607802211DF056FC88F0020075E208466F
+:2043000000211FF0DBFD28460678FF24C6B14FF6FF75001D00212B4610F8142F52080BD324
+:20432000C7884FB1BB4207D055B10289BF1ABAB29542C4BF0C1C151C761E01F10101EBD18D
+:20434000FF2C19D02E49A00000EB0410401818300189C088401A80B250B929484470FF20E8
+:2043600009F030FCFF2120460A4620F0E5F900202349C88024F078FA88F0800035E2B0F14A
+:20438000FF3F18BF002814D13846401E0CD0801E0FD194F8220002280BD1012084F8220052
+:2043A000002020F039FD04E094F82110002021F00DFC88F4805018E24CFF0020ADFE002040
+:2043C00060781DF0C1FB051C08BF88F4004000F00C822F78D32F00F0098194F82000B84251
+:2043E00012D00A2F40F0168194F83F002871A16A002900F00F81A81C88470BE1A8B60200E4
+:20440000F00C0120E4FA0020B94840787F1E00F09680BF1E40F0FE80012818BF022840F040
+:20442000F980AF787FB37F1E40F0F4806F7860781FB325F03BFD4FF6FE720021824218BF1A
+:204440000121081C04D15846408F1146814209D010465F46ADF8100004A9A7F83AA0532098
+:2044600021F0DAF822F0DAFC21F048FE5946002081F84A0019F0E6FBCCE0022140F6B832BF
+:2044800084F82210A7E06878002854D125F0B0FD00210E4603460BF1080063621F460160AB
+:2044A000002F44D1002B38D0002E1F4635D0B146C64824F056F801280CD08D48408E4FF699
+:2044C000FF7181420CD03988884209D01BE0C046E0020120BD4807F10C0124F089FD90B180
+:2044E000BBF83E003989884201D1824501D1FB784BB19BF836007979884209D17C48B97910
+:20450000807B884204D0384621F030FF761EF6B2BF69B9F10109CBD1636A226B002AA9D093
+:20452000184631469047206B002873D1A2E7BF69761CF6B2B4E7002021F0AAF86AE001280C
+:2045400018BF022866D16F7894F845003FB194F84410491CC9B2884284F8441043DB94F877
+:204560002100401E04D0401E3AD0401E1ED051E025F010FB98B994F8460020B1E06A00287D
+:2045800048D0804746E0002102200F468DF808000246ADF80070684624F02EFC13E0012094
+:2045A00025F0F6FC014604F02DF833E0AB2000216A461EF0D9FFCDF808D004208DF80C00AD
+:2045C00002A812F0E9F960784FF480511DF0A8FE607841F288324FF4805125F0BCFD19E00E
+:2045E00021F0D8FA16E001200021DCE7E88948F20101401A0BD0401E05D0801E0AD12846E1
+:2046000019F0DEFA06E0284616F09EF802E0284618F0BCF9284624F047F8D1E66178381C17
+:2046200009D0401E00F0DB80C01E00F0D180801E00F0C080D7E094F83F00C10880F09F8031
+:2046400081087AD20009C0F0CE80062084F8200025F098FC00286CD01FF078FC2569071C7B
+:2046600067D068684078800837D33878032100226B461FF071FA28B968684078410831D213
+:204680000E201BE002980188B52912DAB421018060784FF47A724FF4005125F05CFD544809
+:2046A000416829B10078FF2814BF3878FF208847256968684078400803D2092025F002FBF9
+:2046C0000AE0092003228DF80C0003AB00218DF80D200A2020F00EF82569686840784108F1
+:2046E000C0F0818043490E6826B9800821D37AE0ACFE002038781DF04DF8002600B1012688
+:204700000325301C02D00E2025F0DCFA0C2020706078402143F6982225F01DFD0A208DF874
+:204720000D5003AB00212A468DF80C001FF0E2FF59E00E2025F0C6FA55E0042294F84000F9
+:2047400084F8202040084ED394F84270002F3FD160460078012818BF022844D1012504F13F
+:2047600020000021E5701AF0F1F8032084F8200028461FF0C7FB284624F0CFFC33E004F15D
+:204780002000052594F84010057089080FD394F8421061B90121E170042200211AF0D6F881
+:2047A00084F8205000201FF0ADFB0220E4E72846002111E0002084F83E0084F820003222FF
+:2047C0000846042125F0C7FC0DE0C04648FD002024F03CFB0420012103F014FF03E001209B
+:2047E000014621F0F3F988F0040005B0BDE8F08FDC020120000301202DE9F04FBE48C84C8E
+:20480000ADF1340D06902569406801214FF0E047C06809934FF000080170C24808921F40E6
+:2048200080F800804FF0020000EA020008BF002840F0E682DFF8F092DFF8F0A21E4611464F
+:204840004FF4803018EA060700EA010008BF002833D141464FF4003011EA060700EA02008A
+:2048600008BF00280ED137464FF48000394000EA020008BF002800F0B78285F804801CF0A0
+:20488000B5F9B1E285F80480EB2021F00BFE4A46514682F800800878862801D121F084FEFD
+:2048A00025F094FCE1690A6882F804800968E16125F016FE24F08EFB96E285F8048021F096
+:2048C00059FE81262778A4F80C809949A770994D0860994B2E70FF221A702169069E087AEF
+:2048E000801E81B230684A46D0F8000182F80080C0890B918842C0F26B82E16908310968BA
+:2049000004F1180001600426A6810B98657EA17E04F11902C01E80B2069EE37E0B9005EB83
+:2049200001205178C1F301193168608101F1B80CDCF80010237109780792002908BFB9F163
+:20494000020F00F04582B9F1020F00F3418219B110F0070F00F03C82667800F00705AD1EEB
+:20496000022D08BF002E00F0338231B151460978862902D1002D40F02B82001300F00200E3
+:20498000022864DA35435AD1DCF81C0090F88300022851D0E1690C31097805A80170052774
+:2049A000A78125F013FC554606462878862840D106980068403001680F6837B9D0F80C0546
+:2049C000804706980068006C07689DF9140025F041FC787706980068016C096881F81E8049
+:2049E000006C9DF914100068C177304625F078FD2679678925F0EAFB51460A7807F0100741
+:204A0000862A15D1BA4D05F11E031A88521C1A8087220A7025F064FDE879B04206D11FB99D
+:204A2000404618F001FB07E01B20FAE7E920F8E70646304625F054FD24F0CCFACAE15146BD
+:204A40000878862803D121F0AFFDA77866788FB186B9012F00F0BC816089022F03D110F0D0
+:204A6000070F40F0B581032F05D100F00701032901D0ADE16089010980F0AA81011301F09C
+:204A80000201022902DA810A80F0A28107994978C1F3810BBBF1010F4FEAA1110A9100F01B
+:204AA0009781012900F09481B9F1020F14DA00F00701012918BF03290ED1BBF1000F0BD16B
+:204AC0000A9F002F00F0848106990968AC3109680F78002F00F07C81BC49B9F1020F0DD06B
+:204AE0000A9E11F80B708A5DB918CFB25EB3C10929D3BF1E12E0C046140100200A460A997D
+:204B00000BEB0207891809793A795218C109D7B214D20A995BEA010615D0BF1CFFB212E0CB
+:204B20006811012010050120071401200A140120E813012005140120250001200A995BEAA6
+:204B4000010608BF02270B9AC0F30021781A61718242C0F23D81069E1046C01B4018316887
+:204B600080B2D1F850122081743080B2884700286678606100F02C814146742219F0E6FE24
+:204B800084F8038062891EB9C14902F020000870BF4861790678C446002E30D000292ED101
+:204BA00002F00700032808D0012828D106980068D0F8D40090F882600EB30698406840691B
+:204BC00006781EB124F022FEFE2815D006980068D0F84C02804750B906980068D0F8440249
+:204BE000804720B96289617994F803C007E00420E0706289617901E00420E07084466569F4
+:204C0000268905F1740305F17400AB65079B686093F801A02E812089CAF301190029A5F873
+:204C20005C001878AA8100F0780049EA00004CEA000028744FF0FF06AE730CBF20794046A1
+:204C400085F83AB085F849000A9885F83000A089002FA0EB010086B2A68100F0B480E16927
+:204C6000E78068463A468919083116F03FFFBF19B8B2A0812846017C4FEAAA0212F0030F39
+:204C800002F003076D4601F0400B42D0B9F1020F434601D1C9090BD29DF801209DF80010F7
+:204CA00001EB0221A0F844100DF10205A0F84210814EB0F84410B6F846208A4203D04FF647
+:204CC000FF728A4223D1032F14D06A78297801EB022189B24186B6F84420AD1C01208A4231
+:204CE00014D04FF6FF728A4218BF181C0EE0C0464C02012060692946323025F04DFA606921
+:204D00003B363146323024F073F908350346002B56D00798407886111ED06169B9F1020F91
+:204D200003D0087CC00903D309E05BEA070306D16A782878AD1C00EB0220A1F84200032E0A
+:204D400005D068782A7802EB00220A8504E060692946283025F020FA06990968AC310A685C
+:204D60006089167886B1B9F1020F0DDA00F00702012A18BF032A0BD162692FB94F4BB2F8E8
+:204D800042201B8893421BD100F00702032A05D0012A18D1886A90F88200A0B1D1F89C117B
+:204DA0006069884778B9079881786769407884F80380C1F3011100F078000843387402E004
+:204DC0001BF014FF06E00DF077FE03E0A8C3020024F0F2F825F0FAF9E1690A6882F804804D
+:204DE0000968E16125F07CFB0899099E202047460840374008BF002830D024F0A5F82DE0F3
+:204E00002F4991F90000002803DD91F90000401E08702C4991F90000002803DD91F9000097
+:204E2000401E0870114640461E464FF080770840374008BF00280DD0234991F9000000287C
+:204E400003DD91F90000401E087020480121017024F004FB85F804801BF0C8FEDFF864C037
+:204E60009CF90070B7B108994FF0E0470220374000EA010008BF002816D09CF900000028A8
+:204E800012DC06980068D0F84C0580470CE0C046071401200E48069F80F800803868D0F8B5
+:204EA000582441460846904706984068C06880F800800DB0BDE8F08FDCFF00202200012045
+:204EC000130501201205012014050120110501200E050120964A2DE9F04FADF13C0D00247C
+:204EE0000A918E2309900121101D01708046D47240215171502593712046D0730021D17159
+:204F0000DFF830B21172A02191729089917340F430509081204611681074C44CC24855726B
+:204F2000084084F832304CF21011014300200C909BF80000116058B90C981DF053FF94F848
+:204F40003200000910D30C9808A98DF8200008E094F83200000907D301200DF121018DF8EA
+:204F60002100522020F058FB12F0C9FB24F022FADFF8E4A20B90002840F0C78011F082FD2E
+:204F800000280B9040F0B6800C9804F1240674210D903246212025F031F8002857D10D9906
+:204FA00021207422334624F017FD00284FD1608F4FF6FE7181424AD001200D9094F84A001D
+:204FC000082806D0042804D011F07EFB0C980D903DE0DDF8349042200DF122018DF82290A0
+:204FE00020F01AFB06F12F01432020F015FB06F12C01472020F010FB06F11C014A2020F0AE
+:205000000BFB06F11A014B2020F006FB06F12401284620F001FB06F11601532020F0FCFADF
+:2050200006F12D01542020F0F7FA06F11801E12020F0F2FA94F83200000938BFDDF8309076
+:2050400052200DF122018DF8229020F0E5FA0C9D18E00B9151E00C9AA80000EBC5002946BC
+:205060000C23814609EB07000090012020F0E2FB30B917F80900FF2804BF002007F809008E
+:205080006D1CADB2BAF80000DAF80470A842E2DC10F034FF8A48001D006800B1804720F076
+:2050A000C3FF0D98F0B124F001FFABF81C0028B998F8000000F0F80088F80000C548401CD3
+:2050C0000078022818BF012003D1002184F84A1003208BF8010039360BF11400314625F0B9
+:2050E0005BF801E009200B900B9F74480021002F4180AED0012771480B9794F83C108146A1
+:2051000001208840CBF80C0079E011F0BBFC11F0DBFA04F124022120742124F075FF02A8CD
+:20512000FF210C2219F012FC0C9D56460CE0C046E012012034FD0020294601200C2202AB04
+:2051400021F080FA6D1CADB23088A842F4DC02A8FF21102219F0FAFB0C9D03202946102203
+:2051600002AB21F06FFA6D1C332DF6DB5448006800B1804722F0C4FD002006220C99ADF86D
+:20518000100002A819F0E2FB142017F063FD061C1BD0B1480C300768A7B103270225A8B220
+:2051A00002A90622801924F075F8AD1D7F1EF6D104A93046022224F06DF84C2014213246FB
+:2051C00024F022FF30461FF0E7FC182017F042FD071C10D00C9D1822294619F0B7FB06207E
+:2051E000294618223B4621F02DFA6D1C032DF6DB38461FF0D1FC19F0D3FC304881460B98AF
+:20520000954D01286AD1734E737804F124072BB3012B0DD0022B13D198F8000000F0F8000C
+:2052200040F002000AE0C0460000FFFFE4FA002098F8000000F0F80040F0010088F8000027
+:20524000864823F08EF9002808BF00200DD0042103208BF80A1008E03005012098F8001037
+:2052600001F0F80188F8001002208BF8010024F008FF0999B36B00F07F000818CBF80C30A5
+:205280006430022180B20C90FF2020F07BFE01201AF024FD4FF6FE706087461CE087002012
+:2052A000A4F8486020F044FF0A9801280AD002A80021082219F04AFB02A804E04804012074
+:2052C0001003012000201FF047FD212074213A4624F09AFE0020022120F054FEE8680B9C89
+:2052E00080B9122017F0B6FC0646002EEE606DD04FF6FE70B61F0327411C26F8060F7F1EA6
+:205300007180FAD1002C61D106AB4C200021022224F062FB002852D1BDF8180000284ED042
+:2053200004284CDA182017F095FC03274FF0020800244FF6FE7A0646EB681FFA88F14C205A
+:2053400006221B1924F048FB78BBE868015B8A452BD056B3009620184188002218230620CE
+:2053600020F068FA3069EA6800F2E93333611019418805F13402880000EBC100E968135028
+:20538000081973694188880000EBC1008018E96843600819418818223346062021F052F968
+:2053A00030460021182219F0D1FA7F1E04F1060408F10608C0D116B130461FF0EDFB054B90
+:2053C0007120002108224C3324F006FB24F0E2FB30B101E0ACFE00200120A8700027EF7021
+:2053E0001F48C9F80C001F48C9F8100022F048FB1E481D490860DBF8100050B10BF11004C4
+:20540000076820681FF0C8FB38460028CBF81000F6D109984FF6FF71814217D0012000273B
+:205420008BF800000BF1090201468BF80970852024F0E4FD0BF1090428B9852039460122D4
+:20544000234624F0C9FA0C9823F09EFC22F03CFE0B980FB0BDE8F08F54FE0020E000012076
+:2054600095170100659C020084020120C19F01002DE9F04F0746C44C97F824000026ADF14B
+:20548000840D0128ADF83C6006D197F828102078012902D148B9B2E2207830B9387D0228E9
+:2054A00000F0AD82032800F0AA826078CB4D01280ED1C94821790078884209D097F8380001
+:2054C000E32840F09C8223F05DFF012800F08D824FF4FA60F860E86924F0A3FC40B9E86999
+:2054E000F96824F009FE05F1980024F091FE02E0F9680818F86097F8250002288DF83000B1
+:2055000003D008B9F86A0D9005E00DA807F11801082224F0C3F80CA80DF13E010FAA1AF0A0
+:2055200015FC58B913A807F13401042224F0B6F8BDF83C000DF13E011DF078FF2078012806
+:2055400000F0BB80002840F05A82397D31F0010018BF042940F0538268463146242224F08C
+:205560009DFE384669460BF0CBF997F81780BDF8000010F0070F06D000F0070002280CBFF1
+:2055800014270B2700E00F279DF81900C01987B2384624F081FE5FEA000900F03082044679
+:2055A0006946022224F07AF8BDF80000A41C10F0070F18D000F00700022823D102200DF1EA
+:2055C000080A8DF82400082251460AA824F066F820460822514624F061F89DF810000834B6
+:2055E00004F8010B0EE00DF1040A8DF824600AA80422514624F052F820460422514624F09C
+:205600004DF8241D05A92046042224F047F89DF81800241D04F8010B9DF8190004F8010BCB
+:205620009DF8190068B10799002900F0E8810246204624F033F89DF819002418079824F0F7
+:205640006BFD08A92046022224F028F89DF8220004F8020FB14CE068FFB248B90C2024F078
+:205660001BFEE06000B186604770C0F8049015E0E4680834206820B100F1080420680028B4
+:20568000FAD10C2024F008FE206038B183680BB1866020684770C0F804902068011C00F0E3
+:2056A000AE8181F8008009A808F078FDA869322124F022FD05F174009FE197F83800E32851
+:2056C00005D1206918B18047002800F0988197F83800E2280DD0E3280BD0E02809D0E1282C
+:2056E00007D097F82800012803D0387D032840F08681BDF83C0000280CBFB0460DF13E08EB
+:2057000031462822684624F0C9FD0AA83146032224F0C4FD97F838C0DFF8E8B2BCF1E30F86
+:2057200023D097F8250010F0070F16D000F0070002281AD102A807F11801082223F0AEFF15
+:2057400097F830009DF8283097F838C08DF8100003F0F80040F0020005E0F86A9DF8283030
+:20576000019003F0F8008DF82800BCF1E30F0DD097F829109DF82800C90000F0F70001F05E
+:205780000801014306E0C046200401209DF8281041F008018DF8281097F826309DF8292004
+:2057A0009DF82800190102F0EF0200F0CF0001F03001022B42F0200241EA00018DF82920D3
+:2057C0009DF82A208DF8281002F0F8008DF82A0006DA8BB116E0C04620FB002048190020C0
+:2057E00097F8273043B1012B0CD19DF8290000F0FC0040F0040003E09DF8290000F0F8005F
+:205800008DF82900387D032807D1FB6B9DF82900099340F008008DF829009DF829009DF829
+:20582000282097F84030800100F4006100F4F860084302F030019DF82820014302F0080076
+:205840009DF82820084302F007017A6B8DF818C0084305923043ADF8000023B18DF8193048
+:2058600007F141000790BBF83A00ADF8200097F91500082805DC10F16D0FB8BF6FF06C0031
+:2058800000E00820BB7D6E3040B2002B4FEA60000CBF311C022197F8179040EA81108DF8C3
+:2058A0002200BDF8000010F0070F06D000F0070102290CBF14270B2700E00F27800A06D252
+:2058C0009DF81800E22808BF8DF8196001E03F1DBFB29DF819003F18BFB2384624F0DCFCBE
+:2058E0005FEA000A00F08B8006466946022223F0D5FEBDF80000B61C10F0070F10D000F0E8
+:205900000700022812D102A93046082223F0C6FE9DF81000083606F8010B07E070040120E8
+:2059200001A93046042223F0B9FE361D05A93046042223F0B3FE9DF81800361D06F8010BEC
+:205940009DF8190006F8010B9DF8190060B10799002954D00246304623F0A0FE9DF81900C6
+:205960003618079824F0D8FB08A93046022223F095FE9DF8220006F8020FBDF80000800A5D
+:2059800004D3701C09A9042223F088FE85F85B70F220BBF84870E378C5F85CA0A9F10C06AE
+:2059A00085F85500E188A5F85670002B85F85A6006BF0F204FF6FD71022085F85400B8F1A4
+:2059C000000FA5F84C100AD098F80100800906D305F1580008F10B0123F08CFA66E60CA806
+:2059E00019F062FEA5F8580060E624F0B3FA286AC82124F081FB05F1BC0024F009FC21B09B
+:205A0000BDE8F08FE4FA00202DE9F04FC748C84A0178CD481170CD4D4170CD495C306861A9
+:205A2000ADF12C0D086005F0E9FECE49C948CB4EDFF82CB3091D0A91C74982468946E7E025
+:205A4000480AC0F09980C8489BF800400078012868D024F0A9FA011C00F08A808A7B96F80E
+:205A6000248086F82420778F8A7B08698BF800208A898B7B72870122009200220192012202
+:205A8000029200220392049342780592406800232122069001200790F2200AF009FC8BF8E3
+:205AA0000040C84986F824800F200870DAF80800778750B3AB490C681434276857B102693F
+:205AC0003969914205D007F114042768002FF7D100E097B9DAF80C707FB1786824F01CFB2D
+:205AE0000021DAF80C000A9F4160386824F014FB0020CAF80C00DAF8080024F00DFB002096
+:205B0000CAF808002068CAF80800D9F8181024F04BFA68B30846322124F0EEFAC34824F040
+:205B200077FB25E0B9F85810778F7187C24999F85A008BF8000096F8248086F82400012366
+:205B400000930022019202930392049099F85B000590D9F85C0004232122069001200790D9
+:205B6000F2200AF0A5FB8BF8004086F824807787296921F480712961D9F80C008A0A3AD3F6
+:205B8000071C34D0C468F968A1421FD839468F6800B3D0F80880814210D00246434601E0A9
+:205BA0001A469368B3B1AAB19942F9D198689060184624F0B1FAD9F80C000BE0B4480068ED
+:205BC00024F0AAFA4046C9F80C0003E0F968091BF960BF68002FD5D14CB1D9F81C1030B122
+:205BE0000846214624F088FAAA4824F011FB296921F400712961C80A05D31DF0C9FE296996
+:205C000021F480612961080924BF21F008012961E8684FF0FF3124F05BFC0028F8D02878B2
+:205C20001BF092FF041C00F0418121782878923900F09C80333961D0491F7BD0491E70D0EF
+:205C4000173904D0491E68D0891E61D091E094F84000443080B224F01FFB071C00F089807C
+:205C600004F10408381D0C22414623F017FD20693861207D387594F915007875A07DB875AD
+:205C8000E07D0A2208F11401F87507F1180023F005FD608C788494F8240087F8250094F813
+:205CA000250087F8260094F8260087F8270094F8270087F8280094F8280087F82900E06AC2
+:205CC000F86294F8300087F83000606B786394F8380087F83800E06BF86394F8402004F157
+:205CE000410107F1410087F8402023F0D7FC3846FFF7BEFB384624F00FFA3AE020790028C1
+:205D000037D10A208DF8200008A823F00BFE30E0A188A01D12F07EFE2BE0201D20F08EFB8B
+:205D200027E0CD21002203230AE0C046D4DB00200D140120002108AA08238DF82010C12190
+:205D40001BF07CFA15E0C046C8E800207CFB0020F8FD00207004012048190020E4FA002037
+:205D6000AC0001207804012020040120201D15F0D9F820784FF00108712825DC712851D02D
+:205D8000652810DC652868D0801F77D0423800F0838018386FD0401E6AD0401E01287BD970
+:205DA000801E5DD070E0663854D0801E4ED0801E032871D9001F45D0401E3FD0401E37D031
+:205DC00062E0C0468003012091280FDC912863D07238022860D9C01E20D0401E1AD0401EC6
+:205DE0005AD0C01E58D0801E56D04DE092380DD0C01E012850D9303806284DD91B384BD081
+:205E0000801E012848D9093846D03DE0E76A002F42D035E0A768002F3ED031E06769002F23
+:205E20003AD02DE0E768002F36D029E0BC190020E768002F30D023E094190020E768002FFD
+:205E40002AD01DE0E768002F26D019E0E768002F22D015E0E768FFB112E0E768E7B10FE0B2
+:205E60002746786908B11EF097FEFF69A7B107E067698FB104E0676977B101E0A7685FB1E5
+:205E800038461EF089FE07E04FF0000807E0C04654190020E0190020204622F005FCB8F10C
+:205EA000010F03D014B1204622F0FEFB29698808FFF4C6AD08A80021082218F047FD08A84A
+:205EC00015F0F2FB23F0D4FF4FF4FA674FF47A71B1FBF0F081B207FB01F024F0F5FAFF2044
+:205EE000032120F04FF823F0EDFF024901200860FEE7C0467C0520432DE9FC47D44C0F46B7
+:205F00000646F80B80F00C826078B90F80F0AC81B90880F09F81DFF84C83F90A80F002810A
+:205F2000390B80F0CC80380907D2F80FC0F02E8227F080471AF09AF928E224F047F9814640
+:205F400022F0F2FB002800F0B480082023F0F6FF002840F0AE80802023F0F0FF002840F046
+:205F6000A880684615F0DEFF012803D10098002800F09F8094F84102002840F09A80002537
+:205F80000126E8B223F092FC48B1837A3BB1867290F9090006FA00F0C0B220F04BF96D1CF4
+:205FA000032DEED3032084F8240004F5CE7024F005F9484624F094FAC34800252A460168AB
+:205FC000056050F8081CD44940F8085C04F1600022F0FAFA40460068006B8047A168401A59
+:205FE000010BE06AC1F1FF3282422CBF08444FF0FF30E06294F8300020B12069E16AB1EBC0
+:20600000C02F25D922F0A0FB294600B13146081C1BD0C24840F6090101804580417B06F0FE
+:206020000F0221F00F010A434273017B05F00F0321F00F0143EA010202732946416023F0C0
+:20604000F9FD418811F4406FFBD084F83060E5621DF0F0FDD14829460560022022F08EF80E
+:20606000022020F02BFD112013F038FA207818B96068503024F0C0F8C948007810B90E2063
+:2060800013F02CFA94F8310020B184F83150052020F014FDC348A06284F82450B4F9B400A8
+:2060A000B4F9B610884214BF0220072017F03EFC02E0484624F014FA27F008073AE720B19C
+:2060C000042020F0FBFC0020607065681FF0BAFC38B128462D6A6FF4807100224FF00073FD
+:2060E000A847E06858B140460068006B8047E2686168801AC860000BC8600026E660AA49D9
+:2061000004F16000002222F05FFA0221D4F8A00084F8241018B104F1E00024F075F827F424
+:20612000006707E724F052F8064622F0FDFAD4F898100028894600F08480002900F08180DE
+:206140009A49042504F16000002284F8245022F03BFA304624F0C4F904F5CE7024F02EF8CD
+:2061600040460068006B8047E0604FF0010884F80180284620F0BAFCD9F810006060D9F8D4
+:206180001000816AC90803D3436A29460022984740461BF06FFA606880F81980606813F0A2
+:2061A00079FB6568D5F808A040F60A02D01F564600F1010C00E01E46736833B119888A42EE
+:2061C00003D0884218BF8C45F5D100217160727B08F00F0322F00F0213437373D9F80C206F
+:2061E0001288904224D06046904221D02B8F03B3E96305F13802518095F8440001F00F0345
+:2062000020F00F00034385F8443095F8450008F00F0320F00F00034385F845307260707B38
+:2062200001F00F0520F00F0045EA0001717300E0E160504623F0FEFC5146404621F09EFF97
+:2062400002E0304624F04CF927F480679EE0C04630F500200CF086FBD4F8A00008B927F001
+:20626000020793E08C010010514A116841F08001116020B1042020F021FC0020607023F0A9
+:20628000A5FF80464B480068016804208847216A81421BD1357ECDB1A568BDB1D4F8A85093
+:2062A0006DB1E968098840F60300884204D0E9680988401C884202D106F1140001E006F149
+:2062C00010001EF0A9FC06E01410044040F6C411316171612062404624F002F91FF0B2FB6B
+:2062E00080B1356A30466FF4807100224FF00073A847D4F89800002808BF47F0020701D0DD
+:2063000019F0B4FFF569002130464FF080630A46A84727F0005739E0011C0200F41201209E
+:2063200023F054FFD4F8B06066B306F1280106C90A234FF0E0450B40154008BF002B21D1FE
+:2063400006F1280191E8000306F1280595E8060006F1280322EA090221EA080183E806003C
+:2063600024F0BEF8B16879B1B9F1000F08BFB8F1000F09D03069B6F93010B5684B46424641
+:20638000A84701E024F0ACF827F4804727B104F1E000394623F038FFBDE8FC870000046091
+:2063A00052C30200B9670100F95D010009870200CC210840E00100102DE9F04F4FF0FF08FB
+:2063C0004146ADF14C0D0E910F914FF0000910914E46089609960A96AD4C0B9604F1300BDC
+:2063E0000C96E0680D96494611919EE0E068710306AA042323F040FE119903AA304622F09E
+:20640000FFFB02AA3046012122F0FAFB3046022101AA22F0F5FB069800F0FF0028709DF837
+:206420001900069F6870C7F30140E8709DF80E30AB702878FF2834D0BDF80C70FE2830D063
+:206440004FF6FF70B8422AD107A81EF0F5FFE06871034FF088524FF4005323F00DFEBA4857
+:206460004FF4005750F8041D3F1FBFB2B1F1FF3F07F1885201D1032FF4D810684FF0010A06
+:20648000514600F0FF03FF2B18BF8A46491C000A0529F6DB1060079822F0E4FE5744EF8027
+:2064A00001E01020E8809DF80A00BDF8087028719DF806302F81BDF804206B7129786A8142
+:2064C000E068FF292AD0FE2922D07E291AD07C2912D078290BD0702904D00D99491CC9B2B2
+:2064E0000D9120E00C99491CC9B20C911BE00B99491CC9B20B9116E00A990F96491CC9B2A3
+:206500000A9110E009990E96491CC9B209910AE00899B046491CC9B2089104E009F1010750
+:2065200010965FFA87F9761CF6B2E578B54200F323810D9F002F38D10898022835DA0C9856
+:20654000022832DA099802282FDA4D452BD00C98C0B90898A0B90B980A99084325D021F0F7
+:206560001BFB854219DCB9F1000F14D094F83200FE2120F043FAE5780120DDF8408015E07A
+:20658000012013E0089860B9B9F1000F07D121F003FB854201DC062008E0032006E00220B1
+:2065A000EBE7022002E0119800E004200028A07000F0CC80401E49D0401E00F0AA80401E97
+:2065C00006D0401E00F09880801E00F094800EE121F0E2FA05460C2084F83C5015FB00B0C2
+:2065E000817E84F83D10C07E84F83E0010F0C0FAE2782D1895FBF2F050432D1AE8B284F820
+:206600003200401C90FBF2F15143401A84F831007C201FF0FBF9FF2810D17E201FF0F6F9A0
+:20662000FF280BD1FF201FF0F1F9FF2806D178201FF0ECF9FF2808BF94F8310084F833005B
+:206640000C2110FB01B0808BE0868FE00F9F08F1010090FBF5F184F832806943FF2FA0EBC5
+:206660000100C1B284F8311014D10E98FF2804D10C200E9111FB00B004E00146880000EB3D
+:20668000C100584484F83310808BE086AFE0C0465CFC00203A46D0B2910084F8330001EB32
+:2066A000C2015944898B1729E18640F2A080C91F01AA89B215F046F89DF80F00C0083FD3DE
+:2066C000119F0097BDF81220E18E94F833000323891AC91F01AA89B20CF09AF8002840F0E1
+:2066E0008680BDF81010002900F081809DF814001CF0ACFF7BE0FEE7119EB54226DD3046E6
+:2067000012F08CFE6178E578761CF6B201436170F3E708F1010084F8328090FBF5F1694349
+:20672000401A84F831005FFA88F012F077FE6070FE215FFA88F020F061F9012084F835000E
+:20674000119802F041FD52E00020001111986D1E84F831000C2184F8325010FB01B184F8B8
+:206760003300898BE1867E2120F048F994F83200FE2120F043F93AE00C2116FB01B506AA94
+:206780000423710323F078FC1199304603AA22F037FA304602AA012122F032FA30460221AC
+:2067A00001AA22F02DFA0699163501F0FF0201F0FF00FF2A09D0FE2A07D07E2A05D07C2A05
+:2067C00003D0782A18BF702A0AD1119F47B9C1F38542032A04D19622B2EB116F3FF41EAEF7
+:2067E000304612F01BFE002860703FF4FFAD13B0BDE8F08F2DE9F04FADF1840D1B91CB4906
+:206800001C923CC9064610A83CC00EC980E80E0000248DF84240317F8DF84340B28D8DF8D1
+:206820004D40D6F828C0ADF844400F46ADF85A20F2898DF854706046ADF84A20027802F093
+:206840000303022B8DF8402000F3C38123461D93401C1F9353083CD202F00C0EBEF10C0F83
+:206860000CD053093CBF10F8013B8DF84230BEF1080F04BF01238DF84C3001D08DF84C401A
+:20688000BEF10C0F0AD0737903F00303012B0CD142F00C0273898DF8402004E04578037829
+:2068A000801C03EB0523ADF84430530911D245780378801C03EB0523ADF846300378457891
+:2068C000801C03EB0523ADF8483010F8013B8DF8433010F8013B32F07F058DF855301ED0CB
+:2068E000037833F003058DF8413040F06E8103F0030EBEF1030F00F0688113F0030F00F139
+:2069000001000ED010F8013B02F00305022D8DF8573004BF10F8013B8DF8583001E08DF8A5
+:2069200041401490A0EB0C003F1AFFB2B942C0F24C81C91B8DF85470C8B28DF84D00074354
+:2069400000F04781D00907D370891EF0C5F8002840F03F819DF8402002F00C002146001F77
+:2069600008BF01211E91910933D301211F9180B3B28923F09BFA904202D1F08D000A0ED2EB
+:2069800023F094FA904222D0F08D01460B0A38BF101C07D39DF8402002F0030C2EE07089BF
+:2069A000ADF85A20804623F081FABDF85A10884205D040461BF072FF002800F00A81864833
+:2069C000026810A940469047002840F002819DF84020F08D02F0030C01460B0A0ED2D309D1
+:2069E0000CD39DF8413013F0030F07D102F00C030C2B03D0082B1CBF01231D93DFF8E081A0
+:206A0000BCF1020F00F0C280BCF1010F00F0908012F0030F40F0DD80704A92F82F20012A6A
+:206A200003D1B779002F00F0D4809DF8542002231A92040A9DF84250BDF846B0BDF848A088
+:206A40009DF855E09DF857C0DDF850908DF86430B2899DF84370ADF85C2034D21E9F404605
+:206A60001A30046897B91D9F1FB1104610A915F0DCFD1F9800901C9F0197B07C1B9A02908A
+:206A8000F37C17A910A813F043FAA2E0307C002C8DF8560000F09D8023F008FABDF85C2047
+:206AA000904240F0968030791F9F00901C9D01971B9A02951D9B039196F8300010A90490D3
+:206AC00017A8A04785E0ADF830008DF820308DF8227034798DF833407189ADF818108DF8F9
+:206AE00035E08DF82350ADF826B0ADF828A0CDF82C90307C8DF836C0B27C8DF8320096F886
+:206B000030308DF83420354C8DF83730B4F8481096F83270ADF824101A998DF8387006A834
+:206B2000ADF82A1006F052FE53E0C04620C102001D9FB58937B1000A04D2284610A915F026
+:206B400074FDB5899DF85400B6791030C0B221F0C4FC071C3DD07D81022038703E737C7056
+:206B60009DF854203A7207F110057D609DF84000800928BF01247C721499786822F08AFBFA
+:206B80004046007839461CF087FD22E09DF8417040462230B189036817F0030F10D110A871
+:206BA00007901048ADF8181006A920F01FF980B1062141730068407B21461DF0C3FA08E0FA
+:206BC0003BB110A82246984703E08DF84D408DF8544021B0BDE8F08F80020120E4FA002026
+:206BE000AE000120CB3402002DE9F04FD24CDFF84C93DFF84C83080CADF1140D019180F021
+:206C0000D4810846400838BF0020C0F0D881676823F06AFC054623F02BF94FF47A764FF627
+:206C2000FF726843B0FBF6F081B267B13B887888CB1A9BB2984210DDC01A8242C8BF82B247
+:206C4000FF68002FF2D14FF6FF70904200F095802078012123F07FFA8FE0B87902287FD0F1
+:206C600023F042FC054623F003F997F838204946684301F10A03B0FBF6F03880187890429E
+:206C800066DD97F83600FF2808D197F83800401C87F8380097F8370087F8360097F8356073
+:206CA00097F839300020012101E0401CC0B283420FDD97F8365001FA00F285F0FF052A4253
+:206CC000F3D03618814097F83600F6B2014387F8361097F83400B98F10FB06F2891A89B280
+:206CE0008842C7BFFF2087F83600011C97F8360099F82420FF2818BF97F83A0006D1404695
+:206D00000078642510FB02F212FB05F0788046B9388D3E7A40F020003885386C87F82E603F
+:206D20000BE03A8D4FF6DF70104038853D6C87F82E6097F8342012FB06507862F879CEB239
+:206D400087F82D0007F110007E8406F03FFD10E0B87E97F82A10FA8BE9231EF0C7FE05E013
+:206D6000387CFF2802D0B86921F09EFC38461FF0E5FD207801211AF015FF019880F0010049
+:206D80001DE12878012840F00D8195F8338095F813A06F6995F831006988022220F01AFA1F
+:206DA00005F11C0405F1020B06460020002E02907BD1687F400876D3A87FCDF80CA022F020
+:206DC00071FFBA4605F11009071C60D01C2015F041FF061C59D000211C2217F0B7FDA87FD4
+:206DE000694621F09CFB9DF8010002213075304620F01EFE6888317DB08095F83100FF228F
+:206E0000F07102FA01F0707478680078307495F83000B07495F8331011FB00F0303080B205
+:206E200021F05BFB0746B76127B930461FF086FD00262AE01A20387000237B701A467A8024
+:206E4000E0885946B880B81D21F0FEFCE0783C4BF87303F1200000883882608BB885608962
+:206E60007882A0783875207B787599F80000B87599F80100F87599F902003876039A7A763F
+:206E8000C7F81CA007F13001B962304600E000200028064600F08680274886F80880007866
+:206EA00001211AF07FFE002E7CD0307AA8EB0000B0F1FF3F04BF01200290307CFF285CD01E
+:206EC0006078400828BF4FF00008317DF07C4018404503DCF074FF2088407074B069B17C19
+:206EE000227D806A08FB0100216922F0D3F9029F317D727C012398FBF1F04843A8EB0000AA
+:206F000003FA00F11143C9B27174DFB1401CFF2202FA00F001437174B769B17C207D08FBC0
+:206F20000100B884707CFF280CD1307CB1691CF0B3FBFF20307420E0DC040120ACFE002016
+:206F40000CFB002023F0D0FA074622F091FF1D4B1D4A4FF47A717843B0FBF1F0308093F8BF
+:206F6000241010781F4610FB01F1B87A6423401C10FB01F010FB03F07080F17C327DA8EB45
+:206F80000100801AB0F1FF3F04D0707CFF2801D0029F3FB1E175707C2076BBF8000021463C
+:206FA00015F043FB284621F07FFB084800781AF0CBFD051C7FF4E5AE019880F4004005B0D2
+:206FC000BDE8F08FACFE00200CFB0020DC0401202DE9F04FB74D20F03100ADF1340D0B9087
+:206FE00095F83F00002840F06781687804211DF0B3FD002840F060810B99AF7895F83F00F3
+:2070000001F03F01012F40EA010085F83F00014600F03B810120A87022F0CCF9012805D126
+:20702000562020F081FB08B123F049F8B34C00202071E06808B121F017FFB148476800239E
+:20704000A24680467FB10C247868007821F0FAFF061C05D0327C1AB10020824200F31E81DA
+:207060003F68002FF0D1184620F09AFE002859D1D8F80470002F55D07868007821F0E2FF3F
+:20708000061C4CD0337C002B49D04FF0000844E074690C2018FB00F94C44E079C00838D383
+:2070A000786800788DF814002088ADF81600A088ADF81800079A089B069905981DF0CCFE40
+:2070C000B0B90DF1240B00210422584617F03EFC74694FF6FF700090CDF804B00A23029398
+:2070E00002460392CDF810B034F809104C440AE002681189D388009102F10A00019002935C
+:207100000391049021887868A288007817F0AAF8337C08F101005FFA80F84345B8DC3F6836
+:20712000002FA9D19AF80200DAF80C20162410FB04F081B2562022F061FF0AF10C060A2881
+:207140002BD0092825D021F08FFE562020F0ECFAB0FBF4F0C7B2384620F022FE01281CD039
+:20716000336814FB07F082B20021562022F034FC8AF802700DE041680468CAF814101DF078
+:207180000BFD9AF81000401E8AF8100020461DF003FDDAF814000028EDD108F0EBFE21F024
+:2071A00063FE05F142035520002101221E4622F013FC3078002866D052480078012818BFDD
+:2071C000022843D1504804680021204621F08BFF00283BD122F0DEFC002837D120460AA9E2
+:2071E00005AA17F035FB04469DF82400FD282DD002282BD0032C4FF0000715DA05A83946CF
+:20720000142217F0A3FBFF202146142205AB8DF8240004201FF016FA3C49A00000EBC40067
+:207220000F5009184F604F7285F8427055200121324622F0E9FEFF2003211EF0A3FE687855
+:2072400085F8207004211AF0ADFC54E095F83F000B99072440F0100001F03F0185F820402C
+:20726000014385F83F1000200146FDF733FE10B912F0F4FD3FE0002020F04EF90021204699
+:2072800001F0C0F937E095F83F106878002904BF072485F82040F1D00027D1E7716910FBF8
+:2072A0000411C979C90824BF5B1CDBB2401CC0B2D3E6C0464CFF002095F82100D8B995F8FB
+:2072C000427095F83F1087B10B9880080DD348090BD221F0BBFD0420012101F093F90B9880
+:2072E00095F83F1080F002000B900B9800F03F00084385F83F000DB0BDE8F08FF00C0120CE
+:2073000020050120ADFE0020B800012064FE00202DE9F0430D460146ADF19C0D04A822F019
+:2073200038FF0026304615A920F04EF937460A2800F08681C44C0D2824D1280922D33046E9
+:2073400004A91CF073F820460DF11B01022221F001FC78B90DF147012046022221F0FAFB50
+:2073600040B90DF14B012046022221F0F3FB002800F066810C2022F08FFF002800F060817D
+:20738000044651E1304604A91AF034FA10B9761C052EC7DBAD4E280980F093800DF14701F1
+:2073A00003A8022222F07AF9BDF80C009DF88A50ADF80E00680808D30DF18B000DF10E01B5
+:2073C000022221F0C7FB012827D09DF88A0080082FD30DF18F040DF10E010222204621F0B4
+:2073E000B9FB01280CD09DF88A00042240F001008DF88A000DF18B00214622F04FF95BE0CA
+:207400009DF88A00FF21042200F0FD008DF88A000DF18F0022F042FF4EE09DF88A00FF21BE
+:20742000042200F0FE008DF88A000DF18B0022F035FF0A36304601686C460DF132054368A9
+:2074400021600DF17606018963600A2221813046294621F07FFBC8B90DF1800829460A2204
+:20746000404621F077FB70B9684631460A2221F071FB012820D1684641460A2221F06AFB1B
+:20748000012816D018E020A80A22B5E70DF1760620AD0A223046294622F000F969460A2217
+:2074A000284622F0FBF868460A22314621F052FB10B115A821F003FB384615A91BF0B6FF21
+:2074C000BEE09DF81000C00918D29DF81100400851D304A815A919F079F8002800F0B08078
+:2074E000C5F341110020022908BF01209DF8551001F0FE0108438DF855003CE03046016845
+:2075000043686E460DF176083160018973600A2231816846414621F01DFBB8B90DF13209BC
+:2075200040460A22494621F015FBB0B90DF1800868460A22414621F00DFB28B9404649468A
+:207540000A2221F007FB7BE020A801E00DF176000DF132010A2222F0A1F8C5F34110002142
+:20756000032808BF01219DF8540000F0BF0040EA81108DF854009DF81100800906D30DF1C5
+:207580005F000DF11B01022222F088F89DF81100C00913D39DF855000DF11D01012240F00E
+:2075A00040008DF855000DF1610022F077F80DF166000DF12201102222F070F89DF81000FB
+:2075C000800904D315A9087840F0200008700DF162000DF11E01042222F060F89DF84F0054
+:2075E0009DF850608DF8930015A98DF8946038461BF01CFF20460DF15F01022221F0AAFAB6
+:2076000068B90DF18B012046022221F0A3FA30B90DF18F012046022221F09CFA80B10C2082
+:2076200022F03AFE041C0BD000210C2222F036FE0120A072204622F07FF9204622F06CFD6C
+:2076400027B0BDE8F083C0461EFB002052C002002DE9F04FAF4CDFF8C082DFF8C0B2ADF198
+:20766000340DA0780591090C6ED20598400824BF059880F0010080F081810598800805D381
+:207680000120059FE07087F0020077E10598000938BF0020C0F0728158463230E76A0078DB
+:2076A0000026B146000922D222F01EFF054622F0DFFB236B4FF47A7142466843B0FBF1FCC3
+:2076C00092F82610928EACEB0300824238D8B0FBF2F39BB29942ACBFDDB20D1CB0FBF2F1F3
+:2076E0005143401A80B2ACEB0000206300E00125EFB1C846F878A8420ADD401BC0B2F87026
+:2077000040B109F101061FFA86F93E467F680CE087F803807868002E82460CBFC4F82CA05D
+:20772000706038461DF038FA5746002FE2D1A078B9F1000F04D10021216308211AF0F0FDD2
+:20774000059880F0080019E11AF0FEF9071C00F01281B87FC0B9788CE56A132815D1B7F8A0
+:207760000290281C11D000260188894508D14568002E0CBFE56275601DF00EFA284601E0D6
+:20778000064640680028EFD1E56AB87A97F831102E46022855D1788866B1DFF8E8C13288A7
+:2077A000904204D1B2789CF80030914247D07668002EF4D181468A464646002D08BF002042
+:2077C00004D0012015B16B68002B34D1F18E814237DD082015F03EFA96F82610002830D044
+:2077E000A0F8009080F802A0C17000234360E36A83B9E0629BF83200000911D222F074FE50
+:20780000054622F035FB4FF47A716843B0FBF1F0206300E06860584690F83200000910D307
+:20782000A07808211DF098F958B9A078B28E082122F08EFC05E0401C1D4680B2C2E7F37059
+:2078400096E0514805683878012806D0022840F08F80384618F032FC8AE007F11004B81C96
+:20786000BE8908943B7E0690FA7C07967969099397F819B00A923C7F0B9107F11C0604F0EC
+:207880000C000C280DD0B87F4FF0FE09FF2804D022F008FA041C10D16AE0002D68D06C68BB
+:2078A0000FE0B088FE211EF03DF98146B9F1FE0F5ED022F0F7F9041C5AD0207821F0B8FAEB
+:2078C00005464FF6FF7A0BE0207821F0B1FA054606E0B078FF284BD12D68002D48D06C6816
+:2078E000002C45D0AB68AAF1010823B9A3680BB1B3F8028007E021780220984718B1B0F8CE
+:2079000000801DF049F93389227898450AD03AB943B11CE0AC000120ACFE0020E4FA002013
+:207920009A4514D196F80280B27008980090099B01930A9902910B9A0392CDF810B0079B52
+:20794000069A3046214613F0F7F986F80280307800F00C000C28BCD1B08849461EF0E2F8A3
+:207960008146B9F1FE0F03D022F09CF9041CABD1384620F099FE059880F400400DB0BDE89B
+:20798000F08FC046D2FE0020240501202DE9F04F0E46074630687C68BD68ADF1140D0028AA
+:2079A0003AD022F013FCD4F8E81081460120019008294FF0000088BF0198B168084202D1D9
+:2079C0007168084205D0019880F00100C0B201281DD1D4F8C000B8B9C4F8C060C4F8C46063
+:2079E0000020C4F8D0000146C4F8D41094F8FC30C4F8D810002BC4F8DC100CBF019805203C
+:207A0000D4F8C410087410E094F8F80030B903203074484622F064FD002050E1D4F8C40044
+:207A20004661C4F8C46006233374D4F8C4000021416194F8FC00012808D1022194F8FB0068
+:207A400084F8FC104FF4E0211FF0F0FB706810F0704F06D128B104201FF048F806201FF071
+:207A600045F802201FF042F894F8F800DFF85482002840F0B480E86B3168884240F2AF808A
+:207A800094F8FC00002840F0AA8094F8F90028B1D4F8EC00B0F1FF3F40F0A180484622F0F6
+:207AA0001FFDB768AA463FB1D4F8E800B94609282CBF0220019802E004F1F409002077684E
+:207AC000039037B1D4F8E80009282CBF0220019802E004F1F60700200290DAF80010D6F86A
+:207AE00000B048685FEA0B0540F0020048604ED04046A0F11008D4F8E800ABF1010B092819
+:207B000020D3019803460DE0D8F800108A68398890470346002003B10198031C02D00298F8
+:207B20006D1E3F18DAF800000DB1012BECD0D8F80010C9680A4669469047BDF80000A9F8AE
+:207B400000001FE0019803460DE0D8F800108A68397890470346002003B10198031C02D056
+:207B600002986D1E3F18DAF800000DB1012BECD0D8F80010C9680A46694690479DF8000095
+:207B800089F800000398BBF1000F8144B3D17768DAF80010D4F8F030CA680020134218BF9A
+:207BA0000198102B18BF80F001000028F4D117F0704F06D12FB106201EF080FF04201EF05A
+:207BC0007DFF02201EF07AFFD4F8C010002008740746C4F8C4703E46C4F8C0606EE0D4F891
+:207BE000D800002843D1D4F8DC00002842D1287922F0EEFA4646D4F8CC00326829694068FB
+:207C00005268006891FAA1F1B1FA81F1134602229847D4F8CC0032686969406852680068DE
+:207C200091FAA1F1B1FA81F1134602229847287922F0C8FA287922F0CDFA204629460CF0EE
+:207C400013FB0021D4F8C000C4F8E0100068B0F5806F03D9204629460CF006FB94F8FE0089
+:207C600060B92968486840F00200486006E0D4F8DC0018B9204629460CF0F6FA296848696E
+:207C800040F001004861484622F02AFC94F8F800A0B9D4F8EC1004F16C05284621F037FF84
+:207CA00060B1D4F8C00003210174384609F0E4F92846002121F02BFF00200190019805B071
+:207CC000BDE8F08FD40100102DE9F04FC54CDFF80893207888465FEA1841ADF1140D39D2F1
+:207CE000BE4D281D00685FEA58011AD25FEA980028BF88F0020080F06B8164885FEA181043
+:207D00000DD36846FF21082216F020FE20466946002201231DF0CEFE88F0080058E100205A
+:207D200056E10830002113F0E1FA4C46206818B120F0BAFC002020606868806A1CF02CFF9B
+:207D4000686800248462686820F0AEFC88F001006C603DE119F0F8FE061C00F03781012072
+:207D600037780390F7B996F802A00025AB4617E0A80000EB090759F80000807C82450DD13F
+:207D800005208DF803A061688DF8020009B168468847386820F088FCC7F800B06D1CEDB244
+:207DA000002DE5D03078012850D17068017801F00202022A4ADAC1F38302032A46D1CF11FC
+:207DC00009D0407800F0070101293FD002293DDC30F07F003AD13089273080B220F07DFB29
+:207DE0002578071C32D00020787002233B70F06B06F132010A22786007F1120021F04AFA01
+:207E000007F1080006F128010A2221F043FAB6F84400F883B6F84200B88396F8460087F8DD
+:207E2000210096F9480087F8200096F8490087F822007168328907F1240021F02BFA307AA3
+:207E4000394687F8230028461BF026FC3078022803D1304602F050FC307808287ED1F0787D
+:207E600021F01EF8071C79D0B078002873D02578401E11D0401E3AD0401E4ED106F11C0107
+:207E8000384606F035FE01282AD038461DF004F8002087F8290061E006F11C01384606F000
+:207EA00027FE01281CD097F84100F02853DA97F8260000280CBF0398002097F84050387544
+:207EC00097F8410007F1420187F83800681EC2B207F1410087F8402021F0DCF9257818E053
+:207EE00003203875207839461BF0D6FB36E0042097F8413097F84020387507F1420187F82F
+:207F00003830501EC2B207F1410087F8402021F0C1F9284639461BF0BFFB97F82900E8B131
+:207F200097F825008DF8000097F82500002804BFF86A019005D001A807F11801082221F0AC
+:207F4000A9F926481321016097F830100023684603F0F4F902E038461CF09EFF307805281E
+:207F600004D1304608F012FF0390307804281BD1E068A8B196F84000443014F06BFEE568BD
+:207F8000071C0DD096F840203146443221F082F900201349B860384621F0CCF83046A8472E
+:207FA00030461CF079FF30786168062803D111B1304688473078072803D1216909B13046E8
+:207FC0008847039810B1304620F06EFB88F4004005B0BDE8F08FC0465819002048050120ED
+:207FE000541900209C0301202DE9F04FBF4CDFF80083207889465FEA1941ADF11C0D3FD298
+:208000005FEA590111D32079211D88F83C00E1201DF002FB20F0C6FE0020A8F894000120F2
+:208020001AF0DEFA89F001005CE1E7885FEA990116D25FEA191038BF0020C0F0538194F8D4
+:20804000310050B1E06A94F8301021F032F820B994F83100401E84F8310089F0080041E159
+:20806000002F04BF0020A07007D07F1EB9B24EF66022E180022122F06EF889F0020031E1B0
+:2080800019F062FD071C00F02B81C346387894F83120A178313800F00B81401E00F0BC809B
+:2080A000A13840F01481FE89383E0FD047F6DD70361A40F00C81B8690678002E40F007812A
+:2080C0004078C009C0F0038178885CE089490EC904A880E80E00D7F818A00421504620F092
+:2080E000B2FC3D4606460AF1040010F8011B049606298DF8141010DBFE2918BFFF290FD17D
+:208100000278FF298DF816200AD1401C4278007800EB0220ADF8180002E000788DF81500DB
+:2081200006295ADBFE2931D0FF2912D0287B002840F0CD8068882084002600963346019304
+:208140003246029231460391687C802114F046F9BDE09DF816509BF89600A84205DB002D88
+:2081600040F0B580FF2840F0B28028461DF0E0FF3EB1DBF84C00864203D0CBF84C6020F08F
+:2081800011FEBDF8180020F01BFEA0E09DF8165098F89600A84205DB002D40F09880FF28D3
+:2081A00040F0958028461DF0C3FF002001218140314202D1401C1B28F8DB98F83C108842DC
+:2081C00000F08580207198F82B00642110FB01F20121207821F0BFFF79E02B7B002B76D1E1
+:2081E0009DF815A0BAF1000F71D0BAF1060F6EDA304620F05EFF002869D1AAF10106687C67
+:208200008DF815606B88607004A923840EC904F12C0585E80E005AE0FF2A12D000201AF066
+:20822000DFF90246002000906078B8F894103B4615F0D5FE94F83100002848D0082132226F
+:20824000C7E798F83C007A6801213B46814011420EBF00213844017A5D680020012282405C
+:20826000154203D0C218127A8A4204DB401C1B28F4DB002018D0B8F892002084102600969B
+:2082800021896289002015F0AAFE0120E070A07840B93C20E080207802214EF6602221F0AC
+:2082A0005AFFA078401CA070002084F831000EE004290CDA10480178104820F0FAFE30B9F9
+:2082C00078882081FF2684F83160B8886081384620F0EAF9207819F037FC071C7FF4D6AE4B
+:2082E00089F4004007B0BDE8F08FC046E8000120E4FA002088C2020036FB002000F8FF073E
+:208300002DE9F04FADF1440D0B908069007800210DF12A020F909C2011F020F8B54D681CD8
+:20832000007830F0010009D1002004211FF0E4FB5FFA80FA9DF82A00504402E001204FF02F
+:20834000000A8DF82A000F989DF82A10884280F2DE809DF82A000F99401AC0B20D9002285A
+:20836000C4BF02200D901A2110FB01F000B214F071FC0E90002800F0CD800F980D9F0E9C61
+:208380000C90002F08BF002074D04FF00008B946012645460C9882450ADC0F9940468A45A1
+:2083A00004DAA1EB0A01C9B20C9163E00C9561E0411CC9B20C911FF0B3FB071C54D08E48BC
+:2083C0000146B0F848005D312080A01C21F0E4FE388860820223E375FF222276B87A6076A9
+:2083E0008DF81C503888ADF81E0007A816F0E8FAAB46012808BFB34604F10A00BBF1000FDE
+:2084000006D104F10A00FF21082216F09FFA02E008A921F0C1FE3B797BB93F88002F04BF99
+:208420002575281C04D07448267590F85C00401E207602206075A57515E06F4890F85C00BA
+:20844000401C20763879032804DB26753879032805D106E0022020753879012801D06675FF
+:2084600000E06575A6751A34B9F1010908F1010890D140460D9981424CDD0D9DDFF878B100
+:2084800004F1020804F10A0702264FF0000A4FF001091A3C2D1A0C9987206A4610F05EFF27
+:2084A0005749BDF80A0024F81A0F404621F074FE0DF10201384621F06FFEBDF800004D4BC5
+:2084C0006082587830F0010003D16675A675FF2006E084F8159084F816A09BF85C00401E5A
+:2084E0002076E675638A9DF81200002B60760CBF84F814A084F814900C9808F11A081A37CB
+:208500006D1E00F10100C0B20C90C4D102E000200E900D900B98417C0D9F0E9D8DF82B1087
+:20852000801C16210B9017FB01F0001DC0B28346401C14F08FFB5FEA000854D008F1010415
+:208540000020A2468AF800009DF82A000F9F88F802000D9E88F8037088F8046096B30D9F2B
+:208560002E46241D06F102090A362046494621F013FE08343146204621F00EFE0446A87C49
+:2085800004F8010B688A001204F8010B287D2070697D40EA8100C0B22070A97D40EA01109E
+:2085A00004F8010BE87D04F8010B287E04F8010B687E09F11A091A367F1E05F11A0504F897
+:2085C000010BD2D10D4D0B990DF12B0048F231025B462C1DC4F800A018F0A0FA40461CF0DE
+:2085E000DBFA09346C600E9808B11CF0D5FA11B0BDE8F08FACFE0020E4FA002098FD002001
+:2086000041FB0020FEB5BC4CBC4A0D46014694F83E705078491E00F02C81491E00F00981BC
+:20862000491E00F0C980B64B491E00F0A780491E6AD0491E1FD0491E40F03A810026012D7E
+:208640008DF8016004D0022084F83E0007460DE016F06AFA0D2084F83E00607884F8206025
+:208660000421C82221F077FD94F83E7094F83F0000F0EF0045E003208DF801000FB90120CB
+:2086800020722078002840F035816278606921F055F8002840F02E8110464FF480411CF034
+:2086A0005BFA002840F026810025A561E5611EF049FF60784FF4804119F032FE267A94F85E
+:2086C0003E702EB10B2F03D1284684F83E002F46257294F820106078062906D094F8230083
+:2086E000062808BF84F8235007E084F820500421322221F030FD94F83E7094F83F0000F017
+:20870000F70084F83F00D3E00221012D8DF8011016D0082130F0010084F83E1021D194F895
+:208720004200F0B9002552200DF105018DF805501CF072FF21F0F4F918F08CFB28460EE073
+:208740000025184684F83E50008850863232832021F05AFC032128461DF014FC072020F0DA
+:208760001DFE002084F8200060780421322221F0F2FC94F83F0000F0FB0077E001208DF81F
+:20878000010065B100201F8884F83E00022157863232832021F038FC072020F0FFFD0020A2
+:2087A00084F8200060780421322221F0D4FC94F83F0000F0FD0059E0012818BF022877D188
+:2087C00060780421322221F0C6FC94F83F10606A012D23D00222002084F83E2005468DF8C1
+:2087E000040021F0020184F82050012284F83F1052208DF8012001A91CF00EFF21F090F912
+:2088000018F028FB284620F0C9FD606A00284DD01DF0ACFD606A0028FAD147E001210028F6
+:2088200084F8201066D01DF0A1FD606A0028FAD1FEBD002021F0C6F8042601208DF8016013
+:20884000D0733DB1002084F83E0084F83F00072020F0A4FD002084F820006078314632221B
+:2088600021F079FC94F83F0000F0FE0084F83F001CE0012818BF02281AD1012D23D00120AB
+:2088800007278DF801004FF48051607884F83E7019F046FD00201EF03FFE002084F83F007C
+:2088A0006078022141F2883221F055FC94F83E70A66AFEB18DF800700A20002103226B465F
+:2088C0001BF018FFFEBD002003211DF05BFB04213222607884F8201021F03DFC0820002184
+:2088E00012F0CEFA002084F8210060784FF4805119F016FDFEBDC0464CFF0020ACFE0020F3
+:208900002CFB0020F0B50E467068ADF1140D002800F06381002771687770B24C087858B116
+:20892000487800280CBF381C01202246012110730C32632021F068FB71680D7965B1487997
+:20894000224600280CBF381C0120012150730D326D2021F059FB71688D79ADB90D7ACDB1E7
+:20896000088A10F0070F02D0CA68632A12D9C96820F00AF83846012112F082FA9A4A352039
+:20898000282121F041FB04E0C9794FF4005012F077FA71688D7C45B1888A22462E32022140
+:2089A0001080442021F030FB71688D7D45B1088B2246303202211080462021F025FB71682E
+:2089C0008D7E45B1888B2246323202211080832021F01AFB71688D7F45B1C87F2246921C03
+:2089E00001211070292021F00FFB716891F820504DB191F821002246D21C012110702B20B4
+:208A000021F002FB716891F822504DB191F8230022460A3201211070432021F0F5FA716848
+:208A200091F824504DB191F825002246521D012110702E2021F0E8FA716891F826504DB1FD
+:208A400091F827002246921D012110702F2021F0DBFA716891F828504DB191F82900224686
+:208A6000D21D01211070302021F0CEFA716891F82A504DB191F82B002246121D0121107075
+:208A80002C2021F0C1FA716891F82C50A5B191F82D20102A8DF8002003DD10208DF8000040
+:208AA0000246096B0DF1010020F0F4FB812011216A4621F0A9FA716891F8345055B191F850
+:208AC00035001028C8BF10208A6B0146622021F09BFA716891F83C5045B1086C22463832E4
+:208AE00004211060842021F08FFA716891F844504DB191F8450022460B32012110704B202F
+:208B000021F082FA716891F8465065B104F13C0547310822284620F0BDFB472008212A46AC
+:208B200021F072FA716891F84F5035B101F150020120082121F068FA716891F858504DB1C8
+:208B400091F859008DF811000DF1110152201CF063FD716891F85E5045B191F85F00234A54
+:208B600001211070332021F04FFA716891F85C5035B391F85D0004F1080501212A4628709E
+:208B8000322021F041FA3220394601222B4620F023FF04F1090333203946012220F01CFF7F
+:208BA0001348217A0078012904D04FF4006119F0B7FB04E04FF40061642221F0CCFA71682C
+:208BC00091F860705FB191F861000A4977680A4D087097F86100287001E00220707005B021
+:208BE0000120F0BDACFE002034FC0020B5FE0020E4FA0020291A002070FB0020F0B50E46D5
+:208C00007068ADF1140D002800F06581B068002800F061810025B24C7268757004F10C00CA
+:208C2000177803783FB1B06801210170284603B10846B16848707068637B877847B1B06889
+:208C400001210171284603B10846B16848717068C7785FB1284620F061FCB2680121800B75
+:208C6000917138BF291CB068C171706807794FB1B06801210172B0680C3020F04FFCB1689F
+:208C8000088270684779E18D37B1B068012280F82C20B068C18570688779218E37B1B06878
+:208CA000012280F83020B06841867068C779618E37B1B068012280F83420B068C1867068BD
+:208CC000077AA1783FB1B068012280F83820B06880F839107068477AE1783FB1B068012209
+:208CE00080F83A20B06880F83B107068877AA17A3FB1B068012280F83C20B06880F83D10F7
+:208D00007068C77A61793FB1B068012280F83E20B06880F83F107068077BA1793FB1B06804
+:208D2000012280F84020B06880F841107068477BE1793FB1B068012280F84220B06880F8CE
+:208D400043107068877B21793FB1B068012280F84420B06880F845107068C77B37B3B06844
+:208D6000012111226B4680F846102946812020F033FE9DF80000B16881F84700B26892F8BC
+:208D8000471089B113F066FFB1688864B268906C002808BF82F8475006D09DF800200DF136
+:208DA000010120F077FA00E095647068007C80B1102013F04FFFB1680865B168086D40B14C
+:208DC000012081F84C000B6D10226220294620F003FE7068A16B477C37B1B068012280F8BF
+:208DE0005420B06881657068877CE17A3FB1B068012280F85C20B06880F85D107068C77C94
+:208E000057B1B068012180F85E103649B06808225F3020F03FFA7068077D67B1B0680121E3
+:208E200080F8671020F006FA0146B0680822683020F030FA7068477D87B152200DF1110182
+:208E40001EF04AFF9DF81170B068012180F8701007B92946B06880F871107068877D3FB167
+:208E6000B068012180F87210B06880F873507068C77D237A57B1B06801212A4680F8741004
+:208E800003B10A46B06880F875207068077E617A3FB1B068012280F87620B06880F8771021
+:208EA0007068477E5FB1B06801210F4F80F87810387800B10D46B06880F879507068807E8A
+:208EC00058B1B068012180F87A101BF0CFF8B16881F87B0001E00220707005B00120F0BD08
+:208EE000ACFE002041FB0020291A0020F8B50D4606466868002800F06281002730466F7056
+:208F00001FF0DCFF041C13D11C2013F0A3FE041C00F0578139461C2215F018FD26712046C7
+:208F20001CF070FE20B920461BF036FED12047E1686807785FB1407820B9E1884FF6FE7014
+:208F4000084002E0E08840F00100E080686887785FB1C07820B9E1884FF6FD70084002E0B9
+:208F6000E08840F00200E080686807795FB1407920B9E1884FF6FB70084002E0E08840F02A
+:208F80000400E080686887795FB1C07920B9E1884FF6F770084002E0E08840F00800E0803C
+:208FA0006868077A5FB1407A20B9E1884FF6EF70084002E0E08840F01000E0806868877AAD
+:208FC0005FB1C07A20B9E1884FF6DF70084002E0E08840F02000E0806868077B5FB1407B12
+:208FE00020B9E1884FF6BF70084002E0E08840F04000E0806868877B57B1C07B002807BF56
+:20900000A06820F00100A06840F00100A0606868077C57B1407C002807BFA06820F00200DF
+:20902000A06840F00200A0606868877C57B1C07C002807BFA06820F00400A06840F0040099
+:20904000A0606868877D57B1C07D002807BFA06820F01000A06840F01000A0606868077E44
+:2090600057B1407E002807BFA06820F02000A06840F02000A0606868877E57B1C07E002869
+:2090800007BFA06820F04000A06840F04000A060686890F822705FB190F82300002807BFA7
+:2090A000A06820F48060A06840F48060A060686890F826705FB190F82700002807BFA068F5
+:2090C00020F40050A06840F40050A060686890F828705FB190F82900002807BFA06820F4E5
+:2090E0008040A06840F48040A060686890F82A705FB190F82B00002807BFA06820F40040B5
+:20910000A06840F40040A060686890F834705FB190F83500002807BFA06820F48010A06868
+:2091200040F48010A060686890F838705FB190F83900002807BFA06820F48000A06840F4D4
+:209140008000A060686890F83C705FB190F83D00002807BFA06820F08070A06840F0807098
+:20916000A060686890F83E705FB190F83F00002807BFA06820F00070A06840F00070A060F4
+:20918000686890F840705FB190F84100002807BFA06820F00060A06840F00060A060686820
+:2091A00090F842706FB190F84300002807BFA06820F08050A06840F08050A06001E00220A9
+:2091C00068700120F8BD70472DE9F04FB04E4FF0000A8146ADF1140D57467069CDF808A025
+:2091E000CDF80CA010B1804700B90B27F078002F40F09B8096F8314096F832700146B9F189
+:20920000000FA1F101011FFA81F818BF012155464FF0F80B86F83F1022E0AF421ED0F0683D
+:2092200069036A46042320F027FF009911F4403F1CBF0AF101005FFA80FA01F0FF017C2958
+:2092400018BF782909D1284606215A461FF0E6FC0C2015FB006080F848B0F0786D1CEDB2FA
+:20926000A842DADC401E504503D196F8350000285BD0B8F1000F06F1300500F0CF800398B3
+:209280004FF4005B019096F83F30F06813B9012186F83F106A466103042320F0EDFEB9F1AF
+:2092A000000F05D00099F07811F4403F40F09B80009800F0FF00702803D0204670211DF004
+:2092C0009DFBF06879036A46042320F0D5FE009800F0FF00FE2803D03846FE211DF08EFBB5
+:2092E00038460621FE221FF099FCB800FE2300EBC700FF2186F83C70A200A6F840B04019A7
+:2093000086F83D4000F1180A8AF80030019B86F83E1002EBC4004019A6F84430808BA6F860
+:20932000420001F065FC102801D10020ADE0B9F1000F0CBF10214946B9F1000F07D0B6F860
+:209340004000C0F50050814207DC01200390B6F84000C0F50050814201DD782100E07C21C4
+:2093600038461DF04BFB0DF003FC96F83F300446A8EB04000621FC221FFA80F8181B86F8BB
+:209380003F0038461FF04AFCFC208AF80000029A96F83210F078091996F83E400C27891847
+:2093A00091FBF0F24243891AC9B286F83210491C91FBF0F24243891A86F8311014FB0751BB
+:2093C000898B102905D1611C91FBF0F24243891ACCB20198B9F1000F96F83270029019D0DC
+:2093E0000398B8B11AE096F83F30641C94FBF0F1A8F101024143A6F840B01FFA82F8581ECB
+:20940000641A029986F83F00E4B286F83D40481C80B20290B8F1000F7FF435AF7C201CF006
+:20942000F5FA00240746FF2F1CD17E201CF0EEFA0746FF2F16D196F831700C2017FB005000
+:20944000807DFF280AD0F27896F832008018401E90FBF2F15143401AC7B203E038467E2119
+:209460001DF0CCFA0C2086F8337017FB0050808BF08696F83200FE211DF0C0FAB6F8400055
+:2094800086F83540C0F5005000B205B0BDE8F08F5CFC00202DE9FE4FA84E00900578775D97
+:2094A000002FADF8047000F04681DFF894820D2D4FF0000B4ED0052D15D0072D08D00C2DC2
+:2094C0001AD14068C08A400A28BF4FF0010B13E08478002C08BF07F11B000BD0807D242121
+:2094E00010FB017006E08178012900F02481007CC0192430ADF80400BDF804001EF0EDFF4D
+:20950000041C1FD10C2D40F0168100984068002800F0118120F05AFE444607462068009BEF
+:20952000D0F85413181D8847BDF804001EF0D5FF041C04D1384620F0D3FFBDE8FE8F384658
+:2095400020F0CEFF072D21D0725D009920461FF0A1FE19E044462068D0F8282401A9532051
+:209560009047BDF804104FF6FE70884200F0DE80BDF80410401C884200F0D880009F3889E9
+:20958000002800F0D3803C46052D46D0072D55D1009908782070487860708878A070C878B3
+:2095A000E0700A7ACF798E79487900EB026000EB074000EB06206060A778E7B18F7D27721B
+:2095C00067B1896951B1BA0004F1100002EB47121FF060FE04F11000E06002E00020E06086
+:2095E00020720098806948B31BF0D6FA009800218161817522E01B222272896904F1100027
+:209600001FF048FE04F11000009FE060B8691BF0C3FA00980021816110E0616804F11806C1
+:20962000242230461FF036FE66606169227C06F124001FF02FFE606824306061DFF808A149
+:20964000DFF808910D2D0DD00C2D2CD1009840781A2828D0676837B3F88A400823D309F051
+:209660007CFB20E000994B681878C0F3830200F0020002284DDA33480078904249D15F7866
+:2096800037F03F0745D191F83000022841D109F064FB0098418E4FF6FF728A4203D1406895
+:2096A0008079022817DA50460078BBF1010F19BF4846007800212170214619F0EDFF0C2DA7
+:2096C00039D100984168002935D044462168D1F85413001D2EE0201C1FD054F80C7CAFB93C
+:2096E00010F8021CFF2911D14D46297800F8021C17480A2221461BF0AAFD01280DD12878A5
+:209700004FF4005118F04EFABDE8FE8F1EF0CCFF03E050460078032A02D04446206806E072
+:2097200001220A7019F0B8FFBDE8FE8F2068D0F8541368468847BDE8FE8FC04638C2020032
+:20974000140100201AFB00209C030120E4FA00203C0501202DE9F04F81460D462C20ADF126
+:20976000240D13F077FA071C00F0498120F09EFB698B884214BF012002203870697B2869CD
+:209780000026401A7860687B87F82660B8707C68B87887F827602418207800F00700787094
+:2097A0002078C0F3C100387420780421C0F3401A601C1FF048F94FF00508B861BAF1010F3B
+:2097C00087F81C8006D007F108003146082215F0BDF808E0397F07F10800091920F0DCFC93
+:2097E000387F08303877387C012805D1387F205CB875387F401C38772878DFF80CA200F0E1
+:209800000300012803D0504630300078804687F8018078781FF086FD7877397F28692C7DB2
+:2098200040182861397F7B7F601AC01AC0B22875F8704FF6FF74BC82B869B0F1FF3F32D0D2
+:20984000387C01281CD038B9062078823946484616F06AFC40B30CE0387C022802D00328FB
+:2098600007D01EE0062078823946484616F05CFCD0B104207882394648460BF005F913E0F0
+:209880009AF82F507E82B32075B99AF8651001290AD1B87D19F03AFCB882844218BF301C13
+:2098A00002D1A12000E0A32004463878022806D11FF0C0FC014607F1080020F06DFC002CBF
+:2098C00040F09980514D6878B046012818BF02281CD197F82600012803D097F82700012824
+:2098E00014D1B978F8784018397F4018001D13F0B1F95FEA000809D0B878FA783C7F796848
+:20990000121840461219121D1FF0C4FC38460BF04BFE04466878012818BF022865D1002CF6
+:2099200063D0B8F1000F66D040F203154FF0680A4FF0010900E05C4697F82600012803D08F
+:2099400097F82700012850D1B978FA783B7F786852184146D218121D1FF09CFC97F8260064
+:20996000A34630B997F8270040B1BD8287F8276003E0A7F814A087F826607E8238460BF075
+:2099800013FE041CD8D168463146142214F0DEFF7B8A8DF81190D3B9B88A682803D085428E
+:2099A00015D1FF2011E07868C17B0529C3D12A30FF211FF098FB0028BDD005A8082214F027
+:2099C000C5FF05A820F0EEF8FC208DF8100002A807A9324614F03CFF01469DF81C0020B195
+:2099E000042014226B461CF02DFEB8F1000F02D040461BF0D1F838461BF0CEF800E01024DE
+:209A0000204609B0BDE8F08FE4FA0020ACFE00202DE9F04305468078ADF14C0D1FF0B0FAFF
+:209A2000071C00F03B816878F873DFF888826878F12809D0CD2807D01A2805D0E92803D092
+:209A4000E12818BF1D280CD17889DFF86C92000B80F003813846002104F05EFF002840F0E7
+:209A6000BF8010976B788DF84430A87B8DF845008F4C387C002840F085808B4802685AB103
+:209A8000384619469047012804D179894FF6FE70084078819DF84430787B02282BD17989FA
+:209AA000890826D3E92B24D0CD2B22D0F02B20D0788A7E4B000A08D3B87E30B1B87338688D
+:209AC00000881BF009F8194603E01946887A401CB873B87B401EC0B2B876B87304267E7351
+:209AE000C88D38812078202118F05CF89DF84430787B022801D0062839D1608F398B884277
+:209B000015D0607898B138680088ADF80A00388BADF80800387B8DF80E308DF80C000126CA
+:209B20008DF80D6002A81FF005FD9DF84430788940081CD37E6946B1707810F0030F04D18A
+:209B4000B078317BB2881BF0D1FF79894FF6FE7008407881386800881AF0BEFF002600B160
+:209B600001269DF84430301C01D10BB10FE073B940463E68036830881AF0AEFF28B923B105
+:209B8000984702E010A809F01BFC9DF84430E92B18BF002B07D1396801200090EA7B0888FE
+:209BA00049890BF00FFE94F8320080086ED3787B022802D17889C00806D26878E92865D18C
+:209BC00038461AF01FFE61E03B6818881AF084FF20B94FF6FF70188005205BE0032059E0EE
+:209BE00048460078800826D33968086A18B3C97F02AA0BF061FD6B78E92B07D13968012022
+:209C00000090EA7B088849890BF0DCFDBDF81200396808809DF80D0000280CBF0022402210
+:209C2000BDF81200BDF814100EF026FC18B1788940F0200078816E783889E13E18BFB6F10D
+:209C4000100608D1798911F0300F04D020F019FA00F00700801C388101E0052078736878BF
+:209C6000E92813D04046006800B18047134C206A60B148460078800808D339680888498924
+:209C80001CF0C6FC10B1226A69789047787B022801D106207873A87814F0A4FB07F0DEFE5B
+:209CA00013B0BDE8F083C046C4000120ACFE0020E4FA002008FC002016FB0020ECFB0020BA
+:209CC0002DE9F04F044665692888ADF1440D0027ADF8380016E010FB04F2BB189B780B701C
+:209CE000BB185B88BA181B124B701279401CC0B28A70C91C11E1BDF838007F1CFFB2401C35
+:209D0000ADF83800A878B8420CDD21680BA800906268087D89880EABC2F3C00217F0C0FA46
+:209D20000028E8D1E07A0C2800F09680152840F01081022000EB870080B220F0ADFAB84635
+:209D4000061C00F00681002F4FF0010939D028880025ADF83A00216808A800906268087D1D
+:209D600089880DF13A03C2F3C00217F099FAC8B1BDF82410A800321851809DF8262033183B
+:209D80001A719DF82710BDF83A207F1E05F1010506EB000301F00700587102F10100ADF876
+:209DA0003A00D8D1216808A800906268087D89880DF13A03C2F3C00217F072FA08B14FF07A
+:209DC000000986F8009086F80180216804236768087DA57AB1F804A0109001F1060BF8085A
+:209DE00080F0010000F0010918FB03F0401C044620F052FA071C1BD00146307801F8010BEE
+:209E000000207278824215DC00200090CDF804900121029103900495524605941623069792
+:209E200010980791594606F043FA384620F074F937468BE08200B3189B780B70B3185B88A4
+:209E40001B124B70B3181B79B2188B705279401CC0B2CA70091DD4E73E4606EB4600801CEB
+:209E600080B220F019FA071C73D0002E4FF0010933D02888B0460025ADF83C00216808A8C8
+:209E800000906268087D89880FABC2F3C00217F007FAA0B1BDF8241005EB45003A183B1885
+:209EA000B8F10108518005F101059DF82620BDF83C101A7101F10100ADF83C00DED12168B0
+:209EC00008A800906268087D89880FABC2F3C00217F0E6F908B14FF0000987F800907E70CD
+:209EE000216894F80A806568087D0324B1F804A0109001F1060BE80880F0010016FB04F5EF
+:209F000000F001096D1C284620F0C6F9061C1DD00146387801F8010B00207A7882423FF76A
+:209F2000DAAE00200090CDF80490012102910390CDF81080524605950D23069610980791B5
+:209F4000594606F0B5F9304620F0E6F8384620F0E3F811B00120BDE8F08F70472DE9F04FDF
+:209F6000DFF84C9204460D460020ADF1440D01461F460D9016460E9183460F91D9F808A05A
+:209F8000CDF840B014F0AEF8262803D014F0AAF8252825D1308843F6070181420ED040F688
+:209FA0000201814206D0B0F5C15F19D1F07B022816DD43E0F07B022812DD3FE096F8240056
+:209FC00002280DDD307C0F2838D13169C1F31421B1F5803F04D00F2830D1B1F5A02F2DD11A
+:209FE000002D2BD056B328784FF0010808FA00F01AEA000F22D03046594620F0F5F865607A
+:20A000006C4DA660A86980B110A800900DA90EAA0FAB30460BF0F2FF0E980B214FF6FF72E5
+:20A0200050231DF0A5FDFF2808D020F0CFF882462878022804DB504620F052FA5C46B3E090
+:20A0400000286DD107F088F95B495C4E086840F00200086009A8C9F800601FF00BFE584E3A
+:20A060005849707809AA0B9005F1E00018F012FE554905F58E7009AA18F00CFE09A81FF000
+:20A08000C1FD192109AB3078504A0A9005F160001BF080F84E4A05F17C001A2109AB1BF05B
+:20A0A00079F84C495A4605F5AC7013461AF0B4FC49495A4605F5CE7013461AF0ADFC4748CC
+:20A0C0000068C0F3814030B1454A05F1340004215B461DF089FDB078012802D10E200FF060
+:20A0E000F3FC05F1A0001FF087FB05F198001FF083FB594685F8241085F83010072085F87E
+:20A100004002A960E962374B1970E960052685F83110354A2E610420AA621EF02FF8287859
+:20A1200005EB8001401CC1F8B840C0B22870504620F0D6F91FB901A81FF086FB01AF3868C1
+:20A140004FF4FA76E6602060B8694146A062388A61766083F8692063786800280CBF40F673
+:20A16000C410594620616061204E266266622176E661F86800B12062786900B16062B86887
+:20A1800000B1E061C82204F13800594614F0DEFB04F1500059461DF0CDF815495A4604F191
+:20A1A000B80013461AF038FC204611B0BDE8F08FCC21084030F5002000200940110000E031
+:20A1C00050C302000D9302007D880100011C020015090200E9860200FD8C0200B44F005034
+:20A1E000E5360200FD130120B967010077F500005DA102002DE9F04715469F4A13680F4623
+:20A20000ADF1A00D23A90B6053684B6012890A8101A91DF0D9F98046B8F10A0F00F0278187
+:20A22000B8F10D0F00F0238112A801A902221FF035FA814601A9022268461FF02FFABDF8CF
+:20A24000000010F0070F13D0BDF8000000F00700022818BF022413D10DF106014846082291
+:20A260001FF01CFA0B240DF10E010122814603E00DF10A010422062448461FF00FFA8146EA
+:20A280009DF80500800908D30DF10F01484602221FF004FAA41CE4B281469DF805008011AB
+:20A2A00041080DD30DF11101484601221FF0F6F981469DF80500641CE4B28011410803D290
+:20A2C0009DF8041089090BD30DF11201484604221FF0E4F981469DF80500241DE4B28011EB
+:20A2E000400808D30DF11601484610221FF0D6F91034E4B281469DF80400C0093AD3002058
+:20A300000DF1260A8DF898000A22514623A81EF021FC2646641CE4B278B901220DEB060065
+:20A3200026A98DF8982048301FF0B8F951460A221FF0B4F90A34E4B281460DF1300A23A8BC
+:20A340000A2251461EF006FCA0B99DF898000DEB060326A90122401C8DF8980003F14800FC
+:20A360001FF09CF9484651460A221FF097F90A34E4B281469DF80500400836D39DF83A30C4
+:20A3800026460020641C8DF89900E4B2580811D301220DEB06000DF199018DF8992048304A
+:20A3A0001FF07CF90DF13B0104221FF077F9241DE4B281469DF83A00800816D39DF899002E
+:20A3C0000DEB06030DF199010122401C8DF8990003F148001FF062F90DF13F0148460422AF
+:20A3E0001FF05CF9241DE4B281460DF14301484601221FF053F981469DF80400641CE4B297
+:20A40000000903D39DF80400400906D211A9484601221FF043F9641CE4B217B9287818BB94
+:20A4200020E02878264608B1A41EE4B20DF1020102222018ADF8020038461FF02FF92878A6
+:20A4400000B9BF1C422E0744A8BF012010DA3246384612A91FF022F92878002818BF9DF82C
+:20A46000020003D1A41CE4B2287800192870404628B0BDE8F087C04648C002002DE9F04F80
+:20A480008246ADF1240D12980D460890287A984617464FF0000B012818BF032808D1BAF1BA
+:20A4A000000F05D0BAF1FF0F02D0032802D10FB95C4612E104A80A221EF0ECFE894C207895
+:20A4C0008DF81A7020BB0420874E8DF800003088ADF802001EF0AEFE01AE014630461FF080
+:20A4E0006FFC68460BF078FA1FF0CEFCBDF8021081420BD04FF6FE71814207D0ADF80200A3
+:20A5000030461FF0EDFD68460BF066FA01202070287A4FF004095C468DF80090022815D05E
+:20A5200003280AD001281CBF4FF6FE71ADF80C1017D12888ADF80C0012E001A829461FF03B
+:20A540003FFC684616F0E2F838B109E02888ADF80200684614F034FA10B968460BF03CFA81
+:20A56000287ABDF80C10012819BF3A1C271C0127221C4FF6FE70884200F09B805B484B46AC
+:20A5800026460E3810F80E5FDFF864C1554508D14578BD4205D145888D4202D105799542CF
+:20A5A0004DD05B1E06F10106ECD1002C48D14F484B4626460E3810F80EEFBEF1FF0F04D095
+:20A5C0005B1E06F10106F6D173E080F800A0477004464180B8F1040F0271C8BFC8466046A6
+:20A5E0008168B8F1000F17D0089D4746E146AD1E35F8022FADF81C2011B104A888472A8881
+:20A600001146504601235A461DF08EFBD9F808107F1EEDD14FF0010B089984F80580A01D05
+:20A620004FEA48021EF036FE3048330131460E22A3EB46031B1802201CF004F839E004466B
+:20A64000B8F1000F35D0089D4746E046AD1E35F8029F204649461DF0EBFD40BB34B36079A7
+:20A66000042823DA04EB4000A0F806906079401C60711E48330131460E22A3EB46031B1803
+:20A6800002201BF0DFFF08F108002A880168ADF81C2011B104A888472A88114650460123B2
+:20A6A00000221DF041FB4FF0010B00E000247F1ECDD1BBF1010F10D10E48007880211AF08F
+:20A6C0004BFA40B11CF0EAFA05461FF0F3FA0121284619F0F3FB1CF0F9FA204609B0BDE8C3
+:20A6E000F08FC046FC0201201EFB00206C010020DC0201204DFF00202DE9F04F07460020C3
+:20A70000ADF1340D002106900C22079003A814F01DF907F1240414F8011B01F00300C1F329
+:20A720008018089000208DF80C00CE110A901AD020460078022500F00701641CC0F3C103E1
+:20A74000C0F380198DF80C10C0F340120993B9F1000F0B9218BFB8F1000F40F00281184675
+:20A76000012805D1FDE081460B9001254B4609930898012824D09DF80C0050B1022812D1DC
+:20A7800014F8010B6D1C07F1080108220A90032004E02146022004222D1D241D387404A8BA
+:20A7A0001EF078FDEDB268460021082214F0CEF804A8694608221DF067FF002840F0D18013
+:20A7C0000998022810DAA3469BF80000E02803DBB8F1010F00F0C58097F8223097F82300E1
+:20A7E0000793401BC4B212E007A8214604221EF051FD97F823002D1D211DEAB28B46801A23
+:20A80000001F0422C4B206A809191EF043FD089801281AD1002E40F0A4809BF80000F0287E
+:20A8200080F29F800998002840F09B80B8F1000F0BD1002001464C4A8DF800001226019193
+:20A8400001231660684600F079FD04F1440080B21DF043FE061C00F0848004203070012195
+:20A8600031750025757097F92000707597F82100B07597F82200F075387CB9F1000F2A46CB
+:20A8800086F8200018BF0A1CAA46B8F1000F914618BF8A46022808D0032808D106F11800E2
+:20A8A00004A908221EF0F6FC01E038893083B88B7084089D86F824509DF80C0086F825005A
+:20A8C000099D86F82650DDF82C8086F8278086F828A086F829900498F062DDF8289086F8C2
+:20A8E0003090079B7363069AF2639BF8000086F8380000201BF0BEF930710020B060FF230D
+:20A90000F3607868306120201DF0E7FD0746174890F800A01FB930461DF0C6FE21E01449F1
+:20A9200030461EF007FC0720387000237B70307959462246387706F141001EF0ABFC86F8E9
+:20A94000404087F81090079887F8158003A93D750C22B861381D1EF09DFC5046394618F0E7
+:20A960009BFE0DB0BDE8F08F480501209C0301205C190020F0B5064600240A20ADF15C0D54
+:20A980004FF6FF7502228DF85B0021468DF85A403768ADF80E500DF1560013F0D7FF9DF810
+:20A9A000560007F0070100F0F800014341F018018DF85610BDF85600203D21460540F808CD
+:20A9C00000F020002843C7F34115ADF85600012D08BF01212246032D08BF01229DF856006D
+:20A9E00062F39F1040EAC11022468DF8560005B901222046022D08BF01209DF857103B0977
+:20AA0000022D01F0E00140EA010003F0080141EA000141EA02118DF8571009D09DF85700F3
+:20AA2000F90A01F0200100F0DF0001438DF85710C7F34120012899BF9DF8570000F0BF00CB
+:20AA40009DF8570040F040008DF857009DF85710022201F07F019DF856008DF8571040EA2C
+:20AA60000120ADF80C0003A90DF112001EF016FE306810F0070F13D000F00700022818D18B
+:20AA800005A806F1080108221EF008FE022006F1080108228DF8000001A81EF0FFFD08E05F
+:20AAA00006A8311D04221EF0F9FD8DF800407068019007A806F1100101221EF0EFFD3068D6
+:20AAC000400C34BF0DF10E0106F134010DF11D0002221EF0E3FD30689DF85A700122400A6D
+:20AAE00000F01C0100F00300084347EA00018DF85A100DF11F000DF15A011EF0CFFD08A8EA
+:20AB000006F1200104221EF0C9FD09A806F1240110221EF0C3FD0DA806F1110108221EF060
+:20AB2000BDFD0FA806F11A0102221EF0B7FD0DF13E00FF2110221FF0B1FB3068C0F34110C7
+:20AB4000022820D1BDF80C1012A80122C1F300211FF0A4FB0DF1490006F11C0102221EF01C
+:20AB60009DFD3068400C0BD2684614F09DFD04A9ADF810000DF14B0002221EF08FFD0DE0D8
+:20AB800006F13401F6E712A8214601221FF086FB0DF14B00FF2102221FF080FB0DF14D0076
+:20ABA000FF2104221FF07AFB0DF1510006F1360101221EF073FD9DF8120000090BD29DF88B
+:20ABC0001200400907D20DF152000DF15B0101221EF064FD05E00DF15200FF2101221FF07E
+:20ABE0005DFB31680DF11200FCF792FB17B0F0BD2DE9F04F994E96F83D0096F83F10F37811
+:20AC000096F83C800027ADF12C0D0918491E91FBF3F296F83D4077705A43891AC9B20891AD
+:20AC2000810001EBC0018919B1F84C0096F83C10ADF81C00880000EBC1008019B0F84C50A3
+:20AC4000CDF8248006A81AF0F7FB70780A97A04500F0A180B946CB46BBF1010F00F0908096
+:20AC6000BDF81C10162966DD002840F09580BDF81C0001AAC01F81B2ADF81C10204610F03F
+:20AC800061FDBDF81210BDF81C30884608F1070008F1100287B29A4246D89DF80E00962811
+:20ACA00042D19DF80F00420839D2800837D3BDF81C0000230093A0EB08001FFA80FA9DF8B4
+:20ACC0000D20BDF81C002346401A80B21BF07EFAF8B9E819B0F5005F15DCF068C5F188526F
+:20ACE0000AEB443A3B46D21B514602F500521FF0C3F9ED1909F10109ADB2B5F5005F08BF8F
+:20AD00004FF0010B0BE0BDF81C004FF0010BC01D2EE0BDF81C00401EADF81C0004E0BDF86D
+:20AD20001C00A0EB080023E0204607A916F0C4F801281FD030E0F278B9F1000F07D0484BD4
+:20AD4000BDF81C70A10001EBC401C9188F830899A14220D04249641C94FBF2F05043241AAC
+:20AD6000E4B2A00000EBC4004018808B4FF00009ADF81C0009997078A1427FF46DAF0AE09C
+:20AD8000B9F1000F07D0364ABDF81C70A10001EBC40189188F8320B106981EF063FA102053
+:20ADA00059E0DDF824804FF6F0704FF40051C5EA0040C5EA0141E1FA40F01FFAA0F283B2DD
+:20ADC000102102F18852404618F058FF71780843707006981EF046FAA0450FD1F278204FF2
+:20ADE0001019401E90FBF2F15143401AC4B2A00000EBC400C019808BADF81C00184FBDF8EA
+:20AE00001C00A6F840504FEA8801A6F8440001EBC80186F83E40C9198D83B6F9422096F802
+:20AE20003D10012340461CF0CBFE96F83E10B6F94420022340461CF0C3FEBDF81C001628D0
+:20AE4000DCBF01200A90B5F5005F03DB0A9840F002000A900A980BB0BDE8F08F5CFC00204E
+:20AE60008CFC00202DE9F0410546A88CADF1380D0328C0F22881954F0024069507F1180048
+:20AE80000B94AE6A09940822ADF828402146056007A81FF003FA079816F8012B20F00700B0
+:20AEA00002F00301C2F380030143104641EA830102092CBF41F0080121F00801000960F375
+:20AEC0000411079133B171783078B61C00EB0120ADF8200016F8010B8DF82200AB6A16F8C9
+:20AEE000010B0996AA8C8DF82300F61A901BADF82800287D1EF0D6FEB846002800F0E18043
+:20AF00008068002800F0DD80408800909DF82330079AA988287D02F003021AF0DFFF002816
+:20AF200000F0CF801EF02EFF0246D8F80810A888012741B18B88834202DCCB88834203DA72
+:20AF400009680029F6D121460798002900F00306C0F3800034D050EA060303D19DF8233032
+:20AF60000B2B2DD0D2092BD36B7E4BBB0699487D002840F0A6804888002840F0A280224642
+:20AF80001EF07CF8079E9DF82300069A8DF83000F00880F0010000F001000090BDF820506E
+:20AFA00001959DF82200911D0290107D92888DF831700CAB1AF098FC3A461EF05FF880E09D
+:20AFC000002E4BD1002847D19DF82300172841DA3F4E56F8301000293CD0287D8DF810004B
+:20AFE000BDF82870ADF81270099D059504A888470B9048B906994F7D002F62D14F88002FB3
+:20B000005FD10798802743E09DF8231006EBC106716819B106A888470B9808B11FF07CF818
+:20B020009DF8231031F002004BD0032949D0052947D0062945D0082943D00C2941D0112978
+:20B040003FD013293DD015293BD00B2939D02746069915E08227FBE78427F9E749B1896810
+:20B0600039B106A888470746FF2F2AD00798C0F380000699012F03D1002814BF8327812732
+:20B080004E7DF6B94E88E6B90798420900D3C7B1C0089DF823208DF8317080F001008DF8D0
+:20B0A000302000F001000090BDF8206001969DF822000290087D8A888B1D19460CAB1AF04B
+:20B0C00013FCC8F818400EB0BDE8F081800301204CB502002DE9F043054697484278ADF103
+:20B0E000B40D8DF8012000218DF8B21088468DF8008082788DF80220C2788DF803200830F3
+:20B1000058C802AA58C209C8C1464746464682E809002979CDF80490C1F3C1008DF80810D8
+:20B1200040BB11F0070F13D001F0070102291DD14FF0FF30039005F10801082204A813F02F
+:20B140004AFF06A805F10801012213F044FF0DE003A805F10801042213F03DFF04A8FF21C8
+:20B1600008221FF09BF8FF208DF81800FF208DF8190013E0012811D14FF0FF300390FF216B
+:20B18000082204A81FF08AF8FF2005F1080101228DF818000DF1190013F01DFF4446204644
+:20B1A0000DF12A011CF010FA30B99DF80100401CC3B28DF8010001E09DF80130641C052C22
+:20B1C000EDDB9DF80800C0F3C100012842D1002B00F0A2809DF819409C4200F39D80062C0F
+:20B1E00012DA9DF8B260204641460DF1B202FFF701F848B99DF8B2004A2803DC641C062CE3
+:20B20000EFDB01E08DF8B2609DF8B20010B39DF8B2001FF041F8071C1CD041468DF80380B5
+:20B220009DF819408DF8B210062C13DA204639460DF1B202FEF7DEFF60B99DF8B2309DF82C
+:20B2400003009E4200F101008DF8030002DD641C062CEBDB9DF80810C1F3C10000284ED1D1
+:20B2600011F0070F0CD001F00701022947D102208DF81C0004A9082208A81EF00FFA03E05B
+:20B280008DF81C8003980890FF208DF802000DF16E010AAA07A814F059FDA0B99DF8B240AA
+:20B2A000BDF8280041460DF1B202FEF7A3FF30B99DF8B2004A28C8BF8DF8B24006E04146D4
+:20B2C0008DF8B2101BE08B208DF800009DF8B200A8B19DF8B2001EF0DFFF071C0FD04146A0
+:20B2E0008DF8B210BDF828008DF803800DF1B2023946FEF77FFF10B901208DF803009DF877
+:20B3000019008DF8020028680197694610F03CFC38461EF001FF0BE09DF819008DF80200D2
+:20B320008DF8008028688DF80380694610F02CFC2DB0BDE8F083C046E8C002002DE9F04F9F
+:20B3400005460020ADF1340D8DF81A0028789A46894658B1022840F01A81291D04A808229B
+:20B360001DF098FF4FF00808032006E04FF6FF704FF00408ADF810000220DFF818B28DF8D5
+:20B380001800002701E07F1CFFB2D7B95BF82740002CF8D02E7820798642F4D104F108003A
+:20B3A000291D42461DF070F90028ECD0022E02D0002EE8D105E0B9F1FF0F02D0207C4845E4
+:20B3C000E1D1012F00F0E380B90001EB0B0000245BF801700790BAF1010FFC7009D12046A2
+:20B3E0000090012122460190234602908A46039108E02246009201920292012003902B78E3
+:20B400000DF11A0051461AF0FFFF8346079800685FEAEB1600F1170500F10407017C90F84D
+:20B4200016900995437C08919DF81AA00A930BD09DF81A00C0F3C100022803D0032818BF87
+:20B44000032602D10B2600E002261BF0030F07D13D78022D02D01DB9361D00E0761CF6B2C9
+:20B460004E44F6B2304611F0F5FB00280B9046D005465FEAEB1805F801BB18BF05F801AB82
+:20B480001BF0030F11D13B78022B0BD06BB9387905F8010B787905F8010BB87905F8010BE0
+:20B4A000F8790890089805F8010BB8F1000F0DD0CAF3C100022818BF032807D105F8014B7A
+:20B4C00005F8014B05F8014B05F8014B0A984A46099905F8010B28461DF0DCFE4D44B8F125
+:20B4E000000F0CD0CAF3C100022818BF032806D105F8014B05F8014B05F8014B2C70DDF894
+:20B500002C80B8F1000F42D0B1460798224E00687768C57890F812A027B170681DF0C4F878
+:20B52000204670602C201CF0D8FF074677605FB3680829D2384621462C2213F007FA4FF689
+:20B54000FF7BA80803D3F88A40F00100F882F88A052540F4807004A9F8820A22FC7607F131
+:20B560000800BD761DF096FEA7F812B0C7F828803C7587F82790094887F815A032680078A9
+:20B5800001211EF0E8FD02E0404619F005FB0DB0BDE8F08F58190020480501209C03012085
+:20B5A0002DE9F04F0546ADF1140D02911EF00EFE8A4C012D039000F0D280A346DBF80000EA
+:20B5C000D0F838038047002800F0C58016F0DCFF002800F0C080DBF80410864C8969606898
+:20B5E0000F783C30002F40F0B6807D4E0068357880477168F268AB00401AB0FBF3F7B06837
+:20B600004FF00008C2469146534611464F4573EB0A0301DA884206D84146524687428A41DF
+:20B6200043DA024600E041461046EB172A46C01B71EB08011DF08AFF07466F480068884666
+:20B64000418B00694018643081464FF00001B7EB090778EB0A08784271EB080125DA1EF06F
+:20B6600007FC024653464146384614F04CFC884607464FF00001784271EB080115DA1CF020
+:20B6800059FD054630691EF09DFA10B130691EF095FD28461EF031F8306939461EF08AFD7F
+:20B6A00030691EF089FD002000E001204D490870884698F8000000284DD1DBF80000D0F8EF
+:20B6C000940000780027394615F05AFC00B101274FF0000A381C3CD1DBF8040080690078A2
+:20B6E000002836D16068404D436C286902216A4698479DF8000060B302984FF00109012820
+:20B700001ED03A4F6268286997F9001011F1020F05D0926B97F90010904762682869344E7E
+:20B7200096F9001011F1020F05D0926B96F900109047626828696FF001013170397001E028
+:20B7400062682869DBF80410896981F80090D169884788F800A003981EF0C2FE3AE0206878
+:20B76000D0F894000078012115F00AFC03981EF0B7FE606880690078012811D11DF0C4F86D
+:20B7800060B1606880690178012909D10021029F0170012F04D01DF085FE01E00FF096FE2F
+:20B7A0001DF0B2F8B0B960680C30C1680978022909D101680F7837B12068D0F84C05804776
+:20B7C000241D20680C3001680F781FB9C16808780228FCD005B0BDE8F08FC04614010020E9
+:20B7E000D800002008140120700001200C0501200D050120DCFF0020800001202DE9F04F2D
+:20B80000002124220823ADF12C0D68461EF058FE7C4E002421466A4606F138058DF8184097
+:20B8200028461EF049FE06F10C0000F1040B05601EF03EFEF16806F1100215F037F830705D
+:20B8400086F8244086F82540B48316F011FD4FF0080806F1280080F800806B49316310F02A
+:20B8600051FE6A4D287830B9694A204614211AF06DFB012028700C201EF00EFD6F68B146AD
+:20B8800088B1046009F1540180F80480816037B9686008E011467FE0114654E00F46396808
+:20B8A0000029FBD138601EF05DFA5A4D40460A212A1D1AF02FFB584E776840461CF0EAFDC5
+:20B8C000F0B1DFF858A12546BD4208D03879082814D03B6803B93D461F46002BF6D10C208B
+:20B8E0001EF0DAFC60B10460514680F8048077688160002F0CBF7060286001E05146B960B9
+:20B90000474DF22705F13C00077005F16001696410F0F8FD434E307830B9434A2120014681
+:20B920001AF014FB012030700C201EF0B5FC716868B1046005F12C02077173688260002B68
+:20B9400008BF706003D00A68002AA5D10860374A38460C211AF0DEFA38461DF073FB10B13B
+:20B9600033498160C460204614F0B8F916F0CCFB1CF062F90C201EF08FFC2E4AD16880B150
+:20B980000460012380F80480224E4371D768002F866008BFD06004D00A68002A7FF47AAFA8
+:20B9A000086099F80000D9F80C70C5F824B04FF480764FF40073E8701F49AF623222AE806E
+:20B9C0004FF48067EB8005F174002F8118F00AFA1A49A8614FF4FA6205F1980018F002FA0F
+:20B9E0001749E86141F2883205F1BC0018F0FAF928628DF8244009A81DF094FF0BB0BDE8E0
+:20BA0000F08FC0467CFB0020F4030120081800209927020060B90200F8FD002065E5010075
+:20BA2000481900207004012065420200FCB302006D5E020080030120559602006D96020033
+:20BA4000859602002DE9FE4F824C00906068C06801910121017080484FF0000A80F800A0CA
+:20BA60007E4880F800A02068403001680D681E46174615B9D0F80C0580477949DFF8E481E5
+:20BA8000DFF8E491886E4FF0E2450AEA0702354008BF002A40F089800D46B5F89E1008228A
+:20BAA00053463A4013EA060708BF002A0BD118B14246508B401C50834A4692F90000401EC8
+:20BAC00010701D20ABE04A4692F90030DFF89CB142F201468E42A3F10103137002D0321D28
+:20BAE0008A4216D118B14246508B401C5083584600680199826C0098904750B1424602F1BF
+:20BB000016010088B5F89E30098842F60147874233D15748411C0A78B5F86610B1F5105F77
+:20BB200012D0AF6E42F60600884206D0002FC8D04246508B401C5083C3E7002F71D042462D
+:20BB4000508B401C50836CE0A96F5B460C3319604189062A0CD1427A022902F101024272B6
+:20BB600006DB491E89B24181062003F089FF58E018F026FE0FF06CFF53E0491C361D88B2EC
+:20BB80009E42D08214BFE1201C2011F04DFA99F9000020B199F90000002854DC48E020681E
+:20BBA000D0F85824514650464CE04A4692F900102768491E117007F1400118B14346588BD8
+:20BBC000401C58830868006840680078800925D2284A1078832824D125484378032B1BD1DA
+:20BBE00004234779D1F8945013707B1CDBB2437195F8241099420DDB817895F831304D1C82
+:20BC0000AB42C4BF491CCBB28370832010701DF0E5FC06E0E12002E0852051E7E92011F01E
+:20BC200003FA99F9000040B199F9000000280ADC2068D0F84C05804705E02068D0F85824CB
+:20BC40005046014690476068C06880F800A0BDE8FE8FC04614010020100501200F05012050
+:20BC6000501800208C11012012050120E0FF00204C0201200A1401202DE9F047884E05462B
+:20BC800096F84A00ADF1200D08280CD004280AD0287800F00300012840F0FA802869007880
+:20BCA000062840F0F58068884FF6FE74844200F0EF80718F814206D1287F20B9284613F05A
+:20BCC0003BFA0446E5E01CF027FF002840F0DE80287F4FF000092746E8B1724800780421EC
+:20BCE00040EAC00010FB01F05FFA80F8698885F81C80FF201BF0E4FB8A4648B1E88A48F007
+:20BD000001034FF00109671C2B7740F00400E8824FF0400802E0B5F802A0C846504618F0AF
+:20BD2000DBFE08B100206876A87E08B90F20A876287830F07F0008D1E87E50B996F8240006
+:20BD4000411C86F82410E87603E0287800F003002870287E012806D196F82F0018B9287894
+:20BD600008B90020287696F8320080081CD3B9F1000F0AD1688818F0AFFEA8B1287820B10A
+:20BD8000286900781DF096FE70B1E88AC00902D3A87E012804D028461BF0CCFD20B975E035
+:20BDA000E98AE01E0840E8822878012807D128690078022803D1E88A40F04000E882E88AFA
+:20BDC000C00937D2B9F1000F34D196F83200800830D3687E6988AA1D434613F043FB28B147
+:20BDE0000020EB8A687643F02000E882A87978B1698805F1080018F04FFE07466888B8424E
+:20BE000004BF0021A971E98A41F04001E98200E068882978012904D0A98842460FF050FF5E
+:20BE20006888A98842460CF027FB18B1E88A40F02000E882284606A907F000FC8046BC4272
+:20BE400008BF6F88B8F1000F1DD0059528788DF810006C8DADF812406B7D0093E88A019042
+:20BE600095F82C00029004AA0392728F9DF81830394640460DF0B0FC0446102C04D14046C7
+:20BE800018F08AFE00E0102420461AE7112400E0C224284618F080FE204608B0BDE8F0876E
+:20BEA000E4FA0020B7FE00202DE9F04F7F4E7068416EADF1340D02A88847DFF8F4B19BF99E
+:20BEC000000038B17B4890F90000002818BF002040F0E9801EF07AF9DFF8DC910A9099F885
+:20BEE0000000800806D27D2000210DF08FFD0025079001E00025079502958DF80C5005952B
+:20BF000003228DF818206D4CA4F8BE50C4F8C45094F8C800012705F00F013B4620F00F00EB
+:20BF2000014384F8C810DFF898A10B9394F8C81063F3C71194F8D73084F8C81023F001002E
+:20BF400007F0010343EA000184F8D71094F8D70067F3410084F8D70094F8D70065F38200C7
+:20BF600084F8D70094F8D70065F3C30084F8D70094F8D70065F3041084F8D70094F8D70018
+:20BF800062F3461084F8D700DAF80000D0F8282404F1D801F4209047DFF8288198F80030C4
+:20BFA000A3B94946706809788446890910D3C06B8047C4F8C40094F8C81021F00F0141F0D6
+:20BFC000020184F8C8108DF80C700290D6F804C03E4A3D484FF080738DE80C00DCF8507091
+:20BFE0003B4B006804F1BC01894602AAB8470028708006D5022041F2883115F057F80B9532
+:20C000004DE02C49334F91F90000401C087097F90000401C38709BF90000C6F808902946B1
+:20C02000401C8BF80000022015F040F8DAF8001001F1AC021068077888F8005007B180251C
+:20C04000308F17684FF67F7303401D432843308794F8D420387860F3C71284F8D420D1F811
+:20C06000D400C28CA6F84620428D00F14403A6F844201A6806F13B052A6058686860D1F8FD
+:20C08000D400C18CA4F8EE10418D00F14407A4F8EC10396804F1E4063160786870600A98E0
+:20C0A0001EF01EFA0B980DB0BDE8F08FDCFF002014050120130501200614012050180020A5
+:20C0C00014010020110501208000012020004300F9470000120501202DE9F04F0746861C34
+:20C0E000ADF11C0D30461EF027F882490446182268460FF0FBFC7D780DF10B0031461EF060
+:20C100004BF84FF6FE794FF0010802208DF8160000208DF80800B87AADF81490810805D392
+:20C12000B87A000934BF0326042603E000092CBF0226464670480078002808BF002D00F0B7
+:20C140008E80704890F84A10082940F08B801DF021FD10B1012D00F08280002C27D0207903
+:20C16000864218BF022D72D1042818BF032803D1042E10D0032E0ED0022818BF012812D17E
+:20C18000022E08D0012E06D0022818BF01280AD11EF02EF807E0208882461BF03DFE08B9FB
+:20C1A000ADF814A003E0B81C16F024FC0024BDF81430DFF848B1994514D11BF089FC70B9E0
+:20C1C0005846008882462DB11BF026FE002808BF504601D01DF03EFDADF814000346484636
+:20C1E000984231D018462B4612F078FA07F1020A002839D15846001D016811B1BDF814003C
+:20C200008847BDF81400514632460AF069F904463C4800784FF4803141F288321DF09BFF4D
+:20C2200038494046087164B1022D05D0012D11D1607940F0100002E0607940F00800607178
+:20C2400008E0ADF814900FE04FF0C7080CE02088ADF8140000208DF81600804604E04FF0BF
+:20C26000C30801E04FF0C208CDB125480078A0B9012D12D144B902208DF8160031460122E8
+:20C28000684610F0A1FC31E0002001228DF816006846314610F098FC04E02A46F8E76846CA
+:20C2A00017F0B8FA06469CB145B16079022D40F04000607104BF40F020006071B87AC0090E
+:20C2C00003D3607940F080006071A079401CA07156EA08000AD014B1B81C16F08BFBBDF8AC
+:20C2E00014104846884201D01DF082FF07B0BDE8F08FC046E8B8020034040120F0FB00207C
+:20C30000ADFE0020E4FA00202DE9F04F09AF8846ADF13C0D0026079098F80350B8F806102C
+:20C320000993B868089204240B903879DFF8F0910A9019F80E0F854205D148461BF078FF66
+:20C3400008B1761CB6B2641EF3D1002EB34600F0CD8098F81440F1B2182000EBC10085B2DE
+:20C36000601900B210F076FC041C06D02A46002112F0ECFA26746019E060002C00F0B18011
+:20C3800098F80350B8F806100022284619F09EF906466571B8F80600E08098F81600608105
+:20C3A0000021217298F81420D8F81010E0681CF071FF00250C95B8896082387C0D95A94623
+:20C3C000207551E04FEAC900002104EB000A0019817570780AF11605012810D0B0788AF8BB
+:20C3E0001D007088ADF8180004218DF80C1003A816F074FDBDF80E00AAF8180005E0012000
+:20C40000287001230C93708868803079287198F80000C00903D3A87940F00200A8710C9860
+:20C42000B0B9404869880088884211D1287988F802000A9E00960B9B01930D9B0293089A6C
+:20C44000079940460DF064FDA87940F00500A87109F101005FFA80F9B8F8061098F80300C3
+:20C460004A4619F033F906460EB1CB45AADC2E4D281D06680D98314604E00E4620E0096863
+:20C48000401CC0B20029FAD1052813DB96B1334600E01B6813B99E4202D00BE09E42F8D18A
+:20C4A000306801216860304614F05EFF304618F073FB6E68687820716878401C6870204676
+:20C4C00016B131680029D8D10D99002E01600CBF686030600A9B009409993A78404600F0CF
+:20C4E0004BFBBBF1000F18BF002C15D198F8030098F816708DF80F00B8F806608DF81070FA
+:20C50000BBF1000FADF812600CBFB92010208DF8140003A81DF04DFC0FB0BDE8F08FC046F2
+:20C520005E0100201EFB0020400501202DE9F041844FB81C00780D46290C1FD2E80B38BF14
+:20C540000020C0F0FB801BF0F5FD7D4C804604F10C00006858B107463E6938461DF0A4FF70
+:20C56000384618F019FB371CF6D10020E06040461DF0C3F885F48040BDE8F08115F0E4FA27
+:20C58000061C00F0D9803078F9780024D2280EDCD22800F0C7801A3860D01738052840F2AE
+:20C5A000C1809F3800F0BE80401E48D0B2E0D33800F0B580401E022840F2B480293823D0BB
+:20C5C000401E40F0A78016201BF087FF071C00F0A9802146162212F0B9F9932038707C7009
+:20C5E00070783871B07838743079012814BF02200120B871F0883881F0783875B0781CF04B
+:20C600006BFC00287DD080E00A201BF066FF071C00F0888021460A2212F098F991203870AA
+:20C620007C70B078787170783871F078B871B0883881B0781CF050FC002862D065E07078E3
+:20C6400088426FD0404BF870FA1C21464FF000701AF05CFC78783D49087063E030201BF0C4
+:20C660003CFF071C5ED02146302212F06FF9922038707C70B07B032838711CBFF088F880FB
+:20C6800004D1B81DB11D08221CF004FEF07BB873308A388270887882B088B882708AF88208
+:20C6A000307D3876737D204603B101207876707E214600B10121B976B07DF876F07D3877F8
+:20C6C00096F918007877F069386296F8200087F82400B08DF88496F82E0087F82800B08C28
+:20C6E0007885B08C10F0B6FAF862D8B1B16AB28C1CF0D0FD307D1CF0EFFB30B9F86A18F046
+:20C700004BFA38461BF0D0FF0CE00079394616F0C3FF07E03046F3F793FC044602E0304658
+:20C7200002F0D0FA012C03D030461BF0BDFF03E0B078314616F0B0FF85F40040BDE8F081FA
+:20C7400080040120281A0020E17E020070FB00202DE9F04F8246DAF8185069782878EA78AC
+:20C7600000EB0120A978ADF1240D044601EB0221069118F0B1F9012800F0D9804FF0000862
+:20C78000CDF810802046CDF8148018F0A5F92D1D60B970480088A04208D06F48007830F033
+:20C7A000010040F0D48040468123C2E015F8014B5CB1600010F04EFA049030B1049A2046A1
+:20C7C00029461CF05EF9054600E0444615F8017B5FEA07090AD0780010F03CFA059028B1FA
+:20C7E000059A384629461CF04CF900E0C1465B480568002D76D046460796089668680178E2
+:20C8000000296CD0AA7B520869D3AA68002A04BF8668DDF820B004D0012090474FF0010B4F
+:20C820000646002E5BD070880699814204D006984FF6FF7181424CD1F279B3680499204669
+:20C8400019F0CDFF38B9327B33690599484619F0C6FF00283DD009EB0400022110FB01F083
+:20C860001430C0B21BF039FE071C2AD0D2203870BAF80200788087F80C90002C3C7104BFA6
+:20C880000798B86008D007F114000499B860620007F114001CF0FEFCB9F1000F04BF0898B8
+:20C8A000386108D0059907EB44004FEA4902143038611CF0EFFC686840680078394616F066
+:20C8C000EBFE3078264908F1010701F808005FFA87F8BBF1000F02D0304618F05DF92D6888
+:20C8E000002D8BD1B8F1000F05D19AF80C00A8B90023984600E00023164800880090CDF8E3
+:20C900000480174F02979AF8100003909AF811100AF1020248F2060014F064F8049808B1B8
+:20C9200018F03AF9059890B118F036F90FE0002080230094019002909AF8100003909AF877
+:20C9400011100AF1020248F2060014F04BF809B0BDE8F08F50FD0020ADFE002024050120D1
+:20C96000A8FF00202DE9F041064606F11600ADF1380D18F0F1F97A48007806F11607012804
+:20C9800018BF02282FD100200DF1320501A905AC8DF8320001220095601A83B201A907A86F
+:20C9A00017F0B4F898B16F4800680DF1330101AA11F04EFFADF81C00BDF81C40032C12DA44
+:20C9C00003A8394608221CF065FC214606E003A8394608221CF05EFCBDF81C100420142254
+:20C9E00001AB19F02FFE3846FF211CF07CFB10B15D4901200870002402A839468DF804401E
+:20CA00001DF0CAFB1DF0C6F848B901A813F07EFE012804D02046394608AA1AF00FFD3079FD
+:20CA2000534D012861D006285FD0691C0B7804282AD0032840F0918038460DF11E011AF060
+:20CA4000A3FF58B14FF6FE7039460DF11E021AF0F5FC214638460A4614F06CFEBDF81E006A
+:20CA600006A91AF001FD069838B906A81AF0E6F818B9BDF81E0006990880B11D38460FF0C4
+:20CA80001DFE13F095FC68E0002B66D038460DA901AA11F0DDFE01469DF8340000285CD01F
+:20CAA0008DF8154020460290019001278DF81640142201AB8DF81470042019F0C3FDB21D69
+:20CAC0004FF4817010211DF099FA06F1060828B94FF48170102142461DF096FA6D1F3846D7
+:20CAE0000321AC7119F072F837E0721D1021204612F8017F1FB9491E00F10100F8D11B4F57
+:20CB000010280CD07179B01D1AF04CFB387808B12878D0B170790EF049FB2C7015E0387803
+:20CB200098B9204662210DF1220212F049FD0DF1220021461AF036FB20460EF037FB0DF1FB
+:20CB400022002146102211F001FF0A480178052903D1C079802115F025F80EB0BDE8F0817C
+:20CB6000ADFE0020B800012056FE002049FB002051FF002034FD00202DE9F04F0646ADF139
+:20CB80003C0D032700200A91189D0C93297C0B920CE005EBC002127F530805D3D30803D2BF
+:20CBA00012093CBF7F1EFFB2401CC0B2814201DD002FEED1B9460124002010E005EBC002CE
+:20CBC000177FFB1109D07A0807D307F0040207F00807174304BF641EE4B2401CC0B28142B5
+:20CBE00001DD002CEAD1A346B9F1000F08BF002000F0C5804FF00008B7E04FEAC8002A1891
+:20CC00004019007F02F11604400880F0AA80002723780D9793B9108B1DF05EFA70B1007901
+:20CC2000012818BF032809D1A079BBF1000F40F08000A07100F0948001200D900C9800B143
+:20CC4000202700210C22684611F080FE237813BB0A9800280EBF4FF0080A47F040074FF003
+:20CC60000A0A60884FF6FE71814228D104208DF81800E379ADF8243006A816F02FF94FF611
+:20CC8000FE7000210346B0800A46ADF8003007A814F050FD15E03B480078012808D060888E
+:20CCA00047F00C074FF00C0AB0804FF6FF7006E06088FF2147F00807217141F2080AADF841
+:20CCC00000008DF80270307D8DF8040001238DF80530684608F0E0FB9DF8141061BB039858
+:20CCE000417D6171A0F816A00B9F4776277817B124490978017769890185698A4185297D4B
+:20CD000080F82C10697980F83A10217980F83B10F188C1873189A0F84010717D80F849103C
+:20CD2000B1888187406C327D31691CF0B3FA684617F032FE9DF81410A07940F00100A0710B
+:20CD400051B90D9818B1ABF101075FFA87FBA9F101075FFA87F903E0A07940F00800A0711C
+:20CD6000297C08F101005FFA80F8414503DDB9F1000F7FF442AF2846002114F0F5FA0FB07F
+:20CD8000BDE8F08F70FB00202DE9FE4F9B461546894682461DF01AFA7B49019008680CAF0D
+:20CDA000504508BF48687B4C6FF0010828B1B8301CF008FF002840F0D6801BF0CDF9061CC3
+:20CDC00000F0DB8004F5CE701DF0F8F90023B4F9B400C6F80C90401C86F832306FF31F3008
+:20CDE000A4F8B400C6F808B0B4F8B40030866748C6F810A097E80C0020210027B8461940F0
+:20CE0000104006F1180383E80300424686F8332006F1200383E88001E8683064287C86F8DD
+:20CE2000440028687063287986F83800A868F0636869B064A869F064287F86F85000687FEB
+:20CE400086F851002F7C27B9EF6817B1012086F844002F795FB999F80C0000F00F000228F0
+:20CE600005D1012086F83800D9F808007063484608274568002D18BF002F70D100886FF391
+:20CE80000900B0F5305F18BF022506D196F83300082540F0100086F8330006F1180090E81A
+:20CEA0000C00414606F1180745EA0200194387E80300D4F8D800824507D194F8DC004108D6
+:20CEC00024BF00F0FE0084F8DC0031480768002F39D004F1A0000090D4F8A810D4F8AC20C8
+:20CEE00004F198052B463046B84710F1030F10D0B6F93010B4F9B420914207D0B4F9B4103C
+:20CF000001F6FF716FF31F31A4F8B41010F1020F1BD010F1030F18D096F83300B6F9308080
+:20CF200040F0800086F8330000278AF8FC702868864205D0F068007B00F00F0002281CD165
+:20CF400013F094F919E06FF00200B4F9B410804601F6FF716FF31F31A4F8B41005E07F1EB5
+:20CF60002846FFB285E76FF0020894F8DC0040F0040084F8DC00C4F8D8A001981DF0B0FA45
+:20CF80004046BDE8FE8FC046E8F50020FFEFFF9F5805012030F50020FEB50E461DF016F964
+:20CFA00000257F4A7F4C517855708A080ED2C9081AD31DF095FAA4F1080000F108048068DC
+:20CFC000D0F858242846014690470FE01DF088FA6068C068007828B92068D0F8582429467F
+:20CFE000012090471DF0F2F81DF07AFAB00941D337E02168D1F8982050600098D1F840136F
+:20D0000088472168D1F89800D1F85413001D884732E01DF0DBF82168CA6B117B491E117314
+:20D020001DF05EFA216800983C31CB6D0278586000988DF8042047782FB1162A0AD1D1F8CF
+:20D040001813684601E0D1F80413884721689DF804203C31162A06D0C86DD1F81813001D5C
+:20D06000884721683C310868001D1AF056F800280090CED1300C08D32068D0F8940000783C
+:20D0800014F062FD00280090B3D1700907D327682E20D7F840138DF8040001A88847700826
+:20D0A00007D327682520D7F840138DF8040001A88847B00807D327682620D7F840138DF891
+:20D0C000040001A88847F00807D327682720D7F840138DF8040001A88847300907D3276867
+:20D0E0002920D7F840138DF8040001A88847F00909D32D2027688DF80400D7F840138DF8E3
+:20D10000055001A88847300A09D3302027688DF80400D7F840138DF8055001A88847700AD6
+:20D1200009D3352027688DF80400D7F840138DF8055001A88847300B07D38DF805503720EC
+:20D140008DF8040001A81DF0ABF9700B07D38DF8055038208DF8040001A81DF0A1F9206804
+:20D16000D0F898000068C8B11DF030F82168D1F898100A6800920D601DF0B2F921680098F5
+:20D18000D1F8982050600098D1F8401388472168D1F89800D1F85413001D88472846FEBDAC
+:20D1A000D8000020140100207E492DE9F04F0A680746ADF11C0D0DF10E00026049684160E0
+:20D1C000F88900280CBF08210221BC69DFF8DCB1754A14F801A0A0B9104621461BF008FF72
+:20D1E00060B920461CF0A8FF4FF6FE7650B30179012918BF022925D106881CE059460E88E6
+:20D2000020E0617820785E4600EB012031880646B14216D01CF060FF002498B10179012993
+:20D2200010D18DF800404088ADF80C00684615F055FE00B101ACBAF1000F18BF4FF0FF0A92
+:20D2400000E014464FF6FE71B14218BF002C03D13D7B002D40F0A38056484568B1424FF061
+:20D260000B080DD064B13AF0010006D0387B012800F095804FF080090AE04FF0000907E0E6
+:20D28000FB894FF08109002B0CBF4E1C0DF10E0405F8019B002C14BF211C0DF10E01284681
+:20D2A0001CF07AFF0546BAF1010F05F8016B4FEA2620287064D158460088B04260D1B9F13B
+:20D2C000000F5DD1DFF8E8903320002649460C791CB1032CBCBF761CF6B2401E01F124010F
+:20D2E000F5D136B1022016FB00F000B20FF0B2FC00E0002003466D1C002B08BF00260DD038
+:20D30000844633214846047924B1032CBCBF02882CF8022B491E00F12400F4D163B3FC89AE
+:20D32000002C0CBF08210221B8694018417803EB4100B142A8BF002605DA761AF6B208EBBF
+:20D3400046085FFA88F805F8016B297066B16D1E017805F8021F30F8021B761EF6B2002EBC
+:20D360004FEA21216970F3D1184617F015FC08F102005FFA80F803E000204FF00C08287065
+:20D380000C49FA8910204346C87042F4004207F11100B91C13F0C2FB06490020C87007B050
+:20D3A000BDE8F08F44B7020020FC002050FD0020E40D002098FD00202DE9F04F074678695A
+:20D3C000824600780321ADF12C0D10FB01F0401C80B21CF061FF5FEA000808BF002400F0F0
+:20D3E000EC80002635464FF00709099512E0049931B93968087D228889881AF085FD01E06C
+:20D4000019F06EF9ADF82000BDF820006D1CEDB23618B6B29AF80000A84223DD396815FBF7
+:20D4200009A4641C087D2288898802AB16F094FB80B19DF80E00A178884209D19DF80F10F8
+:20D440008A0803D38909D2D37E2004E0882002E08D2000E0862088F801002088A8F8020023
+:20D46000012509950998002888F8000040F09180CB4610FB0BF0C4B2A01980B21CF00CFFCF
+:20D480000A90002808BF002400F0948081460026A14404E0BDF82000761C8144F6B29AF8BF
+:20D4A0000000B04268DD3968087D16FB0BF50AEB0504641C2288898802AB16F04DFB0028A2
+:20D4C0005AD00A982388049A2D18C5F803902B808AB9396808A800902288087D89884B4602
+:20D4E00019F0ECFD3968D4F80330087D02AA891D18F0D8FC0BE0484602A908AA1AF0DAF934
+:20D500003968087D02AA2346891D19F0FEF90028C0D0099B032113FB01F108EB010208EBC1
+:20D520000105507021885A1C6980D0B209901EB30A9C3968087D2288898805AB16F00CFBED
+:20D54000D0B1079840B93968D4F80330087D05AA891D18F0A7FC0BE09DF81A00D4F8031014
+:20D5600019F0BEF80246D4F8031007981CF096F8761E04F10704DCD1099888F8000028B949
+:20D58000002088F80100012688F800600A981CF0C3FD78683A68C00880F0010000F00100C9
+:20D5A0000090B87A911D0190107D928843460FF081FD012440461CF0AFFD20460BB0BDE894
+:20D5C000F08F70472DE9F0470646F08917468946ADF1280DC01D80B205460EF0B5FE7A4C33
+:20D5E000FF280BD12846FBF7EFFD854204DD641C207800B90520E3E0012000E00020617881
+:20D60000D9B917B1022F18D1B8B1307A8DF80C00F788ADF80A70B588ADF808500023009364
+:20D62000E18E94F8330001AA032305F0F1F89DF814003074BDF81070B78194F83310E58E11
+:20D64000E06806AA0423884649031CF015FD069800F0FF0100F0FF007E2806D140467C2156
+:20D6600019F0CCF9069901F0FF017C2940F0A580F08942F20102C11D8FB2E9198A4240F382
+:20D680009A80F188327AC1F301238DF81D10B18843EA82038DF81C308A1006468DF81E205C
+:20D6A0000423C0F3851201F0030142EA81128DF81F2010FB03F1F21D01F0FC01731990B2B7
+:20D6C0008DF820101FFA83FA0D282BDB4846314600221CF003FC0246052107A81CF0FEFB70
+:20D6E0009DF82010334600F03F064A4641EAA011B0008DF8201040F0020096268DF8210052
+:20D7000029468DF82260404616F0B8FA0646514607AA07234046667016F0B0FA3043607048
+:20D720004DD135E004F12400494632460EF0DEF907A90A68301900F12409484609790260C6
+:20D74000731D0171002204F1240099B21CF0C6FB9DF82010962300F03F068DF8223041EABF
+:20D76000A011B0008DF820103B4640F0020007AE49468DF821003268B0790A60B288887196
+:20D7800040468A8004F12402294616F077FA6070E18EED194FEA8806AAB2C919E18606EB56
+:20D7A000C8010919A1F84C2048B14046514615F04DFF607803E0052000E001206070C0B2EF
+:20D7C0000AB0BDE8F087C0465CFC00202DE9F04705467B4895F80B900078ADF1180D00280F
+:20D7E00008BFBA2000F0E980684600210C2211F0ADF801264FF0000A298B8DF80560C808AE
+:20D800000AD39DF80220C8100B0942F040028DF8022038BF032602E09DF80220C8104B0988
+:20D8200028BF46F0400640080FD342F0C00288098DF8022039BF9DF8030040F002009DF8D8
+:20D84000030040F001008DF8030001EA6100000A28BF46F00806287A5A4F002830D00F28E1
+:20D8600028D0022822D0032818D0012832D1387848B94FF6FD70ADF80000288842F00C025D
+:20D8800046F0040608E0288842F0080246F480564FF0FF09ADF80000824619E0284669469A
+:20D8A00019F064F89DF80220298B13E02888ADF800000FE0288842F0080246F0040605E050
+:20D8C0001CF0F4FA9DF8022042F00402ADF800008DF8022048081AD312F00C0F0DD128882B
+:20D8E00014F0DCFF002808BFBB2066D09DF80220298B42F020028DF80220480807D302F0C7
+:20D900000C00042804BF42F020028DF80220A87C8DF80400684607F0BFFD9DF81400002832
+:20D920004BD1039CE682E87E6076287FA076287A012804BF38782077A87E2085288B608593
+:20D94000E87F84F82C00288B00EA6000000A15D395F82000667D804618F08EFE071C0DD0DF
+:20D960003A7C002008E007EBC001CB7E984504BFCE763A7C401CC0B28242F4DCA87A84F853
+:20D980003A0084F83B90A4F83CA0E889E087288AA4F84000A87E84F84A00A87F84F84B004E
+:20D9A000687F84F84900606C69696A8A1BF072FC684616F0F1FF9DF8140006B0BDE8F08791
+:20D9C000AF00012070FB00202DE9FE4F07462C200FF040F90028386100F0E68000212C2232
+:20D9E00010F0B4FF38694FF6FF7585823C6938880DF1020112F0CEFBDFF8B4B168B30DF18D
+:20DA0000020069461BF048FBBDF80000854224D0002006262074BDF80010BDF80030668225
+:20DA2000674E8A0002EBC100A38206F1240143181A68A2611A68521C1A600E584FF47A74D7
+:20DA4000B6FBF4F06043361A07D101205E46187230784FF4006114F0A5F83969388808318F
+:20DA600012F098FB5348846880461CF093F868B13869002141823869682686823869022392
+:20DA8000037438698461621CC8F808204A48D0F800903869DFF824A10446A18A2E468E4243
+:20DAA00054D104F1080049461BF0A2FA48B91BF0C1FB014648461BF09BFA10B91CF06AF89A
+:20DAC00060B13888396904F04BFD002400B1012400200CB139698D82396908743869044606
+:20DAE000A18A8E4232D15146303991F82F303BBB91F86510012923D101200DF10A013A22A8
+:20DB00001CF073F9C8B901209DF80A50207400233A22A5755D466382D8F80410A28228789F
+:20DB2000A161D8F80410491C0129C8F8041005D14FF4007114F036F800E0A5823C692046CE
+:20DB4000828A3146914204BFA1213975818A8E4224D0017C01290ED0BE6856B91CF01AF895
+:20DB600020B9B878400838BF052100D30D21204602E00D2100E00E210177B87800F0030016
+:20DB800001281ABF514608780520396948703C6960781BF0C7FB6077BDE8FE8F16F0FCFF99
+:20DBA00000203861BDE8FE8F10203875BDE8FE8F3BFD002048040120B800012014FB00209E
+:20DBC00064FE00207A492DE9F04FFF28ADF13C0D0AD148780A78824240F3E680850005EBAE
+:20DBE00000156D18183503E01422183110FB0215E8884FF6FF74844200F0D680287B0028BB
+:20DC000000F0D28068788DF8310000268DF83060684FADF8286038882B7BADF83200C3EB22
+:20DC2000C300401C0FF016F80746287B80000FF011F80D90002F00F0B380002800F0AD800C
+:20DC40002B7B0E904FF0FF0A4FF00709A3463B7050E016FB09F039183C180023A1F801B009
+:20DC6000804684F803A007EB08004360287BB0423EDD2C69711C1846002C39D08642C8BF6E
+:20DC80006468401C491EC0B2F6D18CB32068008807EB0801A1F801002268698868781288E3
+:20DCA00008AB0EF0D7F9012822D19DF8220007EB080107EB08030422C8700E9809995860BA
+:20DCC0001BF0E8FA0E909DF822001BF076FA78B1206800210422801C10F038FE9DF8220006
+:20DCE0000FF02EFA024609992068801C1BF0D2FA761CF6B2287BB042ABDC95F801B0B5F8D7
+:20DD000002A01CF09FF900242346804624E015FB09F0391838184078491C02F8010B088809
+:20DD2000001202F8010B887802F8010B8878D1F8031009F09DFE6D1CEDB2024616E013FBE1
+:20DD40000971491C8878D1F8031018F0C9FC5B1CDBB20019C01C84B238789842EFDC204651
+:20DD60001CF09AFA061C18D0024600253878A842CDDC002100910120019002910391CDF8F9
+:20DD80001080524605940A230696584607910AA902F08EFA30461CF0BFF9384616F0FCFEDE
+:20DDA0000D9808B116F0F8FE0FB0BDE8F08FC046F00C01202CFB00202DE9F04785682A68F0
+:20DDC000D16944681162490832D3D4F8C01049BB2968486820F0020048602968486A20F0A6
+:20DDE00003004862D4F8CC002A6941686F69096847EA0200C862D4F8CC006E6941682A6951
+:20DE0000096846EA0200C1F804052968486920F001004861286801210162284619F0D4FF42
+:20DE2000BDE8F08703220A7403F026F9BDE8F087D4F8CC0041682A696F6909684FF0000990
+:20DE40000226CA4647EA0200C1F80405D4F8C070002F00F0A880D4F8CC00D5F814E0406851
+:20DE6000D4F8E0C0D0F80080BCF1000F04D1EA69A86904F1D80103E004F1DC016A6A286A10
+:20DE8000D8F8043513EA0E0F11D0806810F0070F0DD13868D4F8D030984208D17F6937B9AB
+:20DEA0002B68586A20F002005862C8F804E5906810F0070F74D10F68002F71D0D4F8D400BE
+:20DEC000BCF1000F3844C4F8D40014BF48462020C4F8E000C1F80090D4F8C010D4F8D0209C
+:20DEE000086890424BD8D4F8D420904247D881F81090D4F8C80004F1300730B9D4F8C010AE
+:20DF0000C4F8C810D4F8C80008E04369002B34D1D4F8C0104161D4F8C01040694969C4F824
+:20DF2000C010C0F814A0D4F8E00000280CBFD4F8D800D4F8DC00C4F8D000D4F8C000C4F8E6
+:20DF4000D49088B12046294606F08EF994F8FE0078B1D4F8CC00406801686869D1F80425B3
+:20DF6000024218BF886204E02968486A20F00300486238461CF04AF912E01846C5E7204689
+:20DF8000294606F071F994F8FE0048B1D4F8CC00406801686869D1F80425024218BF8862BE
+:20DFA000761E7FF453AFBDE8F08770472DE9F84F0746714D714C28684030D0F89410267856
+:20DFC00091F883B026B1D0F80C0580472868403001680E6816B9D0F80C058047A046694928
+:20DFE000674C0120012F88F80000D1F8009067702AD9DFF894A1654EBF1E59D07F1E52D0E6
+:20E000007F1E3DD07F1E73D07F1E34D12968096C096891F86D20628191F86E70002F06BF09
+:20E02000E070071CE770686840683178007811FB00F0784381005046C16690F8701021F06F
+:20E040000F0141F0030151E000202E686071306C0068D6F8D410C08AC00934BF91F8250059
+:20E0600091F84E00A070B7B9CF78A7B10228C4BF0220A0700FE02868D0F84C05804737E055
+:20E080002868006C006890F86910617190F86A00A0700027A77109F09DFE2868006C006810
+:20E0A00030BBBDE8F88F0020607117F087FB1FE030788700D9F83C00804771683C22401A3C
+:20E0C000B0FBF7F0B0FBF2F15143401AC0F1780086B2D9F83C00804707FB06015046C16637
+:20E0E00090F8701021F00F0141F0020180F870102748007898B92868403001680F682FB9CB
+:20E10000D0F80C0580472868006C07687A686178107800F0200020719078E07100E06178FE
+:20E12000032903D0022918BF062923D11CF04EF805466078022815D01648077817B916492B
+:20E140000F787FB10221BBF1010F88F8001004D10078832801D113F095FE28461CF0C0F906
+:20E16000BDE8F88F832088F8000028461CF0B8F91AF06CF9BDE8F88F140100200A14012016
+:20E180004C020120E0FF002050180020D8000020FC13012005140120071401202DE9F041A4
+:20E1A0000D4677490A680646ADF1600D14A802604A6842600A8902810A310C2268460DF0E7
+:20E1C00095FC0024204603A919F0FEF98046B8F10A0F1DD0B8F10D0F17D09DF80C0031780D
+:20E1E00000F0070001F0070188420ED1371D0DF11201042238461AF0ADFC48B90DF10E01BC
+:20E20000384608221AF0A6FC10B9641C052CD9DBB8F10D0F02D1042C00F3AF80F220594CDB
+:20E220008DF80900B4F848009DF80C70ADF80A00F80937D34FF002080DF12E0114A80A2233
+:20E240008DF808801AF086FC98B90DF13601684642461BF023FA284614F070FD071C08D067
+:20E26000608F69460C22B88138460DF03FFC2878B8730EA914A80A221AF06CFC90B910A905
+:20E28000684642461BF00AFA284614F057FD071C08D0608F69460C22B88138460DF026FCD6
+:20E2A0002878B8739DF80C00C01123D001208DF80800304611F0F8F9ADF80000284614F001
+:20E2C0003DFD071C16D09DF80D00800904D2304611F0EAF9B88106E007F10C000DF1170167
+:20E2E00002221BF0DBF9694638460C220DF0FEFB2878B8739DF80D0040083ED301209DF84E
+:20E3000042708DF80800780819D30DF14301684602221BF0C3F9284614F010FD071C0ED0F7
+:20E3200007F10C000DF1450102221BF0B7F9694638460C220DF0DAFB28780938B8739DF8E8
+:20E340004200800819D30DF14701684602221BF0A5F9284614F0F2FC071C0ED007F10C00E1
+:20E360000DF1490102221BF099F9694638460C220DF0BCFB28780938B87318B0BDE8F0819B
+:20E3800058C10200E4FA00202DE9F04F724C002704F19800ADF1140DB946B84605680297DB
+:20E3A0008246CDF80C903DB3D4F8AC00B84203D1D4F8A800B8421DD0D4F8A8600EB3D4F842
+:20E3C000A8102869096988421BD195F83300400917D3D4F8AC60A6B90127D4F8A800C068DE
+:20E3E00040880028F9D0D4F8A800C06840880128F3D006E0012704E004F1E00002211BF01F
+:20E4000003FF002D43D087F0010B03A802AA59460CF02CFE5FEA000809D0012F07D003994E
+:20E4200029B104F5AC701BF073F94D462FE0002D2DD04A48066856B3B8F1000F27D0039857
+:20E4400028BBCDF800B002980190D4F8A800D4F8AC100AF108035246B047401E02D0401E1A
+:20E4600008D014E0029800B9284601214B460091014605E001230093D4F8A800D4F8A810F0
+:20E480000069B1F930104A4605F04EFB60E0002F5ED0002D5CD060682969884252D1B8F175
+:20E4A000000F0BD0039848B1D4F8A80030B9D4F8AC0018B9082017F0BDFE49E008201AF0F3
+:20E4C00047FC95F8330004F1E006C0F3001028B9504619F0F1FFC4F8A80004E0504619F044
+:20E4E000EBFFC4F8AC00A8691D49C0430860A8694A6810434860E869C04341F8080CE86938
+:20E5000051F8042C104341F8040CEC680820294619F034FE204619F0FBFD2088A0F6020019
+:20E5200040B141F21E01401A04D041F6E671401A012803D80120214619F020FE4FF08041CF
+:20E54000304603E004F1E0004FF480611BF05CFE05B0BDE8F08FC04630F500205C0501205E
+:20E56000101004402DE9F047ADF1200D109C1D4682460E469046E811002110221FFA80F940
+:20E58000204610F0E3F9C5F3C307D6B104A8214610221AF07FFE2046514610221AF07AFEB3
+:20E5A00004A8214617F02AFC1026224613781AF8011B761E81EA030102F8011BF6D180352F
+:20E5C000ADB24846411E00281FFA81F940F09980002F72D00E2F28DA04A8214610221AF0EC
+:20E5E00059FE204600210E2210F0B0F93A46204641461AF04FFE2E128020E05521461022F2
+:20E60000E5736846A6731AF045FE04A8214617F0F5FB10206B46227813F8011B401E81EA19
+:20E62000020104F8011BF6D187E004A8214610221AF030FE20460021102210F087F93A465B
+:20E64000204641461AF026FE802021461022E05568461AF01FFE04A8214617F0CFFB102741
+:20E6600021466B460A7813F8010B7F1E80EA020001F8010BF6D104A8214610221AF00AFEBD
+:20E68000204600210E2210F061F92812E57321461022A07368461AF0FDFD04A8214617F05F
+:20E6A000ADFB10206B46227813F8011B401E81EA020104F8011BF6D13FE004A82146102201
+:20E6C0001AF0E8FD204600210E2210F03FF92F128020E573214620701022A77368461AF028
+:20E6E000D9FD04A8214617F089FB10206B46227813F8011B401E81EA020104F8011BF6D159
+:20E700001BE004A8214610221AF0C4FD2046414610221AF0BFFD04A8214617F06FFB22461D
+:20E720000021137818F8010B491C102980EA030002F8010BBFF645AFF3E708B0BDE8F087A9
+:20E740002DE9F04F09AF3D7AD7F804800E1C9A4693460446ADF12C0D26D0207A29098DF857
+:20E76000260010D302281FD121881BF09FFB884209D008460322012111F05EFF002818BF93
+:20E78000CD2040F0C180237A022B07D00F2B05D0032B0DD0012B0BD033B909E0208816F0D6
+:20E7A0009BF918B90F2B03D10220ADE00F2323728DF80830032B1CBF2088ADF8000003D189
+:20E7C000684621461BF0E8FCA8081DD250484FF000090368ADF8109043B15868864203D0B7
+:20E7E0001B68002BF9D101E09A681AB9B3688BB158880DE031780220904758B10188ADF8EE
+:20E80000101016F0C9F905E04FF6FF704FF00009ADF810006809ADF818900BD39DF8080041
+:20E820000F2807D0012805D0BDF8180040F00400ADF8180035F07F0005D0BDF8180040F098
+:20E840001000ADF81800E80938BF484606D3BDF8180040F00100ADF8180001208DF8250016
+:20E86000E80805D3BDF8180040F04000ADF818008DF82490A80934BF012004208DF81B0014
+:20E88000617A8DF80B10ADF80EB0ADF812A03D68059598F800008DF81A00397B8DF81C1070
+:20E8A00030788DF80A001AF0C3FA18B1016909B16846884709A815F0DDFA504508DA15488F
+:20E8C0000168002908BF022706D06846884702E06846FEF77BFF07469DF8080002280CD173
+:20E8E0001BF0E4FABDF80010884206D1307898F800105A463B4617F0F9F827B998F80000F8
+:20E90000401C88F8000038460BB0BDE8F08FC04624050120B40001202DE9F8430646307B51
+:20E92000894603461AF02CFB0125041C5DD1D6F8008077891C461C200EF08CF950B1002189
+:20E9400041730473478101818173C173C0F8008041614160041C00F0C08000270781307CF4
+:20E960002074708A6082337C23BB716911B30F460E200EF06FF9E0B1394691F838200270B0
+:20E9800091F83920427091F83A20827091F83B20C270CA8F8280B1F84020C28091F8422067
+:20E9A000027291F84A2002734A88428191F849104173074638466061308B20836189B07E4E
+:20E9C0004FF67F472E46A07607EA0100C108608107D244490A78802707EBC2110843608186
+:20E9E00004E0608940F08000F9E700266089DFF8F880B9F1000FC0F3C21224D10AB38109E0
+:20EA000011D2410909D2C00838BF281C10D31BF038FB00F02000801C0AE01BF032FB00F00C
+:20EA20000F000A3004E01BF02CFB00F07F005F3020810420474660733878202113F0B2F8B6
+:20EA400017E0002515E0022060732068C089C00803D3404634300088208152B160894FF6FD
+:20EA60007F414FF680770140618107EBC21001436181012E32D1667B27893CB3012E0AD0D2
+:20EA8000042E02D0022E0BD020E0042019F060FC062805DB1AE0012019F05AFC082815DC35
+:20EAA000667300202781114960600868002808BF0C6003D00146486830B94C604046007873
+:20EAC000202113F06FF809E00146F4E7606908B116F062F8204616F05FF800252846BDE8A3
+:20EAE000F883C046C1FE0020E4FA0020380501202DE9F04F0C4606460D220021ADF1640D08
+:20EB000014A80FF023FF10220DA821461BF066F94FF0010A002840F0CE8096F82600032891
+:20EB20000DD196F840000EF095F8051C00F0C38096F8402006F141011AF0ACFB00E000256D
+:20EB400096F825004FF000088DF8440040B1022808D112A806F1180108221AF09BFB01E089
+:20EB6000F06A1290726B404611A914AB13F0C1FE96F82500002808BF062403D002280CBF67
+:20EB80000324022496F82610009196F82710019196F829100291C146CDF80C9096F82820E4
+:20EBA000034618A8414617F02FFC834696F82600241DE4B2032805D0022833D196F8400043
+:20EBC0002418E4B220460EF045F85FEA00082CD0074607F801BB9DF8600007F8010B96F8DF
+:20EBE000250038B102280CD1384606F1300152467F1C04E0384606F12C0104223F1D1AF015
+:20EC000049FB06F13401384604221AF043FB96F82600022806D196F84020381D06F1410167
+:20EC20001AF038FBB8F1000F03D1002D43D0A8463EE004A81BF048FA14AF0D230A940DA880
+:20EC4000089706F13C028DF8303096F82610CDF814801B4C049004270992032904F13403C5
+:20EC600018688DF8317016D10695079596F840100B9104A91BF054FA38B996F8402006F17A
+:20EC8000410029461AF006FBCA46284615F084FF606B96F8261002290AD1CDF81890CDF8EC
+:20ECA0001C90CDF82C9004A91BF03AFA00B9CA46404615F071FF504619B0BDE8F08FC046EE
+:20ECC000D4DB002090B50446E08948F20601ADF1240D814211DB81421CD0133800F0AB8099
+:20ECE0001939401A5CD0401E51D0401E00F09780801E21D0401E16D0ADE01A31401A00F063
+:20ED00008480401E78D0401E6CD0123860D0801E55D0A0E0204617F07BFD011C00F09B80E5
+:20ED20004E4B40203AE0204617F072FD011C00F092804B4B202031E06846002118220FF0D6
+:20ED400005FEA06910F8011B8DF800109DF800704278017801EB0221ADF802101FB9C01C3C
+:20ED600001A90DF019FC61883E4B10206A4618F0CDF8039818B115F00FFF002003900598F1
+:20ED8000002868D015F008FF0020059063E0204611F0D8FA011C5ED0334B02200F4606E0B0
+:20EDA000204611F0CFFA071C55D001202F4B61883A4618F0ABF8384615F0EEFE4BE0A06989
+:20EDC0002B4B007807AA8DF81C004FF480003FE0A069284B00780DF11B028DF81B004FF41F
+:20EDE000801035E0A069244B00780DF11A028DF81A004FF400402BE0A069204B007806AA9B
+:20EE00008DF818004FF4005022E0A0691C4B00780DF119028DF819004FF4804018E0684678
+:20EE2000002112220FF092FD204669460BF08EFD144B04200BE0684600210C220FF086FD67
+:20EE40002046694619F05AFB0F4B4FF080706A46618818F05BF809B090BDC0465120020043
+:20EE6000F51F02005BBD01002D1402008F140200DD6E0200AD6E02003D6F02004D6E0200A6
+:20EE80007D6E0200E18A01008D4102002DE9F04F07467E6931780120ADF13C0D00EBC10063
+:20EEA00080B21BF0F9F95FEA000808BF002000F0CB80307800254FF08F0B4FF0860A88F8BB
+:20EEC000000041E06A00B018B0F8010008EBC504641CB21820803968B2F80120087D89888E
+:20EEE00008AB14F039FE01282AD19DF82710C80909D2002031F07F0318BF01207A68C2F336
+:20EF0000C00282421CD1480817D33868490900F1060909D3007D1AF02DFF031C04D0484642
+:20EF200008A90122984700E00020A0709DF8261040B9E1700A98606004E084F802B001E0A4
+:20EF400084F802A06D1CEDB23078A842BADC3968087D7B688D888E1D00240D9697F80AA07A
+:20EF60000C90464631780E95D808254680F0010000F0010B19E0EA00B018B218D778E41CA1
+:20EF8000A4B2401C7FB94168641CA4B229B902880E990C9818F0B8FF02E0C07817F0A0FBD6
+:20EFA0003178001984B26D1CEDB2A942E3DC20461BF072F95FEA000942D00746002527E0CE
+:20EFC000E900701871184978401C07F8011B0188091207F8011B817807F8011B8378ABB9CD
+:20EFE000C17807F8011B416859B90BA9009102880E990C983B4618F061F8BDF82C003F18CE
+:20F0000004E0C0783A4608F033FD07466D1CEDB23078A842D4DC00200090CDF804B0012328
+:20F0200002930390CDF810A00594CDF8189007930E9A0D990C9801F03BF948461BF06CF87F
+:20F0400030461BF069F801200FB0BDE8F08F70472DE9F0410D4680460E220021ADF1200D97
+:20F0600003A80FF073FCA86A417811F01F0F18BF002040F0BD80880924BF01208DF81800E7
+:20F0800031F07F001CBF01208DF81700C80924BF01208DF816009DF816200024012A03D0DB
+:20F0A000287A00B1AC6902E0E87900B16C6934B10DF10E0021461BF06FF89DF81620A98958
+:20F0C000012AADF80C1020D14B4A5778167F27F00100064300F08B80002F00F08880022FA6
+:20F0E00004D11AF0D1FE884240F08180688915F0F3FC00287BD144B11AF09CF801460DF136
+:20F100000E0019F075FF002871D03C4E96F83200800815D39DF81600012811D0BDF80C10BB
+:20F120001AF0B2FE88420BD09DF81700012807D008461AF05BF818B1BDF80C0016F05CFB32
+:20F140009DF81600012821D0BDF80C101AF09CFE884211D19DF81700012808D02848007834
+:20F1600000F00700022807D101208DF818009DF818000AF07DFF35E09DF817209DF81830F7
+:20F1800008460DF10E0107F051FE2BE000249DF818008DF81A40E0B99DF8175007461AF027
+:20F1A000BFFC96F84A00082818BF042811D14FF6FD70ADF800001AF03DF801908DF80940B2
+:20F1C0008DF808708DF80A508DF80B4068460DF005FB9DF818000AF04BFF52200DF11A015C
+:20F1E00016F01AFA0748016809B103A88847404608B0BDE8F081C046ACFE0020E4FA0020E7
+:20F20000E41201208CFD0020F0B50C460546A9792068ADF1440D40EA01406979206040EA5C
+:20F22000012029792060084310F0070F206015D000F00701022920D14FF0FF30606005F18D
+:20F240000801082204F108000FF0C5FE04F1100005F1080101220FF0BEFE0DE0201D05F1BA
+:20F26000080104220FF0B7FE04F10800FF2108221BF014F8FF202074206841097AD2410932
+:20F2800011F0030F18D001F00301032914D0012918BF022922D104F11100FF2108221AF0F5
+:20F2A000FDFF4FF6FF7005F108010222608304F11C000FF090FE10E004F1110005F1080105
+:20F2C00008220FF088FE04F11A0005F1080102220FF081FE4FF6FF70A083206800093ED356
+:20F2E00004F11E0005F1080101220FF074FE206805F10806C10B3CBF4FF0FF31216206D34A
+:20F3000004F12000314604220FF065FE2068000C06D204F12400FF2110221AF0BFFF05E055
+:20F3200004F12400314610220FF055FE2068410C3CBF4FF6FF71A18606D304F13400314694
+:20F3400002220FF048FE2068800C38BFFF200ED304F13600314601220FF03DFE2EE04FF0ED
+:20F36000FF312162FF20A0774FF6FF77A78684F8360023E000252846694618F025F90A286D
+:20F380001CD00D2817D0276817F0070706D10DF10600211D042219F0DDFB48B9022F0AD194
+:20F3A0000DF1020004F11101082219F0D3FB10B1684619F084FB6D1C052DDCDB11B0F0BD6E
+:20F3C0002DE9FC4F83F0004301E02DE9FC4F1F03FF0847EAD2574FEA42284FEA43095FEAE0
+:20F3E000595906D147EA080A1CBF00210020BDE8FC8F57F000575FF4E06E1EF1FF0EF14564
+:20F4000005D14FF00000190D0905BDE8FC8F002B05D55FF0000AD8F100086AEB07070C03D2
+:20F42000E40844EAD0544FEA40254FEA4106760D08D144EA050A19BF00210020191C101C5D
+:20F44000BDE8FC8F44F00054764504D10020090D0905BDE8FC8F002904D55FF0000A6D42E6
+:20F460006AEB0404B6EB090E08D5A2463C465746AA464546D046CEF1000E4E46BEF1360FAD
+:20F480005CBF4FF0000B23E0BEF1000F04BF4FF0000B1AE0CEF1390ABAF120092EBF08FA7A
+:20F4A00009FB07FA0AFB4BEA080BDEF1200A07FA0AFA38BFBA4647FA0EF72DBF28FA0EF8AB
+:20F4C000AEF1200E4AFA0EF8D04415EB08057C4154EA050A02BF00210020BDE8FC8F002C8C
+:20F4E00058BF4FF0000A06D55FF0010A5FF0000E6D426EEB0404A6F101066D006441FAD58B
+:20F5000015F4806E11D005F480794BEA090B15F5806554F1000428BF761C0BD205F40079D8
+:20F520005BEA090B08BF25F4006525F4E0656D0044EB0404B61CDEBF00210020BDE8FC8F4B
+:20F540005FF4E06E1EF1FF0E76450AD34FF0000013F00043FF21C900C91D09051943BDE8F3
+:20F56000FC8F270547EA1530210B41EA065141EACA71BDE8FC8F704767492DE9F04705461B
+:20F580000878ADF1580D002800F0C280A878884610F007008DF844000FD0022840F0B8805F
+:20F5A000A96812A808221AF079F8A96801F10800A86090F800A009310EE0A968CA780878A5
+:20F5C0008F784E784FF0000A00EB0260091D00EB074000EB062012900846491CA9604C1C99
+:20F5E0000F460678AC603C78E32E18BFF32E05D19DF844101298084340F08A8004F1180074
+:20F6000080B218F06AFF071C00F08280FF2C08BF002487F810A04FF0010987F80390A96881
+:20F6200007F1170022461AF039F8BC75381D11A90C227E741AF032F8484616F01BFBB874AE
+:20F640000520387000267E70A878000903D3F87840F02000F870314CAA8804F13A01D8F8F3
+:20F6600010000988914215D011A869460DF1520210F06CFB60B99DF80000800808D3694650
+:20F68000087800F0FD000870BDF8520013F0CEFEBE7038E010B18047002839D088F801909F
+:20F6A00011A8694614AA10F051FB60B99DF80000800808D26946087840F002000870BDF83A
+:20F6C000500013F0B3FE87F8029094F83C1088F80410A8790B30814215D0114E306A1AF0A2
+:20F6E000A0FB40B9306A41F288311AF005FD06F1BC001AF08DFDA87904F13C010B30087097
+:20F70000E12015F089FF07480078394613F0C4FF16B0BDE8F087C04620040120E4FA002024
+:20F72000481900209C0301202DE9F043002407460C22ADF1340D214668468DF814400FF0D4
+:20F7400005F9624DDFF88881B87804281DD001280BD0062809D0022805D003281CBFB320F0
+:20F760008DF8140014D11B2010E0687858B91AF055FD40B9B9684646082206F11C0019F0A7
+:20F7800089FD38883080232000E022208DF804009DF81400002840F086803888BE7BADF8E0
+:20F7A00000003B698DF805607A7B0293012A14BF012021208DF80200684605F06DFE9DF8A7
+:20F7C000140000286FD10398466C05233370B8787070796829B9B01C214610220FF0B6F8B0
+:20F7E00003E0B01C102219F055FDB8781236012812BF0628F87806F8010BB96830461AF012
+:20F80000DFFAB8780836042806D0012804D006281CBF387B307004D1AB202146324613F0C4
+:20F82000A3FE388815F058F910B103980421C1829DF81400002836D1B878042809D038699F
+:20F8400018B9684615F0A8F82DE068460CF032FD29E0B8680BA906AA0EF0FAFF06469DF839
+:20F860002C0018B94FF6FF70B0421CD038694FF0010918B9684615F08FF802E068460CF078
+:20F8800019FDB96808A8082219F004FD8DF8289020468DF8294031461422079006AB069031
+:20F8A000042016F0CFFE687850B91AF0B7FC38B946462146082206F11C000FF047F8348098
+:20F8C0009DF814000DB0BDE8F083C046ACFE002070020120F8B5694C21680546143108685C
+:20F8E000407F002800F0C880D1F8C000B5F84220C08C904240F0C080D1F8581305F1280071
+:20F900008847002800F0B880206840690026467721687031486E90F8290028B16068816A97
+:20F920000220884721687031086890F82B0018B16068816A01208847287C400908D360688D
+:20F94000816A102088472068D0F82813802088476068C16B202088472168C868D1F8FC142E
+:20F96000103088476868226841785269007800EB0120C0F30321517622685269C0F3003759
+:20F9800097762268526900F00F03C0F3031793772068D0F8D40080F82C7022680C32D2F872
+:20F9A000C81091F84F000F2806D093689B7F984202DD6B68DF780FB19068807F48731068A8
+:20F9C00080F83060D2F8C800417B0F290BD19068C07E022850D1D2F8580180472068D0F802
+:20F9E0006C018047F8BDD2F800252846904723680C339868C07E022815D1D3F8F014186883
+:20FA000088472268D2F8D4001169467BD06831F81630D2F8F0244FF4707707FA06F1C91A2A
+:20FA2000904723680C33D3F8C8002A89D3F8A83190F82C1002209847206800F11401D1F81F
+:20FA4000C020D0F8D400527B90F82C0082420FD00868D1F8E81488472268D2F87C01516977
+:20FA6000886050694169D2F8F024904721681431D1F8141310208847F8BDC04614010020D9
+:20FA80002DE9F047634F8046381D0068416EADF1280D02A888475B4D2A684032106800685D
+:20FAA00020B9D2F80C0580472A68403256484FF001096E6880F80090F068007830B9D2F87F
+:20FAC00018244846002190472A684032106801684C68088921788246C1F3401109F096FF46
+:20FAE000079011F0B7F8494E746786F873A00024A6F866401AF06AFB059482463146B8F164
+:20FB0000010FA6F8664004BF4148C1F8B80038F001083E4654D1A1F89E4001F16400C1F874
+:20FB2000A00091F8A90002231A4602F00F0220F00F00024381F8A92091F8A80004F00F078A
+:20FB400020F00F0047EA000291F8B3708C6627F00F0081F8A82040F0040009F00F0291F887
+:20FB6000717081F8B30027F00F00024381F8712028684030006800684268127801F16407A2
+:20FB800092090FD301F120028A66406891F87150807803F00F0381F82E0025F00F000343E4
+:20FBA00081F8713001F1100001F19C0242604A7F04F00F0322F00F0213434B77014601E0C5
+:20FBC00064310F467068174A056D08238DE81800114B106802AAA84710490028088006D486
+:20FBE0000F4991F90000B760401C087004E0484641F2883111F05AFA50461AF071FC0AB0BE
+:20FC0000BDE8F087140100200F05012050180020801A0600DCFF002045BA000028050120EE
+:20FC200012050120800001202DE9F8430D4606466868002800F0C580007819F04DF90028DF
+:20FC400040F0BD8019F0DAFB052880F2B6804FF00008304685F8018019F030F9041C01D0A6
+:20FC6000207B60B11C200CF0F5FF041C00F0AB8041461C220EF06AFE2671012600E046461C
+:20FC80006868007820736868007A504F2076142027610CF0DFFF0028606141D041461422BD
+:20FCA0000EF054FE6968626949689079897900F0F00001F00F010143917168684068616933
+:20FCC000808888806868406861690078087068684068616940884880686840686169C07995
+:20FCE000C871686840686169007B08736069C07940000CF0AFFF616988606769B86818B13C
+:20FD00004046F97981424EDC387B40000CF0A2FF3861606907691FB14146027B8A4238DCE8
+:20FD200004F10C00814608F00FFE0746022F18BFB82F06D1207B13F0B9FD484608F004FE07
+:20FD4000074637B9012E1FD1204615F05BFFC0B11AE0012E15D0606968B1816819B1084620
+:20FD600014F01AFF6069016919B1084614F014FF606914F011FF4846414610220EF0E6FDFF
+:20FD800002E020461AF0C0F9022F18D0B82F16D019E06B685B684A001B690069D35A13521A
+:20FDA0006069491CB9E76A68526841009268BB688A5ACA526769401CA3E7D12002E0D02012
+:20FDC00000E0022068700120BDE8F8832A1A00202DE9F04FDFF898910646A9F1080000F170
+:20FDE00008078068D0F80001807AADF12C0DC0000CF030FF0028089008BF1A2500F0B4809D
+:20FE00001AF0E4F900244FF0FF0B25460A9027E0ADF800608DF80240D2F88823D0206946A2
+:20FE20009047D8B99DF80C00012802D19DF80B1019B998B99DF8071081B1002814BF0823E6
+:20FE400004230DF103005B1E00F801BBFBD105703868D0F894246946D0209047641CE4B260
+:20FE60003A6802F580721068C07AA042D0DC4C462068D0F80001C0884FF6FF78AA461DE0E3
+:20FE8000089901EBC0018A8896421CBF401CC0B261D1C1F800A0A1F804803A68D42004A996
+:20FEA000904702E07F1CBFB225E020682268D0F800016D1CEDB202F58072C088A842D8BFC3
+:20FEC00055464BDDADF80060ADF80250D2F88823D120694690470028E7D1BDF80400804519
+:20FEE000E3D0ADF810002068D0F8882404A9D420904790BB5746226802F580721068C0880B
+:20FF0000B84210DDADF80060ADF80270D2F88823D120694690470028C4D1BDF81000BDF8BB
+:20FF200004108842BED12068D0F80001C088B842BBD1ADF81480ADF8168006A8594608224A
+:20FF40000EF004FD2068D9F8003000F29447D3F80001837A5046834292DC19250A981AF0D0
+:20FF6000BFFA089814F018FE28460BB0BDE8F08F140100202DE9F04F654CE768ADF1140D78
+:20FF8000002F00F0C2804FF0000A5046039094F8028004903DE094F8028035E00A200CF086
+:20FFA00059FED4F80C80071C00F0AF8019F0BBFB0BEB0800808805EB080104220E31388075
+:20FFC000B81D19F067F9049D3A88029948466B460CF040F8012808BF0125284604F11805DC
+:20FFE00020B10199B81C042219F054F9B000394600EB061040190C3015F02CFB012800F03C
+:020000040001F9
+:200000008480204690F80280E7680AF101005FFA80FAD04579DD16201AFB00F5E919785DCC
+:2000200049888146029116F087F9AB460646FF2EB4D12278002F8C46E7D004984FF6FF7678
+:20004000B646014615E0162310FB03F5EB197D5DA9450CD15D88AC4509D1DD88AE42C8BFF7
+:200060002E1C1B89491CC9B29E45C8BF9E46401CC0B28045E7DC0029C7D0042A45DC90006F
+:2000800004F11805634600EB0210291881F80190DDF80CC04B8007198E80521CA1F806E0D6
+:2000A00007F11803A1F808C066461E6131461973D7B229540A2027700CF0CCFDE668071CA1
+:2000C00023D019F030FB06EB0B018888042238800E31B81D19F0DEF83A88029948466B467F
+:2000E0000BF0B8FF012804D10199B81C042219F0D1F82178880000EB0110401939460838B5
+:2001000015F0A8FA01287FF446AF05B0BDE8F08FF00C01202DE9F04160485F4E614C604DBB
+:2001200070601030B06004F14400B0E88C1005F17C01A1E88C108DC881E88D00182204F120
+:20014000140705F1340039460BF0D0FC1822394605F14C000BF0CAFC05F16407182238463F
+:2001600004F12C010BF0C2FC95F870003C2204F1840140F0800085F8700005F1BC000BF085
+:20018000B5FC95F8CB100120024602F0010221F001010A4385F8CB2095F8CB1060F38201E2
+:2001A00085F8CB1095F8CB1021F0200185F8CB1095F8CB1060F3C71185F8CB1004F16401B0
+:2001C000B1E8085105F19C02A2E8085191E80A5082E80A50C5F8A07095F8A81060F3C711E2
+:2001E00085F8A81095F8A91021F00F0141F0020185F8A910042385F8AD30052185F8AC1019
+:2002000095F8AE1000F01F0221F01F010A4385F8AE20032185F8B01095F8B31000F00F0207
+:2002200021F00F010A4385F8B320B4E8841005F12001A1E8841014CC81E8140095F82C1076
+:2002400060F3C71185F82C1095F82F1003F00F0321F00F010B4385F82F3095F82F1060F37F
+:20026000C71185F82F1095F82D1000F00F0021F00F01084385F82D004FF4586028630A4833
+:20028000F0600A4800684069007808B10CF056FC0AF0A4FDBDE8F0817000012038FA002098
+:2002A000501800208CB4020068050120180100202DE9F04F09AF9A4690468146ADF1240D54
+:2002C000B7F814B0BE89069119F0ECFC0028079008BF022000F0B38019F054FD0446E00984
+:2002E00008D259481830056825B1687E012808BF44F0400404A80021082219F0CFFF3D7827
+:2003000035B904A90868002220F00300086006E00498012220F0030040F001000490079819
+:2003200085683DB16888534641460090484615F0D5FD08B9012082E0002E04BF0498C0F359
+:20034000800607D004A90868ADF81460012640F0040008603D7925B904A8016821F0080184
+:2003600003E004A8016841F008013D7A016025B904A8016821F0100103E004A8016841F0F5
+:2003800010010160387C8DF817A0002E8DF8160014BF05200320584480B2814619F07CFFFE
+:2003A000061C4AD0049901F003010170049AC2F3800241EA8201C9B20170049A02F00802F5
+:2003C00011430170049A02F01002114300F8011B0499C90808D39DF8141000F8011BBDF883
+:2003E0001410091200F8011B9DF8161000F8011B9DF8171000F8011BB9695A4619F04EF9F9
+:20040000387F68B90F480096811C01910294007803900799069842464B46FEF791F907E08A
+:20042000009601940698079942464B4608F072FE0446304619F070FE00E01024204609B068
+:20044000BDE8F08F800301208003012001282DE9F84F40F0B080DFF88491D9F8340101282F
+:2004600040F0A6800220C9F8340118F01DFC012015F070FC5FEA000805D00120C9F834011E
+:2004800018F020FC99E0112019F052FD00280CBF00250125102019F04BFD08B145F0020582
+:2004A0000F2019F045FD08B145F00405444CA06A0068014601208847012805D099F83801CA
+:2004C000012818BF002703D1002004F021FD012719F028FDDFF8ECA040080AD20026206A62
+:2004E00080680146504688478346BBF1040FF6D000E00126304600214FF0FF3202F0DCF846
+:20050000012E0ED0BBF1010F05D1206A4068012102465046904732496C39086840F0030070
+:200520000860206840690146284688470B2019F0FFFC254E30B12068C06A3146091D024684
+:20054000088890470A2019F0F3FC28B12068C06A31460246088890471C4903200124C9F8F3
+:2005600034011B4E0C6000233360284613F048F80128FAD1174D2868042015F0EBFB0646C7
+:20058000154804602868012F02D1204604F0C0FC19F09EFC082015F0DDFB0746C9F83441C6
+:2005A00018F090FB57EA060018BF4FF0FF3804E06FF0040801E06FF001084046BDE8F88FCA
+:2005C000B8010010004003401ABD0200282008600C2008402C2009400C4009401015002063
+:2005E00090220840F8B5074661485F4C001DC26A0168B7F5C067C2F30722C4F81071C1F35F
+:200600008441C4F81421C069C4F81811C0F38120C4F8280100F0A38094F830616EB9C4F8CA
+:200620002C71D4F81801C4F82001D4F81461C4F81C61D4F82851C4F82451D4F82C01D4F8A6
+:200640001451002854BF02236FF0010304F59072116800EB4000C018431000EB937001EBCE
+:20066000A0011160D4F82011C4F81C5100291CDD1E293DDDD4F8240130B93429B4BF1539C7
+:200680001E21C4F8201125E02A29BABFD4F820010B381E20C4F82001D4F81C013E28D4BF30
+:2006A000401C3F20C4F81C011FE0D4F82401032812D011F10A0FA6BFD4F820010B300120E0
+:2006C000C4F82001D4F81C010028CCBF401E0020C4F81C01032009E011F1140FA6BFD4F8E8
+:2006E000200115300120C4F820010020C4F824014FF08057D7F8A401B4F81C111B4D406822
+:200700004FF47F4208230646009128463021B047D7F8A40101214FF400321123406800919F
+:20072000064604212846B047D7F8A401B4F8201140684FF4F8021223064600910421284608
+:20074000B047D7F8A401B4F8241140684FF440620A230446009120212846A047F8BD00204D
+:2007600084F83001F8BDC0461015002000A00C4000A00C402DE9F8435F4CDFF868815B4D90
+:20078000D4F83C0100286ED0574E401E0AD0401E60D0401E1CD0401E53D0401E1AD0401E0E
+:2007A00033D02FE04E4801250221006884F83A517022042340680091002107464046B847F4
+:2007C000356004F1500019F0F7FC2846BDE8F883022100E003214FF08059D9F8A40184F884
+:2007E0003A1140680025702204232946074600954046B847D9F8A401C0687022294613465A
+:200800000125DAE70320BDE8F88300262E606E6028688008FCD268688008FCD23748344924
+:200820000127001D06600E200F6008F057FE022016F044F9C4F83C6184F83B610220BDE886
+:20084000F8830520C4F83C010027376030688008FCD242E00320C4F83C01002737603068BF
+:200860008008FCD239E0234F01260F202E6042F62A21C7F80B004FF08059C7F80F10D9F89F
+:20088000A40140684FF4C072072302218446404600910021E047D9F8A401C06800214FF41E
+:2008A000C072072384464046E0472E6028688008FCD394F83901C7F81B6018B903210020DB
+:2008C0000E4602E0002028630321C4F83C6147F8011C686068688008FCD20020BDE8F88330
+:2008E000A401001000A00C4058600C4054600C4004800C4001400C401015002038500C40DD
+:200900002DE9F0410D46044602220021ADF1480D11A80EF01BF800263046694616F054FE4E
+:2009200007460A2F00F0AD800D2F32D094F825809DF8000008F0070100F00700884227D157
+:20094000B8F1000F0BD104F12C000DF10601042218F000F918B1E06A6860002015E0B8F11D
+:20096000020F16D104F118000DF10201082218F0F1F870B105F1080004F11801082218F0F7
+:200980008DFE94F83000287402208DF8440005E00227761C052EBFDB002F72D19DF8000015
+:2009A0009DF844709DF801609DF80D30C11007F007009DF845209DF80D7001F018010143FD
+:2009C00006F0010094F8296041EA401103F00300002E41EA80118DF8441002F0F800C7F332
+:2009E000820141EA00018DF8451007BF9DF8450000F0F7009DF8450040F008008DF845000B
+:200A00009DF84510676B94F838602A8841F050016F619DF844002E7601F0DF0110432880A9
+:200A200040EA0120288094F840008DF8451050B1687619F031FCE86128B194F8402004F105
+:200A4000410118F02BFE104894F9151000880829288405DC11F16D0FB8BF6FF06C0100E032
+:200A60000821A77D6E3148B2002F4FEA60010CBF00220222C8B285F8220040EA821085F864
+:200A8000220012B0BDE8F0811EFB00202DE9FE4F5B4C5C4994F83C80B4F848500A688346AD
+:200AA00001A8026049684160DFF85CA101A80AF11409494618F09CFA00280CBF01260026D7
+:200AC000A76887B11EB93888854206D008E007F10C00494618F08CFA10B1B878804502D00A
+:200AE000BF69002FEED1002F08BFCA2000F0858039894FF6FE70884208BFC3207DD019F0CC
+:200B0000D5F9884208BFC22077D03888A84218BFA4F8480017F094F9F87A4946401C84F87B
+:200B20005C0004F15D0019F037FB02208DF80100684617F069FD04F12405061C58D0306908
+:200B4000062100F8011B94F8321001704FF0010986F81E9018F06EFB706286F81A904020DB
+:200B6000F0823889708086F818B03046FBF784F8061C3ED1092084F84A003B89E38794F84E
+:200B80003C00804518BF84F83C8005F11A014B2014F042FD05F12401502014F03DFD05F1C7
+:200BA0001801E12014F038FD05F11601532014F033FD082049460AF063F94FF4005000216D
+:200BC0000AF05EF920784FF4806111F0A9FB0F480078022804D008200FF0C2FC820001E04E
+:200BE0004FF4DC6220784FF4806119F0B4FA00E0102600208AF805003046BDE8FE8FC04696
+:200C0000E4FA0020E0B8020034FD0020ADFE00202DE9F043054603200C46ADF1340D8DF8B3
+:200C20001E000DF1160019F0B7FA18F003FB01460DF1160018F0DCF9002800F08980207DCC
+:200C4000032818BF012840F08380277A002F7DD0FE2F7BDC032804D1A07D002876D0FE28E4
+:200C600074DC45490A6809A8026049684160DFF80C81082209A908F10C09484617F004FDDB
+:200C800028BBAE1C3E483188008888421FD040460178FF2909D0B94207D040884FF6FF71D8
+:200CA000814202D06189814211D100208DF808004946082203A818F0EDFA02A80FF026FD44
+:200CC0003088BDF80A10884218BF8D2042D12D48EB890768AE1C212B11D02B48076867B1E3
+:200CE000207A6189A37D04F10C02B84728B900208DF82C0016F0B4FF2EE088202AE08C2077
+:200D000063898DF82C00ADF822302FB30DF122000090A27D207A04F10C010123B847D8B146
+:200D200000278DF82C7016F09BFF207D032813D104F10C0008A915F019FE04F10C0858B937
+:200D4000394640460A4610F0F5FC05E0822000E08420AE1C8DF82C000BA80090287C01904F
+:200D6000EA893146012305F1110042F4004213F07DFC0DB0BDE8F083B8C3020094FF002065
+:200D80001EFB002000030120BC0001202DE9F04F0446E078ADF11C0D400810D304F1130028
+:200DA000FF2103220DF0D2FD012001904FF0000903902079CDF8089030B1022801D00120A2
+:200DC00099E00820009005E00427E078009700F0DF00E0704F464A48039E0497C8460597B7
+:200DE00000F1100B069660E04FEA88005BF8007000EB0B0A002F52D025793E79B5424ED1CB
+:200E0000009A07F1080004F1080117F03DFC002845D0A3785BB9022D06D1E078800903D3D1
+:200E2000387C217C88423CD1069F02970FE0DDF818903EB1E078800906D3387C217C88421C
+:200E400002D02EE04F460297B9F1000F24D0042017F043FB071C1FD00498787006263E70FE
+:200E6000DAF80000807CF870DAF8000017F01CFC0598B9F1010FCAF800001CBF0420B8700B
+:200E800005D10698B870059E0396CAF800401B480078394612F000FC029810B12AE0CDF8F6
+:200EA000048008F101005FFA80F8B8F1000F9BD0029D45EA0905012D1CD0042017F00DFB97
+:200EC000011C17D0059806224870019F0A70A27CCA7057B9A078012818BF042005D138467F
+:200EE0004BF82040059A0392022088700348007812F0D2FB039807B0BDE8F08F9C03012039
+:200F0000481900202DE9F84F534D2968D1F8D40090F883A040310868006820B9D1F80C057E
+:200F2000804729684031886F4C4EDFF83491DFF834810078E8B919F049F9377883464FB94B
+:200F400049460F7837B9832041460870584619F0C7FA60E002214046BAF1010F017004D197
+:200F60003078832801D110F08DFF584619F0B8FA65E014F023FC3C4800683C4F016C38687B
+:200F80008847044619F022F9824630460778002F44D149460F78002F40D12868D0F8B800AD
+:200FA000C16C002088472868D0F828246946F42090479DF90000A0421EDC2D4CA079D8B942
+:200FC000504619F08DFA6078042803D02868D0F84C05804704204146A7792E680870781C37
+:200FE000A071D6F8B800C16C09B103208847032060810FF0C7FD22E08320414608700020F6
+:2010000015F09EFA504619F06BFA1A486968C01D09690078087017F019FA10E00222414608
+:201020000A700078832801D110F02CFF504619F057FA2868D0F8B800C16C04208847686826
+:20104000C068007828B92868D0F85824002001469047BDE8F88FC04614010020051401205C
+:20106000071401200A140120E0FF0020800001204C0201204D0201202DE9F0410646746807
+:20108000B56819F0A3F8D4F8C0108046002900F0A18094F8F80028B9087C032818BF0428DC
+:2010A00040F09D80287919F093F8D4F8CC0041686F690968CF6294F8F90018B92968C868DC
+:2010C0004009FCD22968486820F002004860D4F8CC0041682F690968CF622968486A20F030
+:2010E00003004862D4F8CC002A6941686B69096843EA0200C1F804052968486920F00100E6
+:201100004861286801270762D4F8D400D4F8C0100860D4F8D87067B1E8698068C0F3091030
+:20112000401C874205D3D4F8C0201168C919091A1160D4F8DC7067B1686A8068C0F3091061
+:20114000401C874205D3D4F8C0201168C919091A1160304610F00CFE287919F033F8287901
+:2011600019F038F8D4F8C070386857B100230222397C03291CBF04293A743B607F69002F02
+:20118000F6D1D4F8C0100860D4F8C8100022002904BFD4F8C000C4F8C80004D04869B8B9CC
+:2011A000D4F8C0004861C4F8D020C4F8D420C4F8D820C4F8DC20C4F8C020C4F8C420404670
+:2011C00019F08EF904F1300019F020F8BDE8F0810146E3E72968486820F002004860404691
+:2011E00019F07EF9BDE8F0812DE9F0418046D8F80460D8F80050307817F0CAFC7178002773
+:20120000814249D02879401E28D0801E1FD0801E012803D9001F14D0801E35D1287C10F080
+:20122000120F08BF02240AD00324AA69E96928682C71891A18F0BEFF286818F0BDFF2C71B4
+:2012400022E0287C800928BF20270A201DE00421287C2971800828BF022717E019F044F9D2
+:20126000297CA860480828BF012711F0120F0BD00322AB69E96928682A71C91A18F09AFF2B
+:20128000286818F099FF01E0022028717078002850D0012851D055E02879401F26D0401E7F
+:2012A00017D0801E08D0C01E3ED10721287C2971C00828BF042739E0A86818F0BFFB297C14
+:2012C000E860C80828BF0427080928BF47F008072AE0A86818F0B2FB297CE860480928BFB2
+:2012E0001027C80828BF47F004071DE0287C80090ED2A86818F0A2FB07212971297CE86050
+:20130000C80828BF0427080928BF47F008070DE00822AB69296A28682A71C91A18F04AFF90
+:20132000286818F049FF01E007202871707820B1012807D14FF4A02101E04FF4C0213078C1
+:2013400015F074FF2FB1686918B10246394640469047BDE8F08170472DE9F043584C94F831
+:201360004201ADF1140D002840F091804A484B4E4FF00108027B3368416884F842818146C8
+:2013800084F84121C3F38147C4F86C11BFB9D9F81000A0B156F8085C18F06AFD6421024620
+:2013A000C5F306604143B1FBF2F23D49002304F1940013F031FB3B494FF00040086001A886
+:2013C00018F04BFE00252F4604F10C00029501AB8DF80470344903953A4613F01DFB01A88C
+:2013E00018F03BFE04F150000822029501AB8DF804702E49039513F00FFB2D4A04F1D800A1
+:2014000032213B4613F0C6FE2B4A2A4F04F1F4002C212B463D6013F0BDFE306899F80D30DB
+:20142000C0F381501BB1032803D184F8398103281FD002281DD001281BD14FF08059D9F8F8
+:20144000A4011E4C406803214FF040521C230746009129462046B847D9F8A4014068294662
+:201460004FF4007209230746CDF800802046B84706E0386840F040003860022015F036FBAE
+:2014800056F8040CC00802D2284615F02FFB05B00020BDE8F083C046FCC10200B44F0050B0
+:2014A0006595020000A10C404F510100553D0200917E02009022084095F2010000A00C408F
+:2014C000101500202DE9F04F044608469A46ADF1240D214605908E680692129B04914C68AB
+:2014E000756807935044854238BF6FF00304C0F093804B4D28684FF0FF3118F008FB4948C7
+:20150000328C079F48496368026083460B60780819D23846800813D3F768002F3AD03569E8
+:20152000002D37D000970195012002900599069A049853460DF0ACFB5FEA000813D114E057
+:201540004FF0000811E0A0683AEA00070AEA00021CBFB1680A4405990140049808F010FB6A
+:201560005FEA000801D0044652E034680598DDF818905746241805E0BBF80010049818F0F2
+:20158000ABFAA944AFB90798C00840D3F16809B1306910B96FF007043AE000910190002795
+:2015A0000297069A0599049853460DF071FB80462DE0049810F0BCFF38BB049814F00AFFF0
+:2015C00018BB04F0FF05C5F58075BD4288BF3D1C210C8DF80D1002208DF80F40230A8DF87B
+:2015E0000C00BBF8001004988DF80E3018F06BFA03A8042111F0DAFD7F1B641928B9484622
+:20160000294611F0D3FD0028B6D04FF0FF3844460348006818F0F0FD204609B0BDE8F08FF1
+:20162000A8130120A4130120A0130120F0B50446207CADF13C0D0F28C0F2A680656860690B
+:201640000DF1260210F07AFC9DF82600002840F09B80207C0B28C0F29780287A022840F02C
+:201660009380A88900F00F010F2940F08D80C0F303100F2840F088809DF82860002E18BF5A
+:20168000022E40F08180424C404894F84A20022A3BD00068062A39D010B18179012935D01B
+:2016A000082A18BF042A6FD16D8910B18079022827D0B4F84800854266D1012E07D004F1F5
+:2016C0005D000DF12D0117F093FC00285CD120784FF4007113F040FA002855D1E06C0290E1
+:2016E00001268DF80D6002238DF80E3094F852708DF80C7002A80FF08DFF10B114F0FEFCA6
+:2017000042E0284615F0B8FF3EE0006840B900230093288869896A7C04F054F89DF8286063
+:201720002888ADF810006889ADF81200A87B8DF81400AF8900206FF30E0707B101208DF8B3
+:2017400018608DF815009DF827408DF819409DF82C708DF817709DF82A009DF82B308DF82C
+:201760001600687C0DF12D018DF81A009DF838608DF81B3008228DF81C600DF11D0017F05A
+:2017800089FD04A804F036FD0FB0F0BD38040120E4FA00202DE9F04380460E20ADF1340D0D
+:2017A00015464FF001098DF80100B8F1000F8DF8023050488DF8005000F1010000788DF834
+:2017C00004900F468DF8030047D1112004A93A2218F00BFB00283CD1444E0DF111007B19CE
+:2017E0009DF80320716803901C4642F02802481C7060581C227017F041FD054617F01AFD1F
+:201800000146284618F0C8FC48460DF131013A2218F0EBFA083500280CBF9DF8310000202A
+:20182000287017F007FD01460DF1210018F0B4FC7088401C80B27080B0F57A7F02D8706821
+:2018400001282FD12A4800784FF4007110F0AAF928E000207C19039024E07C19ED19687B4C
+:2018600011F054FC3A2808D03B280FD1112004A93B2218F0BAFA30B108E0112004A93A22A0
+:2018800018F0B3FA10B90DF1110000E0002003909DF80300217808432070611D0DF121007F
+:2018A00018F07AFC0DF12900611C042217F0F2FC039E2078002E8DF82D0008BFA12012D068
+:2018C000404669460DF121023B4604F009F9054620780021102200F0F80020700DF111007E
+:2018E0000DF034F828460DB0BDE8F083480401203BFD002013FB00202DE9F047564CA4F105
+:20190000080000F108058068D0F80001807AADF1280DC0000BF09EF90028089008BF1A242C
+:2019200000F0958018F052FC8246286800F59162D0F8000100894FF6FF780026C14608E0E9
+:2019400020682268D0F80001761CB6B202F591620089B042D8BF002473DD2068D0F80001F1
+:20196000C07A0127002548E0ADF81480ADF8168006A8FF2108220CF0E9FF2068D0F8942460
+:2019800004A9D42090472068ADF80480D0F894246946D12090472068D0F800012268C08804
+:2019A0006D1CEDB202F5916230E0ADF800608DF802501268D02069469047A8B99DF80C0037
+:2019C000012810D19DF80B0068B90DF102020820002112F8013FFF2B03D1401E01F1010157
+:2019E000F7D10829ACD0002720682268D0F800016D1CEDB202F59162C07AA842D5DC002F5A
+:201A00009ED12068D0F80001C0880025A84297DDADF80060ADF802501268D120694690474E
+:201A20000028B8D1BDF804008145B4D0ADF810002068D0F8882404A9D4209047002893D03E
+:201A40001924504618F04CFD089813F0A5F820460AB0BDE8F087C04614010020574B2DE9F3
+:201A6000F0475879002840F0A5800020012116F07BFF002800F09E800668002E00F09A8043
+:201A800007464089C1096CD2984698F83210890872D3326A51791479400B04EB01242CBF65
+:201AA000402500253868B7F818900088824613F013F8002846D15046032112F0E7FE00283F
+:201AC0003ED15046002113F02FFD29460DF090FC061C31D07079012806D0032824D00428C3
+:201AE0001FD14FF6FE702FE0B179708811F0180F10D0FF21A042317105D0484503D04FF6EC
+:201B0000FE71814209D1204649464FF6FE7205F041FF02E098F8381031714FF6FE71814207
+:201B200008D17079022807D05046072112F0AEFE10B105E0824603E0504616F025FE03E083
+:201B4000504601E04FF6FF70844202D0398B81420ED1386801880222002320460DF000FA8F
+:201B60000AE038680088034612F0B6FF30B918464FF6FE71814203D1CD2111E04FF6FF702E
+:201B80003968088012F0A8FF00280CBF012000203968C8810849386809F0A8FB011C04D0D7
+:201BA0003868407B12F0CEFA20B91FB138460121FCF7B2FEBDE8F0878D5D0200E4FA00200E
+:201BC0002DE9F04F0446656928780026ADF12C0DB0468DF824000DE03918C978401CC0B20F
+:201BE00002F8011B74E09DF82400761CF6B2401C8DF824006878B0420EDD216809A80090FC
+:201C000008AF01976368E27A087D8988C3F3C0030CF026FA0028E6D1F01C80B218F03CFBC7
+:201C2000071C7BD006B3287845468DF82400216809A8009008AB01936368E27A087D8988DB
+:201C4000C3F3C0030CF00CFA68B19DF822009DF824307919761E05F10105C87003F1010001
+:201C60008DF82400E3D1A846216809A8009008AE01966368E27A087D8988C3F3C0030CF0D0
+:201C8000EFF900280CBF012000203870E07A87F8028078702168666808F1010501F1060BE4
+:201CA000087DB1F804A0A47A0A90F00880F0010000F00109E8B2804618F0EEFA051C08BFFF
+:201CC000102624D002463878002602F8010B3046B978814280DC7878112803D0132813D1D5
+:201CE000142300E012230096CDF804900120029003960494CDF81480069507900A985946F9
+:201D00005246FEF7D5FA0646284618F005FA384618F002FA002E08BF012000D000200BB063
+:201D2000BDE8F08F29282DE9F0410EDC29285FD0203800F09A80401E00F08C80401E7ED015
+:201D4000401E71D0401F61D007E02A3845D0401E38D00E3820D0401E02D00020BDE8F081F4
+:201D600093E8600091E880010CCA284631460BF091FC4FF0000403D828461E46154601E01F
+:201D80001946104633462A46FDF71AFB43463A460BF080FC74D872E093ED000A92ED001A5B
+:201DA000D1ED000A0024B4EEC10AF1EE10FAACBF30EE410A31EE400AB4EEE00AF1EE10FA2F
+:201DC0005EDB5CE018680B68116800248142D4BF411A091A8B4253DC51E018680B68116891
+:201DE00000248142D4BF411A091A8B4248DC46E0B3F90000B1F90030B2F9001000248142AC
+:201E0000D4BF411A091A8B423ADC38E093F9000091F9003092F9001000248142D4BF411A00
+:201E2000091A8B422CDC2AE018680B6811680024814294BF411A091A8B4221D81FE01B6834
+:201E4000106809680024984294BF181AC01A814216D814E01B881088098800249842D4BF3A
+:201E6000181AC01A81420BDC09E01B781078097800249842D4BF181AC01A814200DC0124C6
+:201E80002046BDE8F0817047F0B504462C20ADF16C0D18F001FA071C00F0A28008223A70B1
+:201EA00000257D70207FF870207C04F11401387407F1140017F0F2FB381D211D0C2217F0EF
+:201EC000EDFB4848237D217FC01E466984462846B04206D000E0B6683279914218BF002E3C
+:201EE000F9D1F6B1DCF80C00D8B173B9C17DF27D914212D190F8251096F8252091420CD139
+:201F0000C16AF26A914204D007E0416B726B914203D101793279914203D180680028E4D1EB
+:201F200001E000283AD120461AA916AA01F0C2FC0246BA7098B1401E02D0C01E0FD010E05D
+:201F4000607D9DF8681016AB09F054FF38B107F11C0016A9102217F0A1FBBA7801E0BD70B9
+:201F60002A468DF80020F8783E1D8DF8010096E80D0001A981E80D00387C07F114058DF806
+:201F8000100095E8050005AC07F11C0184E8050007A8102217F082FB68461CE0BD708DF8B7
+:201FA0002C50F8783E1D8DF82D0096E80D000CA981E80D00387C07F114048DF83C0094E871
+:201FC000050010AD07F11C0185E8050012A8102217F064FB0BA817F0B9FC384618F09CF8DD
+:201FE0001BB0F0BD4B1900202DE9F0470546A87A022840F09B804E4CAF7B5248DFF840A1A0
+:20200000666A002F7CD1E168F9B12769EFB16769DFB1A768CFB114300078012815D16888A7
+:202020008847AE1C88B943490A6830889101A1EB820122699047012878D16169308888474A
+:20204000A16830888847BDE8F0873B486D88006878B101680A88954208D1096A4A7809786A
+:2020600001EB0221490A01D220B136E040680028EFD10020314933230027012401F6C4427B
+:202080001679FF2E02D01688B54206D05B1E02F124024FEA4404F3D100E0274601F59A781B
+:2020A00001F12E09002319F803208AB19E0058F8064027420CD0104616F062FF38B1417B8A
+:2020C000052904D1BC431E2348F8064000E000205B1CDBB21E2BE6DB68B1417B05290AD14B
+:2020E000016801270D8056464773307820210FF059FDBDE8F087284611F0B2FBBDE8F087DA
+:20210000A6B1017D012911D1807F40080ED3042016F0E3F9011C09D06420087001274F70D7
+:20212000688856464880307811F0B6FABDE8F087ECFB00206CBC0200380501202001002006
+:20214000E4FA0020ACFE002070B5534C054694F84A00ADF1300D082818BF042840F099807B
+:2021600028460DF10E0116F0C9F94FF6FF7012F033FFBDF80E0004AE314600F0EFFD012843
+:2021800000F087800DF11A0017F0AAFF0DF11A00314616F02DFF58B1BDF80E2017F074FE5A
+:2021A000904205D004F13E014B200A8013F034FA17F07CFEA98A3B4D884216D004A817F07F
+:2021C000BBFF38B10079012818BF022802D104A810F010FC3148016839B105F113000078E1
+:2021E000012802D1BDF80E008847BDF80E00002115F0D6FFBDF80E0015F036FE00248DF8EE
+:202200000040BDF80E00ADF8020068460CF0D8FB98B10DF11A00214608220CF097FB01AC6A
+:202220000DF11A00214616F0E3FE30B104A9204617F0C6FD684603F0CFFB01A804A917F0B2
+:20224000BFFD68460EF062FA50B1BDF80E00BDF80210884204D0ADF80200684603F0BCFB92
+:202260000F482E78046836F0010012D10DF12200FF2108220CF06AFB5CB104AD0DF1220141
+:202280000822284616F000FA18B9BDF80E102846A0470CB070BDC046E4FA0020F4FB0020B1
+:2022A000B0030120ADFE00202DE9F041524D2968F4310A68064692F84400ADF1180D8228EA
+:2022C0001ABF92F84400401C002082F84400086890F8441000EBE10090F82C104A1080F86F
+:2022E0002C2048080AD22968F4310A6892F84400401C82F84400C0B28128E8DB2A68F432C0
+:202300001168DFF8F88091F84400812824DB8878E8B944462168D1B10868C0B10F4615F00F
+:2023200009FF8046386817F0A9FF10B1386818F0B3F8384618F0B8F8384612F02DFC083C49
+:202340000020A060404617F0D8F92A68F4322A203070D2F84C1249E0D2F83C234431E1206D
+:2023600090472C684FF6FF730220ADF80830F43422688DF810009778BFB917F079FD4FF4AE
+:202380007A71B1FBF0F01E49434600220AF0A8FC00282DD02868D0F8F4001A2141702A2768
+:2023A00037702868D0F8401320E0022F1CD0012F19BF0720832108208021002700974932D9
+:2023C0000192D4F8844202AAA047DB2807D0E52805D0F32803D0DF2818BFE82808D1296843
+:2023E000D1F8F4104870DAE7D4F874133046884706B0BDE8F081C04614010020D8040120FB
+:20240000FD7C01002DE9F041064670680F46ADF1300D000944D2F07A002837D0012841D1B4
+:202420000024B968ADF8284021B13068801D089008A8884731680094087D898822460AAB4C
+:2024400013F0C7FABDF82800002800F083803168012500959DF828008DF82A00BDF82870B3
+:20246000019538128DF82B0002950394B27A0492022305930DF12A0706970795087D03220D
+:202480002346891DFDF714FFFF2064E0F06841783768007800EB0120397D10F025FC59E07F
+:2024A000F07A08B1012056E02C4D346868784FF480410FF035FF6869A846A41D40B91820C5
+:2024C0000AF0C8FBC8F8140008B10021416121E070B1637A417A8B4207D161894289914208
+:2024E00003D121880288914220D040690028F1D1D8F814501435286820B100F11405286807
+:202500000028FAD118200AF0A5FB286070B100214161286850B1217A017221880180617AE6
+:2025200041726189418100250573056198F801004FF480410FF036FBF96859B13068F76812
+:20254000801D08907A78387800EB0220ADF8240008A8884700200CB0BDE8F0814CFF0020F2
+:202560002DE9F0430E460024ADF1240DADF8160006F108078DF81440384616F055FA50B955
+:2025800005A80CF01DFAA124012840F08A8005A814F004FA85E038460DF122016A460CF0F4
+:2025A00057F905464FF6FF70A84276D09DF82200DFF8FC8000282BD03C4801789DF81000CD
+:2025C000F8B1401E11D0401E04D0FB3814D0801E12D048E001290CD002290AD006F11E0002
+:2025E00002A9082216F056FE3DE0012918BF022902D14FF4817001E040F20310B08274820E
+:2026000031E005219DF81300718200F07F0029E002A83946082216F03DFE4FF001098DF80E
+:202620001190FF208DF8100017F02BFD274600F00F0000942946142201976B468DF8120091
+:20264000042013F0FFFFAF0007EBC507404621460C223F1838460CF079F9748287F809907C
+:2026600040F20310B082A8003474414600EBC5000A58B2610F580A237F1CB7FBF3F20F50C2
+:202680005A43BF1A0DD1401801210A4F017238784FF480610FF086FA03E0748240F203102F
+:2026A000B082204609B0BDE8F083C046ADFE002064FE00203BFD00202DE9F0478246484E5B
+:2026C0004E4C56F80C0C9046894680082AD245480068810D28D2051704F13400006800683F
+:2026E00080476D1CC0F13E0110F1020F4FEAE101D8BF07218D42B8BF0D1C3B480068C0F3A1
+:202700000320401B102803DA0028D8BF012000E00F20364900F00F0040F0F00081F84D00D3
+:20272000087801E03248306000203249324F256808603868A96927208847324D304805F168
+:20274000300211682B460840106003F17800006820F48070A8672068016B4FF480608847D8
+:202760002068016B4FF4816088472068016B4FF4C0608847244901200860C5F88091286000
+:2027800056F80C0C800806D2B8F1FF3F14BF40464FF0404030603868E8698008FCD3072075
+:2027A00010F07CF90228FAD1BAF1010F13D0206A164E8168304688470428F8D0012804D103
+:2027C000206A4268032130469047D5F8180220F00300C5F818022068806B8047BDE8F0872D
+:2027E0001C000940B44F00500C1300500D620840FD0000400C4009402C200940B8010010CB
+:20280000FFFFFEFE0C20084028200860004003402DE9F04F15460646287A0C4600F03F01F7
+:20282000E8886FF39F2040EA0130A988ADF1140D6FF39F2141EA003B49490E9FC8789A46D5
+:202840004FF0000988462EE09DF80B10C8080CD3BDF80E00844204DD241AA4B2162C13D9C9
+:2028600031E02146304610F0F1FE0020F6F7ACFC98F8330098F803204FF00009401C90FB21
+:20288000F2F15143401AC6B298F803008119491E91FBF0F24243891ACEB2B10001EBC601E1
+:2028A0004144B1F84C40484503DC0020A8810A2052E098F8323009F10101B3421FFA81F9D7
+:2028C000E4D0172CE2D3E41F30466A46A4B2214608F038FF9DF80B108808B7D34808B5D296
+:2028E0002A7AEB881AF00F0018D0401E12D0401E07D0401E18BF04202ED100985845A5D148
+:202900000CE09DF808009042A0D1BDF8060098429CD103E09DF80800904297D1AFB10AF0D5
+:20292000F000102811D1BA89BB68684600210FF0DDF8002888D1F988B868BA884018396827
+:2029400015F0F4FC00287FF47FAF68460EC80EC503C885E80300002005B0BDE8F08FC04628
+:202960005CFC00202DE9F84F504CD4F8A000D4F8A060002800F095800546E86840F60301AC
+:2029800008274A1C02E040687F1EFFB260B15FB10388994218BF9A42F5D129692CC83831DB
+:2029A0002CC189C881E8890006F1280090E800034FF0000A06F12807D34687E8000CB16831
+:2029C00021B357464FF0E24A07EA08001AEA090508BF002813D036A090E80C0002EA0802EE
+:2029E00013EA090308BF002A04D0B5683069B6F93010A847504607EA080800EA0909B568C5
+:202A00003069B6F930104B464246A84717F0DEFB0546B4F9B600401C6FF31F30A4F8B60039
+:202A2000214886F833B06FF00207378615F044FD284617F055FDB4F9B400B4F9B6108842FC
+:202A40002FD16068D4F8B860D4F8BC7090F8FC1000290CBF052007200AF068FF58462EB120
+:202A600096F8FC5005B9306886F8FCB05E462FB197F8FC5005B93E6887F8FCB0864238BF4F
+:202A8000061C66B1B6F1FF3F0BD017F0F1F9B6FBF0F104F5CE7016F03BFEBDE8F88F16F012
+:202AA0002DF9BDE8F88FC046D0F5002030F50020F0FFFFFFFFFFFF8EFEB5524C6069258954
+:202AC000A689E169806D2A468919083109F00EF86269916D49199165E2697619B0B21218BF
+:202AE0000832127801A90A70444EE169401C80B20918097A721C401C117081B2E269A181D5
+:202B000052180832126868460260091DA181042115F099FF63690090054616F035FFD86361
+:202B2000284616F0F5F9A3F84000EA2013F0BAFC02213548324D017068684069007830B133
+:202B4000307810B97078FF2801D00420E0706769E078397C084338749DF9040017F07AFBC6
+:202B600087F8460007F17406BE6539899DF904007B6887F84800B7F85C000026401AC01892
+:202B80007860B88987F84760800A0AD32868D0F80813384688476769786E10B1B7F8680041
+:202BA00010B397F8600050B12868D0F80C13384688476769F86C10B1B7F85000A0B12968C8
+:202BC000B8310A68107838B1936C2BB119463846884767692968B831D1F8A0113846884791
+:202BE000666116F0F7F9FEBD2868D0F8541204F11400884766610DF0F9FFFEBD240001200B
+:202C00001401002068110120051401202DE9F04F0546E97A6869ADF11C0D0229814609D144
+:202C20000078032410FB04F0401C80B217F034FB061C01D100208DE00027A346A246B846BB
+:202C400047E017FB0BF0862332E09DF80E00A178884230D10498F8B129688888032814D108
+:202C6000238893B9D4F8031005A8022216F012FB2868007D10F040FE11F068F92968BDF8A7
+:202C80001400097D10F030F81FE0087D02AA2346891D13F03AFE07E02968D4F80330087DFC
+:202CA00002AA891D13F0FEF8031C0ED017FB0AF031184B7004E017FB0AF08D2231184A701A
+:202CC00021887F1C3018FFB2418008F101005FFA80F899F80000404522DD2968072018FB4B
+:202CE0000094641C087D2288898802AB10F034FF0028A6D09DF80F30002033F07F0318BF92
+:202D000001206968C1F3C00181429ED017FB0AF1862072187318507021887F1CFFB25980C5
+:202D200037701FB9002070700127377068682A68C00880F0010000F001000090A87A911D59
+:202D40000190107D928833460AF0B4F9304617F0E3F9012007B0BDE8F08F70472DE9F047C2
+:202D60008A46071CADF1200D08BF002000F0918049480088B8420AD116F05CFA0146504686
+:202D800016F036F900280CBF0125002500E012254FF00009ADF8027068468DF800900BF08C
+:202DA0000FFE20B101A815F03FFE012843D0122D4AD1504617F0C0F928B101888F4202D059
+:202DC0000679052E03DBB9F1000F3CD13CE00780E6B132490D78032E18DA31493DB901EBE4
+:202DE0008502126B01EB8501C261096B0AE001EB85010B6B9A01A2EB8302C2610A6B91011D
+:202E0000A1EB8201816180F8209003E06FF00101C16181614E46C6600125ADF810705146B5
+:202E20008DF80E500DF1120016F0CAFF0DF10E0002F0D2FD07E001A9504616F0D9F80028DD
+:202E400008BF012500D04D463846514610F04EFA0A2818D0A02813D1124C322604F102084A
+:202E60004046514616F0C4F830B9761E04F11C0408F11C08F4D100E02780384612F0ACF854
+:202E8000012D01D004E001253846494616F01EF9284608B0BDE8F0871EFB0020CBFE00209B
+:202EA00018BC02006C0800202DE9F84F8146D9F80040D9F8047094F82360B4F814A0D4F8F3
+:202EC00010B090460D465EB1A168434816F01FFE002818BF6FF001007BD1012084F82600D5
+:202EE00084F82180002625604A463C483C49E66115F06AFB3978272017F070F95146584623
+:202F0000062204F06BFC002857D13749091F086820F00200086094F82000042806D1334822
+:202F20004C38006840690146272088472D4F4FF0020B4FF0805AC7F8FCB2DAF8FC014068DA
+:202F40000146062088470AF5FE7A38BB584613F0CDFDB8F1020F4FF0010005D0B8F1040FD5
+:202F600018BFB8F1060F01D1314600E00421C7F84C11E968C7F85011C7F8546184F82400CD
+:202F8000DAF80000AA68E968036968681C460B46A04748460DF086FBBDE8F88F40203860F6
+:202FA00080253D6094F8260020B10B4817F024F984F82660C7F8FC6207E094F8260020B14C
+:202FC000054817F019F984F826604FF0FF30E061E069BDE8F88FC046B80E01204012012005
+:202FE000510002000444024088470240FC0100102DE9F04F80464E489346ADF1240D07690D
+:203000000691002F00F090807D6801248246494F07940320B8F1000F8DF8140003D0069800
+:2030200003A914F098FF4FF000094E4601E0761CF6B2A968087BB04217DD03A80090CDF8D8
+:203040000480079802900969FA7C7B69287831F816100AF039FE0446B22C06D0002CE6D1EE
+:20306000DDF81C90B8F1000FE1D1B22C26D0B9F1000F02D0B8F1000F20D0A968002602E045
+:20308000A968761CF6B2C879B04217DD03A80090CDF804800024029489683A7EFB692878D3
+:2030A00031F816100AF010FE0446B22C06D0002CE6D1DDF81C90B8F1000FE1D1B9F1010F33
+:2030C00004D1B8F1000F08BF802100D0FF21DBF80000B22C017314D03878FF2824D1DAF864
+:2030E00010000668CAF81060F6B175682B7823B1F12B02DA002E8CD116E03668CAF81060DC
+:20310000F2E700208AF800009AF8010040210FF007F915F07BF89AF801004FF480410FF033
+:20312000FFF80C2016F0CEFD09B0BDE8F08FC0464CFF0020DC0201202DE9F0470646880F1E
+:20314000C0F08E8000200EF095FA464816F072FD454C40F60A09A4F8009000256580207B56
+:2031600005F00F0120F00F00014321736560607B4FF0010808F00F0720F00F0047EA00010C
+:203180003046617306F086FBD6F808A04A462146D01F574600F1010C00E027467C6834B161
+:2031A00023889A4203D0984218BF9C45F5D179607A7B2E4C05F00F0322F00F0213437B73A7
+:2031C000D4F8983033B1DA681288904223D06046904220D0338FF3B1F56306F138025580AA
+:2031E00096F8440005F00F0320F00F00034386F8443096F8450008F00F0320F00F0003435D
+:2032000086F845304A60487B05F00F0620F00F0046EA00054D7316F02BFB1548A06294F819
+:20322000310080B91348006801684046884701280FD0787B08F00F0120F00F000143797351
+:203240000D4EA66205E011F0C7FC0028FBD010F0A5FD504616F0EEFC5146404614F08EFF99
+:20326000BDE8F08701010E04F412012030F50020F95E0000E0010010992B02002DE9F0435B
+:203280004E49DFF830910A68ADF1140D1AB94C464A34267800E00226444BD9689F68761FD9
+:2032A0007ED0761E7AD0002A67D09179012964D03F4CE76A022903D0A169002973D071E078
+:2032C00038460027002854D1780009F0C3FC5FEA00084BD0E06A40B10021028828F8112029
+:2032E00040684E1CF1B20028F7D14C46B4F89200618F814233D081460A2000EB47008DF8FB
+:203300000D0003A815F080F9061C2CD035690920287004F15D016F70A81C16F03DFF5FB1B2
+:2033200008354046017805F8021F30F8021B7F1E4FEA21216970F5D10124B47715F07AFF69
+:20334000706201A9484614F006FE10B1747701A83062A6F802903046F8F78EFC03E0CDF8AD
+:203360000080FAF72EF9404611F016FC12F0C6FE19E040687F1CFFB2A4E740780E498DF84A
+:203380001000086838B900208DF8050001A9012013F03CFC07E0096804A803E019B101E07A
+:2033A0000FB13946884705B0BDE8F08334040120ECFB0020E4FA00207CFD002038040120DE
+:2033C000F0B5064631684889ADF1440D4008C0F092804A894FF6FE70104048810868036A1D
+:2033E000C57F5978187800EB0120694611F010FFD878997801EB0021ADF80A105A791879CC
+:2034000000EB0220ADF80C0098799DF807708DF81200D879002F8DF8130008BF082403D05C
+:2034200003F10800102405909DF808701FB1181908340690E4B28DF801409DF8057037B199
+:20344000185D641C8DF80500E4B28DF801409DF806C02A480027BCF1000F06D190F82F2033
+:2034600052B1428F8A4206D106E090F82F201AB99DF8022002B90127A7B9BCF1000F05D1B9
+:203480001B190A932D1B8DF81C500CE090F830001B190E330A9315F045FF2D1B281A0E3853
+:2034A0008DF81C000A9B37BB1878042823D10DA800210E220BF04AFABDF80A000A9FADF8D2
+:2034C00034007978880924BF01208DF83F0031F07F001CBF01208DF83E00C80934BF0699AC
+:2034E00005990DF1360016F057FE30798DF840000DA812F037F811B0F0BDC046E4FA0020D9
+:203500002DE9F84F80460D462868DFF824A1D8F80040D8F804700689D0F804B0E16891468A
+:20352000504616F0F4FA0028CDF8009018BF6FF0010074D148464FF0000960723A49656117
+:2035400042464B46C4F804903648A37015F03CF83978272016F042FE31465846062204F0C9
+:203560003DF9A8B9334E4C3E306840690146272088472E4F4FF0020BC7F8FCB2F06C4068D1
+:2035800001460620884750B14020386080263E60504616F031FE4FF0FF30BDE8F88F5846AF
+:2035A00013F0A4FAF06C95F82010C26928699047F26CDDF800C095F8200095F821101368E5
+:2035C000BCF1010F4A4608BF01229847E869C7F85001C7F85491A869C7F85801A96959B18B
+:2035E000F06C076968684A461346B847F06C806901461148401E8847207A042804D0306803
+:203600000069014627208847F06C0369E969EA68A8681C460B46A04740460DF0B7FBBDE8F4
+:20362000F88FC046401201205515020004440240B80E0120FC01001003000080F8B5054625
+:20364000687F0F4600280CBF08201020AE7F0EB10830C0B22E7F0EB1401CC0B2AE7926B115
+:20366000297A00EB4100801CC0B22E7E6870002E0CBF00260E260024297D2B7E85F8344032
+:2036800009188919397033B13A48007815F04AFE3978081838703878742867DC09F0DAFABE
+:2036A000071C64D016F0FCFB95F83420A97F2B7F41EA42016A7F42EA4102A97941EA4201AD
+:2036C0002A7E42EA410203B1012429786B7E44EA420441EA800103F0030041EA801141EA73
+:2036E000042188B2397000127870A878B87068880012F87028793871A88800127871A87E7B
+:20370000B871E87EF871687F002808BF082405D0296A07F1080016F03FFD1024A87F28B1D1
+:20372000696A381916F038FD0834E4B2A87988B1287A3855697A631CD8B239542A7AE96861
+:20374000431CDCB2E019520015F0A4FD287A04EB4004E4B2287F00B13855687829692A7D22
+:203760008019C0B2C01915F095FD00E027463846F8BDC04614FB0020F8B50546A869837815
+:20378000002427461BB3FE2B21DC41780078474E00EB01203188814206D015F01BFD00283B
+:2037A0000CBF8126892613E0184615F041FB264650B18268002A04BF4068846804D0012089
+:2037C000194690470127044604B9832600E08226374801685EB954B1227BE079022380189C
+:2037E00010FB03F00C30C3B2502B01DD58E0042301F8016BA869007801F8010BA8694078A6
+:20380000042B01F8010B42DD181F01F8010B207801F8010BA07801F8010B6088001201F86C
+:20382000010B207901F8010BA088001201F8010BA07900F00F0001F8010BE07901F8010B24
+:20384000E67916B10020864214DC207B0870267BFEB1491C002086421BDD26694200965DFE
+:203860000E702669925B12124A70267B401CC0B2891CF0E7A6684200965D0E70A668925BC9
+:2038800012124A70E679401CC0B2891CDBE70020087005F11100A91C48F204020DF03EF9DE
+:2038A0001FB114B1204611F077F9F8BD50FD00209CFD00202DE9F04100250E1CADF1580D28
+:2038C000904603950746ADF8105004D0B8F1000F18BF002F01D1042083E0104635702946D3
+:2038E000102216F0DBFC38798DF80000002804BFB868019005D001A807F10801082215F039
+:20390000CDFE68460DF1120104AA0CF01FFA36490C7802284ED001284DD09DF8000002280A
+:2039200008D1387C9DF81C10814203D0002818BFFF2840D19DF81F00397D00F00300884245
+:2039400004D19DF81F0010F0030F49D008A903A8042215F0A3FEB8690399884228D99DF86E
+:203960001F00397D00F00300884221D19DF81F00801000F00401042902DA797D012917D07A
+:2039800000F00701072918BF042901D1787D78B105290DD006290BD009A94046102215F087
+:2039A0007DFE9DF81F00C0F382003070012018E00CB115E00CB9284613E0387D0228A8BFCC
+:2039C00003200EDA787D58B9084C40461022214615F0C0F820B921464046102215F05EFE4D
+:2039E000022016B0BDE8F08120040120CCB302002DE9F04F05468846ADF1140D1C46D5F8A7
+:203A000008B00E990092DBF80400019108EB0401884238BF6FF003047BD3404E30684FF07A
+:203A2000FF3116F074F83E48019F01684FF0000978081CD23846CDF80C90800827D334B357
+:203A40003046DBF800200099066823464244491E521E11F8010F12F8015F054085421CBFC6
+:203A60006FF00604301C52D15B1EF2D10FE034EA010701EA040202D02A480068121801EA6B
+:203A8000080128460EF046F9002803903CD1DBF8005010F0A3FA27464544DDF800A00290ED
+:203AA00002E0BF1BB244AD1997B1082F8CBF08263E1C16F08BFB049029463246504615F09A
+:203AC00083F88146049816F00BFDB9F1000FE8D0029814F0F1F9B9F1000F12D10198C00804
+:203AE00012D38CB1DBF8000000994044491E401E10F8012F11F8013F9A4202D1641EF7D175
+:203B000002E04FF0FF3003900448039C006816F073FB204605B0BDE8F08FC04694130120EE
+:203B20009C130120981301202DE9FE4F0CAF1D468B465FEA02083E78009014BF4FF0804A22
+:203B40004FF0005A16F042FB0324DFF804910190BBF1FF3F14D1D9F8A810009816F072F805
+:203B600058B9D9F8AC10009816F06CF800280CBFD9F89870D9F8AC7008E0D9F8A87005E036
+:203B800000985946002211F093FC0746002F59D097F8330030F07F0053D04C46D4F8A8000D
+:203BA000B84219D0D4F8AC00B84215D000982A463346394608F05AFE002842D094F8240091
+:203BC00001283CD094F82400042838D0214904F1E00016F019FB32E0D4F8A8005346002232
+:203BE00011F084FCD4F8AC005346002211F07EFCB8F1000F14BF1848184814F089FAB6B15D
+:203C0000D4F8A80000224FF0807311F06FFCD4F8AC0000224FF0807311F068FC3869C4F8E2
+:203C2000D80094F8DC0040F0010084F8DC0035B1D4F8981000982A46334608F017FE83242C
+:203C400000E00424019816F04BFC2046BDE8FE8F30F500200200004001000204010001044A
+:203C60002DE9F04FADF1140D02921D460191DDF83CB00E9C009016F0A9FA464A6FF001080B
+:203C80004FF00109002392F840A2039009FA03F616EA0A0F6FD0B5F1FF3F18BFAB426AD182
+:203CA000D8B215F003FE002865D0877A002F62D192F84012B14382F840124F468772009DED
+:203CC000437292F842120560491C82F84212019E06722E4F4760017A074601291ED0022973
+:203CE00024D140F20361018290F90930C17C5B1D21F00F0103F00F030B43C3746379817CBB
+:203D000063F3C7018174C17CA37963F34611C174C17CE37963F30411C17407E00A20388251
+:203D200097F90900401DB874A0687861BBF1000F08BF002012D09BF801009BF8001097F935
+:203D40000960134C4FF6FC75800040EA4110711D40EA012005EA000144EA0100B86102983F
+:203D600000B17860506808B9386850600CF07EFA97F9098002E05B1C032B87D3039816F0E2
+:203D8000AFFB404605B0BDE8F08FC04677F500000100040630F500202DE9F84306464FF676
+:203DA000FC751C4617468846B54200F08480002111F0BAFBDFF804910646B9F83A00B042AE
+:203DC00001D1E00977D3214630460BF011FBC0B9A81C00210BF00CFB98B914F0180F0DD041
+:203DE000374B0020997911F0180F03D1962805DA184606E0401C08339628F3DB0220BDE848
+:203E0000F883AD1C0680454518BFA0F802808471610824BF44F004048471012F0CD0417925
+:203E2000012913D0817911F0180F0CBF99F83710FF210171477109E001214171817911F0AE
+:203E4000180F0CBF99F83810FF210171012F32D1B9F84810404612F0DBFB60BB194C1A4F82
+:203E600000204101A1EB8001C919B1F84C6707F52772002396215588AE4205D0491E02F12A
+:203E8000080203F10103F6D1962B04D0401C1C343228E6DB0FE0204600211C220AF056FDFC
+:203EA000A4F80080B9F848006081AA27A77401266674062525740020BDE8F883E4FA00201D
+:203EC000BC0300206C080020200100202DE9F0479646464A88461E2300240146012520466F
+:203EE00097782FB15B1E02F1080204F10104F7D11E2C79D03E4C3F4F814633264FF6FF7C10
+:203F000082F8069037F824AFD04510D0638F53450DD03B7933F0040A06D0012B07D14B89A0
+:203F20009C4508BF284302E093795B1C9371761E4FEA4505E6D1304D3226ACF1010C35F88B
+:203F40001C3F98450DD09C450BD0B4F848306F89BB4206D16F7C27B1AF7C17B193795B1C67
+:203F60009371761EEBD19779082F01DC17B909E0082393718B7C012B04D094F826305B1C81
+:203F8000137101E082F8049094F82B30937094F82570D7708E891680CD7C82F805E0D571C1
+:203FA000B8B116491E2201F12D030D46494613F8017F37B1BE4504D0521E01F10101F6D180
+:203FC00007E01E2905DA83F800E005EB8105C5F834012078402110F0BFFD20B9207840218A
+:203FE000642216F0B5F80120BDE8F087CC020020E4FA0020C00D00205008002020010020B9
+:204000002DE9F84F8346DBF81800057800216A46A3200FF0A9FABDF800004FF00009854218
+:2040200024DABDF80000401B84B2042C01DA0CB91DE00324E00000EB041008F00BFE5FEA1F
+:2040400000090FD007464FF000088CB146467119A2203A460FF088FA761C1837F6B2B4424F
+:20406000F5DC05E04FF0B508002401E04C46C8469BF81100E1B215278DF8020011FB07F0EC
+:20408000001DC0B2401C08F0E5FD4E460BF1020B071C45D0781C82468AF800809DF8001083
+:2040A000E3B2B970FD7004253C7143B3001DE4B2314616F071F8317A00F8011BB17A00F88E
+:2040C000011B7189091200F8011B317D00F8011B317D032906D0317B00F8011BB1890E35EC
+:2040E000091205E006F10C0116F056F8B17D1535641EEDB200F8011B06F11806D8D10C4EA3
+:204100002B460DF10200594648F23302341DC4F800A00CF003FD384610F03EFD09347460AD
+:20412000B9F1000F02D0484610F036FDBDE8F88F98FD00202DE9F84F8046D8F80430B8F87B
+:204140000240002739463A461D191EE013F8036B7F1CD21CFFB292B2A6B913F8056B30467C
+:2041600015F02BF8521D92B278B1304608F0E8FF8618B442B8BF002073DB09181B181218EF
+:2041800089B201E09B1C921C92B29D42DED80E2017FB00F0401CC5B2681880B216F07CF896
+:2041A0005FEA000A5CD0D8F80440002F0AEB05068AF8007054D04FF000084FF0010B0AEBA0
+:2041C000080500210E226D1C284616F067F814F8010B28702B7861782078A41C00EB012095
+:2041E000A5F8010093BB14F8010BE87061782078A31C00EB0120A8801878597800EB012092
+:20420000E880E878014614F0D8FF9C1C20B30846314612F065FAADF800B09DF80030A14602
+:20422000002B07BF411E4FF0FF335B46002128B119F8012B401E72541944F9D1E878C5F87D
+:204240000A6008F07DFF2418361805E061782078A41C00EB012028817F1E08F10E08AED100
+:204260005046BDE8F88F70472DE9F84FD0F8E8200023083A002AC8BF0123D0F8C0C0D0F84E
+:20428000D020E346DBF8004094420CD8DBF81470002FBC4678D001228CF81020D0F8C0B059
+:2042A0004FF0000E00E09646DCF80020A2EB0E02B2F5806F88BF4FF48062D0F8D8702FB96A
+:2042C000C0F8D820D1F81C808E6904E0C0F8DC20D1F824800E6ADCF804402CB92B4C9F0042
+:2042E000E55900F1F6040AE0294D9F00ED5903F1010A02FA03F90EFB0A444C44641EB560DB
+:2043000034600C6804F10809C6F80490B56843F6F07A1401103C0AEA04042543B560DCF8CF
+:20432000086026B9194BDD5900F1F40308E0194DED595F1C02FA03F30EFB07669B195B1E10
+:20434000C8F80850C8F80430C8F80090D8F80830E34544EA0304C8F8084004D1D0F8D030F7
+:204360009B18C0F8D03090F8FE706FB90B685A6A42F003025A62D0F8CC004F6943680A6920
+:20438000196847EA02008862BDE8F88FE8C30200F8C30200F0C30200F8B5374D0024287047
+:2043A000364E85F84A40382030804FF4287008F051FC706028B1706821464FF428720AF08B
+:2043C000C5FA2F482F49304F304E81613049C7610A7D0662012A15D12E4A2F4F4262897F0D
+:2043E000C760490802D2006B58B90BE02B4F07632B4981622B4E06612B4B83602B4A42617E
+:2044000038468047AC602A48046012F007FD15F0D1FB294996274FF6FE7201F1E80020F8C8
+:20442000082F4280047144717F1E8471F7D121480C2700F150035A805C705C607F1E03F825
+:20444000084BF8D10827428004727F1E00F10A00F9D128781E277F1E21F8082BFBD1174A7C
+:204460000121117010214FF47A7215F071FE02F02BF913480460F8BDE4FA002030050120E7
+:20448000ECFB00208D6A02008D8C020045080200ACFE0020CDD101005D8002006986020079
+:2044A00021F20100B1EA01006D300200758C010038050120A4010020CC020020D513012091
+:2044C000380401202DE9F04306467568B7680C46ADF1140D15F07AFE95F8FD1021B9616922
+:2044E000102901D8042903D215F0FAFF00206FE04FF0010985F8FD9015F0F2FF2069C5F8AC
+:20450000E4006069C5F8E800207B85F8F900207885F8F8000020616885F8FC008046C5F846
+:20452000C080C5F8C480C5F8C8802B4AC5F8EC10217E12F8211085F8FA10F989A5F8F61081
+:20454000237B002B0CBF1021494685F8FE00C5F8F010387B05F0B8FA30460DF009FC97F86E
+:204560003B0085F8FB00304609F0F0FB684615F049FB787900966B463979184A01902846EC
+:2045800010F008FE684615F075FBB96802911449009605F130006A460EF07CFB0FF014F9F4
+:2045A000014633460F4AC5F8CC1005F11C00042113F01AFB95F8F80030B905F16C004146A3
+:2045C00012F0B8FE084800E0A068C5F8BC00304605B0BDE8F083C046A0C10200B9DD000030
+:2045E0001549020015A0020001A102002DE9F0410221ADF1280D8DF81210C188ADF80A1014
+:20460000417D8DF814108188ADF81610417E8DF81810818C491E8DF81A10816A4A1C0892E5
+:2046200009788DF81910418A808DADF82400374800250768ADF81C10002F31D04FF0D3087C
+:204640004FF6FF74BDF81600F988884206D08C4223D1C10BCE0301D113281ED19DF81A00AC
+:20466000203080B213F039FF061C16D002A9202214F010FE9DF81A1041B106F120000A465E
+:20468000B061089906F1200014F004FE86F80080387931460FF000F801253F68002FD1D190
+:2046A0001B4908310A884FF6FF732F4693420CD0BDF816500C460020954220D0401CC0B2CC
+:2046C000C2001119A25A9342F6D1DFB9BDF81610C80BC00316D19DF8140098B9132911D04F
+:2046E00041F4004100919DF8180001909DF81900842200230DF10A0112F08AFE02E04968D8
+:2047000002A888470AB0BDE8F081C046A0FD002044B702002DE9F04FADF1140D02A914F0CD
+:2047200083F85FEA000940F08380434F029CFE68218856B1B61F0322002036F8063F9942CB
+:2047400005D0521E00F10100F7D1C82601E080460026182008F07EFA051C0ED0002118229D
+:204760000AF0F4F8608818212A4615F04DFC4FF6FF706080284610F00FFA4FF6FE7A4FF06D
+:20478000000BA4F800A0002E84F804B050D1F868444668B3142008F05DFA5FEA000827D083
+:2047A0004C205946022203AB15F016F902255E46F868B44207D0A9B24C2006226B4615F06B
+:2047C0000BF9694603E0610001EB84010918A8B20622404414F05EFD761CAD1D032EE7DB9C
+:2047E0004C201421424615F00FFC404610F0D4F94C205946022203AB15F0EEF8C0B9FF6885
+:204800005FB1610001EB8401BDF80C007A5A5646964204D138B1401E03E0BDF80C00401C91
+:2048200080B2ADF80C004C20022103AA15F0ECFB484605B0BDE8F08F54FE0020F0B5ADF151
+:204840003C0D12F009FD454E96F84A00082807D0332086F8290086F8270001277765B765D6
+:204860006846002124220AF071F83D4D2878012804D0012000278DF80A0002E000278DF834
+:204880000A700F2446208DF837400DF13701B47010F0C2FE6D1E8DF82470A87B8DF825007E
+:2048A00015F0FEFA8DF826008DF827708DF8287096F85C008DF82A700F28A8BF201C06F13D
+:2048C0005D018DF829000DF12B0015F065FC0DF13300FF2103220AF039F896F896008DF8F3
+:2048E000360009A80CF078FC06F11401452010F093FE08F055FF8DF80C708DF8207096F86F
+:2049000050008DF8157096F851508DF80800B6F848308DF8095096F85320ADF8043096F815
+:204920003C408DF80B2006F13A018DF80640532010F072FE06F13E014B2010F06DFE96F8D1
+:204940002B203078642111FB02F2082115F003FC684604F0FDFF0FB0F0BDC046E4FA0020A4
+:20496000ADFE0020FEB505462B7A33F001000BD02888044610F0B0F830B9032B06D12846CC
+:2049800001A911F0F3FF18B90220FEBDADF80440688A443008F05EF9071C08BF10206ED0D6
+:2049A0000021442209F0D2FFA87A0DF1060113F0B6FD9DF8060087F83A009DF807000121B7
+:2049C00087F83900384613F033F8242207F11000294614F05FFC07F144003864688AB8874E
+:2049E00069696A8A386C14F055FCBDF804002449B8800878F8710878401C087015F074FDE7
+:204A0000044615F035FA97F839604FF47A71FF236043B0FBF1F0388003FA06F087F8370010
+:204A2000002487F83600288B8DF80040400834BF201C01208DF80100287A8DF80200684630
+:204A40000FF018FA801EC1B2BE8FBD8F87F8341097F8342095FBF1F0C0B2387296FBF2F1F4
+:204A60005143761A1CBF401C3872064E388D40F008003885307801210DF094F82046FEBDAF
+:204A8000AC000120DC040120F0B50E460746002406F10805ADF1240D28468DF81C4013F0B9
+:204AA000C3FF18B9384629460BF074FB284607A96A4609F0CDFE3B4D6B78A127012B18BF44
+:204AC000022B11D19DF81C20B2B905A82146082209F03CFF05A807A96A4609F0B9FE4FF617
+:204AE000FF71814204D16B789DF81C5025B907E001216B788DF81C104FF6FF71814207D1FF
+:204B0000002B4CD115F08AFB002848D1274631E0254A9DF8101015782746002932D0491E54
+:204B200024D0491E0AD0FB3908D0891E37D1012B12BF022B012086F826001BE0810001EB2E
+:204B4000C001B069891810314A6882420CD8401C012B486013D0022B11D006F11E0002A95E
+:204B6000082214F097FB1AE0A22718E0012B06D0022B04D040F203107482B0820FE04FF418
+:204B80008170F9E705209DF81330708203F07F00B08205B1012486F8264086F8274038468F
+:204BA00009B0F0BDACFE002054FE0020F8B5474C054620684030816F0F780023B7B395F83F
+:204BC000987097B92521297501680968C98AC90939BFD0F8940090F82500D0F8940090F8B5
+:204BE0004E0085F86A00801C0EE01521297501680968C98AC90939BFD0F8940090F8250022
+:204C0000D0F8940090F84E0085F86A00042085F8693005F1900185F86B000A6805F17007F3
+:204C20003A604E687E600889388101E001202875B5F89E0095F8A07095F82C20E88295F8A5
+:204C4000A160EF760F2A2E770CD02068B5F8A870D0F8046305F12C011A4607B901222846E4
+:204C6000B047034673B995F83C00FF2801D1A86D38B12068D0F8FC2205F13C012846904722
+:204C800003460BB11F461FE020680027D0F87463009795F89C10B5F89A3005F19002284620
+:204CA000B047071C10D1216801F5807108682A89C0899042A8BFD1F8781103DAE5206870D8
+:204CC000D1F86C1128468847F8B2F8BD140100202DE9FF47444D0C4606469046600831D2F1
+:204CE000304610F021FC698F814205D03046022122460BF0A1FC08B9002072E030464FF60A
+:204D0000FE7102222346FFF747F8002868D124F02004E0091ED2304602A913F01CF970B98E
+:204D2000B5F84810304612F0D3FC071C12D0B81C13F07AFE70B1B91C02A815F02DFA44F0D3
+:204D4000200407E04FF6FC76A00834BF44F0080444F0100425486B8F90F80090012509F1CF
+:204D600001010022C9B20170491E00951846C9B20AF0B2FBA0BB4FEA641AA00934BF0620D3
+:204D80000E208DF8050001A813F03EFC071C25D0BD7714F04FFA78623869057004F078047C
+:204DA000447080F802903112C670002301715FEA5A01437103D3801D02A915F0EDF94FF681
+:204DC000FC70B8F1000F788004D0B8F10F0FB8BF87F81A803846F6F74FFF02E0102000E0E1
+:204DE000C7200090BDE8FF87E4FA0020D41301202DE9F041454C05462078002800F0828036
+:204E0000B4F9B600B4F9B41088421DD004F1980128460E4612F0AFF970B9D4F8A8102846F2
+:204E200014F010FF28B906F10801284612F0A3F901E0D4F8A80038B1B0F930100A224FF0E0
+:204E4000E043284602F082FE15F0C0F9804604F1B8000168A94219BF00264660002606609A
+:204E60002078401EC0B2207000283BD194F82400656002280ED1082011F0DCF9404615F0FF
+:204E80002FFB05F150004FF0FF3114F040FE15F09DF9804604F1E00015F0B0F904F16000B8
+:204EA00015F092F904F58E7015F0A8F904F17C0015F08AF904F5AC7015F076F904F5CE700C
+:204EC00015F072F9E16911B104F14800884704F1340013F0F9FB0C480078012802D10E2034
+:204EE00004F0FCFA606805F15007854208BF6660404615F0F5FA384615F07CF905F1B8003F
+:204F000015F052F9BDE8F08152C3020030F500202DE9F843434D444C3E4EDFF8FC80DFF8A8
+:204F200000910746012F44D139480068006801460120884701283CD096F83801002838D199
+:204F400008342068C0F38140C8B940460068B0B154F8080C000834BF4FF480504FF4405008
+:204F60002E4908600A2015F008F94846006901460120884706F1940015F01EF901E013F069
+:204F8000B5F80121206886F83811C0F3814010B94046006848B914F0C5FF800905D28020FF
+:204FA000A860286840F080002860032011F09EFD2BE057BB0BF0DEFBA068C0F38140A8B994
+:204FC0004046006890B106F1940015F0F7F82068000834BF4FF482514FF44151134A4846CA
+:204FE0001160006910B101460020884796F8380158B12868802720F0800028600320AF608F
+:2050000011F05CFD002086F838010020BDE8F883E0010010101500200CC20200A8A00C4085
+:20502000FCC1020090220840AC4F005028A10C40F0B50C466168ADF13C0D002900F0828095
+:205040000878002843D10C3101A8102214F022F96068C1690591016A0691001D0AA913F000
+:20506000E3FB607000282BD06068011D40880DAA0D4612F0E3F908BBBDF834000BA912F067
+:20508000F3F90B9850B90BA811F0D8FD20B9BDF834000B99088001E0112054E0284601A9A3
+:2050A00007F00CFB28460CA913F0BEFB10B90C98012101710BF07CF9002044E0012042E01B
+:2050C0000A984088182101AA14F09EFF3BE001A80021102209F03AFC00273E4605A80090B3
+:2050E000B1B200221423042010F0A4FB607090B9656807A908222D1D284613F0C5FA40B106
+:205100004FB9284601A9082213F0BEFA00B9374601E0374602E0761C032EDFDB002F13DD78
+:20512000616807A80822091D14F0B4F86068C1690591006A05AB1422B1B20690042011F001
+:2051400081FA00E0022060700FB00120F0BD704770B53448324E4FF08055C6F8A800D5F856
+:20516000D801314C036801210A46ADF1400D20469847D5F8D801426801212046904714F019
+:205180001DFB2A4906F154040822204614F082F827490822204613F0C9F820B925492046B6
+:2051A000082214F077F82448A060244DE560244B2361244A62612449A161244DE561244B77
+:2051C0002362244A62622449A162002525636563E562224BA363224AE26322492164F06D7B
+:2051E00010B1F16D2846884706F0CCFF684629463C22082315F04CF940F6B83406F1B000D9
+:2052000008946A462B46184907900224301D069415F03AF915F034F9284610B070BDC04601
+:20522000C8E8002075A1020000400340C87F0500C0C30200F0120050F1A501001D300200FA
+:2052400025D801008DBE0100DDD20100E5E501009DA60100ADF10100C92202004D920200D8
+:20526000ADFA0100DD070200095A00002DE9F04F002788460646ADF1140D039714F0A6FFA5
+:205280003A4D04906868384CC36C2069052103AA9847684614F0E2FADFF8E490CDF808800F
+:2052A000DFF8D0B0DFF8D4A0DFF8CC80009629F0010926F00106B1451BD02D4820F00100EC
+:2052C000B0420ED19BF900106B68206911F1020F24D059469A6B91F90010904781281BD04D
+:2052E00015E040460068D0F84C0580476FF001071AE09AF900106B68206911F1020F0DD09B
+:2053000051469A6B91F900109047812804D040460068D0F84C0580476B682069DB6A6946E5
+:205320003A469847071C04D540460068D0F84C058047B14507D00E4820F00100B04204BF5B
+:205340005846077001E05046077001206F6803902069FB6C052103AA9847049815F0C0F8C4
+:2053600005B0BDE8F08FC04670000120DCFF0020D94E02000D050120140100200C050120FF
+:2053800071C401002DE9F0413C4F3B4C3C4D38696168ADF1300D58B921B92868D0F84C051C
+:2053A00080476168096A07F11C0088473548B8636069016929B12868D0F8D40090F853005B
+:2053C00088472868D0F8D40090F942000CF042FAB0F1FF3F0A9008D00290000834BFBDF83C
+:2053E00008004FF6FF7028490880DFF8A0800026A8F87E60C8F8806098F8890020F00F0085
+:2054000040F0010088F8890098F88810012363F3C71188F888102868D0F8C403804730B9F1
+:205420001B4910206B680870596814230B703869454650B9606804687968164805F17C02FE
+:2054400007F11C03A047386113E0304611F078F86068416E02A88847334660680593066D9F
+:2054600008228DE80C0038697C35294602AAB047A5600CB0BDE8F081DCFF002070000120BA
+:205480001401002054F10080DE18002050180020D800002010080120BCB505460020E8601F
+:2054A00001242861A978287501F0030348081DD2C80801F00C0201D3042A04D1022B01D1A5
+:2054C000480900D202240C2A04BFA41CE4B2022B01D148090AD2241D32F00807E4B203D02D
+:2054E0000C2A18BF042A01D1641CE4B231F07F070BD0E878641C10F0030FE4B205D0641C2A
+:205500008808E4B224BF641CE4B214F0CFFC2A88641CE4B290420BD0880909D321480168E9
+:2055200028468847286918B9A87800F0DF00A870287D002834D150202F6969792B798DF8E0
+:2055400000008DF802101819C0B227B17A7F397F89180918C8B28DF8010068460FF039FEE2
+:20556000C8B12988012747764180A97880F83810E97880F839102979036980F8421019194E
+:20558000416480F848402F691FB13A7F416C89184164E860BCBD284614F05AFD10202875FB
+:2055A000BCBDC04674020120F0B50446A178606840182178ADF1440D0546F9B9217F0D2952
+:2055C00014BF00230123227C617841EAC20141EA431100F8011BA16913F050FE0646012BE6
+:2055E00004D104F1080114F0D7FD0836207C04F10801012804BFA07D307005E02978607821
+:205600000843287004F10801A7692E7804A814F0C3FD06A8394613F031FE0670A078237FF4
+:205620008DF80000E7788DF8013066788DF80270608A8DF8036060B9A18A40F201128A42D4
+:2056400007D194F8281004F11E000CAA0CF034FB03E0A18A0CAA09F0B3FF0CA8FF270390DE
+:20566000207C8DF84070022803D003280CD1022000E000208DF8400008210CAA08AB10A823
+:205680000CF078F908A8039020786368694604AA00F026FA044628780021102200F0F80065
+:2056A000287008A809F052F90CA80021102209F04DF9204611B0F0BD2DE9F04104460D4660
+:2056C000164610460021342209F040F9082D5CDB61782078357000EB012031460FF098FDD6
+:2056E00000280CBF01270027E178A078A2792379657900EB0120B274E179708103EB0520D2
+:20570000F174F579B081002D08BF082103D004F1080010217061357A084625B16018083112
+:20572000B061C9B20846002386F82030757973622DB17070605C491C7071C9B20846757F5E
+:20574000FDB1481CC2B2605C7270511C86F82000C9B27170A25C86F821208242A8BF7377EC
+:2057600010DA0C28C8BF0C20DFF85080450009192A46404613F08EFD7078C6F82480401923
+:20578000C1B270703078814202DD0020BDE8F081B379401A6418C5B2002B08BFB46209D0DC
+:2057A00007480E3D0E34EDB2B4620078357713F0B9FD2D1A35773846BDE8F081360100209D
+:2057C00014FB00202DE9F84F0AAF984691468A463D78009010F01CFFDFF8ECB0002426469C
+:2057E000071C15D16DB1012D42D1B8F1000F3FD05D46287880083BD3009811F0A7F9BDE8C3
+:20580000F88F009851464A460FF01EF8BDE8F88FDFF8B8A00AF11C00006895B9B8F1000F4D
+:205820000BD1B87848444010C0B2B87008B90120B870787808B903207870B878062817DDCE
+:2058400022E000B18047B8F1000F1CD05D46287880080DD35046026A12B1414638469047DE
+:2058600038780D2804DA401CC0B20C28387004D054EA060009D1BDE8F88F009811F066F9A5
+:2058800001247E7001E03E7001265D46323D95F8320080080DD3009814F01EFC48B11EB188
+:2058A000417901F0FE0141715CB1417941F00101417134B195F83200800802D3009813F044
+:2058C00089FCBDE8F88FC04616FB0020ECFB0020B0B5C16891F838300A6903F0030535F0C7
+:2058E000020702F8013B40D1D90803F00C0401D3042C08D1022D01D1590904D2C16891F8AC
+:205900003B1002F8011B0C2C09D1C16891F83C1002F8011BC168898F091202F8011B022D5F
+:2059200001D1590921D2C16891F83E1002F8011BC168C98F091202F8011BC16891F8401076
+:2059400002F8011BC168B1F8401034F008074FEA212102F8011B03D00C2C18BF042C04D164
+:20596000C16891F83A1002F8011BC46894F8391003F0020701F003010F430DD1618D090AF2
+:205980000AD2144D297884F84910297802F8011B2978491C297003E094F8491002F8011B20
+:2059A00033F07F0714D0C16891F839101170C16891F8394014F0030F0AD091F84B1002F8E5
+:2059C000011F990804D3C06890F84C0002F8010FB0BDC046AC0001202DE9F04307464FF60E
+:2059E000FE754FF00008ADF11C0D391DBD8101A88DF8008014F0E4F968460AF087FE07F1DE
+:205A00000409444601280BD1BDF80C00BDF802107E88B8818E4218BF6E4602D1012441E0AF
+:205A200046468DF80E807888ADF810000DF10E0008F0C6FF012808BF0DF10E0430460126AC
+:205A400018BB74B97888854206D1484612F0ECFF012818BF404602D138460CF0DDFB064636
+:205A60001FE0A089B881201D12F0DEFF012807D0484612F0D9FF012813D103213C460DE0A1
+:205A800038460CF0C9FB064606E080893146B88138460EF087F824B16580022120460EF0A1
+:205AA00081F834463E78A6B1384611F0FDFF01280FD10A48BD89001D0168AA0002EBC502E6
+:205AC000501889180A78164203D116430E7014F0C3F9204607B0BDE8F083C04630050120E7
+:205AE0002DE9F04F0C46834661782078D4F80C904018C6B2E0781D469246ADF13C0D0428E7
+:205B0000A8BFA77803DAA07800278019C6B212F011FB0E90E07813F005FC0D90494610226C
+:205B2000F01900EB050809A814F058F94FF000090146BBF1000F25D1E078042847DB00294F
+:205B400046D1684614F0C0FA09A8069621780797637800900D240D9E01951A46CDF810A08C
+:205B6000204FCDF8148058188DF8204052188DF8216040195219039069463868029214F05A
+:205B8000D2FA23E0E078042821DB09BB684614F09BFA09A8069621780797637800900D248B
+:205BA0000D9E01951A46CDF810A00E4FCDF8148058188DF8204052188DF821604019521990
+:205BC000039069463868029214F0AAFA014609B15FFA81F90E9813F090FD48460FB0BDE8AB
+:205BE000F08FC04608DC00202DE9F04780463D49D8F80460C86CD1F808A07F2500220124BF
+:205C0000A946ADF1200DB0438446C86404FA02F01CEA000F10D05FEA0A074FF0000007D08C
+:205C2000BB789A4204BF401CC0B2BF69002FF7D18542C4BF051C9146521C1B2AE6DB002EC1
+:205C40000D4636D1284C5FEA0A0725D02168B5F848004FF6FF72254B3E88B04219D1BE78AB
+:205C6000B14516D19E1F3688B24208D114F07FFAA5F848003E88B0420ED057460AE000245C
+:205C800085F84A4009B1C4208847204612F074F824E0BF69002FDFD185F83C90FEF7CEFDA8
+:205CA000E0B10020216885F84A00B9B1C420884714E0EE64684600211C2208F047FE8DF8B1
+:205CC000044000268DF80760D8F80400009095F852708DF80570684608F09EFF08B0BDE821
+:205CE000F087C046E4FA002044040120E4FE00202DE9F04391460A68D9F8004016788046C7
+:205D000000271D463846ADF1140D242E02F101020A6058D11678521C4C2E0A600ED1AA6810
+:205D2000E41C24F00304241D54F8040C414614F0A3FB2968EF600127091A2960462E1AD16F
+:205D4000E41C24F00304241D54F8040CE41C029024F00304241D54F8040C00274146039000
+:205D6000AA68ADF8047001A814F082FB2968EF600127091A2960532E25D1E41C24F0030488
+:205D8000241D54F8040CE861C9F80040288B0090A968EA69D8F800004B4614F065FBD8F8E0
+:205DA0000040002744B1A9688142D8BF481ED8F800100918C8F80010D9F800402968EF60F4
+:205DC0000127091A2960662E0BD1298B012904D0E41D24F00704083403E0E41C24F0030473
+:205DE000241D1FB9E9690E700127EF60C9F8004005B0BDE8F083FEE73F482DE9F04F001F95
+:205E0000ADF1140D00F1A80100F1980B8046029100F1AC0103914FF4804013F001FDE8B16D
+:205E20004FF00450D0F89813D8F8046090F88503C3F38857C1F31501C0F38002C1F31501BA
+:205E4000B8050143B06841EAC2716A4602F0AAFAD8F804008168012012F090F900270226CD
+:205E60000DF10409234D049759F8044F236883B32068806913F0D4FC824620680023524658
+:205E80000FF034FB1AF00A0F08D1BAF1000F20D0206847F48047C8F8B0001AE02068144955
+:205EA000AB688069014023EA0100A8602068C1692A6822EA010028602168102012F05EF9A4
+:205EC00021680BF1080012F059F8049847F002072060761EC8D127B108F1E000394614F025
+:205EE00093F904F0D7FEF8F74FFA05B0BDE8F08FFDBFFFFF0C10044034F500202DE9F04F84
+:205F0000DFF8E8A0DFF8E88000244FF001096FF001064FF6FF7B2546ADF1240D01A80090DE
+:205F200029462246102303200FF084FC00284CD1BDF804109DF80970A80000EB45102AF88F
+:205F40000010504447719DF80A3083719DF80820027180F809900482BDF80610C4729DF8C5
+:205F60000B7041800623C771049A0372AA278772B2F1FF3FC46016D103798BB11E4A1F324A
+:205F80001778032B0CDA2FB958F82720C26158F8272009E058F827309A01A2EB830202E006
+:205FA000C661866103E0C261826180F820408B450BD08DF81490ADF8201005A80CF08EFF33
+:205FC00018B1BDF8040011F04FFF6D1C332DA5DB2046042111F090FD3328A4BF05480470EF
+:205FE00007F0DEFB09B0BDE8F08FC046E40D002048BC020035040120ACFE00202DE9F84362
+:206000001D463C4B9433089C1B68C3F38018DB0915D20388A3F6020343B141F21E069B1B65
+:2060200004D000F11A030B60C06903E000F112030B604069106000202860206056E0038894
+:20604000A3F60203F3B141F21E069B1B17D041F6E6769B1B05D0876AC36A90F82460BC46C0
+:2060600003E0D0F820C0436A002600F11A070F60C1691160C5F800C02360007E0DE0466A8B
+:20608000836A01E08669C36900F112070F60416911602E602360C67B007C00F00707286827
+:2060A00088B140F203714FF6FF72052311F060FD8146B9F1050F06DA3046394609F0BEFCB8
+:2060C000296841F82900206880B140F203714FF6FF72052311F04CFD0546052D06DA304673
+:2060E000FF2109F0ABFC216841F825004046BDE8F883C046402108402DE9F8433A4C364D4A
+:206100008146241D54F8040C800807D254F8080C05F14D01000C40F0F000087033484FF0B8
+:2061200001214FF080531838DFF8A880C0F804140088D3F8F0012668016803F5F8773046F4
+:206140008847B00E03D2700E24BF022028703868426831464846904710F010FD38B120681E
+:20616000810C2CBF002040F307200FF029F92048BC300068C0F3053188F80010410A39BF94
+:20618000402185F823104021E974800900F0380040F46050A8F85C003868816830468847D1
+:2061A0000E490F4A0AE0105C9478131D844299BF184410F8010C18444078086008684B686F
+:2061C0009842FCD10228EED1064901200860BDE8F883C0460EB00C400962084000600C40C8
+:2061E000B0C3020094046042B04F005018A00C40501300503D492DE9F04105464C310868E5
+:2062000000286CD1384CA7683E1C0BD068883988884203D12979BA78914218D03E46BF69C7
+:20622000002FF4D11C2006F015FDD4F80880071C58D000211C2208F089FB4FF6FE70FF23D7
+:206240003881B8F1000FFB720CBFA760B761687AB871287A78712879B87068883880287BCC
+:206260003875287A012806D107F10C00FF21082208F06CFB05E007F10C0005F10D0113F032
+:206280008BFFA97A06292DDD6879012802D013F079FE38B3B87A0026884202DAEA7A102A3B
+:2062A00005DB884204D1F87AE97A884200DD0126AB791BB9E08F2988884206D12EB1288874
+:2062C0003881A87AB872E87AF872E87908B101203871A87908B10120F870BDE8F08109681F
+:2062E00028468847BDE8F081E4FA002034FD00202DE9F0413A4D04462868ADF1200D18B9B8
+:206300000FF07EFF286840B330490978A14224DD4FF0FF3113F0FBFB2D490C2014FB001473
+:206320006768A668387801282ED0B268511EC843B86028683368844619420BD17068824235
+:2063400008D8B9680140814204D1706930BB308B042804DB604613F04FFF002431E0DFF8D6
+:20636000748058F82030A3B9684613F0A9FA00208DF80C00F1698DF80000307E0491694657
+:206380000EF0AAFC031C01D1002417E0308B48F82030114A815C491C815400E003687B606A
+:2063A0001048318C0D4B01607A681A60204612F04BF90120387020460FF0F2FF286813F055
+:2063C0001BFF204608B0BDE8F081C0464CBF020070C1020044130120D8130120A0130120D1
+:2063E000A8130120A413012038B505461446480817D2880872D31C20002113F0FBFB1D20B6
+:20640000002113F0F7FB1E20002113F0F3FB1C20002111F099FB00211D2011F095FB002114
+:2064200059E01C20002113F0E5FB1D20002113F0E1FB1E20002113F0DDFB284606F092FF77
+:2064400021460090C20F0888A0F6020068B141F21E03C01A09D041F6E773C01A09D191F85E
+:20646000240010F07F0F04D019E0C87B10F07F0F15D1012A0DD01C20002111F065FB1D20E3
+:20648000002111F061FB1E20002111F05DFB1C2014E01C202F2111F057FB3221BCE7012A96
+:2064A00010D01C20002111F04FFB1D20002111F04BFB1E20002111F047FB1E20012113F0AA
+:2064C00099FB38BD1C20002111F03EFB1D20322111F03AFB2F211E2011F036FB38BD70476A
+:2064E000F0B50E1C14460546ADF1140D04D0084613F022FE071C1ED1324F33203979FF2964
+:2065000005D0401E07F12407F8D100274BE001208DF80000ADF80250314601A813F050FCFE
+:206520006846FFF759FABDF80C00002678802846BE7111F099FC00200122014614B1052CD2
+:20654000B8BF04213D803C71797106263E727A72AA25BD723882F871F8728023F86087F87E
+:206560002130E4B118480678032C18DA17483EB900EB8601096B00EB8600F961006B0AE0DA
+:2065800000EB8600036B9901A1EB8301F961016B8801A0EB8100B86187F8202003E06FF0FD
+:2065A0000100F861B8610020042111F0A5FA332802DB07490020087007F0F2F8384605B04F
+:2065C000F0BDC046E40D0020CBFE002018BC020035040120F0B5364D384C0028ADF1140D4B
+:2065E000697820725ED129B9207818B9082012F0D5FE697831F0010051D16846002110228B
+:2066000008F0A4F913F0C6FA002848D0294D05F1240006463930074611F0A3FF20B9284963
+:2066200038461C3113F0B8FD06F1160153200EF0F3FF95F83200000934BF0020012004A9BD
+:206640008DF8100052200EF0E7FF082085F84A0007F0A6F808F068FA1A49486808B901207C
+:206660004860E0794FF440710BF09CFA684610F0FDFA6846002110F095FD95F8650010B9D3
+:20668000002004F093FD68460021102208F05EF909480078012802D0012011F06DFB012097
+:2066A00010F03AFFE07902210BF07CFA05B0F0BDACFE0020E4FA00208EFF002034FD00208C
+:2066C000FCDB0020480401202DE9F84F13F0D9FC364C374D84F82400E87984F82B004FF034
+:2066E000020B84F836B00F2784F8287084F8507084F85170002684F82C6084F82D604FF0F2
+:20670000010884F82F8084F890804FF0050984F83090A87984F82500687984F831804FF61B
+:20672000FE7A84F826002348A4F83AA0007884F83200E878A086A87C84F83C60082284F8D0
+:2067400037002879A4F83EA0314684F8380004F1400008F0FBF804F15D0005F14401A4F873
+:2067600048A013F019FD687A84F88E0084F86560314684F88A70287A84F88B905A4684F8A9
+:206780008D00E87C84F88C8004F1920384F88F00892013F021F908B1A4F8926030460FF069
+:2067A000C7FCA4F89460BDE8F88FC046E4FA0020ACFE0020E612012070B5324C0D46A808CD
+:2067C00050D2E8085DD301250420657010F08EF92D480068006B8047A060606804F1980667
+:2067E0000146306870B10069064649B18E4207D0B16AC90803D3436A0421002298477576C3
+:20680000314661604868214900780860022010F06DF9112003F058F91D48007884F824507C
+:2068200010B90E2003F050F960684168886808B9C86810B1174813F0FDF91749072000260D
+:2068400008601649174B0E60154D4E600A68A36245EA020008601A2013F0BCFC192013F050
+:20686000B9FC70BDFCF77EF8204600F1A001096811B909F0FBFC70BDE03045F0020113F032
+:20688000C3FC70BD30F500208C010010D021084052C30200510007060000046014100440B0
+:2068A0000240004039310100F8B5134602465468956808464FF0FF31203856D0401E5FD01C
+:2068C000401E33D0401E3FD0401E26D0401E1DD0401E52D1D4F8C070002F5AD094F8FE707B
+:2068E000002F56D02968486A40F003004862D4F8CC002A6941686F69096847EA02008862E9
+:206900002968486840F00200486026E0D4F8C070002F3ED10020014605E0D4F8C070002FA5
+:2069200037D10120002184F8FE0032E01E78FF2E15D094F8FB0010F063FC84F8FB6094F890
+:20694000FB00696B11F000F994F8FB00FF2804D010F056FCFF2084F8FB00002119E0104694
+:2069600023210022FFF7A0FF12E094F8F90001280FD1012084F8FC00EFE76FF0010108E0E4
+:2069800094F8FB00002110F051FC002084F8FC0001460846F8BD7047B0B504462079ADF183
+:2069A000580D042869D136480078002865D013F0F1F8002861D1AB20002113AA0CF0D4FDFD
+:2069C000276813A8874207D0002F56D013A8394612F00EFB002850D038460DF1550106AA69
+:2069E00007F036FF9DF85500002846D09DF82800012842D14FF48170002110220BAB12F00B
+:206A0000EBFF032008210BAA0FAB8DF8540015A80AF0B0FF002568460C228DF81450294639
+:206A200007F094FF41208DF80200ADF8005001278DF805701A238DF804306846FEF72CFD0B
+:206A40009DF81400C8B90398456C0F272F702079687012F0EFFB0146082213A812F01AFC4A
+:206A600013A9A81C13F098FB0FA9102205F10A0012F010FC68460DF08FFF16B0B0BDC04696
+:206A8000ADFE0020364AF8B52120742113F0B6FA0A2814BF002501250C2006F0DBF8071C0D
+:206AA00014D0FF210C2207F051FF2E4E002407E0214601200C223B460BF0EAFD641CA4B2E7
+:206AC0003088A042F4DC38460EF066F8102006F0C1F8071C10D0FF21102207F037FF0024ED
+:206AE0000320214610223B460BF0D2FD641C332CF6DB38460EF050F81B48006820B18047B8
+:206B00000A2808BF45F008050FF09BFE0A2808BF45F01005142006F09DF8071C1CD0002170
+:206B2000142207F013FF4C2014213A4613F066FA0446092C04D14C2014213A4613F064FABC
+:206B400038460EF029F8094A712008213F3213F055FA04430A2C01D145F020052846F8BDFC
+:206B600008FB0020300501200C030120B9FE00202DE9FF41384D95F83C00012101AA0446DA
+:206B800012F03EF80221204602AA12F039F89DF80A4095F83D10EA78002605F130074FF0A8
+:206BA000100C10E08C4214BF6346BDF80830880000EBC100491CC019838391FBF2F303FBAB
+:206BC00002F0091AC9B295F83E00401C90FBF2F35343C01A8842E5D195F83D40A84635E091
+:206BE000A00000EBC400C119898B10291AD03A180421022320461C320DF040F86870E86888
+:206C000061036A46042313F037FA009800F0FF007C2802D0FE280BD1FEE7204678210FF023
+:206C2000EDFE05E0204602F0F9FB761CF6B26870E97898F83E30641C94FBF1F04843241A0E
+:206C4000581CE4B290FBF1F24A43801AA042C7D130460090BDE8FF815CFC00202DE9F0472B
+:206C6000ADF1900D13F0B2FA2D4A1178002952D1114601240C7013F033FCFAF76DFB092032
+:206C800002F022FF20A812F0BDFF4FF0FF302190254A2448102120AB0EF07CFA2348244919
+:206CA00090F800800B7800274046054683421BD3DFF880A08600A1460DEB0600041FDAF847
+:206CC0000000315821F0FF0044F8040F880807D2E8B201F0010112F08DFF09FA05F0074306
+:206CE0006D1C361D9D42EAD91549134C4FEA8800C0EB830201F1D003121D1F600DEB0001FC
+:206D0000001904F0F3FE0D49086820F4F85040F40050086001E013F0E3FB24B0BDE8F087B5
+:206D200008060120241201207D2F02003BBF02003CBF0200D4C202000010084000300940BD
+:206D4000002002402DE9F04F09AF8046ADF11C0D9B460491386805923D7A06901946404658
+:206D600010F0D2FA0828A8BF4FF6FE7905DA2E4E410001EBC00136F801904FEA251A680903
+:206D800034BF0820102069110391A90924BF0830C0B28DF80100684611F036FC061C40D0C2
+:206DA0000124B47712F046FA706201A9484611F0D2F830B95FEA5A0006D3C14504D106988E
+:206DC00000E001A874773062346902202070657084F802B084F803804FEA28232371049AA6
+:206DE00062711012A07148460CF0A2FC05994018E0715FEA5A0038BF002005D3069904F1F8
+:206E0000080013F0C9F908200399490804D379680019083013F0C0F9A6F802903046F4F73A
+:206E20002BFF07B0BDE8F08FA80100202DE9D04781461E46924688460846ADF11C0DFDF77D
+:206E400069FC404610F034FF304807684FB103208DF8080041460822684612F01BFA684659
+:206E6000B847ADF80290CDF8048002208DF808000024ADF80040404613F05EF936BB28B929
+:206E8000484641460CF032FAAA281FD112F082FEE0B9AB20214603AA0CF066FB404605A968
+:206EA000224607F0D5FC1A4826300078012807D19DF8140020B98DF80940684608F001F981
+:206EC00001208DF80900684608F0FBF8404613F033F978B1007968B105280BDABAF1010F2D
+:206EE00003D0012818BF022801D113F081F940460BF080FD4846214611F052F9484610F079
+:206F0000B3FF11F037FE07B0BDE8D08708030120ADFE00202DE9F84F06467068B6F80A8026
+:206F2000447800F1020B042C10D0012C07D0062C05D090F81A9000F1120500270AE090F8A9
+:206F4000129000F1130700F11B0503E000F1120700F11A054FF0010A5FB1384611F064FD3C
+:206F6000012806D112F066F90146384612F040F88246BAF1010F1BD0B8F1000F36D1384606
+:206F800069460FF0F3FC012830D10021BDF800007172174F7081387820B17068007805281C
+:206FA00008BF0121317330460BF009F9BDE8F88F202011F092FA071C18D004203870A7F862
+:206FC0000280594610223C71B81D87F8059012F061F907F11600294612F0F2FE87F81E90D0
+:206FE0000448FC77007839460CF056FBBDE8F88FB8FE00203BFD0020F0B5344C054604F1CF
+:207000003A0000880026ADF12C0DA84228D0284613F062F8071C24D03879012818BF022812
+:207020001FD18DF818607888ADF8240006A80BF055FFB0B128483988001D01800DF10B0064
+:2070400007A913F0A9F812F005FE8DF81660ADF8140039790222684605F0B6FDFE6032E087
+:2070600025B986BB284610F0FFFE2CE00BF0BEFDADF82600BDF826000DF12601608753209F
+:207080000EF0CAFA1248BDF82640076810F0E8FD1048007810210AF085FD97B1D6257868C5
+:2070A000007858B1042011F018FA011C06D00D704C807868406800780CF0EEFA3F68002F22
+:2070C000EDD110F079F90BB0F0BDC046E4FA0020240501203BFD0020ECFB002030B50D4633
+:2070E00004463649E07AADF1140D401E4ED0401E37D0001F14D0401F5CD16868002859D01D
+:207100000846A27A2368E1680270981D0122009001A812F0C3FAE068401CE060696846E014
+:20712000E868002846D0E1680DF10200012212F0B5FAE068401CE06012F0E2FEE168ADF8F0
+:20714000040001220DF10600891CE16012F0A6FAE0682168401CE060498AADF80010E96836
+:2071600025E0A86830B3E1680DF10200012212F095FAE068401C0190E0602068817B0229F6
+:2071800004BFC088ADF80000A96811E0286888B10846A27A2368E1680270981D032200905A
+:2071A00001A812F07BFAE068C01CE060296802906846884705B0002030BDC046810301203E
+:2071C0002DE9F04180463448344C06AFADF1200DADF81E300578ADF81C1094F84A001646B3
+:2071E000042814BF0828C22052D0BDF81E004FF6FE71814208BFC3204AD0684600211C2241
+:2072000007F0A4FB032007A984F84A0050200EF003FA4B200DF11E010EF0FEF984F83C603F
+:20722000BDF81C00BDF81E3084F832504146A4F8480004F15D00E38712F0AEFF05F0CE05DE
+:2072400045F080058DF80B60022300268DF81A5038788DF81630BDF81E208DF80860BDF83A
+:207260001C70ADF80E2004F15101ADF81870401C84F85C000F250D7054200EF0CDF904F129
+:20728000500147200D700EF0C7F9684602F048FF08B0BDE8F081C046E6120120E4FA002029
+:2072A0002DE9F047334A32491768334A4E8E15784FF6F8798846ADF1200D01E012F0E1FE13
+:2072C0008145FBDD0028F9D02C4CE76409F107010F2784F85250824684F85070B14284F893
+:2072E00051704FF0000584F8535006D1B8F83200814201D112F0C5FE0646A4F8486008F1CE
+:207300003C0011F02EF908F13C06012804D104F15D00314612F040FF04F15D00064611F027
+:2073200020F918B9E220314610F0D6FCA4F83AA084F85070E58784F85170052084F85C5070
+:2073400029461C2284F84A00684607F0FFFA8DF804508DF80750E06C009094F852608DF8C8
+:207360000560684607F058FC08B0BDE8F087C046ACFE002040FD00208DFF0020E4FA002004
+:207380002DE97C430D460446A16A4878CA78897801EB0229217F042959D1DFF8C08002281E
+:2073A0004FF0010625D9C01E07283FD90838012818D9801E02D0401E38D036E04046A0F107
+:2073C000320191F83200800830D391F84A00082802D14846FFF710FE48460BF05FFFC528F8
+:2073E00024D11CE04046007880081FD30DF094F81CE040460078800818D34846002107F088
+:20740000F7FF70B1817911F0180F0AD0A1890091028843886189104600220BF04FFE002679
+:2074200004E0484612F05EF900E0002512F0F2FE60890DF051FB50B1A07C022807DBA18905
+:20744000404608300088884201D0012E02D00020BDE87C832846BDE87C83C04616FB00203D
+:207460002DE9F04116468846044612F0AFFE074631488325B8F1090F36D8DFE808F0554A07
+:207480004744402917053C37044694F82400E8B9D4F89800D0B9316804F1E00011F05AFF19
+:2074A000316804F58E7011F055FF3FE0044694F8240058B9D4F8980040B93168192012F08C
+:2074C0008DFE31681A2012F089FE2FE000252DE0306828B1012807D180200EF0ABFE25E0C6
+:2074E000802011F035FC21E003251FE02020314610F044FE1AE031781048017016E031689E
+:207500001030016012E03088A0850FE0308860830CE0012026696369607606F1600020615B
+:2075200003F16000606101E030682060384612F0D7FF2846BDE8F08130F5002070F7002097
+:2075400070B50546A87A0024ADF1180D60B9E87A400909D22D480078012804D12F4816306B
+:207560000078012800D0C824002C49D12888696805AA0FF063FFA87A50BB2548E97A007862
+:207580004A0902D2C80818D31EE0E8B900208DF81600204858C8694658C109C881E809001C
+:2075A00068686A460DF1160107F052F99DF8160018B19DF81000022806D0E87A000938BF79
+:2075C000AD2406D3002408E0284607F07EF904461CB1686810F06CFB94B90F4E306890B148
+:2075E000288869680822ADF800000DF1020011F051FE28893168ADF80A006846884702E093
+:20760000284604F03BF9204606B070BD56FE0020340401200CC1020094FD0020ACFE002074
+:207620002DE9F04FADF1140D04900EF07BF95FEA000861D0002427463D46B94623E008EBA5
+:20764000C500401C834612F077FDD0B10179012918BF022915D190F82000012811D10C20DE
+:2076600005F0F8FA061C0CD0594612F095FDC6F80890002C0CBF341CCAF808607F1CB24698
+:20768000FFB26D1CEDB298F80000A842D7DC002F2FD00220049E8DF80C007088ADF80400C0
+:2076A000F80005F0D7FA061C21D074B14D46A14606EBC500494612F06FFDA46848460DF010
+:2076C0006BFA6D1CEDB2002CF1D148F21F00009004983A4601A93346113002F065FB3046FE
+:2076E0000DF05AFA05E02046A4680DF055FA002CF9D140460DF050FA05B0BDE8F08F704743
+:20770000F0B50D464FF0B30C04460021ADF11C0D0E46DFF8C4E00027042238461EF80E3F44
+:20772000FF2B04D00346581C9942C0B202D0521EF4D100E0774627B17A799219D6B2B442A9
+:2077400003DB491C0429E4DB42E028460021182207F0FCF87879A41B2418E0B207EB400074
+:20776000C088688111F066FD0146284612F014FD7878012822D07888ADF80C0004218DF846
+:20778000001068460BF0AAFBE0B103208DF8160001A90DF10E0012F0FFFC9DF816609DF8E9
+:2077A0001600032E287518BFBDF80E0009D105F10C000DF10E0112F0EFFC03E001202875D4
+:2077C0007888A8813878287238794FF0000CA87507B06046F0BDC0465E0100202DE9F04741
+:2077E00088461546814600212022ADF1200D684607F0ACF84046103808D0083804D0083828
+:2078000014BF0026032602E0022600E00126012404FA05F7274D4FF0805000F5D87A2F60BD
+:20782000D0F8B001416927208847C5F87C430321C5F88013C5F8FC42C5F884136868B0420E
+:2078400018BF6E60B8F1180F45F8047C1CBF41464E4606D168464946182204F047F96E46CA
+:20786000202130460EF07EFC204612F06BFCD5F88C036FF39D000028F6D0D5F88C636FF3A3
+:207880009D06C5F88463DAF80000016A27208847DAF8000001692720884716F0404F04D192
+:2078A0002868074218BF002000D1204608B0BDE8F087C046044402402DE9FC4707460E1C8D
+:2078C00014BF4FF0000A4FF0E80A002F5BD0BAF1000F5AD17868401E78603F210170BD6D0B
+:2078E000002D0CBF802000207968DFF8A4900225083E491E7960A84608703889A7F85450CD
+:20790000801C388116F8080FFF2839D02A2834D1706890B3D9F80010D1F8B8108969884718
+:2079200005467868401B78607168CA0809D2D9F80020D2F8B820D46900233A46A04788B1D0
+:2079400013E0D9F8040080680078D9F800408DF80000D4F8B8007168C46978683A466B46CE
+:20796000A04710B9EB20BDE8FC873889B7F85440401938816019A7F85400B8F10108C1D15E
+:207980007868386501E04FF0E80A5046BDE8FC87140100202DE9F84F894600274FF6FE7B54
+:2079A0009046824601253946CDF800B00CE0012F08BF012106D012F064FBC1B291FBF7F0ED
+:2079C0007843091A00273D46274B322233F81C0F834517D0824515D0814513D0804511D059
+:2079E0005E7C7EB1082E0DDA072E0AD0012D05D07F1CFFB2B94205DCBDE8F88F7F1CFFB2AF
+:207A000000E00090521EE1D1184A332332F8240F83451CD082451AD0814518D0804516D001
+:207A2000567AA6B1082E12DA1479012C0FD0022C0DD0072E0AD0012D05D07F1CFFB2B94200
+:207A400005DCBDE8F88F7F1CFFB200E000905B1EDCD10FB10029AAD00099584688421CBFF8
+:207A6000081C80B2BDE8F88F50080020C00D0020844610460029624667D0422A0FDC412A35
+:207A80004EDA083A4FD0521E3ED0521E54D0521E2DD0521F47D0083A222A10D97047433AAB
+:207AA000012A37D99D3A022A21D9083A012A2BD9921E1CD0921F18D0521E14D07047DFE816
+:207AC00002F032233B163936341432233B163936341432233B163936341432234444444438
+:207AE0004444231614C0102222E0082220E0096800F8011B0A0A00F8012B0B0C00F8013B8B
+:207B00000A0E00F8012B70470A7800F8012B0988091218E04B780A7802EB0322921C07E03C
+:207B20000A78521C04E009780DE0072200E0062211F0B4BD0522FBE70A7800F8012B4A78EF
+:207B400000F8012B897800F8011B70472DE9F8430446994690460E1C44BF0020011C5CD44B
+:207B600012F04EFB05463146802220460DF0A0FC071C04D097F8331031F07F0106D12846A8
+:207B800012F06EFC02200021BDE8F8834FF0E0400A2107F1200640EA090941EA080896E879
+:207BA000030008EA000019EA010608BF00281CD0284612F055FC07F1200003C804F1B0069C
+:207BC00004F1B00508EA000809EA010986E8000395E80C0007F1200696E8030007F120054E
+:207BE0009943904385E8030014E00D48B968884203D0B968C4F8A810B86004F1A00080E8B5
+:207C00000003284612F02CFC04F150004FF0FF3111F07DFFB03494E80300BDE8F883C0460F
+:207C2000CB1302002DE9FE43144681460EF084FB88460646FF2E21D02E49B00000EB06100F
+:207C40000A5C4518520852D3EA884FF6FF7393424DD009180F698FB13B681888844203D012
+:207C60007F68002FF8D109E047B13BB14846414622466B4604F0EEF9012802D00220BDE88D
+:207C8000FE831D48007880210CF066FF002804BF0024A04604D00FF001F84FF00108044631
+:207CA000A88818B129890919884220DA9DF80200024611F082FA38B110463B68019A991DA4
+:207CC0009B1CFAF72FF890B111F0F4FF3046F5F779FFB8F1010F03D1204600210CF0EEF8D0
+:207CE000FF2130460A460CF027FD0EF0EFFF0020BDE8FE83080D01204DFF0020F8B52F4C82
+:207D0000334D6788BFB905F108000068D0F8F4002B4BC18F012606FA01F08102A1EB8011DC
+:207D200018784FF47A7201F570714843B0FBF2F081B2A18000E0A1882078B9421ADD214845
+:207D40000068214F016C386888472178C0B28142B8BF20706088401C608012F089F84FF4B0
+:207D60007A71B1FBF0F0194904F10803002204F0B7FFF8BDA968D1F8F46040B20FF043FE49
+:207D800096F84410B2695054A868D0F8F40090F84420012700EBE20002F0070207FA02F1A6
+:207DA000427900238A434271AE686380D6F8940023700078042109F0F5FEF8BDD004012044
+:207DC000D8000020E0FF002080000120FD7C01000C010020F8B50020314C8DF8000012F093
+:207DE00069F9A41EA2782F4D012191404FF6FF72521802402868D0F8B810628108780028C9
+:207E000029D08A6B3AB342F21A0069469047204867790678CEB1C7B99DF80060AEB128680A
+:207E2000D0F8B800C06D80B1804707461E48017857B16868406866890078083010FB01F056
+:207E4000B7FBF0F17018608167799DF80010608907FB01006081607810B905F013F801E052
+:207E600008F090FE2868006C006878B109480B49007840B90848007828B9832208460270CB
+:207E800010F0E4FAF8BD022208460270F8BDC046FC13012005140120071401200A140120CB
+:207EA0004E02012014010020D800002010B504462088ADF1180D0CF00FFE002859D111F04E
+:207EC00069FE002855D1A0782B4958BB207A04284FD1084600686A4605A906F0B9FC04465F
+:207EE0009DF81400002844D09DF81000012840D102209DF813308DF8100033F07F0003D0BA
+:207F00000DF113000FF0F2F80420214614226B460EF098FB002012F03BF801200146F0F7C0
+:207F200071FB26E0207A042823D1084600686A4605A906F08DFC01469DF81400C8B19DF884
+:207F40001000012815D1002201929DF81300009230F07F0003D101208DF81100FF228DF843
+:207F6000102004206B4614220EF06CFB03490220087006B010BDC046B80001206DFF00208D
+:207F800070B5334D06462868D0F83C03ADF1300D8047002818BFFC2057D16846314611221C
+:207FA00003F0A4FDB47C707CF37C8DF812402A688DF81100717D8DF81330D2F8D400B47D1E
+:207FC00090F853008DF815108DF81400002104B10121347E8DF8161096F825208DF818407E
+:207FE000F07D8DF8252096F824308DF81700F48C8DF8243006F119010B220DF11900ADF879
+:20800000264003F073FD707C002448B9812004F021FE0A9078B1FF21812206F097FC0CE0D7
+:208020009DF815000A9440B1810001EB401004F011FE0A9008B91A2406E02A6802F551727C
+:20804000126807206946904720460CB070BDC046140100209EB501468A695078137803EBA1
+:2080600000232E480088984212BF00272C4F3F1D2C48006857B948F202000090087C019069
+:20808000487C8022891C0FF0C3F99EBD002200F8012B00F8013B1C1200F8014B3A78D3103E
+:2080A00003F0020402F0070203F00103234342EAC30200F8012B7A7802F0F80302F0070280
+:2080C0001A4300F8012BBA7800F8012BFA7800F8012B3A7900F8012B7A7900F8012BBA7912
+:2080E00000F8012BFA7900F8012B3A7A00F8012B3A89121200F8012BBA7A00F8012BFA7A16
+:2081000000F8012B3A7B1023027001F11100891C48F2020208F002FD9EBDC04650FD002036
+:20812000E01201209CFD002070B5064600210C22ADF1380D06A806F009FC0FF058FF30F0B1
+:208140007F000CBF002501250024072021460C2206AB0AF09DFA30B92DB1072021460C22E5
+:2081600006AB0EF06FFA641C052CEEDB07A8FF21082206F0EBFB641EA4B207200C2206ABBA
+:2081800021460AF085FA30B92DB1214607200C2206AB0EF057FA68460021182206F0D6FBAC
+:2081A000822018216A4611F029FF30B9012E04D1822018216A4611F027FF09A80021112267
+:2081C00006F0C4FB3A20112109AA11F017FF30B9012E04D13A20112109AA11F015FF3B20F8
+:2081E000112109AA11F00AFF30B9012E04D13B20112109AA11F008FF0EB070BDC8B5071CD0
+:2082000065D097F84000433080B210F066F9061C5DD097F840200021433206F097FBE220F8
+:2082200000233070391D737091E80D00311D81E80D0038693061387D3075B87DB075F87D9D
+:2082400007F11803F0751A6806F118000260596841601A890281788C708497F8250086F801
+:20826000240097F8260086F8250097F8270086F8260097F8280086F8270097F8290086F896
+:208280002800F86AF06297F8300086F83000786B706397F8380086F83800F86BF06397F81D
+:2082A000400086F8400097F8402007F1410106F1410010F0EFFFF22010F00EFE18B930460C
+:2082C00010F0F2F9C8BD007931460BF0E5F9C8BD7FB500242E482D4D2F4E04702D482C7096
+:2082E00031680470D1F800016C70C089D1F850126C61103080B28847286120B93068D0F887
+:208300004C058047286900908DF804409DF8051004F0030221F003010A438DF805209DF817
+:20832000051064F383018DF805109DF8051064F307118DF805103168D1F80011C9896A468B
+:208340001031ADF80610296913680B6052684A60E8612C6202F042FD7068C168087838B9CB
+:208360003068D0F858242046014690477068C1680A4804700A4D2C70087828B93068D0F822
+:20838000582420460146904700907FBD681101200514012007140120140100200A1401208D
+:2083A000FC130120F0B50E460021ADF1140D0191029103911446049103AB02AA04A9009174
+:2083C00001A9FDF71BFE8325310824D2E0B1039F87B10499C6F3150271B1019840F22B21FE
+:2083E000028038460FF0BBFA0298049907F044FA039826E0C6F3150240B1019800884FF695
+:20840000FF71814202D132E0C6F31502019802806280102029E0002829D00399A9B104998A
+:20842000C6F3150699B101984FF6FF720280084632462B210FF093FA0298049907F0BEFCC7
+:20844000049815212180606012E0C6F3150670B102982B2132460FF082FAFF2807D0019892
+:208460004FF6FF71018066601420208000E00325284605B0F0BD70472DE9F84391468846A7
+:2084800007460CF029FB002818BF002058D1384600210DF049F8494606F0AAFF0025041CD7
+:2084A00019D1384610F070F911F016FE002846D041794A0843D389084FF0010606D3404640
+:2084C0003946324608F08EFD80B938E0417941F0020141710AE06079032806D001282ED145
+:2084E000608807210CF0D2F948BB02261CB1A07910F0180F19D1404629460DF015F811492A
+:208500003A31098881420AD040463946324608F069FDA0B9384649460FF042FE0EE03846D6
+:2085200049460822FCF7D4FB08E0608839462A464FF6FE73009040460AF0C0FD01252846EA
+:20854000BDE8F883E4FA00202DE9F04781463148006888464FF47A711E46ADF1280DB1FB29
+:20856000F0F080B202FB00F50FF0E4FD82464146484610F0B9F90824071C36D1142004F00A
+:2085800069FB071C3BD0684600212422234611F063FF012E1ABF0020059005950120ADF84B
+:2085A00010001A48069729466A46002311F050FF0346174882683B609BB187F80490C7F8CF
+:2085C000088000243E73002A3C6108BF876004D0164633691BB937613B68184609E01E4643
+:2085E000F7E738460CF0D8FA09E0386811F054FF3868294611F028FF386811F021FF5046E6
+:2086000011F07BF820460AB0BDE8F087412702008004012040C402002DE9F0438046002165
+:208620000822ADF1240D06A806F090F90021142201A806F08BF90025FF274FF001092E4692
+:20864000274C8DF8147004202946142201AB0AF01FF8002837D1B8F1000F27D101A80090FF
+:2086600029463246142304200DF0E4F803A806A9082210F009F858B90199A80000EBC50057
+:20868000231883F809900B3101912150029A5A6004202946142201AB0DF0D4FF01A8314691
+:2086A000142206F053F98DF814700CE004202946142201AB0DF0C6FFA80000EBC500265048
+:2086C0002018466046726D1C032DBCDBB8F1000F02D030460EF00AFD09B0BDE8F083C046D8
+:2086E00064FE00202DE9F04F0546287B0E46ADF1240D80460DF0C0FF071C30D06C694EB317
+:20870000414608220FF026F8031C27D03CB3A07893F800B0B3F802A097F80A90089011F024
+:20872000C1FA5FEA000819D008200FF0D6FE011C14D0FE2008704E70089B8B7081F803904A
+:2087400081F804B0A1F806A0D8F8040000780AF0A3FF03E0414604220EF0FCFF0CB9002057
+:2087600023E0A088ADF80A00E088ADF80C00207A8DF81800F8680590607B2E688DF81900CB
+:20878000306A4178007800EB0120801110F0030F00F0030208BF0422237801A803F0400105
+:2087A00003F020030097F4F7E7F909B0BDE8F08FF0B50F4629490978ADF1240D81422EDDDA
+:2087C0003FB9274938C96A4638C20AC96F4682E80A00244C04EBC00438682568666810F06C
+:2087E0008CF9A861786810F088F9E861B86810F084F9286238692B686861397B297473B9A0
+:2088000005A811F02AFC0021079405AA069116488DF814100CF020F92860286808B900206D
+:2088200019E0707800280CBF4FF4C0274FF4A0277168002908BF0D4D03D0002814BF0C4DE6
+:208840000C4D30780C4910F0E9FC30782F43394607F0D6FC204609B0F0BDC04657BF020091
+:20886000E8C10200C4C20200E9110100026000200240002002200020F10D02002DE9FE4F41
+:20888000DFF8C08098F8410200284FD0002501212C4698F8412201FA04F0104203D1641C66
+:2088A000032CF6D342E098F841221020A040104218BF0D1C11F08AFC98F841221121A140BC
+:2088C0008A4388F8412211F00BFEE0B210F0EEFF60B3877A57B390F9099019490768012D20
+:2088E000446851F82960019710D0017A02290DD100F1100191E8000C00274FF0805317EA3D
+:208900000B0703EA0A0108BF002901D105F0A8FE012D04D0009600224FF0006303E000228F
+:208920004FF00073009201984946A04798F8410220B108F58E70002111F066FCBDE8FE8F8F
+:208940009430044030F500202DE9F84F0646307810F06EFA002818BF022052D1142004F0A5
+:2089600079F9041C49D02A4841682160666044600025A5603227277301236373A373256193
+:208980003078002839D0F12837DA1F4866680460B168DFF87880C8798968182208F10A09DB
+:2089A0004B460DF01CFF012808BF0225B768D7F810B097F80CA018224B46594650460DF011
+:2089C0000EFF012808BF45F00105B968404600F13A08F879302243460DF001FF012808BF4C
+:2089E00045F0010530224346594650460DF0F7FE012808BF45F002057570002C0CBF102002
+:208A00000020BDE8F88FC04658FF0020A8B6020020050120F0B500240646ADF14C0D254670
+:208A2000ADF8001020460DF102010EF0CDFD0A2854D00D284FD00DF10D016846022210F0CA
+:208A400089F868B90DF139016846022210F082F830B90DF13D016846022210F07BF8B8B11D
+:208A60000C2011F019FC071C12D029460C2211F015FCBDF80000FF2108223880B81C11F074
+:208A80000DFCBD72384610F057FF384611F044FB0EB309A93046082210F05CF878B90DF176
+:208AA0002E013046082210F055F8A0B10DF1360768460222394610F04DF860B906E00BAFBF
+:208AC00068460222394610F045F820B938466946022210F0E3FD641C052CA3DB13B0F0BD5F
+:208AE000F8B5064614460D462C200FF0F6FC071C5AD000212C2205F029FF6220387000236D
+:208B00007B70BD802078B87160883881A07907F111010EF04EFFA08907F11C01420824BFF2
+:208B200001223A77820824BF01224A70C20824BF01228A70020924BF0122CA70420924BFD4
+:208B400001220A71820924BF01224A71C00924BF01208871207900F0070038732079C0F3DE
+:208B6000C00078732079C0F30010B873607900F00700F8736079C0103874E079217A00EB54
+:208B80000120F882607A3876E17AA07A00EB01207883A07BE17B00EB0120B884207C39465C
+:208BA000B862F0B20AF078FDF8BD70472F4870B534380468B4F1FF3F08BF00240FF0F6FFE8
+:208BC00004283CD10BF064FC142838DB28481C4E002510380560306C806C804719480068EE
+:208BE00020B1194800682046FDF786FA174818490560184C0A686FF35B4244EA020008606F
+:208C000015490868C0F30130012806D10A681348104040F400320A600860114D0124EC617D
+:208C20003068016A142088470E49086840F4E02008600D492C6008680028FCD170BDFEE772
+:208C4000B001001080012843800520438C210840482003400000390128000940EFFFFCFC4E
+:208C600000002443002009400C00684250130050940460422DE9FC410646022568468DF888
+:208C800001500FF0C1FC071C52D03869042260240270411C0C700124BC76BC7710F0CAFA9E
+:208CA00078622449F87E7E8038B908462F3890F82420531C80F82430FA76387E012806D126
+:208CC0000846007818B9387808B90020387638460DF10601FAF7B2FC5FEA000825D0242012
+:208CE00003F0B8FF061C1DD00021242205F02EFE502001A90EF0F0FFBDF8040070813573DA
+:208D00009DF8063035727888F3773080F481787DC6F8208008497073304602F0E7FA30460C
+:208D20000BF03AFF40460BF037FF38460BF034FFBDE8FC8113FB00208D5D02002DE9F04119
+:208D400011F0C0F84FF08058D8F8E8014068804711F0E8F8054605F00C000C283FD0E808BB
+:208D600022D20EF091FD234F3C680646012001460FF078FE39687143884215D21E4DF020B3
+:208D8000B0FBF4F0311A284611F05EFB284611F057FB00BF00BF0120F7F758FB00BF00BF12
+:208DA000284611F079FB20E000BF00BF280918D208F5EC74206880680146104888470428D0
+:208DC000F8D0690903D2002818BF002000D101200DF0E2F90A4801210160006803E000BFBC
+:208DE00000BF11F0DFF900BF00BF11F071F8BDE8F081C04640C402001C15002000400340FD
+:208E00002C2009402DE9F04115468046287A1F460E46012803D010460DF021F900E0288801
+:208E20004FF6FE71814221D0264C04210E3C14F80E2F904512D12A7A012A05D16378012B3C
+:208E400002D1638883420CD0012A07D063782BB96288824202D12279974202D0491EE6D10D
+:208E600004E0314620460FF0E3F910B9B420BDE8F081637927460025002B13D007F1060029
+:208E800010D0211D31F8022F964207D17A796D1C521EEDB2D2B27A7112B903E020F8022BBD
+:208EA0005B1EEFD10DB100F0D9FF0FB1787930B96588384610F00EFF28460BF06BF80020F5
+:208EC000BDE8F0816C010020F8B5071C0C4604D0387A022803D0032801D0E820F8BD384613
+:208EE00004F016F8FF2818BF1E2046D1387A054610F0C0FA01210246002001FA00F31A4292
+:208F000002D0401C0528F8DB052804D1022D14BF032D1A2031D0022D07D01A4A7B6808322D
+:208F200002EBC00253603B4610E03A8826128DF80020154D8DF802406B468DF803601212D9
+:208F40008DF8012005F1080202EB80021B680B4D0B4C13603B7A022B19BF2A1C1268221C9F
+:208F6000126801FA00F6022B42EA060214BF2A6022603A7A0BF0D0FF0020F8BDBC10012006
+:208F800098120120B810012094120120F0B505462E4C6878ADF1140DF32850D0DF284ED0ED
+:208FA000E8284CD0DB284AD02068D0F8FC1128468847071C42D1687C00283FD095F83400BC
+:208FC00000283BD12268B83210680078002835D1D2F87C2105F1120109209047061C2DD03C
+:208FE0002068D0F8302405F10B01E72090472068D0F8302405F10801502090472068D0F8B3
+:20900000302405F10A01E12090474FF6FF7202202368ADF80420A97A8DF80C00D3F8C07147
+:2090200000912B89304601A9B8470746F32F05D0DF2F03D0E82F18BFDB2F05D16F70206872
+:20904000D0F804122846884705B0F0BD140100202DE9F0412E4C2068E03081680D68002D7A
+:2090600054D001686A680968914206DAD0F86C0480472068D0F8E80005685DB10DF07AFA4A
+:209080006968884206D2083CA068D0F8D4048047BDE8F0812168D1F8E80000680AE0206880
+:2090A000D0F80015404688473846A8472168D1F8E800006850B34668002E0BD5D1F84C0596
+:2090C000804721682068D1F8E810D0F8E800096800684E68077B856880460DF04BFAB0424F
+:2090E000DDD22168E0318868006840B1096840680968814203DD0BF04FFFBDE8F08110F052
+:20910000DDF92168D1F8E81000200860BDE8F081140100202DE9F04F2E4C09AF94F80080C9
+:209120003E798B4692460546994600212C22ADF12C0D684605F00AFC2B7A032B8DF800302E
+:2091400004D013B12888ADF8020005E00DF102002946082210F09EF8687A8DF80A006B89A7
+:20916000ADF80C30B00824BF01208DF81C00700924BF01208DF81D00300924BF01208DF8D0
+:209180001E00B00924BF01208DF81F00F00924BF01208DF8200036F07F001CBF01208DF888
+:2091A0002100ADF816A08DF82280ADF82490A41C069439680A919BF800008DF814000FF0F2
+:2091C00057F922216A46082308F038F80BB0BDE8F08FC046800301202DE9F04705466988E7
+:2091E000686800273B463C468846064619E0B2787F1CE41CF61CFFB2A4B29AB916F8010B17
+:2092000031460DF06DFA641CA4B221188845B8BF002040DB361824181B1869886868A4B211
+:209220009BB24018B042E2D8012000EBC700C4B2E01880B211F030F85FEA00082AD06D6821
+:2092400008EB040688F8007027B3B94600276978287808EBC704AD1C641C00EB01202080ED
+:2092600015F8010BA070A07878B915F8010BE070E07829460DF034FA82460246294630462C
+:2092800010F00CFA554466605644B9F1010907F10107DCD14046BDE8F08770472DE9F041CE
+:2092A000244D0646287886423AD000283ED1224F3868D0F838038047002837D010F086FFB9
+:2092C0001E4C8046207818B13868D0F84C0580471B48007818B13868D0F84C0580471948F8
+:2092E000007800BB18480078E8B918480078D0B917480078B8B917480078A0B91648007813
+:2093000088B90DF003F92670404611F0E9F8012E05D0022E03D03868D0F84C0580472E70F0
+:209320000020BDE8F081404611F0DAF8E220BDE8F081C04604140120140100200B060120E0
+:209340006811012005140120071401200A1401200014012006140120081401202D4BB0B534
+:20936000144607460A4680384FF000014CD0C01F15D0294D001F32D00D382ED0001F29D02C
+:20938000401E19D0401E12D0812F41DBD82F3FDC184636383F1817F85D0C01460AE0104636
+:2093A0000EF0ACF9002833D01C22074627E01846143001782170B0BD284696224FF6FE7358
+:2093C000083030F8085BAB421CBF491CC9B2521EF7D1EFE70EF0CEFFDFE71846E9E72F46E0
+:2093E00096204FF6FE7337F8085FAB4203D08A4204D0491CC9B2401EF5D1B0BD082220460A
+:2094000039460FF047FFB0BD1846123000882080B0BDC0461AFB0020B40300202DE9FC4181
+:209420002D4C05466069002710B1804700284CD0002F4AD1E068226A690310F013FE0028E9
+:2094400041D40C2004F1300815FB00F026184044173001783036FE29AEBF0121491CC9B220
+:209460000170009840F0FF0061F31F2019496A46042301430091284639460AF0FFFB607062
+:2094800038B9A800FF2100EBC50040448175032444762846FF214FF0FF323B460EF090FB00
+:2094A0002846FF214FF0FF3201230EF089FB2846FF214FF0FF3202230EF082FB1020B08307
+:2094C000FF24347602E0012700E00B273846BDE8FC81C04600000F965CFC00202DE9B043D7
+:2094E000044610F073FE28498146621892F84A01401EC7B2002F82F84A713ED1264800EB87
+:2095000084000478408834F07F07804614D1E0090BD21E480068806901464046884740468F
+:2095200009F0BCFA0228FAD121E001EB8801D1F86011002088471AE04FF08055D5F8B80154
+:20954000006A014640468847D5F8B801806A014640468847D5F8B801006B0146404688476C
+:2095600001210B4A0B48116001688908FCD304F03F00152801DAFFF7B1FF484610F0B0FFB9
+:209580000020BDE8B083C04610150020B80100102820086028200840F0BC02002DE9F84380
+:2095A00005462C684FF0FF36E66210F00FFEDFF89CC094F830E08146BEF1040F09D1624629
+:2095C000177837B1224903204860086820F003000860204A204F63691168002090469F42FE
+:2095E00004D019B96246177807B10120BEF1040F4FF0000703D111B1624613780BB93843A5
+:2096000001D00DF0C3FE94F8320028B1484610F067FF3046BDE8F88394F83000042804D0DE
+:20962000404621460EF0AAFC03E0404621460EF0B8FC012084F83200484610F051FF02F078
+:20964000BDFC284609F08AFDBDE8F883050601200C8002406005012080A9030038B52B4C33
+:209660002068D0F8AC00007808B909F0C7FD00F05FFE2068D0F8B800007820B124480830B6
+:209680000168012088472348007810B91D48007818B12068D0F84C05804710F097FD1E49BC
+:2096A0000A78022A1FD10122174D0A706A78022A03D0032A18BF062A01D183220A7010F005
+:2096C0000FFF697831F0010018BF042902D1FEF781FB6978022903D0032918BF062904D14B
+:2096E0000EF0B4FE01E010F0FBFE2168B8310A68107828B1506918B1D1F8701210208847CF
+:2097000038BDC046071401204C02012014010020E0FF0020051401200A1401202DE9F041AF
+:2097200000248846061CADF1180D8DF8144014BFB8F1000F022049D008466A4605A905F012
+:2097400087F805464FF6FF70A84214D09DF8140060B19DF8100048B99DF81310052010224E
+:20976000334601F07F010CF06DFF2EE0274601E07F1CBFB20FB1B22028E0394605201022BF
+:20978000334608F085FF0928F2D102A8414608220FF080FD47F08007204601942946009051
+:2097A00014228DF810006B468DF8137004200CF049FF0849A80000EBC5000C224518214622
+:2097C000284605F0C3F801206872204606B0BDE8F081C04664FE00202DE9F04F09AF9B46C8
+:2097E00092468946ADF1240DBC8897F800800790242003F02FFA10260028009044D0002186
+:20980000242205F0A3F8484610F066FC002540B10079012818BF032803D1E00938BF44F4DC
+:209820008064E00A28BF01251949009809884181ADF818A080F81FB002230373079A0262BC
+:209840000372A0F800908DF80C8080F80D80F968ADF80A4006C904AB83E80600387A2946F5
+:209860008DF81A006846F5F757F8012809D1012D05D140460FF084FB08B105F0BDFA0026CA
+:2098800002E000980BF088F9304609B0BDE8F08F2CFB0020034630B50020ADF1140D01909A
+:2098A00002460292039298685C7E428001880492A1F60201C9B141F21E05491B15D041F692
+:2098C000E675491B012920D8417E012C62F38201417606D0018B21F47C7141F4347101836A
+:2098E00013E0018B62F30911F9E7417C012C62F38201417405D0018A21F47C7141F43471E7
+:2099000002E0018A62F3091101825A7604A902AA03AB009101A9FCF771FB50B10198008855
+:209920004FF6FF71814204D10298049906F046FA03E00298049905F09FFF044818300168C3
+:2099400009B10298884705B030BDC04630F50020F0B52C4E054630680127ADF13C0D0DA930
+:20996000D0F830248DF83470522090470024342268466C75214685F8204004F0E7FF2868A2
+:209980000090A888ADF80400A8798DF80600287A8DF80900687A8DF80A00A87A214600B1D7
+:2099A0003946E87A8DF80B10214600B13946287B8DF80C10214600B139468DF808400F20B8
+:2099C0008DF80740104B8DF8240043F6FF778DF80D101878ADF8267001280BD13068D0F836
+:2099E0003024291D502090473068D0F83024A91DE12090473068D0F82812684688472046B7
+:209A00000FB0F0BD14010020ADFE0020F8B52D4C06462068D0F828240D4669464F20904784
+:209A20002168D1F8D40090F85300D1F818148847234F04282DD02168D1F8D40090F85300C5
+:209A4000D1F818148847C0B9397806F10800400080B235B14FF47A7292FBF1F28018163044
+:209A600080B29DF80030676801229A407B681B78521E083312FB030018E03978F0006030C9
+:209A800080B2A5B14FF47A7292FBF1F2801898300CE03978700100F5867080B23DB14FF4E3
+:209AA0007A7292FBF1F2801800F5F67080B2122E8CBF28220C22801880B241438800F8BD97
+:209AC000D800002014010020F8B5064610F07EFB264D0746711991F84A01421C002881F8CA
+:209AE0004A213DD1224C04EB8604267806F03F00152801DAFFF7E8FF648836F07F0014D1C8
+:209B0000F0090BD21B4800684069014620468847204609F075FD0128FAD121E005EB840540
+:209B2000D5F86011012088471AE04FF08055D5F8B801C069014620468847D5F8B801406A8E
+:209B4000014620468847D5F8B801C06A0146204688470121084A0948116001688908FCD35E
+:209B6000384610F0BDFC0020F8BDC04610150020F0BC0200B80100102820086028200840D7
+:209B80002DE9FE4F0D4601900BF006FF174600284CD1019841688668254B002F4A683468BF
+:209BA0002448318C1A602C4401603ED04FF6FF7980464FF0D80B4FF0200A019808F0B8FCD0
+:209BC00038BB01980CF006FC18BBB94507D219EA040F04BF8DF800B04FF4803502D0B5685C
+:209BE0008DF800A0210C8DF80110200A8DF80200B8F8001001988DF803400FF064FF68469B
+:209C0000042109F0D3FA40B1B8F8001001980FF063FF4FF0FF30BDE8FE8FB8F800100198B5
+:209C20000FF05AFF64197F1BC7D10020BDE8FE8FA0130120A41301202A480168D1F8B020AB
+:209C4000D1F888031060D1F89C03D1F8B0205060D1F8A003D1F8B0209060D1F88002D1F886
+:209C6000B020D060D1F8A403D1F8B0201061D1F87C02D1F8B0205061D1F88402D1F8B020F1
+:209C80009061D1F8B0200020D061D1F8B030D1F88C231A62D1F8B020134B5062D1F8B0200A
+:209CA0009362124BD1F8B020D362D1F84824D1F8B4301A60D1F8A823D1F8B4305A60D1F864
+:209CC000AC23D1F8B4309A60D1F8B423D1F8B430DA60D1F8B023D1F8B4301A61D1F8AC103E
+:209CE000087070471401002081A1020059A202003EB52C4C94F84A10032903D0012918BF8E
+:209D000009294BD1417800293FD141886187811C53200BF081FC94F84A00092801D00EF0F4
+:209D20008FF80125422002A98DF808500BF074FC0420694684F84A004A200DF0CDFF04F160
+:209D40004000694610F028FA154801780B2905D0B4F8480000210AF045FC01E0062101704A
+:209D6000E08F4FF6FE71814203D069460022FCF7B7FB94F83200000938BF002502A95220B4
+:209D80008DF808500BF048FC06E0B4F848000AF029FC002084F84A000EF006FE3EBDC046C5
+:209DA00034FD0020E4FA00202DE9FE4F294E00900CAF0191301D097A3F8800689A469046E8
+:209DC0000F2903D1019A4FF6FC71118048F21F01B9421CBF4FF0000B012504D14FF0000BDA
+:209DE000022500F801BB814689F8008071785C46401C0AEBC10110F0CFF971780835EDB295
+:209E0000491CC9B2884505D1641C89F8004086F801B017E0641C71700A2CEADB0A24884501
+:209E200089F800400EDD1F2F01D10EF0CDFC48F21F00B84206D1084800784FF48041224631
+:209E400010F089F9009801993A462B4606F066FEBDE8FE8F98FD00203BFD00202B492948DF
+:209E60002DE9F84F491E077891F801800026344631E0254B142014FB00F909EB0305B5F88F
+:209E800002A095F801B00022514658460BF01EFC78B91D4810F8090040081AD358460122D9
+:209EA000FF230DF041FF1648164D2F7890F801800FE0287840080AD2687869880022FF230A
+:209EC0000DF032FF0E480F4D90F801802F78761CF6B2641CE4B2A742CBDC404680210AF0F1
+:209EE0003BFE20B94EB10CF0F1FEBDE8F88F26B903484078802108F013FABDE8F88FC04680
+:209F00004CFF0020F00C0120080D01204DFF00202DE9F04704462848B0F80090207D98465D
+:209F200015468A463830C0B20EF0D7FA08AF061C40D00120307021461C2206F11C000FF0EC
+:209F4000A9F9B01C51460A220FF0A4F9A6F80C902878307495F90200B0746878002370741B
+:209F60003878F362F0747868706186F818806089F081387A7076207D40B106F13800F062B0
+:209F80002169227D06F138000FF084F90B48727F816A807812F0030F09D021B930460EF08B
+:209FA00083FBBDE8F08730468847BDE8F087314609F072FBBDE8F0872CFB0020AC00012099
+:209FC000BCB5054669680C462078401F4AD0801E2CD0801E42D0401F02D0801E3AD0BCBDF5
+:209FE000481C01A90CF0C2FC093401283DD1502000238DF800002F7A8DF80230A7F109000C
+:20A000008DF8010068460BF0E4F8071C2DD0BDF80400788020783A7D87F838003869214656
+:20A020000FF038F93846F1F727FEBCBD6D890C200EF053FA071C18D006203870611C0822FF
+:20A040007D80381D0FF026F908480078394609F023FBBCBD28460DF06BFFBCBD28460DF000
+:20A06000FBFCBCBD2846FCF755FFBCBD3BFD002070B50646012E14BF01200320244C0121A1
+:20A0800004F10902607285200FF0BEFF41F288300DF0C0FF1F4D28784FF4807108F040F975
+:20A0A00028784FF4807106F039FF1B480078022804D14FF40050012100F0E2FE012E04D03C
+:20A0C00041F288300EF070FB70BD022603202670012305F15D01607004F11400637110F0F9
+:20A0E0005BF885F84A600CF009F80C4C0026A6700DF0FCF96078042108F012F96078042166
+:20A1000006F00CFF304684F83F60ECF761FF70BD34FD0020E4FA0020ADFE00204CFF0020B8
+:20A12000B0B5002405462022ADF1200D21462C72684604F00BFC0B22684629460FF0AAF8A5
+:20A14000E87A0A228DF80B00287B8DF80D4005F10E018DF80C000DF10E000FF09BF8AF7E0B
+:20A1600006220DF11A00214604F0F0FB780824BF01208DF81A00B80824BF01208DF81B00D2
+:20A18000F80824BF01208DF81C00380924BF01208DF81D00F80924BF01208DF81E0037F064
+:20A1A0007F001CBF01208DF81F00288B074FADF8180038688DF80D40D0F8F4128DF80C40A9
+:20A1C00068468847204608B0B0BDC04614010020B0B5294C04F124010878ADF1780D74220F
+:20A1E0006B46401C0870212000210FF0F5FB94F8240074216A468DF8000021200FF004FFCC
+:20A200001E4D28790027032805DA0AF0C9F9012808BF042000D00D200FF0C0F8618F4FF648
+:20A22000FE70884208BF0127B4F84810401C88421ED0F7B9012452201DA98DF874400BF09E
+:20A24000EBF9287903280DDA0AF0AAF9012809D1002068712046F6F719FC2979491C074612
+:20A26000297106E06C710020F6F710FC0021F6E7012738461EB0B0BDE4FA00204CFF002020
+:20A28000B0B50546294C297D012905D0152903D0252918BF35291FD1287E00091CD2226849
+:20A2A000D432106890F8820080B168781B280DD16068816A012088472068D0F82C134FF46F
+:20A2C00080608847002022686870D432D2F85C22697828469047B0BD287EC2091ED20129E1
+:20A2E00018BF152901D100090ED26F781B2F09D01FB920683430026802E0206834304268DE
+:20A30000895C04E0232100E03121206834302970006E0078294609F0BFF9B0BD2068006D11
+:20A32000016809B168788847B0BDC04614010020FEB50FF04BFF244CA16962698A4240D086
+:20A34000224A1778002F3CD1214A177837F07F0737D1204A1778002F33D1616110F0C0F871
+:20A3600060691D4E01907068416D20698847019F1A4D0090F90FB1EBD07F16D02868D0F872
+:20A38000D40090F8830001280FD00CF0BFF87068826D206939469047832803D02868D0F8A7
+:20A3A0004C0580470FF05AF8FEBD7068826D206939469047832806D02868D0F84C058047E2
+:20A3C000FEBD10F08DF8FEBD70000120071401200A14012000140120DCFF00201401002011
+:20A3E0002DE9F04704466188606800273B463D468846064615E0B61C16F8010B31460CF07C
+:20A400006FF9ED1CADB229188845B8BF00203DDB36182D181B18618860687F1CADB29BB2F1
+:20A42000FFB24018B042E6D8072017FB00F0401CC6B2F01880B20FF02FFF5FEA000824D0BA
+:20A440006568464488F80070FFB14FF000096978287808EB0904AD1C641C00EB0120208047
+:20A4600015F8010BA070A07829460CF039F982460246294630460FF011F909F1070955445D
+:20A48000C4F803607F1E5644E1D14046BDE8F0872DE9F04704466188606800273B463D469F
+:20A4A0008846064615E0B61C16F8010B31460CF017F9ED1CADB229188845B8BF00203DDBF9
+:20A4C00036182D181B18618860687F1CADB29BB2FFB24018B042E6D8072017FB00F0401C80
+:20A4E000C6B2F01880B20FF0D7FE5FEA000824D06568464488F80070FFB14FF00009697871
+:20A50000287808EB0904AD1C641C00EB0120208015F8010BA070A07829460CF0E1F8824659
+:20A520000246294630460FF0B9F809F107095544C4F803607F1E5644E1D14046BDE8F087F1
+:20A5400030B50C466168ADF1240D00294AD0A068002847D00A780270491C401C08220EF0C5
+:20A5600099FE60680178E9B9401C07A90EF05CF90028607038D1079840880021182201AB93
+:20A580000FF02AFA002860702ED10698A16808620598A168C861A068102201A909300EF0A6
+:20A5A00079FE21E0002501A80090A9B20022142304200BF03FF9607068B9606803A908222B
+:20A5C000401C0EF061F830B90298A16808620198A168C86102E06D1C032DE4DB032D03D1A9
+:20A5E000002000E00220607009B0012030BD7047F0B5294C06462078ADF11C0D032848D1E2
+:20A6000000256846182225700823657029460FF007FD684629460CF009FD20613A222946BB
+:20A6200004F1300004F092F904F13C00FF210A2204F08CF90CF03CFE3146284609F066FB0B
+:20A6400004F11801E0600FF012FD226AE169B1FBF2F0C0B284F830000428A4BF032084F8EE
+:20A660003000E070B2F5005F04D1E768B1EB403F00D317B9012020700CE084F83550FF20B5
+:20A6800084F833004FF40050E086EBF795FE607800E0607007B0F0BD5CFC002003B42DE96C
+:20A6A000F04F09AFD7F808A0BC69D7F814903D8ABE894FF6FF709846ADF12C0DBAF1000F63
+:20A6C000208009D0B8F1000F06D0B9F1000F03D016B1B5F5005F01DD04202DE0194638462B
+:20A6E00001AA04F0A9F9174F034607F110000068002B18BFD8B21FD102F050FCCDF81890D3
+:20A70000ADF81C60ADF81E508346CDF820A006A8009097F83300F98EADF8248001AA122307
+:20A72000F8F776F8C6B216B9BDF8080020803869594605F02DF830460BB0BDE8F04F02B0F7
+:20A740007047C0465CFC002030B5264C054694F82000ADF12C0D012841D10FF01BFA002828
+:20A760003DD1688800283AD11F4905A8122201F0BDF960784FF4805107F0D2FD284605A9EA
+:20A7800000F0E4F8BDF82000B0F5285F23D2174800680DF126016A4604F05AF80446032C9C
+:20A7A00011DA9DF8100010B1FD208DF81000214614226B4604200BF045FF0D4AA0000121CC
+:20A7C00000EBC400115400200FF0E2FB01200146EDF718FF03E0012002210BF0F7F90BB039
+:20A7E00030BDC0464CFF00205EC20200B80001206DFE0020F0B5294E05463068D0F8FC11A1
+:20A80000ADF1140D28468847041C3FD13068D0F82C1128468847041C38D1687C002835D0F8
+:20A8200095F8340090BB3268B8321068007868BBD2F87C2105F1120109209047071C25D0ED
+:20A840003068D0F8302405F10B01E72090473068D0F8302405F10801502090473068D0F80A
+:20A86000302405F10A01E12090474FF6FF7202203368ADF80420A97A8DF80C00D3F8C041EF
+:20A8800000912B89384601A9A04705E030686C70D0F844112846884705B0F0BD140100201A
+:20A8A0007CB50646284D96F8300003283FD196F83A0003283BD12C68D434216806F128006A
+:20A8C000082216310DF032FD78BBD4F85C2306F128014A20904774682B6861782078D3F851
+:20A8E000302400EB0120ADF80000694650209047A41C2B6861782078D3F8302400EB01206E
+:20A90000ADF8000069464B209047E41C2B6861782078D3F8302400EB0120ADF8000069461E
+:20A92000532090472C68002003E0EA2002E02C68E820D434216A48702A253570D4F86C1225
+:20A94000304688477CBDC0461401002080B5806910F8017B0F7043780278002F02EB0322A7
+:20A960004A8047D10A7910F8023F02F0F80203F0070313434F790B7103F0F702037803F04C
+:20A980000803134303F0EF020B7110F8013B03F0100313430B71037807F0070203F0F80371
+:20A9A000134303F0F8024B7110F8013B03F0070313434B7110F8012B8A7110F8012BCA71A7
+:20A9C00010F8012B0A7210F8012B4A7210F8012B8A7210F8012BCA7243780278871C02EB72
+:20A9E00003228A8117F8012B8A7317F8012BCA733878087480BD7047F8B5284E3468103454
+:20AA00006568287EFF2840D0D4F8C47097F88310022927D0AB7E7BB102280DD1D4F8F40427
+:20AA2000804771682C6949683A7909780546083112FB01F1084612E0D4F8F40480476D69D8
+:20AA4000E76AD4F8C43022682D1A93F82C10388977682D1A32F81140D7F8B40080472D1B59
+:20AA60002D1A10E0D4F8F40480476969D4F8C460E76A2568081A96F82C203989401A35F82F
+:20AA80001210A0EB0115002D01D50020F8BD4FF6FF70A842C8BFA8B2F8BDC04614010020AC
+:20AAA00070B5284C2068D0F8D4104D7B4069002141772068C16891F83000401C81F8300010
+:20AAC00020680C30016891F83010042931D06068C16B202088472368D3F8D41091F84F60DD
+:20AAE0000F2E0CD058694A7B807F824207DD4873D3F81415884723683546D3F8D4101A695A
+:20AB0000D86832F8154090F830200126550006FA05F24E7B4FF47075624305FA06F18C080B
+:20AB2000944238BF221CA1EB4201D3F8F024904770BDD0F8580180472068D0F86C018047EC
+:20AB400070BDC0461401002030B50546E889ADF11C0D213801281CD947F6DF71401A01289E
+:20AB600043D8284605F0EEFB041C3ED0207860B9608800218DF80010ADF80200211D01A863
+:20AB80000FF01EF96846FAF727FF20460AF004F82BE0287B48BBA96968460C460FF0FCFAC6
+:20ABA000083414F8010B8DF8080061782078A41C00EB0120ADF80A0014F8010B03288DF800
+:20ABC000140006D06178207800EB0120ADF80C0007E003A821460FF0DFFA14F8080F8DF8E4
+:20ABE000160028466946F6F713F807B030BDFEE7D0B50446607D164601220CF0EBFA071C72
+:20AC000044D0002E42D1E07D97F8351081423DD197F839103B7A0A18934211DD207EFF28A6
+:20AC200011D1FF20884087F8360087F8370097F83500401887F83500002687F8386007E0EC
+:20AC4000207EFF2818D087F83700207E87F836000FF04AFC04460FF00BF997F83A600C4B2C
+:20AC60004FF47A716043B0FBF1F03880012118787E8006F097FFD0BDB87E97F82A10FA8B72
+:20AC800033460AF033FF38460BF058FED0BDC046DC0401202DE9F047254EDFF898900025C8
+:20ACA00001244FF0020A4FF01108E8B20EF0FEFD071C38D0B87A012835D197F909001130D3
+:20ACC00004FA00F0C14346F8041C31680843306097F9090004FA00F0C0B20EF039F807F190
+:20ACE000100000210CF0FAFA0146812909D1B86918B100210CF0F2FA0146812908BF87F83E
+:20AD00000AA081290FD0A9F1040097F9091090F8412208FA01F1114380F84112002100F5A5
+:20AD20008E700FF071FA6D1C032DBED3BDE8F0870C10044034F500202DE9F84F04460AAF3C
+:20AD4000207DD4F810A03D689946934688463030C0B20DF0C2FB061C3ED01A203070A088F1
+:20AD60007080E0885946B080B01D0DF06DFDE078F07398F800003075207B70752878B07543
+:20AD80006878F07595F902003076387A7076F868F061387986F82000608BB08560897082A5
+:20ADA000A6F81090207DB084387C86F82E00B08C002804BF0020B06208D006F13000B062BA
+:20ADC000B28C514606F130000EF064FAD8F804000078314608F060FCBDE8F88F25482649FC
+:20ADE000EE381831C0F8CC1024491E39C0F8D01090F8CB1041F0010180F8CB1090F8CB2098
+:20AE0000012161F3410280F8CB2090F8CB2061F3820280F8CB2090F8CB2022F0080280F861
+:20AE2000CB2090F8CB2061F3041280F8CB2090F8CB30002262F3451380F8CB3090F8CB20AF
+:20AE400061F3861280F8CB2090F8CB2061F3C712052180F8DA1080F8DB100449C0F8DC1027
+:20AE60000349C0F8E01080F8CB207047B8100120941201203E1900206C11012022000120BC
+:20AE8000BCB5244A1278022A04BF234A1040234CB4F86C2000290CBF82430243D00BA4F881
+:20AEA0006C20C70308D001208DF80000694652200AF0B2FBB4F86C20900B07D2D00BC703A5
+:20AEC00004D0D00B28BF04F1580000D20020144D2978C8B1A76E1FB13A6803689A4218D06C
+:20AEE000A066006801280AD00846012107F018FAA16E28780A6801210FF02AF9BCBD08463C
+:20AF0000012106F04FFEBCBDA0660846012107F007FABCBDADFE0020C0CFFFFFECFB00200D
+:20AF2000E4FA002010B50446E089ADF1300DADF80200208AADF80400A07A8DF80F00A089EF
+:20AF4000ADF81000207802288DF80E000CD001280AD00F2808D0032809D10DF10600A11C33
+:20AF600008220EF097F902E06088ADF80600237D8DF81430627D8DF81520E17D8DF8161099
+:20AF8000237E8DF8173094F919208DF81820A17D8DF81910608AADF81200E369079394F8E2
+:20AFA00020208DF82020618CADF82C1094F82430E28C8DF82E30A16AADF8242068460A9150
+:20AFC000EFF750FF0CB010BD2DE9F84F0AAF3C7BBD683E79994690468A468346002C0EBFC3
+:20AFE0000220042000EB46008DF8010068460DF00BFB031C37D0A3F802B083F81A90A3F870
+:20B0000004A03878D876987F01280BD10EF04EFF9988884206D0B8F1000F06BF00209877BA
+:20B02000C3F824801969052001F8010BBCB1701C01F8010B66B13046891E2A7801F8022F07
+:20B0400035F8022B401E4FEA22224A70F5D1891C0EF02CFF01F8010B0EF028FF06120E70AD
+:20B060001846F0F709FEBDE8F88F7047DFF898C0F8B50B1C04464FF000050FD0DCF8987055
+:20B080002E466FB1F868007B00F00F00022803D03F68002FF6D103E03E4601E0DCF8986094
+:20B0A0006EB302B11660F168087B012500F00F00022824D1012B14D0098840F60300884282
+:20B0C00005D0401C88421CBF3069016901D130694169408B9CF842321922091813FB021132
+:20B0E00003E03169888DC9680918706B0CF090FD20600EF0BDFE2168B1FBF0F000E00020BA
+:20B1000020602846F8BDC04630F500202DE9F84F0E46074630684FEA9009224848452CBFF7
+:20B12000002503250FF052F800901F48D0F8BC1000F1B80AB94214BF00240124A10081F012
+:20B1400004015AF80180834627B107F1B8000EF039FDC8B9B8F1000F04D008F1B8000EF0D6
+:20B1600031FD88B93168A00000EBC40050448160317A01740EF07CFEB9FBF0F107F1B80026
+:20B180000EF0C6FA832507E09BF8DC0040F002008BF8DC00CBF8D87000980FF0A1F92846B8
+:20B1A000BDE8F88F40420F0030F50020D0B504461120ADF1180D01F04DFD071C3FD03B2002
+:20B1C000002111223B460EF007FC80BB387884422DD1112001F03EFD061C28D03A200021F8
+:20B1E000112233460EF0F8FBC8B93A2011213A460EF00AFF13490120087013484468B4F17D
+:20B20000004F84BF002444601122394668460EF041F8822018216A4605940EF0F5FE3046B2
+:20B220000021112203F092FB304609F0B5FC38460021112203F08AFB384609F0ADFC06B0FA
+:20B24000D0BDC04649FB002048040120264890B5503800688088ADF11C0D0EF03DFF071CBB
+:20B260003DD020480078012806D1787900F0EF00787140F00800787100248DF80C40788812
+:20B28000ADF8180003A807F029FE04AB38880193ADF800000EF00AFEADF80800787900EAF2
+:20B2A0005001890928BF01248DF80A408DF80B000EF070FC18B9684601F058FD02E0684681
+:20B2C00004F09CFC20B9787900F0FB00787106E004AC20460CF0ECFC204607F08BFB07B0CA
+:20B2E00090BDC046B8FE002094FD002030B50C4605463C220021ADF13C0D684603F026FBCA
+:20B300000A22684629460DF0C5FF6889ADF80A00287B8DF80C00687BE9898DF80D000DF16A
+:20B320000E000CF05BFB287C8DF81600687C8DF81700A87C8DF83700E87C8DF83800E87F86
+:20B34000ADF8280001F086FC099070B1296AEA7F0DF0A0FF4CB19DF828000999A04720B147
+:20B36000099809F019FC1A200BE007480068D0F88812684688470446099808B109F00CFCBE
+:20B3800020460FB030BDC04614010020F0B520480127F84201D008F0D5FA204D204F214E0E
+:20B3A000BD4206D203CD0478A4003459401CA047F6E71D48002800D08047164D164FBD422E
+:20B3C00002D210CDA047FAE7F0BD03251BE0416808300A1C2A400BD11A1C2A40AB4305D074
+:20B3E000046804300C600431043BF9D1131C05D0047801300C700131013BF9D1021C2A4016
+:20B4000001D0A84304300368002BE0D17047C046FFFFFFFF0000000000000000C0C90200B1
+:20B4200038CA020050C9020075F4021030B50C466068ADF1240D002841D002258DF814505B
+:20B440000188ADF80C10817B02298DF81E100DD001290BD00F2909D003290BD100F11001CB
+:20B4600008220DF116000DF015FF03E06068008AADF816001449BDF80C2060680988914223
+:20B480000FD100F10C010091027E817A012308460DF11601EEF7F2FF00280CBF281C00200E
+:20B4A0000EE0818900910DF116050195017E0291837A821C03A9212002F040FB00E002208B
+:20B4C000607009B0012030BD1EFB00202DE9F041204D6868416EADF1280D02A8884768684D
+:20B4E000C06B80471C4CA060217B21F00F0141F002012173029000260596668001208DF88E
+:20B500000C000EF063FE1849091D0968896980460220087069680F6D31468DE803000F48E3
+:20B520000F4B006802AA2146B847064640460EF0D7FF002E06D40B4991F90000AC60401C43
+:20B54000087004E0032041F2883105F0AFFD0AB0BDE8F081DCFF00205018002080000120EB
+:20B5600065E3010012050120140100202DE9F0470F4606460EF060FFEFF311898246202046
+:20B5800080F31188D6F80880474533D01D481E4B0068002F05D49C690125BD4004EBC7049A
+:20B5A00001E01C180025307D01281AD130460EF03FFF306C0EF038FF18B1F1685868884360
+:20B5C00058601869864204D0204631460EF028FF04E020685C6131460EF028FD58682843A6
+:20B5E0005860B760F5603464002F44BF002058610120188189F3118850460EF00DFF40468F
+:20B60000BDE8F0873CAB02000017002070B5064600210C22ADF1180D684603F097F9308882
+:20B6200001211F4C1F4DADF8000009208DF80400307A8DF80510012810D1212063788DF8CB
+:20B6400002006BB90EF0EAFD50B9716805F11C0008220DF01FFE3088288001E08DF80210CF
+:20B660006846F9F719FF9DF8140050B90398406C072101707168401C0EF08EFD684609F01D
+:20B680008BF9607850B90EF0C9FD38B905F11C000021082203F05AF90020288006B070BD42
+:20B6A000ACFE002070020120B0B504460125ADF1200D607927688DF8080020798DF80B501F
+:20B6C0008DF80A006FB338460DF0AEF948B338460DF11A010BF038F8BDF81A004FF6FE7157
+:20B6E000814214BF0027C827A07930B92FB9BDF81A1020688DF809501AE08DF81650BDF8D5
+:20B700001A008DF818706379ADF80C0021688DF817300DF10E000EF03FFD03A809F022FF15
+:20B720000DE000208DF809000DF084FD4FF6FD7101906846ADF8001001F050F80746384645
+:20B7400008B0B0BD7CB506462448006814460D4607236A4605EB46310EF08EFC9DF8000068
+:20B760009DF80010A58183109DF802209DF801009DF8045001F0030140EA012026749DF8C6
+:20B780000310E080891141EA82019DF80320237240EA03309206120D42EAA502E2819DF8C2
+:20B7A00005509DF80420A18041EA003102F00302920142EAA50262729DF806509DF8052028
+:20B7C0002160962DA57202F0030206BF42F00402101C42F00100E0727CBDC04668FC0020A6
+:20B7E0002DE9F04105462C686E680F460EF0EEFC94F8311019B91D490978012904D00EF08E
+:20B800006FFE0020BDE8F081012184F831104FF0000884F832800EF063FE07B9144F94F823
+:20B820003000012806D1786820B9B868002808BF454618D0387884F83000F868206278687F
+:20B84000E060B868A5602061B068010A04D00949814288BF011C00D80749616104F134007F
+:20B8600041460BF067FD2846BDE8F0810406012010C202000100000180A9030030B5054601
+:20B880002989ADF1240D0EF011FB884222D06868ADF8081005AA03900021AB2007F064FE4D
+:20B8A00005A807A9002202F0D3FF1A4827300078012808D19DF81C0028B900208DF81000CB
+:20B8C00002A8FFF7A3FE01208DF8100002A8FFF79DFE1DE000248DF804408DF805406868B2
+:20B8E00000900EF029FC18B1017909B1052906DB0EF0DCFA298888420AD1009403E040792F
+:20B90000000938BF01248DF806406846FFF7CCFE09B030BDACFE0020B0B5244C2068B83014
+:20B9200001680F781E4917B90F783FB909E00F7837F07F0702D11B490F7817B1D0F894045E
+:20B9400080470EF043FC6168174D09692A780978914207D116490978C90803D20EF0C0FD35
+:20B960000120B0BD0EF0BCFD0AF0D0FD0EF020F8012811D12D7808F09DFB18B96068006963
+:20B98000057009E06068006905702068D0F8D40090F942000DF04AFD0DF060FDB0BDC046A3
+:20B9A0000A14012000140120700001201401002006140120B0B5234C2068B83001680F78DE
+:20B9C0001E4917B90F783FB909E00F7837F07F0702D11D490F7817B1D0F8940480470EF0E7
+:20B9E000F5FB6168194D09692A780978914206D113490978C90802D20EF072FD19E00EF003
+:20BA00006FFD0AF083FD0DF0D3FF012811D12D7808F050FB18B960680069057009E0606856
+:20BA2000006905702068D0F8D40090F942000DF0FDFC0DF013FD0120B0BDC0460A14012063
+:20BA40000614012014010020001401207000012070B5254C216840310868006828B9D1F89E
+:20BA60000C0580472068006C006840681B4D007800F0200028710EF0A9FB19490646087891
+:20BA8000832826D12879D8B1216840310868006890F8780010B9D1F80C05804730460EF02A
+:20BAA0001FFD1048008842F20341401A0DD0401E18BFE9200AD101200BF0B2FD1B2005E0D7
+:20BAC0008520087030460EF00BFD002001F0ACFA70BD30460EF004FD70BDC0464C020120D2
+:20BAE0000A1401207218002014010020002A4AD05FEA000C8B071CD1830722D1102A08D37E
+:20BB000070B4103A78C978C0103AFBD270BC103238D0042A2CD3082A05D30C2A24BF08C990
+:20BB200008C008C908C008C908C092072AD0920F22E00B780370491C401C521E22D08B072A
+:20BB4000F7D1C30714D18307D8D0121F12D308C903801B0C4380001D121FF8D20AE008C915
+:20BB600003701B0A43701B0A83701B0AC370001D121FF4D2121D05D00B780370491C401C3B
+:20BB8000521EF9D1604670472DE9F047824624480D460024ADF1280D06786868ADF82040F0
+:20BBA000002808BF271C06D00746022208A839460DF074FDBF1CBDF82000001D80B28146A9
+:20BBC0000EF06AFB5FEA000826D0297800F8011B697800F8011BA97800F8011BE97801700A
+:20BBE0006D682DB1BDF82020401C39460DF056FD0120009001940290039404965146CDF80D
+:20BC000014902122CDF818800B230790F220F4F74FFB40460EF080FA0AB0BDE8F087C046FA
+:20BC20008103012098B5044620200CF056FC071C31D03420231D387093E80500391D81E89B
+:20BC4000050020688088B88121680C2207F10E00891DFFF74BFF2068007DB8766069F8611E
+:20BC6000F87A062805D10097B87E0CF001FCD72106E008280CD10097B87E0CF0F9FBD821E7
+:20BC80006A46082305F0DAFA38460CF00DFD12E038460CF009FD0948006860B121680A7D30
+:20BCA00001798A4204D1816811B12046884798BD00680028F4D1012098BDC046FCFD00204A
+:20BCC000F0B516460C460546ADF1240D08F004FF002840D12846002109F026FC314603F0AF
+:20BCE00087FB071C37D0B879400834D320460DF07DFA012819D0B979C8082CD30EF0D6F85F
+:20BD0000A0420BD1002000902146019005AA02900F2303902846FFF757F9B97988081AD255
+:20BD2000B87900F0FB00B87115E004208DF81000ADF8124004A802F043FE01280BD1002015
+:20BD400000900127214605AA01900F23029028460397FFF739F909B0F0BD2DE9F04180461D
+:20BD600014460E4620200CF0B8FB071C40D00021202202F0EBFD6420387000257D70BE803A
+:20BD80002078B8716088388120893882A07A00F00F00B87420793873E088F881E07AF874AE
+:20BDA000207C3876E07A400000F054FF786188B128460CE0616968006D1C415AFA69815264
+:20BDC0000EE0E2684100401C8A5A7B69CA52F97C8142F6DC207C400000F03CFFF86110B17F
+:20BDE000387EA842E6DC5FFA88F0394607F054FCBDE8F0812DE9F0410D46234998461746F3
+:20BE0000ADF1180D50BB00260C4601A810228DF8166004F12001FFF769FE05A82121202262
+:20BE20000DF116030090F22009F0D3FD9DF81600A8420BD101A8214610220CF08BFE28B967
+:20BE40004046214610220DF029FC18E0012D14D130466221424603F0B3FB10E001A810319A
+:20BE60001022FFF743FE042D18BF072D05D1404601A910220CF06EFE08B1002000E0384646
+:20BE800006B0BDE8F081C046CCB3020003B41046F0B51E1C05AFADF11C0D14BF00280420C9
+:20BEA00038D081B201AA384602F0C6FD1C4C074604F114000068002F2BD110B1804700B9D7
+:20BEC0000B2720692FBB01F069F805460020009094F83300E18E01AA0323F6F799FCC0B27D
+:20BEE00078B901A831460222F1F76CFB071C0CD1BDF8101049B19DF8140007F0A7FB67788E
+:20BF000003E00A280CBF0A2701272069294603F03FFCF8B207B0BDE8F04002B07047C0461D
+:20BF20005CFC00202DE9F84F8146002100200A46C9F800006846FFF799F8DFF87C800026E5
+:20BF40004FF0FF354FF0190A34460746E0B20DF0ADFCC8B1837ABBB1017A0126022917D077
+:20BF60004246516892F8423240694A8B0969891813FB0A110BF04CFE83460DF079FFBBFB8F
+:20BF8000F0F0854288BF051C641C032CDED300E000251FB1012E04D0012F05D0012E04D052
+:20BFA00005E00098854200D9009DC9F800503E43F0B2BDE8F88FC04630F500202DE9F041D5
+:20BFC0000EF004F9204C80462078002650B11F480322083801688260480803D30AF0E6FD5B
+:20BFE0000BF0D4F9164D2868071C0ED008F094FEB86A796A884207D8284639460BF0E4FF82
+:20C000003046012687F832002868217801290ED050B90F480DF0FEFE48B90A4A4FF0FF3085
+:20C02000012105F057FB02E080680DF09FF940460EF056FA16B1B86809F028F9BDE8F0814D
+:20C040006005012080A903000506012010800240081201202DE9FE4F814623480D46904637
+:20C060001C4600210422083083460EF017F91D480768AFB14FF00C0A7868007881450CD184
+:20C080000CF0E0FF48B1037C3BB146692EB1002001E0401CC0B2834205DC3F68002FEBD1CC
+:20C0A0000020BDE8FE8F10FB0AF1725A9542F0D189198A889045ECD122808879A070C97989
+:20C0C000E17001F03DF85B462946ADF8040001A80090484609F07DFCC4F804B00120BDE8C1
+:20C0E000FE8FC04624050120F00C01209EB5477E37F07F0743D0017D012903D0032918BFF0
+:20C1000004293CD11E4C2168D1F89810098901F0020201F00801114331D041684878C0F38F
+:20C12000810002288DF8080006D003280ED1491D68460EF031F809E08A79487940EA0220B3
+:20C14000ADF800000879C97841EA00216068426F684690471E2809D040B16068006D804722
+:20C16000FF280CD16068416D012007E06068006D8047FE2803D16068416D002088479EBD87
+:20C1800014010020F0B51F4D1D4C002124220823ADF1240D6846A5620EF092F9002604F136
+:20C1A0004C07384631466A468DF818600EF084F93C2208232763314604F1680738460EF0A5
+:20C1C00067F94FF44060C4F888000521A5673A46334604F1800004F1A405016074300A4942
+:20C1E000C4F8840028460EF04FF90848E56208490160084981600849C16009B0F0BDC046F2
+:20C20000D4DB00201CE9002065E401000C01002084BC0200F0A4020000B302008B4208BF92
+:20C22000824204D90B1C021C002100207047002B08BF002A0BD10B1C021C00210020002B77
+:20C2400008BF002A1CBFC943C043FDF726B8F0B51C4615460B46024600200021B4FA84F6CD
+:20C26000202E04BFB5FA85F62036B3FA83F7202F04BFB2FA82F72037F61BB6F1200727BFB3
+:20C2800005FA07F400257F42B4403EBF25FA07F73C43B540A34208BFAA4201D3521BA3417F
+:20C2A000404149416D0845EAC4756408761EF1D5F0BD704730B501250446ADF11C0D8DF8CB
+:20C2C0001450F9F705FB206918B11E48016820468847207D50BB684600210C2202F036FBEC
+:20C2E000A0688DF802500088E368ADF80000187D8DF8055009308DF804006846F9F7CCF854
+:20C300009DF8140090B90398456C0E232B70A1684968681C0DF040FFE2681169127D05F150
+:20C3200009000CF0B7FF684608F036FBE06808B108F032FC20460DF08BFE9DF8140007B0F8
+:20C34000207530BD780201202DE9FC47224D81466D1E95F83340E8784FF0FF08002642F2A6
+:20C36000010A0AE0204678210AF048FBE878641C94FBF0F14143641AE4B2B04228DD95F820
+:20C380003200761CA042B6B2F0D0E86861036A4604230DF071FE009800F0FF007828E5D0FC
+:20C3A00005F13007FF2818BF7E2803D120467C210AF024FBA00085F8334000EBC400C019A4
+:20C3C000818BE986808B48448245CBDD95F833804046BDE8FC87C0465DFC00202DE9FE4F0C
+:20C3E0000CAF3E793C888DF800001D4693468A4606F10A00C0B20190401C00F02BFC5FEAB6
+:20C4000000092ED009F101008046594688F800A0401C0CF033FF00F8015B291200F8011B68
+:20C4200000F8014B231200F8013B067026B1B968401C32460CF02EFF0C4C0B49C4F80480F8
+:20C44000E51C48F23802387B019B2870684604F065FB484608F0A0FB05F10A066660002071
+:20C46000E070BDE8FE8FC0460801012098FD00202DE9F0411D4F7868C068012101701C49A2
+:20C480006FF0010008701B480068C06B80471A4C054621786068A2688B002E1AB6FBF3F084
+:20C4A0005843361A8800154902FB03F8B1FBF0F0904203D23868D0F84C058047AD1B1048E0
+:20C4C000656008EB0501F8F7D1FE3868D0F8E40480470DF07BFE0EF003F80BF003FF79687C
+:20C4E000C96800200870BDE8F081C046140100200C050120E0FF0020D8000020FFF6C2FF43
+:20C5000071C40100F0B50546214804782878ADF1240D0BF0BFFF002835D11E48052147687F
+:20C520006FBB1A4A4CCA05A981E84C00047029784560AA688DF800105088ADF802009088FC
+:20C54000ADF80400907900F00F008DF80600D0798DF8070090680290107B8DF814100027E5
+:20C560008DF80C0008238DF81C7020211069CDF818D005AA0490204604F060FE03E0491E42
+:20C5800000F10800CBD109B0F0BDC04604B602007CFB002000FE002070B50E4610F8011B8C
+:20C5A000317042780178801C01EB0221718001784278851C01EB0221B18015F8010B0011CD
+:20C5C000B07115F8014BF4718CB1600000F042FBB06048B35CB1014620466B782A78401E0A
+:20C5E00005F1020502EB032221F8022BF5D12C783473CCB1600000F02DFB306130B9B0684E
+:20C6000090B108F0C9FA0020B06070BD64B101466D1C20466B782A78401E05F1020502EBA9
+:20C62000032221F8022BF5D170BD70B50C4621780646ADF1180D01F00C0531F07F0018BF04
+:20C6400045F0800501F0030045F00205012808BF45F01005880928BF45F020050C22684608
+:20C66000002102F073F98DF80250ADF8006060788DF80300012568468DF80550F8F70CFF57
+:20C680009DF81400C0B903984576A17880F83A10E17880F83B10E188C1872189A0F84010E8
+:20C6A000617D80F84910217E80F84C10E17D80F84B10684608F070F906B070BDFEB50C4630
+:20C6C00001A90BF061F900283DD11F4D0C3DE868002838D0871F00210320BDF8042037F8FE
+:20C6E000063F9A4204D0401E01F10101F5D1FEBD7980182000F0AEFA061C24D000967988FC
+:20C7000006200022182309F095F83046214610220CF0C0FD00247461346179880620182259
+:20C72000334609F08FFF30461822214602F00EF9304608F031FA79883435880000EBC100B2
+:20C740002C5040194460FEBD60FE002038B5224C083CE068D0F8880080470DF037FD0546AD
+:20C76000E068C06D8047E068416AA068D0F8D40090F942008847E068816CA068D0F8AC009B
+:20C7800000788847E068016EA068D0F8D400C08C8847E068A368416ED3F8D400408D88479F
+:20C7A000E068A368816ED3F8D4004430884728460DF096FEE068A568016BD5F8D40090F86C
+:20C7C00043008847A268D2F8D410D2F8302452202931904738BDC0461401002098B5044607
+:20C7E00002208DF8010068460BF00EFF071C3BD038690422411C027000200870227A012AB8
+:20C8000004BF40F020000870607A012803D1087840F040000870A07A01281CBF0123BB76DB
+:20C8200004D10878012340F080000870607A012804D1606808B17B7760683862E07A012827
+:20C8400008BFFB82208808F047F918B1F88A40F00400F882BB770CF0EDFC7862208878802A
+:20C860003846EFF709FA98BD102098BD2DE9FE4F0190214800F198063768994692460D46E2
+:20C880000024804600E03F6897B3BD42FBD1D7F800B0019839460DF0D5F918B33846002245
+:20C8A0004FF0805308F022FE06F10800B9F1000F00900ED0384600224FF0807308F016FE4A
+:20C8C000286998F8DC30C8F8D80043F0010088F8DC00304639460BF077FB009839460BF08F
+:20C8E0004DFB641CBAF1000F18BF5FEA0B07CED12046BDE8FE8FC04630F50020F8B51546FA
+:20C900000C460DF063FC84461E491D488326A4B1641E2CD0641E22D0A41E19D0641E15D1D0
+:20C9200010300768002F0CBF0021F96829604768002F0CBF0021F9680FE00768002F08BFC4
+:20C94000802617D0D1F8A800018E12E0032611E0D1F8B8002860D1F8BC1069600AE0843831
+:20C9600000780021022808BF0121297002E006480178298060460DF0B3FD3046F8BDC0469C
+:20C98000D8F5002030F5002070F70020B0B50024ADF1180D009403F0D5FC071C37D007F019
+:20C9A000D5FA1C48798800780BF0D2F90D46009050B3007B802827DD387810BBADF8065082
+:20C9C00004208DF80400391D02A80DF0F9F901A8F9F702F880B9104D402168782C7005F0C0
+:20C9E0009FFC0BF013FC68784FF4804105F098FC0C200DF067F90AE0798801206A46F6F7F3
+:20CA0000F7FA0098FF210173384608F0C5F806B0B0BDC046E80201204CFF0020F0B5054637
+:20CA2000ADF1340D0DF0D2FB1F4C074608342068D0F8080100686968836B102209A8984717
+:20CA4000061C28D12068D0F808010068016968468847AE682B8B019609A80693EA68009084
+:20CA6000A98B02926E8B0392731A07936B698DF82110701A0493801805900D2325688DF81F
+:20CA80002030D5F80811D5F80401096800688A6969469047064638460DF022FD002E14BF55
+:20CAA000E42000200DB0F0BD0C01002010B5044600213822ADF1900D68460DF0EFFB2046FB
+:20CAC0006946F2F7A1FB009841090DD2C0F3411000282FD06846EDF74DFF17480078C008B9
+:20CAE00028D306F07BFF25E010F0070F0CD000F0070002280DD102208DF8380002A9082221
+:20CB00000FA80CF0CBFD04E000208DF83800019C0F940EA80DF1460111AA03F017F948B9DF
+:20CB20000DF146000BF0CBFFBDF844000DF1460106F07CFC24B010BD220401201CB51E4B1E
+:20CB400003F1D4042078012202F0010120F001000143217093F8D40062F3820083F8D400EF
+:20CB600093F8D40062F3041083F8D40093F8D40062F3861083F8D40010480068406903F1A8
+:20CB8000D401027042F20200ADF8000009880DF10200018003F1D601097801A80170B3F850
+:20CBA000BE00022806D107480068054C426A2068694690471CBDC046501800201801002054
+:20CBC00080000120E0FF00202DE9F84304460420904689468DF8010068460BF015FD1C4DA7
+:20CBE000071C2ED03869072100F8011B217D00F8011BA18A091200F8011BA17D0170012675
+:20CC00007E7704F10B033B62BE770CF013FB7862B9F1030FBE7604D0B9F1010F18BF4020B1
+:20CC200001D14FF48860F8822C46201D0088B8F1010F788004BF002038763846EFF71CF88C
+:20CC400000E010204FF6FE71A980BDE8F883C046ECFB0020F8B5041D14F003001CBF241ACC
+:20CC6000241D0BF067FA1D4A054697685560112C28BFD768386800231E46010821D226B94C
+:20CC8000844209D93B4601261EE0196809188C42196019D81F460846DFB11169001B032869
+:20CCA00007D83868091A1161386840F00040386005E0385144F000403860091B11613F1D4C
+:20CCC00007E080F0004000263F1838680028D4D1002728460CF011FD3846F8BD501A002077
+:20CCE0002DE9F04114460D4680461E1CADF1280D08BF022034D03768EFB90C20FFF7AAFF6E
+:20CD0000071C14D068460021242208230DF0A4FB0023069741466A4605931348ADF8103061
+:20CD20000DF096FB38607D60BC60386808B9082016E037600CE00BF0FDF9044638680DF0FA
+:20CD40009DFA10B138680DF0A7FB20460CF0D5FC386841460DF078FB38680DF071FB002049
+:20CD60000AB0BDE8F081C0460D9F020030B50188ADF11C0DADF802100024ADF80040416891
+:20CD8000C27A019132F07F010AD1D10905D3807A012814BF0320201C0BE00125284609E0D9
+:20CDA000D10905D3807A012814BF0720042000E0052001258DF80800214603AAAB2006F0F3
+:20CDC000D3FB03A805A9224601F042FD09480078012807D19DF8140020B98DF809406846CC
+:20CDE00002F06FF98DF80950684602F06AF907B030BDC046D3FE0020F0B50546ADF1340D8E
+:20CE00000DF0E4F91E4C074608342068D0F8080100686968836B102209A89847061C26D1EA
+:20CE20002068D0F808010068016968468847AE6801962B8B0693698B0791EA68029209A82B
+:20CE400003926E6900900D230496297F8DF820302A698DF8211026680592D6F80811D6F86C
+:20CE60000401096800684A6969469047064638460DF036FB002E14BFE42000200DB0F0BD14
+:20CE80000C01002070B51E4C2068D0F85C0280471C490B781C490D7818B91C2000F0C4F8D6
+:20CEA00070BD0021194E2268A6F8AA10D2F8D42092F8314086F8AC4092F8242086F8AD209F
+:20CEC00096F8AE2042F0200286F8AE2096F8AE206843800022F01F0242F0020286F8AE201A
+:20CEE00096F8AE20C6F8B80061F3871286F8AE2086F8B03086F8AF1086F8B11070BDC0461A
+:20CF0000140100204E020120D8000020501800202DE9FF47067A022E1CBF804608240DD134
+:20CF200000880F128DF80A100DF108088DF8080004248DF80B7000128DF80900DFF854908B
+:20CF4000154F00254FF0010A30460CF093FA0AFA05F1014216D0022E19BF09F1080101EBE5
+:20CF6000C50107F1080101EB850122466846FEF7BDFD4046694622460BF086FB012808BFAA
+:20CF8000281C03D06D1C052DDEDBFF200090BDE8FF87C046B8100120941201202DE9F0432D
+:20CFA000054620480068ADF1140D05EB00090DF07FFA071C16D00DF063F906460DF03CFA47
+:20CFC00080466868012807D100246C60EF604046AE600DF021FA21E0E868874204D140465A
+:20CFE0000DF01AFA01201AE038460CF0C8FB02970024C7F818D0484669463246039409F01F
+:20D000006BFCE8680DF03CF9B04203DAE8683146FEF7ACFA40460DF0FFF9BC61204605B043
+:20D02000BDE8F0831CC40200B0B5074600251D481D4C05701E4805704FB92068006C00689D
+:20D04000C08AC00803D20DF04FFA184908602268AC32D168087808B1496C61B91068007841
+:20D0600008B906F0CBF8FDF763F92068D0F87012384688470BE0384688476068C068007827
+:20D0800028B92068D0F858242846014690472068006C006810B1007D352801D00CF0DEF9BC
+:20D0A000B0BDC046FC13012014010020E40501200A1401202DE9F04F1D4682462878032408
+:20D0C00009AF91468B46ADF1240D10FB04F006460DF0E2F85FEA00082FD0014600200EE05A
+:20D0E00010FB04F2AB185B780B70AB189B78AA184B705288401CC0B212128A70C91C2A787E
+:20D100008242EDDC012A02D1687800B90126002100913878019001250295039139794A463E
+:20D120000491042305965046CDF8188059460795F3F7BEF840460CF0EFFF09B0BDE8F08F7D
+:20D140003A280CDC182817DA083834D0401E30D0401E38D0401E2AD0401F2CD021E0E03880
+:20D16000022824D90838012823D9801E1FD0801F1BD0401E17D014E01838DFE800F01C1A96
+:20D180002418121212121C1A241822201E161C1A241822201E161C1A1212121212121A1867
+:20D1A00016C00020704710207047082070470420704702207047012070470720704706206C
+:20D1C0007047052070470320704770472DE9FF411D4D1F4F1D4C33264FF001082B79002B24
+:20D1E0002AD0032B28DAE9692269F1B982B13868022B4FEA8011A1EB800107D12888904748
+:20D20000012805D161692888884701E0288890478DF800806888ADF80C00684605F05EFEB9
+:20D2200050B101A805F0E6FB06E0A86910F1020F02D0E869401EE861761E05F12405CDD14A
+:20D240000090BDE8FF81C046E40D0020ECFB00206CBC0200F8B51C4ED6F860010168012001
+:20D26000884701282ED0D6F82401184DC4683C21012200232846A047002808BF002022D03B
+:20D280002F8817F0010704D14FF00120C5F80404288830688047012F04BF4FF08070C5F8E0
+:20D2A00004040D4A0A480B4F936901681069D161A0EB9000C91A07FB01F3190C814228BF90
+:20D2C000081C10610120F8BD8000001000A00C403020094040420F009402012003B40021AE
+:20D2E000F0B505AF3846ADF11C0D01AA01F0A4FB1B4C054604F1140000682DB910B18047C4
+:20D3000000B90B2520690DB1E8B224E0FFF746FE002506460095E18E94F8330001AA032300
+:20D32000F5F776FAC7B28FB99DF81400BDF8101006F08CF9009594F83300E18E01AA032343
+:20D34000F5F766FA0A2814BF012767782069314602F01EFA384607B0BDE8F04002B07047F8
+:20D360005CFC002030B5204D45EA0401ADF11C0DC1F315040021019102910391049104A9FF
+:20D380000091806802AA03AB01A9F8F737FE0146019802884FF6FF7090421DD101B30398BF
+:20D3A00008B1049840B9D9B102982B2105AA0BF0B3FCFF2806D113E02B2105AA0BF0ACFCC7
+:20D3C000FF280DD0C4F38850059C80056FF39F54044344F0004403E0A805204042EA000460
+:20D3E000204607B030BDC046FFFF3F00F8B51F4CA0F5C060D4F81011C4F82C010029B8BF9D
+:20D4000049420028B8BF404281422BDA4FF08057D7F8A401B4F81411154D40684FF47F422F
+:20D4200008230646009128463021B047D7F8A401B4F8181140684FF4F802122306460091EE
+:20D4400004212846B047D7F8A401B4F8281140684FF440620A230646009120212846B047AC
+:20D46000012000E0002084F83001F8BD1015002000A00C407CB5204C3C3CE06B00680146E9
+:20D48000042088471B4D02281AD0032818D001282FD12068406803214FF040521C23064631
+:20D4A000009128460021B0472068406801214FF4007209230446009128460021A0477CBD98
+:20D4C0002068406803214FF040521C230646009128460021B0472068406801214FF400727E
+:20D4E00009230446009128460021A047022009F0E5FA7CBD00A00C40E0010010B0B50546EF
+:20D500001E484268184C9269217817783FBB174B8A00B3FBF2F2AA4204D20068D0F84C05B9
+:20D5200080472178164B042011FB00F001B2181D00686768C06B05FB01748047211AA1F5B3
+:20D540004871090806D30A4A011B891A090828BF00F5487407482146F7F788FEB0BD064986
+:20D5600001200870B0BDC046D8000020FFF6C2FF00093D0071C40100081401201401002003
+:20D58000DCFF00207FB51F4C4FF47000E0600025A560656065701C4805700AF0CBFD064653
+:20D5A000206940B10CF00EFB10B120690CF006FE20690CF057FC68460CF04FFD8DF80050FF
+:20D5C0000E48019501216A4607F046FA0C4D206120B92868D0F84C05804720690CF0ECFDC5
+:20D5E00030460CF08AF82868D0F814150F208847E06800F077FE00907FBDC0468D6D02003D
+:20D6000014010020D8000020081401201B49B0B509684BF2F52250430027040A01F44021F4
+:20D62000B1F5802F03D116480068800C00D38FB14FF08055D5F8EC010068804707F06CFA02
+:20D64000D5F8E011C96888472111C01000B2484304EBE0340B48007830B90B48006820F04B
+:20D660007F402418640802E0084880F8407108480460210C416001278760B0BDB44F005097
+:20D680008C1300505016002010200940101500207C600C4010B58B4201D1824233D052EAC8
+:20D6A000000404D143EA01046400002C2BD052EA430401D18C4226E05C006415641C07D17E
+:20D6C0004C006415641C03D1CC0FB4EBD3741AE000290CD4002B16D48B4214D192EA000426
+:20D6E00001D482420FE000280DD101240BE0002B09DC994207D192EA000401D4904202E0C0
+:20D70000002A00D10124EFF3008454BF44F0005424F0005484F3008810BDF8B506AF3E789C
+:20D7200094468E46002E3AD0002735461B1F4FF6FF713C4633F8042F91422BD017B13F8835
+:20D74000B84201DD824205DC6D1E1F4604F10104F0D1F8BDA6421A4608DD361B121F32F813
+:20D76000044FA14202D0761EF9D1121D934203D2D11AC91C8F1000E0012732F8041C12F89F
+:20D78000026C118012F8015C96707F1ED570A2F10402F2D1188083F802C083F803E0F8BDF7
+:20D7A0001E4830B5ADF1140D94386A461430054604F0C4FB002404218DF8044020468DF8A4
+:20D7C00006400AF099F9332807DA0AF081F920B901208DF804008DF80600684603F0FCFC20
+:20D7E0004520294607F018FF9DF8060010B99DF8040000B101248DF8134009499DF8132082
+:20D80000091F08784978104001408DF8131041200DF1130107F000FF05B030BD78FB0020C8
+:20D820003804012003B41046F0B51E1C05AFADF11C0D14BF002804202FD081B201AA3846AA
+:20D8400001F0FAF8174C074604F1140000681FBB10B1804700B90B272069EFB9FFF79EFBB7
+:20D8600005460020009094F83300E18E01AA0323F4F7CEFFC0B250B10A2806D101A831465A
+:20D880000122EFF79FFE071C02D0012700E00D272069294601F07CFFF8B207B0BDE8F04017
+:20D8A00002B070475CFC00202DE9F0411D4C804620684FF0FF310CF02AF9D8F808601A4D5C
+:20D8C000D8F80470144A308C7369796828601160B3B9124A318B89180A78521ED3B20A701E
+:20D8E00073B9404604F024FE404609F041FE78680CF0D1FB0022318B094B286843F82120BC
+:20D9000081B24046F1F7A3FB0020387020680CF073FCBDE8F081C046A0130120D813012011
+:20D9200044130120A8130120A4130120F8B505460CF04CFC1D4C064604F1DC010878A8438D
+:20D9400004F1B80508702868002808BF002706D02868B8300CF036F9002700B101276868AE
+:20D9600038B1B8300CF02EF90025384318BF01252F4694F8DC00A0B9012F12D0D4F8D8002A
+:20D9800078B1816A89080CD3456A30460CF0A8FDD4F8D80002210022A8470020C4F8D800B1
+:20D9A000F8BD30460CF09CFDF8BDC04630F50020F8B507460024081C08BF0124002302B99B
+:20D9C0000123002F33D01AB197F84460002E2ED080B190F844606EB17D6B016CAD08A5EBB1
+:20D9E000910539460CF00FFA2D1AB5F1704F04DB002D02DC012C01D019E00124BAB1D068B8
+:20DA0000007B00F00F00022811D1516B386C8D081146A5EB900538460CF0F5F901262D1A39
+:20DA2000B5F1704F02DB002DD8BF002633431C40E0B2F8BD70B53A2000211122ADF1280DFB
+:20DA400001AB0BF0C9FF1A4D10B9A81C006806908220182101AA0CF0D7FA164E002407A8DB
+:20DA60000090214600220C23072007F0E3FE06F15D0008A908220AF007FE48B9641C052C7F
+:20DA8000EDDB08A8FF21082200F060FF641EA4B2069821460C2207AB0790072008F0D2FD33
+:20DAA000002101A81822298000F050FF0AB070BD4A040120E4FA00208CB501468A695078E3
+:20DAC000137803EB00231A480088984214BF0027184F1948006857B948F203000090087C5B
+:20DAE0000190487C8022891C09F092FC8CBD002200F8012B00F8013B1A1200F8012B3A684E
+:20DB000002F0F00302F00F021A4300F8012B3A68120A02F0F00302F00F021A4305230270FF
+:20DB200001F1110048F20302891C02F0F7FF8CBD50FD0020E01201209CFD00202DE9F84F37
+:20DB400099461E4B82460AAF98467C6858683E88237A8B46032B04D0012B0CBF0E250C25E9
+:20DB600000E0152511460CF017FB00F8019B00F8016B311200F8011B217A00F8011B217A8D
+:20DB8000032907D001290AD1217800F8011B2188091203E021460CF0FFFA397A0170102079
+:20DBA00088F80300524659462B46404602F0B6FF002188F80310BDE8F88FC04698FD002072
+:20DBC0002DE9F04100250446ADF1180D009506F0BDF91A48006840684078400828D3A26913
+:20DBE0009178507800EB012081B21079ADF808100AF0AEF88846071C00901BD00AF006FBC8
+:20DC00000F49A0690E46001DFEF7C6FC388804A90AF0A1F918B900980661284600E001203B
+:20DC200041466A46F5F7E4F90098007BFF2801D10AF0ECFA06B0BDE8F081C0465CFF0020AB
+:20DC4000E8020120BCB51D4D686A50B307460124032085F822400BF0A1FBB87908F038FBA2
+:20DC6000F87A00903988BA783B8907F10C00F9F7A7FA70B913480078000904D210480078AB
+:20DC8000D8B9082001E04FF400402146FDF7F8F8BCBD686A8DF8044008F068FB214601AB9A
+:20DCA00007E00020012185F822000DF105038DF805000A46032006F01DFDBCBD4CFF0020A5
+:20DCC00035FD0020E61201202DE9FC4180461E4808AF1B4CADF804100C303E7ABDF80410C6
+:20DCE000057846B93034302634F8020F81420AD0761EF9D10EE0182034F8026FB14202D02E
+:20DD0000401EF9D106E010461946012201AB08F066FD10B9B120BDE8FC81387950B1094857
+:20DD200004683CB101A8009039682A4601234046A04710B10020BDE8FC81B220BDE8FC81B8
+:20DD4000B0B6020000030120DC02012070B506467568B46895F8F900012816D094F8380075
+:20DD6000A16A09F0F1FE94F83900E16A09F0ECFE94F83A00216B09F0E7FE95F8FB00FF28DE
+:20DD800023D0616B09F0E0FE70BD94F83800E16A09F0DAFE94F83900A16A09F0D5FE94F8B8
+:20DDA0003A00216B09F0D0FE95F8FB00FF280CD0616B09F0C9FE95F8FB0004490BF02EFAC7
+:20DDC00095F8FB0031460BF00DFF70BD1D040200B0B507461A4C1B4D207818B12868D0F8B4
+:20DDE0004C0580472868D4300168194BCA8C991C0A800FB3032F1BD0052F06D0012F04D028
+:20DE0000022F02D0D0F87804804702202070FCF7E5FF2868D0F8D4104FF6FF72CA84D0F863
+:20DE2000D400094FC18C094C3980C08C2080B0BDFCF7D4FF032000E001202070B0BDC04615
+:20DE40006811012014010020220001203E19002070000120F8B51F4C2068D0F8E800002533
+:20DE600005602068D83001680F68A7B181687A68096891420FDD08F07DFB2168D8310A6806
+:20DE800012685368984202DD506008680268086902602068D83041680F684FB101690E68A7
+:20DEA0001EB172687B689A4202DD0F602068D83001690F683FB1806879680068884202DD71
+:20DEC00007F06AF8F8BD0BF0F9FA2068D0F8E8000560F8BD140100202DE9F0411D4CC668E1
+:20DEE000E76C00210125ADF1200DA04605FA01F23A4209D0735C0BF0CDFF984204DAE06CF6
+:20DF00009043E064D8F84C70491C1B29EEDB47B9114F0020396884F84A00C1B1C4208847E0
+:20DF200015E0684600211C2200F010FD8DF8045000268DF80760E06C009094F852708DF848
+:20DF40000570684600F068FE062084F84A0008B0BDE8F081E4FA00204404012010B5044618
+:20DF600000210C22ADF1180D68468DF8141000F0EDFC6078012809D0042807D002281CBF7D
+:20DF8000B3208DF8140004D10A2000E002208DF804009DF8140000BB2078ADF800002123A6
+:20DFA0008DF8023001228DF805206846F7F774FA9DF8140088B90398406C0821017061782F
+:20DFC00041706178022903D16168801C0CF0E4F8684606F0E1FC9DF8140006B010BD2DE9B8
+:20DFE000F04F1D4690466A68834600268A464FF0010909AF3046ADF1140D09FA00F10A42A2
+:20E000001CBF761CF6B2401C1B28F6DBA6B13046FEF720FE041C10D0002001466A6809FA5F
+:20E0200001F3134204D04A19127A431C2254D8B2491C1B29F2DB00E00024CDF8008001961F
+:20E04000029438780390A9786A6853465846FEF7C5F914B1204606F09FFD05B0BDE8F08F74
+:20E060002DE9F843DDF82480089C164689460AF0F7FF071C15D097F805C0002001E0401C5E
+:20E08000C0B284450DDDBD6882005119AA5A9145F5D122788D78AA42F1DC112E0ED0132EF4
+:20E0A00002D00020BDE8F88313B9CA7852080FD2012BE4D1CA789208E1D309E0012B02D1AC
+:20E0C000CA78120904D2002BD9D1CA78D208D6D30868C8F8000098F8020020700120BDE85B
+:20E0E000F8830000C8B50AF061FD01461C4803680429C3F34062C3F3C056C3F300674FF00D
+:20E10000FF302BD1C3F30331491F1BD0C91E24D0491E1DD0891F21D1180E0ED2980E07D348
+:20E12000580E03D2980E03D30F20C8BD1120C8BD002F14BF10200B20C8BD002A14BF0E20B1
+:20E140000D20C8BD56B1002A14BF26202520C8BD002A14BF0A200920C8BD0C20C8BDC0466D
+:20E1600094120050F8B51C4D0446286818B904F0E9FC286818B116490978A14201DC0024F2
+:20E1800023E0144A0C2114FB01246668A7684FF0FF310BF0BCFC114831780268012908BF61
+:20E1A00028680CD039682868531E0B4207D10C497B6809689A4202D81940994201D00024A4
+:20E1C00001E0012131700CF017F82046F8BDC0464CBF020070C1020094130120981301209B
+:20E1E0009C130120F8B50C46054609F0A3FF1C490E78002784466EB31C31BE463846A1F10C
+:20E20000180212F8183F9D4204D0761E00F10100F7D11FE09768EFB13A78944205D0BE4683
+:20E2200057F80C7C002FF7D114E0BEF1000F07D157F80C6CC20002EB00125218966003E0BB
+:20E2400057F80C0C4EF80C0C002047F80C0CFF2607F8026C60460BF050FA3846F8BDC046CC
+:20E26000501A00202DE9F0471D4D9C4608AF143DD7F810A07B68EE68AC78894696460146A5
+:20E2800066B3E878A04229DD162000FB04F28046B15408FB0460A0F80290A0F804E0A0F886
+:20E2A00006C03988018143B1AA78E96808FB02100E30194604220AF0EDFF398908FB046007
+:20E2C0004181B989BAF1000F818104D01230514604220AF0DFFF641CE0B2A870BDE8F0878D
+:20E2E000040D01201D4998B54A68926917783FBB154B1A78154F5B68042412FB04F424B2E7
+:20E30000920000FB0434B7FBF2F2824203D20868D0F84C05804712480068C06B8047211ACA
+:20E32000A1F54871090806D3094A011B891A090828BF00F5487407482146F6F797FF98BD5B
+:20E3400005490120087098BDD8000020FFF6C2FF00093D00D94E02000814012014010020F2
+:20E36000E0FF0020F8B51D4D6868C068012101706868806900781E461746022803D028687D
+:20E38000D0F84C058047002402204FF0807304EA070104EA0602384033400143134308BFED
+:20E3A00000290CD14FF0805304EA0700334008BF002804D12868D0F84C05804709E008496F
+:20E3C0006F6891F90000401E0870B86904700BF069F86868C0680470F8BDC04614010020B9
+:20E3E00012050120BFB50AF0CBFD002835D0417B062932D101680A7A44898DF8082009889C
+:20E40000ADF8001005F036FB200B26D3BDF80010002009F047F900BB114CB4F84810684615
+:20E4200009F073FA0020014609F03CF9071C11D04FF6FF75386801888D420ED0B4F848104A
+:20E44000FAF742FD1A2808D03846002109F02AF9071CEFD108460BF0DFFE0090BFBDC0469C
+:20E46000E4FA00202DE9F041E4F7CEFE1B4C1A49DFF86C802078002608704FF48040486042
+:20E48000206B4FF0FF310CF023F8206C35460921001F50F8042F17681FB9491E05F10105E6
+:20E4A000F7D1082DECDC09F045FE216CAF0079580D680E600BF021F958F8072030462946FA
+:20E4C0009047054609F036FE216C79580A6815430D600BF012F9D3E780040120D4DB002024
+:20E4E0000CBF02002DE9F8438146EFF31188202080F311880124164E164DF461164F6C60FE
+:20E50000F86A016A14208847D9F81000810C14BF000C0420A861386802682321002090476C
+:20E520000E480068C6F8804200280CBF211C03210B4807680FB141F00401286820F4E020ED
+:20E5400040EA01402860346088F31188BDE8F88300002443002009408401001078AB020076
+:20E56000D8AB020010B50246D07A401E2BD0C01E21D0C01F15D0801E15D0401F0ED0801E75
+:20E580000CD0801E1CBF5069002425D15069427800218A421FDD491CC9B2FAE710460BF0E5
+:20E5A000C8FA506917E05069427800218A4212DD491CC9B2FAE75069027800218A420ADDD2
+:20E5C000491CC9B2FAE750690278002101E0491CC9B28A42FBDC012408B106F0DDFA2046B1
+:20E5E00010BD000003B42DE9F04307AFBD681E469046ADF11C0D002D14BF002E042027D029
+:20E600001946384601AA00F017FA144C04F110010968002818BF071C19D10846FEF7BEFC91
+:20E6200081460020009094F83300E18E01AA0323F4F7EEF8C7B237B94146324601A82B4611
+:20E6400003F054FA07462069494601F0A1F8F8B207B0BDE8F04302B07047C0465CFC00206A
+:20E66000F8B507460BF0B2FD044677B3B87A60B397F909200AF068F8012303FA02F1CDB297
+:20E6800040B1144E30681132934098433060DA4346F8042C0020B8610346BB723B7207F12F
+:20E6A00010063B60024686E80C000B4A7B6002F5107003781943017092F8420210B1401E0B
+:20E6C00082F84202284607F0B5FD20460BF008FFF8BDC0460C10044030F50020F8B51D4C87
+:20E6E0000546E07904211E4606F036FA002818BF01202DD109F0B4FA36F0010018BF022ED4
+:20E7000025D10820FEF7A6FA07462069002F08BF10201DD010B9276104E008460168002948
+:20E72000FBD10760E079402106F016FA002180B23960C0F51670BD8080B2B0F5167FF8809E
+:20E7400005D1E07940214FF416720BF004FD0020F8BDC04634FD0020B0B50546AC69ADF1D3
+:20E76000180D20460AF060F948B10AF063FD014620460AF03DFC012818BF201C00D100205B
+:20E780000290277AF80939BF0024201C012000248DF80C0037F07F070CBF201C01208DF8BD
+:20E7A0000D008DF80E4002A8FCF77EFF8DF81000A91C48F23402012304A8009005F111002E
+:20E7C000019405F053FF1FB9029808B90BF0A8F906B0B0BD2DE9FC470646884691469A4641
+:20E7E0001A487168184DB2684B681468118C03603046296003F09CFE07464046241807BBD3
+:20E8000003218DF80010200C8DF80340220A8DF8010029888DF8022030460BF054F96846D5
+:20E82000042104F0C3FC002818BF4FF0FF3704D14846514608F0B2FE0746298830460BF07B
+:20E840004BF93846BDE8FC87A4130120A0130120F0B50F46014616464FF6FF70002FADF104
+:20E86000240DADF818002ED000292CD0002401AA3C7003A80091801A83B201A908221D46CA
+:20E8800006A805F043F9002804BF012038700ED00DF11A002146082200F058F80DF11A0006
+:20E8A0002B4601A90822009006A805F02FF9BDF81800032805DA26B1304601A914220AF0BA
+:20E8C000E9FCBDF8180009B0F0BD30B5044620880125ADF1340D3A22ADF8080060688DF8EE
+:20E8E0000A5007A9049011200BF07FFA20B107A80021112200F02AF80DF11D038DF81550E7
+:20E900009DF81C00039321898DF80B000BF0CEFA884207D08DF81650ADF800106068019019
+:20E92000684602E000208DF81600069002A8F0F7FBFE04460021112207A800F007F82046CA
+:20E940000DB030BD002213460A46194671B510F0030F0BD0002A82BF00F8011BB2F10102AB
+:20E9600010F0030FF6D1002A08BF71BD11F0FF0141EA0121042A18D341EA0141082A0FD3B7
+:20E980000E46102A08D30C460D46B2F10F0312F00F0272C0103BFCD812F0080F18BF42C05E
+:20E9A00012F0040F18BF40F8041B12F0020F18BF20F8021B12F0010F18BF017071BD00006D
+:20E9C0002DE9F04705460021281D0BF0F9F905F104094FF6FE7100206A88A981914227D08F
+:20E9E00014490F884E68044688461FE0A10001EBC401725C12F00F0F16D071186B884A88E2
+:20EA00009A4211D101F1040A50460AF00DF8012807D1484651460BF0D3F9B8F80070D8F8C6
+:20EA20000460AC8101203C46641CA4B2A742DDDCBDE8F0873005012010B5B1F5805FA8BF07
+:20EA4000052031DA0378402BA8BF09202CDA4388B3F5806FA8BF072026DA8388B3F5806F78
+:20EA6000A8BF082020DA114B5B1E1B78032B08BF032019D0D181017801F03F0441880023B9
+:20EA80006FF39F2141EA0431848893816FF39F2444EA01341460818891804488D480017825
+:20EAA000117296249472184610BDC0465DFC0020FEB5044602208DF8080019480D46018880
+:20EAC000ADF800406846FAF7FFF91A281DD01549FF2600224FF6FF77891C081F30F8043FF4
+:20EAE0009F4203D1FF2E08BF161C01E09C4211D0521C052AF2DB052A0DD1FF2E07D10748D0
+:20EB0000B0F84810684608F000FF0020FEBDB0000C52401845800120FEBDC046E4FA00206A
+:20EB20002CFB002020010020BFB519490EC901A880E80E00174D0024274601A800902146EC
+:20EB40003A460C23072006F075FE02A92846082209F09AFD38B9641C052CEEDB019808B9DE
+:20EB60000FB912E004240C49887970B9012088710A4D01990C2201F2E240019001AB6860E1
+:20EB80002146072007F05EFD6F800090BFBDC04620C3020041FB002034FD00204804012095
+:20EBA00010B500211822ADF1300D6846FFF7CEFE822018216A460BF027FA0021112206A841
+:20EBC000FFF7C4FE3A20112106AA0BF01DFA3B20112106AA0BF018FA0C49002008700C48A4
+:20EBE0000078012818BF02280DD10A4A4FF48170102114460BF002FA28B94FF48170102145
+:20EC000022460BF001FA0CB010BDC04649FB0020ADFE002038BC020030B500240546282244
+:20EC2000ADF12C0D2146AC716846FFF78FFE0B220DF1190005F10B010AF02CFB12482968F6
+:20EC4000016068460AF01AFB28798DF8110068798DF81200E8798DF81500287A8DF81600AF
+:20EC6000687A8DF81700A87A8DF81800074800688DF81440D0F87C148DF81340684688471A
+:20EC800020460BB030BDC046E4130120140100202DE9F84F0AAF7C6897F808803E68814695
+:20ECA000184692468B46234658B3074600259C4207D10BEB050148463246FFF78BFD00BB76
+:20ECC0000023B8F1010F05EB0A0103EB060005D00278097800208A4208D006E009780078F6
+:20ECE00001EA000200208A4200D00120002818BF6FF0060006D17F1E03F1010305F101057E
+:20ED0000D5D10020BDE8F88F2DE9F04104460BF05DFA194D29688046D1F8EC00D1F8E010F3
+:20ED200050F8240008602968D1F8E410134C08601048083C00682678C06B80476768B100D6
+:20ED4000B0FBF1F177B92868D0F8E0000068884208D2B1FBF0F10427484316FB07F109B2AB
+:20ED60004143616008F072FC40460BF0B9FBBDE8F081C046E0FF002014010020E000002063
+:20ED800038B51B4D28684069012444772868A830C16A497B0F2927D0006804706868016C66
+:20EDA000202088472B681349D868816103F1D400D96802681B69527B91F8305033F81230F9
+:20EDC0006D00AC404FF470755C43034605FA02F08008A04238BF041CD3F81C2401F110004B
+:20EDE0004B346100904738BDD0F8BC00804738BD14010020A1AA0100B0B51B4903680F68FB
+:20EE00001C8800210A466FB17D7B052D07D13D682D88521CD2B2AC4204BF491CC9B27F68F7
+:20EE2000002FF1D1032905DA092A03DA0F493431098800E00121018105214173418941F41B
+:20EE40000061418118884FF6FF77874206D0054801881846FAF738F81A2802D101200BF00F
+:20EE6000DBF9B0BD2CFB002038050120E4FA002030B54968ADF12C0D81B308208DF8000060
+:20EE800000258DF8015008788DF8020048780A1D8DF8030092E8190001AA82E81900087CBC
+:20EEA00001F114058DF8100095E8090005AC10221C3184E8090007A80AF0ECF92C2009F0B4
+:20EEC0000CFB04460748057844B1204669462C220AF0E0F92846214604F0DEFB0BB001206C
+:20EEE00030BDC0469C030120F8B50B4601464C69601E024218BF221C651E184610EA0507A7
+:20EF00001CBF2044C01B834213D8CF6801F10C0C7FB1531E796803EA070613EA070518BF8A
+:20EF2000561B84198C4206D9BC46DCF80070002FF0D10020F8BD091ABA198D1B3EB98E42A6
+:20EF400004BF3868674608D03968674602E07E6025B1396810180160456038601046F8BD73
+:20EF60002DE9FF4105460420984616460C468DF80100684609F048FB071C28D0B8F1000FFD
+:20EF800008D00120BC800023B8773878FB7640F080003870396903220A70481C06704470A2
+:20EFA00021128170284605F097FD48B9284601A908F0D1FF20B10120787701AE3E6201E044
+:20EFC000002078777D803846ECF756FE00E001200090BDE8FF8198B517460C46521E2CD052
+:20EFE000521E26D0921E0AD0121F03D0083A29D1102200E0082221680AF050FB22E022684B
+:20F00000036852F8011B01F0FF011943016052F8013B1B0641EA1341016052F8013B03F071
+:20F02000FF0341EA03410160126841EA0261016008E0216809F05EFF04E021680278097866
+:20F04000114301702068C019206098BDF8B505460C461A2009F041FA071C31D000211A227C
+:20F06000FFF774FC79203870002078702188B9806188F980217939726679014606B1012159
+:20F080007972A679014606B10121B9720146E07900B10121F972207A3873607A7873A07A19
+:20F0A000B873E07AF873207B082204F10D01387407F111000AF0EEF8E8B2394604F0ECFA10
+:20F0C000F8BD30B5044600210C22ADF11C0D6846FFF73CFC20880121ADF800000C208DF83A
+:20F0E0000400607A8DF8051000280CBF081C21208DF802006846F6F7CFF99DF8141099B94B
+:20F100000398456C06232B706168681C0BF044F8A078687260880012A872207AE8726846B3
+:20F1200005F03AFC9DF81410207A002814BF081C002007B030BD00001B4910B504463422A5
+:20F14000ADF1380D6846FCF7D1FCA088ADF80C006088ADF80A00207D8DF81C0020690A908D
+:20F16000207F8DF80500208DADF81000207E8DF80600607E8DF80400608DADF82E0094F828
+:20F180002C0000228DF83000FF208DF834000DA98DF835004FF0FF308DF836006846E7F76F
+:20F1A00029FB00200EB010BDD0BE020003B41046F0B51E1C05AFADF1140D14BF0028042072
+:20F1C00027D0114638466A46FFF736FC134D044605F114000068DCB910B1804700B90B246A
+:20F1E0002869ACB9FDF7DAFE0746314600226846EEF7E8F9041C07D1BDF80C1021B19DF8C3
+:20F20000100004F023FA6C782869394600F0C0FAE0B205B0BDE8F04002B070475CFC002032
+:20F220002DE9FE43194C1A4D05264FF6FF790A274FF00208A41E34F8040F814521D06388A6
+:20F240008BB15B1E9BB293FBF7F0638078431B1A17D120888DF808802988ADF800006846C3
+:20F26000F9F732FE0DE020888DF808802988ADF80000684608F049FB2046FF210422FFF7EA
+:20F2800065FB761ED7D1BDE8FE83C046200100202CFB002038B51B4C184A0023164994F85A
+:20F2A0003A01136020B3012817D0022807D003281ED151F8350CFEF799F8062016E051F82D
+:20F2C000355C2846F1F78EF940F2FE50A84202D2001DA842F1D8042008E051F8350CFEF727
+:20F2E00095F9074800780028E7D00220C4F83C010AF0A0FA38BDC0463D400C403C500C408F
+:20F300000AC2020010150020F8B50D4606460AF05DFF0446E8B20AF0C9FA8025071C23D0DC
+:20F32000B87A08B3386886421ED11349486891F82410022906D03846FFF792F900F096FF3B
+:20F34000812511E097F909100A4E4FF4A06202EB012202F47F4246EA0201002206F084FF3B
+:20F3600005463846FFF77CF920460BF0B9F82846F8BDC0460100080430F5002070B505465C
+:20F380000AF024FF194C06464FF0FF30E06205F1B8000AF013FFB4F9B400B4F9B610884297
+:20F3A0000FD194F8240002280BD094F8DC0040B130460BF095F80720FEF7B8FA0AF006FF94
+:20F3C0000646B4F9B400B4F9B61088421CBF012085F8FC0006D104F5CE700AF0EFFE0820B1
+:20F3E00006F028FF30460BF07BF870BD30F50020F8B51B4C01F0400C002296264FF6FE75B3
+:20F40000A4F1080737F8081F884208D185420AD0BB790CF0400103F04003994203D0761EC5
+:20F4200002F10102EED11646962E12D1854210D1214696220026087928B1521E01F1080162
+:20F4400006F10106F7D1962E08DA0888614608F0A7FE962EB8BF04EBC60000DB0020F8BDCC
+:20F46000BC0300207CB502281E4614460D4612D0042818BF012829D108461A46012101F078
+:20F48000DBF818B33CB1284602F0E8FB0C28BCBF012020701ADB28460021FFF7A9FF78B1F3
+:20F4A000817911F0180F0BD04FF6FE710091094E0288438831881046002203F0FFFD07E057
+:20F4C000284631460822F5F703FC08B100207CBD01207CBD1EFB00202DE9F84308AF3F78CE
+:20F4E00099461446064607F00FFFDFF858800D46082816DB4FF6FE70002107F005FF082860
+:20F5000008BF02201CD0D7B14100424601EBC000FF23155411184E800B4F8B713878087217
+:20F520000AE04100424601EBC0008118C879A042D8BF032004DD17B1CC71A1F804900020C3
+:20F54000BDE8F883A40100201BFB0020F0B5024691694878097801EB002117480768ADF1EF
+:20F56000140D0AF0A3FC154C88421CBF0020812314D13B46002002E01B68401CC0B2002B23
+:20F58000FAD1401E0023C0B247B1A4467D682E780EB10CF8016B3F68002FF7D10091019051
+:20F5A0000294107C0390517C48F20500921C01F019FA05B0F0BDC04624050120A8FF00205F
+:20F5C00008B513460A4618BB3A2A14BF3B2A012114D0174940F20310904205D12031184654
+:20F5E000102209F057FE08BD10480078682A0AD0B2F5817F18BF622A16D1002110461022F0
+:20F600000AF0EAF908BD0128E9D002280CD1E6E7052808BF052002D0062805D106200093EA
+:20F620000022102306F006F908BDC046ADFE002018BC02002DE9F0470D46298890460446A3
+:20F6400007F03EFF002818BFB82028D109F0CAFE1028A8BFB22022DA1820FDF7FBFADFF880
+:20F660004490D9F80060071C08BF102017D04FF0000AC7F800A0B81D294612223C7109F0BE
+:20F6800009FE16B94E4603E0064630680028FBD1B8F1000F376001D005F07EFB5046BDE87C
+:20F6A000F087C0461C030120DCB504460027211D6846ADF8007009F01DFCBDF800603846E5
+:20F6C00046B1BDF800104FF6F8728A42C8BFBDF8000022DC267826B1022E04BF6779E07A17
+:20F6E0000DE06068070C00F47F4607F47F4100F0FF0407F0FF0744EA06000F4380B287425D
+:20F7000087EA000103D04FF6F8728A4204DC00280EBF0721083881B20846DCBD90B51B4C26
+:20F7200022687032116891F82B70ADF1140D57BB516E8F783FB3037AC168D2F81821184670
+:20F740009047071C1FD02068016F91F82B0040F0040081F82B002068D0F85C1302A8884704
+:20F760006068816A01208847012024680090206F20300190D4F8D400C38CD4F87843394644
+:20F7800002AA0520A04705B090BDC04614010020F8B504461A48006825180AF089FE0B46A4
+:20F7A000071C2BD00AF048FE064623BB38460AF067FDA168884203DDA1683846FBF7D6FEE5
+:20F7C00028460AF031FEA0B928460AF021FE8168E16008460AF054FDEFF31187A060202035
+:20F7E00080F31188084639460AF00EFE87F3118801E00120606030460AF00EFEF8BDC0461E
+:20F800001CC40200F8B51A4C2578064608F092FC84461848037800278BB1001D10F8181F20
+:20F820008E4202D05B1EF9D109E08068074630B13878D12803D057F80C7C002FF8D16046F3
+:20F8400009F05BFF381C10D1022008F046FE0146E07931B1D12008704D70304603F01CFF96
+:20F86000F8BD102102F09EF9F8BD4570F8BDC04634FD0020501A0020002980B534D00F0E9A
+:20F88000202F1BD0212F08BF022218D0A02F08BF032214D087B1102F08BF05220FD0112FE8
+:20F8A00008BF06220BD0402F08BF072207D0502F0CBF0822092202E0042200E00122C1F3EA
+:20F8C0009701090241EA02110268B2F1FF3F41F00F0106D0914204D050F8042FB2F1FF3FE2
+:20F8E000F8D14FF0FF31016080BD00001FB504681748617A012913D000686169806891F808
+:20F9000021100246684690476069416990F82120684605F020FC10B96FF00200606006E01E
+:20F92000006861698268486991F821109047094840210160802404600021C0F8FC12022045
+:20F9400007F0BCF804480AF057FC00901FBDC046FC01001004440240B80E0120B0B50446C4
+:20F96000E16891F8380000F00300012810D12069077C77B9496C0A78052A0AD14978012918
+:20F9800004D006291CBF0321017402D102210174206900210170E068216990F848008870D0
+:20F9A000E068216990F84200C870E068216900694860256909F03EFC014605F108000AF090
+:20F9C000EBFB2069F5F7F0FD2075B0BD2DE9F04380460E464FF6F870ADF1140DB04202DC3E
+:20F9E000B8F1000F24D0144C332500F1070901272079FF2818D0B8F1000F05D1B14513D06B
+:20FA00002088B0420ED00FE08DF800706088ADF80C00684603F062FA30B101A9404609F0EA
+:20FA2000E7FA08B1204604E06D1E04F12404DFD1002005B0BDE8F083E40D0020062809DC79
+:20FA4000062814D0C8B1801E14D0801E0FD0401E0AD007E00A3807D0801E08D0C01E03D0BD
+:20FA60000F3801D000200AE041F2011007E04FF2011004E04FF4817001E040F20250FF2942
+:20FA800004BF40F0C00121F480610AD031B149082CBF40F0100040F0200001E040F03000F3
+:20FAA000014640F2037040EA01407047F8B51A4C6069002510B1804700B90B2520694DBB35
+:20FAC000FDF76CFA65780026074606E03046F9F7A5FC761CF6B205436570E178B142F5DC1B
+:20FAE000002084F83100491E84F832100C2684F8330010FB0641B1F84C10E1867E2106F0E0
+:20FB00007DFF94F83200FE2106F078FF20693946FFF73EFE2846F8BD5CFC002010B50AF08B
+:20FB200055FB154991F82420022A1ED091F8241004291AD00AF0D4FC10480068006B8047A0
+:20FB40000F4A002309F002FD0E4C4FF090531B1820684FF07A044FEA000244EB01040021AD
+:20FB60005B1844EB0204241C04E0074990390C680AF0B6FC204610BD30F500208C0100106B
+:20FB800000093D000413012094300440184930B58422ADF1BC0D02A8FBF7A8FF15490EC914
+:20FBA0002CA880E80E0002A800902CA8019004208DF88C0002F038FC684623A9FBF710FE87
+:20FBC000051C10D00C4928A814220AF000F9284628A907F003F80446284609F08FFE002C3B
+:20FBE00008BF002001D04FF0FF302FB030BDC0465CB802002CC302000813012030B504469B
+:20FC0000A07AADF11C0D50BB606805A96A46FEF71FFE0146E07A400921D29DF81400012811
+:20FC20001DD19DF81000022819D19DF81250FF208A000D4B8DF81000681C02EBC10200F06C
+:20FC40000F008DF81200002001900E330090D5186860985014226B46042006F0F3FC204689
+:20FC6000F7F76EFC07B030BD56FE0020F8B50446102141F221054FF6FF7000F0010742089D
+:20FC800024BF684080B2401017B140F4004080B2491EF2D1641E10274FF6FF7614F8010F30
+:20FCA000082108F0F1FD802106F400437200014296B21CBF83F400439BB213B185EA06023D
+:20FCC00096B24910F0D17F1EE8D13046102108F0DBFD4FF6FF71484080B2F8BD2DE9F04388
+:20FCE0008046ADF14C0D02A808F0E9FE164D4FF00709022600242F68FFB1B868E8B18DF83B
+:20FD000000903A6AADF80260ADF804402AB19DE8030090472F68412808D0BF689DE80300FE
+:20FD2000412202ABB847012807D109E0B8F1010F03D1204602A903F079FB641C052CDADB5F
+:20FD400013B0BDE8F083C046F8FD00202DE9F0410F1C904606460AD04EB1B8F1000F06D0B2
+:20FD600000242046394607F02FFC0A2802D10120BDE8F0810D281BD03578387805F00701A2
+:20FD800000F00700884213D12DB9301DB91D042208F0E0FE38B9022D0AD1301DB91C082272
+:20FDA00008F0D8FE20B1A8F800400020BDE8F081641C052CD5DB0220BDE8F081002980B597
+:20FDC00032D00F0E202F1BD0212F08BF022218D0A02F08BF032214D087B1102F08BF0522A3
+:20FDE0000FD0112F08BF06220BD0402F08BF072207D0502F0CBF0822092202E0042200E05D
+:20FE00000122C1F39701090241EA02110268B2F1FF3F41F00F0106D0914204D050F8042FA6
+:20FE2000B2F1FF3FF8D1016080BD98B504466FF002001F688DF800003A462046FDF7B8FDE7
+:20FE400010B101208DF800009DF9000010F1030F13D1E068007B00F00F0002280DD167B1CC
+:20FE60003A6820463946FDF7A3FD18B9002A1746F6D102E002208DF800009DF9000010F128
+:20FE8000030F04D1E06B10B104208DF80000059807609DF9000098BD10B50C466068ADF15A
+:20FEA000200D58B302218DF814100188ADF80C10817B02298DF81E100DD001290BD00F2900
+:20FEC00009D003290BD100F1100108220DF1160009F0E0F903E06068008AADF81600606877
+:20FEE000818900910DF116030193017E0291837A821C03A92220FDF721FE00E0022060703C
+:20FF000008B0012010BD002B08BF002A0FD10B1C021C002908BF002807BF002000210020BB
+:20FF20004FF00041C4BFC043C943F9F7B6B910B55C0894EA610404D55FF0000E40426EEB33
+:20FF4000010113F0004F04D05FF0000E52426EEB0303FCF763F9241C04D55FF0000E5242D0
+:20FF60006EEB0303640004D55FF0000E40426EEB010110BD2DE9F8430024002B16460F468D
+:20FF80008046254606D5002FC3F1000302D57F42761E2D2599463846494605F03DF80CA02F
+:20FFA000405CB7FBF9F7002F04F1010408F8010DF1D1A64205DD3021301B401E08F8011D28
+:20FFC000FBD10DB108F8015D4046BDE8F883C046303132333435363738396162636465662B
+:20FFE00000000000F8B505462C680F460AF0EEF816490978012902D194F8221019B10AF0E1
+:020000040002F8
+:200000006FFA0020F8BD012684F822600AF068FA07B90D4F387884F8200078686060387869
+:20002000022814BF0021B96884F82360002084F82400A16084F8250084F826000B20F9F763
+:2000400043FD2846F8BDC046A4C202001F05012070B5064635680AF0B9F8002195F82120E2
+:2000600085F82410032A1CBF042A85F825100AF037FA0F4800F108010968090824BF4FF0C7
+:20008000FF31E9610B490160304606F003F895F82000022807D06C68E9692A6895F8213086
+:2000A0003046A04770BD04480AF0A6F870BDC0468847024001000080080F012010B50446C6
+:2000C0006089ADF1200D05A900F064F805A807A96A46FEF7BDFB9DF81C0070B19DF8100041
+:2000E000FD2818BF002808D10D48007828B9607A48B96068007806280FD0607A18B96068BA
+:200100000078072809D0207B18B960680078052803D1044801682046884708B010BDC0463D
+:20012000D4FE0020840201201CB50C46217F052907D104F1080100F02DF8002808BFC82073
+:2001400024D004F10800694608F0A6FFBDF800004FF6FF71814218D02078012810D1BDF8F6
+:2001600000100B4B880000EBC10003F12C014018A16902688A4288BFA22007D8491C01607E
+:20018000BDF80000A08200201CBDA1201CBDC04660FE0020D0B50746184800880C4601263E
+:2001A00087421ED009F070FE874216D0384607F0D2FE06460F480078C8B90AF02FF8B0B907
+:2001C000AEB90D490888B84211D187B11C312046082209F05FF8012609E0084609F080FFBB
+:2001E00005E009F027F80146204609F0D5FF3046D0BDC046ADFE0020700201201EFB0020E8
+:200200002DE9F041174D804605EB880528680C46660824F0FF0186F0010606F0010610F012
+:20022000FF0F0AD109F0D2FF210A6970270CAF70210EE9700AF054F900E02960002706B19F
+:20024000012727B1404604F0010109F0D3FC09F0BDFF054941EA88010F600AF041F90020E0
+:20026000BDE8F08100100840001A4442194838B590F82410022928D0044694F82400012820
+:2002800026D094F82400042822D009F09FFF05466846FBF747FE80B1009949B904F5AC70F2
+:2002A00009F08CFF04F1E000042109F0ADFF08E004F5AC7009F02CFA03E004F5AC7009F00E
+:2002C0007DFF28460AF00CF938BD192009F084FF38BDC04630F5002010B504461848017863
+:2002E0002078ADF1180D001F21D0801E0BD0801E24D1012918BF022920D12079FAF756FF8B
+:2003000007F0AEFC1AE0012918D16088B0B9201D694606F02BFB012810D109F0C7FDADF86A
+:200320000800241D01946846FBF7A8FA06E0012918BF022902D12046ECF714FB06B010BDDD
+:20034000ADFE0020F8B50446A07C0C28B2BF0026A069C67AF01D4000FCF77CFC071C25D0DB
+:20036000A46925783D700DBB641C381D214609F013FF083461782078002500EB0120788041
+:200380003D739EB1A41C14F8010B387314F8010B07F10E01787362782078761EF6B2A41C63
+:2003A000002E00EB022021F8020BF4D13846F8BD2DE9FC410020ADF800001420FCF74AFC5F
+:2003C000071C27D01448006808B38046032402254FF6FE76A8B241460622C01908F05AFF84
+:2003E00038F8060B864204D0BDF80000401CADF80000641E05F10605ECD1384669460222D9
+:2004000008F048FF4C2014213A4609F0FDFD384604F0C2FBBDE8FC8160FE002070B5064649
+:2004200009F0D8FB05466C68304608F0B1FBA0B909F0CCFE0546D4F8C00040B994F8FB0044
+:20044000002106F0F3FE012084F8FC0001E00121017428460AF044F870BD09F0B7FE0646B8
+:2004600094F8FB00002106F0E1FE0121D4F8C00084F8FC1008B10421017430460AF030F8DE
+:200480002846F0F7F9FD70BDF8B5194C6068C06800780E4628B92068D0F858240021012027
+:2004A000904709F093FE054609F008F804F054FD07462068D0F8EC1051F82610D0F8E00092
+:2004C00001602068D0F8E400016007F0BFF82268D2F8D8000168D2F8E02438469047206838
+:2004E000D0F8D4048047284609F0FAFFF8BDC04614010020194898B501684969FF220A76DB
+:20050000016814310B68DC7E012C0CD0D1F8C0104A7B91F82C108A421ED04068406C80475F
+:2005200007F0E0FE98BD0020D876886AC77A9FB1D1F8C00090F843308DF8003090F852305D
+:200540008DF8013090F853008DF80320D1F8C0138DF802006846884798BDC0461401002032
+:200560001949420828BF081C21D2020924BF081C001D1CD2420924BF081C083017D28209B6
+:2005800024BF081C0C3012D2420B24BF081C14300DD2820824BF081C183008D2C20824BF5D
+:2005A000081C1C3003D2C20B03D30846103000687047C11300F40050C903084314BF002084
+:2005C0004FF0FF307047C04634FC002010B50C460146ADF1880D684609F0DBFD11A8214670
+:2005E00009F0D7FD9DF87A00800828BF002021D29DF87A0040080BD30DF17F000DF13701B5
+:20060000042209F04BF89DF87A0040F002000AE00DF17B000DF13701042209F03FF89DF8B3
+:200620007A0040F001008DF87A0011A9204609F0B0FD012022B010BDF8B50F4614460546E3
+:200640004FF6FE76012F03D1032104F01FF920BB2846002104F068FF2146FEF7C9FE012F95
+:2006600017D110B14179012903D0E00938BF2E1C00E046884FF6FE74B44210D0304603211B
+:2006800004F004F948B9B54209D0AC422E46F5D105E020B14079022801D10020F8BD01200F
+:2006A000F8BD000070B505462C6894F8200004280AD0022818BF00261FD113484FF0FF31EE
+:2006C00009F025FAE66918E00D480068806901460C488847000824BF4FF0FF30E061E669C2
+:2006E000002094F8211084F8240003291CBF042984F82500284605F0CDFC304670BDC046D3
+:20070000FC01001001000080080F01202DE9F04706464FF6FE70708006F1040AB08150460B
+:2007200008F082F94FF0000801281DD110480788D0F80490C7B14446A50005EBC4054D44B4
+:20074000287810F00F0F0BD0291D504608F050FC012805D16888B4814FF001083C46708002
+:20076000641CA4B2A742E7DC4046BDE8F087C04630050120B0B5154DD5F860014268002139
+:2007800001209047D5F8600101680120884788B10F4C278817F0010704D14FF00120C4F897
+:2007A0000404208828688047012F04BF4FF08070C4F804040748084CD5F86C710068183C43
+:2007C0006061386880472062B0BDC0468000001000A00C4030200940AC020120F8B5184D06
+:2007E0000C3DE97895F8334000273E4624E095F83200761CA042B6B217D0E86861036A46BA
+:20080000042309F039FC009800F0FF00FF2803D07E2818BF7C2808D1A00000EBC400401960
+:20082000B0F84C003F1A07F50057E978641C94FBF1F04843241AE4B2B142D8DC3846F8BD8E
+:2008400068FC0020E1291CB528D10189154C491C89B20181E9B112480078F8B1943CB4F8A2
+:20086000941088421ADA002001F0BAFEB4F894206421414391FBF2F11A290FDB0A49091FCD
+:20088000096859B1ADF80200ADF80020684688471CBD00202080012001F0A2FE1CBDC046CA
+:2008A000D7FE002078FB0020FC000120F8B5184B1C780F2C25DA1F78E50005EB0415ED182B
+:2008C0002C77FD0005EB07151F7803F11C06AD196860F80000EB071080191F78C160197855
+:2008E000F800CD0000EB071000278019876005EB01101D7880190774E80000EB051080195F
+:200900004261641CE0B21870401EC0B2F8BDC046501A0020F8B5184C1548D4F8A86009F04A
+:2009200081F91449054608680F6800F02000284007F460270DD066B10300C4F8B0600022CF
+:20094000304604F0D3FD04F1E0004FF4804109F05BFC17EA05000AD094F8411241EA5040BA
+:2009600084F84102002104F58E7009F04DFCF8BD20000E000C10044030F50020F0B5184CCD
+:2009800000250526ADF1140D5D3401A80090294600220C23072004F04DFF02AF2046082216
+:2009A000394607F071FE48B93846002108F09BFB18B96D1C052DE8DB00E02E46052E0CDA68
+:2009C00002A82146082208F065FC002031460C2201AB0190072005F035FE05B0F0BDC046CA
+:2009E000E4FA00202DE9F843DFF85C900446904608AF8DF8001009F104003A79398800689F
+:200A000048F20605A5420CBF1025002500F8013B00F8011B0E1200F8016B002A027008BF56
+:200A2000042605D0111DCEB2B968401C08F032FC4F462246684641463346FD7000F06EF8F8
+:200A40000020F870BDE8F88398FD0020F8B50746387A012804D0384605F001FB064600E0F5
+:200A60003E884FF6FE70B04221D0114C0025397A012909D12801A0EB450000194278012AEA
+:200A800002D1428896420AD001290AD02801A0EB45000019437823B941888E4201D109F0F6
+:200AA00019F96D1C042DE2DB304603F073FAF8BD6C010020F8B5844640F6FF741CF8013B25
+:200AC000002210E0481B401E10F8015B7F1E01F8015BF9D103E01CF8010B01F8010B521CAD
+:200AE0005B08082AEADA5808F5D21CF8010B1CF8015B05F00F07FF1CC5F30315122F45EA80
+:200B0000001508D11CF8016B300A24BF1CF8010B60F3DF16BF19AC42D4D1F8BDF0B50E46C9
+:200B2000174604461D4600210C22ADF11C0D04A8FDF70CFF00208DF81900307A0F498DF8A5
+:200B4000180030884A68ADF81000207802F8010C48686B1C401E3A460090881C0190C878A5
+:200B6000074902900F20039004A8EDF7E9FD10B92178491C217007B0F0BDC04698FD0020E4
+:200B800064FD00201649174A00200968A2F8AA00D1F8D41091F8313082F8AC3091F8241095
+:200BA00082F8AD1092F8AE1021F0200182F8AE1092F8AE1021F01F0141F0010182F8AE1068
+:200BC00092F8AE1060F3871182F8AE1082F8AF00054982F8B100097882F8B0107047C04690
+:200BE00014010020501800204E02012070B5154E154C706928B12068D0F8541206F114006B
+:200C0000884709F0E3FAF1690A68002515710968F16109F065FC0D4A0D49107810B908464F
+:200C2000007870B1157008460570F8F717FD6068C068007828B92068D0F858242846014606
+:200C4000904770BD68110120140100200514012007140120F8B509F0B9FA164D164C2E7887
+:200C6000297801290ED001272F7009F039FC6068C068007840B92068D0F85824002138460A
+:200C8000904701E009F02CFCEBF70EF9074609F09DFA07B92E7009F023FC6068C0680078D7
+:200CA00028B92068D0F858240020014690473846F8BDC0460E05012014010020B0B5477883
+:200CC000144D17BB082095F85C4085F84A0034B91148016809B13846884707F0B1F8104C17
+:200CE000601C0078012802D1384607F06BFA0B48006868B1207D01280AD128784FF4804111
+:200D00004FF47A7209F024FAB0BD00204A352870B0BDC046E4FA00204404012010FC0020E3
+:200D2000ACFE002030B50C466068ADF11C0D38B3017819B9401CF3F7EDFC22E0002501A8EE
+:200D40000090A9B200221423042004F073FD607090B9606803A90822401C07F095FC58B91B
+:200D600001A800211422FDF7F1FDA9B20420142201AB05F067FC04E06D1C032DDFDB01E0A0
+:200D80000220607007B0012030BD000038B505462C6801206070207A042809D0022805D140
+:200DA00011484FF0FF3108F0B2FE15E0002038BD0A480068806901460C48801E8847000806
+:200DC00024BF4FF0FF306060002106486170044908602846FEF78AFD606838BDFC01001059
+:200DE0008847024003000080080F01200300008038B505461548007838B31549083951F8C4
+:200E0000084F4A681278954202D0401EF7D138BD2068A16909F0CEF9206809F0CDF9207949
+:200E2000401E02280CD9C01E08D0001F04D0801E14BF01200B2004E0092002E0062000E0EA
+:200E400005202071284608F0DDF938BD57BF0200C4C2020070B504F0C1FB04F080FD08F0CD
+:200E6000A9FE124C606828B1606803F095FE0020208060600E4D2C687CB120686668006A22
+:200E800003F08AFE206803F087FE606903F084FE204603F081FE341CEFD10020286007F012
+:200EA00083FD04480078F3F777FA70BD3005012038050120E4FA00202DE9F0410E4634885D
+:200EC000ADF1200D162C22DDDFF84C804703362CDABFA4F1160085B22025D8F800006A4677
+:200EE000641B2B46A4B2391909F0C6F80DEB050010F8011D962904D16419A0B2308001204C
+:200F000006E06D1EADB2002DF2D1162CDFDC002008B0BDE8F081C04668FC00202DE9F0474F
+:200F2000164E074630788A4600244FF01808B14603E099F80000641CE4B2A0421CDDFF2F7B
+:200F400007D006F11C0114FB08F04518085C874209D0FF2FEDD109F0ABFA14FB08651C35E5
+:200F600069688842E5D107F0E5F86A69116821EA0A01116008F0C1FBBDE8F087501A00201F
+:200F8000F8B5174C2678002786B1221D12F8183F984203D1002301B101231374157C0023C3
+:200FA0002F4318BF0123761E1F46EFD1A0784FB198B9012005F09AFD022005F097FDA07832
+:200FC000401C09E0012808D1012005F077FD022005F074FDA078401EA0703846F8BDC046F9
+:200FE000501A0020F8B5174C064604F13A0000880F46B04208BF012504D030460023FDF7BF
+:20100000AFFF05463046002104F08EFA618F814216D138460021FEF7EBF970B1817911F096
+:20102000180F0AD04FF6FE71009102884388618F1046002202F042F802E0384608F052FBDC
+:201040002846F8BDE4FA0020BFB50546A8690778FF2F08BFFE271348134C0770207880219C
+:2010600001F05EF902F0C2FD00248DF8084008F091FD30B1002F0CBF201C0120084988707F
+:20108000C870287B50B902A80090A91C48F236020123019405F1110003F0E8FA0090BFBD5A
+:2010A00054FE002036040120E4FA002070B50E46054607F03FF8044608F0DAFE012DB6FB7A
+:2010C000F0F00ED0022D07D00B4B18B9186808F023FF0DE0094908E0094B0028F6D00949D0
+:2010E00003E0094B0028F1D008490022FBF7F8FD204608F002FB70BDFCFF00202D8F020015
+:20110000F8FF002045940200F4FF0020ED94020098B5174C2268D2F8DC00D2F8D810076846
+:20112000D2F8E00009680068D2F8E024404290475FB12168E0310868026878688242DCBF42
+:20114000801A78603F68002FF5D1226802F1E4000168D2F8E02009681368994204D01160E1
+:2011600006F074FA2068E430D0F8F003804798BD140100202DE9F041164E0D4604460021FA
+:2011800070682160C068007820B93068D0F858240120904709F01AF880462946204607F00C
+:2011A000E1FE2F682A463FB161687868884203DC3A463F68002FF8D1146027602868844297
+:2011C00003D13068D0F8D4048047404609F088F9BDE8F08114010020F8B5174E054606F19D
+:2011E00014042878A978207068780822707540EA011070752979E878B778B07540EA810076
+:20120000C0B26979B07540EAC100C0B2A979B07540EAC110E91DB07506F1170008F03AF853
+:20122000032205F10F0106F11F0008F033F80E2FC4BFA87CA073F8BDE4FA00202DE9F04159
+:20124000082B90460E46044638BF082398B207F044F91025071C1DD03E7000260F487E70E9
+:201260003946BC700078C7F8048002F015FA70B9304609E009F01CF904F0FCF83978204672
+:20128000FCF7B0FF00B10126002EF3D04578384607F00AFA2846BDE8F081C0460D140120E1
+:2012A0002DE9F041069C1646884607F0CBFE071C07D097F810C0002001E0401C80B28445AA
+:2012C00002DC0020BDE8F0817D69820002EBC0025119AA5A9045F0D11A888D88AA42ECDC74
+:2012E000CD79002235F07F0E18BF0122964201D0EA09E2D307C984E80700A0881880012065
+:20130000BDE8F08170B5174C0546A41EAA7823780021B420012BA27003D12B88E688B34248
+:201320001ED153081AD3930807D3686808F0E8FD6968A278891C696001212B889209E38028
+:2013400003D200220125E27001E00125E570A36825702BB182B22846984770BD02F03EFB6D
+:2013600070BDC04622040120FEB5057C012300221C460EE000EBC206367F770806D316F063
+:201380000C0F03D0F60828BF002300E00024521CD2B29542EEDC077AAFB9012C18BF0129A9
+:2013A00011D141798DF80310012404728DF80830C788ADF80670817A8DF80410684608F0FD
+:2013C000F8FC2046FEBD0020FEBD2DE9F0410446D4F8A8501F461646884605B1A84704F19F
+:2013E000A00003C806400F4008BF002E1CD041462046802204F05CF804F1B00181E8C00066
+:2014000058B100F1200106C900F12003BA43B14383E80600D4F8A81081600020C4F8A80083
+:2014200004F1500008F0E8FEBDE8F081F8B506461446182007F051F8071C27D00021182233
+:20144000FDF784FA6120387000257D70207838716088211D0822F881781D07F01BFF207B94
+:20146000787478B1207B4000FBF7F4FB786148B105E0680001196D1CC9897A698152787CDD
+:20148000A842F6DCF0B2394602F006F9F8BDF8B506461446182007F020F8071C27D00021F4
+:2014A0001822FDF753FA6020387000257D70207838716088211D0822F881781D07F0EAFEF9
+:2014C000207B787478B1207B4000FBF7C3FB786148B105E0680001196D1CC9897A69815207
+:2014E000787CA842F6DCF0B2394602F0D5F8F8BDF8B50646708875680024022807DB032284
+:20150000B0FBF2F15143411A18BF201C20D1401C80B208F0C1FED8B17188012914D003234F
+:2015200072685218AA4212D9297814FB03F287187970AF786978821801EB072151807188E3
+:20154000641CE4B2ED1CEBE72978417001240470F8BD000070B50646356808F037FEA9789E
+:20156000F9B90021697008F0BBFF0F4800F108010968090824BF4FF0FF3169600B4901606A
+:201580003046FEF7B3F9287A022806D02C6969686A696B7A3046A04770BD054808F02CFE7B
+:2015A00070BD08F09DFF70BD8847024003000080080F01207FB508F009FE114C06462078FD
+:2015C000012818D0684608F01DFB00254FF0FF3027216B4601900C4A0A488DF8085003F0A7
+:2015E000D9FD0B48012105F0A5FE0848294605F0A1FE01202070304608F072FF00907FBD59
+:201600000306012040120120F75D0100080F0120B80E012030B5164C05466068ADF11C0D98
+:2016200018BB0820FBF716FB6060002808BF10201CD0296801602979017169794171A97925
+:201640001C22817168460021FDF780F900228DF80720286800902C798DF805406B798DF858
+:2016600004306846FDF7D8FA00E0012007B030BD340401202DE9F04180461548006840684A
+:20168000124F46688568C468B8F1000F0AD0002D08BF002C03D03846503008F0CBFA36B1FB
+:2016A000ECF783FC1EB1B8F1010F00D0B047002D08BF002C08D008F0DBF805B1A84704B15C
+:2016C000A047384606F024FDBDE8F0810100070634F50020F8B507461248012416460D46F9
+:2016E00004700820F8F7F0F9022005F0FFF93120394608F073FD0C490320012D486019BF09
+:20170000086820F00300086840F00300074A086010680068314603460020024698470448B7
+:201720000460F8BD050601200C800240CC010010A80250422DE9FF41154D8046281D06684C
+:2017400011480F461446414607F052FC002804BF0F214FF6FD7002D00C48022100888DF892
+:201760000810ADF800004146304608F015FD6946002200F8017B0A2304702846FFF7CEF994
+:201780000090BDE8FF81C04620FC002050FD002098FD0020024610B54FF6FF70ADF1300D94
+:2017A000ADF8200002208DF82800FF208DF8290008F048FC012300930021019102930391F9
+:2017C000049008460590069008A9079010460322EEF76EFD041C07D1054800784FF4804128
+:2017E00041F2883208F0B7FC20460CB010BDC0464DFF002010B504460A22ADF1180D684644
+:2018000007F04CFF0A21204603AA03F065FC48B99DF800109DF80C2001F0070102F0070299
+:201820008A4201D0002013E09DF8002012F0070F07D002290CD10DF102000DF10E01082215
+:2018400004E00DF106000DF11201042207F082F906B010BD98B5154CE768014697B114488C
+:20186000001D006800693B78007883420ADC7A78D218824206DD7A68C01AC0B210568842C3
+:20188000B8BF011C07480068026EA06890470090054A00996FF39F518A4214BFA0614FF005
+:2018A000FF3098BDE0FF0020FFFF3F00700001201401002070B5164C05466068C068007868
+:2018C00028B92068D0F8582400210120904708F07DFC2268D2F8D810D2F8F82406462846F5
+:2018E000904730B92268D2F8DC10D2F8F824284690472068D0F8E8000068A84203D104F06B
+:20190000EBFDFCF7A7FA304608F0EAFD70BDC0461401002098B5164C2068D0F8E800002186
+:2019200001602068D83001680F68A7B181687A68096891420FDD04F01DFE2168D8310A6870
+:2019400012685368984202DD506008680268086902602068D83041680F683FB101690868C2
+:2019600018B140687A68904200DD0F6098BDC04614010020F0B514461D4610270246ADF1E7
+:20198000240D264601AB16F8010B7F1E80F0360003F8010BF7D10B46009501A80121ECF73E
+:2019A000E1FD05A82946102207F074FC102001AA14F8011B401E81F05C0102F8011BF7D187
+:2019C000009501A8012105AA8023ECF7CBFD09B0F0BD03B480B502AF39780020012908BFE5
+:2019E00001207978012908BF40F00400B978012908BF40F00800F978012908BF40F01000B4
+:201A00003979012908BF40F020007979012908BF40F04000B979012908BF40F08000F9793B
+:201A2000012908BF40F48070BDE8804002B07047C8B5061C2AD0202006F04FFD071C25D090
+:201A400000212022FCF782FFE32000233870311D7B7091E80D00391D81E80D00307C06F1B3
+:201A60001403387493E8050007F1140181E80500307F3877F22007F02FFA18B9384606F0D3
+:201A800013FEC8BD0079394601F006FEC8BDF8B506460C460C2006F020FD071C25D000217B
+:201AA0000C22FCF753FF7620387000257D70A0784000FBF7CFF8B860A0B12088B880A078F1
+:201AC000B871A07810B1A078A84204DCF0B2394601F0E2FDF8BD616868006D1C415ABA6805
+:201AE0008152F0E7384606F0DFFDF8BD2DE9F84314468846064600229946F189B08900922C
+:201B0000727A337C401A80B2054604F05FFB071C14D10C48B28900684544A9B20B199A4222
+:201B200005DAF089A042ACBF0627052706E0327C234601EB42314A4608F09EFA3846BDE808
+:201B4000F883C04668FC00202DE9F047144D8046287800274FF018093C4605F11C0A19E04E
+:201B600014FB09A63178884512D106F1080005F0D4FA0746B06828B920464FF40041FFF766
+:201B8000CDF904E020464FF4004100F00BF82878641CE4B2A042E3DC3846BDE8F087C046C7
+:201BA000501A0020154A2DE9F84F0F461178804600244FF0180A032002F11C06914618E0AF
+:201BC00014FB0AF5725D904511D106F0B3FA83467119486902683A430260C86808B108F0A0
+:201BE0000FFC584607F089FD99F800100020641CE4B2A142E4DCBDE8F88FC046501A002089
+:201C000038B54FF0FF3007F00BFE05460F4C1049A06A81420FD10F4904F16000002206F0F8
+:201C2000D3FC022084F8240003F00CFF18B9F9F731F8ECF7A9FB0848284205D004F1E00040
+:201C40004FF0005108F0E0FA38BDC04630F50020F95E0000F95D010002000040B0B5154C2C
+:201C600001460C20002504F108025388994205D0401E02F1080205F10105F6D10C2D16D104
+:201C80004FF6FE70884212D10C21002514F8087F27B1491E05F10105F8D108340C2D06DAA6
+:201CA0006080606818B102F077FF002060602846B0BDC046EC010020DFB5171C0C46064618
+:201CC00026D02EB340F20110002110226B4607F083FE04F00F0438460DEB0401C4F1100225
+:201CE00007F0D8FA381B69462246103007F0D2FA7F1E3046082617F8012F01783C7A51406E
+:201D0000397010F8011B761E81EA04013972F2D10090DFBD2DE9F84384680D4603F0F4FCE5
+:201D2000174600BB246802F059F964198046002F08BF00250FD00D4E08F048FA81462046BC
+:201D400006F050FF0546484608F0CAFB1DB930683F1A0444F0D1404606F0AEF8002D14BFB6
+:201D60004FF0FF300020BDE8F883C0469813012030B584684568ADF1140D204606F024F82E
+:201D80002168486820F0020048602168486920F00F00486120680321016202A808F006FA9D
+:201DA00009480068D5F8E42001680092D5F8E8000190206895F8F93095F8FA200C46039985
+:201DC000A04705B030BDC046C4010010B0B5124C0546802D03DD2068D0F84C05804708F0A4
+:201DE000F5F90F4927680D70D7F8B8100F780B4917B90F783FB90AE00F7837F07F0702D1DF
+:201E000008490F781FB108F06BFB0120B0BD08F067FBF9F781FDB0BD140100200A14012085
+:201E20007000012000140120B0B5124C0546802D03DD2068D0F84C05804708F0C7F90E49CA
+:201E400027680D70D7F8B8100F780C4917B90F783FB90AE00F7837F07F0702D108490F78EB
+:201E60001FB108F03DFB0120B0BD08F039FBF9F7A1FDB0BD14010020700001200A140120A8
+:201E800000140120154838B508300168D1F8D40090F85300D1F818148847042814BF40F6B1
+:201EA000387443F66C4406F045F9054607F0E0FF074A084B127821464A430749B2FBF0F039
+:201EC0000022FAF70DFF284607F017FC38BDC046D800002000000120498902000C01002056
+:201EE0001CB50E21F8288DF8001023D1124CA268D432116891F8840050B991F942000E283A
+:201F000015D0D2F85C23E02069469047A2680DE014208DF8000091F94200142807D0D2F8B4
+:201F20005C23E0206946904708342268D432D2F8F80280471CBDC0460C01002038B5044602
+:201F400014F8010B15462870207800F00F00687014F8010B0011A870207800F00300E870E3
+:201F60002078C0F3800028712078C0F3C300687114F8010B08222146C011A871E81D07F087
+:201F800089F90834032205F10F00214607F082F914F8030FA87438BD90B50C466768ADF14D
+:201FA000140D07B3124968461222F9F79FFD7888ADF80000397979B1B86868B1084610283D
+:201FC000A8BF0F2061680DF1030389688DF802000246184607F05EF9606800786946012220
+:201FE000FDF728FB00E00220607005B0012090BD4CC202002DE9F041804614460E461020DA
+:2020000006F06BFA071C21D000211022FCF79EFC6520387000257D70BE802078B87160884B
+:2020200038812079B8722079FAF714FEF86040B104E02819F968407968546D1CB87AA8429F
+:20204000F7DC5FFA88F0394601F026FBBDE8F0812DE9F041804614460E46102006F03DFA1D
+:20206000071C21D000211022FCF770FC6620387000257D70BE802078B87160883881207921
+:20208000B8722079FAF7E6FDF86040B104E02819F968407968546D1CB87AA842F7DC5FFA94
+:2020A00088F0394601F0F8FABDE8F081154909681E280ADC1E2819D00C380FD00A380FD0C2
+:2020C000001F0FD0C01E0FD01AE0243810D0001F10D0401E10D0801E10D011E0086870473C
+:2020E0004868704788687047C8687047086970474869704788697047C8697047086A7047A2
+:2021000000207047B016002000B54FF6FF70ADF11C0DADF80E0001218DF810108DF80C10B7
+:202120008DF812108DF804108DF814100B48029004208DF811000020009008238DF81500A2
+:2021400007488DF8161003216A4600788DF81310B621FFF773F807B000BDC04600F8FF07E1
+:202160007CFB0020B0B544684088401E10F0030F18BF002022D180080225C7B205EB8700F6
+:2021800080B208F089F8C8B1217847700170AFB1641C0023657821789A0001EB0521851898
+:2021A0006980A17885182971E1787F1E03F1010300EB020504F104046971EBD1B0BD10B541
+:2021C000044600210C22ADF1180D6846FCF7BEFB6089ADF80000207A8DF80400207B8DF878
+:2021E0000500607A012814BF012021208DF802006846F3F751F99DF8140050B90398616823
+:20220000227A406C07F046F8684602F0C5FB9DF8140006B010BD0000F8B507464FF6FE7008
+:202220003E78B881002006B3104E32887568044619E0A10001EBC4016B5C13F00F0F10D183
+:202240003878685478886D18391D6880281D07F0B7FDBC81284607F0FFFD32887568012009
+:202260001446641CA4B2A242E3DCF8BD3005012030B5ADF1140D684607F0AAFA00206946C4
+:20228000F6F796FA0E4C6946A0600120F6F790FA60604068007806F07BFC28B92078B52184
+:2022A00000220823FEF7CAFF064DA068294607F046FF6068294607F042FF05B030BDC046F6
+:2022C0007CFB0020098A020003B40021F0B505AF3846ADF11C0D01AAFCF7AEFB002818BF16
+:2022E000002015D10D4C2069FAF758FE002506460095E18E94F8330001AA0323F0F788FA41
+:2023000008B9BDF8125020693146FDF741FA284607B0BDE8F04002B07047C0465CFC0020D5
+:20232000F8B50D46064605F005FF04462946304606F0DAFA071C18D0386808F0ADF8384699
+:2023400008F0B2F80B4901F108000068B84207D000E0084601698F42FBD13969016101E03A
+:2023600038698860384602F017FC204607F0C5F9F8BDC0468004012038B5134D95F83901C2
+:20238000002410B91148007860B107F01FFF95F83B11002906BF012185F83B11012408F08A
+:2023A0009FF80CB1002038BD022004F09FFB0E20F7F78AFB05F04EFF01280EBF01200020EA
+:2023C00085F83A0138BDC046101500200AC20200144BB0B511F1800F43EA0202C2F31502E5
+:2023E00008BF071C19D090F9004000277F2C0FD00546D5F801406FF39F54A34208D095F997
+:202400000040A14204DB15F9054F7F1C7F2CF0D137B107EB87077F1F3F18D7F80100B0BDB7
+:202420001046B0BDFFFF3F0038B507F0CFFE0E4C05462078012813D00C480D4A3121002382
+:2024400002F0A8FE0B480C490422082307F042FA0A4A4FF0FF300121FFF73CF901202070F8
+:20246000284608F03DF838BD04060120EC110120BDBF0100081201202003012080A903005B
+:202480003EB5144C05466068017060684270287A022818BF0F2816D129884FF6FF708842FB
+:2024A00005D0C21E8A4202D0801E88420BD102238DF8083007F0FAFC69463622ADF800000A
+:2024C0002046FEF72BFB2046294636220223FEF725FB3EBD98FD00204EF68851CEF2000186
+:2024E00008684FF0F00340EA034008600C4885460C4885446F4607208743BD460A486F4679
+:2025000007600A48002803D07946491D8E460047F8F73CFF06F05AFF07F06EFFFEE7C046FF
+:20252000003A012000060000EC05012085A20200FEB506461248B5680078124C8DF800002E
+:2025400003E0686A08B107F04DF92188304607F0BAFA6846012100F029FE01A8012105F05F
+:202560001DF821880746304607F0B6FA002F18BF381C04D19DF804004008E2D20020FEBD94
+:202580005BBF0200A413012010480078A0B91048007888B90F48007870B90F48007858B935
+:2025A0000E48007840B90648007828B90548007810B90548007808B10020704701207047F2
+:2025C0000E0501200F0501201005012005140120071401200A140120001401200614012037
+:2025E000F8B505461348002133230A460479FF2C06D0078A27B1002D06BF0F44B9B20282A6
+:202600005B1E00F12400F1D1094832234FF6FE7430F81C6FB44206D0078B27B1002D06BF32
+:202620000F44B9B202835B1EF2D10846F8BDC04650080020E40D002038B504461248007880
+:202640000D4640B11149608908310988814203D101F062FF38BD60890021FCF7C9FE60B176
+:20266000807910F0180F08D0688E00906189627F2B8DA08900F022FD38BDA08961890022F7
+:20268000FEF7B0FC38BDC046B4FE002016FB0020FEB5144C154604F1280217681E46FFB17B
+:2026A0003A69EAB101228DF80020BA6AADF80200002AADF8041008BF002003D09DE8030024
+:2026C0009047A76A854208BF00200AD03C699DE803002A463346A047012808BF0A2000D0A3
+:2026E0000920FEBDD4DB00202DE9FE43134C06462068984617460D4607F07AFE814629466A
+:202700003A463046FCF7F0FB07462068494607F06BFE5FB90848006800900196054C029542
+:2027200021880022DD23404607F05AFE3846BDE8FE83C04610AC0200D4AD0200ACAB0200B5
+:2027400098B50446A1682079FFF72CFA207B00BB206807F0A1FE0F498868A04207D000E0CF
+:20276000104602699442FBD12269026101E020698860C86800222261CF6817B9CC6004E0CA
+:2027800010460269002AFBD1046108784968FFF709FA98BD8004012098B5426802F003010C
+:2027A000012920D1D1081ED2104903680F681C7DCFB139798C4203D03F68002FF9D112E0FC
+:2027C000B96881B19F8817B1FF1E09D00BE0120904D2C07A38B9086800B18047002098BD5D
+:2027E000EFF710FE98BD012098BDC0460C18002038B505460021142007F0FCF900240A2009
+:20280000002107F0F7F9C4F1070045FA00F1092001F0010107F0EEF90A20012107F0EAF9A4
+:20282000082007F08FFC641C082CE8DB0A20002107F0E0F91420012107F0DCF94FF42F7058
+:2028400007F080FC38BD7FB506460020029008981D46009002A801903046FDF7E6FA04467C
+:20286000012C03D12846314605F09BFB022C0CD102980268006820B92846314605F07EFB44
+:2028800003E02846314605F02BF8042C03D12846314605F073FB204600907FBD1FB50446BC
+:2028A0000021AB200DF1060200F05EFE06F0C2FC01460DF1060006F09BFBA8B120460DF192
+:2028C000060105F048FB88B10DF10600694605F0ABFF18B90098007930B907E00DF1060078
+:2028E00001A905F051F808B9012000E0002000901FBDD0B51F46144606460B461FB30520CA
+:202900003873187880B95968381D06F0B7FC012E04D05968384606F0B1FC0FE03846002111
+:202920000422FCF713F809E002280CD1191D3846082206F0AFFC0EB1C520387307F10800B5
+:20294000214606F09BFCD0BD70B5418846680325B1FBF5F06843081A18BF00201ED1B1FB42
+:20296000F5F0C0B2044600EB4000401C80B207F093FC98B1047000210DE0327811FB05F3FE
+:20298000C4186270B4787278491CC9B2C318F61C02EB04225A8002788A42EEDC70BD00007C
+:2029A000B0B505462C680F4607F010FC10490978012901D1217819B107F092FD0020B0BD2F
+:2029C0000121217007F08CFD07B9084F38782072786820613878022814BF0020B868E060DD
+:2029E0000B20F7F771F82846B0BDC04694C202001505012090B5ADF1140D07F09DFB071C2B
+:202A000008BF002410D001248DF800407888FF212422ADF80C003846FBF798FF802087F8C4
+:202A20002100684603F0BAFF0020042105F064F8332804DA034901200870FAF7B1FE204661
+:202A400005B090BD3504012010B503F0BFFF114C14202146491CFDF7D3FB0A202146FDF700
+:202A6000CFFB09202146FDF7CBFB0B490820FDF7C7FBB920FFF7BCFE142004F0C1FB0A2079
+:202A800004F0BEFB092004F0BBFB082004F0B8FB10BDC046006200200220002002461348AD
+:202AA00098B570300168476D01F00103002007F004071F4318BF0120930802EA000006D33B
+:202AC00001F002040023204318BF01231846D20806D301F004010022084318BF01221046BA
+:202AE000002814BF0120022098BDC046D02008402DE9F043171C0D464FF00009ADF1240D1F
+:202B000019D0DFF83C804603202FACBF20243C1C4046006871196A46234607F0ADFA4846DD
+:202B20006946224605F0D0FE3F1B2D19BFB2ADB28146002FE8D1484609B0BDE8F083C04637
+:202B400068FC002010B510481249104A006800F00F0083025C1E08461360E1430160012052
+:202B600004F0FEFB044607F031FB094A116831B107F0B6FC34B1204607F0E6F910BD146042
+:202B800007F0AEFC10BDC0463024034098130120941301209C130120084608B500F000517A
+:202BA00000F00400084316D00B480068016801208847012808D007F05BF93221B1FBF0F1B0
+:202BC000064806F0A5FD08BD0549064828310860054807F02FF808BDE001001088F600202E
+:202BE00030F50020F95E0000F4120120F0B5134E00274FF6FE75ADF1140D07F042FA0446F1
+:202C0000301D0088A042F8D007F03EF9A042F4D0204601F061FF0028EFD1002CEDD08DF854
+:202C20000070ADF802406846FBF7CAFE0028E4D1A542E2D0204605B0F0BDC0461AFB00205C
+:202C4000F8B50D46044607F0C1FA06466768A0682946874205D1304607F042FC4FF0FF302E
+:202C6000F8BDE568A26923686D1CB5FBF7F078432D1A05FB0230F8F739FFA0686169E5602A
+:202C8000401CA060814238BF6061304607F028FCA068F8BDB0B5171C0C460546ADF1280D07
+:202CA00019D01048B9680068884204D8B1F1FF3F18BF002014D1684600212822082307F0AD
+:202CC0008BFBFA680792386804907B680593B96806916A4600E000222846214606F0A4F9F2
+:202CE0000AB0B0BD7CAC02009EB507460C46084600226B46032100F02FFFD0B1029A108879
+:202D0000874216D00B4948783FB90020108048784FF40051FFF704FB06E017804FF40051EE
+:202D20004FF47A7207F017FA0348016809B1204688479EBD4CFF0020E002012038B5134CA4
+:202D40000546A06848B9182007F0A6FAA06008B1002141610146056115E0A4681434206856
+:202D600020B100F1140420680028FAD1182007F093FA2060011C06D0486910B10020486194
+:202D800021680D612168084638BDC0467004012098B544684088401E10F0030F18BF0020AD
+:202DA0001FD18008C7B2384600EB4000801C80B207F072FAA8B12178477001708FB1641C6E
+:202DC00000226378217801EB032183185980A1787F1E00EB020302F1030204F103041971B5
+:202DE000EFD198BD12492DE9F04180460120114F087017E07D887E6820462946324607F037
+:202E0000FDF870B9B8F1000F06D120462A460021334606F0E1FD04E020462946324607F099
+:202E2000F3F808373C88002CE4D1BDE8F081C046B9FE002010AE020070B50646B5682968F1
+:202E40007468486820F002004860204607F0BCF9D4F8CC0003F0CDF804F1300007F0CEF9E7
+:202E600094F8F80018B904F16C0007F0C3F9304602F0E4FE287BF6F731FB04F11C0005F0DD
+:202E800023FC002084F8FD0070BD10B50C466168ADF1180DE9B1A068D8B1087800280CBF0C
+:202EA0003B203A2011226B46002106F095FD607088B96068A168007808709DF80000A16860
+:202EC0004870A06810220DF10101801C06F0E2F901E00220607006B0012010BDF8B5064623
+:202EE0004FF6FE7000217080301D06F069FF304604F0DAFD351D0746012F13D1B0890A4BE1
+:202F0000840004EBC004181D0068241860887080241D204605F088FD012803D128462146D6
+:202F200006F04EFF3846F8BD30050120D0B50446122005F0D2FA07460F480668D7B13846EB
+:202F400000211222FBF702FDC720387000237B70A0893882A07A21460A22B873381D06F088
+:202F600099F91EB9384605F09FFBD0BD3079394600F092FBD0BDC0462C1A002011482DE941
+:202F8000F041076800260760B7B1DFF83C800124D8F80410B7FA87F0C0F11F0082008D58A1
+:202FA00004FA00F39F43002D08BF1E4302D08958C0B28847002FEBD116B1304600BF00BF4F
+:202FC000BDE8F081E0200240D4C2020070B5124C054694F84A000E46ADF1200D042814BF3F
+:202FE0000828C22016D0E564684600211C2284F85260FBF7ABFC00958DF8056001208DF897
+:20300000040000238DF80730022284F84A206846FBF702FE08B070BDE4FA0020F8B5124C35
+:2030200006466069002710B1804700B90B272069BFB9F9F7B3FF27780546381C0DD1E08EB4
+:20304000C0F5005000B2864203DC002E18BF042703D10020E6F7B8F8677820692946FCF797
+:2030600097FB3846F8BDC0465CFC00203EB504461048052100224FF6FF75801E30F8043F6E
+:203080009D4201D09C4204D0491E02F10102F5D13EBD052A0DDAFF210422FBF757FC064DBC
+:2030A0000220ADF8004029888DF80800684604F02CFC3EBD200100202CFB00202DE9F04137
+:2030C000044698460D46101C06AF17D108460021FCF78EF9061C17D0B079400814D33888A2
+:2030E00041462246F4F756FC4FF6FE7181420BD0708028460C222546044600E00B2220469E
+:2031000029460023FBF72CFFBDE8F0811CB504463A220120694606F068FEE0B99DF8000019
+:20312000A04216D001200DF101013B2206F05DFE88B99DF80100A0420DD19DF800009DF837
+:2031400001108842A8BF3B2007DA9DF80100F8F72DF83A201CBD4FF6FF701CBD38B504682E
+:2031600094F83000042808BF0F4D17D0022805D001280CBF00204FF0FF3038BD216A04F167
+:20318000340006F0C4FC0DE0012006F0DBFF281F006810F0030FF7D0F8F710FFA06A616A0C
+:2031A0008842F1D8E06A38BD0C800240F0B5124C074600250E46ADF11C0D2068029577B990
+:2031C0000121009106AB01933A788DF81820694606F066FF48B1761E0AD07F1C206800965E
+:2031E0000197694606F05CFF10B94FF0FF3000E0284607B0F0BDC046A013012098B506F031
+:20320000E5FF04460D48007898B90D490F78012037F07F0707D10B490F7837F07F0702D184
+:2032200009490F781FB180F00100C0B208B103F06DF9204607F054F998BDC04606140120B0
+:20324000051401200A1401200014012038B5124C22680546D2F8EC0050F82100D2F8E010C7
+:2032600008602168D1F8E41008600A480068A84203D82068D0F84C058047280803D32068C3
+:20328000D0F84C05804706F0A1FF07F029F904F0DDF938BDE000002014010020124AB0B5EA
+:2032A000032311464C88A04208BFC52015D05B1E01F10401F6D1114603234FF6FE754C880A
+:2032C000A54208D05B1E01F10401F8D1111F032211F8047F27B94880002004220A70B0BD40
+:2032E000521EF5D1C720B0BD28FC00202DE9F047114E00258A460746A846B8F1000F18D183
+:203300006C01A4EB8504A01900F10209484605F08BFB58B1305B874208BF48F00A08514665
+:20332000484605F065FE08B148F0A0086D1C322DE3DB4046BDE8F0876C080020F8B5124C27
+:20334000607801281CD004F5C27600204FF4405731467F1E41F8040BFBD1E82131604BF652
+:20336000FC75A851A5F1E801C6F8E81006F1E801A160F9F76FFCE060A660012060702561B5
+:203380004BF6BE20F8BDC046501A00207CB5124C0346A06A16460025E0B18269D2B1012244
+:2033A0008DF80020826AADF80230ADF8041082B19DE80300904760B1864208D1A06A8269B3
+:2033C0009DE803009047012808BF0A2502E00C2500E0092528467CBDD4DB0020F8B50546E0
+:2033E0000C46122005F079F8071C1ED000211222FBF7ACFA7C203870002078702188B980B7
+:20340000A17AB973267B014606B1012139740146E07A00B101210822B81DF973A11C05F066
+:2034200039FFE8B2394600F037F9F8BD7CB5124C024620680E460025D8B1C169C9B1072139
+:203440008DF800100223ADF80230ADF80420026A72B19DE80300904750B12068C4699DE8E9
+:20346000030041223346A047012808BF0A2500E0092528467CBDC046F8FD002030B500248E
+:203480000822ADF1240D214605A88DF81C40FBF75DFA05A807A96A46FBF7DAF905469DF843
+:2034A0001C0078B1684621461422FBF74FFAFF20294614226B468DF81000042003F0C2F866
+:2034C000204600E0012009B030BD98B5437B0A460021042B1ED1077CE7B94769D7B138783A
+:2034E00010F0030F16D150687C7B437DA34211D112887B899A420DD1C288BB889A4209D102
+:203500008278BB789A4204D0007800F00C00042800D10121084698BD30B50C466068ADF1FB
+:20352000140DD8B1007800280CBF3B253A25616848788DF80000887820B90DF1010003F0DE
+:2035400095FB05E00DF10100C91C102205F0A2FE284611216A4606F057FD00E002206070DF
+:2035600005B0012030BD000038B5104C15466269E368A488A13816D0401E0AD0401E02D07B
+:2035800008380BD038BD0A48006868B18047044609E04AB108462946904738BD28461946FD
+:2035A00006F0FAFD38BD2C8038BDC046AC00012004030120E0B5061C1FD0062004F08DFF41
+:2035C00007460E480568C7B1384600210622FBF7BDF9C521397000237B703178F97071785C
+:2035E0003971B178281C797103D1384605F05CF8E0BD0079394600F04FF8E0BD2C1A002060
+:203600001149C8B570310A684E6D410806D302F0010106F0040600270E4300D001278108F6
+:2036200005D3002117B1930828BF01210F46C00805D3002017B1D10828BF01200746002FEB
+:2036400014BF01200220C8BDD020084038B5491D04468DB2294604F0E7FF20F002002946F1
+:203660000246204605F0DAFA0A480C21493014FB0105287860B12046022104F0D5FF20F0B4
+:20368000030002210246204605F0C8FA0020287038BDC0465CFC0020F8B505460F1C08BF8A
+:2036A00005201CD00E4C2078C0B1241D14F8181F8D4211D104F03EFD0646394604F108006A
+:2036C00003F042FD28464FF40041FEF76BFA304606F013F80020F8BD401EE7D10320F8BD32
+:2036E000501A0020042870B51ED1104D05F5AC70064606F067FAB8B106F0BAFB0446304616
+:2037000006F056FD6043B0F5967F0DD2304606F055FD052003F0EAF92846012180F8311022
+:203720000421E03006F070FD002070BD30F5002098B5114C0146323C94F82C000727C0B9A1
+:203740000846B4F8481002F063FF011C11D094F83100012807D1887804F0F2FE497881429F
+:20376000A8BF081C02E0887804F0EAFE071C08BF0727384698BDC04616FB002070B50E4665
+:20378000044606F023FDA16805463046B1B1A2692369216802FB0311F8F7A8F92069A1684A
+:2037A0006368401C491EB0FBF3F2A1605A43801A2061284606F094FEA06870BD284606F0A3
+:2037C0008FFE4FF0FF3070BDFEB5104D6C682079F6F77AF906F0FAFC2E680746307880B934
+:2037E000684606F00FFAA079094A0190617900956B46301D01F0CEFC01203070284605F0D3
+:20380000B5FA384606F06CFE2846FEBDE0C30200ABA0020010B5002104461822ADF1180DD3
+:2038200021726846FBF792F80B226846214605F031FD08220DF10B0004F10B0105F02AFD16
+:20384000A08AADF81400A07D8DF8160003480068D0F81C126846884706B010BD14010020EF
+:2038600030B5054610484830048800213C22ADF13C0D6846FBF76AF802208DF80C00ADF8FC
+:2038800000508DF808003121ADF80A400DF10E0004F0A4F803480068D0F8881268468847DC
+:2038A0000FB030BD14010020E4FA0020114A80B557680146002F08BF012019D0384643686A
+:2038C0001B78994206D100685060384601F064F9002080BD076857B17A681278914204BFE9
+:2038E00039680160F1D038463F68002FF4D1022080BDC04620050120114980B501F13F027F
+:203900001278120928BF012017D2FF2804D1FF200A490870002080BD70B1F1280CDACF6877
+:2039200057B179680A78904203D03F68002FF8D102E04F78002FEBD1022080BDDC020120E6
+:203940004CFF0020F8B506460F4D104F7388002417E0A20002EBC402921951689068D26847
+:2039600052B9AF420BD00A7855F822200346491C08461946904701E0F8F7B8F87388641C32
+:20398000A4B2A342E5DCF8BD50C902005CC9020010B5ADF1180D05F0F5FC012801D106F0D5
+:2039A000D9FA00208DF802008DF80400029001218DF80310074C60706846EDF7E7F90649D4
+:2039C00020790870FF232371E12001F025FE06B010BDC0462004012020FB00202DE9F041BB
+:2039E0000F4E00254FF6FF70B570DFF8388035702C46F080B368F57009E008EB84073868CF
+:203A000018B104F051FEB3683D60641CE4B2002CF3D01BB1284601460A469847BDE8F08117
+:203A2000200401205819002010B506F0CFFB0C49097879B90B49097861B90B49097849B95D
+:203A40000A49097831B90A49097831F0020108BF012400D0002406F043FD204610BDC04661
+:203A600005140120071401200A1401200014012006140120114980B50B68071C1DD0181CDB
+:203A80000DD00022874204D0024640680028F9D105E0834219BF406850604068086038681E
+:203AA000006A01F079F8386801F076F8786908B101F072F8384601F06FF880BD38050120D5
+:203AC000F8B504F037FB104900252F463E462C46CB68486012E0110809D21FB914461D46D4
+:203AE00001270AE02968A4188918296005E082F000420027B44288BF261C9B181A68002A9F
+:203B0000E9D105F0FAFDF8BD501A002090B5114C2468ADF1240DBCB1276AAFB101248DF8BB
+:203B200018400424ADF81A400024ADF81C400091019202930C9A039206AB049093E803002A
+:203B400022461423B84708B10A2000E0204609B090BDC046FCDB00202DE9F04114460D46A7
+:203B600005F070FA9846071C08D03B7C00204FF00C0C01E0401CC0B2834202DC0020BDE8C8
+:203B8000F0817A6910FB0CF1565AB542F2D189188A889442EED107C988E807000120BDE80A
+:203BA000F081000010B583899A0002EBC3020E4B1B1D1B6801291A44144618BF02290AD1A4
+:203BC0004288022962800BD1001D04F02DFF08B90020207004E0121D011D104606F0F0F81F
+:203BE000204606F039F910BD3005012010B5104CA41EA07888B10120207004F0F5FDA17830
+:203C0000FF290ED00020094BA07018784FF47A724A43802106F09FFA03E00020207004F017
+:203C2000E3FD4120214601F0F7FC10BDE4FA0020360401200E49086820F0020040F408704D
+:203C400008600C48032140F8041C41F230018160012101605022826001604FF4CA6282605E
+:203C600001604FF48652826001600348016070470000046058600440004104402DE9FC47E4
+:203C80000F4C8046606900271D4692460E46B94608B1804758B157B904200090E06806EBFF
+:203CA00048312B46524606F0A7F8814600E00B27B9F1000F48BF01273846BDE8FC87C04680
+:203CC0005CFC00202DE9F0410746B86840681C460D4690462919884238BF6FF0030010D33D
+:203CE000094E30684FF0FF3105F011FF3846294642462346FAF76EFD0446306806F07CFAD9
+:203D00002046BDE8F081C046A81301200E4A98B512780F460446012A01D003F0C9FA0B4872
+:203D20000078A0420CDD07B9064F09480C2114FB01F140588069394602462046904798BDD2
+:203D4000002098BD18C40200090601204CBF020070C102000F49A1F1240000688008FAD3D5
+:203D60000D48001F0068012819BF0122111C20210122074840F8251C002340F83D3C0823EB
+:203D8000C0F8FB3FC0F8FF3F40F83D2C7047C0463D400C407C600C405016002098B506F023
+:203DA00015FA0446F9F756FA0D480021001D0170032002F083FE204606F092FB074CA0688C
+:203DC0000146022088470746102001F0C3FF1FB1A06801460320884798BDC046FCC1020050
+:203DE0004416002070B50E4615460446082300212422ADF1280D684606F02EFB0020069043
+:203E00000590ADF81000084800684FF47A71AAB26B46B1FBF0F080B231464243204606F04F
+:203E2000D7FA20460AB070BD40C40200F8B5104C074604F1080005680E46281C09D00179B3
+:203E40008F4202D1C1888E4210D0054600680028F5D10820F8F7FEFE40B10771C680002141
+:203E60000160A16800290CBFA0602860F8BDC04698FD002038B50178012914BF0025082537
+:203E8000411C8078012814BF082009200B78C0F16C00C4B22BB1052005F044FA241A0D3CAF
+:203EA000E4B20548007820B105F03CFA241A0E3CE4B2641BE0B238BD14FB002002461048B8
+:203EC000F8B5801F06780D46CEB1001D4FF6FF7310F8141F4C0810D30DB1890809D2C78887
+:203EE0003FB1BB4205D0018989188F42A8BF8FB20781017801F0FD010170761EE8D1F8BDF9
+:203F0000F60C01200F4910B50446C87808B1886B10B90020C870486B04F0B4FF0A480068F6
+:203F200038B9012C14BF052003200021E4F76AFB10BD012C14BF012100216420E0F7CAFFB3
+:203F400010BDC0464CFF0020E4FE0020C8B50F480F490278CF68FF2A0F610ED177B17868C4
+:203F600006781EB1F12E01DA46786EB93F68002F0F61F4D102E03F680F610FB90020C8BDA4
+:203F8000786803789A42F6D1C8BDC046DC0201204CFF00201FB54FF6FE71814219D00E4AA2
+:203FA000042300245178012903D011B95188884205D05B1E02F10E0204F10104F2D1042C45
+:203FC00007D1ADF80C00042168468DF8001002F0E5FC00901FBDC0466C010020B0B54FF07A
+:203FE0008054D4F8D8010E4D80680146284688472A1D116804F5EC74C7B241F0300111601C
+:2040000067B1206840680021024628469047206880680146284688470028F8D13846B0BDDA
+:2040200000400340BCB50546FEF782FA002818BF4FF0FF3017D10C4CC72021888DF800000E
+:20404000284605F040FD68460121FFF7AFF821880746284605F040FD002F18BF381C02D190
+:204060002846FEF765FABCBDA4130120104810B50078ADF1780D042815D0082813D000242D
+:2040800090B9212003F050FB74280DD12120214674226B4605F0A0FC30B99DF8260004288E
+:2040A00018BF082800D1012420461EB010BDC0462EFB0020104A98B5D768C7B10D48006898
+:2040C00000690078FF2810D03B7883420DDC7978C918814209DD79681778C01AC0B20C56FE
+:2040E000F81AC0B20856844201D0012098BD002098BDC046180100207000012070B505461C
+:2041000006F064F80E4C2268D2F8D810D2F8F82406462846904730B92268D2F8DC10D2F84D
+:20412000F824284690472068E83001680968A94202D1D0F8F0038047304606F0D1F970BD01
+:204140001401002038B504460D46142004F0C5F9011C0BD00C2008708C7000248C730A4BAA
+:204160004D701878FFF798FA204638BD204604F007FF38B106214173007B02F0CFFC20464D
+:20418000FAF730F9102038BDE4FA0020F8B5064614460D46162004F0A0F9071C19D000214C
+:2041A0001622FAF7D3FB4820387000237B70BD802088A11C0822F88007F1080005F06AF84F
+:2041C000A07A07F1100103F0F4FBF0B23946FFF763FAF8BDD0B504460C2004F07EF90746FE
+:2041E0000D480668BFB1384600210C22FAF7AEFBCC20387000237B706088F8802088B88043
+:2042000020793872A079B872607978721EB130793946FFF741FAD0BD2C1A002098B505F0F8
+:20422000D5FF0446F9F716F80028FBD0032002F045FC0A4900200870204606F051F9084C34
+:20424000A0680146022088470746102001F082FD1FB1A06801460320884798BD481600204D
+:20426000FCC1020098B5426802F00301012919D1D10817D20C4903680F681C7D97B13979F2
+:204280008C4203D03F68002FF9D10BE0B96849B19B88212B06D1120938BF002003D3F2F7A0
+:2042A0001DFF98BD012098BD74040120B0B505460C460E2004F011F9071C19D000210E22F3
+:2042C000FAF744FBE52000233870294608227B70B81DBC8004F0DEFFF22004F0FDFD18B9A7
+:2042E000384604F0E1F9B0BD00793946FFF7D4F9B0BD38B50546297D032905D002291AD1E8
+:20430000808905F0E9FE03E005F10C0005F014FF041C10D0687860B1F12818BFE12804D10C
+:20432000A079012801D105F063FFA07918B1401E00E00020A07138BD90B50F1C4FF0000419
+:20434000ADF1340D18D00168086AA8B1C97F6A46F1F7B2F97888BDF80C1088420CD19DF8CA
+:204360000200012808D10A980178012904D139788078814208BF012420460DB090BDB0B5F2
+:20438000054668886C68410828BF002019D2401C80B205F081FF071C12D0688840103870E3
+:2043A00000200AE06278217807EB4005431CA41CD8B201EB0221A5F8011039788142F1DCA2
+:2043C0003846B0BDF8B505460C460C2004F085F807460C480668A7B1384600210C22FAF7E6
+:2043E000B5FACB21397000237B703C72301C7D6003D1384604F058F9F8BD00793946FFF75A
+:204400004BF9F8BD2C1A00200E4870B50168D8310868006810B94868006888B105F0D6FE95
+:2044200006460948001D056802F0A4F80446304606F056F8641CA5428CBF281B012070BD80
+:20444000002070BD14010020E000002010B504460E48ADF1180D047005F0B6FF002115223C
+:204460006846FAF773FA152102A22346684604F097FEFEE75B417373657274205265617359
+:204480006F6E5D2030782530325800C0C8E800200F4908B5D1F878020B68020F03F0FF03DA
+:2044A0007F2B88BF002304F081FB01464FF0FF3004290CD11146012908D9891E03D0491E76
+:2044C00005D1153300E00B3358B208BD0A2008BDA01000502DE9F041876878681D460C4617
+:2044E00090466119884238BF6FF003000FD3094E30684FF0FF3105F00AFB396840462A4678
+:204500000919F7F7F3FA306805F076FE0020BDE8F081C0469413012010B50E4C20784FF49F
+:20452000805100F019FB88B90B48C27C407E012814BF032101210020F0F7CAFB20784FF42D
+:2045400080514FF47A7205F006FE10BD0120E07010BDC046E4FA0020ACFE0020B0B505F02F
+:2045600035FE05460B48017801290FD00A49024601230878137048B1084C0746206880681C
+:204580000146204688470C347F1EF7D1284605F0A7FFB0BD0A06012050BF02005CC3020021
+:2045A00010B5ADF1280DFAF7BFFA00248220182221466B4605F010FA88B906A8214610221A
+:2045C000FAF7C4F90DF1010006A9102204F05CF828B9684621461822FAF7B8F901242046A8
+:2045E0000AB010BD3EB50E4D0C462C7224B9287810B9032004F0D2FE5035296851B1094860
+:204600008DF80040428FADF80220C08FADF80400684688470220002102F0F8FA3EBDC046A0
+:2046200034FD0020E4FA0020F8B50F4C054660681E46174605F0B0FD62680020012F107211
+:2046400004D16168087A40F040000872012E03D1117A41F080011172204629463422092336
+:20466000FCF75CFAF8BDC04698FD0020F8B50F4C06AF6568D7F800E08446184603E01EF827
+:20468000016B05F8016B0646701E002EC0B2F6D13F79002F07BF0025281C40200025E07019
+:2046A0006046FCF73BFAE570F8BDC04698FD002038B5562003F038F8002808BF012015D0EC
+:2046C0001624B0FBF4F0C5B2284603F069FB012808BF02200AD014FB05F0054CE36882B215
+:2046E0000021562005F078F90020A57038BDC046F00C01202DE9F84306460E48401C90F899
+:2047000000905FEA030814460D4610D0A01CC0B203F0E3FE071C0AD0B81C2246414604F072
+:20472000B9FD3E70484639467D70FEF7B5FFBDE8F883C0464CFF00200F4B10B51C78844268
+:2047400018DD142410FB0430FF294FF0000400F11800048108D0012919BF017801F0FE01B1
+:20476000017841F001010170FF2A03D0017841F00201017010BDC046F00C012098B50E4C6B
+:20478000071C03D12068D0F84C05804705F01EFD0A4A1178B943117005F0A2FEFEF72EFD9B
+:2047A0006068C068007828B92068D0F8582400200146904798BDC0461401002006140120DB
+:2047C00098B50E4C083CA06800F1400319680F6837B9D0F84C058047A3684033186807687D
+:2047E000074810300068044605F0CEF8F860204604F08EFB19680968088298BD140100207C
+:20480000DCFF002010B504462168086AADF1380DA8B1C97F01AAF0F74FFF0A48BDF80E100A
+:204820003A30008888420AD0206800889DF821200090BDF810004FF6FE73FEF73FFC0EB003
+:2048400010BDC046E4FA0020F8B516460C46054601F0C4FE071C16D000211C22FAF776F867
+:204860003D80002E7C8106BF0120B874BE7406480078012818BF072002D1304603F060FE85
+:20488000787406203874F8BD74FB002038B50F4C0D463A3CB4F8481001F0BAFE011C10D05B
+:2048A000887803F04DFE497859B150B194F83120012A02D18142B8BF011C081C01D0854200
+:2048C00001DA002038BD012038BDC0461EFB00200E4A014608B5042002F07EFF01F00EFCA9
+:2048E000022005F0D7F9032005F0D4F90848006850B14FF6F772131DC1881140C180194021
+:20490000C18000680028F7D1002008BD057802002C1A0020F8B507467D68002616E0606970
+:20492000C5F8C8006068666110F0704F06D128B1062002F0C3F8042002F0C0F8022002F03F
+:20494000BDF8D5F8BC20384621469047D5F8C840002CE4D1F8BDF8B5064614460D46082004
+:2049600003F0BBFD071C16D000210822F9F7EEFFE020387000237B703E717D71F220FC807A
+:2049800004F0AAFA18B9384603F08EFEF8BD00793946FEF781FEF8BD10B50446207DA0B9D6
+:2049A0002046F0F795FF206918B10A48016820468847207D20B9E068E7F75EF9207504E068
+:2049C000E06800F0E9F80020E060204605F040FB10BDC04678020120D0B50446042003F074
+:2049E0007CFD07460B4806689FB1384600210422F9F7ACFFC621397000237B70301CFC702A
+:204A000003D1384603F050FED0BD00793946FEF743FED0BD2C1A0020F0B515460E460446B7
+:204A20001F1CADF1240D08BF00230DD0684600212422082305F010FD3B78ADF81030B868AB
+:204A400006907A6805926B46204631462A4605F0BFFC204609B0F0BDB0B50C460546171C98
+:204A6000ADF1280D08BF00220DD0684600212422082305F0F1FCB8683B7806907968ADF88C
+:204A800010306A460591034B2846214605F0E0FC0AB0B0BD6003012038B504460D46084619
+:204AA000FDF7DCF80C28A8BF4FF6FE7011DA094901EBC001487849686160207030B1421EF3
+:204AC00001EB4001627031F8020C38BD00206070284638BDF40100204FF6F87280B500213E
+:204AE000801A03280BD9001F07D0401E03D0801E0ED1012704E0022702E0042700E0082718
+:204B000004480078074202D107B1012100E00221084680BDEDFB00200E4938B58A68CD68DA
+:204B20001B3800FB00F482FB04234443C5FB04234C68C4FB002312091807024308681B1170
+:204B4000C11780184FEA104041EB03010904084338BDC0469402012070B50C46064603F06C
+:204B6000E9FA05462146304603F0BEFE002808BF00240AD0006802F089FA064909684FF4AE
+:204B80007A72B2FBF1F1B0FBF1F4284604F0B5FD204670BD40C40200B0B5071C19D003F0F9
+:204BA000C9FA0C4948604C690B6957F8042C15080BD322F000428D6847F8042C9B183F1FC9
+:204BC0000B61AF4238BF8F6001E0641C4C6104F094FDB0BD501A002070B505F0F7FA0646B1
+:204BE0000C48001D007850B108480068C0680546074800243C2101222346A84700B101247F
+:204C0000304605F06DFC204670BDC046A401001000A00C404416002070B504460C480668DB
+:204C20000C4800682568006B8047801B000B2060A84202D240194008206040F6C411814226
+:204C400004D3B0F5967F02D24FF49671216070BD38F500208C01001070B500260D460D4B17
+:204C6000467134461E202A7B13F8011F8A4204D0401E04F10104F7D102E02846FAF7BCF840
+:204C80001E2C06D106202C686873607B3146FFF759FA70BD4D010020F8B505F097FA0D499F
+:204CA0000B4FCA680C684B680D698E6882EA92024C60ED19CE6082EA42028B6082EA0412D8
+:204CC0000D6154400C6005F00BFC28460019F8BDC587050008130120C8B50E4601460A4837
+:204CE0000778002077B1094A12788A420ADD06B9074E084A0C2011FB00200168C9680A46B5
+:204D000031469047C8BDC0460A06012050BF020088C002005CC302003EB505460EE06A6A0D
+:204D2000AC6AA41A082C28BF0824E869694680182246F6F7DBFE686A00196862A86A696AF8
+:204D4000884206D903486946FEF718FDB0F1FF3FE5D13EBD081201203EB504460C486D4697
+:204D6000016840682960002C686014BF201C684604F018FF04B12546064C2946204605F0A1
+:204D80000BFA71200821224605F03EF93EBDC04604C10200F8FE00200E4830B50468ADF19D
+:204DA000140DA4B100252079A11D12228DF800000DF1020004F06EFA2946082014226B466E
+:204DC00001F040FC24686B1CDDB2002CEBD105B030BDC0461C03012070B5041C0D46ADF1FE
+:204DE000180D09D045B1FAF741FF064604F1100005F086F8B04201D002200BE001A80090C1
+:204E00002246902300200146E9F7ACFB01A82946F4F784FC06B070BD7CB50E4C0125032649
+:204E200001288DF80050E17984F83E600BD0032904DB606A01F09AFA002001E0491CC8B2EB
+:204E4000E071294600E0002130462A466B46FFF751FC7CBD4CFF00200FB40E4890B500684D
+:204E600003AFADF1040D78B13C7801680A78944207D1BA888B889A4203D17A8849888A42B7
+:204E800003D040680028F0D1002001B0BDE8904004B07047040D012038B50E4C024604F147
+:204EA00014000068A0B182420DD00146886801E00146886860B159B18242F9D182688A60B8
+:204EC00003F0F2FB38BD8568606903F0EDFB656138BDC0464819002010B56FF001000C49B0
+:204EE0000C4C08702068D0F8E800006878B16068C068012101702068D0F8DC04804705F0AA
+:204F000065F905F0EDFA6168C9680020087010BD0D0501201401002008B50346104604F040
+:204F2000A9FA012907D00121022A01FA03F120EA010007D109E00121022A01FA03F141EA5C
+:204F4000000002D00249086008BD0249086008BDB81001209412012038B50D480D4C0168DB
+:204F60000A48083C056860682A1A2078800092FBF0F0D1F8D420527BD1F8EC1051F82210D3
+:204F800000F04AF80846656038BDC0461000012014010020E00000200E4870B50068E83070
+:204FA000016809680A4C4D6804F108010968A94202D8D0F86404804705F008F90646E5605A
+:204FC0002846F9F78FF9304605F08AFA70BDC046D8000020140100202DE9F0410D4C4FF6B7
+:204FE000FF7705463226A7F101081C3C34F81C0F854203D0AF4208D1804506D0A01C03F09A
+:2050000013FD10B9204604F0BCF8761EEED1BDE8F081C0466C0800201CB50A1C17D00023A5
+:205020000124E407A04238BF041C944201D95200FBE790425B41904228BF801A914201D21C
+:205040005208F6E7191C021C081C111C1CBD00B1C843F4F722F91CBD98B50C4604F032FF3D
+:20506000002700B101270B4A18329069211AB1F1004F08D8011B891DC90F05D1801DA0429D
+:2050800088BF041C00E0841D14600FB904F020FF98BDC04600200940F8B505F091F90028C1
+:2050A00008BF002013D00A480768002F0DDD0948046800250020294604F0ACFC0646B068DB
+:2050C000A0476D1C7F1E7060F4D14FF0FF30F8BD20C4020038C402000E4B90B51B680024E2
+:2050E000ADF1140D93B15F6987B107238DF808300223ADF80A30ADF80C000B4602A8009284
+:2051000003C82246B847012808BF0A24204605B090BDC046F8FD0020F8B5064634681746CA
+:205120000D4605F053F894F8251021B105F0D8F94FF0FF30F8BD012184F8251005F0D0F9CF
+:2051400028680FC80C3484E80F003A4630462946EDF7AAFEF8BD9EB50090171C01914FF0A0
+:2051600000008DF8080010D00346009A01999C5C595C9DF808207F1E03F1010381EA0401D6
+:2051800042EA01028DF80820EFD19DF8087007B901209EBDF0B514460D4606461F1CADF1B3
+:2051A000340D08BF00230DD0684600213022082305F002F97B680893386805903A7AADF89F
+:2051C00018206B4630462946224600F06FFB0DB0F0BD98B50446617820784018F7F73AFD50
+:2051E000071C13D022780021F9F7B0FB4FF6FE70788004F05BFEB8802078C0193861607841
+:20520000387502F04FFF7875A0783876384698BD00F003028A70C0F38302CA70C0F3811274
+:205220000A71C0F340228A71C0F300224A71C0F380224A77C0F3C022CA71C0F300320A720C
+:20524000C0F3403281F831208013C0B270472DE9F84316468846044602F06CFF276881462B
+:20526000002005462FB100E0401C57F80C7C002FFAD1864204D92046414601F065FF0125C9
+:20528000484604F03AFA2846BDE8F88398B503680021D9629F690FB10221397093F8301057
+:2052A00002290DD001290FD19A692AB91C69D96ADA699B6AA04798BDDC68D96AA04798BDE7
+:2052C00003F1340004F098FF98BDB0B500F02AFB071C18D0002410E007EBC400401C0546D0
+:2052E00004F02AFF38B10079012818BF022802D12846FDF77FFB641CE4B23878A042EBDCE7
+:205300003846FFF749FCB0BDB0B505461446102003F0E3F8071C15D000211022F9F716FB03
+:205320009520387000237B702088A11C0822B88007F1080003F0AEFF60893946F880E8B221
+:20534000FEF7AAF9B0BD000038B50C4CE168054699B1206988B1606978B16888884760B999
+:2053600007490A6868889101A1EB820122699047012802D161696888884738BDECFB0020F7
+:205380006CBC0200C8B5032003F0A7F807460B48066897B1384600210322F9F7D7FACA21EB
+:2053A00000233970301C7B7003D1384603F07CF9C8BD00793946FEF76FF9C8BD2C1A00206B
+:2053C00010F1240F00F1240103DB1C28A8BF3F2100E00021032001F00F030F22A0EB211086
+:2053E000C3F10F0102414FF6FF7343FA01F0024B40EA02401860704718A00C4038B50B4C91
+:20540000207888B10A4D287860B1022806D0012804D008480068D0F84C0580470020287066
+:2054200004F01CF80020207038BDC046041401200B06012014010020F8B54FF0805706460A
+:2054400007F5EC7420680A4D81682846884700F003003060D7F8D8014268002128469047B0
+:2054600020688168284688470028F9D1F8BDC046004003402DE9F0410C4D0646287800249E
+:20548000182705F11C080CE014FB07814A68964205D1C8684FF0FF3105F01AF82878641C0A
+:2054A000E4B2A042F0DCBDE8F081C046501A00200D4B70B50D4606460824B3F93000854217
+:2054C0000BD13046194604F0BDFB30B11AB193F83300024201D0184670BD641E03F1580394
+:2054E000EBD1002070BDC04678F70020F8B51C461546074604F06AFE9FB107F1280106C9BB
+:2055000007F1280307F120062943224383E8060096E8060007F120030D4344EA020683E878
+:20552000600004F0DDFFF8BD10B50446C8090AD2204604F0D1FD20B1007901280CD0022829
+:205540000AD0204610BD2146FF2001F0B9FF002808BF4FF6FE7001D00148008810BDC046F8
+:205560001EFB002038B5044603F064FE0146A01C03F03EFDA51C012809D10848016811B1F6
+:205580002046884748B9E07AF4F772FD38BD2088A27AE37A2946F1F749FC38BD88FD0020D5
+:2055A00030B5054600211822ADF11C0D6846F9F7CDF900240620214618226B46FDF768F845
+:2055C00038B9012D05D10620214618226B4601F039F8641C032CEDDB07B030BD38B50D4CDB
+:2055E000083CA068D0F8C81301208847054600208DF80000A068D0F83024694656209047BC
+:20560000A0680349D0F83024E2209047284638BD18DC00201401002038B505460C46E22DFC
+:2056200002D1094804F0B8FD522D05D1207818B907481C38007830B104480068D0F8302413
+:2056400021462846904738BD18DC002014010020D7FE0020F8B5044667680D464FB12678B4
+:205660003EB128883968098888420FD07F68761EF8D10820F7F7EEFA40B1056061684160AE
+:2056800060602078401C20700020F8BD0120F8BD08B5002101288DF800100FD00A4AD07804
+:2056A00040B1506B30B1D17003F0ECFB322003F06BFB08BD0320E2F7A5FF08BD0320012227
+:2056C0006B46FFF717F808BD4CFF00202DE9F843DFF83080164607460425002418F80E0FE9
+:2056E000874209D1404602F0A3FD28B1A642D8BF404604DD641CE4B26D1EEFD10020BDE80A
+:20570000F883C0465E0100200D4B10B51B6801EA03048C4218BF6FF0040010D1806840687E
+:20572000884298BF6FF0030009D98918884202D31340934202D06FF0050010BD002010BDAC
+:205740009C1301200D480021001F01700748084900680988D0F8D420D184D0F8D400054ADE
+:20576000C18C11800449C08C088070471401002072000120220001203E1900206C11012053
+:20578000F8B50F1C044616D00B4E0025786831680019E83178600A681268BA4202D100281D
+:2057A00048BF7D607868002802D5D1F8640480473F68002FEAD1F8BD1401002098B50D4C0D
+:2057C000A168D1F8B80007789FB1C7698FB1086C0268D06D28B102210023B847A168086C4A
+:2057E0000268106E28B1D1F8B810CC6900230821A04798BD0C010020F8B504460C480768B3
+:20580000AFB100260625386801888C420CD13E817989C90803D3387B01F080F938687D73EE
+:20582000407BF021FEF78EFC7F68002FEBD1F8BD3805012030B50D4C2468ADF1140D94B16A
+:20584000E46984B101258DF80850ADF80A00ADF80C10089D009502AD95E80300A0470128DA
+:2058600018BF002000D10A2005B030BDFCDB0020B0B505460C46102002F02FFE071C14D045
+:2058800000211022F9F762F87720387000237B702088B880207AB87161680822F81D03F080
+:2058A000F9FCE8B23946FDF7F7FEB0BDF8B507460A480B4C0668E0698D00285886420AD17A
+:2058C00008480090384604F073FDE0692858864218BF381C00D10020F8BDC04674AC02007C
+:2058E000501700206003012090B51C785B7803AFADF1240D8DF821308DF8204000230093FF
+:205900003B78019301230293BC8803943C7A04940224059408AC069407930B23EAF7C8FCE4
+:2059200009B090BDF8B58469C08948F21F01814208BF641C2778F800401CF7F78BF9061C93
+:205940000BD0751C377047B1641C2846214604F023FC083408357F1EF7D13046F8BD08B50E
+:2059600010200DF102018DF802005A20FFF754FE4FF4FA706946ADF800005520FFF74CFEF7
+:2059800003200DF103018DF803005920FFF744FE092003F03FFA08BD10B543689B6801EA31
+:2059A00003048C4218BF6FF0040011D180684068884298BF6FF003000AD98918884203D3BF
+:2059C00002EA0300904202D06FF0050010BD002010BD2DE9FF410A9F984614460D46064640
+:2059E00001ABFEF7B9F870B1039828B1404601A93A4601F05FFF06E00097304629462246F7
+:205A0000434601F05BFB0090BDE8FF817CB50C4D0646002401E0641CE4B2E878A042D8BF37
+:205A2000FF200BDDE86861036A46042304F024FB009800F0FF008642EDD120467CBDC0460F
+:205A40005CFC00200C4880B50168886800E0384647681FB101F13802BA42F8D1407B10F063
+:205A60000F0006D1498F40F60900884208BF012000D0002080BDC04634F50020B0B504464C
+:205A8000242002F02AFD0746094805787FB1322038702078B87060687860A1681B2207F1C6
+:205AA000080003F0F7FB28463946FDF7F5FDB0BDE80001203EB515460F220B4C8DF808202D
+:205AC0004FF6FD72ADF800206268107000125070901C04F061FB606813220B236946857264
+:205AE0002046FBF71BF83EBD98FD00202DE9F0411D4616468846044604F0D4F8071C0FD0AB
+:205B0000062002F0EAFC011C0AD0FD2008704D708C708E8081F8038078680078FDF7BCFD33
+:205B2000BDE8F081C8B5FE294FF0000608BF0126094A17686FB1FA88904207D1002E18BF55
+:205B4000387907D13A798A4208BF01263F68002FF1D1FE20C8BDC0461C03012003460C4831
+:205B6000D0B5C7688FB186787EB1163F002017F8164FA34205D17C88A14202D1BC88A2427E
+:205B800004D0761E00F10100F1D1FF20D0BDC046F00C01201CB500200B4C8DF80000042029
+:205BA0008DF801000120A0716846F8F7D7F960784FF48051FCF7B4FB60784FF4805141F213
+:205BC000883204F0C8FA1CBD4CFF00201CB50C4C84F821106178012803D000200121A07113
+:205BE00007E008464FF48051FCF79AFB002184F8441001206B460246FEF77CFD1CBDC0467C
+:205C00004CFF00200C4A80B5121F5768034603F0F5FB0628A8BF00200DDA384600E008462A
+:205C200010B101680029FAD10021002819600CBF53600360012080BD2C1A002038B5846806
+:205C4000456894F8380001F0DBFA94F8390001F0D7FA94F83A0001F0D3FA95F8F900012853
+:205C600003D095F8FB00FF2803D095F8FB0001F0C7FA38BD70B50B4C30B1401E18BF0020EE
+:205C80000DD1074D641C00E0074D2078411C06462170A8470028F8D1002EF6D0304670BDD5
+:205CA000C1A1020049190020A18E020038B50C46054600F05FFC0A49A04204D20846026835
+:205CC0002046DC3205E008460268DC3250680068001968601168D2F810242846904738BDF3
+:205CE000140100200C4808388268D2F8D820002111608268D2F8DC2011608268D2F8E020C8
+:205D00004FF4700313608268D2F8E42013608068D0F8E8000160704714010020094908B53B
+:205D2000012008700A488638006818B10649088B401C0883F02000F0B5FB04480078E8F76D
+:205D400035F908BDFC1301208C1101204D0201203E19002098B504460B48006888B10746A3
+:205D6000B86804420AD0F8683A690021034620469847002818BF4FF0FF3003D13F68002F1A
+:205D8000EED1002098BDC0461015002010B50C1CADF1380D13D001466A462046EFF78CFC06
+:205DA0009DF8060058B19DF801209DF81C300020214603F0C3FA002818BFA42000D10020BD
+:205DC0000EB010BD38B50C4C0D4694F8961081420EDA00F0ADF907482146058091F82B201E
+:205DE0000878642313FB02F24FF4007104F0B3F938BDC046F2FB0020E4FA002010B50C4629
+:205E000001461022ADF1200D684603F0E7FF04A804F05EF910200790CDF810D004A904485B
+:205E200005940068069404F084F908B010BDC0460CDC00202DE9F0410F46044603F0E0FD0D
+:205E400004F1280292E8600033462A46F6F7E6F980460B4642462846314603F077FB17B1E3
+:205E6000303484E803004046BDE8F08170B5049D012A4FF000001E4602D9911E10D070BD88
+:205E8000012908BF012011290BD10024204631462A46E4F7AFF918B9641C052CF6DB70BD66
+:205EA000012070BD7CB515460446E8791E46800812D3204602F066FB78B9204603F06AFFE0
+:205EC000041C08BFC12008D000200090A988288802223346A0477CBD88207CBD1FB50124FA
+:205EE0008DF80C400AB9062B11DB03290FD0002112226B46FDF730FE20B103A86946002271
+:205F000001F0D8FC9DF80C100020012900D1204600901FBDF8B5064614460D46182004F04C
+:205F2000BBF9094B1A6970B1002101600671816005741F69446117B91861F8BD0A4611686E
+:205F40000029FBD11060F8BD80030120F8B5064614460D460C2004F09FF9094A916868B1C0
+:205F60000023036086809768C580846017B99060F8BD11460A68002AFBD10860F8BDC04616
+:205F80008003012038B50C4605460021012203206B468DF8001003F01FFD70B9FF2D19BFEA
+:205FA0009DF80000A0439DF80000204301216A468DF80000032004F027F838BD024610781F
+:205FC00000280CBF00200120517809B140F00200917809B140F00400D17809B140F00800A6
+:205FE000117909B140F04000517909B140F080007047F8B54568066804F0E8F80746307871
+:2060000070B1287903F094FF012806D1286800244460301D04F0D8F834702879F3F75EFA48
+:20602000384604F05DFAF8BD10B50024ADF1180D01A800902146002214230820FFF7FAFB2A
+:2060400040B99DF80400FF2804D00DF106010022F9F7F0FA641C102CEADB06B010BD014667
+:2060600000B50420ADF1140D8DF80000087A022806D001A803F0A4FE6846FAF747FB05E07D
+:206080000888ADF802006846F8F79AFCBDF80C0005B000BD0A4938B5402205680A6080204A
+:2060A00008600024C1F8FC4295F8260020B1054804F0A2F885F82640022000F0FFFC38BD19
+:2060C00004440240B80E01207CB50B4C0026354600940220314600220E23FFF7ABFB20B931
+:2060E0002078FF281CBF6D1CADB2761C0E34042EEEDB28467CBDC0466C01002010B50A4CFA
+:20610000606820B16068FEF747FD0020606002F04BFC064CE06A30B14168E162FEF73CFD35
+:20612000E06A0028F8D110BD34040120ECFB002030B50B4C0546ADF1140D083C6A4684F841
+:20614000965014342046FBF7F9FE68468DF81250FBF742F845202146FFF75EFA05B030BD45
+:20616000ECFA00200A46014610B5101C0ED069B1074A0323C2F88437D2F88C3713F0030F0B
+:20618000FAD1044C012323601160906010BDC046044002400000484210B50A4941F8980C04
+:2061A00008684FF0805440F003000860D4F8B80181692020884704480068D4F8B801806B1F
+:2061C000804710BD242208402C20094038B514460546042211FB02F21846091D02F0FC02DC
+:2061E0008DF800208AB22946FCF782FC02460121684603F073FE84420CBF0020022038BD9A
+:2062000010B5FEF7ABF9012001F0AAF8044603F0DDFF074A116831B104F062F934B120460D
+:2062200003F092FE10BD146004F05AF910BDC046A813012038B5044603F0C8FF0849054617
+:206240000878A04308700878000904D205480821E03003F0D9FF284604F042F938BDC0461B
+:20626000FD13012030F50020F8B516460F46044603F0ACFF05460848001D0068A04205D18A
+:206280003846314601F02AF8044600E00324284604F026F92046F8BD30F500200C2838B5A3
+:2062A00012DA002808BF00240CD0921E0346002403F0FCFD32F8025FA84203D05B1E04F144
+:2062C0000104F5D1A14201D0002038BD012038BD0B49891F8A7992080ED3084A12788242FA
+:2062E0000AD00846017901F0F80141F0020101710C21817101F0E8BE7047C046BAFE002021
+:20630000E61201203EB50225ADF80000094B8DF808505C6804F8010B001204F8010B184630
+:2063200004F8011B0423694622700122FAF7F6FB3EBDC04698FD002002460B48B0B50778A3
+:20634000FF237FB1183000244578AA4202D14588A94206D07F1E00F1140004F10104F3D115
+:2063600000E023461846B0BDF00C01200B4A10B5536A0146181C05D0814205D004468069FA
+:206380000028F9D1022010BD834219BF8169A16199695162FEF700FC002010BD4CFF002095
+:2063A000BCB50B4C0546AB2021888DF80000284603F089FB01216846FCF7F8FE218807463D
+:2063C000284603F089FB17B92846FCF7B1F8BCBDA41301207CB5054609480A4C0078218869
+:2063E0008DF80000284603F06EFB01216846FCF7DDFE21880646284603F06EFB30467CBD42
+:206400004BC20200A4130120F8B50646151C41F00C0006AF18BF40F0400076B1397B3A7AA3
+:206420003C793D7840F0800042EA410244EA420445EA840243EAC2023270F8BD10B5044653
+:206440000C22ADF1200D214601A803F027F9207B082204F110018DF8100005A803F01EF909
+:20646000207E8DF81C006846EBF70EFD08B010BD80280BDC012803D0032818BF802801D1B6
+:2064800001207047022805D1022070478428B8BF042006DB842801DB862801DB002070473A
+:2064A0000320704738B50546EA2D12DBF42D10DA084C083CA068D0F8282469462846904713
+:2064C0000098A368401C0090D3F8302469462846904738BD1401002010B5094C94F9000049
+:2064E00010F1020F0BD00848064B4238006894F90010826B186890476FF00100207010BD8E
+:206500000D05012080000120220001200A4808B50068D0F8B800007800280CBF01200020C1
+:2065200000F00EF8054991F9000018B191F90000401E087008BDC04614010020140501202A
+:2065400038B5054603F042FE044600210220FAF7ADFD074800688369044800684FF0FF31E2
+:206560002A469847204603F0BBFF38BD80000120E0FF002038B503F029FE0546084800681A
+:20658000084CC06B8047083C6168401A21788900B0FBF1F4284603F0A3FF204638BDC04638
+:2065A000E0FF0020E00000200A4908B5888B401C888303F00BFE08490A78862A02D003F00E
+:2065C0008FFF08BD87220A7003F08AFFE920F6F72BFD08BD4C0201200A1401204FF6FE7085
+:2065E00038B5411C01F074F8011C0DD1074C3225A07C08B1607C18B9208800F0A7FA21462D
+:206600006D1E04F11C04F3D1084638BD6C08002038B505460A480E3000880C46A04206D1E4
+:20662000284603F059FD002818BF083007D12846214601F04DF8002814BF1030002038BD39
+:206640001EFB0020BCB50B4D2F68002487B17F6977B101258DF80050ADF80200ADF80410DA
+:206660009DE80300B84718B10A280CBF09240A242046BCBDFCDB00200B4910B5096849B118
+:206680000B7C002201E0521CD2B2934204DC09680029F5D1002010BD01EBC204E47EA04286
+:2066A000F1D1084610BDC0464405012038B5B1F1FF3F044608BF05212020EFF3118580F35E
+:2066C00011880120054B61618840A061586903F06BFEA06285F3118838BDC046E4160020E0
+:2066E00044280BD0432809D0422803D0412801D0F6F726BD0878401C80B270474A780878C1
+:2067000000EB022081B2881C80B28142C8BF4FF6FF707047B0B544684088401EC7B2F81CEA
+:2067200080B203F0B9FD70B121788770017057B1641C3946002214F8013B8518491E02F1F4
+:206740000102EB70F7D1B0BD30B50D4601460024ADF1140D01A88DF8004003F031FB684609
+:20676000F9F7D4FFBDF802104FF6FE72204629808A4218BF012005B030BD38B50E20F6F75D
+:2067800069FA041C10D0FF210E22F8F7DFF80025022029460E222346FBF77AFF6D1C042D0C
+:2067A000F6DB2046FEF7F8F9002038BD70B516460C46054601F0BEFC2968A14219BF54F846
+:2067C0000C1C46F80C1C54F80C1C2960002144F80C1CFF2104F8021C02F08FFF70BDF8B515
+:2067E0008C46071C164611D000245EB13CF814109A1E304632F8025F8D4208BF012006D096
+:20680000401EF7D17F1E04F10104EED10020F8BDF8B5846914F8016BA0780546801DF6F728
+:2068200019FA071C0BD03E70617820782A4600EB01207880E11C781D3D7102F02BFD3846DC
+:20684000F8BD10B5FF211422ADF1180D6846F8F77DF800240820214614226B46FBF718FFF0
+:206860000A2808BF0A2003D0641C102CF2DB002006B010BDB0B505460C46082001F02DFEB0
+:20688000071C0FD000210822F8F760F87A203870207878706088B880A0883946F880E8B2C9
+:2068A000FCF7FAFEB0BD70B5044604F128020CCA0846002102F04AFE04F1300292E8600072
+:2068C0002D1846EB0106290C30040143FEF7C4FB383484E8600070BD10B5044603F060FD16
+:2068E000034603E0184603F057FD03469C4208D0986803F0C5FC9042F4DA184603F096FB92
+:2069000010BD204603F08CFD10BD38B51446E2791D46920810D3224601F034FE68B9A079B4
+:20692000D5F80310FFF7DCFE0246D5F80310A06802F0B4FE002038BD882038BD0A4980B599
+:206940000A1D1768874209D057B1F968884202D00F1CFAD104E0C168F96001E0FA684A60A1
+:20696000FEF71AF980BDC046DC04012038B50C46054602F05FFC0146284602F039FB0128F0
+:2069800004D028462146FFF7DFFE38BD024800882080012038BDC0461EFB002038B5044688
+:2069A00001F082F80546012D0CD10748A28903682478910001EBC2015A5CC818A2435A542C
+:2069C00003F04AFA284638BD340501200A4908B51420F9F715FC1420002103F00BF9012011
+:2069E00003F0B0FB1420012103F004F94FF40C7003F0A8FB08BDC0460162002038B50A46D3
+:206A00000C460546002102F009F907490C39487840B97C2C08BF81F833500C2015FB0010BF
+:206A200080F8464038BDC04668FC0020F8B50A4C054620680E4617464FF0FF3103F067F891
+:206A4000284631463A46FBF765F90546206803F0D3FB2846F8BDC04694130120F8B50A4CF9
+:206A6000054620680E4617464FF0FF3103F04FF8284631463A46F3F783F80546206803F059
+:206A8000BBFB2846F8BDC046A81301200EB509490A68917969B913680749C268096831B140
+:206AA0000193029240788DF8000068468847FFF725FB0EBD38040120FC00012010B504468A
+:206AC00003F084FB084B1A1992F84311491EC9B282F8431121B99A680121A1408A439A608A
+:206AE00003F0FEFC002010BD1015002038B5044603F06CFB084A02F108031D680121A1400E
+:206B0000A4182943196094F84311491C84F8431103F0E6FC002038BD10150020094B10B577
+:206B20001E21002213F8014FA04204D0491E02F10102F7D110BD00201870034941F82200A2
+:206B400010BDC0464D010020540200200A4938B5962203254FF6FE748B795B0807D24B8894
+:206B6000984204D14B79012B04BF4D714C80521E01F10801F0D138BDBC0300200748006872
+:206B8000400909D20748064B074A016803EA9120824208BF012000D000207047B04F005037
+:206BA000F1FF0F0050130050F00107001CB54FF08054D4F8CC014068014602208847D4F802
+:206BC000CC1100904868014601208847019002486946FCF735F81CBD08120120C8B50F46D1
+:206BE000016887B17E6876B13A78042A0BD1BE684EB100224A628F617A68CA61BA688A622D
+:206C0000F2F7CCFCC8BD6FF00200C8BDF8B50446094805780E46022001F05FFC071C09D0D5
+:206C20001EB13146022202F035FB3C7028463946FCF732FDF8BDC0463BFD00200A4A98B559
+:206C40000021176801606FB1BF1F03224FF6FE7437F8063F9C4203D107600846387198BD80
+:206C6000521EF5D1C82098BD60FE002010B504461022ADF1200D04A9684603F0A8F80648DB
+:206C800000686946FFF7AAFF01991022204602F001FB08B010BDC04610DC00200A4980B5FF
+:206CA0000A884FF47A714A43904294BF101A00200022B0FBF1F34B43C71A18BF0122B0FB53
+:206CC000F1F0121890B280BDF60C012010B5094C641E60788021FDF73FFF50B9607880213E
+:206CE000FBF71EFB04480021C180FF21417001F0BBFD10BD4DFF0020F00C012080B5071CB3
+:206D000014BF80210021074B188F4FF67F7202401143054A08431887117867F3C7111170A4
+:206D200080BDC046DCFF002024190020094810B500240470FFF7EAFBF9F758FF06494868E9
+:206D4000C068007828B90868D0F8582420460146904710BD061401201401002010B50A4C22
+:206D60006068C068007828B92068D0F8582400210120904703F02AFA03F0B2FB2068D0F8DE
+:206D8000B800806E804710BD1401002008B503F01DFA084A517841F00201517003F0A0FB1F
+:206DA00005480068D0F8940000780021FAF7FAFE08BDC046D80000201401002038B5044611
+:206DC00009480068D0F8D85003F000FA296831B1A14208BF012403D009680029F8D1002481
+:206DE00003F07EFB204638BD14010020F8B5061C0D464FF000040CD0074807684FB138461A
+:206E00002946B047012803D07F68002FF7D100E03C462046F8BDC0463805012038B5094D0E
+:206E20003224284602F0ADF91C35641EF9D106494FF6FE73002203204B80401E01F8042BBE
+:206E4000FAD138BD6C08002028FC0020F8B5147806460D46082001F040FB071C0DD000214D
+:206E60000822F7F773FD6C20387000237B703946BD80F0B2BC71FCF70FFCF8BDF8B51478D1
+:206E800006460D46082001F028FB071C0DD000210822F7F75BFD6B20387000237B703946C6
+:206EA000BD80F0B2BC71FCF7F7FBF8BDF8B5147806460D46082001F010FB071C0DD000210F
+:206EC0000822F7F743FD7220387000237B703946BD80F0B2BC71FCF7DFFBF8BDF8B51478CC
+:206EE00006460D46082001F0F8FA071C0DD000210822F7F72BFD7420387000237B703946BE
+:206F0000BD80F0B2BC71FCF7C7FBF8BD2DE9F0410546094807681C4690460E4657B1B868F5
+:206F20002840854203D1387931464246A0473F68002FF4D1BDE8F0812C1A0020F8B5147867
+:206F400006460D46082001F0C8FA071C0DD000210822F7F7FBFC6D20387000237B703946C5
+:206F6000BD80F0B2BC71FCF797FBF8BD10B503F00FFA03F061FA032003F006FA0648103018
+:206F8000006830B1034C204602F0F0FF204602F0F3FF10BD67420100C016002008B503F0AB
+:206FA0000FFA012801D003F0EBF9074803F0E4F901F0F2F903F0DCF903F0D6F903F0D0F9B6
+:206FC00003F0CAF908BDC0466D6F0200084910B5002008600120C861064C2060216844F8D3
+:206FE000280C05480068016A14208847206810BD000024432C200940B001001030B500251E
+:20700000ADF1240D0848009502AA01930B46294603F09EF9041C03D002A902F0BBFA254682
+:20702000284609B030BDC046A8C0020030B503460025ADF1240D0848009502AA0191294618
+:2070400003F086F9041C03D002A902F0A3FA2546284609B030BDC046A8C0020030B5002598
+:20706000ADF1240D0848009502AA01930B46294603F06EF9041C03D002A902F097FA254676
+:20708000284609B030BDC046C8C0020038B50446EFF31185202080F31188A08A012809D124
+:2070A00003F022FAE168A368081A834203D22169814200D2002085F3118838BD2DE9FC4119
+:2070C000089F984615460E4602F064FE04460FB1002038803CB10097304629460122434631
+:2070E000A047BDE8FC81C120BDE8FC8110B5041C09D1002484B9214605201022FCF746F974
+:20710000641CA4B2F6E721780520102201F07F01FCF73CF90020207010BD98B5044601F02E
+:2071200009F82168002908BF002709D051F80C2C002322600F4641F80C3CFF2401F8024C6F
+:2071400002F0DBFA384698BD38B50C46054600F0F1FF6CB1002144F80C1C296811B92C60A2
+:2071600006E0114651F80C2C002AFAD141F80C4C02F0C3FA38BD38B50C46054603F026F88C
+:2071800022680346002442B12846114602F05AFD00B114461268002AF6D1184603F0A0F997
+:2071A000204638BD00B51022ADF1140D8DF8001001460DF1010002F06DF83B2011216A465F
+:2071C00002F022FF002111226846F7F7BFFB05B000BD00000346094810B5001D006858B193
+:2071E000C479A34205D18488A14202D18479A24203D0C0680028F3D1002010BDDC0401201F
+:2072000010B5044601F0FEFF07480838006850F824102046F8F7F4FF0021204601F0FEFF41
+:20722000204602F0DFFC10BDDCC2020038B50C46054602F0CBFF0749891C01EB85010A787F
+:20724000C4F3024322F007021A430A7003F048F938BDC0460010084070B5094D95F88A40E7
+:2072600064B102F00EFF4FF47A7600F07F0016FB040228784FF4807102F06AFF70BDC046DF
+:20728000E4FA002010B5202918BF6FF0010009D141688368044A4C681B8C146003490B6069
+:2072A000FCF7C0FE10BDC046A0130120A4130120074898B5007838B1064C074654F80C0B9F
+:2072C000006980477F1EF9D103490120087098BD4CBF020070C102000906012010B50C4656
+:2072E000084924310978022918BF012009D100F00FFF04B1206000F0FF0001280CBF8120B3
+:20730000022010BD30F50020094A38B503460824002084325588AB4202D11578A94205D0C4
+:20732000641E02F10A0200F10100F3D138BDC0462001002030B50D460446242208230021C6
+:20734000ADF1240D684603F0BBF8012029466A468DF81800204603F0AFF8204609B030BD21
+:2073600010B50446002124220823ADF1280D684603F0A6F8044A012069468DF81800204639
+:2073800002F0E2FF0AB010BD60030120074810B5002407490460032008600220FFF78EFBF7
+:2073A0000820F2F79BF80348047010BDA8025042108002400506012010B5002000F02AFE66
+:2073C00002F074FD044601F035FF01460448027800232046FEF76EFB002000F01BFE10BDF1
+:2073E000E612012038B5094C0146E07850B1C87840B9487830B90448002505800120FBF7A7
+:20740000EFF8E57038BDC04678FB0020E80001208CB58DF800000848001D0068027004AFD9
+:2074200043701A1282700022C2703A8804236846F9F774FB8CBDC04698FD00201FB51446FF
+:207440000222ADF8020001A88DF8002002F0B8FC6846EEF7C1FA012814BFC8200020BDF866
+:207460000C10218000901FBD98B5094B00221F680A6057B1BF1F032337F8064FA04204BFFA
+:207480000F60101C02D05B1EF6D1C82098BDC04660FE002010B5074C207838B9064807493F
+:2074A0004FF4B472F4F722FB0120207001F0F8FA10BDC0460C0601204C400021A0AF0200C3
+:2074C000094A10B512686AB11379984218BFFF2805D1931D1C88A14208BF181C03D0126846
+:2074E000002AF1D1002010BD1C03012010B5094C00203E3C207060784021FAF711FF00F005
+:2075000021F860784FF48041FAF70AFF0B2002F0D9FB10BD8AFF0020094A92F8421088421C
+:2075200002D1917801290AD001281CBF002182F83F10423210700121552002F065BD704727
+:207540004CFF0020F8B5094C606968B104F114050026286800F11407FDF71EFB2E603D46EE
+:2075600028680028F5D16661F8BDC0464CFF002038B5094C0546B92021888DF8000028469E
+:2075800002F0A1FA01216846FBF710FE2188284602F0A2FA38BDC046A4130120094A10B5FE
+:2075A000ADF1180D009100240290114608680194694602F075FD002814BF201C4FF0FF30AD
+:2075C00006B010BDA013012038B50D464FF6FF712A46ADF800104121FDF77EFD041C05D173
+:2075E00028466946022201F0B5FA08B9204638BD0D2038BD80B5071C04D107480068D0F8C0
+:207600004C05804702F0E2FD044A1178B943117002F066FF80BDC046140100200614012023
+:2076200010B5041C04D107480068D0F84C05804702F0CCFD044A11780C43147002F050FF53
+:2076400010BDC0461401002006140120084838B50068D0F8E000046802F0B8FD05460548EF
+:2076600004602046F5F74AFF284602F039FF38BD14010020E000002038B5094C0546E06A72
+:2076800028B101888D420AD040680028F9D10820F5F7E0FAE16A10B105804160E06238BDEE
+:2076A000ECFB002080B5071C12BF78680748006850B14289120B04D339B102681288914282
+:2076C00003D040680028F4D1002080BD38050120094A38B532234FF6FF7532F81C4FA042C2
+:2076E00005D15489A14214BF8D42101C02D05B1EF3D1002038BDC0465008002002460948EB
+:2077000038B5002132234FF6FE7430F81C5FAC4203D08A4204D0491CC9B25B1EF5D100200C
+:2077200038BDC046500800200EB5094909680346002061B18A6A52B101218DF80010ADF882
+:207740000200ADF804309DE80300904780B20EBDFCDB0020F8B5057C002301E05B1CDBB2C5
+:207760009D42D8BF00200ADDDE0084191B342778B942F3D1617880190A4316306270F8BDD8
+:20778000027A0B7A93420CD15AB1022A07D1098800880022814208BF012210467047032A05
+:2077A00001D00020704701F023BC7047B0B514780546042000F091FE071C0CD00021042275
+:2077C000F7F7C4F896200023387039467B70E8B2FC70FBF761FFB0BDF8B504460848076899
+:2077E00016460D4657B1F8882040844203D116B138792946B0473F68002FF4D1F8BDC04624
+:207800002C1A0020B0B50C780546042000F065FE071C0CD000210422F7F798F878200023D8
+:20782000387039467B70E8B2FC70FBF735FFB0BD08602E2088800020888102A088600846DE
+:207840007047C0467B756E6B6E6F776E2D696E7374616E63652D6E616D657D000860322059
+:2078600088800020888102A0886008467047C0467B756E6B6E6F776E2D696E7374616E639A
+:20788000652D6E616D657D0038B52020EFF3118580F31188064CA068002102F051FD616902
+:2078A000081AA169814238BF002085F3118838BD80160020B0B50B4699681746054600297E
+:2078C00008BF01200BD09879FEF70AFF996804460246284601F0E2FE07B13C800020B0BD03
+:2078E000F8B516460D46044602F070FC024629463046086043684B60476807B92746396024
+:207900004160104602F0ECFDF8BD10B5041C0FD0207A022818BF03280AD12046F5F7F8FA37
+:20792000FF2805D0227A0021FDF7F6FA002010BDE82010BD00B5817EADF1340D8DF81210AE
+:20794000C27E8DF813204188ADF80A108188427DADF80C106846ECF7B9FA0DB000BD70B53B
+:2079600014460E460546002201F0D6F9FF280AD02B2E19BF40F22B2141EA8421A10241F0D8
+:207980002B0145F8201070BD1FB50C46014602208DF8000001A802F013FA6846F8F7B6FE14
+:2079A000012814BFC8200020BDF80C10218000901FBD420824BF01220A70820824BF01228B
+:2079C0004A70C20824BF01228A70020924BF0122CA70C00924BF0120087170474A0824BFA6
+:2079E00001220270CA0824BF012242704A0924BF0122C2708A0924BF01220271490A24BF9B
+:207A00000121C171704710F15A0F05DB10F1140FC8BF6FF0130001E06FF05900332141F2D4
+:207A2000EE120E2310FB012191FBF3F0C0B27047C8B507460748466857B116B9476004E027
+:207A40000646F0680028FBD1F760B9710020F860C8BDC046DC04012038B5458940684478EA
+:207A6000062000F03AFD01460448007829B108220A704D800C71FBF70FFE38BD3BFD00209A
+:207A8000044805494160054981600549C16005490161704770020120C9D900005DF901001A
+:207AA0009D910200559700000146084B89891A8800208A4208DD8A0002EBC1025968895CAB
+:207AC00011F00F0F18BF01207047C046300501200849091F088850B149680C3911F80C2F38
+:207AE00012F00F0F08BF002002D0401EF6D101207047C0463405012038B5084C0022332397
+:207B00002579A84203DCA942A4BF521CD2B25B1E04F12404F4D1104638BDC046E40D002001
+:207B2000084933220B79052B05DA002808BF081C06D0401E80B2521E01F12401F2D1002029
+:207B40007047C046E40D002070B5084C04EB800425680E4602F03AFB05F0FF053146A94208
+:207B600018BF217002F0BCFC70BDC0460010084038B50C4601466BB1091F002051F8045FD2
+:207B8000B5F1FF3F06D01540AC4204D05B1E00F10100F3D1FF2038BD084910B5087860B12A
+:207BA00039310246002311F80C4FFE2C08BF181C03D0521E03F10103F5D110BD5FFC00201E
+:207BC0001CB55B1C8DF802109624ADF8002099008DF803406A46042389B2FCF74FF8014950
+:207BE00008701CBD5DFC002010B5044610460A46211C08D038B1C8608A6004480B6100F04E
+:207C0000BDF9002010BD6FF0020010BD1015002038B50D460446F7F781FF05F57A71241A33
+:207C2000A008814234BFB0F1405F002003D2401B012898BF012038BD084900B54422ADF1B6
+:207C4000440D6846F3F752FF01208DF83E008DF83F00684601F05CFE11B000BDD4BD020038
+:207C60000849074809780078890803D24FF48071F9F798BF4FF4807140F6C41202F06BBA33
+:207C80003BFD002016FB002010B50446062000F024FC011C09D031200870208848806088FF
+:207CA000024B88801878FBF7F7FC10BDE800012000B5ADF1140D0DF10E01FFF765FE48B949
+:207CC00002208DF80000BDF80E30ADF80C306846FEF764FE05B000BDE22808B505D1064AC5
+:207CE0000846114602F058FA08BD044A1268D2F82824904708BDC04618DC0020140100200D
+:207D000010B5FF211422ADF1180D6846F6F71EFE00240820214614226B46FEF793FC641C30
+:207D2000102CF6DB06B010BD38B51546074A12781C4652B1FEF700FBFF2806D0012D14BF3D
+:207D4000012100212246FCF7F7FC38BDF00C0120084A1432126852B11388994204D1537A53
+:207D6000984208BF101C03D05269002AF4D100207047C0464CFF002001280AD00749C878DE
+:207D800028B1486B18B10020C870FCF7BBB8002100E001210520E0F735BCC0464CFF00204F
+:207DA00010B568B1074C1621E07011FB00F0F4F751FF0021E0600028A17008BF012000D082
+:207DC000002010BDF00C01200168084603E0D1F88C0006E08268C268D208FBD20222C0F82D
+:207DE0008020C8684008F2D30020C1F88000704710B5041C04D106480068D0F84C05804746
+:207E0000044801780C430470F8F724FF10BDC0461401002006140120084A014603235088EE
+:207E2000814204D11078002818BF012004D15B1E02F10402F3D100207047C04628FC0020D6
+:207E400070B50748074C322506886089864202D0204601F096F96D1E04F11C04F5D170BD7A
+:207E60002CFB00206C08002038B50446074801882046FFF72DFC0D4638B101F082F9204685
+:207E80002946FFF725FC0028F7D138BD2CFB002038B5084D69682C6824EA010028600C40A6
+:207EA000E00901D3F5F7E6FA200A01D3FCF7B6F9AC6038BD9022084010B5084C38B106484E
+:207EC00000684068012102462046001F9047206820F03000206010BDD80100100440034047
+:207EE000B0B514780546042000F0F7FA071C0AD000210422F6F72AFD942039463870E8B274
+:207F0000FC70FBF7C9FBB0BDFEB5002516460F46ADF8045001F03EFF041C06D001A82A4613
+:207F20000090314613463846A047BDF80400FEBD0EB5014648894A68ADF8000050788DF889
+:207F4000020092788DF8082008B9487A10B16846EFF7ACFF0EBD1FB50C460021ADF802002C
+:207F600068468DF80010F6F72BFD01A9204601F027FF204600F058FD00901FBD38B50D462B
+:207F8000044602F023F900212A462346116059685160596801B921460A605A6002F0A0FA1A
+:207FA00038BD38B50C46054602F010F900212B4622461C6851601460196801B929464A6050
+:207FC0001A6002F08DFA38BD38B50D46044602F0FDF82A46116801B9214653684B6051681F
+:207FE00001B9214612680A6002F07AFA38BD1CB50024032001216A468DF8004001F0FEFF84
+:2080000028B90320214601226B4601F0E5FC9DF800001CBD074A917828B90120D0700846F7
+:208020000221FAF77DB90023D37002460846022102F091B8AC000120428913090CD392086F
+:2080400008D3427B062A05D0E92903D0CD2918BFF02901D1F0F746BB0020704708B502F078
+:208060003BF8002808BF002009D0017931B1032904DA8169C161012380F82030012008BDA1
+:208080001FB5FF210E226846F6F760FC0024022021460E226B46FEF7D5FA641C042CF6DBF2
+:2080A00000901FBD38B5074B9C782546681CC4B29C70284600F064FF0028F6D1002DF4D0EF
+:2080C000284638BDECFB00200648017808092CBF03200120890828BF40F0040002490870C0
+:2080E0007047C046E6120120EDFB0020054808B50068426801200146904703480349006848
+:20810000086008BDE001001030200940AC02012007490246083908680028FCD10023CB614C
+:208120000A60C8690028FCD0CB6148687047C0460810044010B502F07FF9064980B2000407
+:208140002140040C0C4302F041F880B260F31F44204610BD0000FFFF0749082291F83300E5
+:2081600030F07F0008BF081C04D0521E01F15801F4D100207047C04678F700200A46064916
+:2081800010B54B683BB18968084204D003490C6801462046984710BD50C3020034F50020F5
+:2081A00010B50C460021FDF7BFF92146F7F720F938B14FF6FE710180418000240471447140
+:2081C000847110BD10B5074CE41F207220B9207810B9062001F0E2F8E0792021F9F7E2FC9D
+:2081E00010BDC0463BFD0020024607480168486800E0486803789A4204D0096808680028E0
+:20820000F7D100207047C04658FF002010B5074C606918B1FCF7C0FC00206061E06918B1F6
+:20822000FCF7BAFC0020E06110BDC046DC02012010B530B14379002201E0521CD2B2934236
+:2082400001DC002010BD00EB4204E488A142F4D1012010BD064A1068002818BF012006D162
+:20826000044940200860012348600020D361704704800C4038500C40064902680B390A6007
+:2082800042684A60044902680A390A60406848607047C046220001203E19002006490020F0
+:2082A00008700648001D00680069FF2202704FF0FF308861486170477000012014010020FA
+:2082C00010B504460B2C01DB1A2C04DD04480068D0F84C0580470148047010BD1A190020E4
+:2082E000140100200649487840F00400487005480068D0F8940000780021F9F753BCC0469F
+:20830000D80000201401002038B50D460446FEF731F94019606004480268D2F8D810D2F83C
+:20832000EC242046904738BD1401002010B50346002A08BF00200AD05B1E491E11F8014F94
+:2083400013F8010F844201D1521EF7D1001B10BD024607480168002041B14B7B9A4212BFC5
+:20836000FF2A401CC0B249680029F6D17047C04638050120074910B5322200204FF6FE730B
+:208380001C3131F81C4BA3421CBF401C80B2521EF7D110BD50080020074808B51030006881
+:2083A00028B1034801F0E2FD024801F0E5FD08BDC98902007D950200C0160020074810B575
+:2083C0001030006830B1044C204601F0CFFD204601F0D2FD10BDC046EFA50100C01600201D
+:2083E000074908B5283090E80C000020F3F716FF002908BFB0F1FF3F88BF4FF0FF3008BD2C
+:20840000907E000038B505460024064A0448009429684FF0FF3301F08FFF2C6038BDC046BA
+:20842000A8C00200059D020038B505460024064A0448009429684FF0FF3301F07DFF2C60A7
+:2084400038BDC046C8C00200159D020007480078022807D0062803D0052806D001F0BEB8B0
+:20846000062000E00220E7F70BBB70474D020120074A01460523506820B10078884208BFB7
+:20848000107804D05B1E02F10802F4D10020704700FE0020074B10B501460522586810B14A
+:2084A00004788C4204D0521E03F10803F6D1002010BDC04600FE002038B5054601F086FEAA
+:2084C0002C6834B121682960216801B9294600224A6002F005F8204638BD10B5041C04D090
+:2084E00004F10C00F4F7B6FB08B9002010BD002101600481FF2383720C3010BD38B5846930
+:208500000D466178207800EB0120A41C28802146A81C01F041FE14F8080FA87238BD08B5D9
+:208520000B4600F085FC20B93220187001225A7008BD00F10C010222184600F0ABFE08BD36
+:208540000C28C8BF01200BDC0628C8BF032007DC0228C8BF052003DC002814BF07200020A6
+:2085600070473EB50546002108226846F6F7EEF92846694600F03CFD0024012818BF0124AA
+:2085800020463EBD38B514460D46E179890908D301F0F0FB031C04D0284621460222984772
+:2085A00038BD002038BD000038B5064D0024022021460E222B46FEF745F8641C0E35042CFE
+:2085C000F5DB38BD6C010020F8B516460D46044601F0FAFE074629463246204601F0DFFD53
+:2085E000384601F07DFFF8BD012814BF00200120044B03491A78087060F345121A7070470E
+:20860000240001202419002038B53821017001258570FCF7DEFD041C04D02570A57700F083
+:2086200009FE6062204638BD064A08B5126801EB4031012310466A4601F01EFD9DF8000067
+:2086400008BDC04668FC002010B54FF6FF700C46A04205D0EEF702FB0249E0B2F7F7D0FDCF
+:2086600010BDC0460160002038B5064D0524AD1C2846FF210422F6F769F92D1D641EF7D1DD
+:2086800038BDC0462001002010B5401E491E4AB111F8013F10F8014FA34218BF002002D1C9
+:2086A000521EF5D1012010BD08B5002808BF052009D010F8021CFF2918BF042003D10C388B
+:2086C000FCF76AFA002008BD38B5054601F07EFD044604482946FFF777FC204601F000FFF6
+:2086E00038BDC046101500200648054A816A8A4203D0E030042101F087BDF7F7B7BDC04641
+:20870000F95E000030F5002008B54FF0FF3001F087F8800805D303484FF40061E03001F0D2
+:2087200073FD08BD30F50020064A92F824100020022906D1D2F8A81019B9D2F8AC1001B9FB
+:208740000120704730F5002005480068400838BF002003D303480068C0F3C0107047C0461F
+:2087600040210840000004403EB50446A0686A46EFF718FE0546832D04D169462046002214
+:20878000FDF772FD28463EBD10B5044600F022FD40B9204601F0A0FC08B1007910B14FF6CB
+:2087A000FE7010BD204610BD38B5064C0546E0790421FCF7D1F920B9E0792A46042101F0CE
+:2087C000CAFC38BD34FD002008B501F05AFC42F2107210401218034800784FF4804101F0A1
+:2087E000BAFC08BD3BFD0020054808B500788DF800000448016809B16846884708BDC046E8
+:208800003604012090FD00200346064810B544682170091261701946A27003230422F8F71F
+:208820007DF910BD98FD00201CB50C46002121606946FFF7A9F828B9BDF800002146FEF743
+:2088400013FE1CBDC8201CBD10B50446087A2072087A03281CBF0888208002D1204601F068
+:208860009BFC0020608110BD06490548891D007809884FF47A724A43802101F06CBCC046CC
+:208880004DFF0020F00C0120491E012202FA01F18BB211460022034218BF0A4349005B1004
+:2088A00089B2F8D1104670470649042300200E3911F80E2FFF2A02D04A79101880B25B1EF3
+:2088C000F6D170476C0100200346104610B51A4630B1044B11F8014B62409A5C401EF9D184
+:2088E000104610BD08B1020002460648006800E0006928B103799A42FAD183689942F7D1C9
+:208900007047C0468804012005480EB50068436C0448006802216A4698479DF800000EBD00
+:20892000E0FF002080000120054808B5001D0068016C0448103000688847FFF764F808BDC1
+:20894000DCFF00207000012005490878832805D10020087003490870F0F780BE7047C046FE
+:208960000514012007140120002812BF40680548006828B1427B914203D040680028F9D155
+:208980000020704738050120064A936EC00B07D3104600F1580211609A4204BF00218166F3
+:2089A0007047C046ECFB002038B5064C04F10800006820B18569FCF7EFF8281CFAD1002087
+:2089C000A06038BDE4FA002010B5064C206901F0AFFC0146A06800B9E160A068401CA060BB
+:2089E00010BDC046C0160020054808B54168054801220838026048698969884708BDC046AC
+:208A0000841700200C200940064B1A69090907D31946886142F00203C8680B6101F0F0BCAE
+:208A20007047C0467CFB0020011C4FF0000308D01A46885C08B101230822521CD2B2082A3C
+:208A4000F7DB18467047022908BF017806D0C2780178837801EB026101EB0341407801EB1D
+:208A60000020704702294FF0000204D0012808BF4FF47A7203E0012808BF40F2EE22104655
+:208A8000704780B5074608464FB1437801787F1E00F1020001EB032122F8021BF5D180BD41
+:208AA0004FF00451002081F82004012081F86004022081F86A04032081F87804704710B5CA
+:208AC000FF2122220446F5F741FF00211F2204F12200F5F73BFF0020A07210BD402807DBD4
+:208AE0006528B8BF403806DBE02801DBF92801DBFF2070474530C0B2704710B5041C09D006
+:208B000001F0B6F94FF47A716143B1FBF0F000B9012010BD002010BD08B50420FFF718FCD8
+:208B2000062804DAFF20FFF713FC0C2801DD012008BD002008BD10B54468032001F0ACFBFC
+:208B400038B16278217801EB0221018014F8021F817010BD10B5401E491E11F8013F10F863
+:208B6000014FA34218BF002002D1521EF5D1012010BD0000054808B500784FF48071FBF72A
+:208B8000EBFF08B9FFF76CF808BDC0463BFD00200549C0310968012303FA00F200200A427E
+:208BA00018BF181C7047C04600200240054800684BF641310001B1EB104F14BF4FF0FF30E6
+:208BC000042070471813005008B5044B1B689B699847034A0021116008BDC046A80100106A
+:208BE00084046042044908B5096849698847034A0021116008BDC046A801001084046042C2
+:208C0000034605480068491C890089B201EB4331042301F031BAC04668FC002008B501235F
+:208C20008DF800206A46FBF729F80249491C087008BDC0465CFC0020806802680A604068FD
+:208C4000034A4860106800F00F0080028860704730240340054808B5006800F058FF00280F
+:208C600014BF6FF00200002008BDC04694130120054808B5006800F04AFF002814BF6FF008
+:208C80000200002008BDC046A81301200549B1F89400401CA1F8940080B210B90120F9F7EB
+:208CA0009FBC7047E4FA002008B501F0C5FB0349086001F06DFB0249086008BDE01301209D
+:208CC000DC130120044808B5006801F0C9FB0348006801F0A1FB08BDDC130120E013012035
+:208CE0004FF0FF3181600022026002710274027742771146C1604161816170470548B0F9DC
+:208D0000B610B0F9B400814202D10820FDF792BA7047C04630F5002038B51446054650232B
+:208D200040F2FF32FEF724FF1CB155F82010890A216038BD054908B56A46FDF795FA81287E
+:208D40000CBF9DF902006FF07F0008BD0100030410B5044601F03AFA03490A7814430C7030
+:208D600001F0BEFB10BDC046FD13012040684FF0FF330168034ACB6201688A60006801216C
+:208D800041607047001800200549097818B908460121F8F707BF02460846012101F0DBB941
+:208DA0003BFD0020054808B500784FF48071FBF7D3FE08B9FEF754FF08BDC0463BFD0020B6
+:208DC00005490839B1F89220904203D0A1F89200FFF7E8BF7047C046ECFA00200EB5ADF811
+:208DE00000000448019101688DF8082009B1684688470EBD78FD00200346054810B54468E1
+:208E000021700912617019460223F7F787FE10BD98FD002008B58DF8000004480068D0F89E
+:208E200030246946E020904708BDC0461401002001460548006830B142681278914202D0A2
+:208E400000680028F8D17047240501200EB54FF6FC70B4210122ADF800000F208DF80800EB
+:208E60006846F9F70DFB0EBD10B5054CE06828B1E068FBF791FE0020A070E06010BDC0463E
+:208E8000F00C0120044A054910600C3108608420042101F0B9B8C046E4FE002034FD002080
+:208EA000014605481430006828B10279914202D080680028F9D170474819002001460548D3
+:208EC000006828B10279914203D000680028F9D1002070472C1A002001460548006828B1C4
+:208EE000027B914203D000680028F9D1002070472C1A00200023038031F8012B02F0FF02CA
+:208F0000134303800988090643EA11430380704705494A680978801A8A00B0FBF2F1514356
+:208F2000401A80B27047C046D8000020054991F900004FF08073401C087000200246014663
+:208F4000F5F710BA120501200448002101700448007808B9F0F782BB7047C04607140120A3
+:208F6000051401200A684AB1904203D1106808600120704711461268002AF5D10020704754
+:208F800001460548006828B1027B914203D040680028F9D1002070473805012040B1054BC9
+:208FA00033F8022F914208BF012002D0401EF7D10020704734010020054808300068D0F8C1
+:208FC000B800007808B900F005B8F7F70FBEC0460C0100200448002101700448007808B9A2
+:208FE000F0F73CBB7047C046051401200714012010B5082211F8013B10F8014BA34218BF1C
+:20900000002002D1521EF5D1012010BD0F2808D9044B1038012100F01F024009914043F802
+:209020002010704780E200E0054B10B5044601F07BF9A06800280CBF0020201C10BDC04619
+:209040006003012001460548006828B10279914203D000680028F9D10020704790030120B1
+:2090600001460548006828B10279914203D000680028F9D1002070478C03012008B501F06B
+:2090800007F940B1002A07BF817801F0BF01817841F04001817008BD1CB50C466946FFF75C
+:2090A000C3FB002806BF009840884FF6FF7020801CBD0EB500908DF8041000208DF80500E2
+:2090C0008DF806006846F8F7A5FA0EBD38B50D460446EDF791FF4FF6FD700D2221462B4647
+:2090E000F5F73EFF38BD28B1401E082210F8013F994201D000207047521EF7D10120704716
+:20910000801E08B506D0401E00D0FEE700F092FB002008BDF9F730F908BD08B58DF8010088
+:209120000021032201206B468DF800000A20FBF7E1FA08BD0A68002A08BF086006D01146DE
+:2091400000E011468A68002AFBD18860704738B10628B8BF012006DB802801DB8A2801DBAF
+:20916000002070470220704710B503460C4650080021C0184FF0000341EB0401F3F74EF8EB
+:2091800010BD10B5041C08D000211C22F5F7DEFB4FF6FE702080401C608110BD01207047EC
+:2091A0000CB480B502AF3A6827F003031B1D01F06DF8BDE8804002B0704720380F2807D97F
+:2091C0001838022804D9A838022888BF002000D80120704708B500F07FFF28B1007918B1D1
+:2091E0000528B8BF012000DB002008BD08B500F073FF28B1007918B10328B8BF012000DB12
+:20920000002008BD0449891C01EB8000017801F0FB0101707047C04600100840044A121FA0
+:20922000126802EB80000268914218BF01607047DCC2020010B5044CE22034342146FEF7A0
+:209240004BFD204610BDC046ECFB002010B5002430B1C01D80B2F3F777F8FF2808BF012441
+:20926000204610BD0146034808B5006842680248904708BDD80100100040034000F8011BF4
+:209280000A0A00F8012B0A0C00F8012B090E00F8011B7047034610461A4628B111F8013B5D
+:2092A000401E02F8013BF9D11046704738B50C460546FEF73FFF296844F80C1C2C6000F015
+:2092C0001CFA38BD044908B591F8410118B1D1F86C0100B1804708BD101500201CB5C2F3A7
+:2092E000800302F001040093C2F340032246EAF71BFC1CBD70B515460C460646EFF755FCDB
+:20930000214630462A46EDF76FF870BD10B5044C00F078FF0146A26A6068904710BDC04647
+:2093200030F50020044908B51031096809B1884708BD002008BDC0464804012010B5044C71
+:209340000C3424680CB1A04710BD012010BDC04648040120044A12688A4202D8B1F1FF3F21
+:2093600001D1FDF7A3B970477CAC02000268406892F8303000780021042B18BF0121526972
+:20938000F8F7A8B9044810B500F078FF002400B10124204610BDC046041A002004490A78C5
+:2093A000904204D00870C8791021F8F7FBBB704734FD002008B5FEF71AFE800838BF002007
+:2093C00003D30020FEF7A8F8012008BD0449B1F1FF3F07BF0021081C0868091DEBF7B8BEF6
+:2093E000FFFFFFFF04480168002002E00968401CC0B20029FAD170471C03012004480168DB
+:20940000002002E00968401CC0B20029FAD170472C1A00200349891E08800349891E088004
+:209420007047C046220001203E19002008B5F8F711FAB0F1FF3F08BFE82002D0F0F778FF20
+:20944000002008BD044808B50068D0F82C134FF48050884708BDC046140100200448007809
+:20946000002808BF002001D0F7F7F4BB7047C04606140120022819BF024800680248006811
+:209480007047C046B810012094120120044808B50068D0F82C134FF40070884708BDC0469A
+:2094A0001401002010B5044CA06820B1F4F726F8E068F4F717FF10BDD800002008B500F0C5
+:2094C00085FE034908398A68CA6001F009F808BDE000002004490968D1F8EC2052F82000AC
+:2094E000D1F8E4100860704714010020044808B50068D0F82C134FF40060884708BDC046A6
+:2095000014010020401E082110F8012FFF2A18BF002002D1491EF7D101207047044910B14F
+:209520000A68126802600846001D00887047C04654FC0020044908B5CA681AB1497809B13B
+:209540001146884708BDC046E4FA002030B502FB01F403FB00444FF00005E2FB0054214627
+:20956000284630BD044808B54021A8300160FEF7BDFDFAF753FE08BD00A00C40044988680E
+:20958000401E886003D10869C96800F0C9BE7047C01600200121044A41600021C16012681E
+:2095A0008160801800F0B8BE1CC4020010B50446086903490968A0608847606010BDC0464B
+:2095C00028C402002022EFF3118382F31188426A1143416283F3118800F09ABE0448007819
+:2095E000012802D9C11E012901D8E6F749BA70474D02012030B10449814203D00021202257
+:20960000F5F7A4B97047C04660030120044800B502680A21ADF12C0D684690470BB000BD56
+:2096200088AD020010B54468022000F035FE20B114F8011B01702178417010BD10B544684B
+:20964000022000F029FE20B114F8011B01702178417010BD0448426A81881368806A19438E
+:20966000116000F0CDBEC046481900200448426AC1881368806A1943116000F0C1BEC0468F
+:2096800048190020044A516A10890B6818430860906A00F0B5BEC0464819002003461046EE
+:2096A0001A4628B111F8013B401E02F8013BF9D11046704708B5044B024600214FF080503D
+:2096C000FDF724FC002008BDAD77020008B5044B024600214FF00060FDF718FC002008BD6A
+:2096E0000953020010B500210446FEF759FD002108222046EBF7ECFA10BD08B50090BDF849
+:20970000020000F0EDFEBDF8000000F085FE08BD10B50129044698BF012100F04BFD20462F
+:2097200000F04AFD10BD0146002304204A1C02F8013F401E1371FAD10B80704738B1017BA3
+:2097400001F07C01042903DB40690028F7D1002070470A7A02720A7A022A02D00822FFF786
+:2097600099BD09880180704710B50446FEF726FE032000F009FE204600F03EFE10BD10B564
+:209780002021EFF3118481F3118800F0BDFD84F3118810BD08B5F7F70DFF024901200870E2
+:2097A00008BDC0461505012008B5F7F703FF02490120087008BDC0461F05012008B5E7F767
+:2097C000CBFDEDF74BFAF9F73FF9DFF7FCFC08BD034910B51CC91CC006C980E8060010BD01
+:2097E000E8C102000349096800EB5100B0FBF1F000F06ABE40C4020010B5044600F0E6FC3A
+:2098000000216160216000F06BFE10BD03480078002814BFFE20FF207047C04624000120C2
+:20982000034908310A681040C2430A607047C0460810044008B5E6F79DFF0028FBD0401ED2
+:20984000012800D9FEE708BD034938B53CC93CC01EC980E81E0038BD68C0020010B50021B0
+:209860000C220446F5F772F84FF0FF30207110BD0349103108680028FCD00020086070471E
+:209880000C10044008B5C2F3800302F0010200930123EAF749F908BD0EB50091019291F96E
+:2098A00004300A680121EAF7DBF90EBD0328BABF024901EB401000207047C04610F7002031
+:2098C000034938B53CC93CC01EC980E81E0038BD88C0020001604260836100218160016157
+:2098E0004161521EC2607047034910B51CC91CC006C980E8060010BD10C2020010B504689C
+:2099000004F1340000F076FC002084F8310010BD02460348007814210823F7F78FBCC04678
+:209920007CFB0020024603480078B0210823F7F785BCC0467CFB0020024603480078E621AB
+:209940000823F7F77BBCC0464B190020024603480078E4210823F7F771BCC0464B1900204D
+:2099600003483E30007800280CBF0120002070474DFF0020034991F8D40040F0040081F809
+:20998000D400704750180020034A5168401A11788900B0FBF1F07047D80000200249088034
+:2099A000024908807047C046220001203E190020034808B50078FEF783FC012008BDC0467D
+:2099C0007000012000280CBF00200120014908707047C046E9FA00201CB514460A4601467E
+:2099E000009300202346FBF725FF1CBD0A7A032A02721CBF0988018001D100F0CDBB704749
+:209A0000034808B508300068006B804708BDC0468401001000B903488A0002EBC1010818AF
+:209A20007047C0460005012008B500F069FC0248006800F06DFC08BD8C16002010B5044690
+:209A400000F052FD844232BF001B001B401E10BD034A014608B50820FDF7BEFE002008BDA1
+:209A60004DF00100034A014608B50220FDF7B4FE002008BD71580200034A014608B510205E
+:209A8000FDF7AAFE002008BD75680200034A014608B54020FDF7A0FE002008BDDD3302002C
+:209AA000034A014608B50120FDF796FE002008BD8F1A020001460120042903D00A291CBFA6
+:209AC0000329002070474FF6FF70884203D0C8B2002100F08FB870474FF6FF70884203D058
+:209AE000C8B2012100F086B870474FF0FF3280680A6042684A6080688860704708B58022E9
+:209B0000FBF7D6FC002814BFC068002008BD08B500F0DEFC002814BF00204FF0FF3008BDA4
+:209B200008B50020FDF7F8FCFF200321FCF72AFA08BD40698178002001E0401CC0B281420D
+:209B4000FBDC7047024910B51EC980E81E0010BD94C20200024A02EBC000F8F721BFC04607
+:209B6000C8C30200024910B51EC980E81E0010BDA4C20200024A02EBC000F6F733BAC046CD
+:209B8000D0C30200014602480078F9F785BDC046DC04012002480068FF21FFF7A4BAC046C2
+:209BA000B800012001460248006800F0F5BAC046B80001200248FF2140F22C72F4F7C6BEAC
+:209BC000E40D002008B500F059FB002100B10121084608BD0249096851F820007047C0468A
+:209BE000DCC20200024A126842F820107047C046DCC20200024A01F0010111547047C046D7
+:209C000000200240002101604FF0FF3141600121017270470248002153300170EAF70EBEF8
+:209C2000E4FA0020024A11680840C1431160704708100440024900220C39CA610860704795
+:209C40000C10044021B10969884208BF012000D00020704710B5F8F7C9FF0446F3F7A0FDBA
+:209C6000204610BD00F00300022101FA00F000F01C007047002101604FF0FF328260416078
+:209C8000C1607047024A02EBC000F1F7A9BDC046D8C30200024A002142F820107047C0466E
+:209CA00074FD002008B5FFF7C3F8002814BF4068002008BD024800788021F8F731BBC046D9
+:209CC0004DFF00200249087006200121DEF79ABC8AFF002008B5FF210E22F4F737FEF0F725
+:209CE000BDF808BD486800280CBF022012204870012070470F2802D90149103808607047A0
+:209D000000EF00E002490968401800F0F5BAC0461CC4020008B5024940680968884708BD24
+:209D20002CC4020008B5024B40681B68984708BD24C4020008B5024B40681B68984708BD95
+:209D400030C4020008B5024A40681268904708BD34C4020008B5024940680968884708BD97
+:209D60003CC4020002490020087048807047C046F003012008B5FFF765F9002814BFC06831
+:209D8000002008BD08B500F083FA002814BF8078002008BD08B5FFF755F9002814BF8068F8
+:209DA000002008BD0068002180F822100B20EFF795BB03461979DA88D8781B7AFBF796BEC2
+:209DC00019B900210822F4F7C1BD00F0E5B941600423826000210370084670474160022366
+:209DE000826000210370084670471346024618460B460021FFF7F0BD38B50468049D646A0C
+:209E00000095A04738BD0969006981420CBF0020C8687047416882680020914208BF0120F3
+:209E2000704708B5FDF732F96421B0FBF1F008BDD0F80320C31D08461946F1F757BE08B587
+:209E4000FFF7DEFD000C0904084308BD0068002101700B20EFF742BB017841F08001017064
+:209E6000FEF788BE08B50090684600F01DFB08BD014800687047C04640C4020001480078AA
+:209E80007047C046041401200148001D008870471EFB0020014800787047C046EFFB002066
+:209EA000014800787047C0461AFB0020014800887047C0461EFB0020014908707047C046A9
+:209EC000EFFB0020EFF3108072B6704700207047EFF3108062B670470020704713460A468F
+:209EE00001461846FEF7F0BC0148006800F084B9941301200148006800F07EB9A8130120C2
+:209F000008B50221FEF79FFD80B208BD08B5014688684968884708BD18B1006808B100F0C6
+:209F2000BBBA704701480830006870471015002001491231085C704748160020014909781F
+:209F400008407047FD13012008B50090684600F0CFF908BD014800F09FBAC046041A002083
+:209F6000014A42F82010704774FD00200149091F0860704754050120014908607047C0466A
+:209F800054050120014800787047C0468EFF002001494331087070474CFF0020D0F80320D9
+:209FA00008460021F4F7D2BC014800687047C0467804012008B5FBF7C5FBF3F7E3FA08BDB3
+:209FC00008B5EEF785F9EBF7DDF908BD01480021017070470414012001490C310860704773
+:209FE000DCFF0020014800787047C0466C110120014800687047C046ECFA002013460A462D
+:20A0000001460020F8F744BB13460A4601460020FCF718BB08B51046F7F7AAFE002008BD87
+:20A0200001B9014900F060B9D0C10200426808604A60116041607047014880687047C0460D
+:20A04000E4160020014800787047C04682030120006908B1FAF7A0BD704700218160017028
+:20A060004160704708B503689B68984708BD08B50268D268904708BD10B50468E469A04757
+:20A0800010BD08B5FAF708FE80B208BD4068002180F8FD10704708B501680968884708BD18
+:20A0A00008B502681269904708BD406800680121C164704708B5FAF7EFFDC0B208BD02463B
+:20A0C00056210020F9F762B900212422F4F73EBC00211022F4F73ABC01460020F5F776BCD9
+:20A0E00001464A20FDF7F8BD406800210170704700210222F4F72ABC6422514300F0A4B998
+:20A1000040686C3000F078B808B1FAF745BD70474FF0FF309060704708B1FAF73DBD704708
+:20A120000222E9F7EDB90122E9F7EAB90222FAF7F3BF0122FAF7F0BF0021F5F747BC0068CD
+:20A1400041617047401EFDD170476FF0010070470123EEF7F9B90023EEF7F6B90720F3F729
+:20A16000E5BB0022FCF780B80022FCF77DB8401C80B270470320FAF769B9C000FFF7E2BFD6
+:20A18000E920F2F751BF0846F2F764BD0846FAF703BD4122FFF782BA0822FFF77BB881609D
+:20A1A0004260704730BF704700F09AB800F094B8FCF76CBF00F048B900F042B900F06CB913
+:20A1C00000207047FEF722BF00F082B800F0FCB800F07AB800F074B8FFF78CBD00F06CB873
+:20A1E00000207047002070470020704700207047F3F7D6BA00F05CB800F002B900F054B8DE
+:20A2000000F0C6B8FFF718BFFFF7DCB900F080B800F016B9FFF74ABEFEF7E6B90020704728
+:20A2200000207047002070470020704700207047F32070470020704700207047DC20704797
+:20A24000DD207047002070470020704700207047C2207047FDF7D7BBFFF700B90020704720
+:20A2600000207047002070470020704700207047012070470120704700207047808A70473A
+:20A2800080687047EEF792BC0120704700F008B800207047FFF766BDF2F7DCBCF4F756BBF7
+:20A2A000DFF800F0B9F80210DFF800F0BDE80210DFF800F0FDE60210DFF800F019E90210FF
+:20A2C000DFF800F01DD90210DFF800F0D9D80210DFF800F075E40210DFF800F0FDE9021034
+:20A2E000DFF800F049E60210DFF800F0C9F40210DFF800F0DBEC0210DFF800F09DE80210C2
+:20A30000DFF800F0D7DB0210DFF800F0B1D70210DFF800F091D80210DFF800F0E5DE021073
+:20A32000DFF800F07BEC0210DFF800F019D70210DFF800F077EC0210DFF800F067F30210A5
+:20A34000DFF800F0C5EA0210DFF800F049DC0210DFF800F0F9F20210DFF800F0EBEC021003
+:20A36000DFF800F06BEC0210DFF800F031EC0210DFF800F0F1DC0210DFF800F059F50210EA
+:20A38000DFF800F01BD00210DFF800F011EA0210DFF800F025EA0210DFF800F0D7EC0210A1
+:20A3A000DFF800F0D3EC0210DFF800F07DE80210DFF800F021D40210DFF800F049EB0210EC
+:20A3C000DFF800F0E5F80210DFF800F055EB0210DFF800F08DDD0210DFF800F0F1EB0210B6
+:20A3E000DFF800F039F70210DFF800F0AFEC0210DFF800F0ABEC0210DFF800F0B1F70210EF
+:20A40000DFF800F021CD0210DFF800F0B9DC0210DFF800F0CDEB0210DFF800F045DF021079
+:20A42000DFF800F0D9EB0210DFF800F021EB0210DFF800F02FEB0210DFF800F04DEA021097
+:20A44000DFF800F0E7E90210DFF800F0C3EC0210DFF800F025DB0210DFF800F09DEB021091
+:20A46000DFF800F061DB0210DFF800F0F1EC0210DFF800F05DF10210DFF800F0C5F3021059
+:20A48000DFF800F0A5EA0210DFF800F0D9D50210DFF800F009EC0210DFF800F0C5E202107F
+:20A4A000DFF800F01D870310DFF800F0BBEC0210DFF800F0F5EA0210DFF800F0C1DD02106F
+:20A4C000DFF800F0E5EB0210DFF800F001CE0210DFF800F0B1BF0210DFF800F011F7021001
+:10A4E000DFF800F047EC0210DFF800F011DC02109A
+:20A4F000C4130120E00F0120541301205410012000000000AC110120CC1301205C120120CA
+:20A5100064130120E810012098BE0200F4C202008AC3020010C3020002C3020074130120D7
+:20A530008C0101209001012094010120980101209C010120A0010120A4010120A80101202B
+:20A55000AC010120841301201C1001201C130120141101204EBA0200DCB90200C0BA020065
+:20A5700032BB0200A4BB0200B8C1020044C3020038C3020009140120AC1301205C0401205B
+:20A5900078120120B802012001140120021401208810012030130120C8FC0020B0010120E5
+:20A5B000D4B7020008B202000000000000000000E4C20200E40B0120F8130120F413012036
+:20A5D000B4010120B8010120EC13012018BE0200C8120120640E0120000000000000000035
+:20A5F000A00401200000000000000000000000000000000058010120100A0120E8050120C3
+:20A61000014A031049480310D549031015470310F5A701005D49031081470310A14603105D
+:20A630009548031045450310254A031021440310ED47031099490310E1480310214903108E
+:20A650005553031089520310CD520310655003108D4E0310A1AA010081ED0100F5040200A3
+:20A670000000000059510310ED5003101DF70100CD4B03102952031011530310A955031067
+:20A690007555031069530310DD55031035550310F9A9010021540310855C03100D56031087
+:20A6B0004D5D0310A9640310B55B03106D570310E5610310095E0310C558031085600310B8
+:20A6D00071610310B16203109963031055630310FD600310B15E03108D8F0100D55A031094
+:20A6F000D559031009630310D963031019640310555F0310C56403104D62031071640310FE
+:20A710008D64031055640310E16403102975031079720310A16B0310F57203109D74031095
+:20A73000797403102D74031061730310FD7303105574031015750310D96C0310FD74031096
+:20A75000AD4B0100E17403103D75031081A20100F9640310CD6803102D710310C1740310EE
+:20A77000F56E0310B973031029670310056E0310C56F0310EDC00100A1770310797D0310C2
+:20A790003D7E031049750310157E0310357D031099760310997C0310257B031071780310A6
+:20A7B000B57D0310ED7C0310857E03102D790310B97A0310917B0310B1790310ED7B0310DC
+:20A7D000E97D0310617E0310357A0310D57E0310457C0310A57E0310BD7E0310B97801004C
+:20A7F000D9800310E97E031049830310898403108D8103107D820310E58403102B840310F3
+:20A81000C5830310918703106188031045880310F1850310B18803107D880310C988031075
+:20A830001D870310A186031001850310E188031099880310F9870310399C0100359C031081
+:20A85000819D0310E99A0310359B0310C19B0310419A0310F18803101D8C0310618F031096
+:20A87000F1940310919E0310C19E03103D9E0310699E0310259E0310619D03100D9E0310CF
+:20A89000819B0310ED93031055990310C9970310D9980310BD950310959C0310C19D0310D4
+:20A8B000A59E03107D9E0310C99103104DC70100699C0310DD9D031095900310FD9B0310FA
+:20A8D000CD990310158E0310019D0310E19C0310219D0310419D0310BD9C0310F59D031025
+:20A8F000A19D031055980310E1920310999A0310B99E0310559E0310716402004F91020002
+:20A9100039A20310DD8A020069A1031075A20310C59E0310B9A10310F9A1031015A1031030
+:20A930009DA20310CD9F0200DF6401009D920100FD5302007D9E0200A1B5000031A9031021
+:20A95000ADA20310A9220100B9A8031099A50310A1A8010039A803106DA90310817F01008C
+:20A970006DAC031099B1031009AF031059B1031001B103109DA9031045A2020041A202006A
+:20A9900031A2020025A2020039A202003DA2020029A2020035A2020049A202004DA20200C7
+:20A9B0002DA20200F1B9031075BA031081BB0310E55C020055DE01001519020051900100DF
+:20A9D0008157020011110200BD6D020075110200AD5C020009830200658F0200B518020057
+:20A9F000FD400200756502004D32020089040200D594020009ED01000944020005950200CF
+:20AA100061A2020069A20200D1FD0000F9180100E9C6031065A2020095940000E5A10200B8
+:20AA3000BD5F020053970200D319020075A1020069910200E1A1020051A20200E11E020080
+:20AA5000F9CD01001DCA010001000000000000000000000000000000FFFFFFFFB005012064
+:20AA70000400000000000000000000001400000030FD02101800000008C4020018AB0200C4
+:20AA9000880501200400000000000000000000002400000018FD0210180000000D960200EC
+:20AAB0000800000008AC0200CCAA0200C1C8021001BB021091EB0210DDE5021081E0021012
+:20AAD000B9E5021071E5021031000000010000000100000044C4020000000000FFFFFFFF15
+:20AAF000A805012004000000000000000000000028000000B8FC0210240000001E00000044
+:20AB1000180000000000000080AD02002CAB02009BEC021025E2021005EB021025DE02103C
+:20AB3000FDE10210E1E402102F00000034000000240028000000000008040120FFFFFFFF66
+:20AB5000D0050120040000000000000000000000380000006CFC0210280000000100000010
+:20AB7000100000000000000000000000F7F1021000001A00100000000300000074C3020055
+:20AB90001FC30200080000003600000040030120EC01012009001D00B3C201002001012033
+:20ABB0000100000000001200FFFFFFFFC0050120040000000000000000000000100000007C
+:20ABD00048FD0210180000000000000000001300FFFFFFFFD80501200400000000000000E5
+:20ABF0000000000054000000A0FB02103C000000000001002D0000005CAA02006BB00100B6
+:20AC1000300000000000000008AC020030AC0200E9260200D9DB021059EC0210CDD602107D
+:20AC300085DE02104DE5021029E5021030000000000016000000000000000000FF7F000067
+:20AC500000FF0020FFFFFFFFB805012004000000000000000000000058000000DCFB0210A6
+:20AC70003400000039FB021001002F00060000000000000020000000010000001BF80210CE
+:20AC90002800000080AD0200A8AC020093EC02106DEB02104DEC021029E00210BDE40210E3
+:20ACB00099E402102D000000000000009005012004000000000000000000000010000000FE
+:20ACD00040FC02102C000000000000000000030000000F003C00000000000000000000009C
+:20ACF0002FF90210100000000800000024C20200FFFFFFFFC805012004000000000000001C
+:20AD1000000000001C000000DCFC02102400000094AC020078050120040000000000000015
+:20AD3000000000000C00000000FD021018000000CBD101000000000000000000080000002B
+:20AD5000010000000400000000000000000014000000000044BD0200000019000000180096
+:20AD70002400000089A2020000400000000200005CAA02000000100055F002100C000000B5
+:20AD9000F15C010000000000700501200400000000000000000000002000000010FC02107D
+:20ADB000300000005CBD02000100000011A10200EFAB0100000000000000170000020000CF
+:20ADD0003100000000002300000015000100000018AC0200A0050120040000000000000069
+:20ADF000000000002000000094FC02102400000074BD02000005012020000000FCBF020027
+:20AE10008F0001001C05012087000100ADFE00203500280034FC002028000100C1FE002048
+:20AE300029000100AEFE002084000400E4FE0020860001008DFF00202A000100BAFE00204C
+:20AE50002B000100AFFE00202C000100B0FE00202D000800F0FE00202E000100B1FE0020AD
+:20AE70002F000100B2FE002030000100B3FE002032000100B4FE002033000100B5FE0020B4
+:20AE900034000100BFFE002036000100C5FE002038000100C6FE002039000100BEFE002043
+:20AEB00083000200DEFE002063000100B8FE002065000100C2FE00206D000100B9FE00203C
+:20AED00071000800F8FE002066000100D3FE002043000100B6FE002044000200DAFE002025
+:20AEF00045000100D0FE002046000200DCFE002047000800E8FE002048000100D1FE00203F
+:20AF10004B000100B7FE0020040001001B050120A10001001E050120370001001D05012059
+:20AF300088000100D7FE00203C000100C7FE00203D000100C8FE00204900020018050120B4
+:20AF500067000100D4FE00204D000200E0FE00204E000100D2FE00204F000200E2FE0020AA
+:20AF70003E000100C0FE002051000100CAFE002052000100CBFE002053000100CEFE0020EE
+:20AF900054000100CFFE002000000000000000005D40002189400021954000213B41002124
+:20AFB000074C657900F009F861796940490703D50121044A8903116070BD70B5024908475B
+:20AFD00080030021081104402D59000000F00AF800480047577F000000F00AF80048004702
+:20AFF0001B880000806B0C490007000F48717047094A0A4918235079CB56497EC0188142AB
+:20B0100001DD084602E00F2800DD0F20D189090909010143D1817047E00200218800002160
+:20B030000122274B02212548184710B5254880472548406A00280DD124490A200856002849
+:20B0500009DA401C07D008462038406A2049884200D1804710BDFFF7E3FF10BD00211E4BB3
+:20B070001C4A0846184701201C49400208601C48FB220178114001701248EC38004710B537
+:20B090001849884711492039012807D0020404D50020088514484862012010BD4A6A094B35
+:20B0B000EC3B9A4201D1114A05E007494A6A104B9A42F2D10F4A4A6210BD0000060800008D
+:20B0D0009F060000A1920200080100215401002163920200E7400021B5B4020080E100E0FB
+:20B0F00080030021F7960200DD4000212341002169950200194100210097B92EE5725CCBD3
+:20B110005DCAE473B82F0196BA2D03945FC8E671E7705EC90295BB2CE3745ACD0691BF282F
+:20B13000BE2907905BCCE27559CEE077BC2B05920493BD2AE17658CF51C6E87FB4230D9A0F
+:20B150000C9BB522E97E50C7EB7C52C50E99B720B6210F9853C4EA7DB2250B9C57C0EE79EF
+:20B17000EF7856C10A9DB324089FB126ED7A54C355C2EC7BB027099EA2351B8C47D0FE69CF
+:20B19000FF6846D11A8DA334188FA136FD6A44D345D2FC6BA037198E41D6F86FA4331D8AAF
+:20B1B0001C8BA532F96E40D7FB6C42D51E89A730A6311F8843D4FA6DF3644ADD1681AF388F
+:20B1D000AE3917804BDCF26549DEF067AC3B15821483AD3AF16648DF1087A93EF5624CDB6F
+:20B1F0004DDAF463A83F1186AA3D13844FD8F661F7604ED91285AB3C0001363601010001DB
+:20B21000020100010301000104010606080400000C0100340D01000F10040101140100FF70
+:20B230001608000020020000220100FF23010001240100FE250100082602000028010001D4
+:20B25000290100012A0200002C01000F2E0200003001000131010008320200FF3401000740
+:20B27000350102FF360100003701000138010001390100FF3A01000F3C0200FF3E01010FCE
+:20B290003F0100014001041F41010001420100FF43010080440800004E0100084F01000FAE
+:20B2B00050010001510100FF520100005301000054010001580400005C04000060040000BE
+:20B2D00064040000680400006C0400007004000074040000780400007C040000800100FFB2
+:20B2F00081010001820100018301020284010001E20501200B1401200C140120E105012099
+:20B3100003140120E3050120E0050120D99F0200ADDF00002D94020021760200F575020008
+:20B33000CD1D0200291E0200FD3102007D470200F17D02002D6D0200FD6C0200B5A0020004
+:20B350000D980200E9850200A56402009D8202009D99020015940200798202005D6D0200EE
+:20B3700085D50100C98E01000B7902008925020055180200B59F0200C19F020000000000AD
+:20B390002989020097690100D1DD01004557020000000000D9640200E59F02001D5D02005A
+:20B3B0008D9402000000000000000000050F0100098902003DCB0100293A0200C0C1C2C33D
+:20B3D000C4C5C6C7C8C9CACBCCCDCECFFF000000000000000000000000000000FF000000ED
+:20B3F0000000000000000000000000002100000010002081E8040120210000001100438168
+:20B41000000000002100000012002083E90401202100000013002083EA0401202100000031
+:20B4300014002083EB0401202100000015004381EC0401202100000016001A81FF05012033
+:20B450002100000017001A81FC0501202100000020001843F0040120210000002100F143C0
+:20B47000C0040120210000002200F143B004012021000000FDFF2141F2040120032C0000C6
+:20B49000000000000000000000000000000000000308000000000000000000000001650922
+:20B4B0000000000000000000012C000000000000000000000001001E000000000000000030
+:20B4D000020800000000000000000000000101000800FFFFF4040120D4030120B80301205D
+:20B4F000022C0000000000000000000000000000000000000000000000000000000000000E
+:20B510000128000000000000000000000001003000000000000000000003FF186400000043
+:20B5300000000000000000007856341200000000BAAB000000000001000000007F430200BD
+:20B550008DEE0000D991010025BC010091A401000D2C010091A40100B9D30000F1140200DA
+:20B5700025BC010091A401000D2C01003541010025BC01000000000000000000492902009C
+:20B5900025BC01000000000000000000E1A3010025BC01002596020025BC0100378B0200EF
+:20B5B000C19C0000912D020025BC010000000000000000000000000000000000000000007C
+:20B5D000000000003D960200C11B01001567020025BC01003D960200C11B01001567020019
+:20B5F00025BC0100378B0200C19C00006521020025BC0100000000000000000000000000CE
+:20B6100000000000000000000000000000000000000000000000000000000000000000001A
+:20B630000000000000000000000000000000000000000000000000000000000000000000FA
+:20B650000000000000000000000000000000000000000000000000000000000000000000DA
+:20B670000000000000000000000000000000000000000000000000000000000000000000BA
+:20B6900000000000000000000000000000000000000000000000000000000000000000009A
+:20B6B000000005000600080009001600020102020302000301030105020500060106040B0C
+:20B6D00014061506170600070107020703070009040907000A000C000D000E000F00100079
+:20B6F00011001200130014001B00000101010002010202040004010403040404050406049C
+:20B710000005020603060406050606060706080609060A060B060C060D060E060F06100633
+:20B7300011061206130604070009000B010B020B030B0000FFFFFFFFFFFFFFFF1300000060
+:20B75000492101001F000000217601001F800000CB52020000000000A9D10000010000007E
+:20B77000A9D100000200000055800100028000005713010003000000B9DA010004000000DF
+:20B790007937010004800000871E0100050000004DF501000600000051C700003100000027
+:20B7B0000183000033000000014001003400000059E701003600000049100200FFFF00007C
+:20B7D00000000000360001000600000000000000000F00000000000000000000000000000D
+:20B7F00000000300FFFF00000403FFFF0000FFFF0F00E8030005401F0310000100000000C3
+:20B81000FF3F0F000800050B00000000000000000300010F000000000000000000000000A0
+:20B830000000000000000000000000000000000000000000000000000000000000000000F8
+:20B8500000000000AD00000200000000000000000000000000000000000000000000000029
+:20B870000000000000000000000000000000000000000000000000000000000000000000B8
+:20B89000000000000000000000000000000000000000000000000000000000000000000098
+:20B8B000000000000000000000000000000000000000000000000000000000000000000078
+:20B8D00000000000000000000000000000000000FFFFFFFFFFFFFFFF000000000000000060
+:20B8F0000000000000000000000000000000000001000000D9C0000006000000778401009C
+:20B9100008000000BD0C02000B000000F342020010000000E91F010002000000F19C010059
+:20B93000050000002D160100070000007D3201000C000000119A00000D00000055170000C7
+:20B950006400000049530200FF00000000000000000000040000000003002001A2C3020047
+:20B970000000000000002005A3C30200000000000500420180C3020000000000004042011A
+:20B9900093C30200000000000400420170C202000000000007003001A4C302000000000023
+:20B9B00011003003F003012000000000FDFF21019EC302000300000000002103F203012061
+:20B9D00003000000FDFF2101A0C3020001017101010101011101010131010101010180018E
+:20B9F0000001100161013B001400630173017201620143010001130106013D0135000401EE
+:20BA10001201000100010001000104010401330133013C014401320136000001000165013A
+:20BA300000013500810100010501820183010001660100010001080109010A010B01030099
+:20BA50007100300160001100700031022003500480000700100061000000140063007300C7
+:20BA7000720062004300000013000600000000000400120000000000000000000400040068
+:20BA9000370037003C02440000000000000000006500000035008100000005000000830003
+:20BAB0000000660000000000080009000A000B000302710230016002110270020102020253
+:20BAD000020280020002100261023A00410063027302720262024302000213023800000296
+:20BAF000000204021202000200020002000204020402370037003C024402000239000002D7
+:20BB10000002650200023502810200020502820283020002660200020002080209020A024F
+:20BB30000B020103710301030103010301030103220302030103000310030003000300030F
+:20BB5000000300030003000342030003240306030003000304031203250323032503230393
+:20BB70000403040300030003000344030003000323030003650321003503810300030503D8
+:20BB9000000300030003000325032303080309030A030B030304710402046004110470049A
+:20BBB0000204020401040204000410046104000414046304730472046204430400041304A9
+:20BBD000060400040004040412040004000400040004510464000004000400044404000404
+:20BBF000000400040004650400043504810464000504000483040004660400040004080484
+:20BC100009040A040B042100D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF000000000000000051
+:20BC300000000000000000005A6967426565416C6C69616E636530390A0000000200000030
+:20BC50000400000008000000100000002000000040000000800000000001000000020000D5
+:20BC7000000400000008000000100000002000000040000035810200FB96020055CC0100CB
+:20BC9000994B020089860200EDBA01004DE90100DB840200A98602001B71020049710200E2
+:20BCB0004F520200AD670200AD920200491B020099360200810F0200A51B0200DBFD021005
+:20BCD0002D83020011DC0210E1CC0100199F020081770200ED99020099A10200F18F0200FB
+:20BCF0008F0000008F0001008F0002008F000300900000018F0001019000000290000003AB
+:20BD10008F0001048F0000058F0008048F0000048A000006510000007F0001003F00040019
+:20BD30003F0002003F0001007F0002008F0002048F0001027B7374617469632D696E7374DC
+:20BD5000616E63652D6E616D657D00C07B656D7074792D696E7374616E63652D6E616D6537
+:20BD70007D00C0467B756E6B6E6F776E2D696E7374616E63652D6E616D657D00AD20020009
+:20BD90001FF9021045F8021059F802106DF8021081F8021095F80210E5E40100CD6F02000E
+:20BDB00059500200A7680200E1830200019A0200E9890200355E02003F9E0200F595020040
+:20BDD00075FF010000000000000000000000000000000000000000000000000000000000DE
+:20BDF000000000000000000000000000000000000000000000000000000000000000000033
+:20BE10000000000000000000C003000080070000000F0000001E0000003C000000780000E7
+:20BE300000F0000000E0010000C003000080070000000F0000001E0000003C0000007800F6
+:20BE50000000F0000000F0000000004017FF0000000000000400FFFF080000001000000082
+:20BE70004018002030180020401A0020301A00200A000000090000000C0000000B000000C4
+:20BE900009080AFF0A0000000000000002000000020000000A00000002000000020001005B
+:20BEB000000000000000000000000000000000000000000000000000000000000E00000064
+:20BED000000000000000000000000000000000000000000000000000000000000000000052
+:20BEF0000000000000000000000000000000000000000000FFFFFFFFFFFFFFFF99CF0000D2
+:20BF100071200000C97C000051760000E96B0000AD390000E97F0000DD4000002DC50000C3
+:20BF30000100010001000100010001051E0D0C1C1D1E0F0E0607140A0809000102000100FB
+:20BF5000010001000100010200010205E9A002004BA102002D6A0200398C0200452B020078
+:20BF7000558C020065E10100D5440200E99E0200F1390100A9D80100857202005D6A020074
+:20BF9000EB9A020001620200718C0200F1620100C53C0200F59E0200C514010000000000E0
+:20BFB0000060250000100000A00F012040000000000000000000000000093D001400000072
+:20BFD0006400000008AC0200ECBF0200259D0200359D0200559D0200459D02005D7002004B
+:20BFF000298402005D7802003200000015F9021001E602102DDA021045E7021041D10210E5
+:20C01000C9D30210A5DF02102DE4021061EA02109950020080AD020038C0020075A202001F
+:20C030009DCF010091F70100FD6F020005840200317802002E000000FFFFFFFFFFFFFFFF30
+:20C05000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFF00000000EA
+:20C0700000000000000000003A013A0100000000000000000000000000000000FFFFFFFF3E
+:20C09000000000000000000040420F0008000000000000000000000024C00200800501206B
+:20C0B00004000000000000000000000020000000D0C1020018000000D4BF0200980501204E
+:20C0D000040000000000000000000000140000003CC102001C00000000000000000000001D
+:20C0F0000000000000000000000000000000000000000000FFFFFFFFFFFFFFFF0000000038
+:20C1100000000000000000000000000000000000000000000000000000000000000000000F
+:20C130000000000000000000000000001C000000000000000000000050C1020000000000C0
+:20C150000800000000000000FFFFFFFFFFFFFFFFFFFF0000000000000000000000000000D1
+:20C170005CBF0200F013012000C4020084BF0200B8130120ACBF0200392E0200A96801008F
+:20C190008DA00200C54401008D7900007910010000000000020000000100000003000000C0
+:20C1B000100000002000000000000500BD00B700B100BC001C003000380008003801020092
+:20C1D000180000000000000000000000E0C10200080000000000000005000000D0070000B0
+:20C1F000C8000000FF00000000000000000000003D8D010001910200010101000000000006
+:20C21000020000000000000000000000FFFFFFFF000000000100000000000000000000000F
+:20C230000000010000000100001610000018151002000224145800001000000600000000DF
+:20C250000000000000000000000000000000000000000000000000000000000000000000CE
+:20C27000105465786173496E737472756D656E7473400000000000000000000000000000AD
+:20C29000000000000200000000000000FFFFFFFF000000000200000000000000FFFFFFFF92
+:20C2B000000000000F010000010000000E01000001000000580F0120B4C202007C0F0120A1
+:20C2D000BCC202008C1700206C0D0120E80D0120FFFFFFFF88B22400881300001000000056
+:20C2F0000000000100A6AAACA4A9A9A399B19ABCB6A8313118191A22311C1E203131343179
+:20C31000313117191A21241B1D1F313133312000000000000000000000000000FF000000E0
+:20C3300000000000000100000C0E020B040B0A070800110F000120181A18182C34041E0078
+:20C35000FF000100F59202000700000088C102001009012058BE0200FF00000000000000A1
+:20C3700080A9030025DD021031C8021075DF02100974692E726F757465720204020101013C
+:20C39000010902083230323230313235010A0200010001030100000000BE040A00BE020844
+:20C3B0000102000302000103FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB012012081C2020049
+:20C3D000401101201EC302006C0C012068C30200CC11012010C40200038000CC038000DDAF
+:20C3F0000380000C0380005D038000C0038000D500000500006000000000000000000000BE
+:20C41000000002400A29FF0000000000100000000100000087A1020079A20200F7A901009F
+:1CC430008DA10200C13A02003D33020071A202000A000000C592020000000300D6
+:20C44C005D9F0000F14D0100000000000000000000000000DD920200859802007DF3010094
+:20C46C004998020069A1020063A102009998020000000000F1A0020009F301001DFB0100DF
+:20C48C00358D0200FDC80100FD9A02006174010089CD000065D30100698702000000000016
+:20C4AC00D1230200E18C02000DB1010095970200559B02004D9E0200459B0200C9A00200F2
+:20C4CC0027A1020021A10200A9970200759B0200A59D0200659B0200D1A0020033A10200DF
+:0CC4EC002DA10200DD9D0200CF9D02008A
+:20C4F800003D00000F05D41B002001BF06017FFFFFFEFFEFBD9D914402004CC4027300B826
+:20C518000030FFE1150101FFEFDA1FEEFEBFC701957402FFE6ECC604FF0000EEC806000021
+:20C53800F1FDCA0040F4CC0A0000F6EDCF0040F7D00090FAD410FF0000FBD6120000FDFB20
+:20C558009318FFE05328000001FD560040025932000003FF5D38000004634E00FF00051736
+:20C57800720000062AFF4F1480075F281480FF085A331080095F3FFF10800A664F10800B49
+:20C59800FFCB2130800CCC273FFF800DCDC33F800ED6FF271B800FDA2F1B80FF10DE391B36
+:20C5B8008011E54FFF1B8012E047308013FFE2613F8014F5753F5F807FFFFF3FFFE10F19A7
+:20C5D8003FD801B9A21937FFEF0110FEFFFFEF580362FFE520FFEFC6012F30FFEF153BFD86
+:20C5F800105F20D9A5033F21FFEF46FEFF00050000D200A6FF0159FFE8011FB38813FEFF5A
+:20C61800EF3C010103071E0205E91E431047800200E00D0A01DB020106E00A0100000809AB
+:20C63800CB030801500A07D00821B80B7F803EFFFFE8030509AB7F23456789ABCDEFFFE6EC
+:20C65800C1FF29D000310B631D5B4DE010061D012BD239EC024C2008FC0A2F012EFFEF2384
+:20C67800F8FF0715710724E13344B0151515FF03FFEF650EF9C5A7FFE329FD9A60350100AC
+:20C6980008040120600175027D017D082F31FFEF5318AB6E377E21F3010034010120003157
+:20C6B8006201BF025001B00031FFEF2ED5F8FFEF05BFC046C00000F0FFE0F05300BC087065
+:20C6D8000031C40034CC003455D40034DC0034E40034EC0034833DC52CB74C112D8D037181
+:20C6F800FFE11C5702012000312400342C0034153400343C003444003419CF5FFFEF0D1EFE
+:20C718006EAF52A41600200031474140F9E3A3DF42F33B9F0E899F262BD4D7FFFD0307C258
+:20C7380001838703FF00C3060201A86001EF00D388F759B22B5EC8BE529032058387000180
+:20C75800B1059E01B004D388F35B72FFE108F700040180600248C402764F3282C29C77E992
+:20C7780089027B72C7FF001452285DFF00FFEF124EBAA6A1F732BB897F0BFFE614000A131D
+:20C798003F0F142014003200100A90FF0101007D005A6967FF426565416C6C6961FF6E63A9
+:20C7B800653039C0C1C2FFC3C4C5C6C7C8C9CADFCBCCCDCECF1FFF060502F964A910A70055
+:20C7D800C002008388990F12B010F3D4BFAC336341FE6DFE6C07FEFF648001E05E38CE955A
+:20C7F8007F0405000366F212D56742FD01003247280200EDA16AB1F70BB0009051F070056C
+:20C8180000335578003480003488003490003455980034A00034A80034B0003455B80034A2
+:20C83800C00034C80034D00034DDD8003401003031CF06202F03AC0900200E08FFF000CBD5
+:20C858000600000F902A0100BF05FFEF0221A27F0200114F01006D0070FEFFE9280001208B
+:20C87800EC0101792004B1043D400301200031B6FFEDFF7FFFE46CDC04C63CFA043003FF0D
+:20C89800E49D6F020069CB9702093F03BC06B00BBF0A1C02F606FF00F80508333417002074
+:20C8B800EA00313C003408FFEC0606016B20F002B0F402F4003A0BB06D06FFE2200112C082
+:20C8D8000C0B0CBF006C0FF1FFEF0202600041002000313800B0007200B400022004F001E9
+:20C8F80071814000340131003801B2013C023900010305700035FFE4FFF000570108000045
+:20C91800070100200C00F7F98000F0001FF201ADCA0100D5FFB0000005130200797DF51147
+:20C938003F14F200E0A1611567AF0016BC0214CF5B0507630000FFF0B50A0200319E02008B
+:20C958009D9F0200000000000200000010000000020000001000000002000000100000004B
+:20C9780002000000100000000200000010000000020000001000000002000000FE0D00005C
+:20C99800000100000F15FFF00200000010000000000F58AA0200FFF0000F8CBD0200FFF00E
+:20C9B800000F80160020FFF0F8C40200501A002056C802002001002012C90200501800209D
+:20C9D80060C90200301A002068C902003018002070C90200401A002078C90200401800209F
+:20C9F80080C902001018002088C902002018002090C902001006012098C90200D8000020F4
+:20CA1800A0C902000C010020A8C9020000010020B0C9020004010020B8C902000801002086
+:020000040005F5
+:207FA800000080011000C0FFFDFF58003AC1B9FDFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF74
+:207FC800FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC508FEC5FFFFFFFF00FFFFFF00C5C5FF97
+:187FE800000000FF00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF92
+:00000001FF
diff --git a/tools/fw_TubeZigbee_efr32/MGM210PA32JIA_ncp-uart-sw_6.7.9.gbl b/tools/fw_TubeZigbee_efr32/MGM210PA32JIA_ncp-uart-sw_6.7.9.ota
similarity index 100%
rename from tools/fw_TubeZigbee_efr32/MGM210PA32JIA_ncp-uart-sw_6.7.9.gbl
rename to tools/fw_TubeZigbee_efr32/MGM210PA32JIA_ncp-uart-sw_6.7.9.ota
diff --git a/tools/fw_TubeZigbee_efr32/readme.md b/tools/fw_TubeZigbee_efr32/readme.md
index 20e2929c5..677690b99 100644
--- a/tools/fw_TubeZigbee_efr32/readme.md
+++ b/tools/fw_TubeZigbee_efr32/readme.md
@@ -6,7 +6,7 @@ This firmware is to be used with Tube'z Zigbee EFR32 based gateway:
### Currently recommended versions
-- `MGM210PA32JIA_ncp-uart-sw_6.7.9.gbl` - EZSP version 6.7.9
+- `MGM210PA32JIA_ncp-uart-sw_6.7.9.ota` - EZSP version 6.7.9
The device comes pre-flashed with EZSP 6.9.1_2 but there are unresolved issues with Tasmota and we currently only support 6.7.x. You need to downgrade the flash firmware to 6.7.9. Simply use the **Firmware Upggrade** feature of Tasmota, it will automatically detect that the firmware is for the EFR32 and not for Tasmota.
diff --git a/tools/lv_gpio/lv_gpio_enum.h b/tools/lv_gpio/lv_gpio_enum.h
index 11535f97a..933d83f02 100644
--- a/tools/lv_gpio/lv_gpio_enum.h
+++ b/tools/lv_gpio/lv_gpio_enum.h
@@ -261,7 +261,7 @@ TFMINIPLUS_RX = GPIO_TFMINIPLUS_RX
ZEROCROSS = GPIO_ZEROCROSS
HALLEFFECT = GPIO_HALLEFFECT
EPD_DATA = GPIO_EPD_DATA
-INPUT = GPIO_INPUT
+GPIO_INPUT = GPIO_INPUT // avoid conflict with INPUT
KEY1_PD = GPIO_KEY1_PD
KEY1_INV_PD = GPIO_KEY1_INV_PD
SWT1_PD = GPIO_SWT1_PD
@@ -307,5 +307,23 @@ SDIO_D2 = GPIO_SDIO_D2
SDIO_D3 = GPIO_SDIO_D3
FLOWRATEMETER_SIGNAL = GPIO_FLOWRATEMETER_IN
+BP5758D_CLK = GPIO_BP5758D_CLK
+BP5758D_DAT = GPIO_BP5758D_DAT
+SM2335_CLK = GPIO_SM2335_CLK
+SM2335_DAT = GPIO_SM2335_DAT
+MP3_DFR562_BUSY = GPIO_MP3_DFR562_BUSY
+TM1621_CS = GPIO_TM1621_CS
+TM1621_WR = GPIO_TM1621_WR
+TM1621_RD = GPIO_TM1621_RD
+TM1621_DAT = GPIO_TM1621_DAT
+REL1_BI = GPIO_REL1_BI
+REL1_BI_INV = GPIO_REL1_BI_INV
+I2S_MCLK = GPIO_I2S_MCLK
+MBR_TX = GPIO_MBR_TX
+MBR_RX = GPIO_MBR_RX
+ADE7953_RST = GPIO_ADE7953_RST
+NRG_MBS_TX = GPIO_NRG_MBS_TX
+NRG_MBS_RX = GPIO_NRG_MBS_RX
+ADE7953_CS = GPIO_ADE7953_CS
SENSOR_END = GPIO_SENSOR_END