diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f6351450a..4a15daa5c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -7,7 +7,7 @@ - [ ] Only relevant files were touched - [ ] Only one feature/fix was added per PR and the code change compiles without warnings - [ ] The code change is tested and works with Tasmota core ESP8266 V.2.7.4.9 - - [ ] The code change is tested and works with Tasmota core ESP32 V.1.0.7.5 + - [ ] The code change is tested and works with Tasmota core ESP32 V.2.0.1.1 - [ ] I accept the [CLA](https://github.com/arendst/Tasmota/blob/development/CONTRIBUTING.md#contributor-license-agreement-cla). _NOTE: The code change must pass CI tests. **Your PR cannot be merged unless tests pass**_ diff --git a/.github/workflows/Tasmota_build_devel.yml b/.github/workflows/Tasmota_build_devel.yml index e7c98decd..fe3f995d1 100644 --- a/.github/workflows/Tasmota_build_devel.yml +++ b/.github/workflows/Tasmota_build_devel.yml @@ -1,9 +1,9 @@ -name: Build_firmware_devel +name: Build_firmware_development_cache on: workflow_dispatch: # Manually start a workflow push: - branches: test # Dummy branch run only manually for testing! + branches: development paths-ignore: - '.github/**' # Ignore changes towards the .github directory - '**.md' # Do no build if *.md files changes @@ -1324,7 +1324,6 @@ jobs: runs-on: ubuntu-latest continue-on-error: true steps: - - uses: actions/checkout@v2 - uses: actions/download-artifact@v2 with: name: firmware @@ -1361,30 +1360,33 @@ jobs: [ ! -f ./mv_firmware/firmware/* ] || mv ./mv_firmware/firmware/* ./firmware/tasmota/languages/ - name: Display files to transfer run: ls -R ./* + - name: Push Firmware files to tmp_copy repo + uses: Jason2866/copy_file_to_another_repo_action@main + env: + API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }} + with: + source_file: 'firmware' + destination_repo: 'arendst/tmp_copy' + destination_branch: 'firmware' + user_email: 'github-actions@github.com' + user_name: 'github-actions' - - name: Push Firmware files to https://github.com/arendst/Tasmota-firmware - run: | - git config user.name "Platformio BUILD" - git config user.email github-actions@github.com - git switch -c work - git remote add -f Tasmota "https://github.com/arendst/Tasmota-firmware.git" --track main - git rm -r --cached . - git add -f ./firmware/* - git commit -m ${GITHUB_SHA} - git merge Tasmota-firmware/main --allow-unrelated-histories - git push -u origin main - + Start_final_copy: + needs: Upload + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 - name: Creat trigger.txt run: | echo ${GITHUB_SHA} &> trigger.txt echo "$(begin(speed, config, m_rx_pin, m_tx_pin); - if (serial_buffer_size > 256) { + if (serial_buffer_size > 256) { // RX Buffer can't be resized when Serial is already running (HardwareSerial.cpp) TSerial->setRxBufferSize(serial_buffer_size); } + 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); + } } else { m_valid = false; } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.gitattributes b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.gitattributes new file mode 100644 index 000000000..05945c4fb --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.gitattributes @@ -0,0 +1,3 @@ +# Directories & files to ignore from release archives +docs export-ignore +assets export-ignore diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/CONTRIBUTING.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/CONTRIBUTING.md index 20bb97d94..87fd34fc1 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/CONTRIBUTING.md +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/CONTRIBUTING.md @@ -71,7 +71,7 @@ Include details about your configuration, circuit and environment: * Avoid platform-dependent code. * Use c98 types where possible for better portablity. * In almost all cases, code & documentation should be peer-reviewed by at least one other contributor. -* The code should pass all the existing testing infrastructure in Travis. e.g. Unit tests, cpplint, and basic compilation. +* The code should pass all the existing testing infrastructure in GitHub Actions. e.g. Unit tests, cpplint, and basic compilation etc. * State if you have tested this under real conditions if you have, and what other tests you may have carried out. ### Git Commit Messages diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/Contributors.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/Contributors.md index 811bfea84..afa0a51e9 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/Contributors.md +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/Contributors.md @@ -18,6 +18,7 @@ - [Mark Kuchel](https://github.com/kuchel77) - [Christian Nilsson](https://github.com/NiKiZe) - [Zhongxian Li](https://github.com/siriuslzx) +- [Davide Depau](https://github.com/Depau) All contributors can be found on the [contributors site](https://github.com/crankyoldgit/IRremoteESP8266/graphs/contributors). diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/ISSUE_TEMPLATE/problem-report.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/ISSUE_TEMPLATE/problem-report.md new file mode 100644 index 000000000..1f1556781 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/ISSUE_TEMPLATE/problem-report.md @@ -0,0 +1,57 @@ +--- +name: Problem report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +### Version/revision of the library used +_Typically located in the `library.json` & `src/IRremoteESP8266.h` files in the root directory of the library. +e.g. v2.0.0, or 'master' as at 1st of June, 2017. etc._ + +### Describe the bug +A clear and concise description of what the bug is. + +#### To Reproduce +_What steps did you do, and what did or didn't actually happen? How can we reproduce the issue?_ + +_e.g._ +_1. Initialise the IRsend class._ +_2. `IRsend.sendFoobar(0xdeadbeef);`_ +_3. Foobar BBQ went into Cow(er)-saving mode and fried me a couple of eggs instead._ + +#### Example code used +_Include all relevant code snippets or links to the actual code files. Tip: [How to quote your code so it is still readable in the report](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code)._ + +#### Expected behaviour +_What steps did you do and what should it have done? A clear and concise description of what you expected to happen._ + +_e.g._ +_1. Initialise the IRsend class._ +_2. `IRsend.sendFoobar(0xdeadbeef);`_ +_3. Foobar branded BBQ turns on and cooks me some ribs._ + +#### Output of raw data from [IRrecvDumpV2.ino](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/examples/IRrecvDumpV2/IRrecvDumpV2.ino) or [V3](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/examples/IRrecvDumpV3/) (if applicable) +_Include some serial text of the raw dumps of what the device saw._ + +_**Note**: Output from Tasmota is not acceptable. We can't easily use their raw format._ + + +### What brand/model IR demodulator are you using? +_Brand/Model code_ or _None_ + +_If VS1838b: That is likely your problem. Please buy a better one & try again. Reporting a capture or decode issue when you use one of these is effectively wasting our & your time. See the [FAQ](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Frequently-Asked-Questions#Help_Im_getting_very_inconsistent_results_when_capturing_an_IR_message_using_a_VS1838b_IR_demodulator)_ + +### Circuit diagram and hardware used (if applicable) +_Link to an image of the circuit diagram used. Part number of the IR receiver module etc. ESP8266 or ESP32 board type._ + +### I have followed the steps in the [Troubleshooting Guide](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Troubleshooting-Guide) & read the [FAQ](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Frequently-Asked-Questions) +_Yes/No._ + +### Has this library/code previously worked as expected for you? +_Yes/No. If "Yes", which version last worked for you?_ + +### Other useful information +_More information is always welcome. Be verbose._ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/issue_template.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/issue_template.md deleted file mode 100644 index f0ecf1fba..000000000 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/issue_template.md +++ /dev/null @@ -1,47 +0,0 @@ -_(Please use this template for reporting issues. You can delete what ever is not relevant. Giving us this information will help us help you faster. Please also read the [FAQ](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Frequently-Asked-Questions) & [Troubleshooting Guide](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Troubleshooting-Guide). Your problem may already have an answer there.)_ - -### Version/revision of the library used -_Typically located in the `library.json` & `src/IRremoteESP8266.h` files in the root directory of the library. -e.g. v2.0.0, or 'master' as at 1st of June, 2017. etc._ - -### Expected behavior -_What steps did you do and what should it have done?_ - -e.g. -1. Initialise the IRsend class. -2. IRsend.sendFoobar(0xdeadbeef); -3. Foobar branded BBQ turns on and cooks me some ribs. - -### Actual behavior -_What steps did you do, and what did or didn't actually happen?_ - -e.g. -1. Initialise the IRsend class. -2. IRsend.sendFoobar(0xdeadbeef); -3. Foobar BBQ went into Cow(er)-saving mode and fried me a couple of eggs instead. - -#### Output of raw data from IRrecvDumpV2.ino (if applicable) -_Include some raw dumps of what the device saw._ - -### What brand/model IR demodulator are you using? -_Brand/Model code_ or _None_ - -_If VS1838b: That is likely your problem. Please buy a better one & try again. Reporting a capture or decode issue when you use one of these is effectively wasting our & your time. See the [FAQ](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Frequently-Asked-Questions#Help_Im_getting_very_inconsistent_results_when_capturing_an_IR_message_using_a_VS1838b_IR_demodulator)_ - -### Steps to reproduce the behavior -_What can we do to (pref. reliably) repeat what is happening?_ - -#### Example code used -_Include all relevant code snippets or links to the actual code files. Tip: [How to quote your code so it is still readable](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code)._ - -#### Circuit diagram and hardware used (if applicable) -_Link to an image of the circuit diagram used. Part number of the IR receiver module etc. ESP8266 or ESP32 board type._ - -### I have followed the steps in the [Troubleshooting Guide](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Troubleshooting-Guide) & read the [FAQ](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Frequently-Asked-Questions) -_Yes/No._ - -### Has this library/code previously worked as expected for you? -_Yes/No. If "Yes", which version last worked for you?_ - -### Other useful information -_More information is always welcome. Be verbose._ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/Build.yml b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/Build.yml new file mode 100644 index 000000000..5c0e5907c --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/Build.yml @@ -0,0 +1,37 @@ +name: Build + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + Build_Examples: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + - name: Cache PlatformIO + uses: actions/cache@v2 + with: + path: ~/.platformio + key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} + - name: Set up Python + uses: actions/setup-python@v2 + - name: Install PlatformIO + run: | + python -m pip install --upgrade pip + pip install --upgrade platformio + - name: Build all the examples + env: + PLATFORMIO_BUILD_CACHE_DIR: "../../.pio/buildcache" + run: find . -name platformio.ini -type f | sed 's,/platformio.ini$,,' | xargs --verbose -n 1 pio run --jobs 2 --project-dir diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/Documentation.yml b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/Documentation.yml new file mode 100644 index 000000000..e7520577c --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/Documentation.yml @@ -0,0 +1,15 @@ +# This is a basic workflow that is triggered on push/PRs to the master branch. + +name: Documentation + +# Controls when the action will run. Workflow runs when manually triggered using the UI +# or API. +on: [push, pull_request] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + Doxygen: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: mattnotmitt/doxygen-action@v1 diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/Lint.yml b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/Lint.yml new file mode 100644 index 000000000..a0f7664d9 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/Lint.yml @@ -0,0 +1,28 @@ +name: Code Lint + +on: [push, pull_request] + +jobs: + Linters: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.9 + uses: actions/setup-python@v2 + with: + python-version: 3.9 + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pylint + pip install cpplint + - name: Analysing the code with pylint + run: | + shopt -s nullglob + pylint -d F0001 {src,test,tools}/*.py + - name: Analysing the code with cpplint + run: | + shopt -s nullglob + cpplint --extensions=c,cc,cpp,ino --headers=h,hpp {src,src/locale,test,tools}/*.{h,c,cc,cpp,hpp,ino} examples/*/*.{h,c,cc,cpp,hpp,ino} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/MetaChecks.yml b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/MetaChecks.yml new file mode 100644 index 000000000..2866ffc37 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/MetaChecks.yml @@ -0,0 +1,54 @@ +# This is a basic workflow that is triggered on push/PRs to the master branch. + +name: Library Linter + +# Controls when the action will run. Workflow runs when manually triggered using the UI +# or API. +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + arduino-library-manager-lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: arduino/arduino-lint-action@v1 + with: + library-manager: update + compliance: strict + # Detect case-insensitive file duplication in the same directory. + # This can cause a problem for the Arduino IDE on Windows & Macs. + # See: + # - https://github.com/arduino/Arduino/issues/11441 + # - https://github.com/crankyoldgit/IRremoteESP8266/issues/1451 + detect-duplicate-files: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Look for case-insensitive filename collisions. + run: DUPS=$(find . -path '*/.pio' -prune -o -print | sort | uniq -D -i); if [[ -n "${DUPS}" ]]; then echo -e "Duplicates found:\n${DUPS}"; false; fi + version-number-consitent: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Check all the version numbers match. + run: | + LIB_VERSION=$(egrep "^#define\s+_IRREMOTEESP8266_VERSION_\s+" src/IRremoteESP8266.h | cut -d\" -f2) + test ${LIB_VERSION} == "$(jq -r .version library.json)" + grep -q "^version=${LIB_VERSION}$" library.properties + examples-have-platformio_ini: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Check that every example directory has a platformio.ini file. + run: (status=0; for dir in examples/*; do if [[ ! -f "${dir}/platformio.ini" ]]; then echo "${dir} has no 'platform.ini' file!"; status=1; fi; done; exit ${status}) + supported-devices-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Check that all files have supported sections. + run: (SUPPORTED_OUTPUT=$(python3 tools/scrape_supported_devices.py --noout --alert 2>&1); if [[ $? -ne 0 || -n "${SUPPORTED_OUTPUT}" ]]; then echo "${SUPPORTED_OUTPUT}"; exit 1; fi) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/UnitTests.yml b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/UnitTests.yml new file mode 100644 index 000000000..bbc486b18 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/UnitTests.yml @@ -0,0 +1,23 @@ +name: Tests + +on: [push, pull_request] + +jobs: + Unit_Tests: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Install the Google test suite + env: + MAKEFLAGS: "-j 2" + run: (cd test; make install-googletest) + - name: Build and run the library unit tests. + env: + MAKEFLAGS: "-j 2" + run: (cd test; make run) + - name: Build and run the tools unit tests. + env: + MAKEFLAGS: "-j 2" + run: (cd tools; make all; make run_tests) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.gitignore b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.gitignore index c02171953..a73bc8b00 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.gitignore +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.gitignore @@ -22,7 +22,7 @@ examples/**/lib examples/**/.travis.yml examples/**/.gitignore lib/readme.txt -lib/googletest/**/* +lib/googletest/ # GCC pre-compiled headers. **/*.gch diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.gitmodules b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.gitmodules deleted file mode 100644 index c28fe0509..000000000 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "lib/googletest"] - path = lib/googletest - url = https://github.com/google/googletest.git - branch = v1.8.x diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.travis.yml b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.travis.yml deleted file mode 100644 index 704004f68..000000000 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.travis.yml +++ /dev/null @@ -1,69 +0,0 @@ -language: c -addons: - apt: - packages: - - jq - - doxygen - - graphviz - - python3 - - python3-pip - - pylint3 - - python3-setuptools -env: - - PLATFORMIO_BUILD_CACHE_DIR="../../.pio/buildcache" - IRRECVDUMP_RE=".*IRrecvDumpV.*" - IRMQTTSERVER_RE=".*IRMQTTServer.*" - MAKEFLAGS="-j 2" -cache: - directories: - - "~/.platformio" -before_install: - - wget https://raw.githubusercontent.com/google/styleguide/gh-pages/cpplint/cpplint.py - - python --version && pip --version - - python3 --version && pip3 --version - - sudo pip3 install -U platformio - - pio update -script: echo Running checks -notifications: - email: - on_success: change - on_failure: change -jobs: - include: - - name: "Compile the trivial examples" - script: - # Check that everything compiles but some heavy tasks e.g. IRMQTTServer & IRrecvDumpV2+ - # i.e. We are splitting the work load in to parallel tasks. - - find . -regextype egrep -name platformio.ini -type f \! -regex "${IRRECVDUMP_RE}|${IRMQTTSERVER_RE}" | sed 's,/platformio.ini$,,' | xargs --verbose -n 1 pio run --jobs 2 --project-dir - - name: "Compile the IRrecvDumpV2+ examples" - script: - # Check that IRrecvDumpV2+ compiles. - # i.e. We are splitting the work load in to parallel tasks. - - find . -regextype egrep -name platformio.ini -type f -regex "${IRRECVDUMP_RE}" | sed 's,/platformio.ini$,,' | xargs --verbose -n 1 pio run --jobs 2 --project-dir - - name: "Unit tests, Linter, Doc checks, & Compile IRMQTTServer" - script: - # Run all the Tests & check the code linters have no issues, and that - # IRMQTTServer compiles. - # i.e. We are splitting the work load in to parallel tasks. - # Check the version numbers match. - - LIB_VERSION=$(egrep "^#define\s+_IRREMOTEESP8266_VERSION_\s+" src/IRremoteESP8266.h | cut -d\" -f2) - - test ${LIB_VERSION} == "$(jq -r .version library.json)" - - grep -q "^version=${LIB_VERSION}$" library.properties - # Check the tools programs compile. - - (cd tools; make all) - # Check for lint issues. - - shopt -s nullglob - - python cpplint.py --extensions=c,cc,cpp,ino --headers=h,hpp {src,src/locale,test,tools}/*.{h,c,cc,cpp,hpp,ino} examples/*/*.{h,c,cc,cpp,hpp,ino} - - pylint3 -d F0001 {src,test,tools}/*.py - - shopt -u nullglob - # Build and run the unit tests. - - (cd test; make run) - - (cd tools; make run_tests) - # Check that every example directory has a platformio.ini file. - - (status=0; for dir in examples/*; do if [[ ! -f "${dir}/platformio.ini" ]]; then echo "${dir} has no 'platform.ini' file!"; status=1; fi; done; exit ${status}) - # Check that doxygen completes without errors or warnings. - - (DOXYGEN_OUTPUT=$(doxygen 2>&1); if [[ $? -ne 0 || -n "${DOXYGEN_OUTPUT}" ]]; then echo "${DOXYGEN_OUTPUT}"; exit 1; fi) - # Check that all files has supported sections. - - (SUPPORTED_OUTPUT=$(python3 tools/scrape_supported_devices.py --noout --alert 2>&1); if [[ $? -ne 0 || -n "${SUPPORTED_OUTPUT}" ]]; then echo "${SUPPORTED_OUTPUT}"; exit 1; fi) - # Check that IRMQTTServer compiles. - - find . -regextype egrep -name platformio.ini -type f -regex "${IRMQTTSERVER_RE}" | sed 's,/platformio.ini$,,' | xargs --verbose -n 1 pio run --jobs 2 --project-dir diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README.md index 5dae9cfd9..90fd8d4c8 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README.md +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README.md @@ -10,8 +10,8 @@ This library enables you to **send _and_ receive** infra-red signals on an [ESP8266](https://github.com/esp8266/Arduino) or an [ESP32](https://github.com/espressif/arduino-esp32) using the [Arduino framework](https://www.arduino.cc/) using common 940nm IR LEDs and common IR receiver modules. e.g. TSOP{17,22,24,36,38,44,48}* demodulators etc. -## v2.7.20 Now Available -Version 2.7.20 of the library is now [available](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). You can view the [Release Notes](ReleaseNotes.md) for all the significant changes. +## v2.8.0 Now Available +Version 2.8.0 of the library is now [available](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). You can view the [Release Notes](ReleaseNotes.md) for all the significant changes. #### Upgrading from pre-v2.0 Usage of the library has been slightly changed in v2.0. You will need to change your usage to work with v2.0 and beyond. You can read more about the changes required on our [Upgrade to v2.0](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Upgrading-to-v2.0) page. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README_de.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README_de.md index 51ded0420..4dbd835c4 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README_de.md +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README_de.md @@ -11,8 +11,8 @@ Diese Programmbibliothek ermöglicht das **Senden _und_ Empfangen** von Infrarotsignalen mit [ESP8266](https://github.com/esp8266/Arduino)- und [ESP32](https://github.com/espressif/arduino-esp32)-Mikrocontrollern mithilfe des [Arduino-Frameworks](https://www.arduino.cc/) und handelsüblichen 940nm Infrarot-LEDs undIR-Empfängermodulen, wie zum Beispiel TSOP{17,22,24,36,38,44,48}*-Demodulatoren. -## v2.7.20 jetzt verfügbar -Version 2.7.20 der Bibliothek ist nun [verfügbar](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). Die [Versionshinweise](ReleaseNotes.md) enthalten alle wichtigen Neuerungen. +## v2.8.0 jetzt verfügbar +Version 2.8.0 der Bibliothek ist nun [verfügbar](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). Die [Versionshinweise](ReleaseNotes.md) enthalten alle wichtigen Neuerungen. #### Hinweis für Nutzer von Versionen vor v2.0 Die Benutzung der Bibliothek hat sich mit Version 2.0 leicht geändert. Einige Anpassungen im aufrufenden Code werden nötig sein, um mit Version ab 2.0 korrekt zu funktionieren. Mehr zu den Anpassungen finden sich auf unserer [Upgrade to v2.0](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Upgrading-to-v2.0)-Seite. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README_fr.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README_fr.md index fe314c459..d7033c093 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README_fr.md +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/README_fr.md @@ -10,8 +10,8 @@ Cette librairie vous permetra de **recevoir et d'envoyer des signaux** infrarouge sur le protocole [ESP8266](https://github.com/esp8266/Arduino) ou sur le protocole [ESP32](https://github.com/espressif/arduino-esp32) en utilisant le [Arduino framework](https://www.arduino.cc/) qui utilise la norme 940nm IR LEDs et le module basique de reception d'onde IR. Exemple : TSOP{17,22,24,36,38,44,48}* modules etc. -## v2.7.20 disponible -Version 2.7.20 de la libraire est maintenant [disponible](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). Vous pouvez voir le [Release Notes](ReleaseNotes.md) pour tous les changements importants. +## v2.8.0 disponible +Version 2.8.0 de la libraire est maintenant [disponible](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). Vous pouvez voir le [Release Notes](ReleaseNotes.md) pour tous les changements importants. #### mise à jour depuis pre-v2.0 L'utilisation de la librairie à un peu changer depuis la version in v2.0. Si vous voulez l'utiliser vous devrez changer votre utilisation aussi. Vous pouvez vous renseigner sur les précondition d'utilisation ici : [Upgrade to v2.0](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Upgrading-to-v2.0) page. diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/ReleaseNotes.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/ReleaseNotes.md index f5bc0f66a..0f41b562d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/ReleaseNotes.md +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/ReleaseNotes.md @@ -1,5 +1,73 @@ # Release Notes +## _v2.8.0 (20211119)_ + +**[Bug Fixes]** +- Fix compilation issue when using old 8266 Arduino Frameworks. (#1639 #1640) +- Fix potential security issue with `scrape_supported_devices.py` (#1616 #1619) + +**[Features]** +- SAMSUNG_AC + - Change `clean` setting to a toggle. (#1676 #1677) + - Highest fan speed is available without Powerful setting. (#1675 #1678) + - Change `beep` setting to a toggle. (#1669 #1671) + - Fix Beep for AR12TXEAAWKNEU (#1668 #1669) + - Add support for Horizontal Swing & Econo (#1277 #1667) + - Add support for On, Off, & Sleep Timers (#1277 #1662) + - Fix power control. Clean-up code & bitmaps from Checksum changes. (#1277 #1648 #1650) +- HAIER_AC176/HAIER_AC_YRW02 + - Add support A/B unit setting (#1672) + - Add support degree Fahrenheit (#1659) + - Add support `Lock` function (#1652) + - Implement horizontal swing feature (#1641) + - Implement Quiet setting. (#1634 #1635) +- Basic support for Airton Protocol (#1670 #1681) +- HAIER_AC176: Add Turbo and Quiet settings (#1634) +- Gree: Add `SwingH` & `Econo` control. (#1587 #1653) +- MIRAGE + - Add experimental detailed support. (#1573 #1615) + - Experimental detailed support for KKG29A-C1 remote. (#1573 #1660) +- ELECTRA_AC: Add support for "IFeel" & Sensor settings. (#1644 #1645) +- Add Russian translation (#1649) +- Add Swedish translation (#1627) +- Reduce flash space used. (#1633) +- Strings finally in Flash! (#1493 #1614 #1623) +- Add support for Rhoss Idrowall MPCV 20-30-35-40 A/C protocol (#1630) +- Make `IRAc::opmodeToString()` output nicer for humans. (#1613) +- TCL112AC/TEKNOPOINT: Add support for `GZ055BE1` model (#1486 #1602) +- Support for Arris protocol. (#1598) +- SharpAc: Allow position control of SwingV (#1590 #1594) + +**[Misc]** +- HAIER_AC176/HAIER_AC_YRW02 + - Replace some magic numbers with constants (#1679) + - Small fix `Quiet` and `Turbo` test (#1674) + - Fix `IRHaierAC176::getTemp()` return value description (#1663) +- Security Policy creation and changes. (#1616 #1617 #1618 #1621 #1680) +- IRrecvDumpV2/3: Update PlatformIO envs for missing languages (#1661) +- IRMQTTServer + - Use the correct string for Fan mode in Home Assistant. (#1610 #1657) + - Move a lot of the strings/text to flash. (#1638) +- Minor code style improvements. (#1656) +- Update Supported Devices + - HAIER_AC176 (#1673) + - LG A/C (#1651 #1655) + - Symphony (#1603 #1605) + - Epson (#1574 #1601) + - GREE (#1587 #1588) + - SharpAc (#1590 #1591) +- Add extra tests for LG2 protocol (#1654) +- Fix parameter expansion in several macros. +- Move some strings to `IRtext.cpp` & `locale/default.h` (#1637) +- RHOSS: Move include and defines to their correct places (#1636) +- Make makefile only build required files when running `run-%` target (#1632) +- Update Portuguese translation (#1628) +- Add possibility to run specific test case (#1625) +- Change `googletest` library ignore (#1626) +- Re-work "Fan Only" strings & matching. (#1610) +- Address `C0209` pylint warnings. (#1608) + + ## _v2.7.20 (20210828)_ **[Bug Fixes]** diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/SECURITY.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/SECURITY.md new file mode 100644 index 000000000..c98300789 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/SECURITY.md @@ -0,0 +1,3 @@ +# Security Policy + +You can find this library's Security Policy and contact procedure at https://crankyoldgit.github.io/IRremoteESP8266/SECURITY diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/SupportedProtocols.md b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/SupportedProtocols.md index 348a6d641..cf960a0eb 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/SupportedProtocols.md +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/SupportedProtocols.md @@ -1,14 +1,16 @@ + Last generated: Fri 19 Nov 2021 00:35:37 +0000 ---> # IR Protocols supported by this library | Protocol | Brand | Model | A/C Model | Detailed A/C Support | | --- | --- | --- | --- | --- | +| [Airton](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Airton.cpp) | **Airton** | RD1A1 remote
SMVH09B-2A2A3NH ref. 409730 A/C | | - | | [Airwell](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Airwell.cpp) | **[Airwell](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Airwell.h)** | DLS 21 DCI R410 AW A/C
RC04 remote
RC08W remote | | Yes | | [Aiwa](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Aiwa.cpp) | **Aiwa** | RC-T501 RCU | | - | | [Amcor](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Amcor.cpp) | **[Amcor](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Amcor.h)** | ADR-853H A/C
TAC-444 remote
TAC-495 remote | | Yes | | [Argo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Argo.cpp) | **[Argo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Argo.h)** | Ulisse 13 DCI Mobile Split A/C | | Yes | +| [Arris](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Arris.cpp) | **Arris** | 120A V1.0 A18 remote
VIP1113M Set-top box | | - | | [Bose](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Bose.cpp) | **Bose** | Bose TV Speaker | | - | | [Carrier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Carrier.cpp) | **[Carrier/Surrey](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Carrier.h)** | 42QG5A55970 remote
53NGK009/012 Inverter
619EGX0090E0 A/C
619EGX0120E0 A/C
619EGX0180E0 A/C
619EGX0220E0 A/C | | Yes | | [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Airwell](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | RC08B remote | | Yes | @@ -26,11 +28,13 @@ | [Doshisha](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Doshisha.cpp) | **Doshisha** | CZ-S32D LED Light
CZ-S38D LED Light
CZ-S50D LED Light
RCZ01 remote | | - | | [Ecoclim](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Ecoclim.cpp) | **[EcoClim](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Ecoclim.h)** | HYSFR-P348 remote
ZC200DPO A/C | | Yes | | [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[AUX](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | KFR-35GW/BpNFW=3 A/C
YKR-T/011 remote | | Yes | +| [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[Centek](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | SCT-65Q09 A/C
YKR-P/002E remote | | Yes | | [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | Classic INV 17 / AXW12DCS A/C
YKR-M/003E remote | | Yes | | [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[Frigidaire](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | FGPC102AB1 A/C | | Yes | +| [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[Subtropic](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | SUB-07HN1_18Y A/C
YKR-H/102E remote | | Yes | | [EliteScreens](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_EliteScreens.cpp) | **Elite Screens** | CineTension2 / CineTension3 series
Home2 / Home3 series
Spectrum series
VMAX Plus4 series
VMAX2 / VMAX2 Plus series
ZSP-IR-B / ZSP-IR-W remote | | - | | [EliteScreens](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_EliteScreens.cpp) | **Lumene Screens** | Embassy | | - | -| [Epson](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Epson.cpp) | **Epson** | EN-TW9100W Projector | | - | +| [Epson](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Epson.cpp) | **Epson** | EN-TW9100W Projector
EX3220 Projector
EX5220 Projector
EX5230 Projector
EX6220 Projector
EX7220 Projector
VS230 Projector
VS330 Projector | | - | | [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AGTV14LAC A/C (ARRAH2E)
AR-DB1 remote (ARDB1)
AR-DL10 remote (ARDB1)
AR-RAC1E remote (ARRAH2E)
AR-RAE1E remote (ARRAH2E)
AR-RAH1U remote (ARREB1E)
AR-RAH2E remote (ARRAH2E)
AR-REB1E remote (ARREB1E)
AR-REW4E remote (ARREW4E)
AR-RY4 remote (ARRY4)
AST9RSGCW A/C (ARDB1)
ASTB09LBC A/C (ARRY4)
ASU12RLF A/C (ARREB1E)
ASU30C1 A/C (ARDB1)
ASYG09KETA-B A/C (ARREW4E)
ASYG30LFCA A/C (ARRAH2E)
ASYG7LMCA A/C (ARREB1E) | ARDB1
ARJW2
ARRAH2E
ARREB1E
ARREW4E
ARRY4 | Yes | | [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu General](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AOHG09LLC A/C (ARRAH2E)
AR-JW2 remote (ARJW2)
AR-RCE1E remote (ARRAH2E)
ASHG09LLCA A/C (ARRAH2E) | ARDB1
ARJW2
ARRAH2E
ARREB1E
ARREW4E
ARRY4 | Yes | | [GICable](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_GICable.cpp) | **G.I. Cable** | XRC-200 remote | | - | @@ -39,11 +43,13 @@ | [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Amana](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | PBC093G00CC A/C
YX1FF remote | YAW1F
YBOFB | Yes | | [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Cooper & Hunter](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | CH-S09FTXG A/C
YB1F2 remote | YAW1F
YBOFB | Yes | | [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[EKOKAI](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | A/C | YAW1F
YBOFB | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | YAA1FBF remote
YB1F2F remote | YAW1F
YBOFB | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | VIR09HP115V1AH A/C
VIR12HP230V1AH A/C
YAA1FBF remote
YAN1F1 remote
YB1F2F remote | YAW1F
YBOFB | Yes | | [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Green](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | YBOFB remote
YBOFB2 remote | YAW1F
YBOFB | Yes | | [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[RusClimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | EACS/I-09HAR_X/N3 A/C
YAW1F remote | YAW1F
YBOFB | Yes | | [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Ultimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | Heat Pump | YAW1F
YBOFB | Yes | -| [Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.cpp) | **[Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.h)** | HSU-09HMC203 A/C (HAIER_AC_YRW02)
HSU07-HEA03 remote (HAIER_AC)
YR-W02 remote (HAIER_AC_YRW02) | | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Vailland](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | VAI5-035WNI A/C
YACIFB remote | YAW1F
YBOFB | Yes | +| [Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.cpp) | **[Daichi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.h)** | D-H A/C (HAIER_AC176) | | Yes | +| [Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.cpp) | **[Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.h)** | HSU-09HMC203 A/C (HAIER_AC_YRW02)
HSU07-HEA03 remote (HAIER_AC)
V9014557 M47 8D remote (HAIER_AC176)
YR-W02 remote (HAIER_AC_YRW02) | | Yes | | [Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.cpp) | **[Mabe](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.h)** | MMI18HDBWCA6MI8 A/C (HAIER_AC176)
V12843 HJ200223 remote (HAIER_AC176) | | Yes | | [Hitachi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Hitachi.cpp) | **[Hitachi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Hitachi.h)** | KAZE-312KSDP A/C (HITACHI_AC1)
LT0541-HTA remote (HITACHI_AC1)
PC-LH3B (HITACHI_AC3)
R-LT0541-HTA/Y.K.1.1-1 V2.3 remote (HITACHI_AC1)
RAR-8P2 remote (HITACHI_AC424)
RAS-22NK A/C (HITACHI_AC344)
RAS-35THA6 remote
RAS-AJ25H A/C (HITACHI_AC424)
RF11T1 remote (HITACHI_AC344)
Series VI A/C (Circa 2007) (HITACHI_AC1) | | Yes | | [Inax](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Inax.cpp) | **Lixil** | Inax DT-BA283 Toilet | | - | @@ -53,7 +59,7 @@ | [Kelvinator](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.cpp) | **[Kelvinator](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.h)** | KSV26CRC A/C
KSV26HRC A/C
KSV35CRC A/C
KSV35HRC A/C
KSV53HRC A/C
KSV62HRC A/C
KSV70CRC A/C
KSV70HRC A/C
KSV80HRC A/C
YALIF Remote | | Yes | | [Kelvinator](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.cpp) | **[Sharp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.h)** | A5VEY A/C
YB1FA remote | | Yes | | [LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.cpp) | **[General Electric](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.h)** | 6711AR2853M A/C Remote (LG)
AG1BH09AW101 Split A/C (LG) | | Yes | -| [LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.cpp) | **[LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.h)** | 6711A20083V remote (LG)
A4UW30GFA2 A/C (LG2 - AKB74955603 & AKB73757604)
AKB73757604 remote (LG2 - AKB73757604)
AKB74395308 remote (LG2)
AKB74955603 remote (LG2 - AKB74955603)
AKB75215403 remote (LG2)
AMNW09GSJA0 A/C (LG2 - AKB74955603)
AMNW24GTPA1 A/C (LG2 - AKB73757604)
S4-W12JA3AA A/C (LG2) | | Yes | +| [LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.cpp) | **[LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.h)** | 6711A20083V remote (LG)
A4UW30GFA2 A/C (LG2 - AKB74955603 & AKB73757604)
AKB73315611 remote (LG2 - AKB74955603)
AKB73757604 remote (LG2 - AKB73757604)
AKB74395308 remote (LG2)
AKB74955603 remote (LG2 - AKB74955603)
AKB75215403 remote (LG2)
AMNW09GSJA0 A/C (LG2 - AKB74955603)
AMNW24GTPA1 A/C (LG2 - AKB73757604)
MS05SQ NW0 A/C (LG2 - AKB74955603)
S4-W12JA3AA A/C (LG2) | | Yes | | [Lasertag](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Lasertag.cpp) | **Lasertag** | Phaser emitters | | - | | [Lego](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Lego.cpp) | **LEGO Power Functions** | IR Receiver | | - | | [Lutron](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Lutron.cpp) | **Lutron** | MIR-ITFS remote
MIR-ITFS-F remote
MIR-ITFS-LF remote
SP-HT remote | | - | @@ -69,7 +75,9 @@ | [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Pioneer System](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RG66B6(B)/BGEFU1 remote (MIDEA)
RUBO18GMFILCAD A/C (18K BTU) (MIDEA)
RYBO12GMFILCAD A/C (12K BTU) (MIDEA)
UB018GMFILCFHD A/C (12K BTU) (MIDEA)
WS012GMFI22HLD A/C (12K BTU) (MIDEA)
WS018GMFI22HLD A/C (12K BTU) (MIDEA) | | Yes | | [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Trotec](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RG57H(B)/BGE remote (MIDEA)
TROTEC PAC 3900 X (MIDEA) | | Yes | | [MilesTag2](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_MilesTag2.cpp) | **Milestag2** | Various | | - | -| [Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.cpp) | **Mirage** | VLU series A/C | | - | +| [Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.cpp) | **[Maxell](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.h)** | KKG9A-C1 remote
MX-CH18CF A/C | KKG29AC1
KKG9AC1 | Yes | +| [Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.cpp) | **[Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.h)** | VLU series A/C | KKG29AC1
KKG9AC1 | Yes | +| [Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.cpp) | **[Tronitechnik](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.h)** | KKG29A-C1 remote
Reykir 9000 A/C | KKG29AC1
KKG9AC1 | Yes | | [Mitsubishi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.cpp) | **[Mitsubishi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.h)** | HC3000 Projector (MITSUBISHI2)
KM14A 0179213 remote
MS-GK24VA A/C
TV (MITSUBISHI) | | Yes | | [Mitsubishi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.cpp) | **[Mitsubishi Electric](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.h)** | 001CP T7WE10714 remote (MITSUBISHI136)
KPOA remote (MITSUBISHI112)
MLZ-RX5017AS A/C (MITSUBISHI_AC)
MSH-A24WV A/C (MITSUBISHI112)
MSZ-GV2519 A/C (MITSUBISHI_AC)
MSZ-SF25VE3 A/C (MITSUBISHI_AC)
MSZ-ZW4017S A/C (MITSUBISHI_AC)
MUH-A24WV A/C (MITSUBISHI112)
PEAD-RP71JAA Ducted A/C (MITSUBISHI136)
RH151/M21ED6426 remote (MITSUBISHI_AC)
SG153/M21EDF426 remote (MITSUBISHI_AC)
SG15D remote (MITSUBISHI_AC) | | Yes | | [MitsubishiHeavy](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_MitsubishiHeavy.cpp) | **[Mitsubishi Heavy Industries](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_MitsubishiHeavy.h)** | RKX502A001C remote (88 bit)
RLA502A700B remote (152 bit)
SRKxxZJ-S A/C (88 bit)
SRKxxZM-S A/C (152 bit)
SRKxxZMXA-S A/C (152 bit) | | Yes | @@ -87,18 +95,21 @@ | [Pronto](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Pronto.cpp) | **Pronto** | Pronto Hex | | - | | [RC5_RC6](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_RC5_RC6.cpp) | **Philips** | RC-5X (RC5X)
Standard RC-5 (RC5)
Standard RC-6 (RC6) | | - | | [RCMM](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_RCMM.cpp) | **Microsoft** | XBOX 360 | | - | -| [Samsung](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Samsung.cpp) | **[Samsung](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Samsung.h)** | AH59-02692E Soundbar remote (SAMSUNG36)
AK59-00167A Bluray remote (SAMSUNG36)
AR09FSSDAWKNFA A/C (SAMSUNG_AC)
AR09HSFSBWKN A/C (SAMSUNG_AC)
AR12HSSDBWKNEU A/C (SAMSUNG_AC)
AR12KSFPEWQNET A/C (SAMSUNG_AC)
AR12NXCXAWKXEU A/C (SAMSUNG_AC)
BN59-01178B TV remote (SAMSUNG)
DB63-03556X003 remote
DB93-14195A remote (SAMSUNG_AC)
DB93-16761C remote
HW-J551 Soundbar (SAMSUNG36)
IEC-R03 remote
UA55H6300 TV (SAMSUNG) | | Yes | +| [Rhoss](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Rhoss.cpp) | **[Rhoss](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Rhoss.h)** | Idrowall MPCV 20-30-35-40 | | Yes | +| [Samsung](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Samsung.cpp) | **[Samsung](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Samsung.h)** | AH59-02692E Soundbar remote (SAMSUNG36)
AK59-00167A Bluray remote (SAMSUNG36)
AR09FSSDAWKNFA A/C (SAMSUNG_AC)
AR09HSFSBWKN A/C (SAMSUNG_AC)
AR12HSSDBWKNEU A/C (SAMSUNG_AC)
AR12KSFPEWQNET A/C (SAMSUNG_AC)
AR12NXCXAWKXEU A/C (SAMSUNG_AC)
AR12TXEAAWKNEU A/C (SAMSUNG_AC)
BN59-01178B TV remote (SAMSUNG)
DB63-03556X003 remote
DB93-14195A remote (SAMSUNG_AC)
DB93-16761C remote
DB96-24901C remote (SAMSUNG_AC)
HW-J551 Soundbar (SAMSUNG36)
IEC-R03 remote
UA55H6300 TV (SAMSUNG) | | Yes | | [Sanyo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sanyo.cpp) | **[Sanyo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sanyo.h)** | LC7461 transmitter IC (SANYO_LC7461)
RCS-2HS4E remote (SANYO_AC)
RCS-2S4E remote (SANYO_AC)
SA 8650B - disabled
SAP-K121AHA A/C (SANYO_AC)
SAP-K242AH A/C (SANYO_AC) | | Yes | -| [Sharp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sharp.cpp) | **[Sharp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sharp.h)** | AH-A12REVP-1 A/C (A903)
AH-AxSAY A/C (A907)
AH-PR13-GL A/C (A903)
AH-XP10NRY A/C (A903)
AY-ZP40KR A/C (A907)
CRMC-820 JBEZ remote (A903)
CRMC-A705 JBEZ remote (A705)
CRMC-A863 JBEZ remote (A903)
CRMC-A903JBEZ remote (A903)
CRMC-A907 JBEZ remote (A907)
LC-52D62U TV | A705
A903
A907 | Yes | +| [Sharp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sharp.cpp) | **[Sharp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sharp.h)** | AH-A12REVP-1 A/C (A903)
AH-AxSAY A/C (A907)
AH-PR13-GL A/C (A903)
AH-XP10NRY A/C (A903)
AY-ZP40KR A/C (A907)
CRMC-820 JBEZ remote (A903)
CRMC-A705 JBEZ remote (A705)
CRMC-A863 JBEZ remote (A903)
CRMC-A903JBEZ remote (A903)
CRMC-A907 JBEZ remote (A907)
CRMC-A950 JBEZ (A907)
LC-52D62U TV | A705
A903
A907 | Yes | | [Sherwood](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sherwood.cpp) | **Sherwood** | RC-138 remote
RD6505(B) Receiver | | - | | [Sony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sony.cpp) | **Sony** | HT-CT380 Soundbar (Uses 38kHz & 3 repeats) | | - | | [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **Blyss** | Owen-SW-5 3 Fan
WP-YK8 090218 remote | | - | | [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **SamHop** | SM3015 Fan Remote Control
SM5021 Encoder chip
SM5032 Decoder chip | | - | | [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **Satellite Electronic** | ID6 Remote
JY199I Fan driver
JY199I-L Fan driver | | - | +| [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **SilverCrest** | SSVS 85 A1 Fan | | - | | [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **Symphony** | Air Cooler 3Di | | - | | [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **Westinghouse** | 78095 Remote
Ceiling fan | | - | -| [Tcl](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[Leberg](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | LBS-TOR07 A/C | | Yes | -| [Tcl](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[TCL](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | TAC-09CHSD/XA31I A/C | | Yes | +| [Tcl](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[Leberg](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | LBS-TOR07 A/C (TAC09CHSD) | GZ055BE1
TAC09CHSD | Yes | +| [Tcl](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[TCL](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | TAC-09CHSD/XA31I A/C (TAC09CHSD) | GZ055BE1
TAC09CHSD | Yes | +| [Tcl](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[Teknopoint](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | Allegro SSA-09H A/C (GZ055BE1)
GZ-055B-E1 remote (GZ055BE1) | GZ055BE1
TAC09CHSD | Yes | | [Technibel](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Technibel.cpp) | **[Technibel](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Technibel.h)** | IRO PLUS | | Yes | | [Teco](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Teco.cpp) | **[Alaska](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Teco.h)** | SAC9010QC A/C
SAC9010QC remote | | Yes | | [Teknopoint](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Teknopoint.cpp) | **Teknopoint** | Allegro SSA-09H A/C
GZ-055B-E1 remote | | - | @@ -127,10 +138,12 @@ ## Send & decodable protocols: +- AIRTON - AIRWELL - AIWA_RC_T501 - AMCOR - ARGO +- ARRIS - BOSE - CARRIER_AC - CARRIER_AC40 @@ -202,6 +215,7 @@ - RC5X - RC6 - RCMM +- RHOSS - SAMSUNG - SAMSUNG36 - SAMSUNG_AC diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.h index 0563ac855..1d05d3691 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.h @@ -261,8 +261,8 @@ const uint16_t kMinUnknownSize = 2 * 10; #define KEY_RX_GPIO "rx" // Text for Last Will & Testament status messages. -const char* kLwtOnline = "Online"; -const char* kLwtOffline = "Offline"; +const char* const kLwtOnline = "Online"; +const char* const kLwtOffline = "Offline"; const uint8_t kHostnameLength = 30; const uint8_t kPortLength = 5; // Largest value of uint16_t is "65535". @@ -285,7 +285,7 @@ const uint16_t kJsonAcStateMaxSize = 1024; // Bytes // ----------------- End of User Configuration Section ------------------------- // Constants -#define _MY_VERSION_ "v1.5.2" +#define _MY_VERSION_ "v1.6.0" const uint8_t kRebootTime = 15; // Seconds const uint8_t kQuickDisplayTime = 2; // Seconds @@ -310,29 +310,29 @@ const int8_t kRxGpios[] = { // JSON stuff // Name of the json config file in SPIFFS. -const char* kConfigFile = "/config.json"; -const char* kMqttServerKey = "mqtt_server"; -const char* kMqttPortKey = "mqtt_port"; -const char* kMqttUserKey = "mqtt_user"; -const char* kMqttPassKey = "mqtt_pass"; -const char* kMqttPrefixKey = "mqtt_prefix"; -const char* kHostnameKey = "hostname"; -const char* kHttpUserKey = "http_user"; -const char* kHttpPassKey = "http_pass"; -const char* kCommandDelimiter = ","; +const char* const kConfigFile = "/config.json"; +const char* const kMqttServerKey = "mqtt_server"; +const char* const kMqttPortKey = "mqtt_port"; +const char* const kMqttUserKey = "mqtt_user"; +const char* const kMqttPassKey = "mqtt_pass"; +const char* const kMqttPrefixKey = "mqtt_prefix"; +const char* const kHostnameKey = "hostname"; +const char* const kHttpUserKey = "http_user"; +const char* const kHttpPassKey = "http_pass"; +const char* const kCommandDelimiter = ","; // URLs -const char* kUrlRoot = "/"; -const char* kUrlAdmin = "/admin"; -const char* kUrlAircon = "/aircon"; -const char* kUrlSendDiscovery = "/send_discovery"; -const char* kUrlExamples = "/examples"; -const char* kUrlGpio = "/gpio"; -const char* kUrlGpioSet = "/gpio/set"; -const char* kUrlInfo = "/info"; -const char* kUrlReboot = "/quitquitquit"; -const char* kUrlWipe = "/reset"; -const char* kUrlClearMqtt = "/clear_retained"; +const char* const kUrlRoot = "/"; +const char* const kUrlAdmin = "/admin"; +const char* const kUrlAircon = "/aircon"; +const char* const kUrlSendDiscovery = "/send_discovery"; +const char* const kUrlExamples = "/examples"; +const char* const kUrlGpio = "/gpio"; +const char* const kUrlGpioSet = "/gpio/set"; +const char* const kUrlInfo = "/info"; +const char* const kUrlReboot = "/quitquitquit"; +const char* const kUrlWipe = "/reset"; +const char* const kUrlClearMqtt = "/clear_retained"; #if MQTT_ENABLE const uint32_t kBroadcastPeriodMs = MQTTbroadcastInterval * 1000; // mSeconds. @@ -340,7 +340,7 @@ const uint32_t kBroadcastPeriodMs = MQTTbroadcastInterval * 1000; // mSeconds. // Default is 5 seconds per IR TX GPIOs (channels) used. const uint32_t kStatListenPeriodMs = 5 * 1000 * kNrOfIrTxGpios; // mSeconds const int32_t kMaxPauseMs = 10000; // 10 Seconds. -const char* kSequenceDelimiter = ";"; +const char* const kSequenceDelimiter = ";"; const char kPauseChar = 'P'; #if defined(ESP8266) const uint32_t kChipId = ESP.getChipId(); @@ -349,7 +349,7 @@ const uint32_t kChipId = ESP.getChipId(); const uint32_t kChipId = ESP.getEfuseMac(); // Discard the top 16 bits. #endif // ESP32 -const char* kClimateTopics = +static const char kClimateTopics[] PROGMEM = "(" KEY_PROTOCOL "|" KEY_MODEL "|" KEY_POWER "|" KEY_MODE "|" KEY_TEMP "|" KEY_FANSPEED "|" KEY_SWINGV "|" KEY_SWINGH "|" KEY_QUIET "|" KEY_TURBO "|" KEY_LIGHT "|" KEY_BEEP "|" KEY_ECONO "|" KEY_SLEEP "|" @@ -358,7 +358,7 @@ const char* kClimateTopics = "|" KEY_JSON #endif // MQTT_CLIMATE_JSON ")
"; -const char* kMqttTopics[] = { +static const char* const kMqttTopics[] = { KEY_PROTOCOL, KEY_MODEL, KEY_POWER, KEY_MODE, KEY_TEMP, KEY_FANSPEED, KEY_SWINGV, KEY_SWINGH, KEY_QUIET, KEY_TURBO, KEY_LIGHT, KEY_BEEP, KEY_ECONO, KEY_SLEEP, KEY_FILTER, KEY_CLEAN, KEY_CELSIUS, KEY_RESEND, diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.ino b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.ino index fefd743d8..180c4214c 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.ino +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRMQTTServer/IRMQTTServer.ino @@ -1,6 +1,6 @@ /* * Send & receive arbitrary IR codes via a web server or MQTT. - * Copyright David Conran 2016, 2017, 2018, 2019, 2020 + * Copyright David Conran 2016-2021 * * Copyright: * Code for this has been borrowed from lots of other OpenSource projects & @@ -252,7 +252,8 @@ * - "Middle" * - "Low" * - "Lowest" - * power_command_topic: "ir_server/ac/cmnd/power" + * # `power_command_topic` is probably not needed for most HA configurations + * # power_command_topic: "ir_server/ac/cmnd/power" * mode_command_topic: "ir_server/ac/cmnd/mode" * mode_state_topic: "ir_server/ac/stat/mode" * temperature_command_topic: "ir_server/ac/cmnd/temp" @@ -360,6 +361,12 @@ #include #include +#ifdef ESP32 +#ifdef F +#undef F +#endif // F +#define F(string) string +#endif // ESP32 using irutils::msToString; #if REPORT_VCC @@ -380,7 +387,7 @@ MDNSResponder mdns; WiFiClient espClient; WiFiManager wifiManager; bool flagSaveWifiConfig = false; -char HttpUsername[kUsernameLength + 1] = "admin"; // Default HTT username. +char HttpUsername[kUsernameLength + 1] = "admin"; // Default HTTP username. char HttpPassword[kPasswordLength + 1] = ""; // No HTTP password by default. char Hostname[kHostnameLength + 1] = "ir_server"; // Default hostname. uint16_t *codeArray; @@ -398,14 +405,14 @@ String lastClimateSource; IRrecv *irrecv = NULL; decode_results capture; // Somewhere to store inbound IR messages. int8_t rx_gpio = kDefaultIrRx; -String lastIrReceived = "None"; +String lastIrReceived = FPSTR("None"); uint32_t lastIrReceivedTime = 0; uint32_t irRecvCounter = 0; #endif // IR_RX // Climate stuff IRac *climate[kNrOfIrTxGpios]; -String channel_re = "("; // Will be built later. +String channel_re = FPSTR("("); // Will be built later. uint16_t chan = 0; // The channel to use for the aircon HTML page. TimerMs lastClimateIr = TimerMs(); // When we last sent the IR Climate mesg. @@ -416,8 +423,8 @@ bool hasClimateBeenSent = false; // Has the Climate ever been sent? #if MQTT_ENABLE PubSubClient mqtt_client(espClient); -String lastMqttCmd = "None"; -String lastMqttCmdTopic = "None"; +String lastMqttCmd = FPSTR("None"); +String lastMqttCmdTopic = FPSTR("None"); uint32_t lastMqttCmdTime = 0; uint32_t lastConnectedTime = 0; uint32_t lastDisconnectedTime = 0; @@ -654,7 +661,7 @@ String listOfTxGpios(void) { if (i) result += ", "; result += gpioToString(txGpioTable[i]); if (!found && txGpioTable[i] == getDefaultTxGpio()) { - result += " (default)"; + result += F(" (default)"); found = true; } } @@ -694,7 +701,7 @@ String htmlSelectAcStateProtocol(const String name, const decode_type_t def, break; default: html += htmlOptionItem(String(i), typeToString((decode_type_t)i), - i == def); + i == def); } } } @@ -894,7 +901,7 @@ void handleExamples(void) { #endif // EXAMPLES_ENABLE String htmlSelectBool(const String name, const bool def) { - String html = ""); for (uint16_t i = 0; i < 2; i++) html += htmlOptionItem(IRac::boolToString(i), IRac::boolToString(i), i == def); @@ -903,7 +910,7 @@ String htmlSelectBool(const String name, const bool def) { } String htmlSelectClimateProtocol(const String name, const decode_type_t def) { - String html = ""); for (uint8_t i = 1; i <= decode_type_t::kLastDecodeType; i++) { if (IRac::isProtocolSupported((decode_type_t)i)) { html += htmlOptionItem(String(i), typeToString((decode_type_t)i), @@ -915,14 +922,14 @@ String htmlSelectClimateProtocol(const String name, const decode_type_t def) { } String htmlSelectModel(const String name, const int16_t def) { - String html = ""); for (int16_t i = -1; i <= 6; i++) { String num = String(i); String text; if (i == -1) text = F("Default"); else if (i == 0) - text = F("Unknown"); + text = kUnknownStr; else text = num; html += htmlOptionItem(num, text, i == def); @@ -933,7 +940,7 @@ String htmlSelectModel(const String name, const int16_t def) { String htmlSelectUint(const String name, const uint16_t max, const uint16_t def) { - String html = ""); for (uint16_t i = 0; i < max; i++) { String num = String(i); html += htmlOptionItem(num, num, i == def); @@ -944,7 +951,7 @@ String htmlSelectUint(const String name, const uint16_t max, String htmlSelectGpio(const String name, const int16_t def, const int8_t list[], const int16_t length) { - String html = ": "); for (int16_t i = 0; i < length; i++) { String num = String(list[i]); html += htmlOptionItem(num, list[i] == kGpioUnused ? F("Unused") : num, @@ -956,7 +963,7 @@ String htmlSelectGpio(const String name, const int16_t def, } String htmlSelectMode(const String name, const stdAc::opmode_t def) { - String html = ""); for (int8_t i = -1; i <= (int8_t)stdAc::opmode_t::kLastOpmodeEnum; i++) { String mode = IRac::opmodeToString((stdAc::opmode_t)i); html += htmlOptionItem(mode, mode, (stdAc::opmode_t)i == def); @@ -966,7 +973,7 @@ String htmlSelectMode(const String name, const stdAc::opmode_t def) { } String htmlSelectFanspeed(const String name, const stdAc::fanspeed_t def) { - String html = ""); for (int8_t i = 0; i <= (int8_t)stdAc::fanspeed_t::kLastFanspeedEnum; i++) { String speed = IRac::fanspeedToString((stdAc::fanspeed_t)i); html += htmlOptionItem(speed, speed, (stdAc::fanspeed_t)i == def); @@ -976,7 +983,7 @@ String htmlSelectFanspeed(const String name, const stdAc::fanspeed_t def) { } String htmlSelectSwingv(const String name, const stdAc::swingv_t def) { - String html = ""); for (int8_t i = -1; i <= (int8_t)stdAc::swingv_t::kLastSwingvEnum; i++) { String swing = IRac::swingvToString((stdAc::swingv_t)i); html += htmlOptionItem(swing, swing, (stdAc::swingv_t)i == def); @@ -986,7 +993,7 @@ String htmlSelectSwingv(const String name, const stdAc::swingv_t def) { } String htmlSelectSwingh(const String name, const stdAc::swingh_t def) { - String html = ""); for (int8_t i = -1; i <= (int8_t)stdAc::swingh_t::kLastSwinghEnum; i++) { String swing = IRac::swinghToString((stdAc::swingh_t)i); html += htmlOptionItem(swing, swing, (stdAc::swingh_t)i == def); @@ -1030,84 +1037,85 @@ void handleAirCon(void) { String html = htmlHeader(F("Air Conditioner Control")); html += htmlMenu(); if (kNrOfIrTxGpios > 1) { - html += "
" "" - "" "
Climate #" + + "
Climate #") + htmlSelectUint(KEY_CHANNEL, kNrOfIrTxGpios, chan) + - "" + F("" "
" "
" - "
"; + "
"); } if (climate[chan] != NULL) { - html += "

Current Settings

" + html += F("

Current Settings

" "
" - "" + - "" - " +const char HTTP_SSPM_CURRENT[] PROGMEM = + "{s}" D_CURRENT "
" D_STR_PROTOCOL "" + + "") + + F("" + "" - "" + "" - "" + "" - "" + "" + F("" "" - "" - "" + "" - "" + "" - "" + "" - "" + "" - "" + "" - "" + "" - "" + "" - "" + "" - "" + "" - "" + "" + F("" "
" D_STR_PROTOCOL "") + htmlSelectClimateProtocol(KEY_PROTOCOL, climate[chan]->next.protocol) + - "
" D_STR_MODEL "" + + F("
" D_STR_MODEL "") + htmlSelectModel(KEY_MODEL, climate[chan]->next.model) + - "
" D_STR_POWER "" + + F("
" D_STR_POWER "") + htmlSelectBool(KEY_POWER, climate[chan]->next.power) + - "
" D_STR_MODE "" + + F("
" D_STR_MODE "") + htmlSelectMode(KEY_MODE, climate[chan]->next.mode) + - "
" D_STR_TEMP "" "" + "step='0.5' value='") + String(climate[chan]->next.degrees, 1) + + F("'>" "
" D_STR_FAN "" + + "
" D_STR_FAN "") + htmlSelectFanspeed(KEY_FANSPEED, climate[chan]->next.fanspeed) + - "
" D_STR_SWINGV "" + + F("
" D_STR_SWINGV "") + htmlSelectSwingv(KEY_SWINGV, climate[chan]->next.swingv) + - "
" D_STR_SWINGH "" + + F("
" D_STR_SWINGH "") + htmlSelectSwingh(KEY_SWINGH, climate[chan]->next.swingh) + - "
" D_STR_QUIET "" + + F("
" D_STR_QUIET "") + htmlSelectBool(KEY_QUIET, climate[chan]->next.quiet) + - "
" D_STR_TURBO "" + + F("
" D_STR_TURBO "") + htmlSelectBool(KEY_TURBO, climate[chan]->next.turbo) + - "
" D_STR_ECONO "" + + F("
" D_STR_ECONO "") + htmlSelectBool(KEY_ECONO, climate[chan]->next.econo) + - "
" D_STR_LIGHT "" + + F("
" D_STR_LIGHT "") + htmlSelectBool(KEY_LIGHT, climate[chan]->next.light) + - "
" D_STR_FILTER "" + + F("
" D_STR_FILTER "") + htmlSelectBool(KEY_FILTER, climate[chan]->next.filter) + - "
" D_STR_CLEAN "" + + F("
" D_STR_CLEAN "") + htmlSelectBool(KEY_CLEAN, climate[chan]->next.clean) + - "
" D_STR_BEEP "" + + F("
" D_STR_BEEP "") + htmlSelectBool(KEY_BEEP, climate[chan]->next.beep) + - "
Force resend" + + F("
Force resend") + htmlSelectBool(KEY_RESEND, false) + - "
" "" - ""; + ""); } html += htmlEnd(); server.send(200, "text/html", html); @@ -1232,124 +1240,127 @@ void handleInfo(void) { String html = htmlHeader(F("IR MQTT server info")); html += htmlMenu(); html += - "

General

" - "

Hostname: " + String(Hostname) + "
" - "IP address: " + WiFi.localIP().toString() + "
" - "MAC address: " + WiFi.macAddress() + "
" - "Booted: " + timeSince(1) + "
" + - "Version: " _MY_VERSION_ "
" + F("

General

" + "

Hostname: ") + String(Hostname) + F("
" + "IP address: ") + WiFi.localIP().toString() + F("
" + "MAC address: ") + WiFi.macAddress() + F("
" + "Booted: ") + timeSince(1) + F("
") + + F("Version: " _MY_VERSION_ "
" "Built: " __DATE__ " " __TIME__ "
" - "Period Offset: " + String(offset) + "us
" + "Period Offset: ") + String(offset) + F("us
" "IR Lib Version: " _IRREMOTEESP8266_VERSION_ "
" #if defined(ESP8266) - "ESP8266 Core Version: " + ESP.getCoreVersion() + "
" - "Free Sketch Space: " + String(maxSketchSpace() >> 10) + "k
" + "ESP8266 Core Version: ") + ESP.getCoreVersion() + F("
" + "Free Sketch Space: ") + String(maxSketchSpace() >> 10) + F("k
" #endif // ESP8266 #if defined(ESP32) - "ESP32 SDK Version: " + ESP.getSdkVersion() + "
" + "ESP32 SDK Version: ") + ESP.getSdkVersion() + F("
" #endif // ESP32 - "Cpu Freq: " + String(ESP.getCpuFreqMHz()) + "MHz
" - "Sanity Check: " + String((_sanity == 0) ? "Ok" : "FAILED") + "
" - "IR Send GPIO(s): " + listOfTxGpios() + "
" + "Cpu Freq: ") + String(ESP.getCpuFreqMHz()) + F("MHz
" + "Sanity Check: ") + String((_sanity == 0) ? F("Ok") : F("FAILED")) + + F("
" + "IR Send GPIO(s): ") + listOfTxGpios() + F("
") + irutils::addBoolToString(kInvertTxOutput, - "Inverting GPIO output", false) + "
" - "Total send requests: " + String(sendReqCounter) + "
" - "Last message sent: " + String(lastSendSucceeded ? "Ok" : "FAILED") + - " (" + timeSince(lastSendTime) + ")
" + F("Inverting GPIO output"), false) + F("
" + "Total send requests: ") + String(sendReqCounter) + F("
" + "Last message sent: ") + String(lastSendSucceeded ? F("Ok") : F("FAILED")) + + F(" (") + timeSince(lastSendTime) + F(")
" #if IR_RX - "IR Recv GPIO: " + gpioToString(rx_gpio) + + "IR Recv GPIO: ") + gpioToString(rx_gpio) + F( #if IR_RX_PULLUP " (pullup)" #endif // IR_RX_PULLUP "
" - "Total IR Received: " + String(irRecvCounter) + "
" - "Last IR Received: " + lastIrReceived + - " (" + timeSince(lastIrReceivedTime) + ")
" + "Total IR Received: ") + String(irRecvCounter) + F("
" + "Last IR Received: ") + lastIrReceived + + F(" (") + timeSince(lastIrReceivedTime) + F(")
" #endif // IR_RX - "Duplicate " D_STR_WIFI " networks: " + - String(HIDE_DUPLICATE_NETWORKS ? "Hide" : "Show") + "
" + "Duplicate " D_STR_WIFI " networks: ") + + String(HIDE_DUPLICATE_NETWORKS ? F("Hide") : F("Show")) + F("
" "Min " D_STR_WIFI " signal required: " #ifdef MIN_SIGNAL_STRENGTH - + String(static_cast(MIN_SIGNAL_STRENGTH)) + + ) + // NOLINT(whitespace/parens) + String(static_cast(MIN_SIGNAL_STRENGTH)) + F( #else // MIN_SIGNAL_STRENGTH "8" #endif // MIN_SIGNAL_STRENGTH "%
" "Serial debugging: " #if DEBUG - + String(isSerialGpioUsedByIr() ? D_STR_OFF : D_STR_ON) + + ) + // NOLINT(whitespace/parens) + String(isSerialGpioUsedByIr() ? D_STR_OFF : D_STR_ON) + F( #else // DEBUG D_STR_OFF #endif // DEBUG "
" #if REPORT_VCC - "Vcc: "; + "Vcc: "); html += vccToString(); - html += "V
" + html += F("V
" #endif // REPORT_VCC "

" #if MQTT_ENABLE "

MQTT Information

" - "

Server: " + String(MqttServer) + ":" + String(MqttPort) + " (" + + "

Server: ") + String(MqttServer) + ":" + String(MqttPort) + F(" (") + (mqtt_client.connected() ? "Connected " + timeSince(lastDisconnectedTime) : "Disconnected " + timeSince(lastConnectedTime)) + - ")
" - "Disconnections: " + String(mqttDisconnectCounter - 1) + "
" - "Buffer Size: " + String(mqtt_client.getBufferSize()) + " bytes
" - "Client id: " + MqttClientId + "
" - "Command topic(s): " + listOfCommandTopics() + "
" - "Acknowledgements topic: " + MqttAck + "
" + F(")

" + "Disconnections: ") + String(mqttDisconnectCounter - 1) + F("
" + "Buffer Size: ") + String(mqtt_client.getBufferSize()) + F(" bytes
" + "Client id: ") + MqttClientId + F("
" + "Command topic(s): ") + listOfCommandTopics() + F("
" + "Acknowledgements topic: ") + MqttAck + F("
" #if IR_RX - "IR Received topic: " + MqttRecv + "
" + "IR Received topic: ") + MqttRecv + F("
" #endif // IR_RX - "Log topic: " + MqttLog + "
" - "LWT topic: " + MqttLwt + "
" - "QoS: " + String(QOS) + "
" + "Log topic: ") + MqttLog + F("
" + "LWT topic: ") + MqttLwt + F("
" + "QoS: ") + String(QOS) + F("
" // lastMqttCmd* is unescaped untrusted input. // Avoid any possible HTML/XSS when displaying it. - "Last MQTT command seen: (topic) '" + + "Last MQTT command seen: (topic) '") + irutils::htmlEscape(lastMqttCmdTopic) + - "' (payload) '" + irutils::htmlEscape(lastMqttCmd) + "' (" + - timeSince(lastMqttCmdTime) + ")
" - "Total published: " + String(mqttSentCounter) + "
" - "Total received: " + String(mqttRecvCounter) + "
" + F("' (payload) '") + irutils::htmlEscape(lastMqttCmd) + F("' (") + + timeSince(lastMqttCmdTime) + F(")
" + "Total published: ") + String(mqttSentCounter) + F("
" + "Total received: ") + String(mqttRecvCounter) + F("
" "

" #endif // MQTT_ENABLE "

Climate Information

" "

" - "IR Send GPIO: " + String(txGpioTable[0]) + "
" - "Last update source: " + lastClimateSource + "
" - "Total sent: " + String(irClimateCounter) + "
" - "Last send: " + String(hasClimateBeenSent ? + "IR Send GPIO: ") + String(txGpioTable[0]) + F("
" + "Last update source: ") + lastClimateSource + F("
" + "Total sent: ") + String(irClimateCounter) + F("
" + "Last send: ") + String(hasClimateBeenSent ? (String(lastClimateSucceeded ? "Ok" : "FAILED") + " (" + timeElapsed(lastClimateIr.elapsed()) + ")") : - "Never") + "
" + "Never") + F("
" #if MQTT_ENABLE - "State listen period: " + msToString(kStatListenPeriodMs) + "
" - "State broadcast period: " + msToString(kBroadcastPeriodMs) + "
" - "Last state broadcast: " + (hasBroadcastBeenSent ? + "State listen period: ") + msToString(kStatListenPeriodMs) + F("
" + "State broadcast period: ") + msToString(kBroadcastPeriodMs) + F("
" + "Last state broadcast: ") + (hasBroadcastBeenSent ? timeElapsed(lastBroadcast.elapsed()) : - String("Never")) + "
" + String(F("Never"))) + F("
" #if MQTT_DISCOVERY_ENABLE - "Last discovery sent: " + (lockMqttBroadcast ? - String("Locked") : + "Last discovery sent: ") + (lockMqttBroadcast ? + String(F("Locked")) : (hasDiscoveryBeenSent ? timeElapsed(lastDiscovery.elapsed()) : - String("Never"))) + - "
" - "Discovery topic: " + MqttDiscovery + "
" + + String(F("Never")))) + + F("
" + "Discovery topic: ") + MqttDiscovery + F("
") + F( #endif // MQTT_DISCOVERY_ENABLE - "Command topics: " + MqttClimate + channel_re + '/' + MQTT_CLIMATE_CMND + - '/' + kClimateTopics + - "State topics: " + MqttClimate + channel_re + '/' + MQTT_CLIMATE_STAT + - '/' + kClimateTopics + + "Command topics: ") + MqttClimate + channel_re + + F("/" MQTT_CLIMATE_CMND "/") + FPSTR(kClimateTopics) + + F("State topics: ") + MqttClimate + channel_re + + F("/" MQTT_CLIMATE_STAT "/") + FPSTR(kClimateTopics) + F( #endif // MQTT_ENABLE "

" // Page footer "

" "(Note: Page will refresh every 60 " D_STR_SECONDS ".)" - "

"; + "

"); html += addJsReloadUrl(kUrlInfo, 60, false); html += htmlEnd(); server.send(200, "text/html", html); @@ -1384,14 +1395,14 @@ bool clearMqttSavedStates(const String topic_base) { for (size_t i = 0; i < sizeof(kMqttTopics) / sizeof(char*); i++) { // Sending a retained "" message to the topic should clear previous values // in theory. - String topic = topic_base + channelStr + '/' + F(MQTT_CLIMATE_STAT) + - '/' + String(kMqttTopics[i]); + String topic = topic_base + channelStr + F("/" MQTT_CLIMATE_STAT "/") + + String(kMqttTopics[i]); success &= mqtt_client.publish(topic.c_str(), "", true); } channelStr = '_' + String(channel); } - String logmesg = "Removing all possible settings saved in MQTT for '" + - topic_base + "' "; + String logmesg = F("Removing all possible settings saved in MQTT for '") + + topic_base + F("' "); logmesg += success ? F("succeeded") : F("failed"); mqttLog(logmesg.c_str()); return success; @@ -1410,13 +1421,13 @@ void handleClearMqtt(void) { htmlHeader(F("Clearing saved info from MQTT"), F("Removing all saved settings for this device from " "MQTT.")) + - "

Device restarting. Try connecting in a few " D_STR_SECONDS ".

" + + F("

Device restarting. Try connecting in a few " D_STR_SECONDS ".

") + addJsReloadUrl(kUrlRoot, 10, true) + htmlEnd()); // Do the clearing. - mqttLog("Clearing all saved settings from MQTT."); + mqttLog(PSTR("Clearing all saved settings from MQTT.")); clearMqttSavedStates(MqttClimate); - doRestart("Rebooting..."); + doRestart(PSTR("Rebooting...")); } #endif // MQTT_ENABLE && MQTT_CLEAR_ENABLE @@ -1438,10 +1449,10 @@ void handleReset(void) { // Do the reset. #if MQTT_ENABLE #if MQTT_CLEAR_ENABLE - mqttLog("Clearing all saved climate settings from MQTT."); + mqttLog(PSTR("Clearing all saved climate settings from MQTT.")); clearMqttSavedStates(MqttClimate); #endif // MQTT_CLEAR_ENABLE - mqttLog("Wiping all saved config settings."); + mqttLog(PSTR("Wiping all saved config settings.")); #endif // MQTT_ENABLE if (mountSpiffs()) { debug("Removing JSON config file"); @@ -1451,7 +1462,7 @@ void handleReset(void) { delay(1000); debug("Reseting wifiManager's settings."); wifiManager.resetSettings(); - doRestart("Rebooting..."); + doRestart(PSTR("Rebooting...")); } // Reboot web page @@ -1465,7 +1476,7 @@ void handleReboot() { #endif server.send(200, "text/html", htmlHeader(F("Device restarting.")) + - "

Try connecting in a few " D_STR_SECONDS ".

" + + F("

Try connecting in a few " D_STR_SECONDS ".

") + addJsReloadUrl(kUrlRoot, kRebootTime, true) + htmlEnd()); doRestart("Reboot requested"); @@ -1484,7 +1495,7 @@ bool parseStringAndSendAirCon(IRsend *irsend, const decode_type_t irType, uint8_t state[kStateSizeMax] = {0}; // All array elements are set to 0. uint16_t stateSize = 0; - if (str.startsWith("0x") || str.startsWith("0X")) + if (str.startsWith(PSTR("0x")) || str.startsWith(PSTR("0X"))) strOffset = 2; // Calculate how many hexadecimal characters there are. uint16_t inputLength = str.length() - strOffset; @@ -1643,8 +1654,9 @@ uint16_t * newCodeArray(const uint16_t size) { // Check we malloc'ed successfully. if (result == NULL) // malloc failed, so give up. doRestart( - "FATAL: Can't allocate memory for an array for a new message! " - "Forcing a reboot!", true); // Send to serial only as we are in low mem + PSTR("FATAL: Can't allocate memory for an array for a new message! " + "Forcing a reboot!"), + true); // Send to serial only as we are in low mem return result; } @@ -1666,7 +1678,7 @@ bool parseStringAndSendGC(IRsend *irsend, const String str) { String tmp_str; // Remove the leading "1:1,1," if present. - if (str.startsWith("1:1,1,")) + if (str.startsWith(PSTR("1:1,1,"))) tmp_str = str.substring(6); else tmp_str = str; @@ -2097,7 +2109,7 @@ void setup(void) { if (isSerialGpioUsedByIr()) Serial.end(); #endif // DEBUG - channel_re.reserve(kNrOfIrTxGpios * 3); + channel_re.reserve(kNrOfIrTxGpios * 3 + 3 + 1); // Initialise all the IR transmitters. for (uint8_t i = 0; i < kNrOfIrTxGpios; i++) { if (txGpioTable[i] == kGpioUnused) { @@ -2195,7 +2207,7 @@ void setup(void) { if (strlen(HttpPassword)) { // Allow if password is set. server.on("/update", HTTP_POST, [](){ #if MQTT_ENABLE - mqttLog("Attempting firmware update & reboot"); + mqttLog(PSTR("Attempting firmware update & reboot")); delay(1000); #endif // MQTT_ENABLE server.send(200, "text/html", @@ -2287,7 +2299,7 @@ void unsubscribing(const String topic_name) { void mqttLog(const char* str) { debug(str); - mqtt_client.publish(MqttLog.c_str(), str); + mqtt_client.publish(MqttLog.c_str(), String(str).c_str()); mqttSentCounter++; } @@ -2313,7 +2325,7 @@ bool reconnect(void) { } if (connected) { // Once connected, publish an announcement... - mqttLog("(Re)Connected."); + mqttLog(PSTR("(Re)Connected.")); // Update Last Will & Testament to say we are back online. mqtt_client.publish(MqttLwt.c_str(), kLwtOnline, true); @@ -2364,12 +2376,13 @@ void handleSendMqttDiscovery(void) { server.send(200, "text/html", htmlHeader(F("Sending MQTT Discovery message")) + htmlMenu() + - "

The Home Assistant MQTT Discovery message is being sent to topic: " + - MqttDiscovery + ". It will show up in Home Assistant in a few seconds." + F("

The Home Assistant MQTT Discovery message is being sent to topic: ") + + MqttDiscovery + + F(". It will show up in Home Assistant in a few seconds." "

" "

Warning!

" "

Home Assistant's config for this device is reset each time this is " - " is sent.

" + + " is sent.

") + addJsReloadUrl(kUrlRoot, kRebootTime, true) + htmlEnd()); sendMQTTDiscovery(MqttDiscovery.c_str()); @@ -2416,8 +2429,8 @@ void receivingMQTT(String const topic_name, String const callback_str) { // Or is for a specific ac/climate channel. e.g. "*/ac_[1-9]" debug(("Checking for channel number in " + topic_name).c_str()); for (uint16_t i = 0; i < kNrOfIrTxGpios; i++) { - if (topic_name.endsWith("_" + String(i)) || - (i > 0 && topic_name.startsWith(MqttClimate + "_" + String(i)))) { + if (topic_name.endsWith('_' + String(i)) || + (i > 0 && topic_name.startsWith(MqttClimate + '_' + String(i)))) { channel = i; break; } @@ -2425,8 +2438,8 @@ void receivingMQTT(String const topic_name, String const callback_str) { debug(("Channel = " + String(channel)).c_str()); // Is it a climate topic? if (topic_name.startsWith(MqttClimate)) { - String alt_cmnd_topic = MqttClimate + "_" + String(channel) + '/' + - MQTT_CLIMATE_CMND + '/'; + String alt_cmnd_topic = MqttClimate + '_' + String(channel) + + F("/" MQTT_CLIMATE_CMND "/"); // Also accept climate commands on the '*_0' channel. String cmnd_topic = topic_name.startsWith(alt_cmnd_topic) ? alt_cmnd_topic : MqttClimateCmnd; @@ -2440,7 +2453,7 @@ void receivingMQTT(String const topic_name, String const callback_str) { if (topic_name.equals(cmnd_topic + KEY_RESEND) && callback_str.equalsIgnoreCase(KEY_RESEND)) { force_resend = true; - mqttLog("Climate resend requested."); + mqttLog(PSTR("Climate resend requested.")); } if (sendClimate(stat_topic, true, false, force_resend, true, climate[channel]) && !force_resend) @@ -2548,10 +2561,15 @@ void mqttCallback(char* topic, byte* payload, unsigned int length) { void sendMQTTDiscovery(const char *topic) { if (mqtt_client.publish( topic, String( - "{" - "\"~\":\"" + MqttClimate + "\"," - "\"name\":\"" + MqttHAName + "\"," + F("{" + "\"~\":\"") + MqttClimate + F("\"," + "\"name\":\"") + MqttHAName + F("\"," +#if (!MQTT_CLIMATE_HA_MODE) + // Typically we don't need or use the power command topic if we are using + // our Home Assistant Climate compatiblity mode. It causes odd behaviour + // if both are used. "\"pow_cmd_t\":\"~/" MQTT_CLIMATE_CMND "/" KEY_POWER "\"," +#endif // !MQTT_CLIMATE_HA_MODE "\"mode_cmd_t\":\"~/" MQTT_CLIMATE_CMND "/" KEY_MODE "\"," "\"mode_stat_t\":\"~/" MQTT_CLIMATE_STAT "/" KEY_MODE "\"," // I don't know why, but the modes need to be lower case to work with @@ -2571,22 +2589,22 @@ void sendMQTTDiscovery(const char *topic) { "\"swing_modes\":[\"" D_STR_OFF "\",\"" D_STR_AUTO "\",\"" D_STR_HIGHEST "\",\"" D_STR_HIGH "\",\"" D_STR_MIDDLE "\",\"" D_STR_LOW "\",\"" D_STR_LOWEST "\"]," - "\"uniq_id\":\"" + MqttUniqueId + "\"," + "\"uniq_id\":\"") + MqttUniqueId + F("\"," "\"device\":{" - "\"identifiers\":[\"" + MqttUniqueId + "\"]," - "\"connections\":[[\"mac\",\"" + WiFi.macAddress() + "\"]]," + "\"identifiers\":[\"") + MqttUniqueId + F("\"]," + "\"connections\":[[\"mac\",\"") + WiFi.macAddress() + F("\"]]," "\"manufacturer\":\"IRremoteESP8266\"," "\"model\":\"IRMQTTServer\"," - "\"name\":\"" + Hostname + "\"," + "\"name\":\"") + Hostname + F("\"," "\"sw_version\":\"" _MY_VERSION_ "\"" "}" - "}").c_str(), true)) { - mqttLog("MQTT climate discovery successful sent."); + "}")).c_str(), true)) { + mqttLog(PSTR("MQTT climate discovery successful sent.")); hasDiscoveryBeenSent = true; lastDiscovery.reset(); mqttSentCounter++; } else { - mqttLog("MQTT climate discovery FAILED to send."); + mqttLog(PSTR("MQTT climate discovery FAILED to send.")); } } #endif // MQTT_DISCOVERY_ENABLE @@ -2616,11 +2634,12 @@ void loop(void) { lastReconnectAttempt = 0; wasConnected = true; if (boot) { - mqttLog("IRMQTTServer " _MY_VERSION_ " just booted"); + mqttLog(PSTR("IRMQTTServer " _MY_VERSION_ " just booted")); boot = false; } else { mqttLog(String( - "IRMQTTServer just (re)connected to MQTT. Lost connection about " + F("IRMQTTServer just (re)connected to MQTT. " + "Lost connection about ") + timeSince(lastConnectedTime)).c_str()); } lastConnectedTime = now; @@ -2628,7 +2647,7 @@ void loop(void) { if (lockMqttBroadcast) { // Attempt to fetch back any Climate state stored in MQTT retained // messages on the MQTT broker. - mqttLog("Started listening for previous state."); + mqttLog(PSTR("Started listening for previous state.")); for (uint16_t i = 0; i < kNrOfIrTxGpios; i++) subscribing(genStatTopic(i) + '+'); statListenTime.reset(); @@ -2648,10 +2667,10 @@ void loop(void) { sendClimate(stat_topic, true, false, false, MQTT_CLIMATE_IR_SEND_ON_RESTART, climate[i]); lastClimateSource = F("MQTT (via retain)"); - mqttLog("The state was recovered from MQTT broker."); + mqttLog(PSTR("The state was recovered from MQTT broker.")); } } - mqttLog("Finished listening for previous state."); + mqttLog(PSTR("Finished listening for previous state.")); lockMqttBroadcast = false; // Release the lock so we can broadcast again. } // Periodically send all of the climate state via MQTT. @@ -2671,17 +2690,17 @@ void loop(void) { resultToHexidecimal(&capture); #if REPORT_RAW_UNKNOWNS if (capture.decode_type == UNKNOWN) { - lastIrReceived += ";"; + lastIrReceived += ';'; for (uint16_t i = 1; i < capture.rawlen; i++) { uint32_t usecs; for (usecs = capture.rawbuf[i] * kRawTick; usecs > UINT16_MAX; usecs -= UINT16_MAX) { lastIrReceived += uint64ToString(UINT16_MAX); - lastIrReceived += ",0,"; + lastIrReceived += F(",0,"); } lastIrReceived += uint64ToString(usecs, 10); if (i < capture.rawlen - 1) - lastIrReceived += ","; + lastIrReceived += ','; } } #endif // REPORT_RAW_UNKNOWNS @@ -2875,10 +2894,10 @@ void sendJsonState(const stdAc::state_t state, const String topic, json[KEY_PROTOCOL] = typeToString(state.protocol); json[KEY_MODEL] = state.model; json[KEY_POWER] = IRac::boolToString(state.power); - json[KEY_MODE] = IRac::opmodeToString(state.mode); + json[KEY_MODE] = IRac::opmodeToString(state.mode, ha_mode); // Home Assistant wants mode to be off if power is also off & vice-versa. if (ha_mode && (state.mode == stdAc::opmode_t::kOff || !state.power)) { - json[KEY_MODE] = IRac::opmodeToString(stdAc::opmode_t::kOff); + json[KEY_MODE] = IRac::opmodeToString(stdAc::opmode_t::kOff, ha_mode); json[KEY_POWER] = IRac::boolToString(false); } json[KEY_CELSIUS] = IRac::boolToString(state.celsius); @@ -2965,45 +2984,45 @@ void updateClimate(stdAc::state_t *state, const String str, *state = jsonToState(*state, payload.c_str()); else #endif // MQTT_CLIMATE_JSON - if (str.equals(prefix + KEY_PROTOCOL)) { + if (str.equals(prefix + F(KEY_PROTOCOL))) { state->protocol = strToDecodeType(payload.c_str()); - } else if (str.equals(prefix + KEY_MODEL)) { + } else if (str.equals(prefix + F(KEY_MODEL))) { state->model = IRac::strToModel(payload.c_str()); - } else if (str.equals(prefix + KEY_POWER)) { + } else if (str.equals(prefix + F(KEY_POWER))) { state->power = IRac::strToBool(payload.c_str()); #if MQTT_CLIMATE_HA_MODE if (!state->power) state->mode = stdAc::opmode_t::kOff; #endif // MQTT_CLIMATE_HA_MODE - } else if (str.equals(prefix + KEY_MODE)) { + } else if (str.equals(prefix + F(KEY_MODE))) { state->mode = IRac::strToOpmode(payload.c_str()); #if MQTT_CLIMATE_HA_MODE state->power = (state->mode != stdAc::opmode_t::kOff); #endif // MQTT_CLIMATE_HA_MODE - } else if (str.equals(prefix + KEY_TEMP)) { + } else if (str.equals(prefix + F(KEY_TEMP))) { state->degrees = payload.toFloat(); - } else if (str.equals(prefix + KEY_FANSPEED)) { + } else if (str.equals(prefix + F(KEY_FANSPEED))) { state->fanspeed = IRac::strToFanspeed(payload.c_str()); - } else if (str.equals(prefix + KEY_SWINGV)) { + } else if (str.equals(prefix + F(KEY_SWINGV))) { state->swingv = IRac::strToSwingV(payload.c_str()); - } else if (str.equals(prefix + KEY_SWINGH)) { + } else if (str.equals(prefix + F(KEY_SWINGH))) { state->swingh = IRac::strToSwingH(payload.c_str()); - } else if (str.equals(prefix + KEY_QUIET)) { + } else if (str.equals(prefix + F(KEY_QUIET))) { state->quiet = IRac::strToBool(payload.c_str()); - } else if (str.equals(prefix + KEY_TURBO)) { + } else if (str.equals(prefix + F(KEY_TURBO))) { state->turbo = IRac::strToBool(payload.c_str()); - } else if (str.equals(prefix + KEY_ECONO)) { + } else if (str.equals(prefix + F(KEY_ECONO))) { state->econo = IRac::strToBool(payload.c_str()); - } else if (str.equals(prefix + KEY_LIGHT)) { + } else if (str.equals(prefix + F(KEY_LIGHT))) { state->light = IRac::strToBool(payload.c_str()); - } else if (str.equals(prefix + KEY_BEEP)) { + } else if (str.equals(prefix + F(KEY_BEEP))) { state->beep = IRac::strToBool(payload.c_str()); - } else if (str.equals(prefix + KEY_FILTER)) { + } else if (str.equals(prefix + F(KEY_FILTER))) { state->filter = IRac::strToBool(payload.c_str()); - } else if (str.equals(prefix + KEY_CLEAN)) { + } else if (str.equals(prefix + F(KEY_CLEAN))) { state->clean = IRac::strToBool(payload.c_str()); - } else if (str.equals(prefix + KEY_CELSIUS)) { + } else if (str.equals(prefix + F(KEY_CELSIUS))) { state->celsius = IRac::strToBool(payload.c_str()); - } else if (str.equals(prefix + KEY_SLEEP)) { + } else if (str.equals(prefix + F(KEY_SLEEP))) { state->sleep = payload.toInt(); } } @@ -3024,7 +3043,11 @@ bool sendClimate(const String topic_prefix, const bool retain, diff = true; success &= sendInt(topic_prefix + KEY_MODEL, next.model, retain); } +#ifdef MQTT_CLIMATE_HA_MODE + String mode_str = IRac::opmodeToString(next.mode, MQTT_CLIMATE_HA_MODE); +#else // MQTT_CLIMATE_HA_MODE String mode_str = IRac::opmodeToString(next.mode); +#endif // MQTT_CLIMATE_HA_MODE // I don't know why, but the modes need to be lower case to work with // Home Assistant & Google Home. mode_str.toLowerCase(); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV2/platformio.ini b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV2/platformio.ini index 0063a1133..b56304f66 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV2/platformio.ini +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV2/platformio.ini @@ -52,6 +52,12 @@ build_flags = -D_IR_LOCALE_=it-IT ; Italian [env:pt-BR] build_flags = -D_IR_LOCALE_=pt-BR ; Portuguese (Brazilian) +[env:ru-RU] +build_flags = -D_IR_LOCALE_=ru-RU ; Russian + +[env:sv-SE] +build_flags = -D_IR_LOCALE_=sv-SE ; Swedish + [env:zh-CN] build_flags = -D_IR_LOCALE_=zh-CN ; Chinese (Simplified) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV3/platformio.ini b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV3/platformio.ini index 95a90ac86..e5df92876 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV3/platformio.ini +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/examples/IRrecvDumpV3/platformio.ini @@ -49,5 +49,14 @@ build_flags = -D_IR_LOCALE_=fr-FR ; French [env:it-IT] build_flags = -D_IR_LOCALE_=it-IT ; Italian +[env:pt-BR] +build_flags = -D_IR_LOCALE_=pt-BR ; Portuguese (Brazilian) + +[env:ru-RU] +build_flags = -D_IR_LOCALE_=ru-RU ; Russian + +[env:sv-SE] +build_flags = -D_IR_LOCALE_=sv-SE ; Swedish + [env:zh-CN] build_flags = -D_IR_LOCALE_=zh-CN ; Chinese (Simplified) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/keywords.txt b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/keywords.txt index fefce8d9d..592b5d99b 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/keywords.txt +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/keywords.txt @@ -52,6 +52,7 @@ IRKelonAc KEYWORD1 IRKelvinatorAC KEYWORD1 IRLgAc KEYWORD1 IRMideaAC KEYWORD1 +IRMirageAc KEYWORD1 IRMitsubishi112 KEYWORD1 IRMitsubishi136 KEYWORD1 IRMitsubishiAC KEYWORD1 @@ -60,6 +61,7 @@ IRMitsubishiHeavy88Ac KEYWORD1 IRNeoclimaAc KEYWORD1 IRPanasonicAc KEYWORD1 IRPanasonicAc32 KEYWORD1 +IRRhossAc KEYWORD1 IRSamsungAc KEYWORD1 IRSanyoAc KEYWORD1 IRSanyoAc88 KEYWORD1 @@ -85,16 +87,19 @@ decode_type_t KEYWORD1 fanspeed_t KEYWORD1 fujitsu_ac_remote_model_t KEYWORD1 gree_ac_remote_model_t KEYWORD1 +haier_ac176_remote_model_t KEYWORD1 hitachi_ac1_remote_model_t KEYWORD1 irparams_t KEYWORD1 lg_ac_remote_model_t KEYWORD1 match_result_t KEYWORD1 +mirage_ac_remote_model_t KEYWORD1 opmode_t KEYWORD1 panasonic_ac_remote_model_t KEYWORD1 sharp_ac_remote_model_t KEYWORD1 state_t KEYWORD1 swingh_t KEYWORD1 swingv_t KEYWORD1 +tcl_ac_remote_model_t KEYWORD1 voltas_ac_remote_model_t KEYWORD1 whirlpool_ac_remote_model_t KEYWORD1 @@ -107,6 +112,8 @@ _cancelOffTimer KEYWORD2 _cancelOnTimer KEYWORD2 _delayMicroseconds KEYWORD2 _getEconoToggle KEYWORD2 +_getOffTimer KEYWORD2 +_getOnTimer KEYWORD2 _getTime KEYWORD2 _getTimer KEYWORD2 _isAKB73757604 KEYWORD2 @@ -117,6 +124,9 @@ _restoreState KEYWORD2 _sendSony KEYWORD2 _setEconoToggle KEYWORD2 _setMode KEYWORD2 +_setOffTimer KEYWORD2 +_setOnTimer KEYWORD2 +_setSleepTimer KEYWORD2 _setTemp KEYWORD2 _setTime KEYWORD2 _setTimer KEYWORD2 @@ -135,6 +145,7 @@ addSwingHToString KEYWORD2 addSwingVToString KEYWORD2 addTempFloatToString KEYWORD2 addTempToString KEYWORD2 +addToggleToString KEYWORD2 adjustRepeat KEYWORD2 airwell KEYWORD2 amcor KEYWORD2 @@ -189,10 +200,12 @@ daikin2 KEYWORD2 daikin216 KEYWORD2 daikin64 KEYWORD2 decode KEYWORD2 +decodeAirton KEYWORD2 decodeAirwell KEYWORD2 decodeAiwaRCT501 KEYWORD2 decodeAmcor KEYWORD2 decodeArgo KEYWORD2 +decodeArris KEYWORD2 decodeBose KEYWORD2 decodeCOOLIX KEYWORD2 decodeCarrierAC KEYWORD2 @@ -258,6 +271,7 @@ decodePioneer KEYWORD2 decodeRC5 KEYWORD2 decodeRC6 KEYWORD2 decodeRCMM KEYWORD2 +decodeRhoss KEYWORD2 decodeSAMSUNG KEYWORD2 decodeSamsung36 KEYWORD2 decodeSamsungAC KEYWORD2 @@ -298,6 +312,7 @@ enableIROut KEYWORD2 enableOffTimer KEYWORD2 enableOnTimer KEYWORD2 enableSleepTimer KEYWORD2 +encodeArris KEYWORD2 encodeDoshisha KEYWORD2 encodeJVC KEYWORD2 encodeLG KEYWORD2 @@ -319,6 +334,7 @@ fahrenheitToCelsius KEYWORD2 fanspeedToString KEYWORD2 fixChecksum KEYWORD2 fixup KEYWORD2 +fromCommon KEYWORD2 fujitsu KEYWORD2 get10CHeat KEYWORD2 get3D KEYWORD2 @@ -331,6 +347,7 @@ getBufSize KEYWORD2 getButton KEYWORD2 getCelsius KEYWORD2 getClean KEYWORD2 +getCleanToggle KEYWORD2 getClock KEYWORD2 getCmd KEYWORD2 getComfort KEYWORD2 @@ -367,6 +384,7 @@ getIonFilter KEYWORD2 getLed KEYWORD2 getLight KEYWORD2 getLightToggle KEYWORD2 +getLock KEYWORD2 getMax KEYWORD2 getMode KEYWORD2 getMold KEYWORD2 @@ -396,9 +414,11 @@ getSectionByte KEYWORD2 getSectionChecksum KEYWORD2 getSensor KEYWORD2 getSensorTemp KEYWORD2 +getSensorUpdate KEYWORD2 getSilent KEYWORD2 getSleep KEYWORD2 getSleepTime KEYWORD2 +getSleepTimer KEYWORD2 getSleepTimerEnabled KEYWORD2 getSpecial KEYWORD2 getSpeed KEYWORD2 @@ -481,6 +501,7 @@ isSwingH KEYWORD2 isSwingV KEYWORD2 isSwingVStep KEYWORD2 isSwingVToggle KEYWORD2 +isTcl KEYWORD2 isTimeCommand KEYWORD2 isTimerActive KEYWORD2 isTurboToggle KEYWORD2 @@ -509,6 +530,7 @@ matchSpaceRange KEYWORD2 midea KEYWORD2 minRepeats KEYWORD2 minsToString KEYWORD2 +mirage KEYWORD2 mitsubishi KEYWORD2 mitsubishi112 KEYWORD2 mitsubishi136 KEYWORD2 @@ -532,15 +554,18 @@ resultToSourceCode KEYWORD2 resultToTimingInfo KEYWORD2 resume KEYWORD2 reverseBits KEYWORD2 +rhoss KEYWORD2 samsung KEYWORD2 sanyo KEYWORD2 sanyo88 KEYWORD2 send KEYWORD2 sendAc KEYWORD2 +sendAirton KEYWORD2 sendAirwell KEYWORD2 sendAiwaRCT501 KEYWORD2 sendAmcor KEYWORD2 sendArgo KEYWORD2 +sendArris KEYWORD2 sendBose KEYWORD2 sendCOOLIX KEYWORD2 sendCarrierAC KEYWORD2 @@ -621,6 +646,7 @@ sendRC5 KEYWORD2 sendRC6 KEYWORD2 sendRCMM KEYWORD2 sendRaw KEYWORD2 +sendRhoss KEYWORD2 sendSAMSUNG KEYWORD2 sendSamsung36 KEYWORD2 sendSamsungAC KEYWORD2 @@ -662,6 +688,7 @@ setBreeze KEYWORD2 setButton KEYWORD2 setCelsius KEYWORD2 setClean KEYWORD2 +setCleanToggle KEYWORD2 setClock KEYWORD2 setCmd KEYWORD2 setComfort KEYWORD2 @@ -697,6 +724,7 @@ setIonFilter KEYWORD2 setLed KEYWORD2 setLight KEYWORD2 setLightToggle KEYWORD2 +setLock KEYWORD2 setMax KEYWORD2 setMode KEYWORD2 setModel KEYWORD2 @@ -725,6 +753,7 @@ setSave KEYWORD2 setSensor KEYWORD2 setSensorTemp KEYWORD2 setSensorTempRaw KEYWORD2 +setSensorUpdate KEYWORD2 setSilent KEYWORD2 setSleep KEYWORD2 setSleepTimer KEYWORD2 @@ -791,6 +820,7 @@ teco KEYWORD2 ticksHigh KEYWORD2 ticksLow KEYWORD2 toString KEYWORD2 +toggleArrisRelease KEYWORD2 toggleRC5 KEYWORD2 toggleRC6 KEYWORD2 toggleSwingHoriz KEYWORD2 @@ -821,6 +851,7 @@ xorBytes KEYWORD2 A705 LITERAL1 A903 LITERAL1 A907 LITERAL1 +AIRTON LITERAL1 AIRWELL LITERAL1 AIWA_RC_T501 LITERAL1 AIWA_RC_T501_BITS LITERAL1 @@ -857,6 +888,7 @@ ARJW2 LITERAL1 ARRAH2E LITERAL1 ARREB1E LITERAL1 ARREW4E LITERAL1 +ARRIS LITERAL1 ARRY4 LITERAL1 BOSE LITERAL1 CARRIER_AC LITERAL1 @@ -887,10 +919,12 @@ DAIKIN_HEAT LITERAL1 DAIKIN_MAX_TEMP LITERAL1 DAIKIN_MIN_TEMP LITERAL1 DECODE_AC LITERAL1 +DECODE_AIRTON LITERAL1 DECODE_AIRWELL LITERAL1 DECODE_AIWA_RC_T501 LITERAL1 DECODE_AMCOR LITERAL1 DECODE_ARGO LITERAL1 +DECODE_ARRIS LITERAL1 DECODE_BOSE LITERAL1 DECODE_CARRIER_AC LITERAL1 DECODE_CARRIER_AC40 LITERAL1 @@ -961,6 +995,7 @@ DECODE_PRONTO LITERAL1 DECODE_RC5 LITERAL1 DECODE_RC6 LITERAL1 DECODE_RCMM LITERAL1 +DECODE_RHOSS LITERAL1 DECODE_SAMSUNG LITERAL1 DECODE_SAMSUNG36 LITERAL1 DECODE_SAMSUNG_AC LITERAL1 @@ -1054,6 +1089,7 @@ GREE_SWING_MIDDLE_DOWN LITERAL1 GREE_SWING_MIDDLE_UP LITERAL1 GREE_SWING_UP LITERAL1 GREE_SWING_UP_AUTO LITERAL1 +GZ055BE1 LITERAL1 HAIER_AC LITERAL1 HAIER_AC176 LITERAL1 HAIER_AC_AUTO LITERAL1 @@ -1063,7 +1099,7 @@ HAIER_AC_CMD_MODE LITERAL1 HAIER_AC_CMD_OFF LITERAL1 HAIER_AC_CMD_ON LITERAL1 HAIER_AC_CMD_SLEEP LITERAL1 -HAIER_AC_CMD_SWING LITERAL1 +HAIER_AC_CMD_SWINGV LITERAL1 HAIER_AC_CMD_TEMP_DOWN LITERAL1 HAIER_AC_CMD_TEMP_UP LITERAL1 HAIER_AC_CMD_TIMER_CANCEL LITERAL1 @@ -1080,10 +1116,10 @@ HAIER_AC_HEAT LITERAL1 HAIER_AC_MAX_TEMP LITERAL1 HAIER_AC_MIN_TEMP LITERAL1 HAIER_AC_STATE_LENGTH LITERAL1 -HAIER_AC_SWING_CHG LITERAL1 -HAIER_AC_SWING_DOWN LITERAL1 -HAIER_AC_SWING_OFF LITERAL1 -HAIER_AC_SWING_UP LITERAL1 +HAIER_AC_SWINGV_CHG LITERAL1 +HAIER_AC_SWINGV_DOWN LITERAL1 +HAIER_AC_SWINGV_OFF LITERAL1 +HAIER_AC_SWINGV_UP LITERAL1 HAIER_AC_YRW02 LITERAL1 HAIER_AC_YRW02_AUTO LITERAL1 HAIER_AC_YRW02_BUTTON_FAN LITERAL1 @@ -1110,8 +1146,6 @@ HAIER_AC_YRW02_SWING_DOWN LITERAL1 HAIER_AC_YRW02_SWING_MIDDLE LITERAL1 HAIER_AC_YRW02_SWING_OFF LITERAL1 HAIER_AC_YRW02_SWING_TOP LITERAL1 -HAIER_AC_YRW02_TURBO_HIGH LITERAL1 -HAIER_AC_YRW02_TURBO_LOW LITERAL1 HAIER_AC_YRW02_TURBO_OFF LITERAL1 HIGH LITERAL1 HITACHI_AC LITERAL1 @@ -1144,6 +1178,8 @@ KELVINATOR_HEAT LITERAL1 KELVINATOR_MAX_TEMP LITERAL1 KELVINATOR_MIN_TEMP LITERAL1 KELVINATOR_STATE_LENGTH LITERAL1 +KKG29AC1 LITERAL1 +KKG9AC1 LITERAL1 LASERTAG LITERAL1 LASERTAG_BITS LITERAL1 LEGOPF LITERAL1 @@ -1224,6 +1260,7 @@ RC6_36_BITS LITERAL1 RC6_MODE0_BITS LITERAL1 RCMM LITERAL1 RCMM_BITS LITERAL1 +RHOSS LITERAL1 R_LT0541_HTA_A LITERAL1 R_LT0541_HTA_B LITERAL1 SAMSUNG LITERAL1 @@ -1236,10 +1273,12 @@ SANYO_AC88 LITERAL1 SANYO_LC7461 LITERAL1 SANYO_LC7461_BITS LITERAL1 SANYO_SA8650B_BITS LITERAL1 +SEND_AIRTON LITERAL1 SEND_AIRWELL LITERAL1 SEND_AIWA_RC_T501 LITERAL1 SEND_AMCOR LITERAL1 SEND_ARGO LITERAL1 +SEND_ARRIS LITERAL1 SEND_BOSE LITERAL1 SEND_CARRIER_AC LITERAL1 SEND_CARRIER_AC40 LITERAL1 @@ -1310,6 +1349,7 @@ SEND_RAW LITERAL1 SEND_RC5 LITERAL1 SEND_RC6 LITERAL1 SEND_RCMM LITERAL1 +SEND_RHOSS LITERAL1 SEND_SAMSUNG LITERAL1 SEND_SAMSUNG36 LITERAL1 SEND_SAMSUNG_AC LITERAL1 @@ -1347,6 +1387,7 @@ SONY_15_BITS LITERAL1 SONY_20_BITS LITERAL1 SONY_38K LITERAL1 SYMPHONY LITERAL1 +TAC09CHSD LITERAL1 TCL112AC LITERAL1 TECHNIBEL_AC LITERAL1 TECO LITERAL1 @@ -1381,6 +1422,8 @@ TRUMA LITERAL1 UNKNOWN LITERAL1 UNUSED LITERAL1 USE_IRAM_ATTR LITERAL1 +V9014557_A LITERAL1 +V9014557_B LITERAL1 VESTEL_AC LITERAL1 VOLTAS LITERAL1 WHIRLPOOL_AC LITERAL1 @@ -1390,11 +1433,25 @@ XMP LITERAL1 YAW1F LITERAL1 YBOFB LITERAL1 ZEPEAL LITERAL1 +k0Str LITERAL1 k10CHeatStr LITERAL1 +k122lzfStr LITERAL1 +k1Str LITERAL1 k3DStr LITERAL1 k6thSenseStr LITERAL1 k8CHeatStr LITERAL1 +kA705Str LITERAL1 +kA903Str LITERAL1 +kA907Str LITERAL1 kAirFlowStr LITERAL1 +kAirtonBitMark LITERAL1 +kAirtonBits LITERAL1 +kAirtonDefaultRepeat LITERAL1 +kAirtonFreq LITERAL1 +kAirtonHdrMark LITERAL1 +kAirtonHdrSpace LITERAL1 +kAirtonOneSpace LITERAL1 +kAirtonZeroSpace LITERAL1 kAirwellAuto LITERAL1 kAirwellBits LITERAL1 kAirwellCool LITERAL1 @@ -1420,6 +1477,9 @@ kAiwaRcT501PostBits LITERAL1 kAiwaRcT501PostData LITERAL1 kAiwaRcT501PreBits LITERAL1 kAiwaRcT501PreData LITERAL1 +kAkb73757604Str LITERAL1 +kAkb74955603Str LITERAL1 +kAkb75215403Str LITERAL1 kAllProtocolNamesStr LITERAL1 kAlokaBits LITERAL1 kAlokaLedBlue LITERAL1 @@ -1464,6 +1524,7 @@ kAmcorTolerance LITERAL1 kAmcorVentOn LITERAL1 kAmcorZeroMark LITERAL1 kAmcorZeroSpace LITERAL1 +kArdb1Str LITERAL1 kArgoAuto LITERAL1 kArgoBitMark LITERAL1 kArgoBits LITERAL1 @@ -1497,6 +1558,21 @@ kArgoOneSpace LITERAL1 kArgoStateLength LITERAL1 kArgoTempDelta LITERAL1 kArgoZeroSpace LITERAL1 +kArjw2Str LITERAL1 +kArrah2eStr LITERAL1 +kArreb1eStr LITERAL1 +kArrew4eStr LITERAL1 +kArrisBits LITERAL1 +kArrisChecksumSize LITERAL1 +kArrisCommandSize LITERAL1 +kArrisGapSpace LITERAL1 +kArrisHalfClockPeriod LITERAL1 +kArrisHdrMark LITERAL1 +kArrisHdrSpace LITERAL1 +kArrisOverhead LITERAL1 +kArrisReleaseBit LITERAL1 +kArrisReleaseToggle LITERAL1 +kArry4Str LITERAL1 kAuto LITERAL1 kAutoStr LITERAL1 kAutomaticStr LITERAL1 @@ -1558,6 +1634,7 @@ kCelsiusStr LITERAL1 kCentreStr LITERAL1 kChangeStr LITERAL1 kCirculateStr LITERAL1 +kCkpStr LITERAL1 kCleanStr LITERAL1 kClockStr LITERAL1 kCodeStr LITERAL1 @@ -1567,6 +1644,7 @@ kCommaSpaceStr LITERAL1 kCommandStr LITERAL1 kCool LITERAL1 kCoolStr LITERAL1 +kCoolingStr LITERAL1 kCoolixAuto LITERAL1 kCoolixBitMark LITERAL1 kCoolixBitMarkTicks LITERAL1 @@ -1866,10 +1944,12 @@ kDaikinSwingOn LITERAL1 kDaikinTolerance LITERAL1 kDaikinUnusedTime LITERAL1 kDaikinZeroSpace LITERAL1 +kDashStr LITERAL1 kDayStr LITERAL1 kDaysStr LITERAL1 kDefaultESP32Timer LITERAL1 kDefaultMessageGap LITERAL1 +kDehumidifyStr LITERAL1 kDelonghiAcAuto LITERAL1 kDelonghiAcBitMark LITERAL1 kDelonghiAcBits LITERAL1 @@ -1914,6 +1994,9 @@ kDenonOneSpaceTicks LITERAL1 kDenonTick LITERAL1 kDenonZeroSpace LITERAL1 kDenonZeroSpaceTicks LITERAL1 +kDg11j104Str LITERAL1 +kDg11j13aStr LITERAL1 +kDg11j191Str LITERAL1 kDishBitMark LITERAL1 kDishBitMarkTicks LITERAL1 kDishBits LITERAL1 @@ -1930,6 +2013,7 @@ kDishTick LITERAL1 kDishZeroSpace LITERAL1 kDishZeroSpaceTicks LITERAL1 kDisplayTempStr LITERAL1 +kDkeStr LITERAL1 kDoshishaBitMark LITERAL1 kDoshishaBits LITERAL1 kDoshishaHdrMark LITERAL1 @@ -1939,6 +2023,7 @@ kDoshishaZeroSpace LITERAL1 kDownStr LITERAL1 kDry LITERAL1 kDryStr LITERAL1 +kDryingStr LITERAL1 kDutyDefault LITERAL1 kDutyMax LITERAL1 kEcoclimAuto LITERAL1 @@ -1992,6 +2077,9 @@ kElectraAcMessageGap LITERAL1 kElectraAcMinRepeat LITERAL1 kElectraAcMinTemp LITERAL1 kElectraAcOneSpace LITERAL1 +kElectraAcSensorMaxTemp LITERAL1 +kElectraAcSensorMinTemp LITERAL1 +kElectraAcSensorTempDelta LITERAL1 kElectraAcStateLength LITERAL1 kElectraAcSwingOff LITERAL1 kElectraAcSwingOn LITERAL1 @@ -2008,8 +2096,11 @@ kEyeAutoStr LITERAL1 kEyeStr LITERAL1 kFalseStr LITERAL1 kFan LITERAL1 +kFanOnlyNoSpaceStr LITERAL1 kFanOnlyStr LITERAL1 +kFanOnlyWithSpaceStr LITERAL1 kFanStr LITERAL1 +kFan_OnlyStr LITERAL1 kFastStr LITERAL1 kFilterStr LITERAL1 kFixedStr LITERAL1 @@ -2064,6 +2155,7 @@ kFujitsuAcTempOffsetC LITERAL1 kFujitsuAcTempOffsetF LITERAL1 kFujitsuAcTimerMax LITERAL1 kFujitsuAcZeroSpace LITERAL1 +kGe6711ar2853mStr LITERAL1 kGicableBitMark LITERAL1 kGicableBits LITERAL1 kGicableHdrMark LITERAL1 @@ -2146,6 +2238,13 @@ kGreeStateLength LITERAL1 kGreeSwingAuto LITERAL1 kGreeSwingDown LITERAL1 kGreeSwingDownAuto LITERAL1 +kGreeSwingHAuto LITERAL1 +kGreeSwingHLeft LITERAL1 +kGreeSwingHMaxLeft LITERAL1 +kGreeSwingHMaxRight LITERAL1 +kGreeSwingHMiddle LITERAL1 +kGreeSwingHOff LITERAL1 +kGreeSwingHRight LITERAL1 kGreeSwingLastPos LITERAL1 kGreeSwingMiddle LITERAL1 kGreeSwingMiddleAuto LITERAL1 @@ -2155,6 +2254,7 @@ kGreeSwingUp LITERAL1 kGreeSwingUpAuto LITERAL1 kGreeTimerMax LITERAL1 kGreeZeroSpace LITERAL1 +kGz055be1Str LITERAL1 kHaierAC176Bits LITERAL1 kHaierAC176StateLength LITERAL1 kHaierACBits LITERAL1 @@ -2195,21 +2295,26 @@ kHaierAcMinTemp LITERAL1 kHaierAcOneSpace LITERAL1 kHaierAcPrefix LITERAL1 kHaierAcSleepBit LITERAL1 -kHaierAcSwingChg LITERAL1 -kHaierAcSwingDown LITERAL1 -kHaierAcSwingOff LITERAL1 -kHaierAcSwingUp LITERAL1 +kHaierAcSwingVChg LITERAL1 +kHaierAcSwingVDown LITERAL1 +kHaierAcSwingVOff LITERAL1 +kHaierAcSwingVUp LITERAL1 kHaierAcYrw02Auto LITERAL1 +kHaierAcYrw02ButtonCFAB LITERAL1 kHaierAcYrw02ButtonFan LITERAL1 kHaierAcYrw02ButtonHealth LITERAL1 +kHaierAcYrw02ButtonLock LITERAL1 kHaierAcYrw02ButtonMode LITERAL1 kHaierAcYrw02ButtonPower LITERAL1 kHaierAcYrw02ButtonSleep LITERAL1 -kHaierAcYrw02ButtonSwing LITERAL1 +kHaierAcYrw02ButtonSwingH LITERAL1 +kHaierAcYrw02ButtonSwingV LITERAL1 kHaierAcYrw02ButtonTempDown LITERAL1 kHaierAcYrw02ButtonTempUp LITERAL1 +kHaierAcYrw02ButtonTimer LITERAL1 kHaierAcYrw02ButtonTurbo LITERAL1 kHaierAcYrw02Cool LITERAL1 +kHaierAcYrw02DefTempC LITERAL1 kHaierAcYrw02DefaultRepeat LITERAL1 kHaierAcYrw02Dry LITERAL1 kHaierAcYrw02Fan LITERAL1 @@ -2218,26 +2323,35 @@ kHaierAcYrw02FanHigh LITERAL1 kHaierAcYrw02FanLow LITERAL1 kHaierAcYrw02FanMed LITERAL1 kHaierAcYrw02Heat LITERAL1 +kHaierAcYrw02MaxTempC LITERAL1 +kHaierAcYrw02MaxTempF LITERAL1 +kHaierAcYrw02MinTempC LITERAL1 +kHaierAcYrw02MinTempF LITERAL1 +kHaierAcYrw02ModelA LITERAL1 +kHaierAcYrw02ModelB LITERAL1 kHaierAcYrw02NoTimers LITERAL1 kHaierAcYrw02OffThenOnTimer LITERAL1 kHaierAcYrw02OffTimer LITERAL1 kHaierAcYrw02OnThenOffTimer LITERAL1 kHaierAcYrw02OnTimer LITERAL1 -kHaierAcYrw02Prefix LITERAL1 -kHaierAcYrw02SwingAuto LITERAL1 -kHaierAcYrw02SwingBottom LITERAL1 -kHaierAcYrw02SwingDown LITERAL1 -kHaierAcYrw02SwingMiddle LITERAL1 -kHaierAcYrw02SwingOff LITERAL1 -kHaierAcYrw02SwingTop LITERAL1 -kHaierAcYrw02TurboHigh LITERAL1 -kHaierAcYrw02TurboLow LITERAL1 -kHaierAcYrw02TurboOff LITERAL1 +kHaierAcYrw02SwingHAuto LITERAL1 +kHaierAcYrw02SwingHLeft LITERAL1 +kHaierAcYrw02SwingHLeftMax LITERAL1 +kHaierAcYrw02SwingHMiddle LITERAL1 +kHaierAcYrw02SwingHRight LITERAL1 +kHaierAcYrw02SwingHRightMax LITERAL1 +kHaierAcYrw02SwingVAuto LITERAL1 +kHaierAcYrw02SwingVBottom LITERAL1 +kHaierAcYrw02SwingVDown LITERAL1 +kHaierAcYrw02SwingVMiddle LITERAL1 +kHaierAcYrw02SwingVOff LITERAL1 +kHaierAcYrw02SwingVTop LITERAL1 kHaierAcZeroSpace LITERAL1 kHeader LITERAL1 kHealthStr LITERAL1 kHeat LITERAL1 kHeatStr LITERAL1 +kHeatingStr LITERAL1 kHiStr LITERAL1 kHigh LITERAL1 kHighNibble LITERAL1 @@ -2377,6 +2491,7 @@ kInaxTick LITERAL1 kInaxZeroSpace LITERAL1 kInsideStr LITERAL1 kIonStr LITERAL1 +kJkeStr LITERAL1 kJvcBitMark LITERAL1 kJvcBitMarkTicks LITERAL1 kJvcBits LITERAL1 @@ -2445,6 +2560,8 @@ kKelvinatorStateLength LITERAL1 kKelvinatorTick LITERAL1 kKelvinatorZeroSpace LITERAL1 kKelvinatorZeroSpaceTicks LITERAL1 +kKkg29ac1Str LITERAL1 +kKkg9ac1Str LITERAL1 kLasertagBits LITERAL1 kLasertagDelta LITERAL1 kLasertagExcess LITERAL1 @@ -2461,6 +2578,7 @@ kLastSwinghEnum LITERAL1 kLastSwingvEnum LITERAL1 kLeft LITERAL1 kLeftMax LITERAL1 +kLeftMaxNoSpaceStr LITERAL1 kLeftMaxStr LITERAL1 kLeftStr LITERAL1 kLegoPfBitMark LITERAL1 @@ -2544,7 +2662,9 @@ kLgRptSpace LITERAL1 kLgZeroSpace LITERAL1 kLightStr LITERAL1 kLightToggleStr LITERAL1 +kLkeStr LITERAL1 kLoStr LITERAL1 +kLockStr LITERAL1 kLoudStr LITERAL1 kLow LITERAL1 kLowNibble LITERAL1 @@ -2578,7 +2698,9 @@ kMarkExcess LITERAL1 kMarkState LITERAL1 kMax LITERAL1 kMaxAccurateUsecDelay LITERAL1 +kMaxLeftNoSpaceStr LITERAL1 kMaxLeftStr LITERAL1 +kMaxRightNoSpaceStr LITERAL1 kMaxRightStr LITERAL1 kMaxStr LITERAL1 kMaxTimeoutMs LITERAL1 @@ -2661,6 +2783,34 @@ kMinStr LITERAL1 kMinimumStr LITERAL1 kMinuteStr LITERAL1 kMinutesStr LITERAL1 +kMirageAcCool LITERAL1 +kMirageAcDry LITERAL1 +kMirageAcFan LITERAL1 +kMirageAcFanAuto LITERAL1 +kMirageAcFanHigh LITERAL1 +kMirageAcFanLow LITERAL1 +kMirageAcFanMed LITERAL1 +kMirageAcHeat LITERAL1 +kMirageAcKKG29AC1FanAuto LITERAL1 +kMirageAcKKG29AC1FanHigh LITERAL1 +kMirageAcKKG29AC1FanLow LITERAL1 +kMirageAcKKG29AC1FanMed LITERAL1 +kMirageAcKKG29AC1PowerOff LITERAL1 +kMirageAcKKG29AC1PowerOn LITERAL1 +kMirageAcMaxTemp LITERAL1 +kMirageAcMinTemp LITERAL1 +kMirageAcPowerOff LITERAL1 +kMirageAcRecycle LITERAL1 +kMirageAcSensorTempMax LITERAL1 +kMirageAcSensorTempOffset LITERAL1 +kMirageAcSwingVAuto LITERAL1 +kMirageAcSwingVHigh LITERAL1 +kMirageAcSwingVHighest LITERAL1 +kMirageAcSwingVLow LITERAL1 +kMirageAcSwingVLowest LITERAL1 +kMirageAcSwingVMiddle LITERAL1 +kMirageAcSwingVOff LITERAL1 +kMirageAcTempOffset LITERAL1 kMirageBitMark LITERAL1 kMirageBits LITERAL1 kMirageFreq LITERAL1 @@ -2954,6 +3104,7 @@ kNikaiOneSpaceTicks LITERAL1 kNikaiTick LITERAL1 kNikaiZeroSpace LITERAL1 kNikaiZeroSpaceTicks LITERAL1 +kNkeStr LITERAL1 kNoRepeat LITERAL1 kNoStr LITERAL1 kNowStr LITERAL1 @@ -3042,20 +3193,27 @@ kPanasonicAcTolerance LITERAL1 kPanasonicBitMark LITERAL1 kPanasonicBits LITERAL1 kPanasonicCkp LITERAL1 +kPanasonicCkpStr LITERAL1 kPanasonicDke LITERAL1 +kPanasonicDkeStr LITERAL1 kPanasonicEndGap LITERAL1 kPanasonicFreq LITERAL1 kPanasonicHdrMark LITERAL1 kPanasonicHdrSpace LITERAL1 kPanasonicJke LITERAL1 +kPanasonicJkeStr LITERAL1 kPanasonicKnownGoodState LITERAL1 kPanasonicLke LITERAL1 +kPanasonicLkeStr LITERAL1 kPanasonicManufacturer LITERAL1 kPanasonicMinCommandLength LITERAL1 kPanasonicMinGap LITERAL1 kPanasonicNke LITERAL1 +kPanasonicNkeStr LITERAL1 kPanasonicOneSpace LITERAL1 +kPanasonicPkrStr LITERAL1 kPanasonicRkr LITERAL1 +kPanasonicRkrStr LITERAL1 kPanasonicUnknown LITERAL1 kPanasonicZeroSpace LITERAL1 kPeriodOffset LITERAL1 @@ -3068,6 +3226,7 @@ kPioneerMinGap LITERAL1 kPioneerOneSpace LITERAL1 kPioneerTick LITERAL1 kPioneerZeroSpace LITERAL1 +kPkrStr LITERAL1 kPowerButtonStr LITERAL1 kPowerStr LITERAL1 kPowerToggleStr LITERAL1 @@ -3145,10 +3304,44 @@ kRcz01SignatureMask LITERAL1 kRecycleStr LITERAL1 kRepeat LITERAL1 kRepeatStr LITERAL1 +kRhossBitMark LITERAL1 +kRhossBits LITERAL1 +kRhossDefaultFan LITERAL1 +kRhossDefaultMode LITERAL1 +kRhossDefaultPower LITERAL1 +kRhossDefaultRepeat LITERAL1 +kRhossDefaultSwing LITERAL1 +kRhossDefaultTemp LITERAL1 +kRhossFanAuto LITERAL1 +kRhossFanMax LITERAL1 +kRhossFanMed LITERAL1 +kRhossFanMin LITERAL1 +kRhossFreq LITERAL1 +kRhossGap LITERAL1 +kRhossHdrMark LITERAL1 +kRhossHdrSpace LITERAL1 +kRhossModeAuto LITERAL1 +kRhossModeCool LITERAL1 +kRhossModeDry LITERAL1 +kRhossModeFan LITERAL1 +kRhossModeHeat LITERAL1 +kRhossOneSpace LITERAL1 +kRhossPowerOff LITERAL1 +kRhossPowerOn LITERAL1 +kRhossStateLength LITERAL1 +kRhossSwingOff LITERAL1 +kRhossSwingOn LITERAL1 +kRhossTempMax LITERAL1 +kRhossTempMin LITERAL1 +kRhossZeroSpace LITERAL1 kRight LITERAL1 kRightMax LITERAL1 +kRightMaxNoSpaceStr LITERAL1 kRightMaxStr LITERAL1 kRightStr LITERAL1 +kRkrStr LITERAL1 +kRlt0541htaaStr LITERAL1 +kRlt0541htabStr LITERAL1 kRoomStr LITERAL1 kSamsung36BitMark LITERAL1 kSamsung36Bits LITERAL1 @@ -3164,6 +3357,7 @@ kSamsungAcBreezeOn LITERAL1 kSamsungAcCool LITERAL1 kSamsungAcDefaultRepeat LITERAL1 kSamsungAcDry LITERAL1 +kSamsungAcEconoOn LITERAL1 kSamsungAcExtendedBits LITERAL1 kSamsungAcExtendedStateLength LITERAL1 kSamsungAcFan LITERAL1 @@ -3172,6 +3366,7 @@ kSamsungAcFanAuto2 LITERAL1 kSamsungAcFanHigh LITERAL1 kSamsungAcFanLow LITERAL1 kSamsungAcFanMed LITERAL1 +kSamsungAcFanSpecialOff LITERAL1 kSamsungAcFanTurbo LITERAL1 kSamsungAcHdrMark LITERAL1 kSamsungAcHdrSpace LITERAL1 @@ -3180,16 +3375,17 @@ kSamsungAcMaxTemp LITERAL1 kSamsungAcMinTemp LITERAL1 kSamsungAcOneSpace LITERAL1 kSamsungAcPowerSection LITERAL1 -kSamsungAcPowerful10On LITERAL1 -kSamsungAcPowerfulMask8 LITERAL1 +kSamsungAcPowerfulOn LITERAL1 kSamsungAcSectionGap LITERAL1 kSamsungAcSectionLength LITERAL1 kSamsungAcSectionMark LITERAL1 kSamsungAcSectionSpace LITERAL1 kSamsungAcSections LITERAL1 kSamsungAcStateLength LITERAL1 -kSamsungAcSwingMove LITERAL1 -kSamsungAcSwingStop LITERAL1 +kSamsungAcSwingBoth LITERAL1 +kSamsungAcSwingH LITERAL1 +kSamsungAcSwingOff LITERAL1 +kSamsungAcSwingV LITERAL1 kSamsungAcZeroSpace LITERAL1 kSamsungBitMark LITERAL1 kSamsungBitMarkTicks LITERAL1 @@ -3326,8 +3522,15 @@ kSharpAcSpecialTimer LITERAL1 kSharpAcSpecialTimerHalfHour LITERAL1 kSharpAcSpecialTurbo LITERAL1 kSharpAcStateLength LITERAL1 -kSharpAcSwingNoToggle LITERAL1 -kSharpAcSwingToggle LITERAL1 +kSharpAcSwingVCoanda LITERAL1 +kSharpAcSwingVHigh LITERAL1 +kSharpAcSwingVIgnore LITERAL1 +kSharpAcSwingVLast LITERAL1 +kSharpAcSwingVLow LITERAL1 +kSharpAcSwingVLowest LITERAL1 +kSharpAcSwingVMid LITERAL1 +kSharpAcSwingVOff LITERAL1 +kSharpAcSwingVToggle LITERAL1 kSharpAcTimerHoursMax LITERAL1 kSharpAcTimerHoursOff LITERAL1 kSharpAcTimerIncrement LITERAL1 @@ -3397,6 +3600,7 @@ kSymphonyOneMark LITERAL1 kSymphonyOneSpace LITERAL1 kSymphonyZeroMark LITERAL1 kSymphonyZeroSpace LITERAL1 +kTac09chsdStr LITERAL1 kTcl112AcAuto LITERAL1 kTcl112AcBitMark LITERAL1 kTcl112AcBits LITERAL1 @@ -3408,6 +3612,9 @@ kTcl112AcFanAuto LITERAL1 kTcl112AcFanHigh LITERAL1 kTcl112AcFanLow LITERAL1 kTcl112AcFanMed LITERAL1 +kTcl112AcFanMin LITERAL1 +kTcl112AcFanNight LITERAL1 +kTcl112AcFanQuiet LITERAL1 kTcl112AcGap LITERAL1 kTcl112AcHdrMark LITERAL1 kTcl112AcHdrMarkTolerance LITERAL1 @@ -3417,10 +3624,17 @@ kTcl112AcNormal LITERAL1 kTcl112AcOneSpace LITERAL1 kTcl112AcSpecial LITERAL1 kTcl112AcStateLength LITERAL1 +kTcl112AcSwingVHigh LITERAL1 +kTcl112AcSwingVHighest LITERAL1 +kTcl112AcSwingVLow LITERAL1 +kTcl112AcSwingVLowest LITERAL1 +kTcl112AcSwingVMiddle LITERAL1 kTcl112AcSwingVOff LITERAL1 kTcl112AcSwingVOn LITERAL1 kTcl112AcTempMax LITERAL1 kTcl112AcTempMin LITERAL1 +kTcl112AcTimerMax LITERAL1 +kTcl112AcTimerResolution LITERAL1 kTcl112AcTolerance LITERAL1 kTcl112AcZeroSpace LITERAL1 kTechnibelAcBitMark LITERAL1 @@ -3482,6 +3696,7 @@ kTempDownStr LITERAL1 kTempStr LITERAL1 kTempUpStr LITERAL1 kThreeLetterDayOfWeekStr LITERAL1 +kTimeSep LITERAL1 kTimeoutMs LITERAL1 kTimerModeStr LITERAL1 kTimerStr LITERAL1 @@ -3617,6 +3832,8 @@ kUnknownThreshold LITERAL1 kUpStr LITERAL1 kUpperStr LITERAL1 kUseDefTol LITERAL1 +kV9014557AStr LITERAL1 +kV9014557BStr LITERAL1 kVaneStr LITERAL1 kVestelAcAuto LITERAL1 kVestelAcBitMark LITERAL1 @@ -3737,6 +3954,8 @@ kXmpRepeatCodeAlt LITERAL1 kXmpSections LITERAL1 kXmpSpaceStep LITERAL1 kXmpWordSize LITERAL1 +kYaw1fStr LITERAL1 +kYbofbStr LITERAL1 kYesStr LITERAL1 kZepealBits LITERAL1 kZepealCommandOffOn LITERAL1 diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.json b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.json index 5bce2238e..99160ec37 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.json +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.json @@ -1,6 +1,6 @@ { "name": "IRremoteESP8266", - "version": "2.7.20", + "version": "2.8.0", "keywords": "infrared, ir, remote, esp8266, esp32", "description": "Send and receive infrared signals with multiple protocols (ESP8266/ESP32)", "repository": diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.properties b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.properties index e4985e2a2..e7580dd2d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.properties +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/library.properties @@ -1,5 +1,5 @@ name=IRremoteESP8266 -version=2.7.20 +version=2.8.0 author=David Conran, Sebastien Warin, Mark Szabo, Ken Shirriff maintainer=David Conran, Mark Szabo, Sebastien Warin, Roi Dayan, Massimiliano Pinto, Christian Nilsson sentence=Send and receive infrared signals with multiple protocols (ESP8266/ESP32) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.cpp index 9b4e10cbd..557e5593e 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.cpp @@ -36,6 +36,7 @@ #include "ir_MitsubishiHeavy.h" #include "ir_Neoclima.h" #include "ir_Panasonic.h" +#include "ir_Rhoss.h" #include "ir_Samsung.h" #include "ir_Sanyo.h" #include "ir_Sharp.h" @@ -50,6 +51,17 @@ #include "ir_Voltas.h" #include "ir_Whirlpool.h" +// On the ESP8266 platform we need to use a special version of string handling +// functions to handle the strings stored in the flash address space. +#ifndef STRCASECMP +#if defined(ESP8266) +#define STRCASECMP(LHS, RHS) \ + strcasecmp_P(LHS, reinterpret_cast(RHS)) +#else // ESP8266 +#define STRCASECMP(LHS, RHS) strcasecmp(LHS, RHS) +#endif // ESP8266 +#endif // STRCASECMP + /// Class constructor /// @param[in] pin Gpio pin to use when transmitting IR messages. /// @param[in] inverted true, gpio output defaults to high. false, to low. @@ -233,7 +245,10 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) { #endif #if SEND_MIDEA case decode_type_t::MIDEA: -#endif +#endif // SEND_MIDEA +#if SEND_MIRAGE + case decode_type_t::MIRAGE: +#endif // SEND_MIRAGE #if SEND_MITSUBISHI_AC case decode_type_t::MITSUBISHI_AC: #endif @@ -256,6 +271,9 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) { #if SEND_PANASONIC_AC32 case decode_type_t::PANASONIC_AC32: #endif +#if SEND_RHOSS + case decode_type_t::RHOSS: +#endif #if SEND_SAMSUNG_AC case decode_type_t::SAMSUNG_AC: #endif @@ -277,6 +295,9 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) { #if SEND_TECO case decode_type_t::TECO: #endif +#if SEND_TEKNOPOINT + case decode_type_t::TEKNOPOINT: +#endif // SEND_TEKNOPOINT #if SEND_TOSHIBA_AC case decode_type_t::TOSHIBA_AC: #endif @@ -1018,15 +1039,18 @@ void IRac::goodweather(IRGoodweatherAc *ac, /// @param[in] degrees The temperature setting in degrees. /// @param[in] fan The speed setting for the fan. /// @param[in] swingv The vertical swing setting. +/// @param[in] swingh The horizontal swing setting. /// @param[in] turbo Run the device in turbo/powerful mode. +/// @param[in] econo Toggle the device's economical mode. /// @param[in] light Turn on the LED/Display mode. /// @param[in] clean Turn on the self-cleaning mode. e.g. Mould, dry filters etc /// @param[in] sleep Nr. of minutes for sleep mode. -1 is Off, >= 0 is on. void IRac::gree(IRGreeAC *ac, const gree_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, - const stdAc::swingv_t swingv, const bool turbo, - const bool light, const bool clean, const int16_t sleep) { + const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, + const bool turbo, const bool econo, const bool light, + const bool clean, const int16_t sleep) { ac->begin(); ac->setModel(model); ac->setPower(on); @@ -1035,11 +1059,12 @@ void IRac::gree(IRGreeAC *ac, const gree_ac_remote_model_t model, ac->setFan(ac->convertFan(fan)); ac->setSwingVertical(swingv == stdAc::swingv_t::kAuto, // Set auto flag. ac->convertSwingV(swingv)); + ac->setSwingHorizontal(ac->convertSwingH(swingh)); ac->setLight(light); ac->setTurbo(turbo); + ac->setEcono(econo); ac->setXFan(clean); ac->setSleep(sleep >= 0); // Sleep on this A/C is either on or off. - // No Horizontal Swing setting available. // No Econo setting available. // No Filter setting available. // No Beep setting available. @@ -1068,7 +1093,7 @@ void IRac::haier(IRHaierAC *ac, ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); - ac->setSwing(ac->convertSwingV(swingv)); + ac->setSwingV(ac->convertSwingV(swingv)); // No Horizontal Swing setting available. // No Quiet setting available. // No Turbo setting available. @@ -1089,26 +1114,35 @@ void IRac::haier(IRHaierAC *ac, #if SEND_HAIER_AC176 /// Send a Haier 176 bit A/C message with the supplied settings. /// @param[in, out] ac A Ptr to an IRHaierAC176 object to use. +/// @param[in] model The A/C model to use. /// @param[in] on The power setting. /// @param[in] mode The operation mode setting. +/// @param[in] celsius Temperature units. True is Celsius, False is Fahrenheit. /// @param[in] degrees The temperature setting in degrees. /// @param[in] fan The speed setting for the fan. /// @param[in] swingv The vertical swing setting. +/// @param[in] swingh The horizontal swing setting. /// @param[in] turbo Run the device in turbo/powerful mode. +/// @param[in] quiet Run the device in quiet mode. /// @param[in] filter Turn on the (ion/pollen/etc) filter mode. /// @param[in] sleep Nr. of minutes for sleep mode. -1 is Off, >= 0 is on. -void IRac::haier176(IRHaierAC176 *ac, +void IRac::haier176(IRHaierAC176 *ac, const haier_ac176_remote_model_t model, const bool on, const stdAc::opmode_t mode, - const float degrees, const stdAc::fanspeed_t fan, - const stdAc::swingv_t swingv, const bool turbo, - const bool filter, const int16_t sleep) { + const bool celsius, const float degrees, + const stdAc::fanspeed_t fan, + const stdAc::swingv_t swingv, + const stdAc::swingh_t swingh, + const bool turbo, const bool quiet, const bool filter, + const int16_t sleep) { ac->begin(); + ac->setModel(model); ac->setMode(ac->convertMode(mode)); + ac->setUseFahrenheit(!celsius); ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); - ac->setSwing(ac->convertSwingV(swingv)); - // No Horizontal Swing setting available. - // No Quiet setting available. + ac->setSwingV(ac->convertSwingV(swingv)); + ac->setSwingH(ac->convertSwingH(swingh)); + ac->setQuiet(quiet); ac->setTurbo(turbo); // No Light setting available. ac->setHealth(filter); @@ -1125,24 +1159,31 @@ void IRac::haier176(IRHaierAC176 *ac, /// @param[in, out] ac A Ptr to an IRHaierACYRW02 object to use. /// @param[in] on The power setting. /// @param[in] mode The operation mode setting. +/// @param[in] celsius Temperature units. True is Celsius, False is Fahrenheit. /// @param[in] degrees The temperature setting in degrees. /// @param[in] fan The speed setting for the fan. /// @param[in] swingv The vertical swing setting. +/// @param[in] swingh The horizontal swing setting. /// @param[in] turbo Run the device in turbo/powerful mode. +/// @param[in] quiet Run the device in quiet mode. /// @param[in] filter Turn on the (ion/pollen/etc) filter mode. /// @param[in] sleep Nr. of minutes for sleep mode. -1 is Off, >= 0 is on. void IRac::haierYrwo2(IRHaierACYRW02 *ac, const bool on, const stdAc::opmode_t mode, - const float degrees, const stdAc::fanspeed_t fan, - const stdAc::swingv_t swingv, const bool turbo, - const bool filter, const int16_t sleep) { + const bool celsius, const float degrees, + const stdAc::fanspeed_t fan, + const stdAc::swingv_t swingv, + const stdAc::swingh_t swingh, + const bool turbo, const bool quiet, const bool filter, + const int16_t sleep) { ac->begin(); ac->setMode(ac->convertMode(mode)); + ac->setUseFahrenheit(!celsius); ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); - ac->setSwing(ac->convertSwingV(swingv)); - // No Horizontal Swing setting available. - // No Quiet setting available. + ac->setSwingV(ac->convertSwingV(swingv)); + ac->setSwingH(ac->convertSwingH(swingh)); + ac->setQuiet(quiet); ac->setTurbo(turbo); // No Light setting available. ac->setHealth(filter); @@ -1450,6 +1491,17 @@ void IRac::midea(IRMideaAC *ac, } #endif // SEND_MIDEA +#if SEND_MIRAGE +/// Send a Mirage 120-bit A/C message with the supplied settings. +/// @param[in, out] ac A Ptr to an IRMitsubishiAC object to use. +/// @param[in] state The desired state to send. +void IRac::mirage(IRMirageAc *ac, const stdAc::state_t state) { + ac->begin(); + ac->fromCommon(state); + ac->send(); +} +#endif // SEND_MIRAGE + #if SEND_MITSUBISHI_AC /// Send a Mitsubishi A/C message with the supplied settings. /// @param[in, out] ac A Ptr to an IRMitsubishiAC object to use. @@ -1766,38 +1818,45 @@ void IRac::panasonic32(IRPanasonicAc32 *ac, /// @param[in] degrees The temperature setting in degrees. /// @param[in] fan The speed setting for the fan. /// @param[in] swingv The vertical swing setting. +/// @param[in] swingh The horizontal swing setting. /// @param[in] quiet Run the device in quiet/silent mode. /// @param[in] turbo Run the device in turbo/powerful mode. +/// @param[in] econo Run the device in economical mode. /// @param[in] light Turn on the LED/Display mode. /// @param[in] filter Turn on the (ion/pollen/etc) filter mode. -/// @param[in] clean Turn on the self-cleaning mode. e.g. Mould, dry filters etc -/// @param[in] beep Enable/Disable beeps when receiving IR messages. +/// @param[in] clean Toggle the self-cleaning mode. e.g. Mould, dry filters etc +/// @param[in] beep Toggle beep setting for receiving IR messages. +/// @param[in] sleep Nr. of minutes for sleep mode. <= 0 is Off, > 0 is on. /// @param[in] prevpower The power setting from the previous A/C state. -/// @param[in] forcepower Do we force send the special power message? +/// @param[in] prevsleep Nr. of minutes for sleep from the previous A/C state. +/// @param[in] forceextended Do we force sending the special extended message? void IRac::samsung(IRSamsungAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, - const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, - const bool quiet, const bool turbo, const bool light, + const stdAc::fanspeed_t fan, + const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, + const bool quiet, const bool turbo, const bool econo, + const bool light, const bool filter, const bool clean, - const bool beep, const bool prevpower, - const bool forcepower) { + const bool beep, const int16_t sleep, + const bool prevpower, const int16_t prevsleep, + const bool forceextended) { ac->begin(); - ac->stateReset(forcepower, prevpower); + ac->stateReset(forceextended || (sleep != prevsleep), prevpower); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); ac->setSwing(swingv != stdAc::swingv_t::kOff); - // No Horizontal swing setting available. + ac->setSwingH(swingh != stdAc::swingh_t::kOff); ac->setQuiet(quiet); - ac->setPowerful(turbo); + ac->setPowerful(turbo); // FYI, `setEcono(true)` will override this. ac->setDisplay(light); - // No Econo setting available. + ac->setEcono(econo); ac->setIon(filter); - ac->setClean(clean); - ac->setBeep(beep); - // No Sleep setting available. + ac->setClean(clean); // Toggle + ac->setBeep(beep); // Toggle + ac->setSleepTimer((sleep <= 0) ? 0 : sleep); // No Clock setting available. // Do setMode() again as it can affect fan speed. ac->setMode(ac->convertMode(mode)); @@ -1893,6 +1952,7 @@ void IRac::sanyo88(IRSanyoAc88 *ac, /// @param[in] degrees The temperature setting in degrees. /// @param[in] fan The speed setting for the fan. /// @param[in] swingv The vertical swing setting. +/// @param[in] swingv_prev The previous vertical swing setting. /// @param[in] turbo Run the device in turbo/powerful mode. /// @param[in] light Turn on the LED/Display mode. /// @param[in] filter Turn on the (ion/pollen/etc) filter mode. @@ -1901,14 +1961,15 @@ void IRac::sharp(IRSharpAc *ac, const sharp_ac_remote_model_t model, const bool on, const bool prev_power, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, - const stdAc::swingv_t swingv, const bool turbo, + const stdAc::swingv_t swingv, + const stdAc::swingv_t swingv_prev, const bool turbo, const bool light, const bool filter, const bool clean) { ac->begin(); ac->setModel(model); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); ac->setFan(ac->convertFan(fan, model)); - ac->setSwingToggle(swingv != stdAc::swingv_t::kOff); + if (swingv != swingv_prev) ac->setSwingV(ac->convertSwingV(swingv)); // Econo deliberately not used as it cycles through 3 modes uncontrollably. // ac->setEconoToggle(econo); ac->setIon(filter); @@ -1940,6 +2001,7 @@ void IRac::sharp(IRSharpAc *ac, const sharp_ac_remote_model_t model, #if SEND_TCL112AC /// Send a TCL 112-bit A/C message with the supplied settings. /// @param[in, out] ac A Ptr to an IRTcl112Ac object to use. +/// @param[in] model The A/C model to use. /// @param[in] on The power setting. /// @param[in] mode The operation mode setting. /// @param[in] degrees The temperature setting in degrees. @@ -1951,18 +2013,19 @@ void IRac::sharp(IRSharpAc *ac, const sharp_ac_remote_model_t model, /// @param[in] light Turn on the LED/Display mode. /// @param[in] econo Run the device in economical mode. /// @param[in] filter Turn on the (ion/pollen/etc) filter mode. -void IRac::tcl112(IRTcl112Ac *ac, +void IRac::tcl112(IRTcl112Ac *ac, const tcl_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const bool light, const bool econo, const bool filter) { ac->begin(); + ac->setModel(model); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); - ac->setSwingVertical(swingv != stdAc::swingv_t::kOff); + ac->setSwingVertical(ac->convertSwingV(swingv)); ac->setSwingHorizontal(swingh != stdAc::swingh_t::kOff); ac->setQuiet(quiet); ac->setTurbo(turbo); @@ -2341,6 +2404,35 @@ void IRac::transcold(IRTranscoldAc *ac, } #endif // SEND_TRANSCOLD +#if SEND_RHOSS +/// Send an Rhoss A/C message with the supplied settings. +/// @param[in, out] ac A Ptr to an IRRhossAc object to use. +/// @param[in] on The power setting. +/// @param[in] mode The operation mode setting. +/// @param[in] degrees The temperature setting in degrees. +/// @param[in] fan The speed setting for the fan. +/// @param[in] swing The swing setting. +void IRac::rhoss(IRRhossAc *ac, + const bool on, const stdAc::opmode_t mode, const float degrees, + const stdAc::fanspeed_t fan, const stdAc::swingv_t swing) { + ac->begin(); + ac->setPower(on); + ac->setMode(ac->convertMode(mode)); + ac->setSwing(swing != stdAc::swingv_t::kOff); + ac->setTemp(degrees); + ac->setFan(ac->convertFan(fan)); + // No Quiet setting available. + // No Light setting available. + // No Filter setting available. + // No Turbo setting available. + // No Economy setting available. + // No Clean setting available. + // No Beep setting available. + // No Sleep setting available. + ac->send(); +} +#endif // SEND_RHOSS + /// Create a new state base on the provided state that has been suitably fixed. /// @note This is for use with Home Assistant, which requires mode to be off if /// the power is off. @@ -2425,11 +2517,20 @@ stdAc::state_t IRac::handleToggles(const stdAc::state_t desired, case decode_type_t::WHIRLPOOL_AC: result.power = desired.power ^ prev->power; break; + case decode_type_t::MIRAGE: + if (desired.model == mirage_ac_remote_model_t::KKG29AC1) + result.light = desired.light ^ prev->light; + result.clean = desired.clean ^ prev->clean; + break; case decode_type_t::PANASONIC_AC: // CKP models use a power mode toggle. if (desired.model == panasonic_ac_remote_model_t::kPanasonicCkp) result.power = desired.power ^ prev->power; break; + case decode_type_t::SAMSUNG_AC: + result.beep = desired.beep ^ prev->beep; + result.clean = desired.clean ^ prev->clean; + break; default: {}; } @@ -2494,11 +2595,12 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { // Construct a pointer-safe previous power state incase prev is NULL/NULLPTR. #if (SEND_HITACHI_AC1 || SEND_SAMSUNG_AC || SEND_SHARP_AC) const bool prev_power = (prev != NULL) ? prev->power : !send.power; + const int16_t prev_sleep = (prev != NULL) ? prev->sleep : -1; #endif // (SEND_HITACHI_AC1 || SEND_SAMSUNG_AC || SEND_SHARP_AC) -#if SEND_LG +#if (SEND_LG || SEND_SHARP_AC) const stdAc::swingv_t prev_swingv = (prev != NULL) ? prev->swingv : stdAc::swingv_t::kOff; -#endif // SEND_LG +#endif // (SEND_LG || SEND_SHARP_AC) // Per vendor settings & setup. switch (send.protocol) { #if SEND_AIRWELL @@ -2678,8 +2780,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { IRGreeAC ac(_pin, (gree_ac_remote_model_t)send.model, _inverted, _modulation); gree(&ac, (gree_ac_remote_model_t)send.model, send.power, send.mode, - send.celsius, send.degrees, send.fanspeed, send.swingv, send.turbo, - send.light, send.clean, send.sleep); + send.celsius, send.degrees, send.fanspeed, send.swingv, send.swingh, + send.turbo, send.econo, send.light, send.clean, send.sleep); break; } #endif // SEND_GREE @@ -2696,8 +2798,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case HAIER_AC176: { IRHaierAC176 ac(_pin, _inverted, _modulation); - haier176(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, - send.turbo, send.filter, send.sleep); + haier176(&ac, (haier_ac176_remote_model_t)send.model, send.power, + send.mode, send.celsius, send.degrees, send.fanspeed, + send.swingv, send.swingh, send.turbo, send.filter, send.sleep); break; } #endif // SEND_HAIER_AC176 @@ -2705,8 +2808,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case HAIER_AC_YRW02: { IRHaierACYRW02 ac(_pin, _inverted, _modulation); - haierYrwo2(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, - send.turbo, send.filter, send.sleep); + haierYrwo2(&ac, send.power, send.mode, send.celsius, send.degrees, + send.fanspeed, send.swingv, send.swingh, send.turbo, + send.filter, send.sleep); break; } #endif // SEND_HAIER_AC_YRW02 @@ -2792,6 +2896,14 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { break; } #endif // SEND_MIDEA +#if SEND_MIRAGE + case MIRAGE: + { + IRMirageAc ac(_pin, _inverted, _modulation); + mirage(&ac, send); + break; + } +#endif // SEND_MIRAGE #if SEND_MITSUBISHI_AC case MITSUBISHI_AC: { @@ -2866,13 +2978,22 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { break; } #endif // SEND_PANASONIC_AC32 +#if SEND_RHOSS + case RHOSS: + { + IRRhossAc ac(_pin, _inverted, _modulation); + rhoss(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv); + break; + } +#endif // SEND_RHOSS #if SEND_SAMSUNG_AC case SAMSUNG_AC: { IRSamsungAc ac(_pin, _inverted, _modulation); samsung(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, - send.quiet, send.turbo, send.light, send.filter, send.clean, - send.beep, prev_power); + send.swingh, send.quiet, send.turbo, send.econo, send.light, + send.filter, send.clean, send.beep, send.sleep, + prev_power, prev_sleep); break; } #endif // SEND_SAMSUNG_AC @@ -2899,21 +3020,25 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { { IRSharpAc ac(_pin, _inverted, _modulation); sharp(&ac, (sharp_ac_remote_model_t)send.model, send.power, prev_power, - send.mode, degC, send.fanspeed, send.swingv, send.turbo, send.light, - send.filter, send.clean); + send.mode, degC, send.fanspeed, send.swingv, prev_swingv, + send.turbo, send.light, send.filter, send.clean); break; } #endif // SEND_SHARP_AC -#if SEND_TCL112AC +#if (SEND_TCL112AC || SEND_TEKNOPOINT) case TCL112AC: + case TEKNOPOINT: { IRTcl112Ac ac(_pin, _inverted, _modulation); - tcl112(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, - send.swingh, send.quiet, send.turbo, send.light, send.econo, - send.filter); + tcl_ac_remote_model_t model = (tcl_ac_remote_model_t)send.model; + if (send.protocol == decode_type_t::TEKNOPOINT) + model = tcl_ac_remote_model_t::GZ055BE1; + tcl112(&ac, model, send.power, send.mode, + degC, send.fanspeed, send.swingv, send.swingh, send.quiet, + send.turbo, send.light, send.econo, send.filter); break; } -#endif // SEND_TCL112AC +#endif // (SEND_TCL112AC || SEND_TEKNOPOINT) #if SEND_TECHNIBEL_AC case TECHNIBEL_AC: { @@ -3048,25 +3173,31 @@ bool IRac::hasStateChanged(void) { return cmpStates(next, _prev); } /// @return The equivalent enum. stdAc::opmode_t IRac::strToOpmode(const char *str, const stdAc::opmode_t def) { - if (!strcasecmp(str, kAutoStr) || - !strcasecmp(str, kAutomaticStr)) + if (!STRCASECMP(str, kAutoStr) || + !STRCASECMP(str, kAutomaticStr)) return stdAc::opmode_t::kAuto; - else if (!strcasecmp(str, kOffStr) || - !strcasecmp(str, kStopStr)) + else if (!STRCASECMP(str, kOffStr) || + !STRCASECMP(str, kStopStr)) return stdAc::opmode_t::kOff; - else if (!strcasecmp(str, kCoolStr) || - !strcasecmp(str, "COOLING")) + else if (!STRCASECMP(str, kCoolStr) || + !STRCASECMP(str, kCoolingStr)) return stdAc::opmode_t::kCool; - else if (!strcasecmp(str, kHeatStr) || - !strcasecmp(str, "HEATING")) + else if (!STRCASECMP(str, kHeatStr) || + !STRCASECMP(str, kHeatingStr)) return stdAc::opmode_t::kHeat; - else if (!strcasecmp(str, kDryStr) || - !strcasecmp(str, "DRYING") || - !strcasecmp(str, "DEHUMIDIFY")) + else if (!STRCASECMP(str, kDryStr) || + !STRCASECMP(str, kDryingStr) || + !STRCASECMP(str, kDehumidifyStr)) return stdAc::opmode_t::kDry; - else if (!strcasecmp(str, kFanStr) || - !strcasecmp(str, "FANONLY") || - !strcasecmp(str, kFanOnlyStr)) + else if (!STRCASECMP(str, kFanStr) || + // The following Fans strings with "only" are required to help with + // HomeAssistant & Google Home Climate integration. + // For compatibility only. + // Ref: https://www.home-assistant.io/integrations/google_assistant/#climate-operation-modes + !STRCASECMP(str, kFanOnlyStr) || + !STRCASECMP(str, kFan_OnlyStr) || + !STRCASECMP(str, kFanOnlyWithSpaceStr) || + !STRCASECMP(str, kFanOnlyNoSpaceStr)) return stdAc::opmode_t::kFan; else return def; @@ -3078,26 +3209,26 @@ stdAc::opmode_t IRac::strToOpmode(const char *str, /// @return The equivalent enum. stdAc::fanspeed_t IRac::strToFanspeed(const char *str, const stdAc::fanspeed_t def) { - if (!strcasecmp(str, kAutoStr) || - !strcasecmp(str, kAutomaticStr)) + if (!STRCASECMP(str, kAutoStr) || + !STRCASECMP(str, kAutomaticStr)) return stdAc::fanspeed_t::kAuto; - else if (!strcasecmp(str, kMinStr) || - !strcasecmp(str, kMinimumStr) || - !strcasecmp(str, kLowestStr)) + else if (!STRCASECMP(str, kMinStr) || + !STRCASECMP(str, kMinimumStr) || + !STRCASECMP(str, kLowestStr)) return stdAc::fanspeed_t::kMin; - else if (!strcasecmp(str, kLowStr) || - !strcasecmp(str, kLoStr)) + else if (!STRCASECMP(str, kLowStr) || + !STRCASECMP(str, kLoStr)) return stdAc::fanspeed_t::kLow; - else if (!strcasecmp(str, kMedStr) || - !strcasecmp(str, kMediumStr) || - !strcasecmp(str, kMidStr)) + else if (!STRCASECMP(str, kMedStr) || + !STRCASECMP(str, kMediumStr) || + !STRCASECMP(str, kMidStr)) return stdAc::fanspeed_t::kMedium; - else if (!strcasecmp(str, kHighStr) || - !strcasecmp(str, kHiStr)) + else if (!STRCASECMP(str, kHighStr) || + !STRCASECMP(str, kHiStr)) return stdAc::fanspeed_t::kHigh; - else if (!strcasecmp(str, kMaxStr) || - !strcasecmp(str, kMaximumStr) || - !strcasecmp(str, kHighestStr)) + else if (!STRCASECMP(str, kMaxStr) || + !STRCASECMP(str, kMaximumStr) || + !STRCASECMP(str, kHighestStr)) return stdAc::fanspeed_t::kMax; else return def; @@ -3109,36 +3240,36 @@ stdAc::fanspeed_t IRac::strToFanspeed(const char *str, /// @return The equivalent enum. stdAc::swingv_t IRac::strToSwingV(const char *str, const stdAc::swingv_t def) { - if (!strcasecmp(str, kAutoStr) || - !strcasecmp(str, kAutomaticStr) || - !strcasecmp(str, kOnStr) || - !strcasecmp(str, kSwingStr)) + if (!STRCASECMP(str, kAutoStr) || + !STRCASECMP(str, kAutomaticStr) || + !STRCASECMP(str, kOnStr) || + !STRCASECMP(str, kSwingStr)) return stdAc::swingv_t::kAuto; - else if (!strcasecmp(str, kOffStr) || - !strcasecmp(str, kStopStr)) + else if (!STRCASECMP(str, kOffStr) || + !STRCASECMP(str, kStopStr)) return stdAc::swingv_t::kOff; - else if (!strcasecmp(str, kMinStr) || - !strcasecmp(str, kMinimumStr) || - !strcasecmp(str, kLowestStr) || - !strcasecmp(str, kBottomStr) || - !strcasecmp(str, kDownStr)) + else if (!STRCASECMP(str, kMinStr) || + !STRCASECMP(str, kMinimumStr) || + !STRCASECMP(str, kLowestStr) || + !STRCASECMP(str, kBottomStr) || + !STRCASECMP(str, kDownStr)) return stdAc::swingv_t::kLowest; - else if (!strcasecmp(str, kLowStr)) + else if (!STRCASECMP(str, kLowStr)) return stdAc::swingv_t::kLow; - else if (!strcasecmp(str, kMidStr) || - !strcasecmp(str, kMiddleStr) || - !strcasecmp(str, kMedStr) || - !strcasecmp(str, kMediumStr) || - !strcasecmp(str, kCentreStr)) + else if (!STRCASECMP(str, kMidStr) || + !STRCASECMP(str, kMiddleStr) || + !STRCASECMP(str, kMedStr) || + !STRCASECMP(str, kMediumStr) || + !STRCASECMP(str, kCentreStr)) return stdAc::swingv_t::kMiddle; - else if (!strcasecmp(str, kHighStr) || - !strcasecmp(str, kHiStr)) + else if (!STRCASECMP(str, kHighStr) || + !STRCASECMP(str, kHiStr)) return stdAc::swingv_t::kHigh; - else if (!strcasecmp(str, kHighestStr) || - !strcasecmp(str, kMaxStr) || - !strcasecmp(str, kMaximumStr) || - !strcasecmp(str, kTopStr) || - !strcasecmp(str, kUpStr)) + else if (!STRCASECMP(str, kHighestStr) || + !STRCASECMP(str, kMaxStr) || + !STRCASECMP(str, kMaximumStr) || + !STRCASECMP(str, kTopStr) || + !STRCASECMP(str, kUpStr)) return stdAc::swingv_t::kHighest; else return def; @@ -3150,34 +3281,34 @@ stdAc::swingv_t IRac::strToSwingV(const char *str, /// @return The equivalent enum. stdAc::swingh_t IRac::strToSwingH(const char *str, const stdAc::swingh_t def) { - if (!strcasecmp(str, kAutoStr) || - !strcasecmp(str, kAutomaticStr) || - !strcasecmp(str, kOnStr) || !strcasecmp(str, kSwingStr)) + if (!STRCASECMP(str, kAutoStr) || + !STRCASECMP(str, kAutomaticStr) || + !STRCASECMP(str, kOnStr) || !STRCASECMP(str, kSwingStr)) return stdAc::swingh_t::kAuto; - else if (!strcasecmp(str, kOffStr) || - !strcasecmp(str, kStopStr)) + else if (!STRCASECMP(str, kOffStr) || + !STRCASECMP(str, kStopStr)) return stdAc::swingh_t::kOff; - else if (!strcasecmp(str, kLeftMaxStr) || // "LeftMax" - !strcasecmp(str, D_STR_LEFT " " D_STR_MAX) || // "Left Max" - !strcasecmp(str, D_STR_MAX D_STR_LEFT) || // "MaxLeft" - !strcasecmp(str, kMaxLeftStr)) // "Max Left" + else if (!STRCASECMP(str, kLeftMaxNoSpaceStr) || // "LeftMax" + !STRCASECMP(str, kLeftMaxStr) || // "Left Max" + !STRCASECMP(str, kMaxLeftNoSpaceStr) || // "MaxLeft" + !STRCASECMP(str, kMaxLeftStr)) // "Max Left" return stdAc::swingh_t::kLeftMax; - else if (!strcasecmp(str, kLeftStr)) + else if (!STRCASECMP(str, kLeftStr)) return stdAc::swingh_t::kLeft; - else if (!strcasecmp(str, kMidStr) || - !strcasecmp(str, kMiddleStr) || - !strcasecmp(str, kMedStr) || - !strcasecmp(str, kMediumStr) || - !strcasecmp(str, kCentreStr)) + else if (!STRCASECMP(str, kMidStr) || + !STRCASECMP(str, kMiddleStr) || + !STRCASECMP(str, kMedStr) || + !STRCASECMP(str, kMediumStr) || + !STRCASECMP(str, kCentreStr)) return stdAc::swingh_t::kMiddle; - else if (!strcasecmp(str, kRightStr)) + else if (!STRCASECMP(str, kRightStr)) return stdAc::swingh_t::kRight; - else if (!strcasecmp(str, kRightMaxStr) || // "RightMax" - !strcasecmp(str, D_STR_RIGHT " " D_STR_MAX) || // "Right Max" - !strcasecmp(str, D_STR_MAX D_STR_RIGHT) || // "MaxRight" - !strcasecmp(str, kMaxRightStr)) // "Max Right" + else if (!STRCASECMP(str, kRightMaxNoSpaceStr) || // "RightMax" + !STRCASECMP(str, kRightMaxStr) || // "Right Max" + !STRCASECMP(str, kMaxRightNoSpaceStr) || // "MaxRight" + !STRCASECMP(str, kMaxRightStr)) // "Max Right" return stdAc::swingh_t::kRightMax; - else if (!strcasecmp(str, kWideStr)) + else if (!STRCASECMP(str, kWideStr)) return stdAc::swingh_t::kWide; else return def; @@ -3188,59 +3319,86 @@ stdAc::swingh_t IRac::strToSwingH(const char *str, /// @param[in] str A Ptr to a C-style string to be converted. /// @param[in] def The enum to return if no conversion was possible. /// @return The equivalent enum. +/// @note After adding a new model you should update modelToStr() too. int16_t IRac::strToModel(const char *str, const int16_t def) { // Gree - if (!strcasecmp(str, "YAW1F")) { + if (!STRCASECMP(str, kYaw1fStr)) { return gree_ac_remote_model_t::YAW1F; - } else if (!strcasecmp(str, "YBOFB")) { + } else if (!STRCASECMP(str, kYbofbStr)) { return gree_ac_remote_model_t::YBOFB; + // Haier models + } else if (!STRCASECMP(str, kV9014557AStr)) { + return haier_ac176_remote_model_t::V9014557_A; + } else if (!STRCASECMP(str, kV9014557BStr)) { + return haier_ac176_remote_model_t::V9014557_B; // HitachiAc1 models - } else if (!strcasecmp(str, "R-LT0541-HTA-A")) { + } else if (!STRCASECMP(str, kRlt0541htaaStr)) { return hitachi_ac1_remote_model_t::R_LT0541_HTA_A; - } else if (!strcasecmp(str, "R-LT0541-HTA-B")) { + } else if (!STRCASECMP(str, kRlt0541htabStr)) { return hitachi_ac1_remote_model_t::R_LT0541_HTA_B; // Fujitsu A/C models - } else if (!strcasecmp(str, "ARRAH2E")) { + } else if (!STRCASECMP(str, kArrah2eStr)) { return fujitsu_ac_remote_model_t::ARRAH2E; - } else if (!strcasecmp(str, "ARDB1")) { + } else if (!STRCASECMP(str, kArdb1Str)) { return fujitsu_ac_remote_model_t::ARDB1; - } else if (!strcasecmp(str, "ARREB1E")) { + } else if (!STRCASECMP(str, kArreb1eStr)) { return fujitsu_ac_remote_model_t::ARREB1E; - } else if (!strcasecmp(str, "ARJW2")) { + } else if (!STRCASECMP(str, kArjw2Str)) { return fujitsu_ac_remote_model_t::ARJW2; - } else if (!strcasecmp(str, "ARRY4")) { + } else if (!STRCASECMP(str, kArry4Str)) { return fujitsu_ac_remote_model_t::ARRY4; + } else if (!STRCASECMP(str, kArrew4eStr)) { + return fujitsu_ac_remote_model_t::ARREW4E; // LG A/C models - } else if (!strcasecmp(str, "GE6711AR2853M")) { + } else if (!STRCASECMP(str, kGe6711ar2853mStr)) { return lg_ac_remote_model_t::GE6711AR2853M; - } else if (!strcasecmp(str, "AKB75215403")) { + } else if (!STRCASECMP(str, kAkb75215403Str)) { return lg_ac_remote_model_t::AKB75215403; - } else if (!strcasecmp(str, "AKB74955603")) { + } else if (!STRCASECMP(str, kAkb74955603Str)) { return lg_ac_remote_model_t::AKB74955603; - } else if (!strcasecmp(str, "AKB73757604")) { + } else if (!STRCASECMP(str, kAkb73757604Str)) { return lg_ac_remote_model_t::AKB73757604; // Panasonic A/C families - } else if (!strcasecmp(str, "LKE") || !strcasecmp(str, "PANASONICLKE")) { + } else if (!STRCASECMP(str, kLkeStr) || + !STRCASECMP(str, kPanasonicLkeStr)) { return panasonic_ac_remote_model_t::kPanasonicLke; - } else if (!strcasecmp(str, "NKE") || !strcasecmp(str, "PANASONICNKE")) { + } else if (!STRCASECMP(str, kNkeStr) || + !STRCASECMP(str, kPanasonicNkeStr)) { return panasonic_ac_remote_model_t::kPanasonicNke; - } else if (!strcasecmp(str, "DKE") || !strcasecmp(str, "PANASONICDKE") || - !strcasecmp(str, "PKR") || !strcasecmp(str, "PANASONICPKR")) { + } else if (!STRCASECMP(str, kDkeStr) || + !STRCASECMP(str, kPanasonicDkeStr) || + !STRCASECMP(str, kPkrStr) || + !STRCASECMP(str, kPanasonicPkrStr)) { return panasonic_ac_remote_model_t::kPanasonicDke; - } else if (!strcasecmp(str, "JKE") || !strcasecmp(str, "PANASONICJKE")) { + } else if (!STRCASECMP(str, kJkeStr) || + !STRCASECMP(str, kPanasonicJkeStr)) { return panasonic_ac_remote_model_t::kPanasonicJke; - } else if (!strcasecmp(str, "CKP") || !strcasecmp(str, "PANASONICCKP")) { + } else if (!STRCASECMP(str, kCkpStr) || + !STRCASECMP(str, kPanasonicCkpStr)) { return panasonic_ac_remote_model_t::kPanasonicCkp; - } else if (!strcasecmp(str, "RKR") || !strcasecmp(str, "PANASONICRKR")) { + } else if (!STRCASECMP(str, kRkrStr) || + !STRCASECMP(str, kPanasonicRkrStr)) { return panasonic_ac_remote_model_t::kPanasonicRkr; + // Sharp A/C Models + } else if (!STRCASECMP(str, kA907Str)) { + return sharp_ac_remote_model_t::A907; + } else if (!STRCASECMP(str, kA705Str)) { + return sharp_ac_remote_model_t::A705; + } else if (!STRCASECMP(str, kA903Str)) { + return sharp_ac_remote_model_t::A903; + // TCL A/C Models + } else if (!STRCASECMP(str, kTac09chsdStr)) { + return tcl_ac_remote_model_t::TAC09CHSD; + } else if (!STRCASECMP(str, kGz055be1Str)) { + return tcl_ac_remote_model_t::GZ055BE1; // Voltas A/C models - } else if (!strcasecmp(str, "122LZF")) { + } else if (!STRCASECMP(str, k122lzfStr)) { return voltas_ac_remote_model_t::kVoltas122LZF; // Whirlpool A/C models - } else if (!strcasecmp(str, "DG11J13A") || !strcasecmp(str, "DG11J104") || - !strcasecmp(str, "DG11J1-04")) { + } else if (!STRCASECMP(str, kDg11j13aStr) || + !STRCASECMP(str, kDg11j104Str)) { return whirlpool_ac_remote_model_t::DG11J13A; - } else if (!strcasecmp(str, "DG11J191")) { + } else if (!STRCASECMP(str, kDg11j191Str)) { return whirlpool_ac_remote_model_t::DG11J191; } else { int16_t number = atoi(str); @@ -3256,15 +3414,15 @@ int16_t IRac::strToModel(const char *str, const int16_t def) { /// @param[in] def The boolean value to return if no conversion was possible. /// @return The equivalent boolean value. bool IRac::strToBool(const char *str, const bool def) { - if (!strcasecmp(str, kOnStr) || - !strcasecmp(str, "1") || - !strcasecmp(str, kYesStr) || - !strcasecmp(str, kTrueStr)) + if (!STRCASECMP(str, kOnStr) || + !STRCASECMP(str, k1Str) || + !STRCASECMP(str, kYesStr) || + !STRCASECMP(str, kTrueStr)) return true; - else if (!strcasecmp(str, kOffStr) || - !strcasecmp(str, "0") || - !strcasecmp(str, kNoStr) || - !strcasecmp(str, kFalseStr)) + else if (!STRCASECMP(str, kOffStr) || + !STRCASECMP(str, k0Str) || + !STRCASECMP(str, kNoStr) || + !STRCASECMP(str, kFalseStr)) return false; else return def; @@ -3279,23 +3437,17 @@ String IRac::boolToString(const bool value) { /// Convert the supplied operation mode into the appropriate String. /// @param[in] mode The enum to be converted. +/// @param[in] ha A flag to indicate we want GoogleHome/HomeAssistant output. /// @return The equivalent String for the locale. -String IRac::opmodeToString(const stdAc::opmode_t mode) { +String IRac::opmodeToString(const stdAc::opmode_t mode, const bool ha) { switch (mode) { - case stdAc::opmode_t::kOff: - return kOffStr; - case stdAc::opmode_t::kAuto: - return kAutoStr; - case stdAc::opmode_t::kCool: - return kCoolStr; - case stdAc::opmode_t::kHeat: - return kHeatStr; - case stdAc::opmode_t::kDry: - return kDryStr; - case stdAc::opmode_t::kFan: - return kFanOnlyStr; - default: - return kUnknownStr; + case stdAc::opmode_t::kOff: return kOffStr; + case stdAc::opmode_t::kAuto: return kAutoStr; + case stdAc::opmode_t::kCool: return kCoolStr; + case stdAc::opmode_t::kHeat: return kHeatStr; + case stdAc::opmode_t::kDry: return kDryStr; + case stdAc::opmode_t::kFan: return ha ? kFan_OnlyStr : kFanStr; + default: return kUnknownStr; } } @@ -3304,20 +3456,13 @@ String IRac::opmodeToString(const stdAc::opmode_t mode) { /// @return The equivalent String for the locale. String IRac::fanspeedToString(const stdAc::fanspeed_t speed) { switch (speed) { - case stdAc::fanspeed_t::kAuto: - return kAutoStr; - case stdAc::fanspeed_t::kMax: - return kMaxStr; - case stdAc::fanspeed_t::kHigh: - return kHighStr; - case stdAc::fanspeed_t::kMedium: - return kMediumStr; - case stdAc::fanspeed_t::kLow: - return kLowStr; - case stdAc::fanspeed_t::kMin: - return kMinStr; - default: - return kUnknownStr; + case stdAc::fanspeed_t::kAuto: return kAutoStr; + case stdAc::fanspeed_t::kMax: return kMaxStr; + case stdAc::fanspeed_t::kHigh: return kHighStr; + case stdAc::fanspeed_t::kMedium: return kMediumStr; + case stdAc::fanspeed_t::kLow: return kLowStr; + case stdAc::fanspeed_t::kMin: return kMinStr; + default: return kUnknownStr; } } @@ -3326,22 +3471,14 @@ String IRac::fanspeedToString(const stdAc::fanspeed_t speed) { /// @return The equivalent String for the locale. String IRac::swingvToString(const stdAc::swingv_t swingv) { switch (swingv) { - case stdAc::swingv_t::kOff: - return kOffStr; - case stdAc::swingv_t::kAuto: - return kAutoStr; - case stdAc::swingv_t::kHighest: - return kHighestStr; - case stdAc::swingv_t::kHigh: - return kHighStr; - case stdAc::swingv_t::kMiddle: - return kMiddleStr; - case stdAc::swingv_t::kLow: - return kLowStr; - case stdAc::swingv_t::kLowest: - return kLowestStr; - default: - return kUnknownStr; + case stdAc::swingv_t::kOff: return kOffStr; + case stdAc::swingv_t::kAuto: return kAutoStr; + case stdAc::swingv_t::kHighest: return kHighestStr; + case stdAc::swingv_t::kHigh: return kHighStr; + case stdAc::swingv_t::kMiddle: return kMiddleStr; + case stdAc::swingv_t::kLow: return kLowStr; + case stdAc::swingv_t::kLowest: return kLowestStr; + default: return kUnknownStr; } } @@ -3350,24 +3487,15 @@ String IRac::swingvToString(const stdAc::swingv_t swingv) { /// @return The equivalent String for the locale. String IRac::swinghToString(const stdAc::swingh_t swingh) { switch (swingh) { - case stdAc::swingh_t::kOff: - return kOffStr; - case stdAc::swingh_t::kAuto: - return kAutoStr; - case stdAc::swingh_t::kLeftMax: - return kLeftMaxStr; - case stdAc::swingh_t::kLeft: - return kLeftStr; - case stdAc::swingh_t::kMiddle: - return kMiddleStr; - case stdAc::swingh_t::kRight: - return kRightStr; - case stdAc::swingh_t::kRightMax: - return kRightMaxStr; - case stdAc::swingh_t::kWide: - return kWideStr; - default: - return kUnknownStr; + case stdAc::swingh_t::kOff: return kOffStr; + case stdAc::swingh_t::kAuto: return kAutoStr; + case stdAc::swingh_t::kLeftMax: return kLeftMaxStr; + case stdAc::swingh_t::kLeft: return kLeftStr; + case stdAc::swingh_t::kMiddle: return kMiddleStr; + case stdAc::swingh_t::kRight: return kRightStr; + case stdAc::swingh_t::kRightMax: return kRightMaxStr; + case stdAc::swingh_t::kWide: return kWideStr; + default: return kUnknownStr; } } @@ -3407,6 +3535,21 @@ namespace IRAcUtils { return ac.toString(); } #endif // DECODE_CARRIER_AC64 +#if DECODE_COOLIX + case decode_type_t::COOLIX: { + IRCoolixAC ac(kGpioUnused); + ac.on(); + ac.setRaw(result->value); // Coolix uses value instead of state. + return ac.toString(); + } +#endif // DECODE_COOLIX +#if DECODE_CORONA_AC + case decode_type_t::CORONA_AC: { + IRCoronaAc ac(kGpioUnused); + ac.setRaw(result->state, result->bits / 8); + return ac.toString(); + } +#endif // DECODE_CORONA_AC #if DECODE_DAIKIN case decode_type_t::DAIKIN: { IRDaikinESP ac(kGpioUnused); @@ -3494,6 +3637,69 @@ namespace IRAcUtils { return ac.toString(); } #endif // DECODE_FUJITSU_AC +#if DECODE_GOODWEATHER + case decode_type_t::GOODWEATHER: { + IRGoodweatherAc ac(kGpioUnused); + ac.setRaw(result->value); // Goodweather uses value instead of state. + return ac.toString(); + } +#endif // DECODE_GOODWEATHER +#if DECODE_GREE + case decode_type_t::GREE: { + IRGreeAC ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_GREE +#if DECODE_HAIER_AC + case decode_type_t::HAIER_AC: { + IRHaierAC ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HAIER_AC +#if DECODE_HAIER_AC176 + case decode_type_t::HAIER_AC176: { + IRHaierAC176 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HAIER_AC176 +#if DECODE_HAIER_AC_YRW02 + case decode_type_t::HAIER_AC_YRW02: { + IRHaierACYRW02 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HAIER_AC_YRW02 +#if DECODE_HITACHI_AC + case decode_type_t::HITACHI_AC: { + IRHitachiAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HITACHI_AC +#if DECODE_HITACHI_AC1 + case decode_type_t::HITACHI_AC1: { + IRHitachiAc1 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HITACHI_AC1 +#if DECODE_HITACHI_AC344 + case decode_type_t::HITACHI_AC344: { + IRHitachiAc344 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HITACHI_AC344 +#if DECODE_HITACHI_AC424 + case decode_type_t::HITACHI_AC424: { + IRHitachiAc424 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HITACHI_AC424 #if DECODE_KELON case decode_type_t::KELON: { IRKelonAc ac(kGpioUnused); @@ -3508,6 +3714,28 @@ namespace IRAcUtils { return ac.toString(); } #endif // DECODE_KELVINATOR +#if DECODE_LG + case decode_type_t::LG: + case decode_type_t::LG2: { + IRLgAc ac(kGpioUnused); + ac.setRaw(result->value, result->decode_type); // Use value, not state. + return ac.isValidLgAc() ? ac.toString() : ""; + } +#endif // DECODE_LG +#if DECODE_MIDEA + case decode_type_t::MIDEA: { + IRMideaAC ac(kGpioUnused); + ac.setRaw(result->value); // Midea uses value instead of state. + return ac.toString(); + } +#endif // DECODE_MIDEA +#if DECODE_MIRAGE + case decode_type_t::MIRAGE: { + IRMirageAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_MIRAGE #if DECODE_MITSUBISHI_AC case decode_type_t::MITSUBISHI_AC: { IRMitsubishiAC ac(kGpioUnused); @@ -3548,76 +3776,33 @@ namespace IRAcUtils { return ac.toString(); } #endif // DECODE_NEOCLIMA -#if DECODE_TOSHIBA_AC - case decode_type_t::TOSHIBA_AC: { - IRToshibaAC ac(kGpioUnused); - ac.setRaw(result->state, result->bits / 8); - return ac.toString(); +#if DECODE_PANASONIC_AC + case decode_type_t::PANASONIC_AC: { + if (result->bits > kPanasonicAcShortBits) { + IRPanasonicAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } + return ""; } -#endif // DECODE_TOSHIBA_AC -#if DECODE_TROTEC - case decode_type_t::TROTEC: { - IRTrotecESP ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); +#endif // DECODE_PANASONIC_AC +#if DECODE_PANASONIC_AC32 + case decode_type_t::PANASONIC_AC32: { + if (result->bits >= kPanasonicAc32Bits) { + IRPanasonicAc32 ac(kGpioUnused); + ac.setRaw(result->value); // Uses value instead of state. + return ac.toString(); + } + return ""; } -#endif // DECODE_TROTEC -#if DECODE_TROTEC_3550 - case decode_type_t::TROTEC_3550: { - IRTrotec3550 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_TROTEC_3550 -#if DECODE_TRUMA - case decode_type_t::TRUMA: { - IRTrumaAc ac(kGpioUnused); - ac.setRaw(result->value); // Truma uses value instead of state. - return ac.toString(); - } -#endif // DECODE_TRUMA -#if DECODE_GOODWEATHER - case decode_type_t::GOODWEATHER: { - IRGoodweatherAc ac(kGpioUnused); - ac.setRaw(result->value); // Goodweather uses value instead of state. - return ac.toString(); - } -#endif // DECODE_GOODWEATHER -#if DECODE_GREE - case decode_type_t::GREE: { - IRGreeAC ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_GREE -#if DECODE_MIDEA - case decode_type_t::MIDEA: { - IRMideaAC ac(kGpioUnused); - ac.setRaw(result->value); // Midea uses value instead of state. - return ac.toString(); - } -#endif // DECODE_MIDEA -#if DECODE_HAIER_AC - case decode_type_t::HAIER_AC: { - IRHaierAC ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_HAIER_AC -#if DECODE_HAIER_AC176 - case decode_type_t::HAIER_AC176: { - IRHaierAC176 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_HAIER_AC176 -#if DECODE_HAIER_AC_YRW02 - case decode_type_t::HAIER_AC_YRW02: { - IRHaierACYRW02 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_HAIER_AC_YRW02 +#endif // DECODE_PANASONIC_AC +#if DECODE_RHOSS + case decode_type_t::RHOSS: { + IRRhossAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_RHOSS #if DECODE_SAMSUNG_AC case decode_type_t::SAMSUNG_AC: { IRSamsungAc ac(kGpioUnused); @@ -3646,83 +3831,14 @@ namespace IRAcUtils { return ac.toString(); } #endif // DECODE_SHARP_AC -#if DECODE_COOLIX - case decode_type_t::COOLIX: { - IRCoolixAC ac(kGpioUnused); - ac.on(); - ac.setRaw(result->value); // Coolix uses value instead of state. - return ac.toString(); - } -#endif // DECODE_COOLIX -#if DECODE_CORONA_AC - case decode_type_t::CORONA_AC: { - IRCoronaAc ac(kGpioUnused); - ac.setRaw(result->state, result->bits / 8); - return ac.toString(); - } -#endif // DECODE_CORONA_AC -#if DECODE_PANASONIC_AC - case decode_type_t::PANASONIC_AC: { - if (result->bits > kPanasonicAcShortBits) { - IRPanasonicAc ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } - return ""; - } -#endif // DECODE_PANASONIC_AC -#if DECODE_PANASONIC_AC32 - case decode_type_t::PANASONIC_AC32: { - if (result->bits >= kPanasonicAc32Bits) { - IRPanasonicAc32 ac(kGpioUnused); - ac.setRaw(result->value); // Uses value instead of state. - return ac.toString(); - } - return ""; - } -#endif // DECODE_PANASONIC_AC -#if DECODE_HITACHI_AC - case decode_type_t::HITACHI_AC: { - IRHitachiAc ac(kGpioUnused); +#if (DECODE_TCL112AC || DECODE_TEKNOPOINT) + case decode_type_t::TCL112AC: + case decode_type_t::TEKNOPOINT: { + IRTcl112Ac ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } -#endif // DECODE_HITACHI_AC -#if DECODE_HITACHI_AC1 - case decode_type_t::HITACHI_AC1: { - IRHitachiAc1 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_HITACHI_AC1 -#if DECODE_HITACHI_AC344 - case decode_type_t::HITACHI_AC344: { - IRHitachiAc344 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_HITACHI_AC344 -#if DECODE_HITACHI_AC424 - case decode_type_t::HITACHI_AC424: { - IRHitachiAc424 ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_HITACHI_AC424 -#if DECODE_WHIRLPOOL_AC - case decode_type_t::WHIRLPOOL_AC: { - IRWhirlpoolAc ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_WHIRLPOOL_AC -#if DECODE_VESTEL_AC - case decode_type_t::VESTEL_AC: { - IRVestelAc ac(kGpioUnused); - ac.setRaw(result->value); // Like Coolix, use value instead of state. - return ac.toString(); - } -#endif // DECODE_VESTEL_AC +#endif // (DECODE_TCL112AC || DECODE_TEKNOPOINT) #if DECODE_TECHNIBEL_AC case decode_type_t::TECHNIBEL_AC: { IRTechnibelAc ac(kGpioUnused); @@ -3730,13 +3846,6 @@ namespace IRAcUtils { return ac.toString(); } #endif // DECODE_TECHNIBEL_AC -#if DECODE_VOLTAS - case decode_type_t::VOLTAS: { - IRVoltas ac(kGpioUnused); - ac.setRaw(result->state); - return ac.toString(); - } -#endif // DECODE_VOLTAS #if DECODE_TECO case decode_type_t::TECO: { IRTecoAc ac(kGpioUnused); @@ -3744,21 +3853,13 @@ namespace IRAcUtils { return ac.toString(); } #endif // DECODE_TECO -#if DECODE_TCL112AC - case decode_type_t::TCL112AC: { - IRTcl112Ac ac(kGpioUnused); - ac.setRaw(result->state); +#if DECODE_TOSHIBA_AC + case decode_type_t::TOSHIBA_AC: { + IRToshibaAC ac(kGpioUnused); + ac.setRaw(result->state, result->bits / 8); return ac.toString(); } -#endif // DECODE_TCL112AC -#if DECODE_LG - case decode_type_t::LG: - case decode_type_t::LG2: { - IRLgAc ac(kGpioUnused); - ac.setRaw(result->value, result->decode_type); // Use value, not state. - return ac.isValidLgAc() ? ac.toString() : ""; - } -#endif // DECODE_LG +#endif // DECODE_TOSHIBA_AC #if DECODE_TRANSCOLD case decode_type_t::TRANSCOLD: { IRTranscoldAc ac(kGpioUnused); @@ -3767,6 +3868,48 @@ namespace IRAcUtils { return ac.toString(); } #endif // DECODE_TRANSCOLD +#if DECODE_TROTEC + case decode_type_t::TROTEC: { + IRTrotecESP ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_TROTEC +#if DECODE_TROTEC_3550 + case decode_type_t::TROTEC_3550: { + IRTrotec3550 ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_TROTEC_3550 +#if DECODE_TRUMA + case decode_type_t::TRUMA: { + IRTrumaAc ac(kGpioUnused); + ac.setRaw(result->value); // Truma uses value instead of state. + return ac.toString(); + } +#endif // DECODE_TRUMA +#if DECODE_VESTEL_AC + case decode_type_t::VESTEL_AC: { + IRVestelAc ac(kGpioUnused); + ac.setRaw(result->value); // Like Coolix, use value instead of state. + return ac.toString(); + } +#endif // DECODE_VESTEL_AC +#if DECODE_VOLTAS + case decode_type_t::VOLTAS: { + IRVoltas ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_VOLTAS +#if DECODE_WHIRLPOOL_AC + case decode_type_t::WHIRLPOOL_AC: { + IRWhirlpoolAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_WHIRLPOOL_AC default: return ""; } @@ -3812,6 +3955,14 @@ namespace IRAcUtils { break; } #endif // DECODE_ARGO +#if DECODE_CARRIER_AC64 + case decode_type_t::CARRIER_AC64: { + IRCarrierAc64 ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(); + break; + } +#endif // DECODE_CARRIER_AC64 #if DECODE_COOLIX case decode_type_t::COOLIX: { IRCoolixAC ac(kGpioUnused); @@ -3828,14 +3979,6 @@ namespace IRAcUtils { break; } #endif // DECODE_CARRIER_AC64 -#if DECODE_CARRIER_AC64 - case decode_type_t::CARRIER_AC64: { - IRCarrierAc64 ac(kGpioUnused); - ac.setRaw(decode->value); // Uses value instead of state. - *result = ac.toCommon(); - break; - } -#endif // DECODE_CARRIER_AC64 #if DECODE_DAIKIN case decode_type_t::DAIKIN: { IRDaikinESP ac(kGpioUnused); @@ -4042,6 +4185,14 @@ namespace IRAcUtils { break; } #endif // DECODE_MIDEA +#if DECODE_MIRAGE + case decode_type_t::MIRAGE: { + IRMirageAc ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } +#endif // DECODE_MIRAGE #if DECODE_MITSUBISHI_AC case decode_type_t::MITSUBISHI_AC: { IRMitsubishiAC ac(kGpioUnused); @@ -4108,6 +4259,14 @@ namespace IRAcUtils { break; } #endif // DECODE_PANASONIC_AC32 +#if DECODE_RHOSS + case decode_type_t::RHOSS: { + IRRhossAc ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } +#endif // DECODE_RHOSS #if DECODE_SAMSUNG_AC case decode_type_t::SAMSUNG_AC: { IRSamsungAc ac(kGpioUnused); @@ -4136,18 +4295,22 @@ namespace IRAcUtils { case decode_type_t::SHARP_AC: { IRSharpAc ac(kGpioUnused); ac.setRaw(decode->state); - *result = ac.toCommon(); - break; - } -#endif // DECODE_SHARP_AC -#if DECODE_TCL112AC - case decode_type_t::TCL112AC: { - IRTcl112Ac ac(kGpioUnused); - ac.setRaw(decode->state); *result = ac.toCommon(prev); break; } -#endif // DECODE_TCL112AC +#endif // DECODE_SHARP_AC +#if (DECODE_TCL112AC || DECODE_TEKNOPOINT) + case decode_type_t::TCL112AC: + case decode_type_t::TEKNOPOINT: { + IRTcl112Ac ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(prev); + // Teknopoint uses the TCL protocol, but with a different model number. + // Just keep the original protocol type ... for now. + result->protocol = decode->decode_type; + break; + } +#endif // (DECODE_TCL112AC || DECODE_TEKNOPOINT) #if DECODE_TECHNIBEL_AC case decode_type_t::TECHNIBEL_AC: { IRTechnibelAc ac(kGpioUnused); @@ -4172,6 +4335,14 @@ namespace IRAcUtils { break; } #endif // DECODE_TOSHIBA_AC +#if DECODE_TRANSCOLD + case decode_type_t::TRANSCOLD: { + IRTranscoldAc ac(kGpioUnused); + ac.setRaw(decode->value); // TRANSCOLD Uses value instead of state. + *result = ac.toCommon(prev); + break; + } +#endif // DECODE_TRANSCOLD #if DECODE_TROTEC case decode_type_t::TROTEC: { IRTrotecESP ac(kGpioUnused); @@ -4220,14 +4391,6 @@ namespace IRAcUtils { break; } #endif // DECODE_WHIRLPOOL_AC -#if DECODE_TRANSCOLD - case decode_type_t::TRANSCOLD: { - IRTranscoldAc ac(kGpioUnused); - ac.setRaw(decode->value); // TRANSCOLD Uses value instead of state. - *result = ac.toCommon(prev); - break; - } -#endif // DECODE_TRANSCOLD default: return false; } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.h index 573e7ae7e..afa4bcee0 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRac.h @@ -26,10 +26,12 @@ #include "ir_Kelvinator.h" #include "ir_LG.h" #include "ir_Midea.h" +#include "ir_Mirage.h" #include "ir_Mitsubishi.h" #include "ir_MitsubishiHeavy.h" #include "ir_Neoclima.h" #include "ir_Panasonic.h" +#include "ir_Rhoss.h" #include "ir_Samsung.h" #include "ir_Sanyo.h" #include "ir_Sharp.h" @@ -90,7 +92,8 @@ class IRac { static stdAc::swingh_t strToSwingH( const char *str, const stdAc::swingh_t def = stdAc::swingh_t::kOff); static String boolToString(const bool value); - static String opmodeToString(const stdAc::opmode_t mode); + static String opmodeToString(const stdAc::opmode_t mode, + const bool ha = false); static String fanspeedToString(const stdAc::fanspeed_t speed); static String swingvToString(const stdAc::swingv_t swingv); static String swinghToString(const stdAc::swingh_t swingh); @@ -245,7 +248,8 @@ void electra(IRElectraAc *ac, void gree(IRGreeAC *ac, const gree_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, - const stdAc::swingv_t swingv, const bool turbo, const bool light, + const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, + const bool turbo, const bool econo, const bool light, const bool clean, const int16_t sleep = -1); #endif // SEND_GREE #if SEND_HAIER_AC @@ -257,18 +261,20 @@ void electra(IRElectraAc *ac, #endif // SEND_HAIER_AC #if SEND_HAIER_AC176 void haier176(IRHaierAC176 *ac, - const bool on, const stdAc::opmode_t mode, + const haier_ac176_remote_model_t model, const bool on, + const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, - const stdAc::swingv_t swingv, - const bool turbo, const bool filter, + const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, + const bool turbo, const bool quiet, const bool filter, const int16_t sleep = -1); #endif // SEND_HAIER_AC176 #if SEND_HAIER_AC_YRW02 void haierYrwo2(IRHaierACYRW02 *ac, const bool on, const stdAc::opmode_t mode, - const float degrees, const stdAc::fanspeed_t fan, - const stdAc::swingv_t swingv, - const bool turbo, const bool filter, + const bool celsius, const float degrees, + const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, + const stdAc::swingh_t swingh, const bool turbo, + const bool quiet, const bool filter, const int16_t sleep = -1); #endif // SEND_HAIER_AC_YRW02 #if SEND_HITACHI_AC @@ -326,6 +332,9 @@ void electra(IRElectraAc *ac, const stdAc::swingv_t swingv, const bool turbo, const bool econo, const bool light, const int16_t sleep = -1); #endif // SEND_MIDEA +#if SEND_MIRAGE + void mirage(IRMirageAc *ac, const stdAc::state_t state); +#endif // SEND_MIRAGE #if SEND_MITSUBISHI_AC void mitsubishi(IRMitsubishiAC *ac, const bool on, const stdAc::opmode_t mode, @@ -386,14 +395,21 @@ void electra(IRElectraAc *ac, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh); #endif // SEND_PANASONIC_AC32 +#if SEND_RHOSS + void rhoss(IRRhossAc *ac, + const bool on, const stdAc::opmode_t mode, const float degrees, + const stdAc::fanspeed_t fan, const stdAc::swingv_t swing); +#endif // SEND_RHOSS #if SEND_SAMSUNG_AC void samsung(IRSamsungAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, - const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, - const bool quiet, const bool turbo, const bool light, - const bool filter, const bool clean, - const bool beep, const bool prevpower = true, - const bool forcepower = true); + const stdAc::fanspeed_t fan, + const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, + const bool quiet, const bool turbo, const bool econo, + const bool light, const bool filter, const bool clean, + const bool beep, const int16_t sleep = -1, + const bool prevpower = true, const int16_t prevsleep = -1, + const bool forceextended = true); #endif // SEND_SAMSUNG_AC #if SEND_SANYO_AC void sanyo(IRSanyoAc *ac, @@ -413,11 +429,12 @@ void electra(IRElectraAc *ac, void sharp(IRSharpAc *ac, const sharp_ac_remote_model_t model, const bool on, const bool prev_power, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, - const stdAc::swingv_t swingv, const bool turbo, const bool light, + const stdAc::swingv_t swingv, const stdAc::swingv_t swingv_prev, + const bool turbo, const bool light, const bool filter, const bool clean); #endif // SEND_SHARP_AC #if SEND_TCL112AC - void tcl112(IRTcl112Ac *ac, + void tcl112(IRTcl112Ac *ac, const tcl_ac_remote_model_t model, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp index 9c7519cbd..4970dcf0b 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp @@ -830,8 +830,7 @@ bool IRrecv::decode(decode_results *results, irparams_t *save, DPRINTLN("Attempting Samsung AC (extended) decode"); // Check the extended size first, as it should fail fast due to longer // length. - if (decodeSamsungAC(results, offset, kSamsungAcExtendedBits, false)) - return true; + if (decodeSamsungAC(results, offset, kSamsungAcExtendedBits)) return true; // Now check for the more common length. DPRINTLN("Attempting Samsung AC decode"); if (decodeSamsungAC(results, offset, kSamsungAcBits)) return true; @@ -1036,6 +1035,18 @@ bool IRrecv::decode(decode_results *results, irparams_t *save, DPRINTLN("Attempting Bose decode"); if (decodeBose(results, offset)) return true; #endif // DECODE_BOSE +#if DECODE_ARRIS + DPRINTLN("Attempting Arris decode"); + if (decodeArris(results, offset)) return true; +#endif // DECODE_ARRIS +#if DECODE_RHOSS + DPRINTLN("Attempting Rhoss decode"); + if (decodeRhoss(results, offset)) return true; +#endif // DECODE_RHOSS +#if DECODE_AIRTON + DPRINTLN("Attempting Airton decode"); + if (decodeAirton(results, offset)) return true; +#endif // DECODE_AIRTON // Typically new protocols are added above this line. } #if DECODE_HASH @@ -1811,6 +1822,7 @@ uint16_t IRrecv::matchManchesterData(volatile const uint16_t *data_ptr, const int16_t excess, const bool MSBfirst, const bool GEThomas) { + DPRINTLN("DEBUG: Entered matchManchesterData"); uint16_t offset = 0; uint64_t data = 0; uint16_t nr_half_periods = 0; @@ -1824,7 +1836,10 @@ uint16_t IRrecv::matchManchesterData(volatile const uint16_t *data_ptr, uint16_t min_remaining = nbits; // Check if there is enough capture buffer to possibly have the message. - if (remaining < min_remaining) return 0; // Nope, so abort. + if (remaining < min_remaining) { + DPRINTLN("DEBUG: Ran out of capture buffer!"); + return 0; // Nope, so abort. + } // Convert to ticks. Optimisation: Saves on math/extra instructions later. uint16_t bank = starting_balance / kRawTick; @@ -1847,22 +1862,39 @@ uint16_t IRrecv::matchManchesterData(volatile const uint16_t *data_ptr, while ((offset < remaining || bank) && nr_half_periods < expected_half_periods) { // Get the next entry if we haven't anything existing to process. + DPRINT("DEBUG: Offset = "); + DPRINTLN(offset); if (!bank) bank = *(data_ptr + offset++); + DPRINT("DEBUG: Bank = "); + DPRINTLN(bank * kRawTick); // Check if we don't have a short interval. - if (!match(bank, half_period, tolerance, excess)) return 0; // Not valid. + DPRINTLN("DEBUG: Checking for short interval"); + if (!match(bank, half_period, tolerance, excess)) { + DPRINTLN("DEBUG: It is. Exiting"); + return 0; // Not valid. + } // We've succeeded in matching half a period, so count it. nr_half_periods++; + DPRINT("DEBUG: Half Periods = "); + DPRINTLN(nr_half_periods); // We've now used up our bank, so refill it with the next item, unless we // are at the end of the capture buffer. // If we are assume a single half period of "space". - if (offset < remaining) + if (offset < remaining) { + DPRINT("DEBUG: Offset = "); + DPRINTLN(offset); bank = *(data_ptr + offset++); - else if (offset == remaining) + } else if (offset == remaining) { bank = raw_half_period; - else + } else { return 0; // We are out of buffer, so abort! + } + DPRINT("DEBUG: Bank = "); + DPRINTLN(bank * kRawTick); // Shift the data along and add our new bit. + DPRINT("DEBUG: Adding bit: "); + DPRINTLN((currentBit ? "1" : "0")); data <<= 1; data |= currentBit; @@ -1870,10 +1902,12 @@ uint16_t IRrecv::matchManchesterData(volatile const uint16_t *data_ptr, if (match(bank, half_period * 2, tolerance, excess)) { // It is, so flip the bit we need to append, and remove a half_period of // time from the bank. + DPRINTLN("DEBUG: long interval detected"); currentBit = !currentBit; bank -= raw_half_period; } else if (match(bank, half_period, tolerance, excess)) { // It is a short interval, so eat up all the time and move on. + DPRINTLN("DEBUG: short interval detected"); bank = 0; } else if (nr_half_periods == expected_half_periods - 1 && matchAtLeast(bank, half_period, tolerance, excess)) { diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.h index 1a883d509..f4932b5a6 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.h @@ -18,7 +18,7 @@ const uint16_t kHeader = 2; // Usual nr. of header entries. const uint16_t kFooter = 2; // Usual nr. of footer (stop bits) entries. const uint16_t kStartOffset = 1; // Usual rawbuf entry to start from. -#define MS_TO_USEC(x) (x * 1000U) // Convert milli-Seconds to micro-Seconds. +#define MS_TO_USEC(x) ((x) * 1000U) // Convert milli-Seconds to micro-Seconds. // Marks tend to be 100us too long, and spaces 100us too short // when received due to sensor lag. const uint16_t kMarkExcess = 50; @@ -287,6 +287,10 @@ class IRrecv { bool decodeArgo(decode_results *results, uint16_t offset = kStartOffset, const uint16_t nbits = kArgoBits, const bool strict = true); #endif // DECODE_ARGO +#if DECODE_ARRIS + bool decodeArris(decode_results *results, uint16_t offset = kStartOffset, + const uint16_t nbits = kArrisBits, const bool strict = true); +#endif // DECODE_ARRIS #if DECODE_SONY bool decodeSony(decode_results *results, uint16_t offset = kStartOffset, const uint16_t nbits = kSonyMinBits, @@ -766,6 +770,15 @@ class IRrecv { bool decodeBose(decode_results *results, uint16_t offset = kStartOffset, const uint16_t nbits = kBoseBits, const bool strict = true); #endif // DECODE_BOSE +#if DECODE_RHOSS + bool decodeRhoss(decode_results *results, uint16_t offset = kStartOffset, + const uint16_t nbits = kRhossBits, const bool strict = true); +#endif // DECODE_RHOSS +#if DECODE_AIRTON + bool decodeAirton(decode_results *results, uint16_t offset = kStartOffset, + const uint16_t nbits = kAirtonBits, + const bool strict = true); +#endif // DECODE_AIRTON }; #endif // IRRECV_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRremoteESP8266.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRremoteESP8266.h index 35b45d958..09a3011ce 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRremoteESP8266.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRremoteESP8266.h @@ -53,7 +53,7 @@ #endif // UNIT_TEST // Library Version -#define _IRREMOTEESP8266_VERSION_ "2.7.20" +#define _IRREMOTEESP8266_VERSION_ "2.8.0" // Set the language & locale for the library. See the `locale` dir for options. #ifndef _IR_LOCALE_ @@ -790,6 +790,27 @@ #define SEND_BOSE _IR_ENABLE_DEFAULT_ #endif // SEND_BOSE +#ifndef DECODE_ARRIS +#define DECODE_ARRIS _IR_ENABLE_DEFAULT_ +#endif // DECODE_ARRIS +#ifndef SEND_ARRIS +#define SEND_ARRIS _IR_ENABLE_DEFAULT_ +#endif // SEND_ARRIS + +#ifndef DECODE_RHOSS +#define DECODE_RHOSS _IR_ENABLE_DEFAULT_ +#endif // DECODE_RHOSS +#ifndef SEND_RHOSS +#define SEND_RHOSS _IR_ENABLE_DEFAULT_ +#endif // SEND_RHOSS + +#ifndef DECODE_AIRTON +#define DECODE_AIRTON _IR_ENABLE_DEFAULT_ +#endif // DECODE_AIRTON +#ifndef SEND_AIRTON +#define SEND_AIRTON _IR_ENABLE_DEFAULT_ +#endif // SEND_AIRTON + #if (DECODE_ARGO || DECODE_DAIKIN || DECODE_FUJITSU_AC || DECODE_GREE || \ DECODE_KELVINATOR || DECODE_MITSUBISHI_AC || DECODE_TOSHIBA_AC || \ DECODE_TROTEC || DECODE_HAIER_AC || DECODE_HITACHI_AC || \ @@ -804,7 +825,7 @@ DECODE_HITACHI_AC344 || DECODE_CORONA_AC || DECODE_SANYO_AC || \ DECODE_VOLTAS || DECODE_MIRAGE || DECODE_HAIER_AC176 || \ DECODE_TEKNOPOINT || DECODE_KELON || DECODE_TROTEC_3550 || \ - DECODE_SANYO_AC88 || \ + DECODE_SANYO_AC88 || DECODE_RHOSS || \ false) // Add any DECODE to the above if it uses result->state (see kStateSizeMax) // you might also want to add the protocol to hasACState function @@ -951,14 +972,19 @@ enum decode_type_t { TROTEC_3550, SANYO_AC88, // 105 BOSE, + ARRIS, + RHOSS, + AIRTON, // Add new entries before this one, and update it to point to the last entry. - kLastDecodeType = BOSE, + kLastDecodeType = AIRTON, }; // Message lengths & required repeat values const uint16_t kNoRepeat = 0; const uint16_t kSingleRepeat = 1; +const uint16_t kAirtonBits = 56; +const uint16_t kAirtonDefaultRepeat = kNoRepeat; const uint16_t kAirwellBits = 34; const uint16_t kAirwellMinRepeats = 2; const uint16_t kAiwaRcT501Bits = 15; @@ -970,6 +996,7 @@ const uint16_t kAmcorDefaultRepeat = kSingleRepeat; const uint16_t kArgoStateLength = 12; const uint16_t kArgoBits = kArgoStateLength * 8; const uint16_t kArgoDefaultRepeat = kNoRepeat; +const uint16_t kArrisBits = 32; const uint16_t kCoolixBits = 24; const uint16_t kCoolixDefaultRepeat = kSingleRepeat; const uint16_t kCarrierAcBits = 32; @@ -1195,6 +1222,9 @@ const uint16_t kMilesTag2ShotBits = 14; const uint16_t kMilesTag2MsgBits = 24; const uint16_t kMilesMinRepeat = 0; const uint16_t kBoseBits = 16; +const uint16_t kRhossStateLength = 12; +const uint16_t kRhossBits = kRhossStateLength * 8; +const uint16_t kRhossDefaultRepeat = 0; // Legacy defines. (Deprecated) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.cpp index 4814bd431..e20b97045 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.cpp @@ -637,6 +637,7 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) { case LG: case LG2: return 28; + case ARRIS: case CARRIER_AC: case ELITESCREENS: case EPSON: @@ -665,6 +666,7 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) { case MIDEA: case PANASONIC: return 48; + case AIRTON: case ECOCLIM: case MAGIQUEST: case VESTEL_AC: @@ -738,6 +740,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) { return kNeoclimaBits; case PANASONIC_AC: return kPanasonicAcBits; + case RHOSS: + return kRhossBits; case SAMSUNG_AC: return kSamsungAcBits; case SANYO_AC: @@ -781,6 +785,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data, uint16_t min_repeat __attribute__((unused)) = std::max(IRsend::minRepeats(type), repeat); switch (type) { +#if SEND_AIRTON + case AIRTON: + sendAirton(data, nbits, min_repeat); + break; +#endif // SEND_AIRTON #if SEND_AIRWELL case AIRWELL: sendAirwell(data, nbits, min_repeat); @@ -790,7 +799,12 @@ bool IRsend::send(const decode_type_t type, const uint64_t data, case AIWA_RC_T501: sendAiwaRCT501(data, nbits, min_repeat); break; -#endif +#endif // SEND_AIWA_RC_T501 +#if SEND_ARRIS + case ARRIS: + sendArris(data, nbits, min_repeat); + break; +#endif // SEND_ARRIS #if SEND_BOSE case BOSE: sendBose(data, nbits, min_repeat); @@ -1247,6 +1261,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state, sendPanasonicAC(state, nbytes); break; #endif // SEND_PANASONIC_AC +#if SEND_RHOSS + case RHOSS: + sendRhoss(state, nbytes); + break; +#endif // SEND_RHOSS #if SEND_SAMSUNG_AC case SAMSUNG_AC: sendSamsungAC(state, nbytes); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.h index c20fc64bc..d55ce0238 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRsend.h @@ -136,12 +136,24 @@ enum gree_ac_remote_model_t { YBOFB, // (2) Green, YBOFB2, YAPOF3 }; +/// HAIER_AC176 A/C model numbers +enum haier_ac176_remote_model_t { + V9014557_A = 1, // (1) V9014557 Remote in "A" setting. (Default) + V9014557_B, // (2) V9014557 Remote in "B" setting. +}; + /// HITACHI_AC1 A/C model numbers enum hitachi_ac1_remote_model_t { R_LT0541_HTA_A = 1, // (1) R-LT0541-HTA Remote in "A" setting. (Default) R_LT0541_HTA_B, // (2) R-LT0541-HTA Remote in "B" setting. }; +/// MIRAGE A/C model numbers +enum mirage_ac_remote_model_t { + KKG9AC1 = 1, // (1) KKG9A-C1 Remote. (Default) + KKG29AC1, // (2) KKG29A-C1 Remote. +}; + /// Panasonic A/C model numbers enum panasonic_ac_remote_model_t { kPanasonicUnknown = 0, @@ -160,6 +172,12 @@ enum sharp_ac_remote_model_t { A903 = 3, // 820 too }; +/// TCL A/C model numbers +enum tcl_ac_remote_model_t { + TAC09CHSD = 1, + GZ055BE1 = 2, +}; + /// Voltas A/C model numbers enum voltas_ac_remote_model_t { kVoltasUnknown = 0, // Full Function @@ -737,6 +755,21 @@ class IRsend { void sendBose(const uint64_t data, const uint16_t nbits = kBoseBits, const uint16_t repeat = kNoRepeat); #endif // SEND_BOSE +#if SEND_ARRIS + void sendArris(const uint64_t data, const uint16_t nbits = kArrisBits, + const uint16_t repeat = kNoRepeat); + static uint32_t toggleArrisRelease(const uint32_t data); + static uint32_t encodeArris(const uint32_t command, const bool release); +#endif // SEND_ARRIS +#if SEND_RHOSS + void sendRhoss(const unsigned char data[], + const uint16_t nbytes = kRhossStateLength, + const uint16_t repeat = kRhossDefaultRepeat); +#endif // SEND_RHOSS +#if SEND_AIRTON + void sendAirton(const uint64_t data, const uint16_t nbits = kAirtonBits, + const uint16_t repeat = kAirtonDefaultRepeat); +#endif // SEND_AIRTON protected: #ifdef UNIT_TEST diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.cpp index a7bd7de29..a580bff9f 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.cpp @@ -1,9 +1,10 @@ -// Copyright 2019-2020 - David Conran (@crankyoldgit) +// Copyright 2019-2021 - David Conran (@crankyoldgit) /// @file IRtext.cpp /// @warning If you add or remove an entry in this file, you should run: /// '../tools/generate_irtext_h.sh' to rebuild the `IRtext.h` file. +#include "IRtext.h" #ifndef UNIT_TEST #include #endif // UNIT_TEST @@ -14,178 +15,263 @@ #define PROGMEM // Pretend we have the PROGMEM macro even if we really don't. #endif +#ifndef FPSTR +#define FPSTR(X) X // Also pretend we have flash-string helper class cast. +#endif + +#define IRTEXT_CONST_BLOB_NAME(NAME)\ + NAME ## Blob + +#define IRTEXT_CONST_BLOB_DECL(NAME)\ + const char IRTEXT_CONST_BLOB_NAME(NAME) [] PROGMEM + +#define IRTEXT_CONST_BLOB_PTR(NAME)\ + IRTEXT_CONST_PTR(NAME) {\ + IRTEXT_CONST_PTR_CAST(IRTEXT_CONST_BLOB_NAME(NAME)) } + +#define IRTEXT_CONST_STRING(NAME, VALUE)\ + static IRTEXT_CONST_BLOB_DECL(NAME) { VALUE };\ + IRTEXT_CONST_PTR(NAME) PROGMEM {\ + IRTEXT_CONST_PTR_CAST(&(IRTEXT_CONST_BLOB_NAME(NAME))[0]) } + // Common -const PROGMEM char* kUnknownStr = D_STR_UNKNOWN; ///< "Unknown" -const PROGMEM char* kProtocolStr = D_STR_PROTOCOL; ///< "Protocol" -const PROGMEM char* kPowerStr = D_STR_POWER; ///< "Power" -const PROGMEM char* kOnStr = D_STR_ON; ///< "On" -const PROGMEM char* kOffStr = D_STR_OFF; ///< "Off" -const PROGMEM char* kModeStr = D_STR_MODE; ///< "Mode" -const PROGMEM char* kToggleStr = D_STR_TOGGLE; ///< "Toggle" -const PROGMEM char* kTurboStr = D_STR_TURBO; ///< "Turbo" -const PROGMEM char* kSuperStr = D_STR_SUPER; ///< "Super" -const PROGMEM char* kSleepStr = D_STR_SLEEP; ///< "Sleep" -const PROGMEM char* kLightStr = D_STR_LIGHT; ///< "Light" -const PROGMEM char* kPowerfulStr = D_STR_POWERFUL; ///< "Powerful" -const PROGMEM char* kQuietStr = D_STR_QUIET; ///< "Quiet" -const PROGMEM char* kEconoStr = D_STR_ECONO; ///< "Econo" -const PROGMEM char* kSwingStr = D_STR_SWING; ///< "Swing" -const PROGMEM char* kSwingHStr = D_STR_SWINGH; ///< "SwingH" -const PROGMEM char* kSwingVStr = D_STR_SWINGV; ///< "SwingV" -const PROGMEM char* kBeepStr = D_STR_BEEP; ///< "Beep" -const PROGMEM char* kZoneFollowStr = D_STR_ZONEFOLLOW; ///< "Zone Follow" -const PROGMEM char* kFixedStr = D_STR_FIXED; ///< "Fixed" -const PROGMEM char* kMouldStr = D_STR_MOULD; ///< "Mould" -const PROGMEM char* kCleanStr = D_STR_CLEAN; ///< "Clean" -const PROGMEM char* kPurifyStr = D_STR_PURIFY; ///< "Purify" -const PROGMEM char* kTimerStr = D_STR_TIMER; ///< "Timer" -const PROGMEM char* kOnTimerStr = D_STR_ONTIMER; ///< "On Timer" -const PROGMEM char* kOffTimerStr = D_STR_OFFTIMER; ///< "Off Timer" -const PROGMEM char* kTimerModeStr = D_STR_TIMERMODE; ///< "Timer Mode" -const PROGMEM char* kClockStr = D_STR_CLOCK; ///< "Clock" -const PROGMEM char* kCommandStr = D_STR_COMMAND; ///< "Command" -const PROGMEM char* kXFanStr = D_STR_XFAN; ///< "XFan" -const PROGMEM char* kHealthStr = D_STR_HEALTH; ///< "Health" -const PROGMEM char* kModelStr = D_STR_MODEL; ///< "Model" -const PROGMEM char* kTempStr = D_STR_TEMP; ///< "Temp" -const PROGMEM char* kIFeelStr = D_STR_IFEEL; ///< "IFeel" -const PROGMEM char* kHumidStr = D_STR_HUMID; ///< "Humid" -const PROGMEM char* kSaveStr = D_STR_SAVE; ///< "Save" -const PROGMEM char* kEyeStr = D_STR_EYE; ///< "Eye" -const PROGMEM char* kFollowStr = D_STR_FOLLOW; ///< "Follow" -const PROGMEM char* kIonStr = D_STR_ION; ///< "Ion" -const PROGMEM char* kFreshStr = D_STR_FRESH; ///< "Fresh" -const PROGMEM char* kHoldStr = D_STR_HOLD; ///< "Hold" -const PROGMEM char* kButtonStr = D_STR_BUTTON; ///< "Button" -const PROGMEM char* k8CHeatStr = D_STR_8C_HEAT; ///< "8C Heat" -const PROGMEM char* k10CHeatStr = D_STR_10C_HEAT; ///< "10C Heat" -const PROGMEM char* kNightStr = D_STR_NIGHT; ///< "Night" -const PROGMEM char* kSilentStr = D_STR_SILENT; ///< "Silent" -const PROGMEM char* kFilterStr = D_STR_FILTER; ///< "Filter" -const PROGMEM char* k3DStr = D_STR_3D; ///< "3D" -const PROGMEM char* kCelsiusStr = D_STR_CELSIUS; ///< "Celsius" -const PROGMEM char* kCelsiusFahrenheitStr = D_STR_CELSIUS_FAHRENHEIT; ///< +IRTEXT_CONST_STRING(kUnknownStr, D_STR_UNKNOWN); ///< "Unknown" +IRTEXT_CONST_STRING(kProtocolStr, D_STR_PROTOCOL); ///< "Protocol" +IRTEXT_CONST_STRING(kPowerStr, D_STR_POWER); ///< "Power" +IRTEXT_CONST_STRING(kOnStr, D_STR_ON); ///< "On" +IRTEXT_CONST_STRING(kOffStr, D_STR_OFF); ///< "Off" +IRTEXT_CONST_STRING(k1Str, D_STR_1); ///< "1" +IRTEXT_CONST_STRING(k0Str, D_STR_0); ///< "0" +IRTEXT_CONST_STRING(kModeStr, D_STR_MODE); ///< "Mode" +IRTEXT_CONST_STRING(kToggleStr, D_STR_TOGGLE); ///< "Toggle" +IRTEXT_CONST_STRING(kTurboStr, D_STR_TURBO); ///< "Turbo" +IRTEXT_CONST_STRING(kSuperStr, D_STR_SUPER); ///< "Super" +IRTEXT_CONST_STRING(kSleepStr, D_STR_SLEEP); ///< "Sleep" +IRTEXT_CONST_STRING(kLightStr, D_STR_LIGHT); ///< "Light" +IRTEXT_CONST_STRING(kPowerfulStr, D_STR_POWERFUL); ///< "Powerful" +IRTEXT_CONST_STRING(kQuietStr, D_STR_QUIET); ///< "Quiet" +IRTEXT_CONST_STRING(kEconoStr, D_STR_ECONO); ///< "Econo" +IRTEXT_CONST_STRING(kSwingStr, D_STR_SWING); ///< "Swing" +IRTEXT_CONST_STRING(kSwingHStr, D_STR_SWINGH); ///< "SwingH" +IRTEXT_CONST_STRING(kSwingVStr, D_STR_SWINGV); ///< "SwingV" +IRTEXT_CONST_STRING(kBeepStr, D_STR_BEEP); ///< "Beep" +IRTEXT_CONST_STRING(kZoneFollowStr, D_STR_ZONEFOLLOW); ///< "Zone Follow" +IRTEXT_CONST_STRING(kFixedStr, D_STR_FIXED); ///< "Fixed" +IRTEXT_CONST_STRING(kMouldStr, D_STR_MOULD); ///< "Mould" +IRTEXT_CONST_STRING(kCleanStr, D_STR_CLEAN); ///< "Clean" +IRTEXT_CONST_STRING(kPurifyStr, D_STR_PURIFY); ///< "Purify" +IRTEXT_CONST_STRING(kTimerStr, D_STR_TIMER); ///< "Timer" +IRTEXT_CONST_STRING(kOnTimerStr, D_STR_ONTIMER); ///< "On Timer" +IRTEXT_CONST_STRING(kOffTimerStr, D_STR_OFFTIMER); ///< "Off Timer" +IRTEXT_CONST_STRING(kTimerModeStr, D_STR_TIMERMODE); ///< "Timer Mode" +IRTEXT_CONST_STRING(kClockStr, D_STR_CLOCK); ///< "Clock" +IRTEXT_CONST_STRING(kCommandStr, D_STR_COMMAND); ///< "Command" +IRTEXT_CONST_STRING(kXFanStr, D_STR_XFAN); ///< "XFan" +IRTEXT_CONST_STRING(kHealthStr, D_STR_HEALTH); ///< "Health" +IRTEXT_CONST_STRING(kModelStr, D_STR_MODEL); ///< "Model" +IRTEXT_CONST_STRING(kTempStr, D_STR_TEMP); ///< "Temp" +IRTEXT_CONST_STRING(kIFeelStr, D_STR_IFEEL); ///< "IFeel" +IRTEXT_CONST_STRING(kHumidStr, D_STR_HUMID); ///< "Humid" +IRTEXT_CONST_STRING(kSaveStr, D_STR_SAVE); ///< "Save" +IRTEXT_CONST_STRING(kEyeStr, D_STR_EYE); ///< "Eye" +IRTEXT_CONST_STRING(kFollowStr, D_STR_FOLLOW); ///< "Follow" +IRTEXT_CONST_STRING(kIonStr, D_STR_ION); ///< "Ion" +IRTEXT_CONST_STRING(kFreshStr, D_STR_FRESH); ///< "Fresh" +IRTEXT_CONST_STRING(kHoldStr, D_STR_HOLD); ///< "Hold" +IRTEXT_CONST_STRING(kButtonStr, D_STR_BUTTON); ///< "Button" +IRTEXT_CONST_STRING(k8CHeatStr, D_STR_8C_HEAT); ///< "8C Heat" +IRTEXT_CONST_STRING(k10CHeatStr, D_STR_10C_HEAT); ///< "10C Heat" +IRTEXT_CONST_STRING(kNightStr, D_STR_NIGHT); ///< "Night" +IRTEXT_CONST_STRING(kSilentStr, D_STR_SILENT); ///< "Silent" +IRTEXT_CONST_STRING(kFilterStr, D_STR_FILTER); ///< "Filter" +IRTEXT_CONST_STRING(k3DStr, D_STR_3D); ///< "3D" +IRTEXT_CONST_STRING(kCelsiusStr, D_STR_CELSIUS); ///< "Celsius" +IRTEXT_CONST_STRING(kCelsiusFahrenheitStr, D_STR_CELSIUS_FAHRENHEIT); ///< ///< "Celsius/Fahrenheit" -const PROGMEM char* kTempUpStr = D_STR_TEMPUP; ///< "Temp Up" -const PROGMEM char* kTempDownStr = D_STR_TEMPDOWN; ///< "Temp Down" -const PROGMEM char* kStartStr = D_STR_START; ///< "Start" -const PROGMEM char* kStopStr = D_STR_STOP; ///< "Stop" -const PROGMEM char* kMoveStr = D_STR_MOVE; ///< "Move" -const PROGMEM char* kSetStr = D_STR_SET; ///< "Set" -const PROGMEM char* kCancelStr = D_STR_CANCEL; ///< "Cancel" -const PROGMEM char* kUpStr = D_STR_UP; ///< "Up" -const PROGMEM char* kDownStr = D_STR_DOWN; ///< "Down" -const PROGMEM char* kChangeStr = D_STR_CHANGE; ///< "Change" -const PROGMEM char* kComfortStr = D_STR_COMFORT; ///< "Comfort" -const PROGMEM char* kSensorStr = D_STR_SENSOR; ///< "Sensor" -const PROGMEM char* kWeeklyTimerStr = D_STR_WEEKLYTIMER; ///< "WeeklyTimer" -const PROGMEM char* kWifiStr = D_STR_WIFI; ///< "Wifi" -const PROGMEM char* kLastStr = D_STR_LAST; ///< "Last" -const PROGMEM char* kFastStr = D_STR_FAST; ///< "Fast" -const PROGMEM char* kSlowStr = D_STR_SLOW; ///< "Slow" -const PROGMEM char* kAirFlowStr = D_STR_AIRFLOW; ///< "Air Flow" -const PROGMEM char* kStepStr = D_STR_STEP; ///< "Step" -const PROGMEM char* kNAStr = D_STR_NA; ///< "N/A" -const PROGMEM char* kInsideStr = D_STR_INSIDE; ///< "Inside" -const PROGMEM char* kOutsideStr = D_STR_OUTSIDE; ///< "Outside" -const PROGMEM char* kLoudStr = D_STR_LOUD; ///< "Loud" -const PROGMEM char* kLowerStr = D_STR_LOWER; ///< "Lower" -const PROGMEM char* kUpperStr = D_STR_UPPER; ///< "Upper" -const PROGMEM char* kBreezeStr = D_STR_BREEZE; ///< "Breeze" -const PROGMEM char* kCirculateStr = D_STR_CIRCULATE; ///< "Circulate" -const PROGMEM char* kCeilingStr = D_STR_CEILING; ///< "Ceiling" -const PROGMEM char* kWallStr = D_STR_WALL; ///< "Wall" -const PROGMEM char* kRoomStr = D_STR_ROOM; ///< "Room" -const PROGMEM char* k6thSenseStr = D_STR_6THSENSE; ///< "6th Sense" -const PROGMEM char* kTypeStr = D_STR_TYPE; ///< "Type" -const PROGMEM char* kSpecialStr = D_STR_SPECIAL; ///< "Special" -const PROGMEM char* kIdStr = D_STR_ID; ///< "Id" / Device Identifier -const PROGMEM char* kVaneStr = D_STR_VANE; ///< "Vane" +IRTEXT_CONST_STRING(kTempUpStr, D_STR_TEMPUP); ///< "Temp Up" +IRTEXT_CONST_STRING(kTempDownStr, D_STR_TEMPDOWN); ///< "Temp Down" +IRTEXT_CONST_STRING(kStartStr, D_STR_START); ///< "Start" +IRTEXT_CONST_STRING(kStopStr, D_STR_STOP); ///< "Stop" +IRTEXT_CONST_STRING(kMoveStr, D_STR_MOVE); ///< "Move" +IRTEXT_CONST_STRING(kSetStr, D_STR_SET); ///< "Set" +IRTEXT_CONST_STRING(kCancelStr, D_STR_CANCEL); ///< "Cancel" +IRTEXT_CONST_STRING(kUpStr, D_STR_UP); ///< "Up" +IRTEXT_CONST_STRING(kDownStr, D_STR_DOWN); ///< "Down" +IRTEXT_CONST_STRING(kChangeStr, D_STR_CHANGE); ///< "Change" +IRTEXT_CONST_STRING(kComfortStr, D_STR_COMFORT); ///< "Comfort" +IRTEXT_CONST_STRING(kSensorStr, D_STR_SENSOR); ///< "Sensor" +IRTEXT_CONST_STRING(kWeeklyTimerStr, D_STR_WEEKLYTIMER); ///< "WeeklyTimer" +IRTEXT_CONST_STRING(kWifiStr, D_STR_WIFI); ///< "Wifi" +IRTEXT_CONST_STRING(kLastStr, D_STR_LAST); ///< "Last" +IRTEXT_CONST_STRING(kFastStr, D_STR_FAST); ///< "Fast" +IRTEXT_CONST_STRING(kSlowStr, D_STR_SLOW); ///< "Slow" +IRTEXT_CONST_STRING(kAirFlowStr, D_STR_AIRFLOW); ///< "Air Flow" +IRTEXT_CONST_STRING(kStepStr, D_STR_STEP); ///< "Step" +IRTEXT_CONST_STRING(kNAStr, D_STR_NA); ///< "N/A" +IRTEXT_CONST_STRING(kInsideStr, D_STR_INSIDE); ///< "Inside" +IRTEXT_CONST_STRING(kOutsideStr, D_STR_OUTSIDE); ///< "Outside" +IRTEXT_CONST_STRING(kLoudStr, D_STR_LOUD); ///< "Loud" +IRTEXT_CONST_STRING(kLowerStr, D_STR_LOWER); ///< "Lower" +IRTEXT_CONST_STRING(kUpperStr, D_STR_UPPER); ///< "Upper" +IRTEXT_CONST_STRING(kBreezeStr, D_STR_BREEZE); ///< "Breeze" +IRTEXT_CONST_STRING(kCirculateStr, D_STR_CIRCULATE); ///< "Circulate" +IRTEXT_CONST_STRING(kCeilingStr, D_STR_CEILING); ///< "Ceiling" +IRTEXT_CONST_STRING(kWallStr, D_STR_WALL); ///< "Wall" +IRTEXT_CONST_STRING(kRoomStr, D_STR_ROOM); ///< "Room" +IRTEXT_CONST_STRING(k6thSenseStr, D_STR_6THSENSE); ///< "6th Sense" +IRTEXT_CONST_STRING(kTypeStr, D_STR_TYPE); ///< "Type" +IRTEXT_CONST_STRING(kSpecialStr, D_STR_SPECIAL); ///< "Special" +IRTEXT_CONST_STRING(kIdStr, D_STR_ID); ///< "Id" / Device Identifier +IRTEXT_CONST_STRING(kVaneStr, D_STR_VANE); ///< "Vane" +IRTEXT_CONST_STRING(kLockStr, D_STR_LOCK); ///< "Lock" -const PROGMEM char* kAutoStr = D_STR_AUTO; ///< "Auto" -const PROGMEM char* kAutomaticStr = D_STR_AUTOMATIC; ///< "Automatic" -const PROGMEM char* kManualStr = D_STR_MANUAL; ///< "Manual" -const PROGMEM char* kCoolStr = D_STR_COOL; ///< "Cool" -const PROGMEM char* kHeatStr = D_STR_HEAT; ///< "Heat" -const PROGMEM char* kFanStr = D_STR_FAN; ///< "Fan" -const PROGMEM char* kDryStr = D_STR_DRY; ///< "Dry" -const PROGMEM char* kFanOnlyStr = D_STR_FANONLY; ///< "fan_only" -const PROGMEM char* kRecycleStr = D_STR_RECYCLE; ///< "Recycle" +IRTEXT_CONST_STRING(kAutoStr, D_STR_AUTO); ///< "Auto" +IRTEXT_CONST_STRING(kAutomaticStr, D_STR_AUTOMATIC); ///< "Automatic" +IRTEXT_CONST_STRING(kManualStr, D_STR_MANUAL); ///< "Manual" +IRTEXT_CONST_STRING(kCoolStr, D_STR_COOL); ///< "Cool" +IRTEXT_CONST_STRING(kCoolingStr, D_STR_COOLING); ///< "Cooling" +IRTEXT_CONST_STRING(kHeatStr, D_STR_HEAT); ///< "Heat" +IRTEXT_CONST_STRING(kHeatingStr, D_STR_HEATING); ///< "Heating" +IRTEXT_CONST_STRING(kDryStr, D_STR_DRY); ///< "Dry" +IRTEXT_CONST_STRING(kDryingStr, D_STR_DRYING); ///< "Drying" +IRTEXT_CONST_STRING(kDehumidifyStr, D_STR_DEHUMIDIFY); ///< "Dehumidify" +IRTEXT_CONST_STRING(kFanStr, D_STR_FAN); ///< "Fan" +// The following Fans strings with "only" are required to help with +// HomeAssistant & Google Home Climate integration. For compatibility only. +// Ref: https://www.home-assistant.io/integrations/google_assistant/#climate-operation-modes +IRTEXT_CONST_STRING(kFanOnlyStr, D_STR_FANONLY); ///< "fan-only" +IRTEXT_CONST_STRING(kFan_OnlyStr, D_STR_FAN_ONLY); ///< "fan_only" (HA/legacy) +IRTEXT_CONST_STRING(kFanOnlyWithSpaceStr, D_STR_FANSPACEONLY); ///< "Fan Only" +IRTEXT_CONST_STRING(kFanOnlyNoSpaceStr, D_STR_FANONLYNOSPACE); ///< "FanOnly" -const PROGMEM char* kMaxStr = D_STR_MAX; ///< "Max" -const PROGMEM char* kMaximumStr = D_STR_MAXIMUM; ///< "Maximum" -const PROGMEM char* kMinStr = D_STR_MIN; ///< "Min" -const PROGMEM char* kMinimumStr = D_STR_MINIMUM; ///< "Minimum" -const PROGMEM char* kMedStr = D_STR_MED; ///< "Med" -const PROGMEM char* kMediumStr = D_STR_MEDIUM; ///< "Medium" +IRTEXT_CONST_STRING(kRecycleStr, D_STR_RECYCLE); ///< "Recycle" -const PROGMEM char* kHighestStr = D_STR_HIGHEST; ///< "Highest" -const PROGMEM char* kHighStr = D_STR_HIGH; ///< "High" -const PROGMEM char* kHiStr = D_STR_HI; ///< "Hi" -const PROGMEM char* kMidStr = D_STR_MID; ///< "Mid" -const PROGMEM char* kMiddleStr = D_STR_MIDDLE; ///< "Middle" -const PROGMEM char* kLowStr = D_STR_LOW; ///< "Low" -const PROGMEM char* kLoStr = D_STR_LO; ///< "Lo" -const PROGMEM char* kLowestStr = D_STR_LOWEST; ///< "Lowest" -const PROGMEM char* kMaxRightStr = D_STR_MAXRIGHT; ///< "Max Right" -const PROGMEM char* kRightMaxStr = D_STR_RIGHTMAX_NOSPACE; ///< "RightMax" -const PROGMEM char* kRightStr = D_STR_RIGHT; ///< "Right" -const PROGMEM char* kLeftStr = D_STR_LEFT; ///< "Left" -const PROGMEM char* kMaxLeftStr = D_STR_MAXLEFT; ///< "Max Left" -const PROGMEM char* kLeftMaxStr = D_STR_LEFTMAX_NOSPACE; ///< "LeftMax" -const PROGMEM char* kWideStr = D_STR_WIDE; ///< "Wide" -const PROGMEM char* kCentreStr = D_STR_CENTRE; ///< "Centre" -const PROGMEM char* kTopStr = D_STR_TOP; ///< "Top" -const PROGMEM char* kBottomStr = D_STR_BOTTOM; ///< "Bottom" +IRTEXT_CONST_STRING(kMaxStr, D_STR_MAX); ///< "Max" +IRTEXT_CONST_STRING(kMaximumStr, D_STR_MAXIMUM); ///< "Maximum" +IRTEXT_CONST_STRING(kMinStr, D_STR_MIN); ///< "Min" +IRTEXT_CONST_STRING(kMinimumStr, D_STR_MINIMUM); ///< "Minimum" +IRTEXT_CONST_STRING(kMedStr, D_STR_MED); ///< "Med" +IRTEXT_CONST_STRING(kMediumStr, D_STR_MEDIUM); ///< "Medium" + +IRTEXT_CONST_STRING(kHighestStr, D_STR_HIGHEST); ///< "Highest" +IRTEXT_CONST_STRING(kHighStr, D_STR_HIGH); ///< "High" +IRTEXT_CONST_STRING(kHiStr, D_STR_HI); ///< "Hi" +IRTEXT_CONST_STRING(kMidStr, D_STR_MID); ///< "Mid" +IRTEXT_CONST_STRING(kMiddleStr, D_STR_MIDDLE); ///< "Middle" +IRTEXT_CONST_STRING(kLowStr, D_STR_LOW); ///< "Low" +IRTEXT_CONST_STRING(kLoStr, D_STR_LO); ///< "Lo" +IRTEXT_CONST_STRING(kLowestStr, D_STR_LOWEST); ///< "Lowest" +IRTEXT_CONST_STRING(kMaxRightStr, D_STR_MAXRIGHT); ///< "Max Right" +IRTEXT_CONST_STRING(kMaxRightNoSpaceStr, D_STR_MAXRIGHT_NOSPACE); ///< + ///< "MaxRight" +IRTEXT_CONST_STRING(kRightMaxStr, D_STR_RIGHTMAX); ///< "Right Max" +IRTEXT_CONST_STRING(kRightMaxNoSpaceStr, D_STR_RIGHTMAX_NOSPACE); ///< + ///< "RightMax" +IRTEXT_CONST_STRING(kRightStr, D_STR_RIGHT); ///< "Right" +IRTEXT_CONST_STRING(kLeftStr, D_STR_LEFT); ///< "Left" +IRTEXT_CONST_STRING(kMaxLeftStr, D_STR_MAXLEFT); ///< "Max Left" +IRTEXT_CONST_STRING(kMaxLeftNoSpaceStr, D_STR_MAXLEFT_NOSPACE); ///< "MaxLeft" +IRTEXT_CONST_STRING(kLeftMaxStr, D_STR_LEFTMAX); ///< "Left Max" +IRTEXT_CONST_STRING(kLeftMaxNoSpaceStr, D_STR_LEFTMAX_NOSPACE); ///< "LeftMax" +IRTEXT_CONST_STRING(kWideStr, D_STR_WIDE); ///< "Wide" +IRTEXT_CONST_STRING(kCentreStr, D_STR_CENTRE); ///< "Centre" +IRTEXT_CONST_STRING(kTopStr, D_STR_TOP); ///< "Top" +IRTEXT_CONST_STRING(kBottomStr, D_STR_BOTTOM); ///< "Bottom" // Compound words/phrases/descriptions from pre-defined words. -const PROGMEM char* kEconoToggleStr = D_STR_ECONOTOGGLE; ///< "Econo Toggle" -const PROGMEM char* kEyeAutoStr = D_STR_EYEAUTO; ///< "Eye Auto" -const PROGMEM char* kLightToggleStr = D_STR_LIGHTTOGGLE; ///< "Light Toggle" -const PROGMEM char* kOutsideQuietStr = D_STR_OUTSIDEQUIET; ///< "Outside Quiet" -const PROGMEM char* kPowerToggleStr = D_STR_POWERTOGGLE; ///< "Power Toggle" -const PROGMEM char* kPowerButtonStr = D_STR_POWERBUTTON; ///< "Power Button" -const PROGMEM char* kPreviousPowerStr = D_STR_PREVIOUSPOWER; ///< +IRTEXT_CONST_STRING(kEconoToggleStr, D_STR_ECONOTOGGLE); ///< "Econo Toggle" +IRTEXT_CONST_STRING(kEyeAutoStr, D_STR_EYEAUTO); ///< "Eye Auto" +IRTEXT_CONST_STRING(kLightToggleStr, D_STR_LIGHTTOGGLE); ///< "Light Toggle" +///< "Outside Quiet" +IRTEXT_CONST_STRING(kOutsideQuietStr, D_STR_OUTSIDEQUIET); +IRTEXT_CONST_STRING(kPowerToggleStr, D_STR_POWERTOGGLE); ///< "Power Toggle" +IRTEXT_CONST_STRING(kPowerButtonStr, D_STR_POWERBUTTON); ///< "Power Button" +IRTEXT_CONST_STRING(kPreviousPowerStr, D_STR_PREVIOUSPOWER); ///< ///< "Previous Power" -const PROGMEM char* kDisplayTempStr = D_STR_DISPLAYTEMP; ///< "Display Temp" -const PROGMEM char* kSensorTempStr = D_STR_SENSORTEMP; ///< "Sensor Temp" -const PROGMEM char* kSleepTimerStr = D_STR_SLEEP_TIMER; ///< "Sleep Timer" -const PROGMEM char* kSwingVModeStr = D_STR_SWINGVMODE; ///< "Swing(V) Mode" -const PROGMEM char* kSwingVToggleStr = D_STR_SWINGVTOGGLE; ///< +IRTEXT_CONST_STRING(kDisplayTempStr, D_STR_DISPLAYTEMP); ///< "Display Temp" +IRTEXT_CONST_STRING(kSensorTempStr, D_STR_SENSORTEMP); ///< "Sensor Temp" +IRTEXT_CONST_STRING(kSleepTimerStr, D_STR_SLEEP_TIMER); ///< "Sleep Timer" +IRTEXT_CONST_STRING(kSwingVModeStr, D_STR_SWINGVMODE); ///< "Swing(V) Mode" +IRTEXT_CONST_STRING(kSwingVToggleStr, D_STR_SWINGVTOGGLE); ///< ///< "Swing(V) Toggle" -const PROGMEM char* kTurboToggleStr = D_STR_TURBOTOGGLE; ///< "Turbo Toggle" +IRTEXT_CONST_STRING(kTurboToggleStr, D_STR_TURBOTOGGLE); ///< "Turbo Toggle" -// Separators -char kTimeSep = D_CHR_TIME_SEP; ///< ':' -const PROGMEM char* kSpaceLBraceStr = D_STR_SPACELBRACE; ///< " (" -const PROGMEM char* kCommaSpaceStr = D_STR_COMMASPACE; ///< ", " -const PROGMEM char* kColonSpaceStr = D_STR_COLONSPACE; ///< ": " +// Separators & Punctuation +const char kTimeSep = D_CHR_TIME_SEP; ///< ':' +IRTEXT_CONST_STRING(kSpaceLBraceStr, D_STR_SPACELBRACE); ///< " (" +IRTEXT_CONST_STRING(kCommaSpaceStr, D_STR_COMMASPACE); ///< ", " +IRTEXT_CONST_STRING(kColonSpaceStr, D_STR_COLONSPACE); ///< ": " +IRTEXT_CONST_STRING(kDashStr, D_STR_DASH); ///< "-" // IRutils // - Time -const PROGMEM char* kDayStr = D_STR_DAY; ///< "Day" -const PROGMEM char* kDaysStr = D_STR_DAYS; ///< "Days" -const PROGMEM char* kHourStr = D_STR_HOUR; ///< "Hour" -const PROGMEM char* kHoursStr = D_STR_HOURS; ///< "Hours" -const PROGMEM char* kMinuteStr = D_STR_MINUTE; ///< "Minute" -const PROGMEM char* kMinutesStr = D_STR_MINUTES; ///< "Minutes" -const PROGMEM char* kSecondStr = D_STR_SECOND; ///< "Second" -const PROGMEM char* kSecondsStr = D_STR_SECONDS; ///< "Seconds" -const PROGMEM char* kNowStr = D_STR_NOW; ///< "Now" -const PROGMEM char* kThreeLetterDayOfWeekStr = D_STR_THREELETTERDAYS; ///< +IRTEXT_CONST_STRING(kDayStr, D_STR_DAY); ///< "Day" +IRTEXT_CONST_STRING(kDaysStr, D_STR_DAYS); ///< "Days" +IRTEXT_CONST_STRING(kHourStr, D_STR_HOUR); ///< "Hour" +IRTEXT_CONST_STRING(kHoursStr, D_STR_HOURS); ///< "Hours" +IRTEXT_CONST_STRING(kMinuteStr, D_STR_MINUTE); ///< "Minute" +IRTEXT_CONST_STRING(kMinutesStr, D_STR_MINUTES); ///< "Minutes" +IRTEXT_CONST_STRING(kSecondStr, D_STR_SECOND); ///< "Second" +IRTEXT_CONST_STRING(kSecondsStr, D_STR_SECONDS); ///< "Seconds" +IRTEXT_CONST_STRING(kNowStr, D_STR_NOW); ///< "Now" +IRTEXT_CONST_STRING(kThreeLetterDayOfWeekStr, D_STR_THREELETTERDAYS); ///< ///< "SunMonTueWedThuFriSat" -const PROGMEM char* kYesStr = D_STR_YES; ///< "Yes" -const PROGMEM char* kNoStr = D_STR_NO; ///< "No" -const PROGMEM char* kTrueStr = D_STR_TRUE; ///< "True" -const PROGMEM char* kFalseStr = D_STR_FALSE; ///< "False" +IRTEXT_CONST_STRING(kYesStr, D_STR_YES); ///< "Yes" +IRTEXT_CONST_STRING(kNoStr, D_STR_NO); ///< "No" +IRTEXT_CONST_STRING(kTrueStr, D_STR_TRUE); ///< "True" +IRTEXT_CONST_STRING(kFalseStr, D_STR_FALSE); ///< "False" -const PROGMEM char* kRepeatStr = D_STR_REPEAT; ///< "Repeat" -const PROGMEM char* kCodeStr = D_STR_CODE; ///< "Code" -const PROGMEM char* kBitsStr = D_STR_BITS; ///< "Bits" +IRTEXT_CONST_STRING(kRepeatStr, D_STR_REPEAT); ///< "Repeat" +IRTEXT_CONST_STRING(kCodeStr, D_STR_CODE); ///< "Code" +IRTEXT_CONST_STRING(kBitsStr, D_STR_BITS); ///< "Bits" + +// Model Names +IRTEXT_CONST_STRING(kYaw1fStr, D_STR_YAW1F); ///< "YAW1F" +IRTEXT_CONST_STRING(kYbofbStr, D_STR_YBOFB); ///< "YBOFB" +IRTEXT_CONST_STRING(kV9014557AStr, D_STR_V9014557_A); ///< "V9014557-A" +IRTEXT_CONST_STRING(kV9014557BStr, D_STR_V9014557_B); ///< "V9014557-B" +IRTEXT_CONST_STRING(kRlt0541htaaStr, D_STR_RLT0541HTA_A); ///< "R-LT0541-HTA-A" +IRTEXT_CONST_STRING(kRlt0541htabStr, D_STR_RLT0541HTA_B); ///< "R-LT0541-HTA-B" +IRTEXT_CONST_STRING(kArrah2eStr, D_STR_ARRAH2E); ///< "ARRAH2E" +IRTEXT_CONST_STRING(kArdb1Str, D_STR_ARDB1); ///< "ARDB1" +IRTEXT_CONST_STRING(kArreb1eStr, D_STR_ARREB1E); ///< "ARREB1E" +IRTEXT_CONST_STRING(kArjw2Str, D_STR_ARJW2); ///< "ARJW2" +IRTEXT_CONST_STRING(kArry4Str, D_STR_ARRY4); ///< "ARRY4" +IRTEXT_CONST_STRING(kArrew4eStr, D_STR_ARREW4E); ///< "ARREW4E" +IRTEXT_CONST_STRING(kGe6711ar2853mStr, D_STR_GE6711AR2853M); ///< + ///< "GE6711AR2853M" +IRTEXT_CONST_STRING(kAkb75215403Str, D_STR_AKB75215403); ///< "AKB75215403" +IRTEXT_CONST_STRING(kAkb74955603Str, D_STR_AKB74955603); ///< "AKB74955603" +IRTEXT_CONST_STRING(kAkb73757604Str, D_STR_AKB73757604); ///< "AKB73757604" +IRTEXT_CONST_STRING(kKkg9ac1Str, D_STR_KKG9AC1); ///< "KKG9AC1" +IRTEXT_CONST_STRING(kKkg29ac1Str, D_STR_KKG29AC1); ///< "KKG29AC1" +IRTEXT_CONST_STRING(kLkeStr, D_STR_LKE); ///< "LKE" +IRTEXT_CONST_STRING(kNkeStr, D_STR_NKE); ///< "NKE" +IRTEXT_CONST_STRING(kDkeStr, D_STR_DKE); ///< "DKE" +IRTEXT_CONST_STRING(kPkrStr, D_STR_PKR); ///< "PKR" +IRTEXT_CONST_STRING(kJkeStr, D_STR_JKE); ///< "JKE" +IRTEXT_CONST_STRING(kCkpStr, D_STR_CKP); ///< "CKP" +IRTEXT_CONST_STRING(kRkrStr, D_STR_RKR); ///< "RKR" +IRTEXT_CONST_STRING(kPanasonicLkeStr, D_STR_PANASONICLKE); ///< "PANASONICLKE" +IRTEXT_CONST_STRING(kPanasonicNkeStr, D_STR_PANASONICNKE); ///< "PANASONICNKE" +IRTEXT_CONST_STRING(kPanasonicDkeStr, D_STR_PANASONICDKE); ///< "PANASONICDKE" +IRTEXT_CONST_STRING(kPanasonicPkrStr, D_STR_PANASONICPKR); ///< "PANASONICPKR" +IRTEXT_CONST_STRING(kPanasonicJkeStr, D_STR_PANASONICJKE); ///< "PANASONICJKE" +IRTEXT_CONST_STRING(kPanasonicCkpStr, D_STR_PANASONICCKP); ///< "PANASONICCKP" +IRTEXT_CONST_STRING(kPanasonicRkrStr, D_STR_PANASONICRKR); ///< "PANASONICRKR" +IRTEXT_CONST_STRING(kA907Str, D_STR_A907); ///< "A907" +IRTEXT_CONST_STRING(kA705Str, D_STR_A705); ///< "A705" +IRTEXT_CONST_STRING(kA903Str, D_STR_A903); ///< "A903" +IRTEXT_CONST_STRING(kTac09chsdStr, D_STR_TAC09CHSD); ///< "TAC09CHSD" +IRTEXT_CONST_STRING(kGz055be1Str, D_STR_GZ055BE1); ///< "GZ055BE1" +IRTEXT_CONST_STRING(k122lzfStr, D_STR_122LZF); ///< "122LZF" +IRTEXT_CONST_STRING(kDg11j13aStr, D_STR_DG11J13A); ///< "DG11J13A" +IRTEXT_CONST_STRING(kDg11j104Str, D_STR_DG11J104); ///< "DG11J104" +IRTEXT_CONST_STRING(kDg11j191Str, D_STR_DG11J191); ///< "DG11J191" // Protocol Names // Needs to be in decode_type_t order. -const PROGMEM char *kAllProtocolNamesStr = +IRTEXT_CONST_BLOB_DECL(kAllProtocolNamesStr) { D_STR_UNUSED "\x0" D_STR_RC5 "\x0" D_STR_RC6 "\x0" @@ -293,5 +379,11 @@ const PROGMEM char *kAllProtocolNamesStr = D_STR_TROTEC_3550 "\x0" D_STR_SANYO_AC88 "\x0" D_STR_BOSE "\x0" + D_STR_ARRIS "\x0" + D_STR_RHOSS "\x0" + D_STR_AIRTON "\x0" ///< New protocol strings should be added just above this line. - "\x0"; ///< This string requires double null termination. + "\x0" ///< This string requires double null termination. +}; + +IRTEXT_CONST_BLOB_PTR(kAllProtocolNamesStr); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.h index 55840688d..ee8ea5934 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRtext.h @@ -12,158 +12,224 @@ // Constant text to be shared across all object files. // This means there is only one copy of the character/string/text etc. -extern char kTimeSep; -extern const char* k10CHeatStr; -extern const char* k3DStr; -extern const char* k6thSenseStr; -extern const char* k8CHeatStr; -extern const char* kAirFlowStr; -extern const char *kAllProtocolNamesStr; -extern const char* kAutomaticStr; -extern const char* kAutoStr; -extern const char* kBeepStr; -extern const char* kBitsStr; -extern const char* kBottomStr; -extern const char* kBreezeStr; -extern const char* kButtonStr; -extern const char* kCancelStr; -extern const char* kCeilingStr; -extern const char* kCelsiusFahrenheitStr; -extern const char* kCelsiusStr; -extern const char* kCentreStr; -extern const char* kChangeStr; -extern const char* kCirculateStr; -extern const char* kCleanStr; -extern const char* kClockStr; -extern const char* kCodeStr; -extern const char* kColonSpaceStr; -extern const char* kComfortStr; -extern const char* kCommandStr; -extern const char* kCommaSpaceStr; -extern const char* kCoolStr; -extern const char* kDaysStr; -extern const char* kDayStr; -extern const char* kDisplayTempStr; -extern const char* kDownStr; -extern const char* kDryStr; -extern const char* kEconoStr; -extern const char* kEconoToggleStr; -extern const char* kEyeAutoStr; -extern const char* kEyeStr; -extern const char* kFalseStr; -extern const char* kFanOnlyStr; -extern const char* kFanStr; -extern const char* kFastStr; -extern const char* kFilterStr; -extern const char* kFixedStr; -extern const char* kFollowStr; -extern const char* kFreshStr; -extern const char* kHealthStr; -extern const char* kHeatStr; -extern const char* kHighestStr; -extern const char* kHighStr; -extern const char* kHiStr; -extern const char* kHoldStr; -extern const char* kHoursStr; -extern const char* kHourStr; -extern const char* kHumidStr; -extern const char* kIdStr; -extern const char* kIFeelStr; -extern const char* kInsideStr; -extern const char* kIonStr; -extern const char* kLastStr; -extern const char* kLeftMaxStr; -extern const char* kLeftStr; -extern const char* kLightStr; -extern const char* kLightToggleStr; -extern const char* kLoStr; -extern const char* kLoudStr; -extern const char* kLowerStr; -extern const char* kLowestStr; -extern const char* kLowStr; -extern const char* kManualStr; -extern const char* kMaximumStr; -extern const char* kMaxLeftStr; -extern const char* kMaxRightStr; -extern const char* kMaxStr; -extern const char* kMediumStr; -extern const char* kMedStr; -extern const char* kMiddleStr; -extern const char* kMidStr; -extern const char* kMinimumStr; -extern const char* kMinStr; -extern const char* kMinutesStr; -extern const char* kMinuteStr; -extern const char* kModelStr; -extern const char* kModeStr; -extern const char* kMouldStr; -extern const char* kMoveStr; -extern const char* kNAStr; -extern const char* kNightStr; -extern const char* kNoStr; -extern const char* kNowStr; -extern const char* kOffStr; -extern const char* kOffTimerStr; -extern const char* kOnStr; -extern const char* kOnTimerStr; -extern const char* kOutsideQuietStr; -extern const char* kOutsideStr; -extern const char* kPowerButtonStr; -extern const char* kPowerfulStr; -extern const char* kPowerStr; -extern const char* kPowerToggleStr; -extern const char* kPreviousPowerStr; -extern const char* kProtocolStr; -extern const char* kPurifyStr; -extern const char* kQuietStr; -extern const char* kRecycleStr; -extern const char* kRepeatStr; -extern const char* kRightMaxStr; -extern const char* kRightStr; -extern const char* kRoomStr; -extern const char* kSaveStr; -extern const char* kSecondsStr; -extern const char* kSecondStr; -extern const char* kSensorStr; -extern const char* kSensorTempStr; -extern const char* kSetStr; -extern const char* kSilentStr; -extern const char* kSleepStr; -extern const char* kSleepTimerStr; -extern const char* kSlowStr; -extern const char* kSpaceLBraceStr; -extern const char* kSpecialStr; -extern const char* kStartStr; -extern const char* kStepStr; -extern const char* kStopStr; -extern const char* kSuperStr; -extern const char* kSwingHStr; -extern const char* kSwingStr; -extern const char* kSwingVModeStr; -extern const char* kSwingVStr; -extern const char* kSwingVToggleStr; -extern const char* kTempDownStr; -extern const char* kTempStr; -extern const char* kTempUpStr; -extern const char* kThreeLetterDayOfWeekStr; -extern const char* kTimerModeStr; -extern const char* kTimerStr; -extern const char* kToggleStr; -extern const char* kTopStr; -extern const char* kTrueStr; -extern const char* kTurboStr; -extern const char* kTurboToggleStr; -extern const char* kTypeStr; -extern const char* kUnknownStr; -extern const char* kUpperStr; -extern const char* kUpStr; -extern const char* kVaneStr; -extern const char* kWallStr; -extern const char* kWeeklyTimerStr; -extern const char* kWideStr; -extern const char* kWifiStr; -extern const char* kXFanStr; -extern const char* kYesStr; -extern const char* kZoneFollowStr; +#ifdef ESP8266 +class __FlashStringHelper; +#define IRTEXT_CONST_PTR_CAST(PTR)\ + reinterpret_cast(PTR) +#define IRTEXT_CONST_PTR(NAME) const __FlashStringHelper* const NAME +#else // ESP8266 +#define IRTEXT_CONST_PTR_CAST(PTR) PTR +#define IRTEXT_CONST_PTR(NAME) const char* const NAME +#endif // ESP8266 + +extern const char kTimeSep; +extern IRTEXT_CONST_PTR(k0Str); +extern IRTEXT_CONST_PTR(k10CHeatStr); +extern IRTEXT_CONST_PTR(k122lzfStr); +extern IRTEXT_CONST_PTR(k1Str); +extern IRTEXT_CONST_PTR(k3DStr); +extern IRTEXT_CONST_PTR(k6thSenseStr); +extern IRTEXT_CONST_PTR(k8CHeatStr); +extern IRTEXT_CONST_PTR(kA705Str); +extern IRTEXT_CONST_PTR(kA903Str); +extern IRTEXT_CONST_PTR(kA907Str); +extern IRTEXT_CONST_PTR(kAirFlowStr); +extern IRTEXT_CONST_PTR(kAkb73757604Str); +extern IRTEXT_CONST_PTR(kAkb74955603Str); +extern IRTEXT_CONST_PTR(kAkb75215403Str); +extern IRTEXT_CONST_PTR(kArdb1Str); +extern IRTEXT_CONST_PTR(kArjw2Str); +extern IRTEXT_CONST_PTR(kArrah2eStr); +extern IRTEXT_CONST_PTR(kArreb1eStr); +extern IRTEXT_CONST_PTR(kArrew4eStr); +extern IRTEXT_CONST_PTR(kArry4Str); +extern IRTEXT_CONST_PTR(kAutomaticStr); +extern IRTEXT_CONST_PTR(kAutoStr); +extern IRTEXT_CONST_PTR(kBeepStr); +extern IRTEXT_CONST_PTR(kBitsStr); +extern IRTEXT_CONST_PTR(kBottomStr); +extern IRTEXT_CONST_PTR(kBreezeStr); +extern IRTEXT_CONST_PTR(kButtonStr); +extern IRTEXT_CONST_PTR(kCancelStr); +extern IRTEXT_CONST_PTR(kCeilingStr); +extern IRTEXT_CONST_PTR(kCelsiusFahrenheitStr); +extern IRTEXT_CONST_PTR(kCelsiusStr); +extern IRTEXT_CONST_PTR(kCentreStr); +extern IRTEXT_CONST_PTR(kChangeStr); +extern IRTEXT_CONST_PTR(kCirculateStr); +extern IRTEXT_CONST_PTR(kCkpStr); +extern IRTEXT_CONST_PTR(kCleanStr); +extern IRTEXT_CONST_PTR(kClockStr); +extern IRTEXT_CONST_PTR(kCodeStr); +extern IRTEXT_CONST_PTR(kColonSpaceStr); +extern IRTEXT_CONST_PTR(kComfortStr); +extern IRTEXT_CONST_PTR(kCommandStr); +extern IRTEXT_CONST_PTR(kCommaSpaceStr); +extern IRTEXT_CONST_PTR(kCoolingStr); +extern IRTEXT_CONST_PTR(kCoolStr); +extern IRTEXT_CONST_PTR(kDashStr); +extern IRTEXT_CONST_PTR(kDaysStr); +extern IRTEXT_CONST_PTR(kDayStr); +extern IRTEXT_CONST_PTR(kDehumidifyStr); +extern IRTEXT_CONST_PTR(kDg11j104Str); +extern IRTEXT_CONST_PTR(kDg11j13aStr); +extern IRTEXT_CONST_PTR(kDg11j191Str); +extern IRTEXT_CONST_PTR(kDisplayTempStr); +extern IRTEXT_CONST_PTR(kDkeStr); +extern IRTEXT_CONST_PTR(kDownStr); +extern IRTEXT_CONST_PTR(kDryingStr); +extern IRTEXT_CONST_PTR(kDryStr); +extern IRTEXT_CONST_PTR(kEconoStr); +extern IRTEXT_CONST_PTR(kEconoToggleStr); +extern IRTEXT_CONST_PTR(kEyeAutoStr); +extern IRTEXT_CONST_PTR(kEyeStr); +extern IRTEXT_CONST_PTR(kFalseStr); +extern IRTEXT_CONST_PTR(kFanOnlyNoSpaceStr); +extern IRTEXT_CONST_PTR(kFan_OnlyStr); +extern IRTEXT_CONST_PTR(kFanOnlyStr); +extern IRTEXT_CONST_PTR(kFanOnlyWithSpaceStr); +extern IRTEXT_CONST_PTR(kFanStr); +extern IRTEXT_CONST_PTR(kFastStr); +extern IRTEXT_CONST_PTR(kFilterStr); +extern IRTEXT_CONST_PTR(kFixedStr); +extern IRTEXT_CONST_PTR(kFollowStr); +extern IRTEXT_CONST_PTR(kFreshStr); +extern IRTEXT_CONST_PTR(kGe6711ar2853mStr); +extern IRTEXT_CONST_PTR(kGz055be1Str); +extern IRTEXT_CONST_PTR(kHealthStr); +extern IRTEXT_CONST_PTR(kHeatingStr); +extern IRTEXT_CONST_PTR(kHeatStr); +extern IRTEXT_CONST_PTR(kHighestStr); +extern IRTEXT_CONST_PTR(kHighStr); +extern IRTEXT_CONST_PTR(kHiStr); +extern IRTEXT_CONST_PTR(kHoldStr); +extern IRTEXT_CONST_PTR(kHoursStr); +extern IRTEXT_CONST_PTR(kHourStr); +extern IRTEXT_CONST_PTR(kHumidStr); +extern IRTEXT_CONST_PTR(kIdStr); +extern IRTEXT_CONST_PTR(kIFeelStr); +extern IRTEXT_CONST_PTR(kInsideStr); +extern IRTEXT_CONST_PTR(kIonStr); +extern IRTEXT_CONST_PTR(kJkeStr); +extern IRTEXT_CONST_PTR(kKkg29ac1Str); +extern IRTEXT_CONST_PTR(kKkg9ac1Str); +extern IRTEXT_CONST_PTR(kLastStr); +extern IRTEXT_CONST_PTR(kLeftMaxNoSpaceStr); +extern IRTEXT_CONST_PTR(kLeftMaxStr); +extern IRTEXT_CONST_PTR(kLeftStr); +extern IRTEXT_CONST_PTR(kLightStr); +extern IRTEXT_CONST_PTR(kLightToggleStr); +extern IRTEXT_CONST_PTR(kLkeStr); +extern IRTEXT_CONST_PTR(kLoStr); +extern IRTEXT_CONST_PTR(kLockStr); +extern IRTEXT_CONST_PTR(kLoudStr); +extern IRTEXT_CONST_PTR(kLowerStr); +extern IRTEXT_CONST_PTR(kLowestStr); +extern IRTEXT_CONST_PTR(kLowStr); +extern IRTEXT_CONST_PTR(kManualStr); +extern IRTEXT_CONST_PTR(kMaximumStr); +extern IRTEXT_CONST_PTR(kMaxLeftNoSpaceStr); +extern IRTEXT_CONST_PTR(kMaxLeftStr); +extern IRTEXT_CONST_PTR(kMaxRightNoSpaceStr); +extern IRTEXT_CONST_PTR(kMaxRightStr); +extern IRTEXT_CONST_PTR(kMaxStr); +extern IRTEXT_CONST_PTR(kMediumStr); +extern IRTEXT_CONST_PTR(kMedStr); +extern IRTEXT_CONST_PTR(kMiddleStr); +extern IRTEXT_CONST_PTR(kMidStr); +extern IRTEXT_CONST_PTR(kMinimumStr); +extern IRTEXT_CONST_PTR(kMinStr); +extern IRTEXT_CONST_PTR(kMinutesStr); +extern IRTEXT_CONST_PTR(kMinuteStr); +extern IRTEXT_CONST_PTR(kModelStr); +extern IRTEXT_CONST_PTR(kModeStr); +extern IRTEXT_CONST_PTR(kMouldStr); +extern IRTEXT_CONST_PTR(kMoveStr); +extern IRTEXT_CONST_PTR(kNAStr); +extern IRTEXT_CONST_PTR(kNightStr); +extern IRTEXT_CONST_PTR(kNkeStr); +extern IRTEXT_CONST_PTR(kNoStr); +extern IRTEXT_CONST_PTR(kNowStr); +extern IRTEXT_CONST_PTR(kOffStr); +extern IRTEXT_CONST_PTR(kOffTimerStr); +extern IRTEXT_CONST_PTR(kOnStr); +extern IRTEXT_CONST_PTR(kOnTimerStr); +extern IRTEXT_CONST_PTR(kOutsideQuietStr); +extern IRTEXT_CONST_PTR(kOutsideStr); +extern IRTEXT_CONST_PTR(kPanasonicCkpStr); +extern IRTEXT_CONST_PTR(kPanasonicDkeStr); +extern IRTEXT_CONST_PTR(kPanasonicJkeStr); +extern IRTEXT_CONST_PTR(kPanasonicLkeStr); +extern IRTEXT_CONST_PTR(kPanasonicNkeStr); +extern IRTEXT_CONST_PTR(kPanasonicPkrStr); +extern IRTEXT_CONST_PTR(kPanasonicRkrStr); +extern IRTEXT_CONST_PTR(kPkrStr); +extern IRTEXT_CONST_PTR(kPowerButtonStr); +extern IRTEXT_CONST_PTR(kPowerfulStr); +extern IRTEXT_CONST_PTR(kPowerStr); +extern IRTEXT_CONST_PTR(kPowerToggleStr); +extern IRTEXT_CONST_PTR(kPreviousPowerStr); +extern IRTEXT_CONST_PTR(kProtocolStr); +extern IRTEXT_CONST_PTR(kPurifyStr); +extern IRTEXT_CONST_PTR(kQuietStr); +extern IRTEXT_CONST_PTR(kRecycleStr); +extern IRTEXT_CONST_PTR(kRepeatStr); +extern IRTEXT_CONST_PTR(kRightMaxNoSpaceStr); +extern IRTEXT_CONST_PTR(kRightMaxStr); +extern IRTEXT_CONST_PTR(kRightStr); +extern IRTEXT_CONST_PTR(kRkrStr); +extern IRTEXT_CONST_PTR(kRlt0541htaaStr); +extern IRTEXT_CONST_PTR(kRlt0541htabStr); +extern IRTEXT_CONST_PTR(kRoomStr); +extern IRTEXT_CONST_PTR(kSaveStr); +extern IRTEXT_CONST_PTR(kSecondsStr); +extern IRTEXT_CONST_PTR(kSecondStr); +extern IRTEXT_CONST_PTR(kSensorStr); +extern IRTEXT_CONST_PTR(kSensorTempStr); +extern IRTEXT_CONST_PTR(kSetStr); +extern IRTEXT_CONST_PTR(kSilentStr); +extern IRTEXT_CONST_PTR(kSleepStr); +extern IRTEXT_CONST_PTR(kSleepTimerStr); +extern IRTEXT_CONST_PTR(kSlowStr); +extern IRTEXT_CONST_PTR(kSpaceLBraceStr); +extern IRTEXT_CONST_PTR(kSpecialStr); +extern IRTEXT_CONST_PTR(kStartStr); +extern IRTEXT_CONST_PTR(kStepStr); +extern IRTEXT_CONST_PTR(kStopStr); +extern IRTEXT_CONST_PTR(kSuperStr); +extern IRTEXT_CONST_PTR(kSwingHStr); +extern IRTEXT_CONST_PTR(kSwingStr); +extern IRTEXT_CONST_PTR(kSwingVModeStr); +extern IRTEXT_CONST_PTR(kSwingVStr); +extern IRTEXT_CONST_PTR(kSwingVToggleStr); +extern IRTEXT_CONST_PTR(kTac09chsdStr); +extern IRTEXT_CONST_PTR(kTempDownStr); +extern IRTEXT_CONST_PTR(kTempStr); +extern IRTEXT_CONST_PTR(kTempUpStr); +extern IRTEXT_CONST_PTR(kThreeLetterDayOfWeekStr); +extern IRTEXT_CONST_PTR(kTimerModeStr); +extern IRTEXT_CONST_PTR(kTimerStr); +extern IRTEXT_CONST_PTR(kToggleStr); +extern IRTEXT_CONST_PTR(kTopStr); +extern IRTEXT_CONST_PTR(kTrueStr); +extern IRTEXT_CONST_PTR(kTurboStr); +extern IRTEXT_CONST_PTR(kTurboToggleStr); +extern IRTEXT_CONST_PTR(kTypeStr); +extern IRTEXT_CONST_PTR(kUnknownStr); +extern IRTEXT_CONST_PTR(kUpperStr); +extern IRTEXT_CONST_PTR(kUpStr); +extern IRTEXT_CONST_PTR(kV9014557AStr); +extern IRTEXT_CONST_PTR(kV9014557BStr); +extern IRTEXT_CONST_PTR(kVaneStr); +extern IRTEXT_CONST_PTR(kWallStr); +extern IRTEXT_CONST_PTR(kWeeklyTimerStr); +extern IRTEXT_CONST_PTR(kWideStr); +extern IRTEXT_CONST_PTR(kWifiStr); +extern IRTEXT_CONST_PTR(kXFanStr); +extern IRTEXT_CONST_PTR(kYaw1fStr); +extern IRTEXT_CONST_PTR(kYbofbStr); +extern IRTEXT_CONST_PTR(kYesStr); +extern IRTEXT_CONST_PTR(kZoneFollowStr); +extern IRTEXT_CONST_PTR(kAllProtocolNamesStr); #endif // IRTEXT_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.cpp index f9892d2a4..d3a83c507 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.cpp @@ -1,4 +1,4 @@ -// Copyright 2017 David Conran +// Copyright 2017-2021 David Conran #include "IRutils.h" #ifndef UNIT_TEST @@ -17,6 +17,27 @@ #include "IRsend.h" #include "IRtext.h" +// On the ESP8266 platform we need to use a set of ..._P functions +// to handle the strings stored in the flash address space. +#ifndef STRCASECMP +#if defined(ESP8266) +#define STRCASECMP(LHS, RHS) \ + strcasecmp_P(LHS, reinterpret_cast(RHS)) +#else // ESP8266 +#define STRCASECMP strcasecmp +#endif // ESP8266 +#endif // STRCASECMP +#ifndef STRLEN +#if defined(ESP8266) +#define STRLEN(PTR) strlen_P(PTR) +#else // ESP8266 +#define STRLEN(PTR) strlen(PTR) +#endif // ESP8266 +#endif // STRLEN +#ifndef FPSTR +#define FPSTR(X) X +#endif // FPSTR + /// Reverse the order of the requested least significant nr. of bits. /// @param[in] input Bit pattern/integer to reverse. /// @param[in] nbits Nr. of bits to reverse. (LSB -> MSB) @@ -74,7 +95,10 @@ String uint64ToString(uint64_t input, uint8_t base) { /// @returns A String representation of the integer. String int64ToString(int64_t input, uint8_t base) { if (input < 0) { - return "-" + uint64ToString(-input, base); + // Using String(kDashStr) to keep compatible with old arduino + // frameworks. Not needed with 3.0.2. + ///> @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1639#issuecomment-944906016 + return String(kDashStr) + uint64ToString(-input, base); } return uint64ToString(input, base); } @@ -93,21 +117,20 @@ void serialPrintUint64(uint64_t input, uint8_t base) { /// @param[in] str A C-style string containing a protocol name or number. /// @return A decode_type_t enum. (decode_type_t::UNKNOWN if no match.) decode_type_t strToDecodeType(const char * const str) { - const char *ptr = kAllProtocolNamesStr; - uint16_t length = strlen(ptr); + auto *ptr = reinterpret_cast(kAllProtocolNamesStr); + uint16_t length = STRLEN(ptr); for (uint16_t i = 0; length; i++) { - if (!strcasecmp(str, ptr)) return (decode_type_t)i; + if (!STRCASECMP(str, ptr)) return (decode_type_t)i; ptr += length + 1; - length = strlen(ptr); + length = STRLEN(ptr); } - // Handle integer values of the type by converting to a string and back again. decode_type_t result = strToDecodeType( typeToString((decode_type_t)atoi(str)).c_str()); if (result > 0) return result; - else - return decode_type_t::UNKNOWN; + + return decode_type_t::UNKNOWN; } /// Convert a protocol type (enum etc) to a human readable string. @@ -117,16 +140,20 @@ decode_type_t strToDecodeType(const char * const str) { String typeToString(const decode_type_t protocol, const bool isRepeat) { String result = ""; result.reserve(30); // Size of longest protocol name + " (Repeat)" - const char *ptr = kAllProtocolNamesStr; if (protocol > kLastDecodeType || protocol == decode_type_t::UNKNOWN) { result = kUnknownStr; } else { - for (uint16_t i = 0; i <= protocol && strlen(ptr); i++) { - if (i == protocol) { - result = ptr; - break; + auto *ptr = reinterpret_cast(kAllProtocolNamesStr); + if (protocol > kLastDecodeType || protocol == decode_type_t::UNKNOWN) { + result = kUnknownStr; + } else { + for (uint16_t i = 0; i <= protocol && STRLEN(ptr); i++) { + if (i == protocol) { + result = FPSTR(ptr); + break; + } + ptr += STRLEN(ptr) + 1; } - ptr += strlen(ptr) + 1; } } if (isRepeat) { @@ -175,6 +202,7 @@ bool hasACState(const decode_type_t protocol) { case MWM: case NEOCLIMA: case PANASONIC_AC: + case RHOSS: case SAMSUNG_AC: case SANYO_AC: case SANYO_AC88: @@ -318,7 +346,7 @@ String resultToTimingInfo(const decode_results * const results) { for (uint16_t i = 1; i < results->rawlen; i++) { if (i % 2 == 0) - output += '-'; // even + output += kDashStr; // even else output += F(" +"); // odd value = uint64ToString(results->rawbuf[i] * kRawTick); @@ -515,7 +543,18 @@ namespace irutils { /// @return The resulting String. String addBoolToString(const bool value, const String label, const bool precomma) { - return addLabeledString((value ? kOnStr : kOffStr), label, precomma); + return addLabeledString(value ? kOnStr : kOffStr, label, precomma); + } + + /// Create a String with a colon separated toggle flag suitable for Humans. + /// e.g. "Light: Toggle", "Light: -" + /// @param[in] toggle The value of the toggle to come after the label. + /// @param[in] label The label to precede the value. + /// @param[in] precomma Should the output string start with ", " or not? + /// @return The resulting String. + String addToggleToString(const bool toggle, const String label, + const bool precomma) { + return addLabeledString(toggle ? kToggleStr : kDashStr, label, precomma); } /// Create a String with a colon separated labeled Integer suitable for @@ -547,75 +586,101 @@ namespace irutils { /// @param[in] protocol The IR protocol. /// @param[in] model The model number for that protocol. /// @return The resulting String. + /// @note After adding a new model you should update IRac::strToModel() too. String modelToStr(const decode_type_t protocol, const int16_t model) { switch (protocol) { case decode_type_t::FUJITSU_AC: switch (model) { - case fujitsu_ac_remote_model_t::ARRAH2E: return F("ARRAH2E"); - case fujitsu_ac_remote_model_t::ARDB1: return F("ARDB1"); - case fujitsu_ac_remote_model_t::ARREB1E: return F("ARREB1E"); - case fujitsu_ac_remote_model_t::ARJW2: return F("ARJW2"); - case fujitsu_ac_remote_model_t::ARRY4: return F("ARRY4"); - case fujitsu_ac_remote_model_t::ARREW4E: return F("ARREW4E"); - default: return kUnknownStr; + case fujitsu_ac_remote_model_t::ARRAH2E: return kArrah2eStr; + case fujitsu_ac_remote_model_t::ARDB1: return kArdb1Str; + case fujitsu_ac_remote_model_t::ARREB1E: return kArreb1eStr; + case fujitsu_ac_remote_model_t::ARJW2: return kArjw2Str; + case fujitsu_ac_remote_model_t::ARRY4: return kArry4Str; + case fujitsu_ac_remote_model_t::ARREW4E: return kArrew4eStr; + default: return kUnknownStr; } break; case decode_type_t::GREE: switch (model) { - case gree_ac_remote_model_t::YAW1F: return F("YAW1F"); - case gree_ac_remote_model_t::YBOFB: return F("YBOFB"); - default: return kUnknownStr; + case gree_ac_remote_model_t::YAW1F: return kYaw1fStr; + case gree_ac_remote_model_t::YBOFB: return kYbofbStr; + default: return kUnknownStr; + } + break; + case decode_type_t::HAIER_AC176: + switch (model) { + case haier_ac176_remote_model_t::V9014557_A: + return kV9014557AStr; + case haier_ac176_remote_model_t::V9014557_B: + return kV9014557BStr; + default: + return kUnknownStr; } break; case decode_type_t::HITACHI_AC1: switch (model) { case hitachi_ac1_remote_model_t::R_LT0541_HTA_A: - return F("R-LT0541-HTA-A"); + return kRlt0541htaaStr; case hitachi_ac1_remote_model_t::R_LT0541_HTA_B: - return F("R-LT0541-HTA-B"); - default: return kUnknownStr; + return kRlt0541htabStr; + default: + return kUnknownStr; } break; case decode_type_t::LG: case decode_type_t::LG2: switch (model) { - case lg_ac_remote_model_t::GE6711AR2853M: return F("GE6711AR2853M"); - case lg_ac_remote_model_t::AKB75215403: return F("AKB75215403"); - case lg_ac_remote_model_t::AKB74955603: return F("AKB74955603"); - case lg_ac_remote_model_t::AKB73757604: return F("AKB73757604"); - default: return kUnknownStr; + case lg_ac_remote_model_t::GE6711AR2853M: return kGe6711ar2853mStr; + case lg_ac_remote_model_t::AKB75215403: return kAkb75215403Str; + case lg_ac_remote_model_t::AKB74955603: return kAkb74955603Str; + case lg_ac_remote_model_t::AKB73757604: return kAkb73757604Str; + default: return kUnknownStr; } break; - case decode_type_t::SHARP_AC: + case decode_type_t::MIRAGE: switch (model) { - case sharp_ac_remote_model_t::A907: return F("A907"); - case sharp_ac_remote_model_t::A705: return F("A705"); - case sharp_ac_remote_model_t::A903: return F("A903"); - default: return kUnknownStr; + case mirage_ac_remote_model_t::KKG9AC1: return kKkg9ac1Str; + case mirage_ac_remote_model_t::KKG29AC1: return kKkg29ac1Str; + default: return kUnknownStr; } break; case decode_type_t::PANASONIC_AC: switch (model) { - case panasonic_ac_remote_model_t::kPanasonicLke: return F("LKE"); - case panasonic_ac_remote_model_t::kPanasonicNke: return F("NKE"); - case panasonic_ac_remote_model_t::kPanasonicDke: return F("DKE"); - case panasonic_ac_remote_model_t::kPanasonicJke: return F("JKE"); - case panasonic_ac_remote_model_t::kPanasonicCkp: return F("CKP"); - case panasonic_ac_remote_model_t::kPanasonicRkr: return F("RKR"); - default: return kUnknownStr; + case panasonic_ac_remote_model_t::kPanasonicLke: return kLkeStr; + case panasonic_ac_remote_model_t::kPanasonicNke: return kNkeStr; + case panasonic_ac_remote_model_t::kPanasonicDke: return kDkeStr; + case panasonic_ac_remote_model_t::kPanasonicJke: return kJkeStr; + case panasonic_ac_remote_model_t::kPanasonicCkp: return kCkpStr; + case panasonic_ac_remote_model_t::kPanasonicRkr: return kRkrStr; + default: return kUnknownStr; + } + break; + case decode_type_t::SHARP_AC: + switch (model) { + case sharp_ac_remote_model_t::A907: return kA907Str; + case sharp_ac_remote_model_t::A705: return kA705Str; + case sharp_ac_remote_model_t::A903: return kA903Str; + default: return kUnknownStr; + } + break; + case decode_type_t::TCL112AC: + switch (model) { + case tcl_ac_remote_model_t::TAC09CHSD: return kTac09chsdStr; + case tcl_ac_remote_model_t::GZ055BE1: return kGz055be1Str; + default: return kUnknownStr; } break; case decode_type_t::VOLTAS: switch (model) { - case voltas_ac_remote_model_t::kVoltas122LZF: return F("122LZF"); - default: return kUnknownStr; + case voltas_ac_remote_model_t::kVoltas122LZF: return k122lzfStr; + default: return kUnknownStr; } break; case decode_type_t::WHIRLPOOL_AC: switch (model) { - case whirlpool_ac_remote_model_t::DG11J13A: return F("DG11J13A"); - case whirlpool_ac_remote_model_t::DG11J191: return F("DG11J191"); - default: return kUnknownStr; + case whirlpool_ac_remote_model_t::DG11J13A: return kDg11j13aStr; + case whirlpool_ac_remote_model_t::DG11J191: return kDg11j191Str; + default: return kUnknownStr; } break; default: return kUnknownStr; @@ -690,8 +755,8 @@ namespace irutils { if (mode == automatic) result += kAutoStr; else if (mode == cool) result += kCoolStr; else if (mode == heat) result += kHeatStr; - else if (mode == dry) result += kDryStr; - else if (mode == fan) result += kFanStr; + else if (mode == dry) result += kDryStr; + else if (mode == fan) result += kFanStr; else result += kUnknownStr; return result + ')'; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.h index fdda6d7ae..61fe8b269 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRutils.h @@ -48,6 +48,8 @@ float fahrenheitToCelsius(const float deg); namespace irutils { String addBoolToString(const bool value, const String label, const bool precomma = true); + String addToggleToString(const bool toggle, const String label, + const bool precomma = true); String addIntToString(const uint16_t value, const String label, const bool precomma = true); String addSignedIntToString(const int16_t value, const String label, @@ -97,10 +99,10 @@ namespace irutils { bool getBit(const uint64_t data, const uint8_t position, const uint8_t size = 64); bool getBit(const uint8_t data, const uint8_t position); -#define GETBIT8(a, b) (a & ((uint8_t)1 << b)) -#define GETBIT16(a, b) (a & ((uint16_t)1 << b)) -#define GETBIT32(a, b) (a & ((uint32_t)1 << b)) -#define GETBIT64(a, b) (a & ((uint64_t)1 << b)) +#define GETBIT8(a, b) ((a) & ((uint8_t)1 << (b))) +#define GETBIT16(a, b) ((a) & ((uint16_t)1 << (b))) +#define GETBIT32(a, b) ((a) & ((uint32_t)1 << (b))) +#define GETBIT64(a, b) ((a) & ((uint64_t)1 << (b))) #define GETBITS8(data, offset, size) \ (((data) & (((uint8_t)UINT8_MAX >> (8 - (size))) << (offset))) >> (offset)) #define GETBITS16(data, offset, size) \ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Airton.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Airton.cpp new file mode 100644 index 000000000..507894f37 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Airton.cpp @@ -0,0 +1,70 @@ +// Copyright 2021 David Conran (crankyoldgit) +/// @file +/// @brief Support for Airton protocol +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1670 + +// Supports: +// Brand: Airton, Model: SMVH09B-2A2A3NH ref. 409730 A/C +// Brand: Airton, Model: RD1A1 remote + +#include "IRrecv.h" +#include "IRsend.h" +#include "IRutils.h" + +const uint16_t kAirtonHdrMark = 6630; +const uint16_t kAirtonBitMark = 400; +const uint16_t kAirtonHdrSpace = 3350; +const uint16_t kAirtonOneSpace = 1260; +const uint16_t kAirtonZeroSpace = 430; +const uint16_t kAirtonFreq = 38000; // Hz. (Just a guess) + +#if SEND_AIRTON +// Function should be safe up to 64 bits. +/// Send a Airton formatted message. +/// Status: STABLE / Confirmed working. +/// @param[in] data containing the IR command. +/// @param[in] nbits Nr. of bits to send. usually kAirtonBits +/// @param[in] repeat Nr. of times the message is to be repeated. +void IRsend::sendAirton(const uint64_t data, const uint16_t nbits, + const uint16_t repeat) { + sendGeneric(kAirtonHdrMark, kAirtonHdrSpace, + kAirtonBitMark, kAirtonOneSpace, + kAirtonBitMark, kAirtonZeroSpace, + kAirtonBitMark, kDefaultMessageGap, + data, nbits, kAirtonFreq, false, repeat, kDutyDefault); +} +#endif // SEND_AIRTON + +#if DECODE_AIRTON +/// Decode the supplied Airton message. +/// Status: STABLE / Confirmed working. LSBF ordering confirmed via temperature. +/// @param[in,out] results Ptr to the data to decode & where to store the decode +/// @param[in] offset The starting index to use when attempting to decode the +/// raw data. Typically/Defaults to kStartOffset. +/// @param[in] nbits The number of data bits to expect. +/// @param[in] strict Flag indicating if we should perform strict matching. +/// @return A boolean. True if it can decode it, false if it can't. +bool IRrecv::decodeAirton(decode_results *results, uint16_t offset, + const uint16_t nbits, const bool strict) { + if (results->rawlen < 2 * nbits + kHeader + kFooter - offset) + return false; // Too short a message to match. + if (strict && nbits != kAirtonBits) + return false; + + // Header + Data + Footer + if (!matchGeneric(&(results->rawbuf[offset]), &(results->value), + results->rawlen - offset, nbits, + kAirtonHdrMark, kAirtonHdrSpace, + kAirtonBitMark, kAirtonOneSpace, + kAirtonBitMark, kAirtonZeroSpace, + kAirtonBitMark, kDefaultMessageGap, + true, kUseDefTol, kMarkExcess, false)) return false; + + // Success + results->decode_type = decode_type_t::AIRTON; + results->bits = nbits; + results->command = 0; + results->address = 0; + return true; +} +#endif // DECODE_AIRTON diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Arris.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Arris.cpp new file mode 100644 index 000000000..5b39808c8 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Arris.cpp @@ -0,0 +1,123 @@ +// Copyright 2021 David Conran +#include "IRrecv.h" +#include "IRsend.h" +#include "IRutils.h" + +/// @file +/// @brief Arris "Manchester code" based protocol. +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1595 + +// Supports: +// Brand: Arris, Model: VIP1113M Set-top box +// Brand: Arris, Model: 120A V1.0 A18 remote + +const uint8_t kArrisOverhead = 2; +const uint16_t kArrisHalfClockPeriod = 320; // uSeconds +const uint16_t kArrisHdrMark = 8 * kArrisHalfClockPeriod; // uSeconds +const uint16_t kArrisHdrSpace = 6 * kArrisHalfClockPeriod; // uSeconds +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1595#issuecomment-913755841 +// aka. 77184 uSeconds. +const uint32_t kArrisGapSpace = 102144 - ((8 + 6 + kArrisBits * 2) * + kArrisHalfClockPeriod); // uSeconds +const uint32_t kArrisReleaseToggle = 0x800008; +const uint8_t kArrisChecksumSize = 4; +const uint8_t kArrisCommandSize = 19; +const uint8_t kArrisReleaseBit = kArrisChecksumSize + kArrisCommandSize; + +using irutils::sumNibbles; + +#if SEND_ARRIS +/// Send an Arris Manchester Code formatted message. +/// Status: STABLE / Confirmed working. +/// @param[in] data The message to be sent. +/// @param[in] nbits The number of bits of the message to be sent. +/// @param[in] repeat The number of times the command is to be repeated. +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1595 +void IRsend::sendArris(const uint64_t data, const uint16_t nbits, + const uint16_t repeat) { + enableIROut(38); + for (uint16_t r = 0; r <= repeat; r++) { + // Header (part 1) + mark(kArrisHdrMark); + space(kArrisHdrSpace); + // Header (part 2) + Data + Footer + sendManchester(kArrisHalfClockPeriod * 2, 0, kArrisHalfClockPeriod, + 0, kArrisGapSpace, data, nbits); + } +} + +/// Flip the toggle button release bits of an Arris message. +/// Used to indicate a change of remote button's state. e.g. Press vs. Release. +/// @param[in] data The existing Arris message. +/// @return A data message suitable for use in sendArris() with the release bits +/// flipped. +uint32_t IRsend::toggleArrisRelease(const uint32_t data) { + return data ^ kArrisReleaseToggle; +} + +/// Construct a raw 32-bit Arris message code from the supplied command & +/// release setting. +/// @param[in] command The command code. +/// @param[in] release The button/command action: press (false), release (true) +/// @return A raw 32-bit Arris message code suitable for sendArris() etc. +/// @note Sequence of bits = header + release + command + checksum. +uint32_t IRsend::encodeArris(const uint32_t command, const bool release) { + uint32_t result = 0x10000000; + irutils::setBits(&result, kArrisChecksumSize, kArrisCommandSize, command); + irutils::setBit(&result, kArrisReleaseBit, release); + return result + sumNibbles(result); +} +#endif // SEND_ARRIS + +#if DECODE_ARRIS +/// Decode the supplied Arris "Manchester code" message. +/// Status: STABLE / Confirmed working. +/// @param[in,out] results Ptr to the data to decode & where to store the decode +/// result. +/// @param[in] offset The starting index to use when attempting to decode the +/// raw data. Typically/Defaults to kStartOffset. +/// @param[in] nbits The number of data bits to expect. +/// @param[in] strict Flag indicating if we should perform strict matching. +/// @return A boolean. True if it can decode it, false if it can't. +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1595 +bool IRrecv::decodeArris(decode_results *results, uint16_t offset, + const uint16_t nbits, const bool strict) { + if (results->rawlen < nbits + kArrisOverhead - offset) + return false; // Too short a message to match. + + // Compliance + if (strict && nbits != kArrisBits) + return false; // Doesn't match our protocol defn. + + // Header (part 1) + if (!matchMark(results->rawbuf[offset++], kArrisHdrMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kArrisHdrSpace)) return false; + + // Header (part 2) + Data + uint64_t data = 0; + if (!matchManchester(results->rawbuf + offset, &data, + results->rawlen - offset, nbits, + kArrisHalfClockPeriod * 2, 0, + kArrisHalfClockPeriod, 0, 0, + false, kUseDefTol, kMarkExcess, true, false)) + return false; + + // Compliance + if (strict) + // Validate the checksum. + if (GETBITS32(data, 0, kArrisChecksumSize) != + sumNibbles(data >> kArrisChecksumSize)) + return false; + + // Success + results->decode_type = decode_type_t::ARRIS; + results->bits = nbits; + results->value = data; + // Set the address as the Release Bit for something useful. + results->address = static_cast(GETBIT32(data, kArrisReleaseBit)); + // The last 4 bits are likely a checksum value, so skip those. Everything else + // after the release bit. e.g. Bits 10-28 + results->command = GETBITS32(data, kArrisChecksumSize, kArrisCommandSize); + return true; +} +#endif // DECODE_ARRIS diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.cpp index 1c3a40a62..f5cacf0e7 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Coolix.cpp @@ -611,7 +611,11 @@ String IRCoolixAC::toString(void) const { result += addBoolToString(getZoneFollow(), kZoneFollowStr); result += addLabeledString( (getSensorTemp() == kCoolixSensorTempIgnoreCode) - ? kOffStr : uint64ToString(getSensorTemp()) + 'C', kSensorTempStr); + // Encasing with String(blah) to keep compatible with old arduino + // frameworks. Not needed with 3.0.2. + ///> @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1639#issuecomment-944906016 + ? kOffStr : String(uint64ToString(getSensorTemp()) + 'C'), + kSensorTempStr); return result; } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Electra.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Electra.cpp index fd70e4bd6..b4d670b88 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Electra.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Electra.cpp @@ -1,4 +1,4 @@ -// Copyright 2018, 2019 David Conran +// Copyright 2018-2021 David Conran /// @file /// @brief Support for Electra A/C protocols. /// @see https://github.com/ToniA/arduino-heatpumpir/blob/master/AUXHeatpumpIR.cpp @@ -28,6 +28,7 @@ using irutils::addLabeledString; using irutils::addModeToString; using irutils::addFanToString; using irutils::addTempToString; +using irutils::addToggleToString; #if SEND_ELECTRA_AC /// Send a Electra A/C formatted message. @@ -309,6 +310,52 @@ bool IRElectraAc::getTurbo(void) const { return _.Turbo; } +/// Get the IFeel mode of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRElectraAc::getIFeel(void) const { return _.IFeel; } + +/// Set the IFeel mode of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRElectraAc::setIFeel(const bool on) { + _.IFeel = on; + if (_.IFeel) + // Make sure there is a reasonable value in _.SensorTemp + setSensorTemp(getSensorTemp()); + else + // Clear any previous stored temp.. + _.SensorTemp = kElectraAcSensorMinTemp; +} + +/// Get the silent Sensor Update setting of the message. +/// i.e. Is this _just_ a sensor temp update message from the remote? +/// @note The A/C just takes the sensor temp value from the message and +/// will not follow any of the other settings in the message. +/// @return true, the setting is on. false, the setting is off. +bool IRElectraAc::getSensorUpdate(void) const { return _.SensorUpdate; } + +/// Set the silent Sensor Update setting of the message. +/// i.e. Is this _just_ a sensor temp update message from the remote? +/// @note The A/C will just take the sensor temp value from the message and +/// will not follow any of the other settings in the message. If set, the A/C +/// unit will also not beep in response to the message. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRElectraAc::setSensorUpdate(const bool on) { _.SensorUpdate = on; } + +/// Set the Sensor temperature for the IFeel mode. +/// @param[in] temp The temperature in degrees celsius. +void IRElectraAc::setSensorTemp(const uint8_t temp) { + _.SensorTemp = std::min(kElectraAcSensorMaxTemp, + std::max(kElectraAcSensorMinTemp, temp)) + + kElectraAcSensorTempDelta; +} + +/// Get the current sensor temperature setting for the IFeel mode. +/// @return The current setting for temp. in degrees celsius. +uint8_t IRElectraAc::getSensorTemp(void) const { + return std::max(kElectraAcSensorTempDelta, _.SensorTemp) - + kElectraAcSensorTempDelta; +} + /// Convert the current internal state into its stdAc::state_t equivalent. /// @return The stdAc equivalent of the native settings. stdAc::state_t IRElectraAc::toCommon(void) const { @@ -341,19 +388,26 @@ stdAc::state_t IRElectraAc::toCommon(void) const { /// @return A human readable string. String IRElectraAc::toString(void) const { String result = ""; - result.reserve(130); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(_.Power, kPowerStr, false); - result += addModeToString(_.Mode, kElectraAcAuto, kElectraAcCool, - kElectraAcHeat, kElectraAcDry, kElectraAcFan); - result += addTempToString(getTemp()); - result += addFanToString(_.Fan, kElectraAcFanHigh, kElectraAcFanLow, - kElectraAcFanAuto, kElectraAcFanAuto, - kElectraAcFanMed); - result += addBoolToString(getSwingV(), kSwingVStr); - result += addBoolToString(getSwingH(), kSwingHStr); - result += addLabeledString(getLightToggle() ? kToggleStr : "-", kLightStr); - result += addBoolToString(_.Clean, kCleanStr); - result += addBoolToString(_.Turbo, kTurboStr); + result.reserve(160); // Reserve some heap for the string to reduce fragging. + if (!_.SensorUpdate) { + result += addBoolToString(_.Power, kPowerStr, false); + result += addModeToString(_.Mode, kElectraAcAuto, kElectraAcCool, + kElectraAcHeat, kElectraAcDry, kElectraAcFan); + result += addTempToString(getTemp()); + result += addFanToString(_.Fan, kElectraAcFanHigh, kElectraAcFanLow, + kElectraAcFanAuto, kElectraAcFanAuto, + kElectraAcFanMed); + result += addBoolToString(getSwingV(), kSwingVStr); + result += addBoolToString(getSwingH(), kSwingHStr); + result += addToggleToString(getLightToggle(), kLightStr); + result += addBoolToString(_.Clean, kCleanStr); + result += addBoolToString(_.Turbo, kTurboStr); + result += addBoolToString(_.IFeel, kIFeelStr); + } + if (_.IFeel || _.SensorUpdate) { + result += addIntToString(getSensorTemp(), kSensorTempStr, !_.SensorUpdate); + result += 'C'; + } return result; } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Electra.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Electra.h index 886a92c56..8fd4ee182 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Electra.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Electra.h @@ -1,4 +1,4 @@ -// Copyright 2019 David Conran +// Copyright 2019-2021 David Conran /// @file /// @brief Support for Electra A/C protocols. /// @see https://github.com/ToniA/arduino-heatpumpir/blob/master/AUXHeatpumpIR.cpp @@ -9,6 +9,10 @@ // Brand: Electra, Model: Classic INV 17 / AXW12DCS A/C // Brand: Electra, Model: YKR-M/003E remote // Brand: Frigidaire, Model: FGPC102AB1 A/C +// Brand: Subtropic, Model: SUB-07HN1_18Y A/C +// Brand: Subtropic, Model: YKR-H/102E remote +// Brand: Centek, Model: SCT-65Q09 A/C +// Brand: Centek, Model: YKR-P/002E remote #ifndef IR_ELECTRA_H_ #define IR_ELECTRA_H_ @@ -37,7 +41,9 @@ union ElectraProtocol { uint8_t :5; uint8_t SwingH :3; // Byte 3 - uint8_t :8; + uint8_t :6; + uint8_t SensorUpdate :1; + uint8_t :1; // Byte 4 uint8_t :5; uint8_t Fan :3; @@ -46,10 +52,12 @@ union ElectraProtocol { uint8_t Turbo :1; uint8_t :1; // Byte 6 - uint8_t :5; + uint8_t :3; + uint8_t IFeel :1; + uint8_t :1; uint8_t Mode :3; // Byte 7 - uint8_t :8; + uint8_t SensorTemp :8; // Byte 8 uint8_t :8; // Byte 9 @@ -93,6 +101,11 @@ const uint8_t kElectraAcLightToggleMask = 0x11; // and known OFF values of 0x08 (0b00001000) & 0x05 (0x00000101) const uint8_t kElectraAcLightToggleOff = 0x08; +// Re: Byte[7]. Or Delta == 0xA and Temperature are stored in last 6 bits, +// and bit 7 stores Unknown flag +const uint8_t kElectraAcSensorTempDelta = 0x4A; +const uint8_t kElectraAcSensorMinTemp = 0; // 0C +const uint8_t kElectraAcSensorMaxTemp = 50; // 50C // Classes /// Class for handling detailed Electra A/C messages. @@ -130,6 +143,12 @@ class IRElectraAc { bool getLightToggle(void) const; void setTurbo(const bool on); bool getTurbo(void) const; + void setIFeel(const bool on); + bool getIFeel(void) const; + void setSensorUpdate(const bool on); + bool getSensorUpdate(void) const; + void setSensorTemp(const uint8_t temp); + uint8_t getSensorTemp(void) const; uint8_t* getRaw(void); void setRaw(const uint8_t new_code[], const uint16_t length = kElectraAcStateLength); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Epson.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Epson.cpp index 4f92704bc..a92beef4f 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Epson.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Epson.cpp @@ -6,6 +6,13 @@ // Supports: // Brand: Epson, Model: EN-TW9100W Projector +// Brand: Epson, Model: VS230 Projector +// Brand: Epson, Model: VS330 Projector +// Brand: Epson, Model: EX3220 Projector +// Brand: Epson, Model: EX5220 Projector +// Brand: Epson, Model: EX5230 Projector +// Brand: Epson, Model: EX6220 Projector +// Brand: Epson, Model: EX7220 Projector #define __STDC_LIMIT_MACROS #include diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Goodweather.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Goodweather.cpp index c86797ad5..1d6918e7f 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Goodweather.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Goodweather.cpp @@ -21,6 +21,7 @@ using irutils::addLabeledString; using irutils::addModeToString; using irutils::addFanToString; using irutils::addTempToString; +using irutils::addToggleToString; #if SEND_GOODWEATHER /// Send a Goodweather HVAC formatted message. @@ -346,9 +347,10 @@ String IRGoodweatherAc::toString(void) const { result += addFanToString(_.Fan, kGoodweatherFanHigh, kGoodweatherFanLow, kGoodweatherFanAuto, kGoodweatherFanAuto, kGoodweatherFanMed); - result += addLabeledString(_.Turbo ? kToggleStr : "-", kTurboStr); - result += addLabeledString(_.Light ? kToggleStr : "-", kLightStr); - result += addLabeledString(_.Sleep ? kToggleStr : "-", kSleepStr); + + result += addToggleToString(_.Turbo, kTurboStr); + result += addToggleToString(_.Light, kLightStr); + result += addToggleToString(_.Sleep, kSleepStr); result += addIntToString(_.Swing, kSwingStr); result += kSpaceLBraceStr; switch (_.Swing) { diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.cpp index 1d1371b2d..3c3a8583e 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.cpp @@ -35,6 +35,7 @@ using irutils::addLabeledString; using irutils::addModeToString; using irutils::addModelToString; using irutils::addFanToString; +using irutils::addSwingHToString; using irutils::addTempToString; using irutils::minsToString; @@ -220,15 +221,11 @@ bool IRGreeAC::getPower(void) const { /// Set the default temperature units to use. /// @param[in] on Use Fahrenheit as the units. /// true is Fahrenheit, false is Celsius. -void IRGreeAC::setUseFahrenheit(const bool on) { - _.UseFahrenheit = on; -} +void IRGreeAC::setUseFahrenheit(const bool on) { _.UseFahrenheit = on; } /// Get the default temperature units in use. /// @return true is Fahrenheit, false is Celsius. -bool IRGreeAC::getUseFahrenheit(void) const { - return _.UseFahrenheit; -} +bool IRGreeAC::getUseFahrenheit(void) const { return _.UseFahrenheit; } /// Set the temp. in degrees /// @param[in] temp Desired temperature in Degrees. @@ -281,9 +278,7 @@ void IRGreeAC::setFan(const uint8_t speed) { /// Get the current fan speed setting. /// @return The current fan speed. -uint8_t IRGreeAC::getFan(void) const { - return _.Fan; -} +uint8_t IRGreeAC::getFan(void) const { return _.Fan; } /// Set the operating mode of the A/C. /// @param[in] new_mode The desired operating mode. @@ -305,81 +300,63 @@ void IRGreeAC::setMode(const uint8_t new_mode) { /// Get the operating mode setting of the A/C. /// @return The current operating mode setting. -uint8_t IRGreeAC::getMode(void) const { - return _.Mode; -} +uint8_t IRGreeAC::getMode(void) const { return _.Mode; } /// Set the Light (LED) setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. -void IRGreeAC::setLight(const bool on) { - _.Light = on; -} +void IRGreeAC::setLight(const bool on) { _.Light = on; } /// Get the Light (LED) setting of the A/C. /// @return true, the setting is on. false, the setting is off. -bool IRGreeAC::getLight(void) const { - return _.Light; -} +bool IRGreeAC::getLight(void) const { return _.Light; } /// Set the IFeel setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. -void IRGreeAC::setIFeel(const bool on) { - _.IFeel = on; -} +void IRGreeAC::setIFeel(const bool on) { _.IFeel = on; } /// Get the IFeel setting of the A/C. /// @return true, the setting is on. false, the setting is off. -bool IRGreeAC::getIFeel(void) const { - return _.IFeel; -} +bool IRGreeAC::getIFeel(void) const { return _.IFeel; } /// Set the Wifi (enabled) setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. -void IRGreeAC::setWiFi(const bool on) { - _.WiFi = on; -} +void IRGreeAC::setWiFi(const bool on) { _.WiFi = on; } /// Get the Wifi (enabled) setting of the A/C. /// @return true, the setting is on. false, the setting is off. -bool IRGreeAC::getWiFi(void) const { - return _.WiFi; -} +bool IRGreeAC::getWiFi(void) const { return _.WiFi; } /// Set the XFan (Mould) setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. -void IRGreeAC::setXFan(const bool on) { - _.Xfan = on; -} +void IRGreeAC::setXFan(const bool on) { _.Xfan = on; } /// Get the XFan (Mould) setting of the A/C. /// @return true, the setting is on. false, the setting is off. -bool IRGreeAC::getXFan(void) const { - return _.Xfan; -} +bool IRGreeAC::getXFan(void) const { return _.Xfan; } /// Set the Sleep setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. -void IRGreeAC::setSleep(const bool on) { - _.Sleep = on; -} +void IRGreeAC::setSleep(const bool on) { _.Sleep = on; } /// Get the Sleep setting of the A/C. /// @return true, the setting is on. false, the setting is off. -bool IRGreeAC::getSleep(void) const { - return _.Sleep; -} +bool IRGreeAC::getSleep(void) const { return _.Sleep; } /// Set the Turbo setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. -void IRGreeAC::setTurbo(const bool on) { - _.Turbo = on; -} +void IRGreeAC::setTurbo(const bool on) { _.Turbo = on; } /// Get the Turbo setting of the A/C. /// @return true, the setting is on. false, the setting is off. -bool IRGreeAC::getTurbo(void) const { - return _.Turbo; -} +bool IRGreeAC::getTurbo(void) const { return _.Turbo; } + +/// Set the Econo setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRGreeAC::setEcono(const bool on) { _.Econo = on; } + +/// Get the Econo setting of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRGreeAC::getEcono(void) const { return _.Econo; } /// Set the Vertical Swing mode of the A/C. /// @param[in] automatic Do we use the automatic setting? @@ -409,32 +386,37 @@ void IRGreeAC::setSwingVertical(const bool automatic, const uint8_t position) { new_position = kGreeSwingAuto; } } - _.Swing = new_position; + _.SwingV = new_position; } /// Get the Vertical Swing Automatic mode setting of the A/C. /// @return true, the setting is on. false, the setting is off. -bool IRGreeAC::getSwingVerticalAuto(void) const { - return _.SwingAuto; -} +bool IRGreeAC::getSwingVerticalAuto(void) const { return _.SwingAuto; } /// Get the Vertical Swing position setting of the A/C. /// @return The native position/mode. -uint8_t IRGreeAC::getSwingVerticalPosition(void) const { - return _.Swing; +uint8_t IRGreeAC::getSwingVerticalPosition(void) const { return _.SwingV; } + +/// Get the Horizontal Swing position setting of the A/C. +/// @return The native position/mode. +uint8_t IRGreeAC::getSwingHorizontal(void) const { return _.SwingH; } + +/// Set the Horizontal Swing mode of the A/C. +/// @param[in] position The position/mode to set the vanes to. +void IRGreeAC::setSwingHorizontal(const uint8_t position) { + if (position <= kGreeSwingHMaxRight) + _.SwingH = position; + else + _.SwingH = kGreeSwingHOff; } /// Set the timer enable setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. -void IRGreeAC::setTimerEnabled(const bool on) { - _.TimerEnabled = on; -} +void IRGreeAC::setTimerEnabled(const bool on) { _.TimerEnabled = on; } /// Get the timer enabled setting of the A/C. /// @return true, the setting is on. false, the setting is off. -bool IRGreeAC::getTimerEnabled(void) const { - return _.TimerEnabled; -} +bool IRGreeAC::getTimerEnabled(void) const { return _.TimerEnabled; } /// Get the timer time value from the A/C. /// @return The number of minutes the timer is set for. @@ -478,9 +460,7 @@ void IRGreeAC::setDisplayTempSource(const uint8_t mode) { /// Get the temperature display mode. /// i.e. Internal, External temperature sensing. /// @return The current temp source being displayed. -uint8_t IRGreeAC::getDisplayTempSource(void) const { - return _.DisplayTemp; -} +uint8_t IRGreeAC::getDisplayTempSource(void) const { return _.DisplayTemp; } /// Convert a stdAc::opmode_t enum into its native mode. /// @param[in] mode The enum to be converted. @@ -523,6 +503,21 @@ uint8_t IRGreeAC::convertSwingV(const stdAc::swingv_t swingv) { } } +/// Convert a stdAc::swingh_t enum into it's native setting. +/// @param[in] swingh The enum to be converted. +/// @return The native equivalent of the enum. +uint8_t IRGreeAC::convertSwingH(const stdAc::swingh_t swingh) { + switch (swingh) { + case stdAc::swingh_t::kAuto: return kGreeSwingHAuto; + case stdAc::swingh_t::kLeftMax: return kGreeSwingHMaxLeft; + case stdAc::swingh_t::kLeft: return kGreeSwingHLeft; + case stdAc::swingh_t::kMiddle: return kGreeSwingHMiddle; + case stdAc::swingh_t::kRight: return kGreeSwingHRight; + case stdAc::swingh_t::kRightMax: return kGreeSwingHMaxRight; + default: return kGreeSwingHOff; + } +} + /// Convert a native mode into its stdAc equivalent. /// @param[in] mode The native setting to be converted. /// @return The stdAc equivalent of the native setting. @@ -530,9 +525,9 @@ stdAc::opmode_t IRGreeAC::toCommonMode(const uint8_t mode) { switch (mode) { case kGreeCool: return stdAc::opmode_t::kCool; case kGreeHeat: return stdAc::opmode_t::kHeat; - case kGreeDry: return stdAc::opmode_t::kDry; - case kGreeFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kGreeDry: return stdAc::opmode_t::kDry; + case kGreeFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } @@ -541,10 +536,10 @@ stdAc::opmode_t IRGreeAC::toCommonMode(const uint8_t mode) { /// @return The stdAc equivalent of the native setting. stdAc::fanspeed_t IRGreeAC::toCommonFanSpeed(const uint8_t speed) { switch (speed) { - case kGreeFanMax: return stdAc::fanspeed_t::kMax; + case kGreeFanMax: return stdAc::fanspeed_t::kMax; case kGreeFanMax - 1: return stdAc::fanspeed_t::kMedium; - case kGreeFanMin: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + case kGreeFanMin: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; } } @@ -553,12 +548,27 @@ stdAc::fanspeed_t IRGreeAC::toCommonFanSpeed(const uint8_t speed) { /// @return The stdAc equivalent of the native setting. stdAc::swingv_t IRGreeAC::toCommonSwingV(const uint8_t pos) { switch (pos) { - case kGreeSwingUp: return stdAc::swingv_t::kHighest; - case kGreeSwingMiddleUp: return stdAc::swingv_t::kHigh; - case kGreeSwingMiddle: return stdAc::swingv_t::kMiddle; + case kGreeSwingUp: return stdAc::swingv_t::kHighest; + case kGreeSwingMiddleUp: return stdAc::swingv_t::kHigh; + case kGreeSwingMiddle: return stdAc::swingv_t::kMiddle; case kGreeSwingMiddleDown: return stdAc::swingv_t::kLow; - case kGreeSwingDown: return stdAc::swingv_t::kLowest; - default: return stdAc::swingv_t::kAuto; + case kGreeSwingDown: return stdAc::swingv_t::kLowest; + default: return stdAc::swingv_t::kAuto; + } +} + +/// Convert a native Horizontal Swing into its stdAc equivalent. +/// @param[in] pos The native setting to be converted. +/// @return The stdAc equivalent of the native setting. +stdAc::swingh_t IRGreeAC::toCommonSwingH(const uint8_t pos) { + switch (pos) { + case kGreeSwingHAuto: return stdAc::swingh_t::kAuto; + case kGreeSwingHMaxLeft: return stdAc::swingh_t::kLeftMax; + case kGreeSwingHLeft: return stdAc::swingh_t::kLeft; + case kGreeSwingHMiddle: return stdAc::swingh_t::kMiddle; + case kGreeSwingHRight: return stdAc::swingh_t::kRight; + case kGreeSwingHMaxRight: return stdAc::swingh_t::kRightMax; + default: return stdAc::swingh_t::kOff; } } @@ -576,15 +586,15 @@ stdAc::state_t IRGreeAC::toCommon(void) { if (_.SwingAuto) result.swingv = stdAc::swingv_t::kAuto; else - result.swingv = toCommonSwingV(_.Swing); + result.swingv = toCommonSwingV(_.SwingV); + result.swingh = toCommonSwingH(_.SwingH); result.turbo = _.Turbo; + result.econo = _.Econo; result.light = _.Light; result.clean = _.Xfan; result.sleep = _.Sleep ? 0 : -1; // Not supported. - result.swingh = stdAc::swingh_t::kOff; result.quiet = false; - result.econo = false; result.filter = false; result.beep = false; result.clock = -1; @@ -604,6 +614,7 @@ String IRGreeAC::toString(void) { result += addFanToString(_.Fan, kGreeFanMax, kGreeFanMin, kGreeFanAuto, kGreeFanAuto, kGreeFanMed); result += addBoolToString(_.Turbo, kTurboStr); + result += addBoolToString(_.Econo, kEconoStr); result += addBoolToString(_.IFeel, kIFeelStr); result += addBoolToString(_.WiFi, kWifiStr); result += addBoolToString(_.Xfan, kXFanStr); @@ -611,9 +622,9 @@ String IRGreeAC::toString(void) { result += addBoolToString(_.Sleep, kSleepStr); result += addLabeledString(_.SwingAuto ? kAutoStr : kManualStr, kSwingVModeStr); - result += addIntToString(_.Swing, kSwingVStr); + result += addIntToString(_.SwingV, kSwingVStr); result += kSpaceLBraceStr; - switch (_.Swing) { + switch (_.SwingV) { case kGreeSwingLastPos: result += kLastStr; break; @@ -623,6 +634,12 @@ String IRGreeAC::toString(void) { default: result += kUnknownStr; } result += ')'; + result += addSwingHToString(_.SwingH, kGreeSwingHAuto, kGreeSwingHMaxLeft, + kGreeSwingHLeft, kGreeSwingHMiddle, + kGreeSwingHRight, kGreeSwingHMaxRight, + kGreeSwingHOff, + // rest are unused. + 0xFF, 0xFF, 0xFF, 0xFF); result += addLabeledString( _.TimerEnabled ? minsToString(getTimer()) : kOffStr, kTimerStr); uint8_t src = _.DisplayTemp; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.h index 4f89fde5c..be5ac31ce 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Gree.h @@ -14,10 +14,15 @@ // Brand: Green, Model: YBOFB2 remote // Brand: Gree, Model: YAA1FBF remote // Brand: Gree, Model: YB1F2F remote +// Brand: Gree, Model: YAN1F1 remote +// Brand: Gree, Model: VIR09HP115V1AH A/C +// Brand: Gree, Model: VIR12HP230V1AH A/C // Brand: Amana, Model: PBC093G00CC A/C // Brand: Amana, Model: YX1FF remote // Brand: Cooper & Hunter, Model: YB1F2 remote // Brand: Cooper & Hunter, Model: CH-S09FTXG A/C +// Brand: Vailland, Model: YACIFB remote +// Brand: Vailland, Model: VAI5-035WNI A/C #ifndef IR_GREE_H_ #define IR_GREE_H_ @@ -60,19 +65,22 @@ union GreeProtocol{ uint8_t UseFahrenheit :1; uint8_t unknown1 :4; // value=0b0101 // Byte 4 - uint8_t Swing:4; - uint8_t :0; + uint8_t SwingV :4; + uint8_t SwingH :3; + uint8_t :1; // Byte 5 uint8_t DisplayTemp :2; uint8_t IFeel :1; uint8_t unknown2 :3; // value = 0b100 uint8_t WiFi :1; - uint8_t :0; + uint8_t :1; // Byte 6 - uint8_t :8; + uint8_t :8; // Byte 7 - uint8_t :4; - uint8_t Sum:4; + uint8_t :2; + uint8_t Econo :1; + uint8_t :1; + uint8_t Sum :4; }; }; @@ -95,16 +103,24 @@ const uint8_t kGreeMinTempF = 61; // Fahrenheit const uint8_t kGreeMaxTempF = 86; // Fahrenheit const uint16_t kGreeTimerMax = 24 * 60; -const uint8_t kGreeSwingLastPos = 0b0000; -const uint8_t kGreeSwingAuto = 0b0001; -const uint8_t kGreeSwingUp = 0b0010; -const uint8_t kGreeSwingMiddleUp = 0b0011; -const uint8_t kGreeSwingMiddle = 0b0100; -const uint8_t kGreeSwingMiddleDown = 0b0101; -const uint8_t kGreeSwingDown = 0b0110; -const uint8_t kGreeSwingDownAuto = 0b0111; -const uint8_t kGreeSwingMiddleAuto = 0b1001; -const uint8_t kGreeSwingUpAuto = 0b1011; +const uint8_t kGreeSwingLastPos = 0b0000; // 0 +const uint8_t kGreeSwingAuto = 0b0001; // 1 +const uint8_t kGreeSwingUp = 0b0010; // 2 +const uint8_t kGreeSwingMiddleUp = 0b0011; // 3 +const uint8_t kGreeSwingMiddle = 0b0100; // 4 +const uint8_t kGreeSwingMiddleDown = 0b0101; // 5 +const uint8_t kGreeSwingDown = 0b0110; // 6 +const uint8_t kGreeSwingDownAuto = 0b0111; // 7 +const uint8_t kGreeSwingMiddleAuto = 0b1001; // 9 +const uint8_t kGreeSwingUpAuto = 0b1011; // 11 + +const uint8_t kGreeSwingHOff = 0b000; // 0 +const uint8_t kGreeSwingHAuto = 0b001; // 1 +const uint8_t kGreeSwingHMaxLeft = 0b010; // 2 +const uint8_t kGreeSwingHLeft = 0b011; // 3 +const uint8_t kGreeSwingHMiddle = 0b100; // 4 +const uint8_t kGreeSwingHRight = 0b101; // 5 +const uint8_t kGreeSwingHMaxRight = 0b110; // 6 const uint8_t kGreeDisplayTempOff = 0b00; // 0 const uint8_t kGreeDisplayTempSet = 0b01; // 1 @@ -171,6 +187,8 @@ class IRGreeAC { bool getSleep(void) const; void setTurbo(const bool on); bool getTurbo(void) const; + void setEcono(const bool on); + bool getEcono(void) const; void setIFeel(const bool on); bool getIFeel(void) const; void setWiFi(const bool on); @@ -178,6 +196,8 @@ class IRGreeAC { void setSwingVertical(const bool automatic, const uint8_t position); bool getSwingVerticalAuto(void) const; uint8_t getSwingVerticalPosition(void) const; + void setSwingHorizontal(const uint8_t position); + uint8_t getSwingHorizontal(void) const; uint16_t getTimer(void) const; void setTimer(const uint16_t minutes); void setDisplayTempSource(const uint8_t mode); @@ -185,9 +205,11 @@ class IRGreeAC { static uint8_t convertMode(const stdAc::opmode_t mode); static uint8_t convertFan(const stdAc::fanspeed_t speed); static uint8_t convertSwingV(const stdAc::swingv_t swingv); + static uint8_t convertSwingH(const stdAc::swingh_t swingh); static stdAc::opmode_t toCommonMode(const uint8_t mode); static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed); static stdAc::swingv_t toCommonSwingV(const uint8_t pos); + static stdAc::swingh_t toCommonSwingH(const uint8_t pos); stdAc::state_t toCommon(void); uint8_t* getRaw(void); void setRaw(const uint8_t new_code[]); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.cpp index a43e9400d..5c9f2a36d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.cpp @@ -32,6 +32,8 @@ using irutils::addBoolToString; using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; +using irutils::addModelToString; +using irutils::addSwingHToString; using irutils::addFanToString; using irutils::addTempToString; using irutils::minsToString; @@ -322,22 +324,22 @@ void IRHaierAC::setCurrTime(const uint16_t nr_mins) { } /// Get the Vertical Swing position setting of the A/C. -/// @return The native swing mode. -uint8_t IRHaierAC::getSwing(void) const { - return _.Swing; +/// @return The native vertical swing mode. +uint8_t IRHaierAC::getSwingV(void) const { + return _.SwingV; } /// Set the Vertical Swing mode of the A/C. /// @param[in] state The mode to set the vanes to. -void IRHaierAC::setSwing(const uint8_t state) { - if (state == _.Swing) return; // Nothing to do. +void IRHaierAC::setSwingV(const uint8_t state) { + if (state == _.SwingV) return; // Nothing to do. switch (state) { - case kHaierAcSwingOff: - case kHaierAcSwingUp: - case kHaierAcSwingDown: - case kHaierAcSwingChg: + case kHaierAcSwingVOff: + case kHaierAcSwingVUp: + case kHaierAcSwingVDown: + case kHaierAcSwingVChg: _.Command = kHaierAcCmdSwing; - _.Swing = state; + _.SwingV = state; break; } } @@ -376,11 +378,11 @@ uint8_t IRHaierAC::convertSwingV(const stdAc::swingv_t position) { switch (position) { case stdAc::swingv_t::kHighest: case stdAc::swingv_t::kHigh: - case stdAc::swingv_t::kMiddle: return kHaierAcSwingUp; + case stdAc::swingv_t::kMiddle: return kHaierAcSwingVUp; case stdAc::swingv_t::kLow: - case stdAc::swingv_t::kLowest: return kHaierAcSwingDown; - case stdAc::swingv_t::kOff: return kHaierAcSwingOff; - default: return kHaierAcSwingChg; + case stdAc::swingv_t::kLowest: return kHaierAcSwingVDown; + case stdAc::swingv_t::kOff: return kHaierAcSwingVOff; + default: return kHaierAcSwingVChg; } } @@ -414,10 +416,10 @@ stdAc::fanspeed_t IRHaierAC::toCommonFanSpeed(const uint8_t speed) { /// @return The native equivalent of the enum. stdAc::swingv_t IRHaierAC::toCommonSwingV(const uint8_t pos) { switch (pos) { - case kHaierAcSwingUp: return stdAc::swingv_t::kHighest; - case kHaierAcSwingDown: return stdAc::swingv_t::kLowest; - case kHaierAcSwingOff: return stdAc::swingv_t::kOff; - default: return stdAc::swingv_t::kAuto; + case kHaierAcSwingVUp: return stdAc::swingv_t::kHighest; + case kHaierAcSwingVDown: return stdAc::swingv_t::kLowest; + case kHaierAcSwingVOff: return stdAc::swingv_t::kOff; + default: return stdAc::swingv_t::kAuto; } } @@ -433,7 +435,7 @@ stdAc::state_t IRHaierAC::toCommon(void) const { result.celsius = true; result.degrees = getTemp(); result.fanspeed = toCommonFanSpeed(getFan()); - result.swingv = toCommonSwingV(_.Swing); + result.swingv = toCommonSwingV(_.SwingV); result.filter = _.Health; result.sleep = _.Sleep ? 0 : -1; // Not supported. @@ -443,7 +445,7 @@ stdAc::state_t IRHaierAC::toCommon(void) const { result.econo = false; result.light = false; result.clean = false; - result.beep = false; + result.beep = true; result.clock = -1; return result; } @@ -452,7 +454,7 @@ stdAc::state_t IRHaierAC::toCommon(void) const { /// @return A human readable string. String IRHaierAC::toString(void) const { String result = ""; - result.reserve(150); // Reserve some heap for the string to reduce fragging. + result.reserve(170); // Reserve some heap for the string to reduce fragging. uint8_t cmd = _.Command; result += addIntToString(cmd, kCommandStr, false); result += kSpaceLBraceStr; @@ -492,7 +494,7 @@ String IRHaierAC::toString(void) const { result += kHealthStr; break; case kHaierAcCmdSwing: - result += kSwingStr; + result += kSwingVStr; break; default: result += kUnknownStr; @@ -503,19 +505,19 @@ String IRHaierAC::toString(void) const { result += addTempToString(getTemp()); result += addFanToString(getFan(), kHaierAcFanHigh, kHaierAcFanLow, kHaierAcFanAuto, kHaierAcFanAuto, kHaierAcFanMed); - result += addIntToString(_.Swing, kSwingStr); + result += addIntToString(_.SwingV, kSwingVStr); result += kSpaceLBraceStr; - switch (_.Swing) { - case kHaierAcSwingOff: + switch (_.SwingV) { + case kHaierAcSwingVOff: result += kOffStr; break; - case kHaierAcSwingUp: + case kHaierAcSwingVUp: result += kUpStr; break; - case kHaierAcSwingDown: + case kHaierAcSwingVDown: result += kDownStr; break; - case kHaierAcSwingChg: + case kHaierAcSwingVChg: result += kChangeStr; break; default: @@ -581,9 +583,9 @@ bool IRHaierAC176::validChecksum(const uint8_t state[], const uint16_t length) { /// Reset the internal state to a fixed known good state. void IRHaierAC176::stateReset(void) { std::memset(_.raw, 0, sizeof _.raw); - _.Prefix = kHaierAcYrw02Prefix; + _.Model = kHaierAcYrw02ModelA; _.Prefix2 = kHaierAc176Prefix; - _.Temp = kHaierAcDefTemp - kHaierAcMinTemp; + _.Temp = kHaierAcYrw02DefTempC - kHaierAcYrw02MinTempC; _.Health = true; setFan(kHaierAcYrw02FanAuto); _.Power = true; @@ -609,17 +611,42 @@ void IRHaierAC176::setButton(uint8_t button) { switch (button) { case kHaierAcYrw02ButtonTempUp: case kHaierAcYrw02ButtonTempDown: - case kHaierAcYrw02ButtonSwing: + case kHaierAcYrw02ButtonSwingV: + case kHaierAcYrw02ButtonSwingH: case kHaierAcYrw02ButtonFan: case kHaierAcYrw02ButtonPower: case kHaierAcYrw02ButtonMode: case kHaierAcYrw02ButtonHealth: case kHaierAcYrw02ButtonTurbo: case kHaierAcYrw02ButtonSleep: + case kHaierAcYrw02ButtonLock: + case kHaierAcYrw02ButtonCFAB: _.Button = button; } } +/// Get/Detect the model of the A/C. +/// @return The enum of the compatible model. +haier_ac176_remote_model_t IRHaierAC176::getModel(void) const { + switch (_.Model) { + case kHaierAcYrw02ModelB: return haier_ac176_remote_model_t::V9014557_B; + default: return haier_ac176_remote_model_t::V9014557_A; + } +} + +/// Set the model of the A/C to emulate. +/// @param[in] model The enum of the appropriate model. +void IRHaierAC176::setModel(haier_ac176_remote_model_t model) { + _.Button = kHaierAcYrw02ButtonCFAB; + switch (model) { + case haier_ac176_remote_model_t::V9014557_B: + _.Model = kHaierAcYrw02ModelB; + break; + default: + _.Model = kHaierAcYrw02ModelA; + } +} + /// Get the Button/Command setting of the A/C. /// @return The value of the button/command that was pressed. uint8_t IRHaierAC176::getButton(void) const { @@ -629,47 +656,118 @@ uint8_t IRHaierAC176::getButton(void) const { /// Set the operating mode of the A/C. /// @param[in] mode The desired operating mode. void IRHaierAC176::setMode(uint8_t mode) { - uint8_t new_mode = mode; - _.Button = kHaierAcYrw02ButtonMode; switch (mode) { case kHaierAcYrw02Auto: - case kHaierAcYrw02Cool: case kHaierAcYrw02Dry: + case kHaierAcYrw02Fan: + // Turbo & Quiet is only available in Cool/Heat mode. + _.Turbo = false; + _.Quiet = false; + // FALL-THRU + case kHaierAcYrw02Cool: case kHaierAcYrw02Heat: - case kHaierAcYrw02Fan: break; - default: new_mode = kHaierAcYrw02Auto; // Unexpected, default to auto mode. + _.Button = kHaierAcYrw02ButtonMode; + _.Mode = mode; + break; + default: + setMode(kHaierAcYrw02Auto); // Unexpected, default to auto mode. } - _.Mode = new_mode; } /// Get the operating mode setting of the A/C. /// @return The current operating mode setting. -uint8_t IRHaierAC176::getMode(void) const { - return _.Mode; -} +uint8_t IRHaierAC176::getMode(void) const { return _.Mode; } + +/// Set the default temperature units to use. +/// @param[in] on Use Fahrenheit as the units. +/// true is Fahrenheit, false is Celsius. +void IRHaierAC176::setUseFahrenheit(const bool on) { _.UseFahrenheit = on; } + +/// Get the default temperature units in use. +/// @return true is Fahrenheit, false is Celsius. +bool IRHaierAC176::getUseFahrenheit(void) const { return _.UseFahrenheit; } /// Set the temperature. -/// @param[in] celsius The temperature in degrees celsius. -void IRHaierAC176::setTemp(const uint8_t celsius) { - uint8_t temp = celsius; - if (temp < kHaierAcMinTemp) - temp = kHaierAcMinTemp; - else if (temp > kHaierAcMaxTemp) - temp = kHaierAcMaxTemp; - +/// @param[in] degree The temperature in degrees. +/// @param[in] fahrenheit Use units of Fahrenheit and set that as units used. +void IRHaierAC176::setTemp(const uint8_t degree, const bool fahrenheit) { uint8_t old_temp = getTemp(); - if (old_temp == temp) return; - if (old_temp > temp) - _.Button = kHaierAcYrw02ButtonTempDown; - else - _.Button = kHaierAcYrw02ButtonTempUp; - _.Temp = temp - kHaierAcMinTemp; + if (old_temp == degree) return; + + if (_.UseFahrenheit == fahrenheit) { + if (old_temp > degree) + _.Button = kHaierAcYrw02ButtonTempDown; + else + _.Button = kHaierAcYrw02ButtonTempUp; + } else { + _.Button = kHaierAcYrw02ButtonCFAB; + } + _.UseFahrenheit = fahrenheit; + + uint8_t temp = degree; + if (fahrenheit) { + if (temp < kHaierAcYrw02MinTempF) + temp = kHaierAcYrw02MinTempF; + else if (temp > kHaierAcYrw02MaxTempF) + temp = kHaierAcYrw02MaxTempF; + if (degree >= 77) { temp++; } + if (degree >= 79) { temp++; } + // See at IRHaierAC176::getTemp() comments for clarification + _.ExtraDegreeF = temp % 2; + _.Temp = (temp - kHaierAcYrw02MinTempF -_.ExtraDegreeF) >> 1; + } else { + if (temp < kHaierAcYrw02MinTempC) + temp = kHaierAcYrw02MinTempC; + else if (temp > kHaierAcYrw02MaxTempC) + temp = kHaierAcYrw02MaxTempC; + _.Temp = temp - kHaierAcYrw02MinTempC; + } } /// Get the current temperature setting. -/// @return The current setting for temp. in degrees celsius. +/// The unit of temperature is specified by UseFahrenheit value. +/// @return The current setting for temperature. uint8_t IRHaierAC176::getTemp(void) const { - return _.Temp + kHaierAcMinTemp; + if (!_.UseFahrenheit) { return _.Temp + kHaierAcYrw02MinTempC; } + uint8_t degree = _.Temp*2 + kHaierAcYrw02MinTempF + _.ExtraDegreeF; + // The way of coding the temperature in degree Fahrenheit is + // kHaierAcYrw02MinTempF + Temp*2 + ExtraDegreeF, for example + // Temp = 0b0011, ExtraDegreeF = 0b1, temperature is 60 + 3*2 + 1 = 67F + // But around 78F there is unconsistency, see table below + // + // | Fahrenheit | Temp | ExtraDegreeF | + // | 60F | 0b0000 | 0b0 | + // | 61F | 0b0000 | 0b1 | + // | 62F | 0b0001 | 0b0 | + // | 63F | 0b0001 | 0b1 | + // | 64F | 0b0010 | 0b0 | + // | 65F | 0b0010 | 0b1 | + // | 66F | 0b0011 | 0b0 | + // | 67F | 0b0011 | 0b1 | + // | 68F | 0b0100 | 0b0 | + // | 69F | 0b0100 | 0b1 | + // | 70F | 0b0101 | 0b0 | + // | 71F | 0b0101 | 0b1 | + // | 72F | 0b0110 | 0b0 | + // | 73F | 0b0110 | 0b1 | + // | 74F | 0b0111 | 0b0 | + // | 75F | 0b0111 | 0b1 | + // | 76F | 0b1000 | 0b0 | + // | Not Used | 0b1000 | 0b1 | + // | 77F | 0b1001 | 0b0 | + // | Not Used | 0b1001 | 0b1 | + // | 78F | 0b1010 | 0b0 | + // | 79F | 0b1010 | 0b1 | + // | 80F | 0b1011 | 0b0 | + // | 81F | 0b1011 | 0b1 | + // | 82F | 0b1100 | 0b0 | + // | 83F | 0b1100 | 0b1 | + // | 84F | 0b1101 | 0b0 | + // | 86F | 0b1110 | 0b0 | + // | 85F | 0b1101 | 0b1 | + if (degree >= 77) { degree--; } + if (degree >= 79) { degree--; } + return degree; } /// Set the Health (filter) setting of the A/C. @@ -681,15 +779,11 @@ void IRHaierAC176::setHealth(const bool on) { /// Get the Health (filter) setting of the A/C. /// @return true, the setting is on. false, the setting is off. -bool IRHaierAC176::getHealth(void) const { - return _.Health; -} +bool IRHaierAC176::getHealth(void) const { return _.Health; } /// Get the value of the current power setting. /// @return true, the setting is on. false, the setting is off. -bool IRHaierAC176::getPower(void) const { - return _.Power; -} +bool IRHaierAC176::getPower(void) const { return _.Power; } /// Change the power setting. /// @param[in] on true, the setting is on. false, the setting is off. @@ -706,9 +800,7 @@ void IRHaierAC176::off(void) { setPower(false); } /// Get the Sleep setting of the A/C. /// @return true, the setting is on. false, the setting is off. -bool IRHaierAC176::getSleep(void) const { - return _.Sleep; -} +bool IRHaierAC176::getSleep(void) const { return _.Sleep; } /// Set the Sleep setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. @@ -718,30 +810,42 @@ void IRHaierAC176::setSleep(const bool on) { } /// Get the Turbo setting of the A/C. -/// @return The current turbo speed setting. -uint8_t IRHaierAC176::getTurbo(void) const { - return _.Turbo; -} +/// @return The current turbo setting. +bool IRHaierAC176::getTurbo(void) const { return _.Turbo; } /// Set the Turbo setting of the A/C. -/// @param[in] speed The desired turbo speed setting. -/// @note Valid speeds are kHaierAcYrw02TurboOff, kHaierAcYrw02TurboLow, & -/// kHaierAcYrw02TurboHigh. -void IRHaierAC176::setTurbo(uint8_t speed) { - switch (speed) { - case kHaierAcYrw02TurboOff: - case kHaierAcYrw02TurboLow: - case kHaierAcYrw02TurboHigh: - _.Turbo = speed; +/// @param[in] on The desired turbo setting. +/// @note Turbo & Quiet can't be on at the same time, and only in Heat/Cool mode +void IRHaierAC176::setTurbo(const bool on) { + switch (getMode()) { + case kHaierAcYrw02Cool: + case kHaierAcYrw02Heat: + _.Turbo = on; _.Button = kHaierAcYrw02ButtonTurbo; + if (on) _.Quiet = false; + } +} + +/// Get the Quiet setting of the A/C. +/// @return The current Quiet setting. +bool IRHaierAC176::getQuiet(void) const { return _.Quiet; } + +/// Set the Quiet setting of the A/C. +/// @param[in] on The desired Quiet setting. +/// @note Turbo & Quiet can't be on at the same time, and only in Heat/Cool mode +void IRHaierAC176::setQuiet(const bool on) { + switch (getMode()) { + case kHaierAcYrw02Cool: + case kHaierAcYrw02Heat: + _.Quiet = on; + _.Button = kHaierAcYrw02ButtonTurbo; + if (on) _.Turbo = false; } } /// Get the current fan speed setting. /// @return The current fan speed. -uint8_t IRHaierAC176::getFan(void) const { - return _.Fan; -} +uint8_t IRHaierAC176::getFan(void) const { return _.Fan; } /// Set the speed of the fan. /// @param[in] speed The desired setting. @@ -757,30 +861,61 @@ void IRHaierAC176::setFan(uint8_t speed) { } } +/// For backward compatibility. Use getSwingV() instead. /// Get the Vertical Swing position setting of the A/C. /// @return The native position/mode. -uint8_t IRHaierAC176::getSwing(void) const { return _.Swing; } +uint8_t IRHaierAC176::getSwing(void) const { + return IRHaierAC176::getSwingV(); +} + +/// For backward compatibility. Use setSwingV() instead. +/// Set the Vertical Swing mode of the A/C. +/// @param[in] pos The position/mode to set the vanes to. +void IRHaierAC176::setSwing(uint8_t pos) { setSwingV(pos); } + +/// Get the Vertical Swing position setting of the A/C. +/// @return The native position/mode. +uint8_t IRHaierAC176::getSwingV(void) const { return _.SwingV; } /// Set the Vertical Swing mode of the A/C. /// @param[in] pos The position/mode to set the vanes to. -void IRHaierAC176::setSwing(uint8_t pos) { +void IRHaierAC176::setSwingV(uint8_t pos) { uint8_t newpos = pos; switch (pos) { - case kHaierAcYrw02SwingOff: - case kHaierAcYrw02SwingAuto: - case kHaierAcYrw02SwingTop: - case kHaierAcYrw02SwingMiddle: - case kHaierAcYrw02SwingBottom: - case kHaierAcYrw02SwingDown: _.Button = kHaierAcYrw02ButtonSwing; break; + case kHaierAcYrw02SwingVOff: + case kHaierAcYrw02SwingVAuto: + case kHaierAcYrw02SwingVTop: + case kHaierAcYrw02SwingVMiddle: + case kHaierAcYrw02SwingVBottom: + case kHaierAcYrw02SwingVDown: _.Button = kHaierAcYrw02ButtonSwingV; break; default: return; // Unexpected value so don't do anything. } // Heat mode has no MIDDLE setting, use BOTTOM instead. - if (pos == kHaierAcYrw02SwingMiddle && _.Mode == kHaierAcYrw02Heat) - newpos = kHaierAcYrw02SwingBottom; + if (pos == kHaierAcYrw02SwingVMiddle && _.Mode == kHaierAcYrw02Heat) + newpos = kHaierAcYrw02SwingVBottom; // BOTTOM is only allowed if we are in Heat mode, otherwise MIDDLE. - if (pos == kHaierAcYrw02SwingBottom && _.Mode != kHaierAcYrw02Heat) - newpos = kHaierAcYrw02SwingMiddle; - _.Swing = newpos; + if (pos == kHaierAcYrw02SwingVBottom && _.Mode != kHaierAcYrw02Heat) + newpos = kHaierAcYrw02SwingVMiddle; + _.SwingV = newpos; +} + +/// Get the Horizontal Swing position setting of the A/C. +/// @return The native position/mode. +uint8_t IRHaierAC176::getSwingH(void) const { return _.SwingH; } + +/// Set the Horizontal Swing mode of the A/C. +/// @param[in] pos The position/mode to set the vanes to. +void IRHaierAC176::setSwingH(uint8_t pos) { + switch (pos) { + case kHaierAcYrw02SwingHMiddle: + case kHaierAcYrw02SwingHLeftMax: + case kHaierAcYrw02SwingHLeft: + case kHaierAcYrw02SwingHRight: + case kHaierAcYrw02SwingHRightMax: + case kHaierAcYrw02SwingHAuto: _.Button = kHaierAcYrw02ButtonSwingH; break; + default: return; // Unexpected value so don't do anything. + } + _.SwingH = pos; } @@ -867,6 +1002,17 @@ uint16_t IRHaierAC176::getOffTimer(void) const { return _.OffTimerHrs * 60 + _.OffTimerMins; } +/// Get the Lock setting of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRHaierAC176::getLock(void) const { return _.Lock; } + +/// Set the Lock setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRHaierAC176::setLock(const bool on) { + _.Button = kHaierAcYrw02ButtonLock; + _.Lock = on; +} + /// Convert a stdAc::opmode_t enum into its native mode. /// @param[in] mode The enum to be converted. /// @return The native equivalent of the enum. @@ -900,12 +1046,27 @@ uint8_t IRHaierAC176::convertFan(const stdAc::fanspeed_t speed) { uint8_t IRHaierAC176::convertSwingV(const stdAc::swingv_t position) { switch (position) { case stdAc::swingv_t::kHighest: - case stdAc::swingv_t::kHigh: return kHaierAcYrw02SwingTop; - case stdAc::swingv_t::kMiddle: return kHaierAcYrw02SwingMiddle; - case stdAc::swingv_t::kLow: return kHaierAcYrw02SwingDown; - case stdAc::swingv_t::kLowest: return kHaierAcYrw02SwingBottom; - case stdAc::swingv_t::kOff: return kHaierAcYrw02SwingOff; - default: return kHaierAcYrw02SwingAuto; + case stdAc::swingv_t::kHigh: return kHaierAcYrw02SwingVTop; + case stdAc::swingv_t::kMiddle: return kHaierAcYrw02SwingVMiddle; + case stdAc::swingv_t::kLow: return kHaierAcYrw02SwingVDown; + case stdAc::swingv_t::kLowest: return kHaierAcYrw02SwingVBottom; + case stdAc::swingv_t::kOff: return kHaierAcYrw02SwingVOff; + default: return kHaierAcYrw02SwingVAuto; + } +} + +/// Convert a stdAc::swingh_t enum into it's native setting. +/// @param[in] position The enum to be converted. +/// @return The native equivalent of the enum. +uint8_t IRHaierAC176::convertSwingH(const stdAc::swingh_t position) { + switch (position) { + case stdAc::swingh_t::kMiddle: return kHaierAcYrw02SwingHMiddle; + case stdAc::swingh_t::kLeftMax: return kHaierAcYrw02SwingHLeftMax; + case stdAc::swingh_t::kLeft: return kHaierAcYrw02SwingHLeft; + case stdAc::swingh_t::kRight: return kHaierAcYrw02SwingHRight; + case stdAc::swingh_t::kRightMax: return kHaierAcYrw02SwingHRightMax; + case stdAc::swingh_t::kAuto: return kHaierAcYrw02SwingHAuto; + default: return kHaierAcYrw02SwingHMiddle; } } @@ -939,12 +1100,27 @@ stdAc::fanspeed_t IRHaierAC176::toCommonFanSpeed(const uint8_t speed) { /// @return The native equivalent of the enum. stdAc::swingv_t IRHaierAC176::toCommonSwingV(const uint8_t pos) { switch (pos) { - case kHaierAcYrw02SwingTop: return stdAc::swingv_t::kHighest; - case kHaierAcYrw02SwingMiddle: return stdAc::swingv_t::kMiddle; - case kHaierAcYrw02SwingDown: return stdAc::swingv_t::kLow; - case kHaierAcYrw02SwingBottom: return stdAc::swingv_t::kLowest; - case kHaierAcYrw02SwingOff: return stdAc::swingv_t::kOff; - default: return stdAc::swingv_t::kAuto; + case kHaierAcYrw02SwingVTop: return stdAc::swingv_t::kHighest; + case kHaierAcYrw02SwingVMiddle: return stdAc::swingv_t::kMiddle; + case kHaierAcYrw02SwingVDown: return stdAc::swingv_t::kLow; + case kHaierAcYrw02SwingVBottom: return stdAc::swingv_t::kLowest; + case kHaierAcYrw02SwingVOff: return stdAc::swingv_t::kOff; + default: return stdAc::swingv_t::kAuto; + } +} + +/// Convert a stdAc::swingh_t enum into it's native setting. +/// @param[in] pos The enum to be converted. +/// @return The native equivalent of the enum. +stdAc::swingh_t IRHaierAC176::toCommonSwingH(const uint8_t pos) { + switch (pos) { + case kHaierAcYrw02SwingHMiddle: return stdAc::swingh_t::kMiddle; + case kHaierAcYrw02SwingHLeftMax: return stdAc::swingh_t::kLeftMax; + case kHaierAcYrw02SwingHLeft: return stdAc::swingh_t::kLeft; + case kHaierAcYrw02SwingHRight: return stdAc::swingh_t::kRight; + case kHaierAcYrw02SwingHRightMax: return stdAc::swingh_t::kRightMax; + case kHaierAcYrw02SwingHAuto: return stdAc::swingh_t::kAuto; + default: return stdAc::swingh_t::kOff; } } @@ -953,23 +1129,23 @@ stdAc::swingv_t IRHaierAC176::toCommonSwingV(const uint8_t pos) { stdAc::state_t IRHaierAC176::toCommon(void) const { stdAc::state_t result; result.protocol = decode_type_t::HAIER_AC_YRW02; - result.model = -1; // No models used. + result.model = getModel(); result.power = _.Power; result.mode = toCommonMode(_.Mode); - result.celsius = true; + result.celsius = !_.UseFahrenheit; result.degrees = getTemp(); result.fanspeed = toCommonFanSpeed(_.Fan); - result.swingv = toCommonSwingV(_.Swing); + result.swingv = toCommonSwingV(_.SwingV); + result.swingh = toCommonSwingH(_.SwingH); result.filter = _.Health; result.sleep = _.Sleep ? 0 : -1; + result.turbo = _.Turbo; + result.quiet = _.Quiet; // Not supported. - result.swingh = stdAc::swingh_t::kOff; - result.quiet = false; - result.turbo = false; result.econo = false; result.light = false; result.clean = false; - result.beep = false; + result.beep = true; result.clock = -1; return result; } @@ -978,8 +1154,9 @@ stdAc::state_t IRHaierAC176::toCommon(void) const { /// @return A human readable string. String IRHaierAC176::toString(void) const { String result = ""; - result.reserve(130); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(_.Power, kPowerStr, false); + result.reserve(280); // Reserve some heap for the string to reduce fragging. + result += addModelToString(decode_type_t::HAIER_AC176, getModel(), false); + result += addBoolToString(_.Power, kPowerStr); uint8_t cmd = _.Button; result += addIntToString(cmd, kButtonStr); result += kSpaceLBraceStr; @@ -1005,12 +1182,24 @@ String IRHaierAC176::toString(void) const { case kHaierAcYrw02ButtonHealth: result += kHealthStr; break; - case kHaierAcYrw02ButtonSwing: - result += kSwingStr; + case kHaierAcYrw02ButtonSwingV: + result += kSwingVStr; + break; + case kHaierAcYrw02ButtonSwingH: + result += kSwingHStr; break; case kHaierAcYrw02ButtonTurbo: result += kTurboStr; break; + case kHaierAcYrw02ButtonTimer: + result += kTimerStr; + break; + case kHaierAcYrw02ButtonLock: + result += kLockStr; + break; + case kHaierAcYrw02ButtonCFAB: + result += kCelsiusFahrenheitStr; + break; default: result += kUnknownStr; } @@ -1018,51 +1207,49 @@ String IRHaierAC176::toString(void) const { result += addModeToString(_.Mode, kHaierAcYrw02Auto, kHaierAcYrw02Cool, kHaierAcYrw02Heat, kHaierAcYrw02Dry, kHaierAcYrw02Fan); - result += addTempToString(getTemp()); + result += addTempToString(getTemp(), !_.UseFahrenheit); result += addFanToString(_.Fan, kHaierAcYrw02FanHigh, kHaierAcYrw02FanLow, kHaierAcYrw02FanAuto, kHaierAcYrw02FanAuto, kHaierAcYrw02FanMed); - result += addIntToString(_.Turbo, kTurboStr); + result += addBoolToString(_.Turbo, kTurboStr); + result += addBoolToString(_.Quiet, kQuietStr); + result += addIntToString(_.SwingV, kSwingVStr); result += kSpaceLBraceStr; - switch (_.Turbo) { - case kHaierAcYrw02TurboOff: + switch (_.SwingV) { + case kHaierAcYrw02SwingVOff: result += kOffStr; break; - case kHaierAcYrw02TurboLow: - result += kLowStr; - break; - case kHaierAcYrw02TurboHigh: - result += kHighStr; - break; - default: - result += kUnknownStr; - } - result += ')'; - result += addIntToString(_.Swing, kSwingStr); - result += kSpaceLBraceStr; - switch (_.Swing) { - case kHaierAcYrw02SwingOff: - result += kOffStr; - break; - case kHaierAcYrw02SwingAuto: + case kHaierAcYrw02SwingVAuto: result += kAutoStr; break; - case kHaierAcYrw02SwingBottom: + case kHaierAcYrw02SwingVBottom: result += kLowestStr; break; - case kHaierAcYrw02SwingDown: + case kHaierAcYrw02SwingVDown: result += kLowStr; break; - case kHaierAcYrw02SwingTop: + case kHaierAcYrw02SwingVTop: result += kHighestStr; break; - case kHaierAcYrw02SwingMiddle: + case kHaierAcYrw02SwingVMiddle: result += kMiddleStr; break; default: result += kUnknownStr; } result += ')'; + result += addSwingHToString(_.SwingH, kHaierAcYrw02SwingHAuto, + kHaierAcYrw02SwingHLeftMax, + kHaierAcYrw02SwingHLeft, + kHaierAcYrw02SwingHMiddle, + kHaierAcYrw02SwingHRight, + kHaierAcYrw02SwingHRightMax, + // Below are unused. + kHaierAcYrw02SwingHMiddle, + kHaierAcYrw02SwingHMiddle, + kHaierAcYrw02SwingHMiddle, + kHaierAcYrw02SwingHMiddle, + kHaierAcYrw02SwingHMiddle); result += addBoolToString(_.Sleep, kSleepStr); result += addBoolToString(_.Health, kHealthStr); const uint8_t tmode = getTimerMode(); @@ -1098,6 +1285,7 @@ String IRHaierAC176::toString(void) const { result += addLabeledString((tmode != kHaierAcYrw02NoTimers && tmode != kHaierAcYrw02OnTimer) ? minsToString(getOffTimer()) : kOffStr, kOffTimerStr); + result += addBoolToString(_.Lock, kLockStr); return result; } // End of IRHaierAC176 class. @@ -1203,7 +1391,7 @@ bool IRrecv::decodeHaierACYRW02(decode_results* results, uint16_t offset, // Compliance if (strict) { - if (results->state[0] != kHaierAcYrw02Prefix) return false; + if (results->state[0] != kHaierAcYrw02ModelA) return false; if (!IRHaierACYRW02::validChecksum(results->state, nbits / 8)) return false; } @@ -1236,7 +1424,8 @@ bool IRrecv::decodeHaierAC176(decode_results* results, uint16_t offset, // Compliance if (strict) { - if (results->state[0] != kHaierAcYrw02Prefix) return false; + if ((results->state[0] != kHaierAcYrw02ModelA) && + (results->state[0] != kHaierAcYrw02ModelB)) return false; if (!IRHaierAC176::validChecksum(results->state, nbits / 8)) return false; } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.h index 2e287cd12..4e5c8e64c 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Haier.h @@ -1,4 +1,4 @@ -// Copyright 2018 crankyoldgit +// Copyright 2018-2021 crankyoldgit /// @file /// @brief Support for Haier A/C protocols. /// The specifics of reverse engineering the protocols details: @@ -13,8 +13,10 @@ // Brand: Haier, Model: HSU07-HEA03 remote (HAIER_AC) // Brand: Haier, Model: YR-W02 remote (HAIER_AC_YRW02) // Brand: Haier, Model: HSU-09HMC203 A/C (HAIER_AC_YRW02) +// Brand: Haier, Model: V9014557 M47 8D remote (HAIER_AC176) // Brand: Mabe, Model: MMI18HDBWCA6MI8 A/C (HAIER_AC176) // Brand: Mabe, Model: V12843 HJ200223 remote (HAIER_AC176) +// Brand: Daichi, Model: D-H A/C (HAIER_AC176) #ifndef IR_HAIER_H_ #define IR_HAIER_H_ @@ -41,7 +43,7 @@ union HaierProtocol{ // Byte 2 uint8_t CurrHours:5; uint8_t unknown :1; // value=1 - uint8_t Swing :2; + uint8_t SwingV :2; // Byte 3 uint8_t CurrMins:6; uint8_t OffTimer:1; @@ -84,10 +86,10 @@ const uint8_t kHaierAcCmdTimerCancel = 0b1010; const uint8_t kHaierAcCmdHealth = 0b1100; const uint8_t kHaierAcCmdSwing = 0b1101; -const uint8_t kHaierAcSwingOff = 0b00; -const uint8_t kHaierAcSwingUp = 0b01; -const uint8_t kHaierAcSwingDown = 0b10; -const uint8_t kHaierAcSwingChg = 0b11; +const uint8_t kHaierAcSwingVOff = 0b00; +const uint8_t kHaierAcSwingVUp = 0b01; +const uint8_t kHaierAcSwingVDown = 0b10; +const uint8_t kHaierAcSwingVChg = 0b11; const uint8_t kHaierAcAuto = 0; const uint8_t kHaierAcCool = 1; @@ -118,11 +120,11 @@ const uint8_t kHaierAcSleepBit = 0b01000000; #define HAIER_AC_CMD_TIMER_SET kHaierAcCmdTimerSet #define HAIER_AC_CMD_TIMER_CANCEL kHaierAcCmdTimerCancel #define HAIER_AC_CMD_HEALTH kHaierAcCmdHealth -#define HAIER_AC_CMD_SWING kHaierAcCmdSwing -#define HAIER_AC_SWING_OFF kHaierAcSwingOff -#define HAIER_AC_SWING_UP kHaierAcSwingUp -#define HAIER_AC_SWING_DOWN kHaierAcSwingDown -#define HAIER_AC_SWING_CHG kHaierAcSwingChg +#define HAIER_AC_CMD_SWINGV kHaierAcCmdSwing +#define HAIER_AC_SWINGV_OFF kHaierAcSwingVOff +#define HAIER_AC_SWINGV_UP kHaierAcSwingVUp +#define HAIER_AC_SWINGV_DOWN kHaierAcSwingVDown +#define HAIER_AC_SWINGV_CHG kHaierAcSwingVChg #define HAIER_AC_AUTO kHaierAcAuto #define HAIER_AC_COOL kHaierAcCool #define HAIER_AC_DRY kHaierAcDry @@ -133,85 +135,54 @@ const uint8_t kHaierAcSleepBit = 0b01000000; #define HAIER_AC_FAN_MED kHaierAcFanMed #define HAIER_AC_FAN_HIGH kHaierAcFanHigh -/// Native representation of a Haier YRW02 A/C message. -union HaierYRW02Protocol{ - uint8_t raw[kHaierACYRW02StateLength]; ///< The state in native form - struct { - // Byte 0 - uint8_t Prefix; - // Byte 1 - uint8_t Swing:4; - uint8_t Temp :4; // 16C~30C - // Byte 2 - uint8_t :8; - // Byte 3 - uint8_t :1; - uint8_t Health:1; - uint8_t :6; - // Byte 4 - uint8_t :6; - uint8_t Power:1; - uint8_t :1; - // Byte 5 - uint8_t :5; - uint8_t Fan:3; - // Byte 6 - uint8_t :6; - uint8_t Turbo:2; - // Byte 7 - uint8_t :5; - uint8_t Mode:3; - // Byte 8 - uint8_t :7; - uint8_t Sleep:1; - // Byte 9 - uint8_t :8; - // Byte 10 - uint8_t :8; - // Byte 11 - uint8_t :8; - // Byte 12 - uint8_t Button:4; - uint8_t :4; - // Byte 13 - uint8_t Sum; - }; -}; +const uint8_t kHaierAcYrw02MinTempC = 16; +const uint8_t kHaierAcYrw02MaxTempC = 30; +const uint8_t kHaierAcYrw02MinTempF = 60; +const uint8_t kHaierAcYrw02MaxTempF = 86; +const uint8_t kHaierAcYrw02DefTempC = 25; -const uint8_t kHaierAcYrw02Prefix = 0xA6; +const uint8_t kHaierAcYrw02ModelA = 0xA6; +const uint8_t kHaierAcYrw02ModelB = 0x59; const uint8_t kHaierAc176Prefix = 0xB7; -const uint8_t kHaierAcYrw02SwingOff = 0x0; -const uint8_t kHaierAcYrw02SwingTop = 0x1; -const uint8_t kHaierAcYrw02SwingMiddle = 0x2; // Not available in heat mode. -const uint8_t kHaierAcYrw02SwingBottom = 0x3; // Only available in heat mode. -const uint8_t kHaierAcYrw02SwingDown = 0xA; -const uint8_t kHaierAcYrw02SwingAuto = 0xC; // Airflow +const uint8_t kHaierAcYrw02SwingVOff = 0x0; +const uint8_t kHaierAcYrw02SwingVTop = 0x1; +const uint8_t kHaierAcYrw02SwingVMiddle = 0x2; // Not available in heat mode. +const uint8_t kHaierAcYrw02SwingVBottom = 0x3; // Only available in heat mode. +const uint8_t kHaierAcYrw02SwingVDown = 0xA; +const uint8_t kHaierAcYrw02SwingVAuto = 0xC; // Airflow + +const uint8_t kHaierAcYrw02SwingHMiddle = 0x0; +const uint8_t kHaierAcYrw02SwingHLeftMax = 0x3; +const uint8_t kHaierAcYrw02SwingHLeft = 0x4; +const uint8_t kHaierAcYrw02SwingHRight = 0x5; +const uint8_t kHaierAcYrw02SwingHRightMax = 0x6; +const uint8_t kHaierAcYrw02SwingHAuto = 0x7; const uint8_t kHaierAcYrw02FanHigh = 0b001; const uint8_t kHaierAcYrw02FanMed = 0b010; const uint8_t kHaierAcYrw02FanLow = 0b011; const uint8_t kHaierAcYrw02FanAuto = 0b101; // HAIER_AC176 uses `0` in Fan2 -const uint8_t kHaierAcYrw02TurboOff = 0x0; -const uint8_t kHaierAcYrw02TurboHigh = 0x1; -const uint8_t kHaierAcYrw02TurboLow = 0x2; - const uint8_t kHaierAcYrw02Auto = 0b000; // 0 const uint8_t kHaierAcYrw02Cool = 0b001; // 1 const uint8_t kHaierAcYrw02Dry = 0b010; // 2 const uint8_t kHaierAcYrw02Heat = 0b100; // 4 const uint8_t kHaierAcYrw02Fan = 0b110; // 5 -const uint8_t kHaierAcYrw02ButtonTempUp = 0x0; -const uint8_t kHaierAcYrw02ButtonTempDown = 0x1; -const uint8_t kHaierAcYrw02ButtonSwing = 0x2; -const uint8_t kHaierAcYrw02ButtonFan = 0x4; -const uint8_t kHaierAcYrw02ButtonPower = 0x5; -const uint8_t kHaierAcYrw02ButtonMode = 0x6; -const uint8_t kHaierAcYrw02ButtonHealth = 0x7; -const uint8_t kHaierAcYrw02ButtonTurbo = 0x8; -const uint8_t kHaierAcYrw02ButtonSleep = 0xB; +const uint8_t kHaierAcYrw02ButtonTempUp = 0b00000; +const uint8_t kHaierAcYrw02ButtonTempDown = 0b00001; +const uint8_t kHaierAcYrw02ButtonSwingV = 0b00010; +const uint8_t kHaierAcYrw02ButtonSwingH = 0b00011; +const uint8_t kHaierAcYrw02ButtonFan = 0b00100; +const uint8_t kHaierAcYrw02ButtonPower = 0b00101; +const uint8_t kHaierAcYrw02ButtonMode = 0b00110; +const uint8_t kHaierAcYrw02ButtonHealth = 0b00111; +const uint8_t kHaierAcYrw02ButtonTurbo = 0b01000; +const uint8_t kHaierAcYrw02ButtonSleep = 0b01011; +const uint8_t kHaierAcYrw02ButtonTimer = 0b10000; +const uint8_t kHaierAcYrw02ButtonLock = 0b10100; +const uint8_t kHaierAcYrw02ButtonCFAB = 0b11010; const uint8_t kHaierAcYrw02NoTimers = 0b000; const uint8_t kHaierAcYrw02OffTimer = 0b001; @@ -224,12 +195,13 @@ union HaierAc176Protocol{ uint8_t raw[kHaierAC176StateLength]; ///< The state in native form struct { // Byte 0 - uint8_t Prefix :8; + uint8_t Model :8; // Byte 1 - uint8_t Swing :4; + uint8_t SwingV :4; uint8_t Temp :4; // 16C~30C // Byte 2 - uint8_t :8; + uint8_t :5; + uint8_t SwingH :3; // Byte 3 uint8_t :1; uint8_t Health :1; @@ -244,7 +216,8 @@ union HaierAc176Protocol{ uint8_t Fan :3; // Byte 6 uint8_t OffTimerMins:6; - uint8_t Turbo:2; + uint8_t Turbo :1; + uint8_t Quiet :1; // Byte 7 uint8_t OnTimerHrs :5; uint8_t Mode :3; @@ -255,12 +228,16 @@ union HaierAc176Protocol{ // Byte 9 uint8_t :8; // Byte 10 - uint8_t :8; + uint8_t ExtraDegreeF :1; + uint8_t :4; + uint8_t UseFahrenheit:1; + uint8_t :2; // Byte 11 uint8_t :8; // Byte 12 - uint8_t Button :4; - uint8_t :4; + uint8_t Button :5; + uint8_t Lock :1; + uint8_t :2; // Byte 13 uint8_t Sum :8; // Byte 14 @@ -295,8 +272,6 @@ union HaierAc176Protocol{ #define HAIER_AC_YRW02_FAN_LOW kHaierAcYrw02FanLow #define HAIER_AC_YRW02_FAN_AUTO kHaierAcYrw02FanAuto #define HAIER_AC_YRW02_TURBO_OFF kHaierAcYrw02TurboOff -#define HAIER_AC_YRW02_TURBO_HIGH kHaierAcYrw02TurboHigh -#define HAIER_AC_YRW02_TURBO_LOW kHaierAcYrw02TurboLow #define HAIER_AC_YRW02_AUTO kHaierAcYrw02Auto #define HAIER_AC_YRW02_COOL kHaierAcYrw02Cool #define HAIER_AC_YRW02_DRY kHaierAcYrw02Dry @@ -355,8 +330,8 @@ class IRHaierAC { uint16_t getCurrTime(void) const; void setCurrTime(const uint16_t mins); - uint8_t getSwing(void) const; - void setSwing(const uint8_t state); + uint8_t getSwingV(void) const; + void setSwingV(const uint8_t state); uint8_t* getRaw(void); void setRaw(const uint8_t new_code[]); @@ -400,10 +375,15 @@ class IRHaierAC176 { void begin(void); void stateReset(void); + void setModel(const haier_ac176_remote_model_t model); + haier_ac176_remote_model_t getModel(void) const; + void setButton(const uint8_t button); uint8_t getButton(void) const; - void setTemp(const uint8_t temp); + void setUseFahrenheit(const bool on); + bool getUseFahrenheit(void) const; + void setTemp(const uint8_t temp, const bool fahrenheit = false); uint8_t getTemp(void) const; void setFan(const uint8_t speed); @@ -422,9 +402,18 @@ class IRHaierAC176 { bool getHealth(void) const; void setHealth(const bool on); - uint8_t getTurbo(void) const; - void setTurbo(const uint8_t speed); + bool getTurbo(void) const; + void setTurbo(const bool on); + bool getQuiet(void) const; + void setQuiet(const bool on); + uint8_t getSwingV(void) const; + void setSwingV(const uint8_t pos); + uint8_t getSwingH(void) const; + void setSwingH(const uint8_t pos); + + /// These functions are for backward compatibility. + /// Use getSwingV() and setSwingV() instead. uint8_t getSwing(void) const; void setSwing(const uint8_t pos); @@ -435,6 +424,9 @@ class IRHaierAC176 { void setOffTimer(const uint16_t mins); uint16_t getOffTimer(void) const; + bool getLock(void) const; + void setLock(const bool on); + uint8_t* getRaw(void); virtual void setRaw(const uint8_t new_code[]); static bool validChecksum(const uint8_t state[], @@ -442,9 +434,13 @@ class IRHaierAC176 { static uint8_t convertMode(const stdAc::opmode_t mode); static uint8_t convertFan(const stdAc::fanspeed_t speed); static uint8_t convertSwingV(const stdAc::swingv_t position); + static uint8_t convertSwingH(const stdAc::swingh_t position); static stdAc::opmode_t toCommonMode(const uint8_t mode); static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed); static stdAc::swingv_t toCommonSwingV(const uint8_t pos); + static stdAc::swingh_t toCommonSwingH(const uint8_t pos); + static bool toCommonTurbo(const uint8_t speed); + static bool toCommonQuiet(const uint8_t speed); stdAc::state_t toCommon(void) const; String toString(void) const; #ifndef UNIT_TEST diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_LG.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_LG.h index 6010282ca..2bd7dbc1c 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_LG.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_LG.h @@ -15,6 +15,8 @@ // Brand: LG, Model: AMNW09GSJA0 A/C (LG2 - AKB74955603) // Brand: LG, Model: AMNW24GTPA1 A/C (LG2 - AKB73757604) // Brand: LG, Model: AKB73757604 remote (LG2 - AKB73757604) +// Brand: LG, Model: AKB73315611 remote (LG2 - AKB74955603) +// Brand: LG, Model: MS05SQ NW0 A/C (LG2 - AKB74955603) // Brand: General Electric, Model: AG1BH09AW101 Split A/C (LG) // Brand: General Electric, Model: 6711AR2853M A/C Remote (LG) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mirage.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mirage.cpp index 8a573a8dc..a806937b1 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mirage.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mirage.cpp @@ -1,15 +1,35 @@ -// Copyright 2020 David Conran (crankyoldgit) +// Copyright 2020-2021 David Conran (crankyoldgit) /// @file /// @brief Support for Mirage protocol /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1289 +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1573 -// Supports: -// Brand: Mirage, Model: VLU series A/C +#include "ir_Mirage.h" +#include +#include +#ifndef ARDUINO +#include +#endif #include "IRrecv.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" +using irutils::addBoolToString; +using irutils::addFanToString; +using irutils::addIntToString; +using irutils::addLabeledString; +using irutils::addModeToString; +using irutils::addModelToString; +using irutils::addSwingHToString; +using irutils::addSwingVToString; +using irutils::addTempToString; +using irutils::addToggleToString; +using irutils::minsToString; +using irutils::bcdToUint8; +using irutils::uint8ToBcd; +using irutils::sumNibbles; // Constants const uint16_t kMirageHdrMark = 8360; ///< uSeconds @@ -20,6 +40,9 @@ const uint16_t kMirageZeroSpace = 545; ///< uSeconds const uint32_t kMirageGap = kDefaultMessageGap; ///< uSeconds (just a guess) const uint16_t kMirageFreq = 38000; ///< Hz. (Just a guess) +const uint8_t kMirageAcKKG29AC1PowerOn = 0b00; // 0 +const uint8_t kMirageAcKKG29AC1PowerOff = 0b11; // 3 + #if SEND_MIRAGE /// Send a Mirage formatted message. @@ -58,6 +81,8 @@ bool IRrecv::decodeMirage(decode_results *results, uint16_t offset, kMirageBitMark, kMirageZeroSpace, kMirageBitMark, kMirageGap, true, kUseDefTol, kMarkExcess, false)) return false; + // Compliance + if (strict && !IRMirageAc::validChecksum(results->state)) return false; // Success results->decode_type = decode_type_t::MIRAGE; @@ -67,4 +92,756 @@ bool IRrecv::decodeMirage(decode_results *results, uint16_t offset, // is a union data type. return true; } + +// Code to emulate Mirage A/C IR remote control unit. + +/// Class constructor +/// @param[in] pin GPIO to be used when sending. +/// @param[in] inverted Is the output signal to be inverted? +/// @param[in] use_modulation Is frequency modulation to be used? +IRMirageAc::IRMirageAc(const uint16_t pin, const bool inverted, + const bool use_modulation) + : _irsend(pin, inverted, use_modulation) { stateReset(); } + +/// Reset the state of the remote to a known good state/sequence. +void IRMirageAc::stateReset(void) { + // The state of the IR remote in IR code form. + static const uint8_t kReset[kMirageStateLength] = { + 0x56, 0x6C, 0x00, 0x00, 0x20, 0x1A, 0x00, 0x00, + 0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x42}; + setRaw(kReset); + _model = mirage_ac_remote_model_t::KKG9AC1; +} + +/// Set up hardware to be able to send a message. +void IRMirageAc::begin(void) { _irsend.begin(); } + +#if SEND_MITSUBISHI_AC +/// Send the current internal state as an IR message. +/// @param[in] repeat Nr. of times the message will be repeated. +void IRMirageAc::send(const uint16_t repeat) { + _irsend.sendMirage(getRaw(), kMirageStateLength, repeat); + // Reset any toggles after a send. + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + setCleanToggle(false); + setLight(false); // For this model (only), Light is a toggle. + break; + default: + break; + } +} +#endif // SEND_MITSUBISHI_AC + +/// Get a PTR to the internal state/code for this protocol. +/// @return PTR to a code for this protocol based on the current internal state. +uint8_t *IRMirageAc::getRaw(void) { + checksum(); + return _.raw; +} + +/// Set the internal state from a valid code for this protocol. +/// @param[in] data A valid code for this protocol. +void IRMirageAc::setRaw(const uint8_t *data) { + std::memcpy(_.raw, data, kMirageStateLength); + _model = getModel(true); +} + +/// Guess the Mirage remote model from the supplied state code. +/// @param[in] state A valid state code for this protocol. +/// @return The model code. +/// @note This result isn't perfect. Both protocols can look the same but have +/// wildly different settings. +mirage_ac_remote_model_t IRMirageAc::getModel(const uint8_t *state) { + Mirage120Protocol p; + std::memcpy(p.raw, state, kMirageStateLength); + // Check for KKG29AC1 specific settings. + if (p.RecycleHeat || p.Filter || p.Sleep_Kkg29ac1 || p.CleanToggle || + p.IFeel || p.OffTimerEnable || p.OnTimerEnable) + return mirage_ac_remote_model_t::KKG29AC1; + // Check for things specific to KKG9AC1 + if ((p.Minutes || p.Seconds) || // Is part of the clock set? + // Are the timer times set, but not enabled? (enable check filtered above) + (p.OffTimerHours || p.OffTimerMins) || + (p.OnTimerHours || p.OnTimerMins)) + return mirage_ac_remote_model_t::KKG9AC1; + // As the above test has a 1 in 3600+ (for 1 second an hour) chance of a false + // negative in theory, we are going assume that anything left should be a + // KKG29AC1 model. + return mirage_ac_remote_model_t::KKG29AC1; // Default. +} + +/// Get the model code of the interal message state. +/// @param[in] useRaw If set, we try to get the model info from just the state. +/// @return The model code. +mirage_ac_remote_model_t IRMirageAc::getModel(const bool useRaw) const { + return useRaw ? getModel(_.raw) : _model; +} + +/// Set the model code of the interal message state. +/// @param[in] model The desired model to use for the settings. +void IRMirageAc::setModel(const mirage_ac_remote_model_t model) { + if (model != _model) { // Only change things if we need to. + // Save the old settings. + stdAc::state_t state = toCommon(); + const uint16_t ontimer = getOnTimer(); + const uint16_t offtimer = getOffTimer(); + const bool ifeel = getIFeel(); + const uint8_t sensor = getSensorTemp(); + // Change the model. + state.model = model; + // Restore/Convert the settings. + fromCommon(state); + setOnTimer(ontimer); + setOffTimer(offtimer); + setIFeel(ifeel); + setSensorTemp(sensor); + } +} + +/// Calculate and set the checksum values for the internal state. +void IRMirageAc::checksum(void) { _.Sum = calculateChecksum(_.raw); } + +/// Verify the checksum is valid for a given state. +/// @param[in] data The array to verify the checksum of. +/// @return true, if the state has a valid checksum. Otherwise, false. +bool IRMirageAc::validChecksum(const uint8_t *data) { + return calculateChecksum(data) == data[kMirageStateLength - 1]; +} + +/// Calculate the checksum for a given state. +/// @param[in] data The value to calc the checksum of. +/// @return The calculated checksum value. +uint8_t IRMirageAc::calculateChecksum(const uint8_t *data) { + return sumNibbles(data, kMirageStateLength - 1); +} + +/// Set the requested power state of the A/C to on. +void IRMirageAc::on(void) { setPower(true); } + +/// Set the requested power state of the A/C to off. +void IRMirageAc::off(void) { setPower(false); } + +/// Change the power setting. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRMirageAc::setPower(bool on) { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + _.Power = on ? kMirageAcKKG29AC1PowerOn : kMirageAcKKG29AC1PowerOff; + break; + default: + // In order to change the power setting, it seems must be less than + // kMirageAcPowerOff. kMirageAcPowerOff is larger than half of the + // possible value stored in the allocated bit space. + // Thus if the value is larger than kMirageAcPowerOff the power is off. + // Less than, then power is on. + // We can't just aribitarily add or subtract the value (which analysis + // indicates is how the power status changes. Very weird, I know!) as that + // is not an idempotent action, we must check if the addition or + // substraction is needed first. e.g. via getPower() + // i.e. If we added or subtracted twice, we would cause a wrap of the + // integer and not get the desired result. + if (on) + _.SwingAndPower -= getPower() ? 0 : kMirageAcPowerOff; + else + _.SwingAndPower += getPower() ? kMirageAcPowerOff : 0; + } +} + +/// Get the value of the current power setting. +/// @return true, the setting is on. false, the setting is off. +bool IRMirageAc::getPower(void) const { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + return _.Power == kMirageAcKKG29AC1PowerOn; + default: + return _.SwingAndPower < kMirageAcPowerOff; + } +} + +/// Get the operating mode setting of the A/C. +/// @return The current operating mode setting. +uint8_t IRMirageAc::getMode(void) const { return _.Mode; } + +/// Set the operating mode of the A/C. +/// @param[in] mode The desired operating mode. +void IRMirageAc::setMode(const uint8_t mode) { + switch (mode) { + case kMirageAcCool: + case kMirageAcDry: + case kMirageAcHeat: + case kMirageAcFan: + case kMirageAcRecycle: + _.Mode = mode; + // Reset turbo if we have to. + setTurbo(getTurbo()); + break; + default: // Default to cool mode for anything else. + setMode(kMirageAcCool); + } +} + +/// Set the temperature. +/// @param[in] degrees The temperature in degrees celsius. +void IRMirageAc::setTemp(const uint8_t degrees) { + // Make sure we have desired temp in the correct range. + uint8_t celsius = std::max(degrees, kMirageAcMinTemp); + _.Temp = std::min(celsius, kMirageAcMaxTemp) + kMirageAcTempOffset; +} + +/// Get the current temperature setting. +/// @return The current setting for temp. in degrees celsius. +uint8_t IRMirageAc::getTemp(void) const { return _.Temp - kMirageAcTempOffset; } + +/// Set the speed of the fan. +/// @param[in] speed The desired setting. +void IRMirageAc::setFan(const uint8_t speed) { + _.Fan = (speed <= kMirageAcFanLow) ? speed : kMirageAcFanAuto; +} + +/// Get the current fan speed setting. +/// @return The current fan speed/mode. +uint8_t IRMirageAc::getFan(void) const { return _.Fan; } + +/// Change the Turbo setting. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRMirageAc::setTurbo(bool on) { + const bool value = (on && (getMode() == kMirageAcCool)); + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + _.Turbo_Kkg29ac1 = value; + break; + default: + _.Turbo_Kkg9ac1 = value; + } +} + +/// Get the value of the current Turbo setting. +/// @return true, the setting is on. false, the setting is off. +bool IRMirageAc::getTurbo(void) const { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: return _.Turbo_Kkg29ac1; + default: return _.Turbo_Kkg9ac1; + } +} + +/// Change the Sleep setting. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRMirageAc::setSleep(bool on) { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + _.Sleep_Kkg29ac1 = on; + break; + default: + _.Sleep_Kkg9ac1 = on; + } +} + +/// Get the value of the current Sleep setting. +/// @return true, the setting is on. false, the setting is off. +bool IRMirageAc::getSleep(void) const { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: return _.Sleep_Kkg29ac1; + default: return _.Sleep_Kkg9ac1; + } +} + +/// Change the Light/Display setting. +/// @param[in] on true, the setting is on. false, the setting is off. +/// @note Light is a toggle on the KKG29AC1 model. +void IRMirageAc::setLight(bool on) { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + _.LightToggle_Kkg29ac1 = on; + break; + default: + _.Light_Kkg9ac1 = on; + } +} + +/// Get the value of the current Light/Display setting. +/// @return true, the setting is on. false, the setting is off. +/// @note Light is a toggle on the KKG29AC1 model. +bool IRMirageAc::getLight(void) const { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: return _.LightToggle_Kkg29ac1; + default: return _.Light_Kkg9ac1; + } +} + +/// Get the clock time of the A/C unit. +/// @return Nr. of seconds past midnight. +uint32_t IRMirageAc::getClock(void) const { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + return 0; + default: + return ((bcdToUint8(_.Hours) * 60) + bcdToUint8(_.Minutes)) * 60 + + bcdToUint8(_.Seconds); + } +} + +/// Set the clock time on the A/C unit. +/// @param[in] nr_of_seconds Nr. of seconds past midnight. +void IRMirageAc::setClock(const uint32_t nr_of_seconds) { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + _.Minutes = _.Seconds = 0; // No clock setting. Clear it just in case. + break; + default: + uint32_t remaining = std::min( + nr_of_seconds, (uint32_t)(24 * 60 * 60 - 1)); // Limit to 23:59:59. + _.Seconds = uint8ToBcd(remaining % 60); + remaining /= 60; + _.Minutes = uint8ToBcd(remaining % 60); + remaining /= 60; + _.Hours = uint8ToBcd(remaining); + } +} + +/// Set the Vertical Swing setting/position of the A/C. +/// @param[in] position The desired swing setting. +void IRMirageAc::setSwingV(const uint8_t position) { + switch (position) { + case kMirageAcSwingVOff: + case kMirageAcSwingVLowest: + case kMirageAcSwingVLow: + case kMirageAcSwingVMiddle: + case kMirageAcSwingVHigh: + case kMirageAcSwingVHighest: + case kMirageAcSwingVAuto: + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + _.SwingV = (position != kMirageAcSwingVOff); + break; + default: + const bool power = getPower(); + _.SwingAndPower = position; + // Power needs to be reapplied after overwriting SwingAndPower + setPower(power); + } + break; + default: // Default to Auto for anything else. + setSwingV(kMirageAcSwingVAuto); + } +} + +/// Get the Vertical Swing setting/position of the A/C. +/// @return The desired Vertical Swing setting/position. +uint8_t IRMirageAc::getSwingV(void) const { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + return _.SwingV ? kMirageAcSwingVAuto : kMirageAcSwingVOff; + default: + return _.SwingAndPower - (getPower() ? 0 : kMirageAcPowerOff); + } +} + +/// Set the Horizontal Swing setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRMirageAc::setSwingH(const bool on) { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + _.SwingH = on; + break; + default: + break; + } +} + +/// Get the Horizontal Swing setting of the A/C. +/// @return on true, the setting is on. false, the setting is off. +bool IRMirageAc::getSwingH(void) const { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: return _.SwingH; + default: return false; + } +} + +/// Set the Quiet setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRMirageAc::setQuiet(const bool on) { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + _.Quiet = on; + break; + default: + break; + } +} + +/// Get the Quiet setting of the A/C. +/// @return on true, the setting is on. false, the setting is off. +bool IRMirageAc::getQuiet(void) const { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: return _.Quiet; + default: return false; + } +} + +/// Set the CleanToggle setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRMirageAc::setCleanToggle(const bool on) { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + _.CleanToggle = on; + break; + default: + break; + } +} + +/// Get the Clean Toggle setting of the A/C. +/// @return on true, the setting is on. false, the setting is off. +bool IRMirageAc::getCleanToggle(void) const { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: return _.CleanToggle; + default: return false; + } +} + +/// Set the Filter setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRMirageAc::setFilter(const bool on) { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + _.Filter = on; + break; + default: + break; + } +} + +/// Get the Filter setting of the A/C. +/// @return on true, the setting is on. false, the setting is off. +bool IRMirageAc::getFilter(void) const { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: return _.Filter; + default: return false; + } +} + +/// Set the IFeel setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRMirageAc::setIFeel(const bool on) { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + _.IFeel = on; + if (on) { + // If no previous sensor temp, default to currently desired temp. + if (!_.SensorTemp) _.SensorTemp = getTemp(); + } else { + _.SensorTemp = 0; // When turning it off, clear the Sensor Temp. + } + break; + default: + break; + } +} + +/// Get the IFeel setting of the A/C. +/// @return on true, the setting is on. false, the setting is off. +bool IRMirageAc::getIFeel(void) const { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: return _.IFeel; + default: return false; + } +} + +/// Set the Sensor Temp setting of the A/C's remote. +/// @param[in] degrees The desired sensor temp. in degrees celsius. +void IRMirageAc::setSensorTemp(const uint8_t degrees) { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + _.SensorTemp = std::min(kMirageAcSensorTempMax, degrees) + + kMirageAcSensorTempOffset; + break; + default: + break; + } +} + +/// Get the Sensor Temp setting of the A/C's remote. +/// @return The current setting for the sensor temp. in degrees celsius. +uint16_t IRMirageAc::getSensorTemp(void) const { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + return _.SensorTemp - kMirageAcSensorTempOffset; + default: + return false; + } +} + +/// Get the number of minutes the On Timer is currently set for. +/// @return Nr. of Minutes the timer is set for. 0, is the timer is not in use. +uint16_t IRMirageAc::getOnTimer(void) const { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + return _.OnTimerEnable ? _.OnTimerHours * 60 + _.OnTimerMins : 0; + default: + return 0; + } +} + +/// Set the number of minutes for the On Timer. +/// @param[in] nr_of_mins How long to set the timer for. 0 disables the timer. +void IRMirageAc::setOnTimer(const uint16_t nr_of_mins) { + uint16_t mins = std::min(nr_of_mins, (uint16_t)(24 * 60)); + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + _.OnTimerEnable = (mins > 0); + _.OnTimerHours = mins / 60; + _.OnTimerMins = mins % 60; + break; + default: + break; + } +} + +/// Get the number of minutes the Off Timer is currently set for. +/// @return Nr. of Minutes the timer is set for. 0, is the timer is not in use. +uint16_t IRMirageAc::getOffTimer(void) const { + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + return _.OffTimerEnable ? _.OffTimerHours * 60 + _.OffTimerMins : 0; + default: + return 0; + } +} + +/// Set the number of minutes for the Off Timer. +/// @param[in] nr_of_mins How long to set the timer for. 0 disables the timer. +void IRMirageAc::setOffTimer(const uint16_t nr_of_mins) { + uint16_t mins = std::min(nr_of_mins, (uint16_t)(24 * 60)); + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + _.OffTimerEnable = (mins > 0); + _.OffTimerHours = mins / 60; + _.OffTimerMins = mins % 60; + break; + default: + break; + } +} + +/// Convert a native mode into its stdAc equivalent. +/// @param[in] mode The native setting to be converted. +/// @return The stdAc equivalent of the native setting. +stdAc::opmode_t IRMirageAc::toCommonMode(const uint8_t mode) { + switch (mode) { + case kMirageAcHeat: return stdAc::opmode_t::kHeat; + case kMirageAcDry: return stdAc::opmode_t::kDry; + case kMirageAcFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kCool; + } +} + +/// Convert a native fan speed into its stdAc equivalent. +/// @param[in] speed The native setting to be converted. +/// @param[in] model The model type to use to influence the conversion. +/// @return The stdAc equivalent of the native setting. +stdAc::fanspeed_t IRMirageAc::toCommonFanSpeed(const uint8_t speed, + const mirage_ac_remote_model_t model) { + switch (model) { + case mirage_ac_remote_model_t::KKG29AC1: + switch (speed) { + case kMirageAcKKG29AC1FanHigh: return stdAc::fanspeed_t::kHigh; + case kMirageAcKKG29AC1FanMed: return stdAc::fanspeed_t::kMedium; + case kMirageAcKKG29AC1FanLow: return stdAc::fanspeed_t::kLow; + default: return stdAc::fanspeed_t::kAuto; + } + break; + default: + switch (speed) { + case kMirageAcFanHigh: return stdAc::fanspeed_t::kHigh; + case kMirageAcFanMed: return stdAc::fanspeed_t::kMedium; + case kMirageAcFanLow: return stdAc::fanspeed_t::kLow; + default: return stdAc::fanspeed_t::kAuto; + } + } +} + +/// Convert a stdAc::opmode_t enum into its native mode. +/// @param[in] mode The enum to be converted. +/// @return The native equivalent of the enum. +uint8_t IRMirageAc::convertMode(const stdAc::opmode_t mode) { + switch (mode) { + case stdAc::opmode_t::kHeat: return kMirageAcHeat; + case stdAc::opmode_t::kDry: return kMirageAcDry; + case stdAc::opmode_t::kFan: return kMirageAcFan; + default: return kMirageAcCool; + } +} + +/// Convert a stdAc::fanspeed_t enum into it's native speed. +/// @param[in] speed The enum to be converted. +/// @param[in] model The model type to use to influence the conversion. +/// @return The native equivalent of the enum. +uint8_t IRMirageAc::convertFan(const stdAc::fanspeed_t speed, + const mirage_ac_remote_model_t model) { + uint8_t low; + uint8_t med; + switch (model) { + case mirage_ac_remote_model_t::KKG29AC1: + low = kMirageAcKKG29AC1FanLow; + med = kMirageAcKKG29AC1FanMed; + break; + default: + low = kMirageAcFanLow; + med = kMirageAcFanMed; + } + switch (speed) { + case stdAc::fanspeed_t::kMin: + case stdAc::fanspeed_t::kLow: return low; + case stdAc::fanspeed_t::kMedium: return med; + case stdAc::fanspeed_t::kHigh: + case stdAc::fanspeed_t::kMax: return kMirageAcFanHigh; + default: return kMirageAcFanAuto; + } +} + +/// Convert a stdAc::swingv_t enum into it's native setting. +/// @param[in] position The enum to be converted. +/// @return The native equivalent of the enum. +uint8_t IRMirageAc::convertSwingV(const stdAc::swingv_t position) { + switch (position) { + case stdAc::swingv_t::kHighest: return kMirageAcSwingVHighest; + case stdAc::swingv_t::kHigh: return kMirageAcSwingVHigh; + case stdAc::swingv_t::kMiddle: return kMirageAcSwingVMiddle; + case stdAc::swingv_t::kLow: return kMirageAcSwingVLow; + case stdAc::swingv_t::kLowest: return kMirageAcSwingVLowest; + case stdAc::swingv_t::kOff: return kMirageAcSwingVOff; + default: return kMirageAcSwingVAuto; + } +} + +/// Convert a native vertical swing postion to it's common equivalent. +/// @param[in] pos A native position to convert. +/// @return The common vertical swing position. +stdAc::swingv_t IRMirageAc::toCommonSwingV(const uint8_t pos) { + switch (pos) { + case kMirageAcSwingVHighest: return stdAc::swingv_t::kHighest; + case kMirageAcSwingVHigh: return stdAc::swingv_t::kHigh; + case kMirageAcSwingVMiddle: return stdAc::swingv_t::kMiddle; + case kMirageAcSwingVLow: return stdAc::swingv_t::kLow; + case kMirageAcSwingVLowest: return stdAc::swingv_t::kLowest; + case kMirageAcSwingVAuto: return stdAc::swingv_t::kAuto; + default: return stdAc::swingv_t::kOff; + } +} + +/// Convert the current internal state into its stdAc::state_t equivalent. +/// @return The stdAc equivalent of the native settings. +stdAc::state_t IRMirageAc::toCommon(void) const { + stdAc::state_t result; + result.protocol = decode_type_t::MIRAGE; + result.model = _model; + result.power = getPower(); + result.mode = toCommonMode(_.Mode); + result.celsius = true; + result.degrees = getTemp(); + result.fanspeed = toCommonFanSpeed(getFan(), _model); + result.swingv = toCommonSwingV(getSwingV()); + result.swingh = getSwingH() ? stdAc::swingh_t::kAuto : stdAc::swingh_t::kOff; + result.turbo = getTurbo(); + result.light = getLight(); + result.clean = getCleanToggle(); + result.filter = getFilter(); + result.sleep = getSleep() ? 0 : -1; + result.quiet = getQuiet(); + result.clock = getClock() / 60; + // Not supported. + result.econo = false; + result.beep = false; + return result; +} + +/// Convert & set a stdAc::state_t to its equivalent internal settings. +/// @param[in] state The desired state in stdAc::state_t form. +void IRMirageAc::fromCommon(const stdAc::state_t state) { + stateReset(); + _model = (mirage_ac_remote_model_t)state.model; // Set directly to avoid loop + setPower(state.power); + setTemp(state.celsius ? state.degrees : fahrenheitToCelsius(state.degrees)); + setMode(convertMode(state.mode)); + setFan(convertFan(state.fanspeed, _model)); + setTurbo(state.turbo); + setSleep(state.sleep >= 0); + setLight(state.light); + setSwingV(convertSwingV(state.swingv)); + setSwingH(state.swingh != stdAc::swingh_t::kOff); + setQuiet(state.quiet); + setCleanToggle(state.clean); + setFilter(state.filter); + // setClock() expects seconds, not minutes. + setClock((state.clock > 0) ? state.clock * 60 : 0); + // Non-common settings. + setOnTimer(0); + setOffTimer(0); + setIFeel(false); +} + +/// Convert the internal state into a human readable string. +/// @return A string containing the settings in human-readable form. +String IRMirageAc::toString(void) const { + String result = ""; + result.reserve(240); // Reserve some heap for the string to reduce fragging. + result += addModelToString(decode_type_t::MIRAGE, _model, false); + result += addBoolToString(getPower(), kPowerStr); + result += addModeToString(_.Mode, 0xFF, kMirageAcCool, + kMirageAcHeat, kMirageAcDry, + kMirageAcFan); + result += addTempToString(getTemp()); + uint8_t fanlow; + uint8_t fanmed; + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + fanlow = kMirageAcKKG29AC1FanLow; + fanmed = kMirageAcKKG29AC1FanMed; + break; + default: // e.g. Model KKG9AC1 + fanlow = kMirageAcFanLow; + fanmed = kMirageAcFanMed; + } + result += addFanToString(_.Fan, kMirageAcFanHigh, fanlow, kMirageAcFanAuto, + kMirageAcFanAuto, fanmed); + result += addBoolToString(getTurbo(), kTurboStr); + result += addBoolToString(getSleep(), kSleepStr); + switch (_model) { + case mirage_ac_remote_model_t::KKG29AC1: + result += addBoolToString(_.Quiet, kQuietStr); + result += addToggleToString(getLight(), kLightStr); + result += addBoolToString(_.SwingV, kSwingVStr); + result += addBoolToString(_.SwingH, kSwingHStr); + result += addBoolToString(_.Filter, kFilterStr); + result += addToggleToString(_.CleanToggle, kCleanStr); + result += addLabeledString(getOnTimer() ? minsToString(getOnTimer()) + : kOffStr, + kOnTimerStr); + result += addLabeledString(getOffTimer() ? minsToString(getOffTimer()) + : kOffStr, + kOffTimerStr); + result += addBoolToString(_.IFeel, kIFeelStr); + if (_.IFeel) { + result += addIntToString(getSensorTemp(), kSensorTempStr); + result += 'C'; + } + break; + default: // e.g. Model KKG9AC1 + result += addBoolToString(getLight(), kLightStr); + result += addSwingVToString(getSwingV(), + kMirageAcSwingVAuto, + kMirageAcSwingVHighest, + kMirageAcSwingVHigh, + 0xFF, // Unused. + kMirageAcSwingVMiddle, + 0xFF, // Unused. + kMirageAcSwingVLow, + kMirageAcSwingVLowest, + kMirageAcSwingVOff, + 0xFF, 0xFF, 0xFF); // Unused. + result += addLabeledString(minsToString(getClock() / 60), kClockStr); + } + return result; +} #endif // DECODE_MIRAGE diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mirage.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mirage.h new file mode 100644 index 000000000..b2b39e759 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mirage.h @@ -0,0 +1,277 @@ +// Copyright 2020-2021 David Conran (crankyoldgit) +/// @file +/// @brief Support for Mirage protocol +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1289 +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1573 + + +// Supports: +// Brand: Mirage, Model: VLU series A/C +// Brand: Maxell, Model: MX-CH18CF A/C +// Brand: Maxell, Model: KKG9A-C1 remote +// Brand: Tronitechnik, Model: Reykir 9000 A/C +// Brand: Tronitechnik, Model: KKG29A-C1 remote + +#ifndef IR_MIRAGE_H_ +#define IR_MIRAGE_H_ + +#define __STDC_LIMIT_MACROS +#include +#ifndef UNIT_TEST +#include +#endif +#include "IRremoteESP8266.h" +#include "IRsend.h" +#ifdef UNIT_TEST +#include "IRsend_test.h" +#endif + +/// Native representation of a Mirage 120-bit A/C message. +/// @see https://docs.google.com/spreadsheets/d/1Ucu9mOOIIJoWQjUJq_VCvwgV3EwKaRk8K2AuZgccYEk/edit#gid=0 +union Mirage120Protocol{ + uint8_t raw[kMirageStateLength]; ///< The state in code form. + struct { // Common + // Byte 0 + uint8_t Header :8; // Header. (0x56) + // Byte 1 + uint8_t Temp :8; // Celsius minus 0x5C. + // Byte 2 + uint8_t :8; // Unknown / Unused. + // Byte 3 + uint8_t :8; // Unknown / Unused. + // Byte 4 + uint8_t Fan :2; // Fan Speed. + uint8_t :2; // Unknown / Unused. + uint8_t Mode :4; // Cool, Heat, Dry, Fan, Recycle + // Byte 5 + uint8_t :8; + // Byte 6 + uint8_t :8; + // Byte 7 + uint8_t :8; + // Byte 8 + uint8_t :8; + // Byte 9 + uint8_t :8; + // Byte 10 + uint8_t :8; + // Byte 11 + uint8_t :8; + // Byte 12 + uint8_t :8; + // Byte 13 + uint8_t :8; + // Byte 14 + uint8_t Sum :8; // Sum of all the previous nibbles. + }; + struct { // KKG9AC1 remote + // Byte 0 + uint8_t :8; // Header + // Byte 1 + uint8_t :8; // Temp + // Byte 2 + uint8_t :8; // Unknown / Unused. + // Byte 3 + uint8_t :3; // Unknown / Unused. + uint8_t Light_Kkg9ac1 :1; // Aka. Display. Seems linked to Sleep mode. + uint8_t :4; // Unknown / Unused. + // Byte 4 + uint8_t :8; // Fan & Mode + // Byte 5 + uint8_t :1; // Unknown + uint8_t SwingAndPower :7; + // Byte 6 + uint8_t :7; // Unknown / Unused. + uint8_t Sleep_Kkg9ac1 :1; // Sleep mode on or off. + // Byte 7 + uint8_t :3; // Unknown / Unused. + uint8_t Turbo_Kkg9ac1 :1; // Turbo mode on or off. Only works in Cool mode. + uint8_t :4; // Unknown / Unused. + // Byte 8 + uint8_t :8; // Unknown / Unused. + // Byte 9 + uint8_t :8; // Unknown / Unused. + // Byte 10 + uint8_t :8; // Unknown / Unused. + // Byte 11 + uint8_t Seconds :8; // Nr. of Seconds in BCD. + // Byte 12 + uint8_t Minutes :8; // Nr. of Minutes in BCD. + // Byte 13 + uint8_t Hours :8; // Nr. of Hours in BCD. + // Byte 14 + uint8_t :8; // Sum + }; + struct { // KKG29A-C1 remote + // Byte 0 + uint8_t :8; // Header + // Byte 1 + uint8_t :8; // Temp + // Byte 2 + uint8_t :8; + // Byte 3 + uint8_t Quiet :1; + uint8_t :7; + // Byte 4 + uint8_t :2; // Fan + uint8_t OffTimerEnable :1; + uint8_t OnTimerEnable :1; + uint8_t :3; // Mode + uint8_t :1; + // Byte 5 + uint8_t SwingH :1; + uint8_t SwingV :1; + uint8_t LightToggle_Kkg29ac1 :1; // Aka. Display Toggle. + uint8_t :3; + uint8_t Power :2; + // Byte 6 + uint8_t :1; + uint8_t Filter :1; // Aka. UVC + uint8_t :1; + uint8_t Sleep_Kkg29ac1 :1; // Sleep mode on or off. + uint8_t :2; + uint8_t RecycleHeat :1; + uint8_t :1; + // Byte 7 + uint8_t SensorTemp :6; // Temperature at the remote + uint8_t CleanToggle :1; + uint8_t IFeel :1; + // Byte 8 + uint8_t OnTimerHours :5; + uint8_t :2; + uint8_t Turbo_Kkg29ac1 :1; // Turbo mode on or off. + // Byte 9 + uint8_t OnTimerMins :6; + uint8_t :2; + // Byte 10 + uint8_t OffTimerHours :5; + uint8_t :3; + // Byte 11 + uint8_t OffTimerMins :6; + uint8_t :2; + // Byte 12 + uint8_t :8; + // Byte 13 + uint8_t :8; + // Byte 14 + uint8_t :8; // Sum + }; +}; + +// Constants +const uint8_t kMirageAcHeat = 0b001; // 1 +const uint8_t kMirageAcCool = 0b010; // 2 +const uint8_t kMirageAcDry = 0b011; // 3 +const uint8_t kMirageAcRecycle = 0b100; // 4 +const uint8_t kMirageAcFan = 0b101; // 5 + +const uint8_t kMirageAcFanAuto = 0b00; // 0 +const uint8_t kMirageAcFanHigh = 0b01; // 1 +const uint8_t kMirageAcFanMed = 0b10; // 2 +const uint8_t kMirageAcFanLow = 0b11; // 3 +const uint8_t kMirageAcKKG29AC1FanAuto = 0b00; // 0 +const uint8_t kMirageAcKKG29AC1FanHigh = 0b01; // 1 +const uint8_t kMirageAcKKG29AC1FanLow = 0b10; // 2 +const uint8_t kMirageAcKKG29AC1FanMed = 0b11; // 3 + +const uint8_t kMirageAcMinTemp = 16; // 16C +const uint8_t kMirageAcMaxTemp = 32; // 32C +const uint8_t kMirageAcTempOffset = 0x5C; +const uint8_t kMirageAcSensorTempOffset = 20; +const uint8_t kMirageAcSensorTempMax = 43; // Celsius + +const uint8_t kMirageAcPowerOff = 0x5F; +const uint8_t kMirageAcSwingVOff = 0b0000; // 0 +const uint8_t kMirageAcSwingVLowest = 0b0011; // 3 +const uint8_t kMirageAcSwingVLow = 0b0101; // 5 +const uint8_t kMirageAcSwingVMiddle = 0b0111; // 7 +const uint8_t kMirageAcSwingVHigh = 0b1001; // 9 +const uint8_t kMirageAcSwingVHighest = 0b1011; // 11 +const uint8_t kMirageAcSwingVAuto = 0b1101; // 13 + + +/// Class for handling detailed Mirage 120-bit A/C messages. +/// @note Inspired and derived from the work done at: https://github.com/r45635/HVAC-IR-Control +/// @warning Consider this very alpha code. Seems to work, but not validated. +class IRMirageAc { + public: + explicit IRMirageAc(const uint16_t pin, const bool inverted = false, + const bool use_modulation = true); + void stateReset(void); +#if SEND_MIRAGE + void send(const uint16_t repeat = kMirageMinRepeat); + /// Run the calibration to calculate uSec timing offsets for this platform. + /// @return The uSec timing offset needed per modulation of the IR Led. + /// @note This will produce a 65ms IR signal pulse at 38kHz. + /// Only ever needs to be run once per object instantiation, if at all. + int8_t calibrate(void) { return _irsend.calibrate(); } +#endif // SEND_MIRAGE + void begin(void); + void on(void); + void off(void); + void setPower(const bool on); + bool getPower(void) const; + void setTemp(const uint8_t degrees); + uint8_t getTemp(void) const; + void setFan(const uint8_t speed); + uint8_t getFan(void) const; + void setMode(const uint8_t mode); + uint8_t getMode(void) const; + uint8_t* getRaw(void); + void setRaw(const uint8_t* data); + uint32_t getClock(void) const; + void setClock(const uint32_t nr_of_seconds); + void setTurbo(const bool on); + bool getTurbo(void) const; + void setLight(const bool on); + bool getLight(void) const; + void setSleep(const bool on); + bool getSleep(void) const; + void setSwingV(const uint8_t position); + uint8_t getSwingV(void) const; + void setSwingH(const bool on); + bool getSwingH(void) const; + void setQuiet(const bool on); + bool getQuiet(void) const; + void setCleanToggle(const bool on); + bool getCleanToggle(void) const; + void setFilter(const bool on); + bool getFilter(void) const; + void setIFeel(const bool on); + bool getIFeel(void) const; + void setSensorTemp(const uint8_t degrees); + uint16_t getSensorTemp(void) const; + uint16_t getOnTimer(void) const; + uint16_t getOffTimer(void) const; + void setOnTimer(const uint16_t nr_of_mins); + void setOffTimer(const uint16_t nr_of_mins); + mirage_ac_remote_model_t getModel(const bool useRaw = false) const; + void setModel(const mirage_ac_remote_model_t model); + static mirage_ac_remote_model_t getModel(const uint8_t *state); + static bool validChecksum(const uint8_t* data); + static uint8_t calculateChecksum(const uint8_t* data); + static uint8_t convertMode(const stdAc::opmode_t mode); + static uint8_t convertFan(const stdAc::fanspeed_t speed, + const mirage_ac_remote_model_t model = mirage_ac_remote_model_t::KKG9AC1); + static uint8_t convertSwingV(const stdAc::swingv_t position); + static stdAc::opmode_t toCommonMode(const uint8_t mode); + static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed, + const mirage_ac_remote_model_t model = mirage_ac_remote_model_t::KKG9AC1); + static stdAc::swingv_t toCommonSwingV(const uint8_t pos); + stdAc::state_t toCommon(void) const; + void fromCommon(const stdAc::state_t state); + String toString(void) const; +#ifndef UNIT_TEST + + private: + IRsend _irsend; ///< Instance of the IR send class +#else // UNIT_TEST + /// @cond IGNORE + IRsendTest _irsend; ///< Instance of the testing IR send class + /// @endcond +#endif // UNIT_TEST + Mirage120Protocol _; + mirage_ac_remote_model_t _model; + void checksum(void); +}; +#endif // IR_MIRAGE_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mitsubishi.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mitsubishi.cpp index 03e562ef5..160a882bf 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mitsubishi.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Mitsubishi.cpp @@ -1166,7 +1166,7 @@ void IRsend::sendMitsubishi112(const unsigned char data[], } #endif // SEND_MITSUBISHI112 -#if DECODE_MITSUBISHI112 || DECODE_TCL112AC +#if (DECODE_MITSUBISHI112 || DECODE_TCL112AC) /// Decode the supplied Mitsubishi/TCL 112-bit A/C message. /// (MITSUBISHI112, TCL112AC) /// Status: STABLE / Reported as working. @@ -1212,7 +1212,7 @@ bool IRrecv::decodeMitsubishi112(decode_results *results, uint16_t offset, gap = kMitsubishi112Gap; } #endif // DECODE_MITSUBISHI112 -#if DECODE_TCL112AC +#if (DECODE_TCL112AC || DECODE_TEKNOPOINT) if (typeguess == decode_type_t::UNKNOWN && // We didn't match Mitsubishi112 matchMark(results->rawbuf[offset], kTcl112AcHdrMark, kTcl112AcHdrMarkTolerance, 0)) { @@ -1224,7 +1224,7 @@ bool IRrecv::decodeMitsubishi112(decode_results *results, uint16_t offset, gap = kTcl112AcGap; tolerance += kTcl112AcTolerance; } -#endif // DECODE_TCL112AC +#endif // (DECODE_TCL112AC || DECODE_TEKNOPOINT) if (typeguess == decode_type_t::UNKNOWN) return false; // No header matched. offset++; diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Rhoss.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Rhoss.cpp new file mode 100644 index 000000000..f906f49be --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Rhoss.cpp @@ -0,0 +1,364 @@ +// Copyright 2021 Tom Rosenback + +/// @file +/// @brief Support for Rhoss protocols. + +#include "ir_Rhoss.h" +#include +#include +#include "IRrecv.h" +#include "IRsend.h" +#include "IRtext.h" +#include "IRutils.h" + +const uint16_t kRhossHdrMark = 3042; +const uint16_t kRhossHdrSpace = 4248; +const uint16_t kRhossBitMark = 648; +const uint16_t kRhossOneSpace = 1545; +const uint16_t kRhossZeroSpace = 457; +const uint32_t kRhossGap = kDefaultMessageGap; +const uint16_t kRhossFreq = 38; + +using irutils::addBoolToString; +using irutils::addModeToString; +using irutils::addFanToString; +using irutils::addTempToString; + +#if SEND_RHOSS +/// Send a Rhoss HVAC formatted message. +/// Status: STABLE / Reported as working. +/// @param[in] data The message to be sent. +/// @param[in] nbytes The number of bytes of message to be sent. +/// @param[in] repeat The number of times the command is to be repeated. +void IRsend::sendRhoss(const unsigned char data[], const uint16_t nbytes, + const uint16_t repeat) { + // Check if we have enough bytes to send a proper message. + if (nbytes < kRhossStateLength) return; + + // We always send a message, even for repeat=0, hence '<= repeat'. + for (uint16_t r = 0; r <= repeat; r++) { + sendGeneric(kRhossHdrMark, kRhossHdrSpace, kRhossBitMark, + kRhossOneSpace, kRhossBitMark, kRhossZeroSpace, + kRhossBitMark, kRhossZeroSpace, + data, nbytes, kRhossFreq, false, 0, kDutyDefault); + mark(kRhossBitMark); + // Gap + space(kRhossGap); + } +} +#endif // SEND_RHOSS + +#if DECODE_RHOSS +/// Decode the supplied Rhoss formatted message. +/// Status: STABLE / Known working. +/// @param[in,out] results Ptr to the data to decode & where to store the result +/// @param[in] offset The starting index to use when attempting to decode the +/// raw data. Typically/Defaults to kStartOffset. +/// @param[in] nbits The number of data bits to expect. +/// @param[in] strict Flag indicating if we should perform strict matching. +bool IRrecv::decodeRhoss(decode_results *results, uint16_t offset, + const uint16_t nbits, const bool strict) { + if (strict && nbits != kRhossBits) return false; + + if (results->rawlen <= 2 * nbits + kHeader + kFooter - 1 + offset) { + return false; // Can't possibly be a valid Rhoss message. + } + + uint16_t used; + // Header + Data Block (96 bits) + Footer + used = matchGeneric(results->rawbuf + offset, results->state, + results->rawlen - offset, kRhossBits, + kRhossHdrMark, kRhossHdrSpace, + kRhossBitMark, kRhossOneSpace, + kRhossBitMark, kRhossZeroSpace, + kRhossBitMark, kRhossZeroSpace, + false, kUseDefTol, kMarkExcess, false); + + if (!used) return false; + offset += used; + + // Footer (Part 2) + if (!matchMark(results->rawbuf[offset++], kRhossBitMark)) { + return false; + } + + if (offset < results->rawlen && + !matchAtLeast(results->rawbuf[offset], kRhossGap)) { + return false; + } + + if (strict && !IRRhossAc::validChecksum(results->state)) return false; + + // Success + results->decode_type = decode_type_t::RHOSS; + results->bits = nbits; + // No need to record the state as we stored it as we decoded it. + // As we use result->state, we don't record value, address, or command as it + // is a union data type. + return true; +} + +#endif // DECODE_RHOSS + +/// Class constructor +/// @param[in] pin GPIO to be used when sending. +/// @param[in] inverted Is the output signal to be inverted? +/// @param[in] use_modulation Is frequency modulation to be used? +IRRhossAc::IRRhossAc(const uint16_t pin, const bool inverted, + const bool use_modulation) + : _irsend(pin, inverted, use_modulation) { this->stateReset(); } + +/// Set up hardware to be able to send a message. +void IRRhossAc::begin(void) { _irsend.begin(); } + +#if SEND_RHOSS +/// Send the current internal state as an IR message. +/// @param[in] repeat Nr. of times the message will be repeated. +void IRRhossAc::send(const uint16_t repeat) { + _irsend.sendRhoss(getRaw(), kRhossStateLength, repeat); +} +#endif // SEND_RHOSS + +/// Calculate the checksum for the supplied state. +/// @param[in] state The source state to generate the checksum from. +/// @param[in] length Length of the supplied state to checksum. +/// @return The checksum value. +uint8_t IRRhossAc::calcChecksum(const uint8_t state[], const uint16_t length) { + return sumBytes(state, length - 1); +} + +/// Verify the checksum is valid for a given state. +/// @param[in] state The array to verify the checksum of. +/// @param[in] length The size of the state. +/// @return A boolean indicating if it's checksum is valid. +bool IRRhossAc::validChecksum(const uint8_t state[], const uint16_t length) { + return (state[length - 1] == IRRhossAc::calcChecksum(state, length)); +} + +/// Update the checksum value for the internal state. +void IRRhossAc::checksum(void) { + _.Sum = IRRhossAc::calcChecksum(_.raw, kRhossStateLength); + _.raw[kRhossStateLength - 1] = _.Sum; +} + +/// Reset the internals of the object to a known good state. +void IRRhossAc::stateReset(void) { + for (uint8_t i = 1; i < kRhossStateLength; i++) _.raw[i] = 0x0; + _.raw[0] = 0xAA; + _.raw[2] = 0x60; + _.raw[6] = 0x54; + _.Power = kRhossDefaultPower; + _.Fan = kRhossDefaultFan; + _.Mode = kRhossDefaultMode; + _.Swing = kRhossDefaultSwing; + _.Temp = kRhossDefaultTemp - kRhossTempMin; +} + +/// Get the raw state of the object, suitable to be sent with the appropriate +/// IRsend object method. +/// @return A PTR to the internal state. +uint8_t* IRRhossAc::getRaw(void) { + checksum(); // Ensure correct bit array before returning + return _.raw; +} + +/// Set the raw state of the object. +/// @param[state] state The raw state from the native IR message. +void IRRhossAc::setRaw(const uint8_t state[]) { + std::memcpy(_.raw, state, kRhossStateLength); +} + +/// Set the internal state to have the power on. +void IRRhossAc::on(void) { setPower(true); } + +/// Set the internal state to have the power off. +void IRRhossAc::off(void) { setPower(false); } + +/// Set the internal state to have the desired power. +/// @param[in] on The desired power state. +void IRRhossAc::setPower(const bool on) { + _.Power = (on ? kRhossPowerOn : kRhossPowerOff); +} + +/// Get the power setting from the internal state. +/// @return A boolean indicating the power setting. +bool IRRhossAc::getPower(void) const { + return _.Power == kRhossPowerOn; +} + +/// Set the temperature. +/// @param[in] degrees The temperature in degrees celsius. +void IRRhossAc::setTemp(const uint8_t degrees) { + uint8_t temp = std::max(kRhossTempMin, degrees); + _.Temp = std::min(kRhossTempMax, temp) - kRhossTempMin; +} + +/// Get the current temperature setting. +/// @return Get current setting for temp. in degrees celsius. +uint8_t IRRhossAc::getTemp(void) const { + return _.Temp + kRhossTempMin; +} + +/// Set the speed of the fan. +/// @param[in] speed The desired setting. +void IRRhossAc::setFan(const uint8_t speed) { + switch (speed) { + case kRhossFanAuto: + case kRhossFanMin: + case kRhossFanMed: + case kRhossFanMax: + _.Fan = speed; + break; + default: + _.Fan = kRhossFanAuto; + } +} + +/// Get the current fan speed setting. +/// @return The current fan speed. +uint8_t IRRhossAc::getFan(void) const { + return _.Fan; +} + +/// Set the Vertical Swing mode of the A/C. +/// @param[in] state true, the Swing is on. false, the Swing is off. +void IRRhossAc::setSwing(const bool state) { + _.Swing = state; +} + +/// Get the Vertical Swing speed of the A/C. +/// @return The native swing speed setting. +uint8_t IRRhossAc::getSwing(void) const { + return _.Swing; +} + +/// Get the current operation mode setting. +/// @return The current operation mode. +uint8_t IRRhossAc::getMode(void) const { + return _.Mode; +} + +/// Set the desired operation mode. +/// @param[in] mode The desired operation mode. +void IRRhossAc::setMode(const uint8_t mode) { + switch (mode) { + case kRhossModeFan: + case kRhossModeCool: + case kRhossModeDry: + case kRhossModeHeat: + case kRhossModeAuto: + _.Mode = mode; + return; + default: + _.Mode = kRhossDefaultMode; + break; + } +} + +/// Convert a stdAc::opmode_t enum into its native mode. +/// @param[in] mode The enum to be converted. +/// @return The native equivalent of the enum. +uint8_t IRRhossAc::convertMode(const stdAc::opmode_t mode) { + switch (mode) { + case stdAc::opmode_t::kCool: + return kRhossModeCool; + case stdAc::opmode_t::kHeat: + return kRhossModeHeat; + case stdAc::opmode_t::kDry: + return kRhossModeDry; + case stdAc::opmode_t::kFan: + return kRhossModeFan; + case stdAc::opmode_t::kAuto: + return kRhossModeAuto; + default: + return kRhossDefaultMode; + } +} + +/// Convert a stdAc::fanspeed_t enum into it's native speed. +/// @param[in] speed The enum to be converted. +/// @return The native equivalent of the enum. +uint8_t IRRhossAc::convertFan(const stdAc::fanspeed_t speed) { + switch (speed) { + case stdAc::fanspeed_t::kMin: + case stdAc::fanspeed_t::kLow: + return kRhossFanMin; + case stdAc::fanspeed_t::kMedium: + return kRhossFanMed; + case stdAc::fanspeed_t::kHigh: + case stdAc::fanspeed_t::kMax: + return kRhossFanMax; + default: + return kRhossDefaultFan; + } +} + +/// Convert a native mode into its stdAc equivalent. +/// @param[in] mode The native setting to be converted. +/// @return The stdAc equivalent of the native setting. +stdAc::opmode_t IRRhossAc::toCommonMode(const uint8_t mode) { + switch (mode) { + case kRhossModeCool: return stdAc::opmode_t::kCool; + case kRhossModeHeat: return stdAc::opmode_t::kHeat; + case kRhossModeDry: return stdAc::opmode_t::kDry; + case kRhossModeFan: return stdAc::opmode_t::kFan; + case kRhossModeAuto: return stdAc::opmode_t::kAuto; + default: return stdAc::opmode_t::kAuto; + } +} + +/// Convert a native fan speed into its stdAc equivalent. +/// @param[in] speed The native setting to be converted. +/// @return The stdAc equivalent of the native setting. +stdAc::fanspeed_t IRRhossAc::toCommonFanSpeed(const uint8_t speed) { + switch (speed) { + case kRhossFanMax: return stdAc::fanspeed_t::kMax; + case kRhossFanMed: return stdAc::fanspeed_t::kMedium; + case kRhossFanMin: return stdAc::fanspeed_t::kMin; + case kRhossFanAuto: + default: + return stdAc::fanspeed_t::kAuto; + } +} + +/// Convert the current internal state into its stdAc::state_t equivalent. +/// @return The stdAc equivalent of the native settings. +stdAc::state_t IRRhossAc::toCommon(void) const { + stdAc::state_t result; + result.protocol = decode_type_t::RHOSS; + result.power = getPower(); + result.mode = toCommonMode(_.Mode); + result.celsius = true; + result.degrees = _.Temp; + result.fanspeed = toCommonFanSpeed(_.Fan); + result.swingv = _.Swing ? stdAc::swingv_t::kAuto : stdAc::swingv_t::kOff; + // Not supported. + result.model = -1; + result.turbo = false; + result.swingh = stdAc::swingh_t::kOff; + result.light = false; + result.filter = false; + result.econo = false; + result.quiet = false; + result.clean = false; + result.beep = false; + result.sleep = -1; + result.clock = -1; + return result; +} + +/// Convert the current internal state into a human readable string. +/// @return A human readable string. +String IRRhossAc::toString(void) const { + String result = ""; + result.reserve(70); // Reserve some heap for the string to reduce fragging. + result += addBoolToString(getPower(), kPowerStr, false); + result += addModeToString(getMode(), kRhossModeAuto, kRhossModeCool, + kRhossModeHeat, kRhossModeDry, kRhossModeFan); + result += addTempToString(getTemp()); + result += addFanToString(getFan(), kRhossFanMax, kRhossFanMin, + kRhossFanAuto, kRhossFanAuto, + kRhossFanMed); + result += addBoolToString(getSwing(), kSwingVStr); + return result; +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Rhoss.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Rhoss.h new file mode 100644 index 000000000..8f66ce738 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Rhoss.h @@ -0,0 +1,145 @@ +// Copyright 2021 Tom Rosenback + +/// @file +/// @brief Support for Rhoss A/C protocol +// Supports: +// Brand: Rhoss, Model: Idrowall MPCV 20-30-35-40 + +#ifndef IR_RHOSS_H_ +#define IR_RHOSS_H_ + +#define __STDC_LIMIT_MACROS +#include +#ifndef UNIT_TEST +#include +#endif +#include "IRremoteESP8266.h" +#include "IRsend.h" +#ifdef UNIT_TEST +#include "IRsend_test.h" +#endif + + +/// Native representation of a Rhoss A/C message. +union RhossProtocol{ + uint8_t raw[kRhossStateLength]; // The state of the IR remote. + struct { + // Byte 0 + uint8_t :8; // Typically 0xAA + // Byte 1 + uint8_t Temp :4; + uint8_t :4; // Typically 0x0 + // Byte 2 + uint8_t :8; // Typically 0x60 + // Byte 3 + uint8_t :8; // Typically 0x0 + // Byte 4 + uint8_t Fan :2; + uint8_t :2; // Typically 0x0 + uint8_t Mode :4; + // Byte 5 + uint8_t Swing :1; + uint8_t :5; // Typically 0x0 + uint8_t Power :2; + // Byte 6 + uint8_t :8; // Typically 0x54 + // Byte 7 + uint8_t :8; // Typically 0x0 + // Byte 8 + uint8_t :8; // Typically 0x0 + // Byte 9 + uint8_t :8; // Typically 0x0 + // Byte 10 + uint8_t :8; // Typically 0x0 + // Byte 11 + uint8_t Sum :8; + }; +}; + +// Constants + +// Fan Control +const uint8_t kRhossFanAuto = 0b00; +const uint8_t kRhossFanMin = 0b01; +const uint8_t kRhossFanMed = 0b10; +const uint8_t kRhossFanMax = 0b11; +// Modes +const uint8_t kRhossModeHeat = 0b0001; +const uint8_t kRhossModeCool = 0b0010; +const uint8_t kRhossModeDry = 0b0011; +const uint8_t kRhossModeFan = 0b0100; +const uint8_t kRhossModeAuto = 0b0101; + +// Temperature +const uint8_t kRhossTempMin = 16; // Celsius +const uint8_t kRhossTempMax = 30; // Celsius + +// Power +const uint8_t kRhossPowerOn = 0b10; // 0x2 +const uint8_t kRhossPowerOff = 0b01; // 0x1 + +// Swing +const uint8_t kRhossSwingOn = 0b1; // 0x1 +const uint8_t kRhossSwingOff = 0b0; // 0x0 + +const uint8_t kRhossDefaultFan = kRhossFanAuto; +const uint8_t kRhossDefaultMode = kRhossModeCool; +const uint8_t kRhossDefaultTemp = 21; // Celsius +const bool kRhossDefaultPower = false; +const bool kRhossDefaultSwing = false; + +// Classes + +/// Class for handling detailed Rhoss A/C messages. +class IRRhossAc { + public: + explicit IRRhossAc(const uint16_t pin, const bool inverted = false, + const bool use_modulation = true); + + void stateReset(); +#if SEND_RHOSS + void send(const uint16_t repeat = kRhossDefaultRepeat); + /// Run the calibration to calculate uSec timing offsets for this platform. + /// @return The uSec timing offset needed per modulation of the IR Led. + /// @note This will produce a 65ms IR signal pulse at 38kHz. + /// Only ever needs to be run once per object instantiation, if at all. + int8_t calibrate(void) { return _irsend.calibrate(); } +#endif // SEND_RHOSS + void begin(); + static uint8_t calcChecksum(const uint8_t state[], + const uint16_t length = kRhossStateLength); + static bool validChecksum(const uint8_t state[], + const uint16_t length = kRhossStateLength); + void setPower(const bool state); + bool getPower(void) const; + void on(void); + void off(void); + void setTemp(const uint8_t temp); + uint8_t getTemp(void) const; + void setFan(const uint8_t speed); + uint8_t getFan(void) const; + void setSwing(const bool state); + uint8_t getSwing(void) const; + void setMode(const uint8_t mode); + uint8_t getMode(void) const; + uint8_t* getRaw(void); + void setRaw(const uint8_t state[]); + static uint8_t convertMode(const stdAc::opmode_t mode); + static uint8_t convertFan(const stdAc::fanspeed_t speed); + static stdAc::opmode_t toCommonMode(const uint8_t mode); + static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed); + stdAc::state_t toCommon(void) const; + String toString(void) const; +#ifndef UNIT_TEST + + private: + IRsend _irsend; +#else + /// @cond IGNORE + IRsendTest _irsend; + /// @endcond +#endif + RhossProtocol _; + void checksum(void); +}; +#endif // IR_RHOSS_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Samsung.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Samsung.cpp index 9e1ad4669..94cb52bba 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Samsung.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Samsung.cpp @@ -1,5 +1,5 @@ // Copyright 2009 Ken Shirriff -// Copyright 2017, 2018, 2019 David Conran +// Copyright 2017-2021 David Conran /// @file /// @brief Support for Samsung protocols. /// Samsung originally added from https://github.com/shirriff/Arduino-IRremote/ @@ -62,12 +62,25 @@ const uint16_t kSamsung36BitMark = 512; /// < uSeconds const uint16_t kSamsung36OneSpace = 1468; /// < uSeconds const uint16_t kSamsung36ZeroSpace = 490; /// < uSeconds +// _.Swing +const uint8_t kSamsungAcSwingV = 0b010; +const uint8_t kSamsungAcSwingH = 0b011; +const uint8_t kSamsungAcSwingBoth = 0b100; +const uint8_t kSamsungAcSwingOff = 0b111; +// _.FanSpecial +const uint8_t kSamsungAcFanSpecialOff = 0b000; +const uint8_t kSamsungAcPowerfulOn = 0b011; +const uint8_t kSamsungAcBreezeOn = 0b101; +const uint8_t kSamsungAcEconoOn = 0b111; + using irutils::addBoolToString; using irutils::addFanToString; using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; using irutils::addTempToString; +using irutils::addToggleToString; +using irutils::minsToString; #if SEND_SAMSUNG /// Send a 32-bit Samsung formatted message. @@ -275,17 +288,22 @@ IRSamsungAc::IRSamsungAc(const uint16_t pin, const bool inverted, } /// Reset the internal state of the emulation. -/// @param[in] forcepower A flag indicating if force sending a special power +/// @param[in] extended A flag indicating if force sending a special extended /// message with the first `send()` call. /// @param[in] initialPower Set the initial power state. True, on. False, off. -void IRSamsungAc::stateReset(const bool forcepower, const bool initialPower) { +void IRSamsungAc::stateReset(const bool extended, const bool initialPower) { static const uint8_t kReset[kSamsungAcExtendedStateLength] = { 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x02, 0xAE, 0x71, 0x00, 0x15, 0xF0}; std::memcpy(_.raw, kReset, kSamsungAcExtendedStateLength); - _forcepower = forcepower; + _forceextended = extended; _lastsentpowerstate = initialPower; setPower(initialPower); + _OnTimerEnable = false; + _OffTimerEnable = false; + _Sleep = false; + _lastSleep = false; + _OnTimer = _OffTimer = _lastOnTimer = _lastOffTimer = 0; } /// Set up hardware to be able to send a message. @@ -351,30 +369,28 @@ void IRSamsungAc::checksum(void) { #if SEND_SAMSUNG_AC /// Send the current internal state as an IR message. /// @param[in] repeat Nr. of times the message will be repeated. -/// @param[in] calcchecksum Do we update the checksum before sending? /// @note Use for most function/mode/settings changes to the unit. /// i.e. When the device is already running. -void IRSamsungAc::send(const uint16_t repeat, const bool calcchecksum) { - // Do we need to send a the special power on/off message? i.e. An Extended Msg - if (getPower() != _lastsentpowerstate || _forcepower) { // We do. - sendExtended(repeat, calcchecksum); - _forcepower = false; // It has now been sent, so clear the flag if set. - } else { // No, it's just a normal message. - if (calcchecksum) checksum(); - _irsend.sendSamsungAC(_.raw, kSamsungAcStateLength, repeat); - } +void IRSamsungAc::send(const uint16_t repeat) { + // Do we need to send a special (extended) message? + if (getPower() != _lastsentpowerstate || _forceextended || + (_lastOnTimer != _OnTimer) || (_lastOffTimer != _OffTimer) || + (_Sleep != _lastSleep)) // We do. + sendExtended(repeat); + else // No, it's just a normal message. + _irsend.sendSamsungAC(getRaw(), kSamsungAcStateLength, repeat); } /// Send the extended current internal state as an IR message. /// @param[in] repeat Nr. of times the message will be repeated. -/// @param[in] calcchecksum Do we update the checksum before sending? -/// @note Use this for when you need to power on/off the device. -/// Samsung A/C requires an extended length message when you want to -/// change the power operating mode of the A/C unit. -void IRSamsungAc::sendExtended(const uint16_t repeat, const bool calcchecksum) { +/// @note Samsung A/C requires an extended length message when you want to +/// change the power operating mode, Timers, or Sleep setting of the A/C unit. +void IRSamsungAc::sendExtended(const uint16_t repeat) { + _lastsentpowerstate = getPower(); // Remember the last power state sent. + _lastOnTimer = _OnTimer; + _lastOffTimer = _OffTimer; static const uint8_t extended_middle_section[kSamsungAcSectionLength] = { 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00}; - if (calcchecksum) checksum(); // Copy/convert the internal state to an extended state by // copying the second section to the third section, and inserting the extended // middle (second) section. @@ -383,13 +399,16 @@ void IRSamsungAc::sendExtended(const uint16_t repeat, const bool calcchecksum) { kSamsungAcSectionLength); std::memcpy(_.raw + kSamsungAcSectionLength, extended_middle_section, kSamsungAcSectionLength); + _setOnTimer(); + _setSleepTimer(); // This also sets any Off Timer if needed too. // Send it. - _irsend.sendSamsungAC(_.raw, kSamsungAcExtendedStateLength, repeat); + _irsend.sendSamsungAC(getRaw(), kSamsungAcExtendedStateLength, repeat); // Now revert it by copying the third section over the second section. std::memcpy(_.raw + kSamsungAcSectionLength, - _.raw + 2* kSamsungAcSectionLength, + _.raw + 2 * kSamsungAcSectionLength, kSamsungAcSectionLength); - _lastsentpowerstate = getPower(); // Remember the last power state sent. + + _forceextended = false; // It has now been sent, so clear the flag if set. } /// Send the special extended "On" message as the library can't seem to @@ -434,6 +453,11 @@ void IRSamsungAc::setRaw(const uint8_t new_code[], const uint16_t length) { kSamsungAcExtendedStateLength)); // Shrink the extended state into a normal state. if (length > kSamsungAcStateLength) { + _OnTimerEnable = _.OnTimerEnable; + _OffTimerEnable = _.OffTimerEnable; + _Sleep = _.Sleep5 && _.Sleep12; + _OnTimer = _getOnTimer(); + _OffTimer = _getOffTimer(); for (uint8_t i = kSamsungAcStateLength; i < length; i++) _.raw[i - kSamsungAcSectionLength] = _.raw[i]; } @@ -448,14 +472,13 @@ void IRSamsungAc::off(void) { setPower(false); } /// Change the power setting. /// @param[in] on true, the setting is on. false, the setting is off. void IRSamsungAc::setPower(const bool on) { - _.Power1 = !on; // Cleared when on. - _.Power6 = (on ? 0b11 : 0b00); + _.Power1 = _.Power2 = (on ? 0b11 : 0b00); } /// Get the value of the current power setting. /// @return true, the setting is on. false, the setting is off. bool IRSamsungAc::getPower(void) const { - return (_.Power6 == 0b11) && !_.Power1; + return _.Power1 == 0b11 && _.Power2 == 0b11; } /// Set the temperature. @@ -524,56 +547,79 @@ uint8_t IRSamsungAc::getFan(void) const { /// Get the vertical swing setting of the A/C. /// @return true, the setting is on. false, the setting is off. -/// @todo (Hollako) Explain why sometimes the LSB of remote_state[9] is a 1. -/// e.g. 0xAE or 0XAF for swing move. bool IRSamsungAc::getSwing(void) const { - return _.Swing == kSamsungAcSwingMove; + switch (_.Swing) { + case kSamsungAcSwingV: + case kSamsungAcSwingBoth: return true; + default: return false; + } } /// Set the vertical swing setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. -/// @todo (Hollako) Explain why sometimes the LSB of remote_state[9] is a 1. -/// e.g. 0xAE or 0XAF for swing move. void IRSamsungAc::setSwing(const bool on) { - _.Swing = (on ? kSamsungAcSwingMove : kSamsungAcSwingStop); + switch (_.Swing) { + case kSamsungAcSwingBoth: + case kSamsungAcSwingH: + _.Swing = on ? kSamsungAcSwingBoth : kSamsungAcSwingH; + break; + default: + _.Swing = on ? kSamsungAcSwingV : kSamsungAcSwingOff; + } } -/// Get the Beep setting of the A/C. +/// Get the horizontal swing setting of the A/C. /// @return true, the setting is on. false, the setting is off. -bool IRSamsungAc::getBeep(void) const { - return _.Beep; +bool IRSamsungAc::getSwingH(void) const { + switch (_.Swing) { + case kSamsungAcSwingH: + case kSamsungAcSwingBoth: return true; + default: return false; + } } -/// Set the Beep setting of the A/C. +/// Set the horizontal swing setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. -void IRSamsungAc::setBeep(const bool on) { - _.Beep = on; +void IRSamsungAc::setSwingH(const bool on) { + switch (_.Swing) { + case kSamsungAcSwingV: + case kSamsungAcSwingBoth: + _.Swing = on ? kSamsungAcSwingBoth : kSamsungAcSwingV; + break; + default: + _.Swing = on ? kSamsungAcSwingH : kSamsungAcSwingOff; + } } -/// Get the Clean setting of the A/C. +/// Get the Beep toggle setting of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRSamsungAc::getBeep(void) const { return _.BeepToggle; } + +/// Set the Beep toggle setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRSamsungAc::setBeep(const bool on) { _.BeepToggle = on; } + +/// Get the Clean toggle setting of the A/C. /// @return true, the setting is on. false, the setting is off. bool IRSamsungAc::getClean(void) const { - return _.Clean10 && _.Clean11; + return _.CleanToggle10 && _.CleanToggle11; } -/// Set the Clean setting of the A/C. +/// Set the Clean toggle setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. void IRSamsungAc::setClean(const bool on) { - _.Clean10 = on; - _.Clean11 = on; + _.CleanToggle10 = on; + _.CleanToggle11 = on; } /// Get the Quiet setting of the A/C. /// @return true, the setting is on. false, the setting is off. -bool IRSamsungAc::getQuiet(void) const { - return !_.Quiet1 && _.Quiet5; -} +bool IRSamsungAc::getQuiet(void) const { return _.Quiet; } /// Set the Quiet setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. void IRSamsungAc::setQuiet(const bool on) { - _.Quiet1 = !on; // Cleared when on. - _.Quiet5 = on; + _.Quiet = on; if (on) { // Quiet mode seems to set fan speed to auto. setFan(kSamsungAcFanAuto); @@ -584,25 +630,20 @@ void IRSamsungAc::setQuiet(const bool on) { /// Get the Powerful (Turbo) setting of the A/C. /// @return true, the setting is on. false, the setting is off. bool IRSamsungAc::getPowerful(void) const { - return !(_.Powerful8 & kSamsungAcPowerfulMask8) && - (_.Powerful10 == kSamsungAcPowerful10On) && + return (_.FanSpecial == kSamsungAcPowerfulOn) && (_.Fan == kSamsungAcFanTurbo); } /// Set the Powerful (Turbo) setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. void IRSamsungAc::setPowerful(const bool on) { - uint8_t off_value = getBreeze() ? kSamsungAcBreezeOn : 0b000; - _.Powerful10 = (on ? kSamsungAcPowerful10On : off_value); + uint8_t off_value = (getBreeze() || getEcono()) ? _.FanSpecial + : kSamsungAcFanSpecialOff; + _.FanSpecial = (on ? kSamsungAcPowerfulOn : off_value); if (on) { - _.Powerful8 &= ~kSamsungAcPowerfulMask8; // Bit needs to be cleared. // Powerful mode sets fan speed to Turbo. setFan(kSamsungAcFanTurbo); setQuiet(false); // Powerful 'on' is mutually exclusive to Quiet. - } else { - _.Powerful8 |= kSamsungAcPowerfulMask8; // Bit needs to be set. - // Turning off Powerful mode sets fan speed to Auto if we were in Turbo mode - if (_.Fan == kSamsungAcFanTurbo) setFan(kSamsungAcFanAuto); } } @@ -610,7 +651,7 @@ void IRSamsungAc::setPowerful(const bool on) { /// @return true, the setting is on. false, the setting is off. /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1062 bool IRSamsungAc::getBreeze(void) const { - return (_.Breeze == kSamsungAcBreezeOn) && + return (_.FanSpecial == kSamsungAcBreezeOn) && (_.Fan == kSamsungAcFanAuto && !getSwing()); } @@ -618,36 +659,155 @@ bool IRSamsungAc::getBreeze(void) const { /// @param[in] on true, the setting is on. false, the setting is off. /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1062 void IRSamsungAc::setBreeze(const bool on) { - uint8_t off_value = getPowerful() ? kSamsungAcPowerful10On : 0b000; - _.Breeze = (on ? kSamsungAcBreezeOn : off_value); + const uint8_t off_value = (getPowerful() || + getEcono()) ? _.FanSpecial + : kSamsungAcFanSpecialOff; + _.FanSpecial = (on ? kSamsungAcBreezeOn : off_value); if (on) { setFan(kSamsungAcFanAuto); setSwing(false); } } +/// Get the current Economy (Eco) setting of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRSamsungAc::getEcono(void) const { + return (_.FanSpecial == kSamsungAcEconoOn) && + (_.Fan == kSamsungAcFanAuto && getSwing()); +} + +/// Set the current Economy (Eco) setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRSamsungAc::setEcono(const bool on) { + const uint8_t off_value = (getBreeze() || + getPowerful()) ? _.FanSpecial + : kSamsungAcFanSpecialOff; + _.FanSpecial = (on ? kSamsungAcEconoOn : off_value); + if (on) { + setFan(kSamsungAcFanAuto); + setSwing(true); + } +} + /// Get the Display (Light/LED) setting of the A/C. /// @return true, the setting is on. false, the setting is off. -bool IRSamsungAc::getDisplay(void) const { - return _.Display; -} +bool IRSamsungAc::getDisplay(void) const { return _.Display; } /// Set the Display (Light/LED) setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. -void IRSamsungAc::setDisplay(const bool on) { - _.Display = on; -} +void IRSamsungAc::setDisplay(const bool on) { _.Display = on; } /// Get the Ion (Filter) setting of the A/C. /// @return true, the setting is on. false, the setting is off. -bool IRSamsungAc::getIon(void) const { - return _.Ion; -} +bool IRSamsungAc::getIon(void) const { return _.Ion; } /// Set the Ion (Filter) setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. -void IRSamsungAc::setIon(const bool on) { - _.Ion = on; +void IRSamsungAc::setIon(const bool on) { _.Ion = on; } + +/// Get the On Timer setting of the A/C from a raw extended state. +/// @return The Nr. of minutes the On Timer is set for. +uint16_t IRSamsungAc::_getOnTimer(void) const { + if (_.OnTimeDay) return 24 * 60; + return (_.OnTimeHrs2 * 2 + _.OnTimeHrs1) * 60 + _.OnTimeMins * 10; +} + +/// Set the current On Timer value of the A/C into the raw extended state. +void IRSamsungAc::_setOnTimer(void) { + _.OnTimerEnable = _OnTimerEnable = (_OnTimer > 0); + _.OnTimeDay = (_OnTimer >= 24 * 60); + if (_.OnTimeDay) { + _.OnTimeHrs2 = _.OnTimeHrs1 = _.OnTimeMins = 0; + return; + } + _.OnTimeMins = (_OnTimer % 60) / 10; + const uint8_t hours = _OnTimer / 60; + _.OnTimeHrs1 = hours & 0b1; + _.OnTimeHrs2 = hours >> 1; +} + +/// Get the Off Timer setting of the A/C from a raw extended state. +/// @return The Nr. of minutes the Off Timer is set for. +uint16_t IRSamsungAc::_getOffTimer(void) const { + if (_.OffTimeDay) return 24 * 60; + return (_.OffTimeHrs2 * 2 + _.OffTimeHrs1) * 60 + _.OffTimeMins * 10; +} + +/// Set the current Off Timer value of the A/C into the raw extended state. +void IRSamsungAc::_setOffTimer(void) { + _.OffTimerEnable = _OffTimerEnable = (_OffTimer > 0); + _.OffTimeDay = (_OffTimer >= 24 * 60); + if (_.OffTimeDay) { + _.OffTimeHrs2 = _.OffTimeHrs1 = _.OffTimeMins = 0; + return; + } + _.OffTimeMins = (_OffTimer % 60) / 10; + const uint8_t hours = _OffTimer / 60; + _.OffTimeHrs1 = hours & 0b1; + _.OffTimeHrs2 = hours >> 1; +} + +// Set the current Sleep Timer value of the A/C into the raw extended state. +void IRSamsungAc::_setSleepTimer(void) { + _setOffTimer(); + // The Sleep mode/timer should only be engaged if an off time has been set. + _.Sleep5 = _Sleep && _OffTimerEnable; + _.Sleep12 = _.Sleep5; +} + +/// Get the On Timer setting of the A/C. +/// @return The Nr. of minutes the On Timer is set for. +uint16_t IRSamsungAc::getOnTimer(void) const { return _OnTimer; } + +/// Get the Off Timer setting of the A/C. +/// @return The Nr. of minutes the Off Timer is set for. +/// @note Sleep & Off Timer share the same timer. +uint16_t IRSamsungAc::getOffTimer(void) const { + return _Sleep ? 0 : _OffTimer; +} + +/// Get the Sleep Timer setting of the A/C. +/// @return The Nr. of minutes the Off Timer is set for. +/// @note Sleep & Off Timer share the same timer. +uint16_t IRSamsungAc::getSleepTimer(void) const { + return _Sleep ? _OffTimer : 0; +} + +#define TIMER_RESOLUTION(mins) \ + (((std::min((mins), (uint16_t)(24 * 60))) / 10) * 10) + +/// Set the On Timer value of the A/C. +/// @param[in] nr_of_mins The number of minutes the timer should be. +/// @note The timer time only has a resolution of 10 mins. +/// @note Setting the On Timer active will cancel the Sleep timer/setting. +void IRSamsungAc::setOnTimer(const uint16_t nr_of_mins) { + // Limit to one day, and round down to nearest 10 min increment. + _OnTimer = TIMER_RESOLUTION(nr_of_mins); + _OnTimerEnable = _OnTimer > 0; + if (_OnTimer) _Sleep = false; +} + +/// Set the Off Timer value of the A/C. +/// @param[in] nr_of_mins The number of minutes the timer should be. +/// @note The timer time only has a resolution of 10 mins. +/// @note Setting the Off Timer active will cancel the Sleep timer/setting. +void IRSamsungAc::setOffTimer(const uint16_t nr_of_mins) { + // Limit to one day, and round down to nearest 10 min increment. + _OffTimer = TIMER_RESOLUTION(nr_of_mins); + _OffTimerEnable = _OffTimer > 0; + if (_OffTimer) _Sleep = false; +} + +/// Set the Sleep Timer value of the A/C. +/// @param[in] nr_of_mins The number of minutes the timer should be. +/// @note The timer time only has a resolution of 10 mins. +/// @note Sleep timer acts as an Off timer, and cancels any On Timer. +void IRSamsungAc::setSleepTimer(const uint16_t nr_of_mins) { + // Limit to one day, and round down to nearest 10 min increment. + _OffTimer = TIMER_RESOLUTION(nr_of_mins); + if (_OffTimer) setOnTimer(0); // Clear the on timer if set. + _Sleep = _OffTimer > 0; + _OffTimerEnable = _Sleep; } /// Convert a stdAc::opmode_t enum into its native mode. @@ -714,18 +874,17 @@ stdAc::state_t IRSamsungAc::toCommon(void) const { result.celsius = true; result.degrees = getTemp(); result.fanspeed = toCommonFanSpeed(_.Fan); - result.swingv = getSwing() ? stdAc::swingv_t::kAuto : - stdAc::swingv_t::kOff; + result.swingv = getSwing() ? stdAc::swingv_t::kAuto : stdAc::swingv_t::kOff; + result.swingh = getSwingH() ? stdAc::swingh_t::kAuto : stdAc::swingh_t::kOff; result.quiet = getQuiet(); result.turbo = getPowerful(); + result.econo = getEcono(); result.clean = getClean(); - result.beep = _.Beep; + result.beep = _.BeepToggle; result.light = _.Display; result.filter = _.Ion; + result.sleep = _Sleep ? getSleepTimer() : -1; // Not supported. - result.swingh = stdAc::swingh_t::kOff; - result.econo = false; - result.sleep = -1; result.clock = -1; return result; } @@ -734,7 +893,7 @@ stdAc::state_t IRSamsungAc::toCommon(void) const { /// @return A human readable string. String IRSamsungAc::toString(void) const { String result = ""; - result.reserve(115); // Reserve some heap for the string to reduce fragging. + result.reserve(230); // Reserve some heap for the string to reduce fragging. result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(_.Mode, kSamsungAcAuto, kSamsungAcCool, kSamsungAcHeat, kSamsungAcDry, @@ -764,14 +923,21 @@ String IRSamsungAc::toString(void) const { break; } result += ')'; - result += addBoolToString(getSwing(), kSwingStr); - result += addBoolToString(_.Beep, kBeepStr); - result += addBoolToString(getClean(), kCleanStr); + result += addBoolToString(getSwing(), kSwingVStr); + result += addBoolToString(getSwingH(), kSwingHStr); + result += addToggleToString(_.BeepToggle, kBeepStr); + result += addToggleToString(getClean(), kCleanStr); result += addBoolToString(getQuiet(), kQuietStr); result += addBoolToString(getPowerful(), kPowerfulStr); + result += addBoolToString(getEcono(), kEconoStr); result += addBoolToString(getBreeze(), kBreezeStr); result += addBoolToString(_.Display, kLightStr); result += addBoolToString(_.Ion, kIonStr); + if (_OnTimerEnable) + result += addLabeledString(minsToString(_OnTimer), kOnTimerStr); + if (_OffTimerEnable) + result += addLabeledString(minsToString(_OffTimer), + _Sleep ? kSleepTimerStr : kOffTimerStr); return result; } @@ -811,9 +977,6 @@ bool IRrecv::decodeSamsungAC(decode_results *results, uint16_t offset, offset += used; } // Compliance - // Is the signature correct? - DPRINTLN("DEBUG: Checking signature."); - if (results->state[0] != 0x02 || results->state[2] != 0x0F) return false; if (strict) { // Is the checksum valid? if (!IRSamsungAc::validChecksum(results->state, nbits / 8)) { diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Samsung.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Samsung.h index bf9215edc..acabb3648 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Samsung.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Samsung.h @@ -1,4 +1,4 @@ -// Copyright 2018 David Conran +// Copyright 2018-2021 David Conran /// @file /// @brief Support for Samsung protocols. /// Samsung originally added from https://github.com/shirriff/Arduino-IRremote/ @@ -7,6 +7,7 @@ /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1062 /// @see http://elektrolab.wz.cz/katalog/samsung_protocol.pdf /// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1538 (Checksum) +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1277 (Timers) // Supports: // Brand: Samsung, Model: UA55H6300 TV (SAMSUNG) @@ -18,11 +19,13 @@ // Brand: Samsung, Model: AH59-02692E Soundbar remote (SAMSUNG36) // Brand: Samsung, Model: HW-J551 Soundbar (SAMSUNG36) // Brand: Samsung, Model: AR09FSSDAWKNFA A/C (SAMSUNG_AC) +// Brand: Samsung, Model: AR09HSFSBWKN A/C (SAMSUNG_AC) // Brand: Samsung, Model: AR12KSFPEWQNET A/C (SAMSUNG_AC) // Brand: Samsung, Model: AR12HSSDBWKNEU A/C (SAMSUNG_AC) // Brand: Samsung, Model: AR12NXCXAWKXEU A/C (SAMSUNG_AC) -// Brand: Samsung, Model: AR09HSFSBWKN A/C (SAMSUNG_AC) +// Brand: Samsung, Model: AR12TXEAAWKNEU A/C (SAMSUNG_AC) // Brand: Samsung, Model: DB93-14195A remote (SAMSUNG_AC) +// Brand: Samsung, Model: DB96-24901C remote (SAMSUNG_AC) #ifndef IR_SAMSUNG_H_ #define IR_SAMSUNG_H_ @@ -41,116 +44,125 @@ /// Native representation of a Samsung A/C message. union SamsungProtocol{ uint8_t raw[kSamsungAcExtendedStateLength]; ///< State in code form. - struct { + struct { // Standard message map // Byte 0 - uint8_t :8; + uint8_t :8; // Byte 1 uint8_t :4; - uint8_t Quiet1 :1; - uint8_t Power1 :1; - uint8_t :2; - // Byte 2~4 - uint8_t pad0[3]; + uint8_t :4; // Sum1Lower + // Byte 2 + uint8_t :4; // Sum1Upper + uint8_t :4; + // Byte 3 + uint8_t :8; + // Byte 4 + uint8_t :8; // Byte 5 - uint8_t :5; - uint8_t Quiet5 :1; + uint8_t :4; + uint8_t Sleep5 :1; + uint8_t Quiet :1; uint8_t :2; // Byte 6 uint8_t :4; - uint8_t Power6 :2; + uint8_t Power1 :2; uint8_t :2; // Byte 7 - uint8_t :8; + uint8_t :8; // Byte 8 - uint8_t Powerful8 :8; + uint8_t :4; + uint8_t :4; // Sum2Lower // Byte 9 - uint8_t :4; - uint8_t Swing :3; - uint8_t :1; + uint8_t :4; // Sum1Upper + uint8_t Swing :3; + uint8_t :1; // Byte 10 - uint8_t :1; - uint8_t Powerful10 :3; - uint8_t Display :1; - uint8_t :2; - uint8_t Clean10 :1; + uint8_t :1; + uint8_t FanSpecial :3; // Powerful, Breeze/WindFree, Econo + uint8_t Display :1; + uint8_t :2; + uint8_t CleanToggle10 :1; // Byte 11 - uint8_t Ion :1; - uint8_t Clean11 :1; - uint8_t :2; - uint8_t Temp :4; + uint8_t Ion :1; + uint8_t CleanToggle11 :1; + uint8_t :2; + uint8_t Temp :4; // Byte 12 uint8_t :1; uint8_t Fan :3; uint8_t Mode :3; uint8_t :1; // Byte 13 - uint8_t :1; - uint8_t Beep :1; - uint8_t :6; + uint8_t :2; + uint8_t BeepToggle :1; + uint8_t :1; + uint8_t Power2 :2; + uint8_t :2; }; - struct { + struct { // Extended message map // 1st Section // Byte 0 - uint8_t :8; + uint8_t :8; // Byte 1 - uint8_t :4; - uint8_t Sum1Lower :4; + uint8_t :4; + uint8_t Sum1Lower :4; // Byte 2 - uint8_t Sum1Upper :4; - uint8_t :4; + uint8_t Sum1Upper :4; + uint8_t :4; // Byte 3 - uint8_t :8; + uint8_t :8; // Byte 4 - uint8_t :8; + uint8_t :8; // Byte 5 - uint8_t :8; + uint8_t :8; // Byte 6 - uint8_t :8; + uint8_t :8; // 2nd Section // Byte 7 - uint8_t :8; + uint8_t :8; // Byte 8 - uint8_t :4; - uint8_t Sum2Lower :4; + uint8_t :4; + uint8_t Sum2Lower :4; // Byte 9 - uint8_t Sum2Upper :4; - uint8_t :4; + uint8_t Sum2Upper :4; + uint8_t OffTimeMins :3; // In units of 10's of mins + uint8_t OffTimeHrs1 :1; // LSB of the number of hours. // Byte 10 - uint8_t :1; - uint8_t Breeze :3; // WindFree - uint8_t :4; + uint8_t OffTimeHrs2 :4; // MSBs of the number of hours. + uint8_t OnTimeMins :3; // In units of 10's of mins + uint8_t OnTimeHrs1 :1; // LSB of the number of hours. // Byte 11 - uint8_t :8; + uint8_t OnTimeHrs2 :4; // MSBs of the number of hours. + uint8_t :4; // Byte 12 - uint8_t :8; + uint8_t OffTimeDay :1; + uint8_t OnTimerEnable :1; + uint8_t OffTimerEnable :1; + uint8_t Sleep12 :1; + uint8_t OnTimeDay :1; + uint8_t :3; // Byte 13 - uint8_t :8; + uint8_t :8; // 3rd Section // Byte 14 - uint8_t :8; + uint8_t :8; // Byte 15 - uint8_t :4; - uint8_t Sum3Lower :4; + uint8_t :4; + uint8_t Sum3Lower :4; // Byte 16 - uint8_t Sum3Upper :4; - uint8_t :4; + uint8_t Sum3Upper :4; + uint8_t :4; // Byte 17 - uint8_t :8; + uint8_t :8; // Byte 18 - uint8_t :8; + uint8_t :8; // Byte 19 - uint8_t :8; + uint8_t :8; // Byte 20 - uint8_t :8; + uint8_t :8; }; }; // Constants -const uint8_t kSamsungAcPowerfulMask8 = 0b01010000; -const uint8_t kSamsungAcSwingMove = 0b010; -const uint8_t kSamsungAcSwingStop = 0b111; -const uint8_t kSamsungAcPowerful10On = 0b011; -const uint8_t kSamsungAcBreezeOn = 0b101; const uint8_t kSamsungAcMinTemp = 16; // C Mask 0b11110000 const uint8_t kSamsungAcMaxTemp = 30; // C Mask 0b11110000 const uint8_t kSamsungAcAutoTemp = 25; // C Mask 0b11110000 @@ -174,12 +186,10 @@ class IRSamsungAc { public: explicit IRSamsungAc(const uint16_t pin, const bool inverted = false, const bool use_modulation = true); - void stateReset(const bool forcepower = true, const bool initialPower = true); + void stateReset(const bool extended = true, const bool initialPower = true); #if SEND_SAMSUNG_AC - void send(const uint16_t repeat = kSamsungAcDefaultRepeat, - const bool calcchecksum = true); - void sendExtended(const uint16_t repeat = kSamsungAcDefaultRepeat, - const bool calcchecksum = true); + void send(const uint16_t repeat = kSamsungAcDefaultRepeat); + void sendExtended(const uint16_t repeat = kSamsungAcDefaultRepeat); void sendOn(const uint16_t repeat = kSamsungAcDefaultRepeat); void sendOff(const uint16_t repeat = kSamsungAcDefaultRepeat); /// Run the calibration to calculate uSec timing offsets for this platform. @@ -201,6 +211,8 @@ class IRSamsungAc { uint8_t getMode(void) const; void setSwing(const bool on); bool getSwing(void) const; + void setSwingH(const bool on); + bool getSwingH(void) const; void setBeep(const bool on); bool getBeep(void) const; void setClean(const bool on); @@ -211,10 +223,18 @@ class IRSamsungAc { bool getPowerful(void) const; void setBreeze(const bool on); bool getBreeze(void) const; + void setEcono(const bool on); + bool getEcono(void) const; void setDisplay(const bool on); bool getDisplay(void) const; void setIon(const bool on); bool getIon(void) const; + uint16_t getOnTimer(void) const; + void setOnTimer(const uint16_t nr_of_mins); + uint16_t getOffTimer(void) const; + void setOffTimer(const uint16_t nr_of_mins); + uint16_t getSleepTimer(void) const; + void setSleepTimer(const uint16_t nr_of_mins); uint8_t* getRaw(void); void setRaw(const uint8_t new_code[], const uint16_t length = kSamsungAcStateLength); @@ -238,9 +258,22 @@ class IRSamsungAc { /// @endcond #endif // UNIT_TEST SamsungProtocol _; - bool _forcepower; ///< Hack to know when we need to send a special power mesg + bool _forceextended; ///< Flag to know when we need to send an extended mesg. bool _lastsentpowerstate; + bool _OnTimerEnable; + bool _OffTimerEnable; + bool _Sleep; + bool _lastSleep; + uint16_t _OnTimer; + uint16_t _OffTimer; + uint16_t _lastOnTimer; + uint16_t _lastOffTimer; void checksum(void); + uint16_t _getOnTimer(void) const; + uint16_t _getOffTimer(void) const; + void _setOnTimer(void); + void _setOffTimer(void); + void _setSleepTimer(void); }; #endif // IR_SAMSUNG_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sharp.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sharp.cpp index 8cbace41e..38f0ac32c 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sharp.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sharp.cpp @@ -45,7 +45,9 @@ using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; using irutils::addModelToString; +using irutils::addSwingVToString; using irutils::addTempToString; +using irutils::addToggleToString; using irutils::minsToString; // Also used by Denon protocol @@ -544,24 +546,73 @@ void IRSharpAc::setTurbo(const bool on) { _.Special = kSharpAcSpecialTurbo; } +/// Get the Vertical Swing setting of the A/C. +/// @return The position of the Vertical Swing setting. +uint8_t IRSharpAc::getSwingV(void) const { return _.Swing; } + +/// Set the Vertical Swing setting of the A/C. +/// @note Some positions may not work on all models. +/// @param[in] position The desired position/setting. +/// @note `setSwingV(kSharpAcSwingVLowest)` will only allow the Lowest setting +/// in Heat mode, it will default to `kSharpAcSwingVLow` otherwise. +/// If you want to set this value in other modes e.g. Cool, you must +/// use `setSwingV`s optional `force` parameter. +/// @param[in] force Do we override the safety checks and just do it? +void IRSharpAc::setSwingV(const uint8_t position, const bool force) { + switch (position) { + case kSharpAcSwingVCoanda: + // Only allowed in Heat mode. + if (!force && getMode() != kSharpAcHeat) { + setSwingV(kSharpAcSwingVLow); // Use the next lowest setting. + return; + } + // FALLTHRU + case kSharpAcSwingVHigh: + case kSharpAcSwingVMid: + case kSharpAcSwingVLow: + case kSharpAcSwingVToggle: + case kSharpAcSwingVOff: + case kSharpAcSwingVLast: // Technically valid, but we don't use it. + // All expected non-positions set the special bits. + _.Special = kSharpAcSpecialSwing; + // FALLTHRU + case kSharpAcSwingVIgnore: + _.Swing = position; + } +} + +/// Convert a standard A/C vertical swing into its native setting. +/// @param[in] position A stdAc::swingv_t position to convert. +/// @return The equivalent native horizontal swing position. +uint8_t IRSharpAc::convertSwingV(const stdAc::swingv_t position) { + switch (position) { + case stdAc::swingv_t::kHighest: + case stdAc::swingv_t::kHigh: return kSharpAcSwingVHigh; + case stdAc::swingv_t::kMiddle: return kSharpAcSwingVMid; + case stdAc::swingv_t::kLow: return kSharpAcSwingVLow; + case stdAc::swingv_t::kLowest: return kSharpAcSwingVCoanda; + case stdAc::swingv_t::kAuto: return kSharpAcSwingVToggle; + case stdAc::swingv_t::kOff: return kSharpAcSwingVOff; + default: return kSharpAcSwingVIgnore; + } +} + /// Get the (vertical) Swing Toggle setting of the A/C. /// @return true, the setting is on. false, the setting is off. bool IRSharpAc::getSwingToggle(void) const { - return _.Swing == kSharpAcSwingToggle; + return getSwingV() == kSharpAcSwingVToggle; } /// Set the (vertical) Swing Toggle setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. void IRSharpAc::setSwingToggle(const bool on) { - _.Swing = (on ? kSharpAcSwingToggle : kSharpAcSwingNoToggle); + setSwingV(on ? kSharpAcSwingVToggle : kSharpAcSwingVIgnore); if (on) _.Special = kSharpAcSpecialSwing; } /// Get the Ion (Filter) setting of the A/C. /// @return true, the setting is on. false, the setting is off. -bool IRSharpAc::getIon(void) const { - return _.Ion; -} +bool IRSharpAc::getIon(void) const { return _.Ion; } /// Set the Ion (Filter) setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. @@ -628,15 +679,11 @@ uint16_t IRSharpAc::getTimerTime(void) const { /// Is the Timer enabled? /// @return true, the setting is on. false, the setting is off. -bool IRSharpAc::getTimerEnabled(void) const { - return _.TimerEnabled; -} +bool IRSharpAc::getTimerEnabled(void) const { return _.TimerEnabled; } /// Get the current timer type. /// @return true, It's an "On" timer. false, It's an "Off" timer. -bool IRSharpAc::getTimerType(void) const { - return _.TimerType; -} +bool IRSharpAc::getTimerType(void) const { return _.TimerType; } /// Set or cancel the timer function. /// @param[in] enable Is the timer to be enabled (true) or canceled(false)? @@ -765,10 +812,34 @@ stdAc::fanspeed_t IRSharpAc::toCommonFanSpeed(const uint8_t speed) const { } } +/// Convert a native vertical swing postion to it's common equivalent. +/// @param[in] pos A native position to convert. +/// @param[in] mode What operating mode are we in? +/// @return The common vertical swing position. +stdAc::swingv_t IRSharpAc::toCommonSwingV(const uint8_t pos, + const stdAc::opmode_t mode) const { + switch (pos) { + case kSharpAcSwingVHigh: return stdAc::swingv_t::kHighest; + case kSharpAcSwingVMid: return stdAc::swingv_t::kMiddle; + case kSharpAcSwingVLow: return stdAc::swingv_t::kLow; + case kSharpAcSwingVCoanda: // Coanda has mode dependent positionss + switch (mode) { + case stdAc::opmode_t::kCool: return stdAc::swingv_t::kHighest; + case stdAc::opmode_t::kHeat: return stdAc::swingv_t::kLowest; + default: return stdAc::swingv_t::kOff; + } + case kSharpAcSwingVToggle: return stdAc::swingv_t::kAuto; + default: return stdAc::swingv_t::kOff; + } +} + /// Convert the current internal state into its stdAc::state_t equivalent. +/// @param[in] prev Ptr to the previous state if required. /// @return The stdAc equivalent of the native settings. -stdAc::state_t IRSharpAc::toCommon(void) const { +stdAc::state_t IRSharpAc::toCommon(const stdAc::state_t *prev) const { stdAc::state_t result; + // Start with the previous state if given it. + if (prev != NULL) result = *prev; result.protocol = decode_type_t::SHARP_AC; result.model = getModel(); result.power = getPower(); @@ -777,8 +848,8 @@ stdAc::state_t IRSharpAc::toCommon(void) const { result.degrees = getTemp(); result.fanspeed = toCommonFanSpeed(_.Fan); result.turbo = getTurbo(); - result.swingv = getSwingToggle() ? stdAc::swingv_t::kAuto - : stdAc::swingv_t::kOff; + if (getSwingV() != kSharpAcSwingVIgnore) + result.swingv = toCommonSwingV(getSwingV(), result.mode); result.filter = _.Ion; result.econo = getEconoToggle(); result.light = getLightToggle(); @@ -797,14 +868,16 @@ stdAc::state_t IRSharpAc::toCommon(void) const { String IRSharpAc::toString(void) const { String result = ""; const sharp_ac_remote_model_t model = getModel(); - result.reserve(160); // Reserve some heap for the string to reduce fragging. + result.reserve(170); // Reserve some heap for the string to reduce fragging. result += addModelToString(decode_type_t::SHARP_AC, getModel(), false); - result += addLabeledString(isPowerSpecial() ? "-" - : (getPower() ? kOnStr : kOffStr), + result += addLabeledString(isPowerSpecial() ? String("-") + : String(getPower() ? kOnStr + : kOffStr), kPowerStr); + const uint8_t mode = _.Mode; result += addModeToString( - _.Mode, + mode, // Make the value invalid if the model doesn't support an Auto mode. (model == sharp_ac_remote_model_t::A907) ? kSharpAcAuto : 255, kSharpAcCool, kSharpAcHeat, kSharpAcDry, kSharpAcFan); @@ -821,18 +894,37 @@ String IRSharpAc::toString(void) const { kSharpAcFanAuto, kSharpAcFanAuto, kSharpAcFanMed); } + if (getSwingV() == kSharpAcSwingVIgnore) { + result += addIntToString(kSharpAcSwingVIgnore, kSwingVStr); + result += kSpaceLBraceStr; + result += kNAStr; + result += ')'; + } else { + result += addSwingVToString( + getSwingV(), 0xFF, + // Coanda means Highest when in Cool mode. + (mode == kSharpAcCool) ? kSharpAcSwingVCoanda : kSharpAcSwingVToggle, + kSharpAcSwingVHigh, + 0xFF, // Upper Middle is unused + kSharpAcSwingVMid, + 0xFF, // Lower Middle is unused + kSharpAcSwingVLow, + kSharpAcSwingVCoanda, + kSharpAcSwingVOff, + // Below are unused. + kSharpAcSwingVToggle, + 0xFF, + 0xFF); + } result += addBoolToString(getTurbo(), kTurboStr); - result += addBoolToString(getSwingToggle(), kSwingVToggleStr); result += addBoolToString(_.Ion, kIonStr); switch (model) { case sharp_ac_remote_model_t::A705: case sharp_ac_remote_model_t::A903: - result += addLabeledString(getLightToggle() ? kToggleStr : "-", - kLightStr); + result += addToggleToString(getLightToggle(), kLightStr); break; default: - result += addLabeledString(getEconoToggle() ? kToggleStr : "-", - kEconoStr); + result += addToggleToString(getEconoToggle(), kEconoStr); } result += addBoolToString(_.Clean, kCleanStr); if (_.TimerEnabled) diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sharp.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sharp.h index dd6d826ac..b3be534e7 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sharp.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Sharp.h @@ -17,6 +17,7 @@ // Brand: Sharp, Model: AY-ZP40KR A/C (A907) // Brand: Sharp, Model: AH-AxSAY A/C (A907) // Brand: Sharp, Model: CRMC-A907 JBEZ remote (A907) +// Brand: Sharp, Model: CRMC-A950 JBEZ (A907) // Brand: Sharp, Model: AH-PR13-GL A/C (A903) // Brand: Sharp, Model: CRMC-A903JBEZ remote (A903) // Brand: Sharp, Model: AH-XP10NRY A/C (A903) @@ -121,8 +122,23 @@ const uint8_t kSharpAcTimerHoursMax = 0b1100; // 12 const uint8_t kSharpAcOffTimerType = 0b0; const uint8_t kSharpAcOnTimerType = 0b1; -const uint8_t kSharpAcSwingToggle = 0b111; -const uint8_t kSharpAcSwingNoToggle = 0b000; +// Ref: https://github.com/crankyoldgit/IRremoteESP8266/discussions/1590#discussioncomment-1260213 +const uint8_t kSharpAcSwingVIgnore = 0b000; // Don't change the swing setting. +const uint8_t kSharpAcSwingVHigh = 0b001; // 0° down. Similar to Cool Coanda. +const uint8_t kSharpAcSwingVOff = 0b010; // Stop & Go to last fixed pos. +const uint8_t kSharpAcSwingVMid = 0b011; // 30° down +const uint8_t kSharpAcSwingVLow = 0b100; // 45° down +const uint8_t kSharpAcSwingVLast = 0b101; // Same as kSharpAcSwingVOff. +// Toggles between last fixed pos & either 75° down (Heat) or 0° down (Cool) +// i.e. alternate between last pos <-> 75° down if in Heat mode, AND +// alternate between last pos <-> 0° down if in Cool mode. +// Note: `setSwingV(kSharpAcSwingVLowest)` will only allow the Lowest setting in +// Heat mode, it will default to `kSharpAcSwingVLow` otherwise. +// If you want to set this value in other modes e.g. Cool, you must +// use `setSwingV`s optional `force` parameter. +const uint8_t kSharpAcSwingVLowest = 0b110; +const uint8_t kSharpAcSwingVCoanda = kSharpAcSwingVLowest; +const uint8_t kSharpAcSwingVToggle = 0b111; // Toggle Constant swinging on/off. const uint8_t kSharpAcSpecialPower = 0x00; const uint8_t kSharpAcSpecialTurbo = 0x01; @@ -166,6 +182,8 @@ class IRSharpAc { void setTurbo(const bool on); bool getSwingToggle(void) const; void setSwingToggle(const bool on); + uint8_t getSwingV(void) const; + void setSwingV(const uint8_t position, const bool force = false); bool getIon(void) const; void setIon(const bool on); bool getEconoToggle(void) const; @@ -187,9 +205,13 @@ class IRSharpAc { static uint8_t convertFan(const stdAc::fanspeed_t speed, const sharp_ac_remote_model_t model = sharp_ac_remote_model_t::A907); + static uint8_t convertSwingV(const stdAc::swingv_t position); stdAc::opmode_t toCommonMode(const uint8_t mode) const; stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed) const; - stdAc::state_t toCommon(void) const; + stdAc::swingv_t toCommonSwingV( + const uint8_t pos, + const stdAc::opmode_t mode = stdAc::opmode_t::kHeat) const; + stdAc::state_t toCommon(const stdAc::state_t *prev = NULL) const; String toString(void) const; #ifndef UNIT_TEST diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Symphony.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Symphony.cpp index d5fedb29b..b629ef72d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Symphony.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Symphony.cpp @@ -18,6 +18,15 @@ // Brand: Satellite Electronic, Model: ID6 Remote // Brand: Satellite Electronic, Model: JY199I Fan driver // Brand: Satellite Electronic, Model: JY199I-L Fan driver +// Brand: SilverCrest, Model: SSVS 85 A1 Fan + +// Known Codes: +// SilverCrest SSVS 85 A1 Fan: +// 0x581 - On/Off +// 0x582 - Speed +// 0x584 - Mist +// 0x588 - Timer +// 0x590 - OSC #include #include "IRrecv.h" diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.cpp index cce9d1f4c..a9e8784a3 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.cpp @@ -15,12 +15,18 @@ // Constants +const uint8_t kTcl112AcTimerResolution = 20; // Minutes +const uint16_t kTcl112AcTimerMax = 720; // Minutes (12 hrs) + using irutils::addBoolToString; using irutils::addFanToString; using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; +using irutils::addModelToString; +using irutils::addSwingVToString; using irutils::addTempFloatToString; +using irutils::minsToString; #if SEND_TCL112AC /// Send a TCL 112-bit A/C message. @@ -71,6 +77,8 @@ void IRTcl112Ac::send(const uint16_t repeat) { _quiet_prev = _quiet; // Restore the old state. setRaw(save); + // Make sure it looks like a normal TCL mesg if needed. + if (_.MsgType == kTcl112AcNormal) _.isTcl = true; } // Send the normal (type 1) state. _irsend.sendTcl112Ac(getRaw(), kTcl112AcStateLength, repeat); @@ -109,6 +117,17 @@ bool IRTcl112Ac::validChecksum(uint8_t state[], const uint16_t length) { return (length > 1 && state[length - 1] == calcChecksum(state, length)); } +/// Check the supplied state looks like a TCL112AC message. +/// @param[in] state The array to verify the checksum of. +/// @note Assumes the state is the correct size. +/// @return true, if the state looks like a TCL112AC message. Otherwise, false. +/// @warning This is just a guess. +bool IRTcl112Ac::isTcl(const uint8_t state[]) { + Tcl112Protocol mesg; + std::memcpy(mesg.raw, state, kTcl112AcStateLength); + return (mesg.MsgType != kTcl112AcNormal) || mesg.isTcl; +} + /// Reset the internal state of the emulation. (On, Cool, 24C) void IRTcl112Ac::stateReset(void) { // A known good state. (On, Cool, 24C) @@ -121,6 +140,19 @@ void IRTcl112Ac::stateReset(void) { _quiet_explictly_set = false; } +/// Get/Detect the model of the A/C. +/// @return The enum of the compatible model. +tcl_ac_remote_model_t IRTcl112Ac::getModel(void) const { + return isTcl(_.raw) ? tcl_ac_remote_model_t::TAC09CHSD + : tcl_ac_remote_model_t::GZ055BE1; +} + +/// Set the model of the A/C to emulate. +/// @param[in] model The enum of the appropriate model. +void IRTcl112Ac::setModel(const tcl_ac_remote_model_t model) { + _.isTcl = (model != tcl_ac_remote_model_t::GZ055BE1); +} + /// Get a PTR to the internal state/code for this protocol. /// @return PTR to a code for this protocol based on the current internal state. uint8_t* IRTcl112Ac::getRaw(void) { @@ -203,6 +235,7 @@ float IRTcl112Ac::getTemp(void) const { void IRTcl112Ac::setFan(const uint8_t speed) { switch (speed) { case kTcl112AcFanAuto: + case kTcl112AcFanMin: case kTcl112AcFanLow: case kTcl112AcFanMed: case kTcl112AcFanHigh: @@ -250,14 +283,23 @@ void IRTcl112Ac::setSwingHorizontal(const bool on) { _.SwingH = on; } bool IRTcl112Ac::getSwingHorizontal(void) const { return _.SwingH; } /// Set the vertical swing setting of the A/C. -/// @param[in] on true, the setting is on. false, the setting is off. -void IRTcl112Ac::setSwingVertical(const bool on) { - _.SwingV = (on ? kTcl112AcSwingVOn : kTcl112AcSwingVOff); +/// @param[in] setting The value of the desired setting. +void IRTcl112Ac::setSwingVertical(const uint8_t setting) { + switch (setting) { + case kTcl112AcSwingVOff: + case kTcl112AcSwingVHighest: + case kTcl112AcSwingVHigh: + case kTcl112AcSwingVMiddle: + case kTcl112AcSwingVLow: + case kTcl112AcSwingVLowest: + case kTcl112AcSwingVOn: + _.SwingV = setting; + } } /// Get the vertical swing setting of the A/C. -/// @return true, the setting is on. false, the setting is off. -bool IRTcl112Ac::getSwingVertical(void) const { return _.SwingV; } +/// @return The current setting. +uint8_t IRTcl112Ac::getSwingVertical(void) const { return _.SwingV; } /// Set the Turbo setting of the A/C. /// @param[in] on true, the setting is on. false, the setting is off. @@ -291,6 +333,36 @@ bool IRTcl112Ac::getQuiet(const bool def) const { return _quiet_explictly_set ? _quiet : def; } +/// Get how long the On Timer is set for, in minutes. +/// @return The time in nr of minutes. +uint16_t IRTcl112Ac::getOnTimer(void) const { + return _.OnTimer * kTcl112AcTimerResolution; +} + +/// Set or cancel the On Timer function. +/// @param[in] mins Nr. of minutes the timer is to be set to. +/// @note Rounds down to 20 min increments. (max: 720 mins (12h), 0 is Off) +void IRTcl112Ac::setOnTimer(const uint16_t mins) { + _.OnTimer = std::min(mins, kTcl112AcTimerMax) / kTcl112AcTimerResolution; + _.OnTimerEnabled = _.OnTimer > 0; + _.TimerIndicator = _.OnTimerEnabled || _.OffTimerEnabled; +} + +/// Get how long the Off Timer is set for, in minutes. +/// @return The time in nr of minutes. +uint16_t IRTcl112Ac::getOffTimer(void) const { + return _.OffTimer * kTcl112AcTimerResolution; +} + +/// Set or cancel the Off Timer function. +/// @param[in] mins Nr. of minutes the timer is to be set to. +/// @note Rounds down to 20 min increments. (max: 720 mins (12h), 0 is Off) +void IRTcl112Ac::setOffTimer(const uint16_t mins) { + _.OffTimer = std::min(mins, kTcl112AcTimerMax) / kTcl112AcTimerResolution; + _.OffTimerEnabled = _.OffTimer > 0; + _.TimerIndicator = _.OnTimerEnabled || _.OffTimerEnabled; +} + /// Convert a stdAc::opmode_t enum into its native mode. /// @param[in] mode The enum to be converted. /// @return The native equivalent of the enum. @@ -309,7 +381,7 @@ uint8_t IRTcl112Ac::convertMode(const stdAc::opmode_t mode) { /// @return The native equivalent of the enum. uint8_t IRTcl112Ac::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { - case stdAc::fanspeed_t::kMin: + case stdAc::fanspeed_t::kMin: return kTcl112AcFanMin; case stdAc::fanspeed_t::kLow: return kTcl112AcFanLow; case stdAc::fanspeed_t::kMedium: return kTcl112AcFanMed; case stdAc::fanspeed_t::kHigh: @@ -331,6 +403,21 @@ stdAc::opmode_t IRTcl112Ac::toCommonMode(const uint8_t mode) { } } +/// Convert a stdAc::swingv_t enum into it's native setting. +/// @param[in] position The enum to be converted. +/// @return The native equivalent of the enum. +uint8_t IRTcl112Ac::convertSwingV(const stdAc::swingv_t position) { + switch (position) { + case stdAc::swingv_t::kOff: return kTcl112AcSwingVOff; + case stdAc::swingv_t::kHighest: return kTcl112AcSwingVHighest; + case stdAc::swingv_t::kHigh: return kTcl112AcSwingVHigh; + case stdAc::swingv_t::kMiddle: return kTcl112AcSwingVMiddle; + case stdAc::swingv_t::kLow: return kTcl112AcSwingVLow; + case stdAc::swingv_t::kLowest: return kTcl112AcSwingVLowest; + default: return kTcl112AcSwingVOn; + } +} + /// Convert a native fan speed into its stdAc equivalent. /// @param[in] spd The native setting to be converted. /// @return The stdAc equivalent of the native setting. @@ -338,11 +425,21 @@ stdAc::fanspeed_t IRTcl112Ac::toCommonFanSpeed(const uint8_t spd) { switch (spd) { case kTcl112AcFanHigh: return stdAc::fanspeed_t::kMax; case kTcl112AcFanMed: return stdAc::fanspeed_t::kMedium; - case kTcl112AcFanLow: return stdAc::fanspeed_t::kMin; + case kTcl112AcFanLow: return stdAc::fanspeed_t::kLow; + case kTcl112AcFanMin: return stdAc::fanspeed_t::kMin; default: return stdAc::fanspeed_t::kAuto; } } +/// Convert a native vertical swing postion to it's common equivalent. +/// @param[in] setting A native position to convert. +/// @return The common vertical swing position. +stdAc::swingv_t IRTcl112Ac::toCommonSwingV(const uint8_t setting) { + switch (setting) { + case kTcl112AcSwingVOff: return stdAc::swingv_t::kOff; + default: return stdAc::swingv_t::kAuto; + } +} /// Convert the current internal state into its stdAc::state_t equivalent. /// @param[in] prev Ptr to the previous state if required. /// @return The stdAc equivalent of the native settings. @@ -351,7 +448,7 @@ stdAc::state_t IRTcl112Ac::toCommon(const stdAc::state_t *prev) const { // Start with the previous state if given it. if (prev != NULL) result = *prev; result.protocol = decode_type_t::TCL112AC; - result.model = -1; // Not supported. + result.model = getModel(); result.quiet = getQuiet(result.quiet); // The rest only get updated if it is a "normal" message. if (_.MsgType == kTcl112AcNormal) { @@ -360,7 +457,7 @@ stdAc::state_t IRTcl112Ac::toCommon(const stdAc::state_t *prev) const { result.celsius = true; result.degrees = getTemp(); result.fanspeed = toCommonFanSpeed(_.Fan); - result.swingv = _.SwingV ? stdAc::swingv_t::kAuto : stdAc::swingv_t::kOff; + result.swingv = toCommonSwingV(_.SwingV); result.swingh = _.SwingH ? stdAc::swingh_t::kAuto : stdAc::swingh_t::kOff; result.turbo = _.Turbo; result.filter = _.Health; @@ -379,8 +476,10 @@ stdAc::state_t IRTcl112Ac::toCommon(const stdAc::state_t *prev) const { /// @return A human readable string. String IRTcl112Ac::toString(void) const { String result = ""; - result.reserve(150); // Reserve some heap for the string to reduce fragging. - result += addIntToString(_.MsgType, D_STR_TYPE, false); + result.reserve(220); // Reserve some heap for the string to reduce fragging. + tcl_ac_remote_model_t model = getModel(); + result += addModelToString(decode_type_t::TCL112AC, model, false); + result += addIntToString(_.MsgType, D_STR_TYPE); switch (_.MsgType) { case kTcl112AcNormal: result += addBoolToString(_.Power, kPowerStr); @@ -388,14 +487,32 @@ String IRTcl112Ac::toString(void) const { kTcl112AcHeat, kTcl112AcDry, kTcl112AcFan); result += addTempFloatToString(getTemp()); result += addFanToString(_.Fan, kTcl112AcFanHigh, kTcl112AcFanLow, - kTcl112AcFanAuto, kTcl112AcFanAuto, + kTcl112AcFanAuto, kTcl112AcFanMin, kTcl112AcFanMed); - result += addBoolToString(_.Econo, kEconoStr); - result += addBoolToString(_.Health, kHealthStr); - result += addBoolToString(_.Turbo, kTurboStr); - result += addBoolToString(_.SwingH, kSwingHStr); - result += addBoolToString(_.SwingV, kSwingVStr); - result += addBoolToString(getLight(), kLightStr); + result += addSwingVToString(_.SwingV, kTcl112AcSwingVOff, + kTcl112AcSwingVHighest, + kTcl112AcSwingVHigh, + 0xFF, // unused + kTcl112AcSwingVMiddle, + 0xFF, // unused + kTcl112AcSwingVLow, + kTcl112AcSwingVLowest, + kTcl112AcSwingVOff, + kTcl112AcSwingVOn, // Swing + 0xFF, 0xFF); // Both Unused + if (model != tcl_ac_remote_model_t::GZ055BE1) { + result += addBoolToString(_.SwingH, kSwingHStr); + result += addBoolToString(_.Econo, kEconoStr); + result += addBoolToString(_.Health, kHealthStr); + result += addBoolToString(_.Turbo, kTurboStr); + result += addBoolToString(getLight(), kLightStr); + } + result += addLabeledString( + _.OnTimerEnabled ? minsToString(getOnTimer()) : kOffStr, + kOnTimerStr); + result += addLabeledString( + _.OffTimerEnabled ? minsToString(getOffTimer()) : kOffStr, + kOffTimerStr); break; case kTcl112AcSpecial: result += addBoolToString(_.Quiet, kQuietStr); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.h index b9f059627..e1696c42a 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Tcl.h @@ -4,8 +4,10 @@ /// @brief Support for TCL protocols. // Supports: -// Brand: Leberg, Model: LBS-TOR07 A/C -// Brand: TCL, Model: TAC-09CHSD/XA31I A/C +// Brand: Leberg, Model: LBS-TOR07 A/C (TAC09CHSD) +// Brand: TCL, Model: TAC-09CHSD/XA31I A/C (TAC09CHSD) +// Brand: Teknopoint, Model: Allegro SSA-09H A/C (GZ055BE1) +// Brand: Teknopoint, Model: GZ-055B-E1 remote (GZ055BE1) #ifndef IR_TCL_H_ #define IR_TCL_H_ @@ -25,41 +27,54 @@ union Tcl112Protocol{ uint8_t raw[kTcl112AcStateLength]; ///< The State in IR code form. struct { // Byte 0~2 - uint8_t pad0[3]; + uint8_t :8; + uint8_t :8; + uint8_t :8; // Byte 3 - uint8_t MsgType :2; - uint8_t :6; + uint8_t MsgType :2; + uint8_t :6; // Byte 4 - uint8_t :8; + uint8_t :8; // Byte 5 - uint8_t :2; - uint8_t Power :1; - uint8_t :2; - uint8_t Quiet :1; - uint8_t Light :1; - uint8_t Econo :1; + uint8_t :2; + uint8_t Power :1; + uint8_t OffTimerEnabled :1; + uint8_t OnTimerEnabled :1; + uint8_t Quiet :1; + uint8_t Light :1; + uint8_t Econo :1; // Byte 6 - uint8_t Mode :4; - uint8_t Health :1; - uint8_t Turbo :1; - uint8_t :2; + uint8_t Mode :4; + uint8_t Health :1; + uint8_t Turbo :1; + uint8_t :2; // Byte 7 - uint8_t Temp :4; - uint8_t :4; + uint8_t Temp :4; + uint8_t :4; // Byte 8 - uint8_t Fan :3; - uint8_t SwingV :3; - uint8_t :2; - // Byte 9~11 - uint8_t pad1[3]; + uint8_t Fan :3; + uint8_t SwingV :3; + uint8_t TimerIndicator :1; + uint8_t :1; + // Byte 9 + uint8_t :1; // 0 + uint8_t OffTimer :6; + uint8_t :1; // 0 + // Byte 10 + uint8_t :1; // 0 + uint8_t OnTimer :6; + uint8_t :1; // 0 + // Byte 11 + uint8_t :8; // 00000000 // Byte 12 - uint8_t :3; - uint8_t SwingH :1; - uint8_t :1; - uint8_t HalfDegree :1; - uint8_t :2; + uint8_t :3; + uint8_t SwingH :1; + uint8_t :1; + uint8_t HalfDegree :1; + uint8_t :1; + uint8_t isTcl :1; // Byte 13 - uint8_t Sum :8; + uint8_t Sum :8; }; }; @@ -81,15 +96,23 @@ const uint8_t kTcl112AcFan = 7; const uint8_t kTcl112AcAuto = 8; const uint8_t kTcl112AcFanAuto = 0b000; +const uint8_t kTcl112AcFanMin = 0b001; // Aka. "Night" const uint8_t kTcl112AcFanLow = 0b010; const uint8_t kTcl112AcFanMed = 0b011; const uint8_t kTcl112AcFanHigh = 0b101; +const uint8_t kTcl112AcFanNight = kTcl112AcFanMin; +const uint8_t kTcl112AcFanQuiet = kTcl112AcFanMin; const float kTcl112AcTempMax = 31.0; const float kTcl112AcTempMin = 16.0; -const uint8_t kTcl112AcSwingVOn = 0b111; -const uint8_t kTcl112AcSwingVOff = 0b000; +const uint8_t kTcl112AcSwingVOff = 0b000; +const uint8_t kTcl112AcSwingVHighest = 0b001; +const uint8_t kTcl112AcSwingVHigh = 0b010; +const uint8_t kTcl112AcSwingVMiddle = 0b011; +const uint8_t kTcl112AcSwingVLow = 0b100; +const uint8_t kTcl112AcSwingVLowest = 0b101; +const uint8_t kTcl112AcSwingVOn = 0b111; // MsgType const uint8_t kTcl112AcNormal = 0b01; const uint8_t kTcl112AcSpecial = 0b10; @@ -113,6 +136,8 @@ class IRTcl112Ac { uint8_t* getRaw(void); void setRaw(const uint8_t new_code[], const uint16_t length = kTcl112AcStateLength); + tcl_ac_remote_model_t getModel(void) const; + void setModel(const tcl_ac_remote_model_t model); void on(void); void off(void); void setPower(const bool on); @@ -135,16 +160,23 @@ class IRTcl112Ac { bool getLight(void) const; void setSwingHorizontal(const bool on); bool getSwingHorizontal(void) const; - void setSwingVertical(const bool on); - bool getSwingVertical(void) const; + void setSwingVertical(const uint8_t setting); + uint8_t getSwingVertical(void) const; void setTurbo(const bool on); bool getTurbo(void) const; void setQuiet(const bool on); bool getQuiet(const bool def = false) const; + uint16_t getOnTimer(void) const; + void setOnTimer(const uint16_t mins); + uint16_t getOffTimer(void) const; + void setOffTimer(const uint16_t mins); + static bool isTcl(const uint8_t state[]); static uint8_t convertMode(const stdAc::opmode_t mode); static uint8_t convertFan(const stdAc::fanspeed_t speed); + static uint8_t convertSwingV(const stdAc::swingv_t position); static stdAc::opmode_t toCommonMode(const uint8_t mode); static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed); + static stdAc::swingv_t toCommonSwingV(const uint8_t setting); stdAc::state_t toCommon(const stdAc::state_t *prev = NULL) const; String toString(void) const; #ifndef UNIT_TEST diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Transcold.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Transcold.cpp index 066196073..14cc7f8bd 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Transcold.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/ir_Transcold.cpp @@ -29,7 +29,7 @@ using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; using irutils::addTempToString; - +using irutils::addToggleToString; #if SEND_TRANSCOLD /// Send a Transcold message @@ -391,13 +391,7 @@ String IRTranscoldAc::toString(void) const { result += addBoolToString(getPower(), kPowerStr, false); if (!getPower()) return result; // If it's off, there is no other info. // Special modes. - if (getSwing()) { - result += kCommaSpaceStr; - result += kSwingStr; - result += kColonSpaceStr; - result += kToggleStr; - return result; - } + if (getSwing()) return result + addToggleToString(true, kSwingStr); result += addModeToString(getMode(), kTranscoldAuto, kTranscoldCool, kTranscoldHeat, kTranscoldDry, kTranscoldFan); result += addIntToString(_.Fan, kFanStr); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/defaults.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/defaults.h index b55b87abc..0fcc04791 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/defaults.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/defaults.h @@ -30,9 +30,15 @@ #ifndef D_STR_ON #define D_STR_ON "On" #endif // D_STR_ON +#ifndef D_STR_1 +#define D_STR_1 "1" +#endif // D_STR_1 #ifndef D_STR_OFF #define D_STR_OFF "Off" #endif // D_STR_OFF +#ifndef D_STR_0 +#define D_STR_0 "0" +#endif // D_STR_0 #ifndef D_STR_MODE #define D_STR_MODE "Mode" #endif // D_STR_MODE @@ -285,6 +291,9 @@ #ifndef D_STR_VANE #define D_STR_VANE "Vane" #endif // D_STR_VANE +#ifndef D_STR_LOCK +#define D_STR_LOCK "Lock" +#endif // D_STR_LOCK #ifndef D_STR_AUTO #define D_STR_AUTO "Auto" @@ -298,18 +307,42 @@ #ifndef D_STR_COOL #define D_STR_COOL "Cool" #endif // D_STR_COOL +#ifndef D_STR_COOLING +#define D_STR_COOLING "Cooling" +#endif // D_STR_COOLING #ifndef D_STR_HEAT #define D_STR_HEAT "Heat" #endif // D_STR_HEAT +#ifndef D_STR_HEATING +#define D_STR_HEATING "Heating" +#endif // D_STR_HEATING #ifndef D_STR_FAN #define D_STR_FAN "Fan" #endif // D_STR_FAN #ifndef D_STR_FANONLY -#define D_STR_FANONLY "fan_only" +#define D_STR_FANONLY "fan-only" #endif // D_STR_FANONLY +#ifndef D_STR_FAN_ONLY +#define D_STR_FAN_ONLY "fan_only" +#endif // D_STR_FAN_ONLY +#ifndef D_STR_ONLY +#define D_STR_ONLY "Only" +#endif // D_STR_ONLY +#ifndef D_STR_FANSPACEONLY +#define D_STR_FANSPACEONLY D_STR_FAN " " D_STR_ONLY +#endif // D_STR_FANSPACEONLY +#ifndef D_STR_FANONLYNOSPACE +#define D_STR_FANONLYNOSPACE D_STR_FAN D_STR_ONLY +#endif // D_STR_FANONLYNOSPACE #ifndef D_STR_DRY #define D_STR_DRY "Dry" #endif // D_STR_DRY +#ifndef D_STR_DRYING +#define D_STR_DRYING "Drying" +#endif // D_STR_DRYING +#ifndef D_STR_DEHUMIDIFY +#define D_STR_DEHUMIDIFY "Dehumidify" +#endif // D_STR_DEHUMIDIFY #ifndef D_STR_MAX #define D_STR_MAX "Max" @@ -360,6 +393,12 @@ #ifndef D_STR_MAXRIGHT #define D_STR_MAXRIGHT D_STR_MAX " " D_STR_RIGHT // Set `D_STR_MAX` first! #endif // D_STR_MAXRIGHT +#ifndef D_STR_MAXRIGHT_NOSPACE +#define D_STR_MAXRIGHT_NOSPACE D_STR_MAX D_STR_RIGHT // Set `D_STR_MAX` first! +#endif // D_STR_MAXRIGHT_NOSPACE +#ifndef D_STR_RIGHTMAX +#define D_STR_RIGHTMAX D_STR_RIGHT " " D_STR_MAX // Set `D_STR_MAX` first! +#endif // D_STR_RIGHTMAX #ifndef D_STR_RIGHTMAX_NOSPACE #define D_STR_RIGHTMAX_NOSPACE D_STR_RIGHT D_STR_MAX // Set `D_STR_MAX` first! #endif // D_STR_RIGHTMAX_NOSPACE @@ -369,6 +408,12 @@ #ifndef D_STR_MAXLEFT #define D_STR_MAXLEFT D_STR_MAX " " D_STR_LEFT // Set `D_STR_MAX` first! #endif // D_STR_MAXLEFT +#ifndef D_STR_MAXLEFT_NOSPACE +#define D_STR_MAXLEFT_NOSPACE D_STR_MAX D_STR_LEFT // Set `D_STR_MAX` first! +#endif // D_STR_MAXLEFT_NOSPACE +#ifndef D_STR_LEFTMAX +#define D_STR_LEFTMAX D_STR_LEFT " " D_STR_MAX // Set `D_STR_MAX` first! +#endif // D_STR_LEFTMAX #ifndef D_STR_LEFTMAX_NOSPACE #define D_STR_LEFTMAX_NOSPACE D_STR_LEFT D_STR_MAX // Set `D_STR_MAX` first! #endif // D_STR_LEFTMAX_NOSPACE @@ -440,6 +485,9 @@ #ifndef D_STR_COLONSPACE #define D_STR_COLONSPACE ": " #endif // D_STR_COLONSPACE +#ifndef D_STR_DASH +#define D_STR_DASH "-" +#endif // D_STR_DASH #ifndef D_STR_DAY #define D_STR_DAY "Day" @@ -495,7 +543,135 @@ #define D_STR_BITS "Bits" #endif // D_STR_BITS +// Model Names +#ifndef D_STR_YAW1F +#define D_STR_YAW1F "YAW1F" +#endif // D_STR_YAW1F +#ifndef D_STR_YBOFB +#define D_STR_YBOFB "YBOFB" +#endif // D_STR_YBOFB +#ifndef D_STR_V9014557_A +#define D_STR_V9014557_A "V9014557-A" +#endif // D_STR_V9014557_A +#ifndef D_STR_V9014557_B +#define D_STR_V9014557_B "V9014557-B" +#endif // D_STR_V9014557_B +#ifndef D_STR_RLT0541HTA_A +#define D_STR_RLT0541HTA_A "R-LT0541-HTA-A" +#endif // D_STR_RLT0541HTA_A +#ifndef D_STR_RLT0541HTA_B +#define D_STR_RLT0541HTA_B "R-LT0541-HTA-B" +#endif // D_STR_RLT0541HTA_B +#ifndef D_STR_ARRAH2E +#define D_STR_ARRAH2E "ARRAH2E" +#endif // D_STR_ARRAH2E +#ifndef D_STR_ARDB1 +#define D_STR_ARDB1 "ARDB1" +#endif // D_STR_ARDB1 +#ifndef D_STR_ARREB1E +#define D_STR_ARREB1E "ARREB1E" +#endif // D_STR_ARREB1E +#ifndef D_STR_ARJW2 +#define D_STR_ARJW2 "ARJW2" +#endif // D_STR_ARJW2 +#ifndef D_STR_ARRY4 +#define D_STR_ARRY4 "ARRY4" +#endif // D_STR_ARRY4 +#ifndef D_STR_ARREW4E +#define D_STR_ARREW4E "ARREW4E" +#endif // D_STR_ARREW4E +#ifndef D_STR_GE6711AR2853M +#define D_STR_GE6711AR2853M "GE6711AR2853M" +#endif // D_STR_GE6711AR2853M +#ifndef D_STR_AKB75215403 +#define D_STR_AKB75215403 "AKB75215403" +#endif // D_STR_AKB75215403 +#ifndef D_STR_AKB74955603 +#define D_STR_AKB74955603 "AKB74955603" +#endif // D_STR_AKB74955603 +#ifndef D_STR_AKB73757604 +#define D_STR_AKB73757604 "AKB73757604" +#endif // D_STR_AKB73757604 +#ifndef D_STR_KKG9AC1 +#define D_STR_KKG9AC1 "KKG9AC1" +#endif // D_STR_KKG9AC1 +#ifndef D_STR_KKG29AC1 +#define D_STR_KKG29AC1 "KKG29AC1" +#endif // D_STR_KKG9AC1 +#ifndef D_STR_LKE +#define D_STR_LKE "LKE" +#endif // D_STR_LKE +#ifndef D_STR_NKE +#define D_STR_NKE "NKE" +#endif // D_STR_NKE +#ifndef D_STR_DKE +#define D_STR_DKE "DKE" +#endif // D_STR_DKE +#ifndef D_STR_PKR +#define D_STR_PKR "PKR" +#endif // D_STR_PKR +#ifndef D_STR_JKE +#define D_STR_JKE "JKE" +#endif // D_STR_JKE +#ifndef D_STR_CKP +#define D_STR_CKP "CKP" +#endif // D_STR_CKP +#ifndef D_STR_RKR +#define D_STR_RKR "RKR" +#endif // D_STR_RKR +#ifndef D_STR_PANASONICLKE +#define D_STR_PANASONICLKE "PANASONICLKE" +#endif // D_STR_PANASONICLKE +#ifndef D_STR_PANASONICNKE +#define D_STR_PANASONICNKE "PANASONICNKE" +#endif // D_STR_PANASONICNKE +#ifndef D_STR_PANASONICDKE +#define D_STR_PANASONICDKE "PANASONICDKE" +#endif // D_STR_PANASONICDKE +#ifndef D_STR_PANASONICPKR +#define D_STR_PANASONICPKR "PANASONICPKR" +#endif // D_STR_PANASONICPKR +#ifndef D_STR_PANASONICJKE +#define D_STR_PANASONICJKE "PANASONICJKE" +#endif // D_STR_PANASONICJKE +#ifndef D_STR_PANASONICCKP +#define D_STR_PANASONICCKP "PANASONICCKP" +#endif // D_STR_PANASONICCKP +#ifndef D_STR_PANASONICRKR +#define D_STR_PANASONICRKR "PANASONICRKR" +#endif // D_STR_PANASONICRKR +#ifndef D_STR_A907 +#define D_STR_A907 "A907" +#endif // D_STR_A907 +#ifndef D_STR_A705 +#define D_STR_A705 "A705" +#endif // D_STR_A705 +#ifndef D_STR_A903 +#define D_STR_A903 "A903" +#endif // D_STR_A903 +#ifndef D_STR_TAC09CHSD +#define D_STR_TAC09CHSD "TAC09CHSD" +#endif // D_STR_TAC09CHSD +#ifndef D_STR_GZ055BE1 +#define D_STR_GZ055BE1 "GZ055BE1" +#endif // D_STR_GZ055BE1 +#ifndef D_STR_122LZF +#define D_STR_122LZF "122LZF" +#endif // D_STR_122LZF +#ifndef D_STR_DG11J13A +#define D_STR_DG11J13A "DG11J13A" +#endif // D_STR_DG11J13A +#ifndef D_STR_DG11J104 +#define D_STR_DG11J104 "DG11J104" +#endif // D_STR_DG11J104 +#ifndef D_STR_DG11J191 +#define D_STR_DG11J191 "DG11J191" +#endif // D_STR_DG11J191 + // Protocols Names +#ifndef D_STR_AIRTON +#define D_STR_AIRTON "AIRTON" +#endif // D_STR_AIRTON #ifndef D_STR_AIRWELL #define D_STR_AIRWELL "AIRWELL" #endif // D_STR_AIRWELL @@ -508,6 +684,9 @@ #ifndef D_STR_ARGO #define D_STR_ARGO "ARGO" #endif // D_STR_ARGO +#ifndef D_STR_ARRIS +#define D_STR_ARRIS "ARRIS" +#endif // D_STR_ARRIS #ifndef D_STR_BOSE #define D_STR_BOSE "BOSE" #endif // D_STR_BOSE @@ -733,6 +912,9 @@ #ifndef D_STR_RCMM #define D_STR_RCMM "RCMM" #endif // D_STR_RCMM +#ifndef D_STR_RHOSS +#define D_STR_RHOSS "RHOSS" +#endif // D_STR_RHOSS #ifndef D_STR_SAMSUNG #define D_STR_SAMSUNG "SAMSUNG" #endif // D_STR_SAMSUNG diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/pt-BR.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/pt-BR.h index 4875dda0d..4b2c929e0 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/pt-BR.h +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/pt-BR.h @@ -29,6 +29,7 @@ #define D_STR_TIMER "Timer" #define D_STR_ONTIMER D_STR_TIMER " " D_STR_ON #define D_STR_OFFTIMER D_STR_TIMER " " D_STR_OFF +#define D_STR_TIMERMODE D_STR_MODE " " D_STR_TIMER #define D_STR_CLOCK "Relógio" #define D_STR_COMMAND "Comando" #define D_STR_HEALTH "Saúde" @@ -84,6 +85,11 @@ #define D_STR_6THSENSE "Sexto sentido" #define D_STR_ZONEFOLLOW "Acompanhar ambiente" #define D_STR_FIXED "Fixo" +#define D_STR_TYPE "Tipo" +#define D_STR_SPECIAL "Especial" +#define D_STR_RECYCLE "Reciclar" +#define D_STR_ID "Id" +#define D_STR_VANE "Vane" #define D_STR_AUTO "Auto" #define D_STR_AUTOMATIC "Automático" @@ -91,7 +97,11 @@ #define D_STR_COOL "Esfriar" #define D_STR_HEAT "Aquecer" #define D_STR_FAN "Ventilar" -#define D_STR_FANONLY "Apenas ventilar" +#define D_STR_FANONLY "Apenas-ventilar" +#define D_STR_FAN_ONLY "Apenas_ventilar" +#define D_STR_ONLY "Apenas" +#define D_STR_FANSPACEONLY D_STR_ONLY " " D_STR_FAN +#define D_STR_FANONLYNOSPACE D_STR_ONLY D_STR_FAN #define D_STR_DRY "Secar" #define D_STR_8C_HEAT D_STR_HEAT " 8C" diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/ru-RU.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/ru-RU.h new file mode 100644 index 000000000..02a892403 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/ru-RU.h @@ -0,0 +1,152 @@ +// Copyright 2021 - PtilopsisLeucotis (@PtilopsisLeucotis) +// Locale/language file for Russian / Russia. +// This file will override the default values located in `defaults.h`. +#ifndef LOCALE_RU_RU_H_ +#define LOCALE_RU_RU_H_ + +#define D_STR_UNKNOWN "НЕИЗВЕСТНО" +#define D_STR_PROTOCOL "Протокол" +#define D_STR_POWER "Питание" +#define D_STR_PREVIOUS "Предыдущий" +#define D_STR_ON "Вкл" +#define D_STR_OFF "Выкл" +#define D_STR_MODE "Режим" +#define D_STR_TOGGLE "Переключить" +#define D_STR_TURBO "Турбо" +#define D_STR_SUPER "Супер" +#define D_STR_SLEEP "Сон" +#define D_STR_LIGHT "Свет" +#define D_STR_POWERFUL "Мощный" +#define D_STR_QUIET "Тихий" +#define D_STR_ECONO "Экономичный" +#define D_STR_SWING "Качание" +#define D_STR_SWINGH D_STR_SWING"(Г)" +#define D_STR_SWINGV D_STR_SWING"(В)" +#define D_STR_BEEP "Звук" +#define D_STR_MOULD "Плесень" +#define D_STR_CLEAN "Чистый" +#define D_STR_PURIFY "Очистка" +#define D_STR_TIMER "Таймер" +#define D_STR_ONTIMER "Таймер Включения" +#define D_STR_OFFTIMER "Таймер Выключения" +#define D_STR_TIMERMODE "Режим Таймера" +#define D_STR_CLOCK "Часы" +#define D_STR_COMMAND "Команда" +#define D_STR_HEALTH "Здоровье" +#define D_STR_MODEL "Модель" +#define D_STR_TEMP "Температура" +#define D_STR_HUMID "Влажность" +#define D_STR_SAVE "Сохранить" +#define D_STR_EYE "Глаз" +#define D_STR_FOLLOW "Следовать" +#define D_STR_ION "Ион" +#define D_STR_FRESH "Свежесть" +#define D_STR_HOLD "Удержать" +#define D_STR_BUTTON "Кнопка" +#define D_STR_NIGHT "Ночь" +#define D_STR_SILENT "Тихий" +#define D_STR_FILTER "Фильтр" +#define D_STR_CELSIUS "Цельсий" +#define D_STR_FAHRENHEIT "Фаренгейт" +#define D_STR_UP "Выше" +#define D_STR_TEMPUP D_STR_TEMP " " D_STR_UP +#define D_STR_DOWN "Ниже" +#define D_STR_TEMPDOWN D_STR_TEMP " " D_STR_DOWN +#define D_STR_CHANGE "Изменение" +#define D_STR_START "Запуск" +#define D_STR_STOP "Остановка" +#define D_STR_MOVE "Перемещение" +#define D_STR_SET "Установка" +#define D_STR_CANCEL "Отмена" +#define D_STR_COMFORT "Комфорт" +#define D_STR_SENSOR "Сенсор" +#define D_STR_DISPLAY "Дисплей" +#define D_STR_WEEKLY "Недельный" +#define D_STR_LAST "Последний" +#define D_STR_FAST "Быстро" +#define D_STR_SLOW "Медленно" +#define D_STR_AIRFLOW "Воздушный Поток" +#define D_STR_STEP "Шаг" +#define D_STR_NA "Н/Д" +#define D_STR_INSIDE "Внутри" +#define D_STR_OUTSIDE "Снаружи" +#define D_STR_LOUD "Громко" +#define D_STR_UPPER "Верхнее" +#define D_STR_LOWER "Нижнее" +#define D_STR_BREEZE "Бриз" +#define D_STR_CIRCULATE "Циркуляция" +#define D_STR_CEILING "Потолок" +#define D_STR_WALL "Стена" +#define D_STR_ROOM "Комната" +#define D_STR_6THSENSE "6-ое чувство" +#define D_STR_FIXED "Фиксированный" +#define D_STR_TYPE "Тип" +#define D_STR_SPECIAL "Специальный" +#define D_STR_RECYCLE "Рециркуляция" +#define D_STR_VANE "Жалюзи" +#define D_STR_LOCK "Блокировка" +#define D_STR_AUTO "Авто" +#define D_STR_AUTOMATIC "Автоматический" +#define D_STR_MANUAL "Ручной" +#define D_STR_COOL "Охл" +#define D_STR_COOLING "Охлаждение" +#define D_STR_HEAT "Нагр" +#define D_STR_HEATING "Обогрев" +#define D_STR_FAN "Вентиляция" +#define D_STR_ONLY "Только" +#define D_STR_FANSPACEONLY D_STR_ONLY " " D_STR_FAN +#define D_STR_FANONLYNOSPACE D_STR_ONLY D_STR_FAN +#define D_STR_DRY "Сухо" +#define D_STR_DRYING "Сушка" +#define D_STR_DEHUMIDIFY "Осушение" +#define D_STR_MAX "Макс" +#define D_STR_MAXIMUM "Максимум" +#define D_STR_MIN "Мин" +#define D_STR_MINIMUM "Минимум" +#define D_STR_MED "Сред" +#define D_STR_MEDIUM "Среднее" +#define D_STR_HIGHEST "Верхнее" +#define D_STR_HIGH "Верх" +#define D_STR_HI "Верх" +#define D_STR_MID "Сред" +#define D_STR_MIDDLE "Середина" +#define D_STR_LOW "Низ" +#define D_STR_LO "Низ" +#define D_STR_LOWEST "Нижнее" +#define D_STR_RIGHT "Право" +#define D_STR_LEFT "Лево" +#define D_STR_WIDE "Широкий" +#define D_STR_CENTRE "Центр" +#define D_STR_TOP "Наивысший" +#define D_STR_BOTTOM "Наинизший" +#define D_STR_DAY "День" +#define D_STR_DAYS "Дней" +#define D_STR_HOUR "Час" +#define D_STR_HOURS "Часов" +#define D_STR_MINUTE "Минута" +#define D_STR_MINUTES "Минут" +#define D_STR_SECOND "Секунда" +#define D_STR_SECONDS "Секунд" +#define D_STR_NOW "Сейчас" +#define D_STR_THREELETTERDAYS "ВскПндВтрСреЧтвПтнСуб" +#define D_STR_YES "Да" +#define D_STR_NO "Нет" +#define D_STR_TRUE "Истина" +#define D_STR_FALSE "Ложь" +#define D_STR_REPEAT "Повтор" +#define D_STR_CODE "Код" +#define D_STR_BITS "Бит" + +// IRrecvDumpV2+ +#define D_STR_TIMESTAMP "Метка Времени" +#define D_STR_LIBRARY "Библиотека" +#define D_STR_MESGDESC "Описание Сообщения." +#define D_STR_TOLERANCE "Допуск" +#define D_STR_IRRECVDUMP_STARTUP \ + "IRrecvDump запущен и ождает ИК команды на Входе %d" +#define D_WARN_BUFFERFULL \ + "ПРЕДУПРЕЖДЕНИЕ: ИК код слишком велик для буфера (>= %d). " \ + "Этому результату не следует доверять, пока это не будет исправлено. " \ + "Исправьте и увеличьте `kCaptureBufferSize`." + +#endif // LOCALE_RU_RU_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/sv-SE.h b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/sv-SE.h new file mode 100644 index 000000000..b82ec42bc --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/locale/sv-SE.h @@ -0,0 +1,189 @@ +// Copyright 2021 - Tom Rosenback (@tomrosenback) +// Locale/language file for swedish / Sweden. +// This file will override the default values located in `defaults.h`. +#ifndef LOCALE_SV_SE_H_ +#define LOCALE_SV_SE_H_ + +#define D_STR_UNKNOWN "OKÄND" +#define D_STR_PROTOCOL "Protokoll" +#define D_STR_POWER "Strömläge" +#define D_STR_PREVIOUS "Föregående" +#define D_STR_ON "På" +#define D_STR_OFF "Av" +#define D_STR_MODE "Läge" +#define D_STR_TOGGLE "Växla" +#define D_STR_TURBO "Turbo" +#define D_STR_SUPER "Super" +#define D_STR_SLEEP "Sova" +#define D_STR_LIGHT "Svag" +#define D_STR_POWERFUL "Kraftig" +#define D_STR_QUIET "Tyst" +#define D_STR_ECONO "Eko" +#define D_STR_SWING "Sving" +#define D_STR_SWINGH D_STR_SWING"(H)" +#define D_STR_SWINGV D_STR_SWING"(V)" +#define D_STR_BEEP "Pip" +#define D_STR_MOULD "Forma" +#define D_STR_CLEAN "Rengör" +#define D_STR_PURIFY "Rena" +#define D_STR_TIMER "Timer" +#define D_STR_ONTIMER "På timer" +#define D_STR_OFFTIMER "Av timer" +#define D_STR_TIMERMODE "Timerläge" +#define D_STR_CLOCK "Klocka" +#define D_STR_COMMAND "Kommando" +#define D_STR_XFAN "XFan" +#define D_STR_HEALTH "Hälsa" +#define D_STR_MODEL "Modell" +#define D_STR_TEMP "Temp" +#define D_STR_IFEEL "Känns som" +#define D_STR_HUMID "Humid" +#define D_STR_SAVE "Save" +#define D_STR_EYE "Öga" +#define D_STR_FOLLOW "Följ" +#define D_STR_ION "Ion" +#define D_STR_FRESH "Frisk" +#define D_STR_HOLD "Håll" +#define D_STR_8C_HEAT "8C " D_STR_HEAT +#define D_STR_10C_HEAT "10C " D_STR_HEAT +#define D_STR_BUTTON "Knapp" +#define D_STR_NIGHT "Natt" +#define D_STR_SILENT "Tyst" +#define D_STR_FILTER "Filter" +#define D_STR_3D "3D" +#define D_STR_CELSIUS "Celsius" +#define D_STR_FAHRENHEIT "Fahrenheit" +#define D_STR_CELSIUS_FAHRENHEIT D_STR_CELSIUS "/" D_STR_FAHRENHEIT +#define D_STR_UP "Upp" +#define D_STR_TEMPUP D_STR_TEMP " upp" +#define D_STR_DOWN "Ner" +#define D_STR_TEMPDOWN D_STR_TEMP " ner" +#define D_STR_CHANGE "Ändra" +#define D_STR_START "Starta" +#define D_STR_STOP "Stoppa" +#define D_STR_MOVE "Flytta" +#define D_STR_SET "Ställ in" +#define D_STR_CANCEL "Avbryt" +#define D_STR_COMFORT "Komfort" +#define D_STR_SENSOR "Sensor" +#define D_STR_DISPLAY "Display" +#define D_STR_WEEKLY "Veckovis" +#define D_STR_WEEKLYTIMER D_STR_WEEKLY " timer" +#define D_STR_WIFI "WiFi" +#define D_STR_LAST "Senast" +#define D_STR_FAST "Snabb" +#define D_STR_SLOW "Sakta" +#define D_STR_AIRFLOW "Luftflöde" +#define D_STR_STEP "Steppa" +#define D_STR_NA "N/A" +#define D_STR_INSIDE "Inne" +#define D_STR_OUTSIDE "Ute" +#define D_STR_LOUD "Hög" +#define D_STR_UPPER "Övre" +#define D_STR_LOWER "Nedre" +#define D_STR_BREEZE "Bris" +#define D_STR_CIRCULATE "Cirkulera" +#define D_STR_CEILING "Tak" +#define D_STR_WALL "Vägg" +#define D_STR_ROOM "Rum" +#define D_STR_6THSENSE "6e sinne" +#define D_STR_ZONEFOLLOW "Följ zon" +#define D_STR_FIXED "Fast" +#define D_STR_TYPE "Typ" +#define D_STR_SPECIAL "Speciell" +#define D_STR_RECYCLE "Återvinn" +#define D_STR_ID "Id" +#define D_STR_VANE "Vindflöjel" + +#define D_STR_AUTO "Auto" +#define D_STR_AUTOMATIC "Automatisk" +#define D_STR_MANUAL "Manuell" +#define D_STR_COOL "Kyla" +#define D_STR_HEAT "Värme" +#define D_STR_FAN "Fläkt" +#define D_STR_FANONLY "fläkt-enbart" +#define D_STR_FAN_ONLY "fläkt_enbart" +#define D_STR_ONLY "Enbart" +#define D_STR_FANSPACEONLY D_STR_FAN " " D_STR_ONLY +#define D_STR_FANONLYNOSPACE D_STR_FAN D_STR_ONLY +#define D_STR_DRY "Torka" + +#define D_STR_MAX "Max" +#define D_STR_MAXIMUM "Maximum" +#define D_STR_MIN "Min" +#define D_STR_MINIMUM "Minimum" +#define D_STR_MED "Med" +#define D_STR_MEDIUM "Medium" + +#define D_STR_HIGHEST "Högsta" +#define D_STR_HIGH "Hög" +#define D_STR_HI "Hög" +#define D_STR_MID "Mellan" +#define D_STR_MIDDLE "Mellan" +#define D_STR_LOW "Låg" +#define D_STR_LO "Låg" +#define D_STR_LOWEST "Lägsta" +#define D_STR_RIGHT "Höger" +#define D_STR_MAXRIGHT D_STR_MAX " höger" +#define D_STR_RIGHTMAX_NOSPACE D_STR_MAX D_STR_RIGHT +#define D_STR_LEFT "Vänster" +#define D_STR_MAXLEFT D_STR_MAX " vänster" +#define D_STR_LEFTMAX_NOSPACE D_STR_MAX D_STR_LEFT +#define D_STR_WIDE "Vid" +#define D_STR_CENTRE "Mitten" +#define D_STR_TOP "Topp" +#define D_STR_BOTTOM "Botten" + +#define D_STR_ECONOTOGGLE D_STR_TOGGLE " eko" +#define D_STR_EYEAUTO D_STR_AUTO " öga" +#define D_STR_LIGHTTOGGLE D_STR_TOGGLE " svag" +#define D_STR_OUTSIDEQUIET D_STR_QUIET " ute" +#define D_STR_POWERTOGGLE D_STR_TOGGLE " strömläge" +#define D_STR_POWERBUTTON "Strömknapp" +#define D_STR_PREVIOUSPOWER "Föregående strömläge" +#define D_STR_DISPLAYTEMP "Displaytemp" +#define D_STR_SENSORTEMP "Sensortemp" +#define D_STR_SLEEP_TIMER "Sovtimer" +#define D_STR_SWINGVMODE D_STR_SWINGV " läge" +#define D_STR_SWINGVTOGGLE D_STR_TOGGLE " sving(v)" +#define D_STR_TURBOTOGGLE D_STR_TOGGLE " turbo" + +// Separatorer +#define D_CHR_TIME_SEP ':' +#define D_STR_SPACELBRACE " (" +#define D_STR_COMMASPACE ", " +#define D_STR_COLONSPACE ": " + +#define D_STR_DAY "Dag" +#define D_STR_DAYS D_STR_DAY "ar" +#define D_STR_HOUR "Timme" +#define D_STR_HOURS "Timmar" +#define D_STR_MINUTE "Minut" +#define D_STR_MINUTES D_STR_MINUTE "er" +#define D_STR_SECOND "Sekund" +#define D_STR_SECONDS D_STR_MINUTE "er" +#define D_STR_NOW "Nu" +#define D_STR_THREELETTERDAYS "SönMånTisOnsTorFreLör" + +#define D_STR_YES "Ja" +#define D_STR_NO "Nej" +#define D_STR_TRUE "Sant" +#define D_STR_FALSE "Falskt" + +#define D_STR_REPEAT "Upprepa" +#define D_STR_CODE "Kod" +#define D_STR_BITS "Bitar" + +// IRrecvDumpV2+ +#define D_STR_TIMESTAMP "Tidskod" +#define D_STR_LIBRARY "Bibliotek" +#define D_STR_MESGDESC "Meddelande beskr." +#define D_STR_TOLERANCE "Tolerans" +#define D_STR_IRRECVDUMP_STARTUP \ + "IRrecvDump har nu startats och väntar på IR signaler på PIN %d" +#define D_WARN_BUFFERFULL \ + "VARNING: IR koden är för stor för att rymmas i bufferminnet (>= %d). " \ + "Detta resultat är inte pålitligt innan problemet är åtgärdat. " \ + "Redigera och öka `kCaptureBufferSize`." + +#endif // LOCALE_SV_SE_H_ diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRac_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRac_test.cpp index 140e50137..d43cfcd9d 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRac_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/IRac_test.cpp @@ -19,6 +19,7 @@ #include "ir_Kelvinator.h" #include "ir_LG.h" #include "ir_Midea.h" +#include "ir_Mirage.h" #include "ir_Mitsubishi.h" #include "ir_MitsubishiHeavy.h" #include "ir_Neoclima.h" @@ -560,7 +561,8 @@ TEST(TestIRac, Electra) { IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 6 (Fan), Temp: 26C, Fan: 1 (High), " - "Swing(V): On, Swing(H): On, Light: Toggle, Clean: On, Turbo: On"; + "Swing(V): On, Swing(H): On, Light: Toggle, Clean: On, Turbo: On, " + "IFeel: Off"; ac.begin(); irac.electra(&ac, @@ -727,9 +729,10 @@ TEST(TestIRac, Gree) { IRrecv capture(kGpioUnused); char expected[] = "Model: 1 (YAW1F), Power: On, Mode: 1 (Cool), Temp: 71F, " - "Fan: 2 (Medium), Turbo: Off, IFeel: Off, WiFi: Off, XFan: On, " - "Light: On, Sleep: On, Swing(V) Mode: Manual, " - "Swing(V): 3 (UNKNOWN), Timer: Off, Display Temp: 0 (Off)"; + "Fan: 2 (Medium), Turbo: Off, Econo: Off, IFeel: Off, WiFi: Off, " + "XFan: On, Light: On, Sleep: On, Swing(V) Mode: Manual, " + "Swing(V): 3 (UNKNOWN), Swing(H): 5 (Right), Timer: Off, " + "Display Temp: 0 (Off)"; ac.begin(); irac.gree(&ac, @@ -740,7 +743,9 @@ TEST(TestIRac, Gree) { 71, // Degrees (F) stdAc::fanspeed_t::kMedium, // Fan speed stdAc::swingv_t::kHigh, // Vertical swing + stdAc::swingh_t::kRight, // Horizontal swing false, // Turbo + false, // Econo true, // Light true, // Clean (aka Mold/XFan) 8 * 60 + 0); // Sleep time @@ -760,7 +765,7 @@ TEST(TestIRac, Haier) { IRrecv capture(kGpioUnused); char expected[] = "Command: 1 (On), Mode: 1 (Cool), Temp: 24C, Fan: 2 (Medium), " - "Swing: 1 (Up), Sleep: On, Health: On, Clock: 13:45, " + "Swing(V): 1 (Up), Sleep: On, Health: On, Clock: 13:45, " "On Timer: Off, Off Timer: Off"; ac.begin(); @@ -788,19 +793,24 @@ TEST(TestIRac, Haier176) { IRac irac(kGpioUnused); IRrecv capture(kGpioUnused); const char expected[] = - "Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 23C, " - "Fan: 2 (Medium), Turbo: 1 (High), Swing: 1 (Highest), Sleep: On, " - "Health: On, Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off"; + "Model: 1 (V9014557-A), Power: On, Button: 5 (Power), " + "Mode: 1 (Cool), Temp: 23C, Fan: 2 (Medium), Turbo: On, Quiet: Off, " + "Swing(V): 1 (Highest), Swing(H): 0 (Middle), Sleep: On, Health: On, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off"; ac.begin(); irac.haier176(&ac, - true, // Power - stdAc::opmode_t::kCool, // Mode - 23, // Celsius - stdAc::fanspeed_t::kMedium, // Fan speed - stdAc::swingv_t::kHigh, // Vertical swing - true, // Turbo - true, // Filter - 8 * 60 + 0); // Sleep time + haier_ac176_remote_model_t::V9014557_A, // Model + true, // Power + stdAc::opmode_t::kCool, // Mode + true, // Celsius + 23, // Degrees + stdAc::fanspeed_t::kMedium, // Fan speed + stdAc::swingv_t::kHigh, // Vertical swing + stdAc::swingh_t::kOff, // Horizontal swing + true, // Turbo + false, // Quiet + true, // Filter + 8 * 60 + 0); // Sleep time ASSERT_EQ(expected, ac.toString()); ac._irsend.makeDecodeResult(); EXPECT_TRUE(capture.decode(&ac._irsend.capture)); @@ -816,20 +826,24 @@ TEST(TestIRac, HaierYrwo2) { IRac irac(kGpioUnused); IRrecv capture(kGpioUnused); char expected[] = - "Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 23C, " - "Fan: 2 (Medium), Turbo: 1 (High), Swing: 1 (Highest), Sleep: On, " - "Health: On, Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off"; + "Model: 1 (V9014557-A), Power: On, Button: 5 (Power), " + "Mode: 1 (Cool), Temp: 23C, Fan: 2 (Medium), Turbo: Off, Quiet: On, " + "Swing(V): 1 (Highest), Swing(H): 7 (Auto), Sleep: On, Health: On, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off"; ac.begin(); irac.haierYrwo2(&ac, - true, // Power - stdAc::opmode_t::kCool, // Mode - 23, // Celsius - stdAc::fanspeed_t::kMedium, // Fan speed - stdAc::swingv_t::kHigh, // Vertical swing - true, // Turbo - true, // Filter - 8 * 60 + 0); // Sleep time + true, // Power + stdAc::opmode_t::kCool, // Mode + true, // Celsius + 23, // Degrees + stdAc::fanspeed_t::kMedium, // Fan speed + stdAc::swingv_t::kHigh, // Vertical swing + stdAc::swingh_t::kAuto, // Vertical swing + false, // Turbo + true, // Quiet + true, // Filter + 8 * 60 + 0); // Sleep time ASSERT_EQ(expected, ac.toString()); ac._irsend.makeDecodeResult(); EXPECT_TRUE(capture.decode(&ac._irsend.capture)); @@ -1125,7 +1139,22 @@ TEST(TestIRac, Issue1513) { stdAc::swingh_t::kOff, // Horizontal swing true); // Light ac._irsend.makeDecodeResult(); - // All sent, we assume the above works. Just need to switch to swing off now. + EXPECT_EQ(121, ac._irsend.capture.rawlen); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(LG2, ac._irsend.capture.decode_type); // Not "LG" + ASSERT_EQ(kLgBits, ac._irsend.capture.bits); + ASSERT_EQ( + "Model: 2 (AKB75215403), Power: On, Mode: 4 (Heat), Temp: 26C, " + "Fan: 0 (Quiet)", + IRAcUtils::resultAcToString(&ac._irsend.capture)); + + // The next should be a SwingV On. + EXPECT_TRUE(capture.decodeLG(&ac._irsend.capture, 61)); + ASSERT_EQ(LG2, ac._irsend.capture.decode_type); // Not "LG" + ASSERT_EQ(kLgBits, ac._irsend.capture.bits); + EXPECT_EQ(kLgAcSwingVSwing, ac._irsend.capture.value); + ASSERT_EQ("Model: 3 (AKB74955603), Swing(V): 20 (Swing)", + IRAcUtils::resultAcToString(&ac._irsend.capture)); ac._irsend.reset(); ac.stateReset(); ac.send(); @@ -1163,6 +1192,79 @@ TEST(TestIRac, Issue1513) { IRAcUtils::resultAcToString(&ac._irsend.capture)); } +// Ref: +// https://github.com/crankyoldgit/IRremoteESP8266/issues/1651#issuecomment-952811720 +TEST(TestIRac, Issue1651) { + // Simulate sending a state with a SwingV off, then followed by a SwingV Auto. + IRLgAc ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); + ac.begin(); + // IRhvac {"Vendor":"LG2","Model":3,"Mode":"Auto","Power":"On","Celsius":"On", + // "Temp":15,"FanSpeed":"Auto","SwingV":"Off","SwingH":"Off", + // "Quiet":"Off","Turbo":"Off","Econo":"Off","Light":"On", + // "Filter":"Off","Clean":"Off","Beep":"Off","Sleep":-1} + ac._irsend.reset(); + irac.lg(&ac, + lg_ac_remote_model_t::AKB74955603, // Model + true, // Power + stdAc::opmode_t::kAuto, // Mode + 15, // Degrees C (Note: 16C is min) + stdAc::fanspeed_t::kAuto, // Fan speed + stdAc::swingv_t::kOff, // Vertical swing + stdAc::swingv_t::kOff, // Vertical swing (previous) + stdAc::swingh_t::kOff, // Horizontal swing + true); // Light + ac._irsend.makeDecodeResult(); + // As we are not making a change of the SwingV state, there should only be + // one message. (i.e. 60 + 1) + EXPECT_EQ(61, ac._irsend.capture.rawlen); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(LG2, ac._irsend.capture.decode_type); // Not "LG" + ASSERT_EQ(kLgBits, ac._irsend.capture.bits); + ASSERT_EQ( + "Model: 2 (AKB75215403), Power: On, Mode: 3 (Auto), Temp: 16C, " + "Fan: 5 (Auto)", + IRAcUtils::resultAcToString(&ac._irsend.capture)); + ac._irsend.reset(); + ac.stateReset(); + ac.send(); + // IRhvac {"Vendor":"LG2","Model":3,"Mode":"Auto","Power":"On","Celsius":"On", + // "Temp":15,"FanSpeed":"Max","SwingV":"Auto","SwingH":"Off", + // "Quiet":"Off","Turbo":"Off","Econo":"Off","Light":"On", + // "Filter":"Off","Clean":"Off","Beep":"Off","Sleep":-1} + ac._irsend.makeDecodeResult(); + ac._irsend.reset(); + irac.lg(&ac, + lg_ac_remote_model_t::AKB74955603, // Model + true, // Power + stdAc::opmode_t::kAuto, // Mode + 15, // Degrees C (Note: 16C is min) + stdAc::fanspeed_t::kMax, // Fan speed + stdAc::swingv_t::kAuto, // Vertical swing + stdAc::swingv_t::kOff, // Vertical swing (previous) + stdAc::swingh_t::kOff, // Horizontal swing + true); // Light + ac._irsend.makeDecodeResult(); + // There should only be two messages. + EXPECT_EQ(121, ac._irsend.capture.rawlen); + // First message should be normal. + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(LG2, ac._irsend.capture.decode_type); // Not "LG" + ASSERT_EQ(kLgBits, ac._irsend.capture.bits); + ASSERT_EQ( + "Model: 2 (AKB75215403), Power: On, Mode: 3 (Auto), Temp: 16C, " + "Fan: 4 (Maximum)", + IRAcUtils::resultAcToString(&ac._irsend.capture)); + // The next should be a SwingV Off. + EXPECT_TRUE(capture.decodeLG(&ac._irsend.capture, 61)); + ASSERT_EQ(LG2, ac._irsend.capture.decode_type); // Not "LG" + ASSERT_EQ(kLgBits, ac._irsend.capture.bits); + EXPECT_EQ(kLgAcSwingVSwing, ac._irsend.capture.value); + ASSERT_EQ("Model: 3 (AKB74955603), Swing(V): 20 (Swing)", + IRAcUtils::resultAcToString(&ac._irsend.capture)); +} + TEST(TestIRac, LG2_AKB73757604) { IRLgAc ac(kGpioUnused); IRac irac(kGpioUnused); @@ -1252,6 +1354,62 @@ TEST(TestIRac, Midea) { ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); } +TEST(TestIRac, Mirage) { + IRMirageAc ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); + stdAc::state_t state, r, p; + const char expected_KKG9AC1[] = + "Model: 1 (KKG9AC1), Power: On, Mode: 3 (Dry), Temp: 27C, " + "Fan: 2 (Medium), Turbo: Off, Sleep: On, Light: Off, " + "Swing(V): 9 (High), Clock: 17:31"; + + ac.begin(); + + state.model = mirage_ac_remote_model_t::KKG9AC1; + state.power = true; + state.mode = stdAc::opmode_t::kDry; + state.celsius = true; + state.degrees = 27; + state.fanspeed = stdAc::fanspeed_t::kMedium; + state.swingv = stdAc::swingv_t::kHigh; + state.swingh = stdAc::swingh_t::kLeft; + state.turbo = false; + state.quiet = true; + state.light = false; + state.filter = true; + state.clean = false; + state.sleep = 8 * 60 + 0; + state.clock = 17 * 60 + 31; + state.beep = false; + irac.mirage(&ac, state); + + ASSERT_EQ(expected_KKG9AC1, ac.toString()); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(MIRAGE, ac._irsend.capture.decode_type); + ASSERT_EQ(kMirageBits, ac._irsend.capture.bits); + ASSERT_EQ(expected_KKG9AC1, IRAcUtils::resultAcToString(&ac._irsend.capture)); + ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + + const char expected_KKG29AC1[] = + "Model: 2 (KKG29AC1), Power: On, Mode: 3 (Dry), Temp: 27C, " + "Fan: 3 (Medium), Turbo: Off, Sleep: On, Quiet: On, Light: -, " + "Swing(V): On, Swing(H): On, Filter: On, Clean: -, " + "On Timer: Off, Off Timer: Off, IFeel: Off"; + ac._irsend.reset(); + state.model = mirage_ac_remote_model_t::KKG29AC1; + irac.mirage(&ac, state); + ASSERT_EQ(expected_KKG29AC1, ac.toString()); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(MIRAGE, ac._irsend.capture.decode_type); + ASSERT_EQ(kMirageBits, ac._irsend.capture.bits); + ASSERT_EQ(expected_KKG29AC1, + IRAcUtils::resultAcToString(&ac._irsend.capture)); + ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); +} + TEST(TestIRac, Mitsubishi) { IRMitsubishiAC ac(kGpioUnused); IRac irac(kGpioUnused); @@ -1493,9 +1651,10 @@ TEST(TestIRac, Samsung) { IRSamsungAc ac(kGpioUnused); IRac irac(kGpioUnused); IRrecv capture(kGpioUnused); - char expected[] = - "Power: On, Mode: 0 (Auto), Temp: 28C, Fan: 6 (Auto), Swing: On, " - "Beep: On, Clean: On, Quiet: On, Powerful: Off, Breeze: Off, " + const char expected[] = + "Power: On, Mode: 0 (Auto), Temp: 28C, Fan: 6 (Auto), " + "Swing(V): On, Swing(H): On, Beep: Toggle, " + "Clean: Toggle, Quiet: On, Powerful: Off, ""Econo: Off, Breeze: Off, " "Light: On, Ion: Off"; ac.begin(); @@ -1505,14 +1664,18 @@ TEST(TestIRac, Samsung) { 28, // Celsius stdAc::fanspeed_t::kMedium, // Fan speed stdAc::swingv_t::kAuto, // Vertical swing + stdAc::swingh_t::kAuto, // Horizontal swing true, // Quiet false, // Turbo + false, // Econo true, // Light (Display) false, // Filter (Ion) - true, // Clean + true, // Clean (Toggle) true, // Beep + -1, // Sleep true, // Previous power state - false); // with dopower Off + -1, // Previous Sleep + false); // Force Extended ASSERT_EQ(expected, ac.toString()); ac._irsend.makeDecodeResult(); EXPECT_TRUE(capture.decode(&ac._irsend.capture)); @@ -1529,22 +1692,59 @@ TEST(TestIRac, Samsung) { 28, // Celsius stdAc::fanspeed_t::kMedium, // Fan speed stdAc::swingv_t::kAuto, // Vertical swing + stdAc::swingh_t::kAuto, // Horizontal swing true, // Quiet false, // Turbo + false, // Econo true, // Light (Display) false, // Filter (Ion) - true, // Clean + true, // Clean (Toggle) true, // Beep + -1, // Sleep true, // Previous power state - true); // with dopower On + -1, // Previous Sleep + true); // Force Extended ASSERT_EQ(expected, ac.toString()); // Class should be in the desired mode. ac._irsend.makeDecodeResult(); EXPECT_TRUE(capture.decode(&ac._irsend.capture)); ASSERT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type); - // We expect an extended state because of `dopower`. + // We expect an extended state because of `Force Extended`. ASSERT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + + ac._irsend.reset(); + const char sleep[] = + "Power: On, Mode: 0 (Auto), Temp: 28C, Fan: 6 (Auto), " + "Swing(V): On, Swing(H): Off, Beep: -, Clean: Toggle, " + "Quiet: On, Powerful: Off, Econo: Off, Breeze: Off, " + "Light: On, Ion: Off, Sleep Timer: 08:00"; + irac.samsung(&ac, + true, // Power + stdAc::opmode_t::kAuto, // Mode + 28, // Celsius + stdAc::fanspeed_t::kMedium, // Fan speed + stdAc::swingv_t::kAuto, // Vertical swing + stdAc::swingh_t::kOff, // Horizontal swing + true, // Quiet + false, // Turbo + false, // Econo + true, // Light (Display) + false, // Filter (Ion) + true, // Clean (Toggle) + false, // Beep + 8 * 60, // Sleep + true, // Previous power state + -1, // Previous Sleep + false); // Force Extended + ASSERT_EQ(sleep, ac.toString()); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type); + // We expect an extended state because of the change in `sleep`. + ASSERT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits); + ASSERT_EQ(sleep, IRAcUtils::resultAcToString(&ac._irsend.capture)); + ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); } TEST(TestIRac, Sanyo) { @@ -1610,7 +1810,7 @@ TEST(TestIRac, Sharp) { IRrecv capture(kGpioUnused); char expected[] = "Model: 1 (A907), Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 3 (Medium), " - "Turbo: Off, Swing(V) Toggle: On, Ion: On, Econo: -, Clean: Off"; + "Swing(V): 7 (Swing), Turbo: Off, Ion: On, Econo: -, Clean: Off"; ac.begin(); irac.sharp(&ac, @@ -1621,6 +1821,7 @@ TEST(TestIRac, Sharp) { 28, // Celsius stdAc::fanspeed_t::kMedium, // Fan speed stdAc::swingv_t::kAuto, // Vertical swing + stdAc::swingv_t::kOff, // Previous Vertical swing false, // Turbo false, // Light true, // Filter (Ion) @@ -1640,23 +1841,25 @@ TEST(TestIRac, Tcl112) { IRac irac(kGpioUnused); IRrecv capture(kGpioUnused); char expected[] = - "Type: 1, Power: On, Mode: 3 (Cool), Temp: 20C, Fan: 3 (Medium), " - "Econo: On, Health: On, Turbo: Off, Swing(H): On, Swing(V): Off, " - "Light: On"; + "Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 20C, " + "Fan: 3 (Medium), Swing(V): 0 (Auto), Swing(H): On, " + "Econo: On, Health: On, Turbo: Off, Light: On, " + "On Timer: Off, Off Timer: Off"; ac.begin(); irac.tcl112(&ac, - true, // Power - stdAc::opmode_t::kCool, // Mode - 20, // Celsius - stdAc::fanspeed_t::kMedium, // Fan speed - stdAc::swingv_t::kOff, // Vertical swing - stdAc::swingh_t::kAuto, // Horizontal swing - false, // Quiet (aka. Mute) - false, // Turbo - true, // Light - true, // Econo - true); // Filter (aka. Health) + tcl_ac_remote_model_t::TAC09CHSD, // Model + true, // Power + stdAc::opmode_t::kCool, // Mode + 20, // Celsius + stdAc::fanspeed_t::kMedium, // Fan speed + stdAc::swingv_t::kOff, // Vertical swing + stdAc::swingh_t::kAuto, // Horizontal swing + false, // Quiet (aka. Mute) + false, // Turbo + true, // Light + true, // Econo + true); // Filter (aka. Health) ASSERT_EQ(expected, ac.toString()); ac._irsend.makeDecodeResult(); EXPECT_TRUE(capture.decode(&ac._irsend.capture)); @@ -1668,23 +1871,24 @@ TEST(TestIRac, Tcl112) { // Test the quiet mode, which should generate two messages. ac._irsend.reset(); irac.tcl112(&ac, - true, // Power - stdAc::opmode_t::kCool, // Mode - 20, // Celsius - stdAc::fanspeed_t::kMedium, // Fan speed - stdAc::swingv_t::kOff, // Vertical swing - stdAc::swingh_t::kAuto, // Horizontal swing - true, // Quiet (aka. Mute) - false, // Turbo - true, // Light - true, // Econo - true); // Filter (aka. Health) + tcl_ac_remote_model_t::TAC09CHSD, // Model + true, // Power + stdAc::opmode_t::kCool, // Mode + 20, // Celsius + stdAc::fanspeed_t::kMedium, // Fan speed + stdAc::swingv_t::kOff, // Vertical swing + stdAc::swingh_t::kAuto, // Horizontal swing + true, // Quiet (aka. Mute) + false, // Turbo + true, // Light + true, // Econo + true); // Filter (aka. Health) ac._irsend.makeDecodeResult(); EXPECT_TRUE(capture.decode(&ac._irsend.capture)); ASSERT_EQ(TCL112AC, ac._irsend.capture.decode_type); ASSERT_EQ(kTcl112AcBits, ac._irsend.capture.bits); ASSERT_EQ( - "Type: 2, Quiet: On", + "Model: 1 (TAC09CHSD), Type: 2, Quiet: On", IRAcUtils::resultAcToString(&ac._irsend.capture)); // TCL112 uses the Mitsubishi112 decoder. // Skip first message. @@ -2335,6 +2539,10 @@ TEST(TestIRac, opmodeToString) { EXPECT_EQ("Auto", IRac::opmodeToString(stdAc::opmode_t::kAuto)); EXPECT_EQ("Cool", IRac::opmodeToString(stdAc::opmode_t::kCool)); EXPECT_EQ("UNKNOWN", IRac::opmodeToString((stdAc::opmode_t)500)); + // Home Assistant/Google Home differences. + EXPECT_EQ("Fan", IRac::opmodeToString(stdAc::opmode_t::kFan, false)); + EXPECT_EQ("fan_only", IRac::opmodeToString(stdAc::opmode_t::kFan, true)); + EXPECT_EQ("Fan", IRac::opmodeToString(stdAc::opmode_t::kFan)); // Default } TEST(TestIRac, fanspeedToString) { diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/Makefile b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/Makefile index 132350803..7a193e813 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/Makefile +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/Makefile @@ -3,6 +3,9 @@ # make [all] - makes everything. # make TARGET - makes the given target. # make run - makes everything and runs all the tests. +# make run_tests - run all tests +# make run-% - run specific test file (exclude _test.cpp) +# replace % with given test file, eg run-IRsend # make clean - removes all files generated by make. # make install-googletest - install the googletest code suite @@ -45,6 +48,7 @@ clean : run : all failed=""; \ for unittest in $(TESTS); do \ + echo "RUNNING: $${unittest}"; \ ./$${unittest} || failed="$${failed} $${unittest}"; \ done; \ if [ -n "$${failed}" ]; then \ @@ -55,6 +59,10 @@ run : all run_tests : run +run-% : %_test + echo "RUNNING: $*"; \ + ./$*_test + install-googletest : rm -rf ../lib/googletest git clone -b v1.8.x https://github.com/google/googletest.git ../lib/googletest diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Airton_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Airton_test.cpp new file mode 100644 index 000000000..e4e66ee13 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Airton_test.cpp @@ -0,0 +1,62 @@ +// Copyright 2021 crankyoldgit + +#include "IRac.h" +#include "IRrecv.h" +#include "IRrecv_test.h" +#include "IRsend.h" +#include "IRsend_test.h" +#include "gtest/gtest.h" + +// Tests for decodeAirton(). + +TEST(TestDecodeAirton, RealExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + const uint16_t rawData[115] = { + 6632, 3352, + 404, 1266, 404, 1264, 406, 430, 406, 430, 400, 1264, 406, 430, 402, 1264, + 408, 1262, 406, 1264, 404, 430, 402, 434, 402, 432, 402, 1264, 406, 430, + 404, 432, 400, 456, 376, 432, 402, 430, 402, 1264, 404, 1264, 404, 432, + 402, 434, 398, 434, 402, 430, 404, 1264, 404, 432, 402, 430, 404, 1264, + 406, 430, 402, 432, 400, 434, 402, 430, 402, 430, 404, 432, 402, 430, + 402, 432, 402, 432, 402, 430, 402, 432, 402, 430, 402, 434, 400, 432, + 402, 1264, 404, 430, 404, 1264, 404, 432, 402, 454, 378, 432, 402, 430, + 404, 1264, 404, 1264, 404, 1264, 378, 1292, 404, 432, 402, 1264, 404, 432, + 402}; + irsend.begin(); + irsend.reset(); + irsend.sendRaw(rawData, 115, 38); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(decode_type_t::AIRTON, irsend.capture.decode_type); + ASSERT_EQ(kAirtonBits, irsend.capture.bits); + EXPECT_EQ(0x5E1400090C11D3, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x0, irsend.capture.command); +} + +TEST(TestDecodeAirton, SyntheticExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + irsend.reset(); + irsend.sendAirton(0x5E1400090C11D3); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(decode_type_t::AIRTON, irsend.capture.decode_type); + ASSERT_EQ(kAirtonBits, irsend.capture.bits); + EXPECT_EQ(0x5E1400090C11D3, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x0, irsend.capture.command); +} + +TEST(TestUtils, Housekeeping) { + ASSERT_EQ("AIRTON", typeToString(decode_type_t::AIRTON)); + ASSERT_EQ(decode_type_t::AIRTON, strToDecodeType("AIRTON")); + ASSERT_FALSE(hasACState(decode_type_t::AIRTON)); + ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::AIRTON)); + ASSERT_EQ(kAirtonBits, IRsend::defaultBits(decode_type_t::AIRTON)); + ASSERT_EQ(kAirtonDefaultRepeat, IRsend::minRepeats(decode_type_t::AIRTON)); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Arris_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Arris_test.cpp new file mode 100644 index 000000000..2a219b6b2 --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Arris_test.cpp @@ -0,0 +1,189 @@ +// Copyright 2021 David Conran + +#include "IRac.h" +#include "IRrecv.h" +#include "IRrecv_test.h" +#include "IRsend.h" +#include "IRsend_test.h" +#include "gtest/gtest.h" + +// Tests for decodeArris(). + +// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1595 +// Data from: +// https://github.com/crankyoldgit/IRremoteESP8266/files/7100289/raw_data.txt +TEST(TestDecodeArris, RealExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + + const uint16_t rawData_1[59] = { + 2584, 1896, 666, 306, 338, 300, 336, 304, 668, 610, 332, 306, 338, 300, + 334, 304, 332, 312, 332, 306, 340, 300, 334, 304, 330, 308, 338, 302, 334, + 304, 330, 308, 336, 308, 336, 302, 332, 306, 330, 310, 674, 606, 336, 302, + 332, 306, 338, 306, 668, 612, 668, 306, 338, 304, 332, 308, 336, 608, + 334}; // UNKNOWN EDF1C0D0 + + irsend.begin(); + irsend.reset(); + irsend.sendRaw(rawData_1, 59, 38); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(decode_type_t::ARRIS, irsend.capture.decode_type); + EXPECT_EQ(kArrisBits, irsend.capture.bits); + EXPECT_EQ(0x1000085E, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x85, irsend.capture.command); + + irsend.reset(); + const uint16_t rawData_2[115] = { + 2584, 1898, 664, 308, 338, 302, 332, 306, 668, 614, 330, 308, 336, 302, + 332, 306, 340, 304, 330, 310, 336, 304, 332, 306, 338, 300, 334, 304, 330, + 308, 336, 302, 332, 312, 334, 306, 330, 308, 336, 302, 670, 610, 332, 306, + 330, 310, 336, 308, 674, 606, 664, 312, 334, 306, 338, 302, 334, 612, 330, + 5930, + 2584, 1898, 664, 308, 336, 302, 332, 306, 666, 614, 338, 300, 336, 304, + 332, 310, 674, 610, 332, 334, 312, 328, 308, 332, 304, 336, 310, 330, 306, + 332, 302, 314, 330, 336, 308, 330, 306, 334, 640, 612, 330, 308, 336, 302, + 332, 312, 672, 608, 672, 608, 672, 304, 330, 614, 330 + }; // UNKNOWN E6A77D83 + irsend.sendRaw(rawData_2, 115, 38); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(decode_type_t::ARRIS, irsend.capture.decode_type); + EXPECT_EQ(kArrisBits, irsend.capture.bits); + EXPECT_EQ(0x1000085E, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x85, irsend.capture.command); + + const uint16_t rawData_3[51] = { + 2584, 1896, 666, 308, 338, 328, 306, 332, 640, 612, 332, 336, 310, 300, + 334, 304, 678, 606, 336, 330, 306, 334, 310, 300, 334, 304, 332, 308, 338, + 302, 334, 310, 672, 304, 332, 614, 668, 612, 330, 336, 638, 620, 670, 610, + 670, 304, 330, 310, 336, 610, 672}; // UNKNOWN 4CA048A1 + irsend.reset(); + irsend.sendRaw(rawData_3, 51, 38); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(decode_type_t::ARRIS, irsend.capture.decode_type); + EXPECT_EQ(kArrisBits, irsend.capture.bits); + EXPECT_EQ(0x1080695D, irsend.capture.value); + EXPECT_EQ(0x1, irsend.capture.address); + EXPECT_EQ(0x695, irsend.capture.command); +} + +TEST(TestDecodeArris, SyntheticExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + irsend.reset(); + irsend.sendArris(0x1000085E); + irsend.makeDecodeResult(); + + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(decode_type_t::ARRIS, irsend.capture.decode_type); + EXPECT_EQ(kArrisBits, irsend.capture.bits); + EXPECT_EQ(0x1000085E, irsend.capture.value); + EXPECT_EQ(0x0, irsend.capture.address); + EXPECT_EQ(0x85, irsend.capture.command); + + EXPECT_EQ( + "f38000d50" +// const uint16_t rawData_1[59] = { +// 2584, 1896, + "m2560s1920" +// 666, 306, + "m640s320" +// 338, 300, + "m320s320" +// 336, 304, + "m320s320" +// 668, 610, + "m640s640" +// 332, 306, + "m320s320" +// 338, 300, + "m320s320" +// 334, 304, + "m320s320" +// 332, 312, + "m320s320" +// 332, 306, + "m320s320" +// 340, 300, + "m320s320" +// 334, 304, + "m320s320" +// 330, 308, + "m320s320" +// 338, 302, + "m320s320" +// 334, 304, + "m320s320" +// 330, 308, + "m320s320" +// 336, 308, + "m320s320" +// 336, 302, + "m320s320" +// 332, 306, + "m320s320" +// 330, 310, + "m320s320" +// 674, 606, + "m640s640" +// 336, 302, + "m320s320" +// 332, 306, + "m320s320" +// 338, 306, + "m320s320" +// 668, 612, + "m640s640" +// 668, 306, + "m640s320" +// 338, 304, + "m320s320" +// 332, 308, + "m320s320" +// 336, 608, + "m320s640" +// 334}; // UNKNOWN EDF1C0D0 + "m320s77184", irsend.outputStr()); + + irsend.reset(); + irsend.sendArris(0x1080695D); + irsend.makeDecodeResult(); + + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(decode_type_t::ARRIS, irsend.capture.decode_type); + EXPECT_EQ(kArrisBits, irsend.capture.bits); + EXPECT_EQ(0x1080695D, irsend.capture.value); + EXPECT_EQ(0x1, irsend.capture.address); + EXPECT_EQ(0x695, irsend.capture.command); +} + +TEST(TestUtils, Housekeeping) { + ASSERT_EQ("ARRIS", typeToString(decode_type_t::ARRIS)); + ASSERT_EQ(decode_type_t::ARRIS, strToDecodeType("ARRIS")); + ASSERT_FALSE(hasACState(decode_type_t::ARRIS)); + ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::ARRIS)); + ASSERT_EQ(kArrisBits, IRsend::defaultBits(decode_type_t::ARRIS)); + ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::ARRIS)); +} + +TEST(TestSendArris, ReleaseToggle) { + EXPECT_EQ(0x10800F5D, IRsend::toggleArrisRelease(0x10000F55)); + EXPECT_EQ(0x10000F55, IRsend::toggleArrisRelease(0x10800F5D)); + EXPECT_EQ( + 0x10800F5D, + IRsend::toggleArrisRelease(IRsend::toggleArrisRelease(0x10800F5D))); +} + +TEST(TestSendArris, encodeArris) { + EXPECT_EQ(0x10800F5D, IRsend::encodeArris(0xF5, true)); + EXPECT_EQ(0x10000F55, IRsend::encodeArris(0xF5, false)); + EXPECT_EQ(0x1080695D, IRsend::encodeArris(0x695, true)); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Electra_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Electra_test.cpp index 1fddf537b..9c1dedd09 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Electra_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Electra_test.cpp @@ -101,7 +101,8 @@ TEST(TestDecodeElectraAC, RealExampleDecode) { EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), " - "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off", + "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, " + "IFeel: Off", IRAcUtils::resultAcToString(&irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); @@ -235,7 +236,8 @@ TEST(TestIRElectraAcClass, HumanReadable) { ac.setRaw(on_cool_32C_auto_voff); EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 32C, Fan: 5 (Auto), " - "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off", + "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, " + "IFeel: Off", ac.toString()); uint8_t on_cool_16C_auto_voff[13] = { 0xC3, 0x47, 0xE0, 0x00, 0xA0, 0x00, 0x20, @@ -243,7 +245,8 @@ TEST(TestIRElectraAcClass, HumanReadable) { ac.setRaw(on_cool_16C_auto_voff); EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 5 (Auto), " - "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off", + "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, " + "IFeel: Off", ac.toString()); uint8_t on_cool_16C_low_voff[13] = { 0xC3, 0x47, 0xE0, 0x00, 0x60, 0x00, 0x20, @@ -251,7 +254,8 @@ TEST(TestIRElectraAcClass, HumanReadable) { ac.setRaw(on_cool_16C_low_voff); EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 3 (Low), " - "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off", + "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, " + "IFeel: Off", ac.toString()); } @@ -275,7 +279,8 @@ TEST(TestIRElectraAcClass, Clean) { ac.setRaw(on); EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), " - "Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off", + "Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off, " + "IFeel: Off", ac.toString()); } @@ -301,7 +306,8 @@ TEST(TestIRElectraAcClass, Turbo) { ac.setRaw(on); EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), " - "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: On", + "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: On, " + "IFeel: Off", ac.toString()); } @@ -325,7 +331,8 @@ TEST(TestIRElectraAcClass, LightToggle) { ac.setRaw(on); EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), " - "Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off", + "Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off, " + "IFeel: Off", ac.toString()); } @@ -352,8 +359,76 @@ TEST(TestIRElectraAcClass, ConstructKnownState) { EXPECT_EQ( "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), " - "Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off", + "Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off, " + "IFeel: Off", ac.toString()); EXPECT_STATE_EQ(on_cool_24C_fan1_swing_off_turbo_off_clean_on, ac.getRaw(), kElectraAcBits); } + +TEST(TestIRElectraAcClass, IFeelAndSensor) { + IRElectraAc ac(kGpioUnused); + ac.stateReset(); + // Test a real example. + const uint8_t ifeel_on[kElectraAcStateLength] = { + 0xC3, 0x6F, 0xE0, 0x00, 0xA0, 0x00, 0x28, + 0x64, 0x00, 0x20, 0x00, 0x1E, 0x7C}; + ac.setRaw(ifeel_on); + EXPECT_TRUE(ac.getIFeel()); + EXPECT_EQ(26, ac.getSensorTemp()); + EXPECT_EQ( + "Power: On, Mode: 1 (Cool), Temp: 21C, Fan: 5 (Auto), " + "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, " + "IFeel: On, Sensor Temp: 26C", + ac.toString()); + + ac.stateReset(); + EXPECT_FALSE(ac.getIFeel()); + EXPECT_EQ(kElectraAcSensorMinTemp, ac.getSensorTemp()); + + ac.setIFeel(true); + EXPECT_TRUE(ac.getIFeel()); + EXPECT_EQ(kElectraAcSensorMinTemp, ac.getSensorTemp()); + + ac.setSensorTemp(kElectraAcSensorMaxTemp); + EXPECT_EQ(kElectraAcSensorMaxTemp, ac.getSensorTemp()); + + ac.setSensorTemp(kElectraAcSensorMaxTemp + 1); + EXPECT_EQ(kElectraAcSensorMaxTemp, ac.getSensorTemp()); + + ac.setIFeel(false); + EXPECT_FALSE(ac.getIFeel()); + EXPECT_EQ(kElectraAcSensorMinTemp, ac.getSensorTemp()); + EXPECT_EQ(0, ac._.SensorTemp); + + ac.setIFeel(true); + ac.setSensorTemp(kElectraAcSensorMinTemp); + EXPECT_TRUE(ac.getIFeel()); + EXPECT_EQ(kElectraAcSensorMinTemp, ac.getSensorTemp()); + + ac.setSensorTemp(26); // Celsius + EXPECT_TRUE(ac.getIFeel()); + EXPECT_EQ(26, ac.getSensorTemp()); + + EXPECT_FALSE(ac.getSensorUpdate()); + ac.setSensorUpdate(true); + EXPECT_TRUE(ac.getSensorUpdate()); + EXPECT_EQ("Sensor Temp: 26C", ac.toString()); + ac.setSensorUpdate(false); + EXPECT_FALSE(ac.getSensorUpdate()); + + const uint8_t sensor_update_28C[kElectraAcStateLength] = { + 0xC3, 0x9F, 0xE0, 0x40, 0xA0, 0x00, 0x88, + 0x66, 0x00, 0x30, 0x00, 0x1E, 0x5E}; + ac.setRaw(sensor_update_28C); + EXPECT_TRUE(ac.getSensorUpdate()); + EXPECT_EQ(28, ac.getSensorTemp()); + EXPECT_EQ("Sensor Temp: 28C", ac.toString()); + ac.setSensorUpdate(false); + EXPECT_FALSE(ac.getSensorUpdate()); + EXPECT_EQ( + "Power: On, Mode: 4 (Heat), Temp: 27C, Fan: 5 (Auto), " + "Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, " + "IFeel: On, Sensor Temp: 28C", + ac.toString()); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Gree_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Gree_test.cpp index 597fd3c09..cb1832f61 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Gree_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Gree_test.cpp @@ -303,9 +303,10 @@ TEST(TestGreeClass, Temperature) { EXPECT_EQ(63, ac.getTemp()); EXPECT_EQ( "Model: 2 (YBOFB), Power: On, Mode: 1 (Cool), Temp: 63F, Fan: 0 (Auto), " - "Turbo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, Sleep: Off, " - "Swing(V) Mode: Manual, Swing(V): 0 (Last), Timer: Off, " - "Display Temp: 0 (Off)", ac.toString()); + "Turbo: Off, Econo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, " + "Sleep: Off, " + "Swing(V) Mode: Manual, Swing(V): 0 (Last), Swing(H): 0 (Off), " + "Timer: Off, Display Temp: 0 (Off)", ac.toString()); } TEST(TestGreeClass, OperatingMode) { @@ -385,6 +386,20 @@ TEST(TestGreeClass, Turbo) { EXPECT_TRUE(ac.getTurbo()); } +TEST(TestGreeClass, Econo) { + IRGreeAC ac(kGpioUnused); + ac.begin(); + + ac.setEcono(true); + EXPECT_TRUE(ac.getEcono()); + + ac.setEcono(false); + EXPECT_FALSE(ac.getEcono()); + + ac.setEcono(true); + EXPECT_TRUE(ac.getEcono()); +} + TEST(TestGreeClass, IFeel) { IRGreeAC ac(kGpioUnused); ac.begin(); @@ -506,6 +521,24 @@ TEST(TestGreeClass, VerticalSwing) { EXPECT_EQ(kGreeSwingAuto, ac.getSwingVerticalPosition()); } +TEST(TestGreeClass, HorizontalSwing) { + IRGreeAC ac(kGpioUnused); + ac.begin(); + + ac.setSwingHorizontal(kGreeSwingHAuto); + EXPECT_EQ(kGreeSwingHAuto, ac.getSwingHorizontal()); + + ac.setSwingHorizontal(kGreeSwingHMiddle); + EXPECT_EQ(kGreeSwingHMiddle, ac.getSwingHorizontal()); + + ac.setSwingHorizontal(kGreeSwingHMaxRight); + EXPECT_EQ(kGreeSwingHMaxRight, ac.getSwingHorizontal()); + + // Out of bounds. + ac.setSwingHorizontal(kGreeSwingHMaxRight + 1); + EXPECT_EQ(kGreeSwingHOff, ac.getSwingHorizontal()); +} + TEST(TestGreeClass, SetAndGetRaw) { IRGreeAC ac(kGpioUnused); uint8_t initialState[kGreeStateLength] = {0x00, 0x09, 0x20, 0x50, @@ -543,8 +576,9 @@ TEST(TestGreeClass, HumanReadable) { EXPECT_EQ( "Model: 1 (YAW1F), Power: Off, Mode: 0 (Auto), Temp: 25C, Fan: 0 (Auto), " - "Turbo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, Sleep: Off, " - "Swing(V) Mode: Manual, Swing(V): 0 (Last), " + "Turbo: Off, Econo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, " + "Sleep: Off, " + "Swing(V) Mode: Manual, Swing(V): 0 (Last), Swing(H): 0 (Off), " "Timer: Off, Display Temp: 0 (Off)", ac.toString()); ac.on(); @@ -562,9 +596,10 @@ TEST(TestGreeClass, HumanReadable) { ac.setDisplayTempSource(3); EXPECT_EQ( "Model: 1 (YAW1F), Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 3 (High), " - "Turbo: On, IFeel: On, WiFi: On, XFan: On, Light: Off, Sleep: On, " - "Swing(V) Mode: Auto, Swing(V): 1 (Auto), Timer: 12:30, " - "Display Temp: 3 (Outside)", + "Turbo: On, Econo: Off, IFeel: On, WiFi: On, XFan: On, Light: Off, " + "Sleep: On, " + "Swing(V) Mode: Auto, Swing(V): 1 (Auto), Swing(H): 0 (Off), " + "Timer: 12:30, Display Temp: 3 (Outside)", ac.toString()); } @@ -623,9 +658,10 @@ TEST(TestDecodeGree, NormalRealExample) { ac.setRaw(irsend.capture.state); EXPECT_EQ( "Model: 1 (YAW1F), Power: On, Mode: 1 (Cool), Temp: 26C, Fan: 1 (Low), " - "Turbo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, Sleep: Off, " - "Swing(V) Mode: Manual, Swing(V): 2 (UNKNOWN), Timer: Off, " - "Display Temp: 3 (Outside)", + "Turbo: Off, Econo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, " + "Sleep: Off, " + "Swing(V) Mode: Manual, Swing(V): 2 (UNKNOWN), Swing(H): 0 (Off), " + "Timer: Off, Display Temp: 3 (Outside)", IRAcUtils::resultAcToString(&irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); @@ -681,8 +717,9 @@ TEST(TestGreeClass, Issue814Power) { EXPECT_EQ(gree_ac_remote_model_t::YBOFB, ac.getModel()); EXPECT_EQ( "Model: 2 (YBOFB), Power: On, Mode: 1 (Cool), Temp: 23C, Fan: 1 (Low), " - "Turbo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, Sleep: Off, " - "Swing(V) Mode: Auto, Swing(V): 1 (Auto), Timer: Off, " + "Turbo: Off, Econo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, " + "Sleep: Off, " + "Swing(V) Mode: Auto, Swing(V): 1 (Auto), Swing(H): 0 (Off), Timer: Off, " "Display Temp: 0 (Off)", ac.toString()); ac.off(); diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Haier_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Haier_test.cpp index 8b89b1098..b60a08f23 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Haier_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Haier_test.cpp @@ -105,597 +105,711 @@ TEST(TestSendHaierAC, SendWithRepeats) { // Tests for IRHaierAC class. TEST(TestHaierACClass, Command) { - IRHaierAC haier(kGpioUnused); - haier.begin(); + IRHaierAC ac(kGpioUnused); + ac.begin(); - haier.setCommand(kHaierAcCmdOff); - EXPECT_EQ(kHaierAcCmdOff, haier.getCommand()); - haier.setCommand(kHaierAcCmdOn); - EXPECT_EQ(kHaierAcCmdOn, haier.getCommand()); - haier.setCommand(kHaierAcCmdMode); - EXPECT_EQ(kHaierAcCmdMode, haier.getCommand()); - haier.setCommand(kHaierAcCmdFan); - EXPECT_EQ(kHaierAcCmdFan, haier.getCommand()); - haier.setCommand(kHaierAcCmdTempUp); - EXPECT_EQ(kHaierAcCmdTempUp, haier.getCommand()); - haier.setCommand(kHaierAcCmdTempDown); - EXPECT_EQ(kHaierAcCmdTempDown, haier.getCommand()); - haier.setCommand(kHaierAcCmdSleep); - EXPECT_EQ(kHaierAcCmdSleep, haier.getCommand()); - haier.setCommand(kHaierAcCmdTimerSet); - EXPECT_EQ(kHaierAcCmdTimerSet, haier.getCommand()); - haier.setCommand(kHaierAcCmdTimerCancel); - EXPECT_EQ(kHaierAcCmdTimerCancel, haier.getCommand()); - haier.setCommand(kHaierAcCmdHealth); - EXPECT_EQ(kHaierAcCmdHealth, haier.getCommand()); - haier.setCommand(kHaierAcCmdSwing); - EXPECT_EQ(kHaierAcCmdSwing, haier.getCommand()); - haier.setCommand(kHaierAcCmdOn); - EXPECT_EQ(kHaierAcCmdOn, haier.getCommand()); - haier.setCommand(kHaierAcCmdOff); - EXPECT_EQ(kHaierAcCmdOff, haier.getCommand()); + ac.setCommand(kHaierAcCmdOff); + EXPECT_EQ(kHaierAcCmdOff, ac.getCommand()); + ac.setCommand(kHaierAcCmdOn); + EXPECT_EQ(kHaierAcCmdOn, ac.getCommand()); + ac.setCommand(kHaierAcCmdMode); + EXPECT_EQ(kHaierAcCmdMode, ac.getCommand()); + ac.setCommand(kHaierAcCmdFan); + EXPECT_EQ(kHaierAcCmdFan, ac.getCommand()); + ac.setCommand(kHaierAcCmdTempUp); + EXPECT_EQ(kHaierAcCmdTempUp, ac.getCommand()); + ac.setCommand(kHaierAcCmdTempDown); + EXPECT_EQ(kHaierAcCmdTempDown, ac.getCommand()); + ac.setCommand(kHaierAcCmdSleep); + EXPECT_EQ(kHaierAcCmdSleep, ac.getCommand()); + ac.setCommand(kHaierAcCmdTimerSet); + EXPECT_EQ(kHaierAcCmdTimerSet, ac.getCommand()); + ac.setCommand(kHaierAcCmdTimerCancel); + EXPECT_EQ(kHaierAcCmdTimerCancel, ac.getCommand()); + ac.setCommand(kHaierAcCmdHealth); + EXPECT_EQ(kHaierAcCmdHealth, ac.getCommand()); + ac.setCommand(kHaierAcCmdSwing); + EXPECT_EQ(kHaierAcCmdSwing, ac.getCommand()); + ac.setCommand(kHaierAcCmdOn); + EXPECT_EQ(kHaierAcCmdOn, ac.getCommand()); + ac.setCommand(kHaierAcCmdOff); + EXPECT_EQ(kHaierAcCmdOff, ac.getCommand()); // Test unexpected values. - haier.setCommand(0b00001110); - EXPECT_EQ(kHaierAcCmdOff, haier.getCommand()); - haier.setCommand(0b00001111); - EXPECT_EQ(kHaierAcCmdOff, haier.getCommand()); - haier.setCommand(0b00000100); - EXPECT_EQ(kHaierAcCmdOff, haier.getCommand()); + ac.setCommand(0b00001110); + EXPECT_EQ(kHaierAcCmdOff, ac.getCommand()); + ac.setCommand(0b00001111); + EXPECT_EQ(kHaierAcCmdOff, ac.getCommand()); + ac.setCommand(0b00000100); + EXPECT_EQ(kHaierAcCmdOff, ac.getCommand()); } TEST(TestHaierACClass, OperatingMode) { - IRHaierAC haier(kGpioUnused); - haier.begin(); + IRHaierAC ac(kGpioUnused); + ac.begin(); - haier.setMode(kHaierAcAuto); - EXPECT_EQ(kHaierAcAuto, haier.getMode()); + ac.setMode(kHaierAcAuto); + EXPECT_EQ(kHaierAcAuto, ac.getMode()); - haier.setMode(kHaierAcCool); - EXPECT_EQ(kHaierAcCool, haier.getMode()); + ac.setMode(kHaierAcCool); + EXPECT_EQ(kHaierAcCool, ac.getMode()); - haier.setMode(kHaierAcHeat); - EXPECT_EQ(kHaierAcHeat, haier.getMode()); + ac.setMode(kHaierAcHeat); + EXPECT_EQ(kHaierAcHeat, ac.getMode()); - haier.setMode(kHaierAcFan); - EXPECT_EQ(kHaierAcFan, haier.getMode()); + ac.setMode(kHaierAcFan); + EXPECT_EQ(kHaierAcFan, ac.getMode()); - haier.setMode(kHaierAcDry); - EXPECT_EQ(kHaierAcDry, haier.getMode()); + ac.setMode(kHaierAcDry); + EXPECT_EQ(kHaierAcDry, ac.getMode()); - haier.setMode(kHaierAcAuto - 1); - EXPECT_EQ(kHaierAcAuto, haier.getMode()); + ac.setMode(kHaierAcAuto - 1); + EXPECT_EQ(kHaierAcAuto, ac.getMode()); - haier.setMode(kHaierAcCool); - EXPECT_EQ(kHaierAcCool, haier.getMode()); + ac.setMode(kHaierAcCool); + EXPECT_EQ(kHaierAcCool, ac.getMode()); - haier.setMode(kHaierAcFan + 1); - EXPECT_EQ(kHaierAcAuto, haier.getMode()); + ac.setMode(kHaierAcFan + 1); + EXPECT_EQ(kHaierAcAuto, ac.getMode()); - haier.setMode(255); - EXPECT_EQ(kHaierAcAuto, haier.getMode()); + ac.setMode(255); + EXPECT_EQ(kHaierAcAuto, ac.getMode()); } TEST(TestHaierACClass, Temperature) { - IRHaierAC haier(kGpioUnused); - haier.begin(); + IRHaierAC ac(kGpioUnused); + ac.begin(); - haier.setTemp(kHaierAcMinTemp); - EXPECT_EQ(kHaierAcMinTemp, haier.getTemp()); + ac.setTemp(kHaierAcMinTemp); + EXPECT_EQ(kHaierAcMinTemp, ac.getTemp()); - haier.setCommand(kHaierAcCmdOn); - haier.setTemp(kHaierAcMinTemp + 1); - EXPECT_EQ(kHaierAcMinTemp + 1, haier.getTemp()); - EXPECT_EQ(kHaierAcCmdTempUp, haier.getCommand()); + ac.setCommand(kHaierAcCmdOn); + ac.setTemp(kHaierAcMinTemp + 1); + EXPECT_EQ(kHaierAcMinTemp + 1, ac.getTemp()); + EXPECT_EQ(kHaierAcCmdTempUp, ac.getCommand()); - haier.setTemp(kHaierAcMaxTemp); - EXPECT_EQ(kHaierAcMaxTemp, haier.getTemp()); - EXPECT_EQ(kHaierAcCmdTempUp, haier.getCommand()); + ac.setTemp(kHaierAcMaxTemp); + EXPECT_EQ(kHaierAcMaxTemp, ac.getTemp()); + EXPECT_EQ(kHaierAcCmdTempUp, ac.getCommand()); - haier.setTemp(kHaierAcMinTemp - 1); - EXPECT_EQ(kHaierAcMinTemp, haier.getTemp()); - EXPECT_EQ(kHaierAcCmdTempDown, haier.getCommand()); + ac.setTemp(kHaierAcMinTemp - 1); + EXPECT_EQ(kHaierAcMinTemp, ac.getTemp()); + EXPECT_EQ(kHaierAcCmdTempDown, ac.getCommand()); - haier.setTemp(kHaierAcMaxTemp + 1); - EXPECT_EQ(kHaierAcMaxTemp, haier.getTemp()); - EXPECT_EQ(kHaierAcCmdTempUp, haier.getCommand()); + ac.setTemp(kHaierAcMaxTemp + 1); + EXPECT_EQ(kHaierAcMaxTemp, ac.getTemp()); + EXPECT_EQ(kHaierAcCmdTempUp, ac.getCommand()); - haier.setTemp(23); - EXPECT_EQ(23, haier.getTemp()); - EXPECT_EQ(kHaierAcCmdTempDown, haier.getCommand()); - haier.setCommand(kHaierAcCmdOn); - haier.setTemp(23); - EXPECT_EQ(23, haier.getTemp()); - EXPECT_EQ(kHaierAcCmdOn, haier.getCommand()); + ac.setTemp(23); + EXPECT_EQ(23, ac.getTemp()); + EXPECT_EQ(kHaierAcCmdTempDown, ac.getCommand()); + ac.setCommand(kHaierAcCmdOn); + ac.setTemp(23); + EXPECT_EQ(23, ac.getTemp()); + EXPECT_EQ(kHaierAcCmdOn, ac.getCommand()); - haier.setTemp(0); - EXPECT_EQ(kHaierAcMinTemp, haier.getTemp()); - EXPECT_EQ(kHaierAcCmdTempDown, haier.getCommand()); + ac.setTemp(0); + EXPECT_EQ(kHaierAcMinTemp, ac.getTemp()); + EXPECT_EQ(kHaierAcCmdTempDown, ac.getCommand()); - haier.setTemp(255); - EXPECT_EQ(kHaierAcMaxTemp, haier.getTemp()); - EXPECT_EQ(kHaierAcCmdTempUp, haier.getCommand()); + ac.setTemp(255); + EXPECT_EQ(kHaierAcMaxTemp, ac.getTemp()); + EXPECT_EQ(kHaierAcCmdTempUp, ac.getCommand()); } TEST(TestHaierACClass, FanSpeed) { - IRHaierAC haier(kGpioUnused); - haier.begin(); - haier.setFan(kHaierAcFanLow); - haier.setCommand(kHaierAcCmdOn); + IRHaierAC ac(kGpioUnused); + ac.begin(); + ac.setFan(kHaierAcFanLow); + ac.setCommand(kHaierAcCmdOn); - haier.setFan(kHaierAcFanAuto); - EXPECT_EQ(kHaierAcFanAuto, haier.getFan()); - EXPECT_EQ(kHaierAcCmdFan, haier.getCommand()); + ac.setFan(kHaierAcFanAuto); + EXPECT_EQ(kHaierAcFanAuto, ac.getFan()); + EXPECT_EQ(kHaierAcCmdFan, ac.getCommand()); - haier.setFan(kHaierAcFanLow); - EXPECT_EQ(kHaierAcFanLow, haier.getFan()); - haier.setFan(kHaierAcFanMed); - EXPECT_EQ(kHaierAcFanMed, haier.getFan()); - haier.setFan(kHaierAcFanHigh); - EXPECT_EQ(kHaierAcFanHigh, haier.getFan()); + ac.setFan(kHaierAcFanLow); + EXPECT_EQ(kHaierAcFanLow, ac.getFan()); + ac.setFan(kHaierAcFanMed); + EXPECT_EQ(kHaierAcFanMed, ac.getFan()); + ac.setFan(kHaierAcFanHigh); + EXPECT_EQ(kHaierAcFanHigh, ac.getFan()); - haier.setCommand(kHaierAcCmdOn); - haier.setFan(kHaierAcFanHigh); - EXPECT_EQ(kHaierAcFanHigh, haier.getFan()); - EXPECT_EQ(kHaierAcCmdOn, haier.getCommand()); + ac.setCommand(kHaierAcCmdOn); + ac.setFan(kHaierAcFanHigh); + EXPECT_EQ(kHaierAcFanHigh, ac.getFan()); + EXPECT_EQ(kHaierAcCmdOn, ac.getCommand()); } -TEST(TestHaierACClass, Swing) { - IRHaierAC haier(kGpioUnused); - haier.begin(); - haier.setFan(kHaierAcFanLow); - haier.setCommand(kHaierAcCmdOn); +TEST(TestHaierACClass, SwingV) { + IRHaierAC ac(kGpioUnused); + ac.begin(); + ac.setFan(kHaierAcFanLow); + ac.setCommand(kHaierAcCmdOn); - haier.setSwing(kHaierAcSwingOff); - EXPECT_EQ(kHaierAcSwingOff, haier.getSwing()); + ac.setSwingV(kHaierAcSwingVOff); + EXPECT_EQ(kHaierAcSwingVOff, ac.getSwingV()); - haier.setSwing(kHaierAcSwingUp); - EXPECT_EQ(kHaierAcSwingUp, haier.getSwing()); - EXPECT_EQ(kHaierAcCmdSwing, haier.getCommand()); + ac.setSwingV(kHaierAcSwingVUp); + EXPECT_EQ(kHaierAcSwingVUp, ac.getSwingV()); + EXPECT_EQ(kHaierAcCmdSwing, ac.getCommand()); - haier.setSwing(kHaierAcSwingDown); - EXPECT_EQ(kHaierAcSwingDown, haier.getSwing()); - EXPECT_EQ(kHaierAcCmdSwing, haier.getCommand()); + ac.setSwingV(kHaierAcSwingVDown); + EXPECT_EQ(kHaierAcSwingVDown, ac.getSwingV()); + EXPECT_EQ(kHaierAcCmdSwing, ac.getCommand()); - haier.setSwing(kHaierAcSwingChg); - EXPECT_EQ(kHaierAcSwingChg, haier.getSwing()); - EXPECT_EQ(kHaierAcCmdSwing, haier.getCommand()); + ac.setSwingV(kHaierAcSwingVChg); + EXPECT_EQ(kHaierAcSwingVChg, ac.getSwingV()); + EXPECT_EQ(kHaierAcCmdSwing, ac.getCommand()); } TEST(TestHaierACClass, CurrentTime) { - IRHaierAC haier(kGpioUnused); - haier.begin(); - EXPECT_EQ(0, haier.getCurrTime()); + IRHaierAC ac(kGpioUnused); + ac.begin(); + EXPECT_EQ(0, ac.getCurrTime()); - haier.setCurrTime(1); - EXPECT_EQ(1, haier.getCurrTime()); + ac.setCurrTime(1); + EXPECT_EQ(1, ac.getCurrTime()); - haier.setCurrTime(60); - EXPECT_EQ(60, haier.getCurrTime()); + ac.setCurrTime(60); + EXPECT_EQ(60, ac.getCurrTime()); - haier.setCurrTime(61); - EXPECT_EQ(61, haier.getCurrTime()); + ac.setCurrTime(61); + EXPECT_EQ(61, ac.getCurrTime()); - haier.setCurrTime(18 * 60 + 34); // 18:34 - EXPECT_EQ(1114, haier.getCurrTime()); + ac.setCurrTime(18 * 60 + 34); // 18:34 + EXPECT_EQ(1114, ac.getCurrTime()); - haier.setCurrTime(23 * 60 + 59); // 23:59 - EXPECT_EQ(kHaierAcMaxTime, haier.getCurrTime()); // 23:59 + ac.setCurrTime(23 * 60 + 59); // 23:59 + EXPECT_EQ(kHaierAcMaxTime, ac.getCurrTime()); // 23:59 - haier.setCurrTime(23 * 60 + 59 + 1); // 24:00 - EXPECT_EQ(kHaierAcMaxTime, haier.getCurrTime()); // 23:59 + ac.setCurrTime(23 * 60 + 59 + 1); // 24:00 + EXPECT_EQ(kHaierAcMaxTime, ac.getCurrTime()); // 23:59 - haier.setCurrTime(UINT16_MAX); - EXPECT_EQ(kHaierAcMaxTime, haier.getCurrTime()); // 23:59 + ac.setCurrTime(UINT16_MAX); + EXPECT_EQ(kHaierAcMaxTime, ac.getCurrTime()); // 23:59 } TEST(TestHaierACClass, Timers) { - IRHaierAC haier(kGpioUnused); - haier.begin(); + IRHaierAC ac(kGpioUnused); + ac.begin(); - haier.setCommand(kHaierAcCmdOn); + ac.setCommand(kHaierAcCmdOn); // Off by default. - EXPECT_GT(0, haier.getOnTimer()); - EXPECT_GT(0, haier.getOffTimer()); - EXPECT_EQ(kHaierAcCmdOn, haier.getCommand()); + EXPECT_GT(0, ac.getOnTimer()); + EXPECT_GT(0, ac.getOffTimer()); + EXPECT_EQ(kHaierAcCmdOn, ac.getCommand()); // On Timer. - haier.setOnTimer(6 * 60); // 6am - EXPECT_EQ(6 * 60, haier.getOnTimer()); // 6am - EXPECT_GT(0, haier.getOffTimer()); - EXPECT_EQ(kHaierAcCmdTimerSet, haier.getCommand()); + ac.setOnTimer(6 * 60); // 6am + EXPECT_EQ(6 * 60, ac.getOnTimer()); // 6am + EXPECT_GT(0, ac.getOffTimer()); + EXPECT_EQ(kHaierAcCmdTimerSet, ac.getCommand()); - haier.setCommand(kHaierAcCmdOn); - EXPECT_EQ(6 * 60, haier.getOnTimer()); // 6am - EXPECT_GT(0, haier.getOffTimer()); - EXPECT_EQ(kHaierAcCmdOn, haier.getCommand()); + ac.setCommand(kHaierAcCmdOn); + EXPECT_EQ(6 * 60, ac.getOnTimer()); // 6am + EXPECT_GT(0, ac.getOffTimer()); + EXPECT_EQ(kHaierAcCmdOn, ac.getCommand()); - haier.cancelTimers(); - EXPECT_GT(0, haier.getOnTimer()); - EXPECT_GT(0, haier.getOffTimer()); - EXPECT_EQ(kHaierAcCmdTimerCancel, haier.getCommand()); + ac.cancelTimers(); + EXPECT_GT(0, ac.getOnTimer()); + EXPECT_GT(0, ac.getOffTimer()); + EXPECT_EQ(kHaierAcCmdTimerCancel, ac.getCommand()); // Off Timer. - haier.setOffTimer(18 * 60 + 30); // 6:30pm - EXPECT_GT(0, haier.getOnTimer()); - EXPECT_EQ(18 * 60 + 30, haier.getOffTimer()); // 6:30pm - EXPECT_EQ(kHaierAcCmdTimerSet, haier.getCommand()); + ac.setOffTimer(18 * 60 + 30); // 6:30pm + EXPECT_GT(0, ac.getOnTimer()); + EXPECT_EQ(18 * 60 + 30, ac.getOffTimer()); // 6:30pm + EXPECT_EQ(kHaierAcCmdTimerSet, ac.getCommand()); - haier.setCommand(kHaierAcCmdOn); - EXPECT_GT(0, haier.getOnTimer()); - EXPECT_EQ(18 * 60 + 30, haier.getOffTimer()); // 6:30pm - EXPECT_EQ(kHaierAcCmdOn, haier.getCommand()); + ac.setCommand(kHaierAcCmdOn); + EXPECT_GT(0, ac.getOnTimer()); + EXPECT_EQ(18 * 60 + 30, ac.getOffTimer()); // 6:30pm + EXPECT_EQ(kHaierAcCmdOn, ac.getCommand()); - haier.cancelTimers(); - EXPECT_GT(0, haier.getOnTimer()); - EXPECT_GT(0, haier.getOffTimer()); - EXPECT_EQ(kHaierAcCmdTimerCancel, haier.getCommand()); + ac.cancelTimers(); + EXPECT_GT(0, ac.getOnTimer()); + EXPECT_GT(0, ac.getOffTimer()); + EXPECT_EQ(kHaierAcCmdTimerCancel, ac.getCommand()); // Both Timers. - haier.setOnTimer(6 * 60); // 6am - EXPECT_EQ(kHaierAcCmdTimerSet, haier.getCommand()); - haier.setOffTimer(18 * 60 + 30); // 6:30pm - EXPECT_EQ(kHaierAcCmdTimerSet, haier.getCommand()); - EXPECT_EQ(6 * 60, haier.getOnTimer()); // 6am - EXPECT_EQ(18 * 60 + 30, haier.getOffTimer()); // 6:30pm + ac.setOnTimer(6 * 60); // 6am + EXPECT_EQ(kHaierAcCmdTimerSet, ac.getCommand()); + ac.setOffTimer(18 * 60 + 30); // 6:30pm + EXPECT_EQ(kHaierAcCmdTimerSet, ac.getCommand()); + EXPECT_EQ(6 * 60, ac.getOnTimer()); // 6am + EXPECT_EQ(18 * 60 + 30, ac.getOffTimer()); // 6:30pm - haier.cancelTimers(); - EXPECT_GT(0, haier.getOnTimer()); - EXPECT_GT(0, haier.getOffTimer()); - EXPECT_EQ(kHaierAcCmdTimerCancel, haier.getCommand()); + ac.cancelTimers(); + EXPECT_GT(0, ac.getOnTimer()); + EXPECT_GT(0, ac.getOffTimer()); + EXPECT_EQ(kHaierAcCmdTimerCancel, ac.getCommand()); } TEST(TestHaierACClass, MessageConstuction) { - IRHaierAC haier(kGpioUnused); + IRHaierAC ac(kGpioUnused); EXPECT_EQ( "Command: 1 (On), Mode: 0 (Auto), Temp: 25C, Fan: 1 (Low), " - "Swing: 0 (Off), Sleep: Off, Health: Off, " + "Swing(V): 0 (Off), Sleep: Off, Health: Off, " "Clock: 00:00, On Timer: Off, Off Timer: Off", - haier.toString()); - haier.setMode(kHaierAcCool); - haier.setTemp(21); - haier.setFan(kHaierAcFanHigh); + ac.toString()); + ac.setMode(kHaierAcCool); + ac.setTemp(21); + ac.setFan(kHaierAcFanHigh); EXPECT_EQ( "Command: 3 (Fan), Mode: 1 (Cool), Temp: 21C, Fan: 3 (High), " - "Swing: 0 (Off), Sleep: Off, Health: Off, " + "Swing(V): 0 (Off), Sleep: Off, Health: Off, " "Clock: 00:00, On Timer: Off, Off Timer: Off", - haier.toString()); - haier.setSwing(kHaierAcSwingChg); - haier.setHealth(true); - haier.setSleep(true); - haier.setCurrTime(615); // 10:15am + ac.toString()); + ac.setSwingV(kHaierAcSwingVChg); + ac.setHealth(true); + ac.setSleep(true); + ac.setCurrTime(615); // 10:15am EXPECT_EQ( "Command: 8 (Sleep), Mode: 1 (Cool), Temp: 21C, Fan: 3 (High), " - "Swing: 3 (Change), Sleep: On, Health: On, " + "Swing(V): 3 (Change), Sleep: On, Health: On, " "Clock: 10:15, On Timer: Off, Off Timer: Off", - haier.toString()); - haier.setOnTimer(800); // 1:20pm - haier.setOffTimer(1125); // 6:45pm - haier.setCommand(kHaierAcCmdOn); + ac.toString()); + ac.setOnTimer(800); // 1:20pm + ac.setOffTimer(1125); // 6:45pm + ac.setCommand(kHaierAcCmdOn); EXPECT_EQ( "Command: 1 (On), Mode: 1 (Cool), Temp: 21C, Fan: 3 (High), " - "Swing: 3 (Change), Sleep: On, Health: On, " + "Swing(V): 3 (Change), Sleep: On, Health: On, " "Clock: 10:15, On Timer: 13:20, Off Timer: 18:45", - haier.toString()); + ac.toString()); // Now change a few already set things. - haier.setMode(kHaierAcHeat); + ac.setMode(kHaierAcHeat); EXPECT_EQ( "Command: 2 (Mode), Mode: 3 (Heat), Temp: 21C, Fan: 3 (High), " - "Swing: 3 (Change), Sleep: On, Health: On, " + "Swing(V): 3 (Change), Sleep: On, Health: On, " "Clock: 10:15, On Timer: 13:20, Off Timer: 18:45", - haier.toString()); + ac.toString()); - haier.setTemp(25); + ac.setTemp(25); EXPECT_EQ( "Command: 6 (Temp Up), Mode: 3 (Heat), Temp: 25C, Fan: 3 (High), " - "Swing: 3 (Change), Sleep: On, Health: On, " + "Swing(V): 3 (Change), Sleep: On, Health: On, " "Clock: 10:15, On Timer: 13:20, Off Timer: 18:45", - haier.toString()); + ac.toString()); uint8_t expectedState[kHaierACStateLength] = {0xA5, 0x96, 0xEA, 0xCF, 0x32, 0x6D, 0x6D, 0x54, 0x54}; - EXPECT_STATE_EQ(expectedState, haier.getRaw(), kHaierACBits); + EXPECT_STATE_EQ(expectedState, ac.getRaw(), kHaierACBits); // Check that the checksum is valid. - EXPECT_TRUE(IRHaierAC::validChecksum(haier.getRaw())); + EXPECT_TRUE(IRHaierAC::validChecksum(ac.getRaw())); // Now load up some random data. uint8_t randomState[kHaierACStateLength] = {0x52, 0x49, 0x50, 0x20, 0x54, 0x61, 0x6C, 0x69, 0x61}; EXPECT_FALSE(IRHaierAC::validChecksum(randomState)); - haier.setRaw(randomState); + ac.setRaw(randomState); EXPECT_EQ( "Command: 9 (Timer Set), Mode: 3 (Heat), Temp: 20C, Fan: 3 (High), " - "Swing: 1 (Up), Sleep: On, Health: Off, " + "Swing(V): 1 (Up), Sleep: On, Health: Off, " "Clock: 16:32, On Timer: Off, Off Timer: Off", - haier.toString()); + ac.toString()); // getRaw() should correct the checksum. - EXPECT_TRUE(IRHaierAC::validChecksum(haier.getRaw())); + EXPECT_TRUE(IRHaierAC::validChecksum(ac.getRaw())); } // Tests for the IRHaierACYRW02 class. TEST(TestHaierACYRW02Class, Button) { - IRHaierACYRW02 haier(kGpioUnused); - haier.begin(); + IRHaierACYRW02 ac(kGpioUnused); + ac.begin(); - haier.setButton(kHaierAcYrw02ButtonPower); - EXPECT_EQ(kHaierAcYrw02ButtonPower, haier.getButton()); - haier.setButton(kHaierAcYrw02ButtonMode); - EXPECT_EQ(kHaierAcYrw02ButtonMode, haier.getButton()); - haier.setButton(kHaierAcYrw02ButtonSleep); - EXPECT_EQ(kHaierAcYrw02ButtonSleep, haier.getButton()); - haier.setButton(kHaierAcYrw02ButtonFan); + ac.setButton(kHaierAcYrw02ButtonPower); + EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton()); + ac.setButton(kHaierAcYrw02ButtonMode); + EXPECT_EQ(kHaierAcYrw02ButtonMode, ac.getButton()); + ac.setButton(kHaierAcYrw02ButtonSleep); + EXPECT_EQ(kHaierAcYrw02ButtonSleep, ac.getButton()); + ac.setButton(kHaierAcYrw02ButtonFan); // Test unexpected values. - haier.setButton(0xFF); - EXPECT_EQ(kHaierAcYrw02ButtonFan, haier.getButton()); - haier.setButton(0x10); - EXPECT_EQ(kHaierAcYrw02ButtonFan, haier.getButton()); + ac.setButton(0xFF); + EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton()); + ac.setButton(0x10); + EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton()); } TEST(TestHaierACYRW02Class, OperatingMode) { - IRHaierACYRW02 haier(kGpioUnused); - haier.begin(); + IRHaierACYRW02 ac(kGpioUnused); + ac.begin(); - haier.setButton(kHaierAcYrw02ButtonPower); - haier.setMode(kHaierAcYrw02Auto); - EXPECT_EQ(kHaierAcYrw02Auto, haier.getMode()); - EXPECT_EQ(kHaierAcYrw02ButtonMode, haier.getButton()); + ac.setButton(kHaierAcYrw02ButtonPower); + ac.setMode(kHaierAcYrw02Auto); + EXPECT_EQ(kHaierAcYrw02Auto, ac.getMode()); + EXPECT_EQ(kHaierAcYrw02ButtonMode, ac.getButton()); - haier.setMode(kHaierAcYrw02Cool); - EXPECT_EQ(kHaierAcYrw02Cool, haier.getMode()); + ac.setMode(kHaierAcYrw02Cool); + EXPECT_EQ(kHaierAcYrw02Cool, ac.getMode()); - haier.setMode(kHaierAcYrw02Heat); - EXPECT_EQ(kHaierAcYrw02Heat, haier.getMode()); + ac.setMode(kHaierAcYrw02Heat); + EXPECT_EQ(kHaierAcYrw02Heat, ac.getMode()); - haier.setMode(kHaierAcYrw02Fan); - EXPECT_EQ(kHaierAcYrw02Fan, haier.getMode()); + ac.setMode(kHaierAcYrw02Fan); + EXPECT_EQ(kHaierAcYrw02Fan, ac.getMode()); - haier.setMode(kHaierAcYrw02Dry); - EXPECT_EQ(kHaierAcYrw02Dry, haier.getMode()); + ac.setMode(kHaierAcYrw02Dry); + EXPECT_EQ(kHaierAcYrw02Dry, ac.getMode()); - haier.setMode(kHaierAcYrw02Auto - 1); - EXPECT_EQ(kHaierAcYrw02Auto, haier.getMode()); + ac.setMode(kHaierAcYrw02Auto - 1); + EXPECT_EQ(kHaierAcYrw02Auto, ac.getMode()); - haier.setMode(kHaierAcYrw02Cool); - EXPECT_EQ(kHaierAcYrw02Cool, haier.getMode()); + ac.setMode(kHaierAcYrw02Cool); + EXPECT_EQ(kHaierAcYrw02Cool, ac.getMode()); - haier.setMode(kHaierAcYrw02Fan + 1); - EXPECT_EQ(kHaierAcYrw02Auto, haier.getMode()); + ac.setMode(kHaierAcYrw02Fan + 1); + EXPECT_EQ(kHaierAcYrw02Auto, ac.getMode()); - haier.setMode(255); - EXPECT_EQ(kHaierAcYrw02Auto, haier.getMode()); + ac.setMode(255); + EXPECT_EQ(kHaierAcYrw02Auto, ac.getMode()); } TEST(TestHaierACYRW02Class, Temperature) { - IRHaierACYRW02 haier(kGpioUnused); - haier.begin(); + IRHaierACYRW02 ac(kGpioUnused); + ac.begin(); - haier.setTemp(kHaierAcMinTemp); - EXPECT_EQ(kHaierAcMinTemp, haier.getTemp()); + ac.setTemp(kHaierAcYrw02MinTempC); + EXPECT_EQ(kHaierAcYrw02MinTempC, ac.getTemp()); - haier.setButton(kHaierAcYrw02ButtonPower); - haier.setTemp(kHaierAcMinTemp + 1); - EXPECT_EQ(kHaierAcMinTemp + 1, haier.getTemp()); - EXPECT_EQ(kHaierAcYrw02ButtonTempUp, haier.getButton()); + ac.setButton(kHaierAcYrw02ButtonPower); + ac.setTemp(kHaierAcYrw02MinTempC + 1); + EXPECT_EQ(kHaierAcYrw02MinTempC + 1, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); - haier.setTemp(kHaierAcMaxTemp); - EXPECT_EQ(kHaierAcMaxTemp, haier.getTemp()); - EXPECT_EQ(kHaierAcYrw02ButtonTempUp, haier.getButton()); + ac.setTemp(kHaierAcYrw02MaxTempC); + EXPECT_EQ(kHaierAcYrw02MaxTempC, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); - haier.setTemp(kHaierAcMinTemp - 1); - EXPECT_EQ(kHaierAcMinTemp, haier.getTemp()); - EXPECT_EQ(kHaierAcYrw02ButtonTempDown, haier.getButton()); + ac.setTemp(kHaierAcYrw02MinTempC - 1); + EXPECT_EQ(kHaierAcYrw02MinTempC, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton()); - haier.setTemp(kHaierAcMaxTemp + 1); - EXPECT_EQ(kHaierAcMaxTemp, haier.getTemp()); - EXPECT_EQ(kHaierAcYrw02ButtonTempUp, haier.getButton()); + ac.setTemp(kHaierAcYrw02MaxTempC + 1); + EXPECT_EQ(kHaierAcYrw02MaxTempC, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); - haier.setTemp(23); - EXPECT_EQ(23, haier.getTemp()); - EXPECT_EQ(kHaierAcYrw02ButtonTempDown, haier.getButton()); - haier.setButton(kHaierAcYrw02ButtonPower); - haier.setTemp(23); - EXPECT_EQ(23, haier.getTemp()); - EXPECT_EQ(kHaierAcYrw02ButtonPower, haier.getButton()); + ac.setTemp(23); + EXPECT_EQ(23, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton()); + ac.setButton(kHaierAcYrw02ButtonPower); + ac.setTemp(23); + EXPECT_EQ(23, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton()); - haier.setTemp(0); - EXPECT_EQ(kHaierAcMinTemp, haier.getTemp()); - EXPECT_EQ(kHaierAcYrw02ButtonTempDown, haier.getButton()); + ac.setTemp(kHaierAcYrw02MinTempF, true); + EXPECT_EQ(kHaierAcYrw02MinTempF, ac.getTemp()); - haier.setTemp(255); - EXPECT_EQ(kHaierAcMaxTemp, haier.getTemp()); - EXPECT_EQ(kHaierAcYrw02ButtonTempUp, haier.getButton()); + ac.setButton(kHaierAcYrw02ButtonPower); + ac.setTemp(kHaierAcYrw02MinTempF + 1, true); + EXPECT_EQ(kHaierAcYrw02MinTempF + 1, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); + + ac.setTemp(kHaierAcYrw02MaxTempF, true); + EXPECT_EQ(kHaierAcYrw02MaxTempF, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); + + ac.setTemp(kHaierAcYrw02MinTempF - 1, true); + EXPECT_EQ(kHaierAcYrw02MinTempF, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton()); + + ac.setTemp(kHaierAcYrw02MaxTempF + 1, true); + EXPECT_EQ(kHaierAcYrw02MaxTempF, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); + + ac.setTemp(66, true); + EXPECT_EQ(66, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton()); + ac.setButton(kHaierAcYrw02ButtonPower); + ac.setTemp(66, true); + EXPECT_EQ(66, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton()); + + // Test specific cases for converting to Fahrenheit + ac.setTemp(76, true); + EXPECT_EQ(76, ac.getTemp()); + ac.setTemp(77, true); + EXPECT_EQ(77, ac.getTemp()); + ac.setTemp(78, true); + EXPECT_EQ(78, ac.getTemp()); + + ac.setTemp(24); + EXPECT_EQ(kHaierAcYrw02ButtonCFAB, ac.getButton()); + + ac.setTemp(0); + EXPECT_EQ(kHaierAcYrw02MinTempC, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempDown, ac.getButton()); + + ac.setTemp(255); + EXPECT_EQ(kHaierAcMaxTemp, ac.getTemp()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); } TEST(TestHaierACYRW02Class, HealthMode) { - IRHaierACYRW02 haier(kGpioUnused); - haier.begin(); + IRHaierACYRW02 ac(kGpioUnused); + ac.begin(); - haier.setHealth(true); - EXPECT_TRUE(haier.getHealth()); - EXPECT_EQ(kHaierAcYrw02ButtonHealth, haier.getButton()); + ac.setHealth(true); + EXPECT_TRUE(ac.getHealth()); + EXPECT_EQ(kHaierAcYrw02ButtonHealth, ac.getButton()); - haier.setButton(kHaierAcYrw02ButtonTempUp); - haier.setHealth(false); - EXPECT_FALSE(haier.getHealth()); - EXPECT_EQ(kHaierAcYrw02ButtonHealth, haier.getButton()); + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setHealth(false); + EXPECT_FALSE(ac.getHealth()); + EXPECT_EQ(kHaierAcYrw02ButtonHealth, ac.getButton()); - haier.setHealth(true); - EXPECT_TRUE(haier.getHealth()); - EXPECT_EQ(kHaierAcYrw02ButtonHealth, haier.getButton()); + ac.setHealth(true); + EXPECT_TRUE(ac.getHealth()); + EXPECT_EQ(kHaierAcYrw02ButtonHealth, ac.getButton()); } TEST(TestHaierACYRW02Class, Power) { - IRHaierACYRW02 haier(kGpioUnused); - haier.begin(); + IRHaierACYRW02 ac(kGpioUnused); + ac.begin(); - haier.setPower(true); - EXPECT_TRUE(haier.getPower()); - EXPECT_EQ(kHaierAcYrw02ButtonPower, haier.getButton()); + ac.setPower(true); + EXPECT_TRUE(ac.getPower()); + EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton()); - haier.setButton(kHaierAcYrw02ButtonTempUp); - haier.setPower(false); - EXPECT_FALSE(haier.getPower()); - EXPECT_EQ(kHaierAcYrw02ButtonPower, haier.getButton()); + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setPower(false); + EXPECT_FALSE(ac.getPower()); + EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton()); - haier.setPower(true); - EXPECT_TRUE(haier.getPower()); - EXPECT_EQ(kHaierAcYrw02ButtonPower, haier.getButton()); + ac.setPower(true); + EXPECT_TRUE(ac.getPower()); + EXPECT_EQ(kHaierAcYrw02ButtonPower, ac.getButton()); - haier.off(); - EXPECT_FALSE(haier.getPower()); - haier.on(); - EXPECT_TRUE(haier.getPower()); + ac.off(); + EXPECT_FALSE(ac.getPower()); + ac.on(); + EXPECT_TRUE(ac.getPower()); } TEST(TestHaierACYRW02Class, SleepMode) { - IRHaierACYRW02 haier(kGpioUnused); - haier.begin(); + IRHaierACYRW02 ac(kGpioUnused); + ac.begin(); - haier.setSleep(true); - EXPECT_TRUE(haier.getSleep()); - EXPECT_EQ(kHaierAcYrw02ButtonSleep, haier.getButton()); + ac.setSleep(true); + EXPECT_TRUE(ac.getSleep()); + EXPECT_EQ(kHaierAcYrw02ButtonSleep, ac.getButton()); - haier.setButton(kHaierAcYrw02ButtonTempUp); - haier.setSleep(false); - EXPECT_FALSE(haier.getSleep()); - EXPECT_EQ(kHaierAcYrw02ButtonSleep, haier.getButton()); + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setSleep(false); + EXPECT_FALSE(ac.getSleep()); + EXPECT_EQ(kHaierAcYrw02ButtonSleep, ac.getButton()); - haier.setSleep(true); - EXPECT_TRUE(haier.getSleep()); - EXPECT_EQ(kHaierAcYrw02ButtonSleep, haier.getButton()); + ac.setSleep(true); + EXPECT_TRUE(ac.getSleep()); + EXPECT_EQ(kHaierAcYrw02ButtonSleep, ac.getButton()); } -TEST(TestHaierACYRW02Class, TurboMode) { - IRHaierACYRW02 haier(kGpioUnused); - haier.begin(); +TEST(TestHaierACYRW02Class, TurboAndQuiet) { + IRHaierACYRW02 ac(kGpioUnused); + ac.begin(); - haier.setTurbo(kHaierAcYrw02TurboOff); - EXPECT_EQ(kHaierAcYrw02TurboOff, haier.getTurbo()); - EXPECT_EQ(kHaierAcYrw02ButtonTurbo, haier.getButton()); + ac.setMode(kHaierAcYrw02Cool); // Turbo & Quiet is allowed in this mode. + ac.setTurbo(false); + ac.setQuiet(false); + EXPECT_FALSE(ac.getTurbo()); + EXPECT_FALSE(ac.getQuiet()); + EXPECT_EQ(kHaierAcYrw02ButtonTurbo, ac.getButton()); - haier.setButton(kHaierAcYrw02ButtonTempUp); + ac.setButton(kHaierAcYrw02ButtonTempUp); - haier.setTurbo(kHaierAcYrw02TurboLow); - EXPECT_EQ(kHaierAcYrw02TurboLow, haier.getTurbo()); - EXPECT_EQ(kHaierAcYrw02ButtonTurbo, haier.getButton()); + ac.setTurbo(true); + EXPECT_TRUE(ac.getTurbo()); + EXPECT_FALSE(ac.getQuiet()); + EXPECT_EQ(kHaierAcYrw02ButtonTurbo, ac.getButton()); - haier.setTurbo(kHaierAcYrw02TurboHigh); - EXPECT_EQ(kHaierAcYrw02TurboHigh, haier.getTurbo()); - EXPECT_EQ(kHaierAcYrw02ButtonTurbo, haier.getButton()); + ac.setQuiet(true); + EXPECT_FALSE(ac.getTurbo()); + EXPECT_TRUE(ac.getQuiet()); + EXPECT_EQ(kHaierAcYrw02ButtonTurbo, ac.getButton()); - haier.setTurbo(kHaierAcYrw02TurboOff); - EXPECT_EQ(kHaierAcYrw02TurboOff, haier.getTurbo()); - EXPECT_EQ(kHaierAcYrw02ButtonTurbo, haier.getButton()); + ac.setTurbo(false); + ac.setQuiet(false); + EXPECT_FALSE(ac.getTurbo()); + EXPECT_FALSE(ac.getQuiet()); + EXPECT_EQ(kHaierAcYrw02ButtonTurbo, ac.getButton()); + + ac.setMode(kHaierAcYrw02Auto); // Turbo & Quiet is not allowed in this mode. + EXPECT_FALSE(ac.getTurbo()); + EXPECT_FALSE(ac.getQuiet()); + ac.setTurbo(true); + EXPECT_FALSE(ac.getTurbo()); + EXPECT_NE(kHaierAcYrw02ButtonTurbo, ac.getButton()); + ac.setQuiet(true); + EXPECT_FALSE(ac.getQuiet()); + EXPECT_NE(kHaierAcYrw02ButtonTurbo, ac.getButton()); } TEST(TestHaierACYRW02Class, Fan) { - IRHaierACYRW02 haier(kGpioUnused); - haier.begin(); + IRHaierACYRW02 ac(kGpioUnused); + ac.begin(); - haier.setFan(kHaierAcYrw02FanAuto); - EXPECT_EQ(kHaierAcYrw02FanAuto, haier.getFan()); - EXPECT_EQ(kHaierAcYrw02ButtonFan, haier.getButton()); + ac.setFan(kHaierAcYrw02FanAuto); + EXPECT_EQ(kHaierAcYrw02FanAuto, ac.getFan()); + EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton()); - haier.setButton(kHaierAcYrw02ButtonTempUp); + ac.setButton(kHaierAcYrw02ButtonTempUp); - haier.setFan(kHaierAcYrw02FanLow); - EXPECT_EQ(kHaierAcYrw02FanLow, haier.getFan()); - EXPECT_EQ(kHaierAcYrw02ButtonFan, haier.getButton()); + ac.setFan(kHaierAcYrw02FanLow); + EXPECT_EQ(kHaierAcYrw02FanLow, ac.getFan()); + EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton()); - haier.setFan(kHaierAcYrw02FanHigh); - EXPECT_EQ(kHaierAcYrw02FanHigh, haier.getFan()); - EXPECT_EQ(kHaierAcYrw02ButtonFan, haier.getButton()); + ac.setFan(kHaierAcYrw02FanHigh); + EXPECT_EQ(kHaierAcYrw02FanHigh, ac.getFan()); + EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton()); - haier.setFan(kHaierAcYrw02FanMed); - EXPECT_EQ(kHaierAcYrw02FanMed, haier.getFan()); - EXPECT_EQ(kHaierAcYrw02ButtonFan, haier.getButton()); + ac.setFan(kHaierAcYrw02FanMed); + EXPECT_EQ(kHaierAcYrw02FanMed, ac.getFan()); + EXPECT_EQ(kHaierAcYrw02ButtonFan, ac.getButton()); // Test unexpected values. - haier.setButton(kHaierAcYrw02ButtonTempUp); - haier.setFan(0x00); - EXPECT_EQ(kHaierAcYrw02FanMed, haier.getFan()); - EXPECT_EQ(kHaierAcYrw02ButtonTempUp, haier.getButton()); + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setFan(0x00); + EXPECT_EQ(kHaierAcYrw02FanMed, ac.getFan()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); } -TEST(TestHaierACYRW02Class, Swing) { - IRHaierACYRW02 haier(kGpioUnused); - haier.begin(); +TEST(TestHaierACYRW02Class, SwingV) { + IRHaierACYRW02 ac(kGpioUnused); + ac.begin(); - haier.setSwing(kHaierAcYrw02SwingOff); - EXPECT_EQ(kHaierAcYrw02SwingOff, haier.getSwing()); - EXPECT_EQ(kHaierAcYrw02ButtonSwing, haier.getButton()); + ac.setSwingV(kHaierAcYrw02SwingVOff); + EXPECT_EQ(kHaierAcYrw02SwingVOff, ac.getSwingV()); + EXPECT_EQ(kHaierAcYrw02ButtonSwingV, ac.getButton()); - haier.setButton(kHaierAcYrw02ButtonTempUp); + ac.setButton(kHaierAcYrw02ButtonTempUp); - haier.setSwing(kHaierAcYrw02SwingAuto); - EXPECT_EQ(kHaierAcYrw02SwingAuto, haier.getSwing()); - EXPECT_EQ(kHaierAcYrw02ButtonSwing, haier.getButton()); + ac.setSwingV(kHaierAcYrw02SwingVAuto); + EXPECT_EQ(kHaierAcYrw02SwingVAuto, ac.getSwingV()); + EXPECT_EQ(kHaierAcYrw02ButtonSwingV, ac.getButton()); - haier.setSwing(kHaierAcYrw02SwingTop); - EXPECT_EQ(kHaierAcYrw02SwingTop, haier.getSwing()); - EXPECT_EQ(kHaierAcYrw02ButtonSwing, haier.getButton()); + ac.setSwingV(kHaierAcYrw02SwingVTop); + EXPECT_EQ(kHaierAcYrw02SwingVTop, ac.getSwingV()); + EXPECT_EQ(kHaierAcYrw02ButtonSwingV, ac.getButton()); - haier.setSwing(kHaierAcYrw02SwingDown); - EXPECT_EQ(kHaierAcYrw02SwingDown, haier.getSwing()); - EXPECT_EQ(kHaierAcYrw02ButtonSwing, haier.getButton()); + ac.setSwingV(kHaierAcYrw02SwingVDown); + EXPECT_EQ(kHaierAcYrw02SwingVDown, ac.getSwingV()); + EXPECT_EQ(kHaierAcYrw02ButtonSwingV, ac.getButton()); // Test unexpected values. - haier.setButton(kHaierAcYrw02ButtonTempUp); - haier.setSwing(0xFF); - EXPECT_EQ(kHaierAcYrw02SwingDown, haier.getSwing()); - EXPECT_EQ(kHaierAcYrw02ButtonTempUp, haier.getButton()); + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setSwingV(0xFF); + EXPECT_EQ(kHaierAcYrw02SwingVDown, ac.getSwingV()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); // Test the mode-dependant positions. - haier.setMode(kHaierAcYrw02Auto); - haier.setSwing(kHaierAcYrw02SwingMiddle); - EXPECT_EQ(kHaierAcYrw02SwingMiddle, haier.getSwing()); - EXPECT_EQ(kHaierAcYrw02ButtonSwing, haier.getButton()); - haier.setMode(kHaierAcYrw02Heat); - haier.setSwing(kHaierAcYrw02SwingMiddle); - EXPECT_EQ(kHaierAcYrw02SwingBottom, haier.getSwing()); - haier.setSwing(kHaierAcYrw02SwingAuto); - EXPECT_EQ(kHaierAcYrw02SwingAuto, haier.getSwing()); - haier.setSwing(kHaierAcYrw02SwingBottom); - EXPECT_EQ(kHaierAcYrw02SwingBottom, haier.getSwing()); - haier.setMode(kHaierAcYrw02Cool); - haier.setSwing(kHaierAcYrw02SwingBottom); - EXPECT_EQ(kHaierAcYrw02SwingMiddle, haier.getSwing()); + ac.setMode(kHaierAcYrw02Auto); + ac.setSwingV(kHaierAcYrw02SwingVMiddle); + EXPECT_EQ(kHaierAcYrw02SwingVMiddle, ac.getSwingV()); + EXPECT_EQ(kHaierAcYrw02ButtonSwingV, ac.getButton()); + ac.setMode(kHaierAcYrw02Heat); + ac.setSwingV(kHaierAcYrw02SwingVMiddle); + EXPECT_EQ(kHaierAcYrw02SwingVBottom, ac.getSwingV()); + ac.setSwingV(kHaierAcYrw02SwingVAuto); + EXPECT_EQ(kHaierAcYrw02SwingVAuto, ac.getSwingV()); + ac.setSwingV(kHaierAcYrw02SwingVBottom); + EXPECT_EQ(kHaierAcYrw02SwingVBottom, ac.getSwingV()); + ac.setMode(kHaierAcYrw02Cool); + ac.setSwingV(kHaierAcYrw02SwingVBottom); + EXPECT_EQ(kHaierAcYrw02SwingVMiddle, ac.getSwingV()); +} + +TEST(TestHaierACYRW02Class, SwingH) { + IRHaierACYRW02 ac(kGpioUnused); + ac.begin(); + + ac.setSwingH(kHaierAcYrw02SwingVOff); + EXPECT_EQ(kHaierAcYrw02SwingHMiddle, ac.getSwingH()); + EXPECT_EQ(kHaierAcYrw02ButtonSwingH, ac.getButton()); + + ac.setButton(kHaierAcYrw02ButtonTempUp); + + ac.setSwingH(kHaierAcYrw02SwingHLeftMax); + EXPECT_EQ(kHaierAcYrw02SwingHLeftMax, ac.getSwingH()); + EXPECT_EQ(kHaierAcYrw02ButtonSwingH, ac.getButton()); + + ac.setSwingH(kHaierAcYrw02SwingHLeft); + EXPECT_EQ(kHaierAcYrw02SwingHLeft, ac.getSwingH()); + EXPECT_EQ(kHaierAcYrw02ButtonSwingH, ac.getButton()); + + ac.setSwingH(kHaierAcYrw02SwingHRight); + EXPECT_EQ(kHaierAcYrw02SwingHRight, ac.getSwingH()); + EXPECT_EQ(kHaierAcYrw02ButtonSwingH, ac.getButton()); + + ac.setSwingH(kHaierAcYrw02SwingHRightMax); + EXPECT_EQ(kHaierAcYrw02SwingHRightMax, ac.getSwingH()); + EXPECT_EQ(kHaierAcYrw02ButtonSwingH, ac.getButton()); + + ac.setSwingH(kHaierAcYrw02SwingHAuto); + EXPECT_EQ(kHaierAcYrw02SwingHAuto, ac.getSwingH()); + EXPECT_EQ(kHaierAcYrw02ButtonSwingH, ac.getButton()); + + // Test unexpected values. + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setSwingH(0xFF); + EXPECT_EQ(kHaierAcYrw02SwingHAuto, ac.getSwingH()); + EXPECT_EQ(kHaierAcYrw02ButtonTempUp, ac.getButton()); +} + +TEST(TestHaierACYRW02Class, Lock) { + IRHaierACYRW02 ac(kGpioUnused); + ac.begin(); + + ac.setLock(true); + EXPECT_TRUE(ac.getLock()); + EXPECT_EQ(kHaierAcYrw02ButtonLock, ac.getButton()); + + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setLock(false); + EXPECT_FALSE(ac.getLock()); + EXPECT_EQ(kHaierAcYrw02ButtonLock, ac.getButton()); + + ac.setLock(true); + EXPECT_TRUE(ac.getLock()); + EXPECT_EQ(kHaierAcYrw02ButtonLock, ac.getButton()); } TEST(TestHaierACYRW02Class, MessageConstuction) { - IRHaierACYRW02 haier(kGpioUnused); + IRHaierACYRW02 ac(kGpioUnused); EXPECT_EQ( - "Power: On, Button: 5 (Power), Mode: 0 (Auto), Temp: 25C," - " Fan: 5 (Auto), Turbo: 0 (Off), Swing: 0 (Off), Sleep: Off," - " Health: On, Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off", - haier.toString()); - haier.setMode(kHaierAcYrw02Cool); - haier.setTemp(21); - haier.setFan(kHaierAcYrw02FanHigh); + "Model: 1 (V9014557-A), Power: On, Button: 5 (Power), " + "Mode: 0 (Auto), Temp: 25C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 0 (Off), Swing(H): 0 (Middle), Sleep: Off, Health: On, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", + ac.toString()); + ac.setMode(kHaierAcYrw02Cool); + ac.setTemp(21); + ac.setFan(kHaierAcYrw02FanHigh); EXPECT_EQ( - "Power: On, Button: 4 (Fan), Mode: 1 (Cool), Temp: 21C," - " Fan: 1 (High), Turbo: 0 (Off), Swing: 0 (Off), Sleep: Off," - " Health: On, Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off", - haier.toString()); + "Model: 1 (V9014557-A), Power: On, Button: 4 (Fan), " + "Mode: 1 (Cool), Temp: 21C, Fan: 1 (High), Turbo: Off, Quiet: Off, " + "Swing(V): 0 (Off), Swing(H): 0 (Middle), Sleep: Off, Health: On, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", + ac.toString()); - haier.setSwing(kHaierAcYrw02SwingMiddle); - haier.setHealth(false); - haier.setSleep(true); - haier.setTurbo(kHaierAcYrw02TurboHigh); + ac.setTemp(75, true); + ac.setSwingV(kHaierAcYrw02SwingVMiddle); + ac.setHealth(false); + ac.setSleep(true); + ac.setTurbo(true); EXPECT_EQ( - "Power: On, Button: 8 (Turbo), Mode: 1 (Cool), Temp: 21C, " - "Fan: 1 (High), Turbo: 1 (High), Swing: 2 (Middle), " - "Sleep: On, Health: Off, " - "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off", - haier.toString()); + "Model: 1 (V9014557-A), Power: On, Button: 8 (Turbo), " + "Mode: 1 (Cool), Temp: 75F, Fan: 1 (High), Turbo: On, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: On, Health: Off, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", + ac.toString()); } // Decode "real" state messages. @@ -704,55 +818,60 @@ TEST(TestHaierACYRW02Class, RealStates) { 0xA6, 0xE1, 0x00, 0x00, 0x40, 0x20, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0x6E}; - IRHaierACYRW02 haier(kGpioUnused); - haier.setRaw(expectedState1); + IRHaierACYRW02 ac(kGpioUnused); + ac.setRaw(expectedState1); EXPECT_EQ( - "Power: On, Button: 7 (Health), Mode: 4 (Heat), Temp: 30C, " - "Fan: 1 (High), Turbo: 0 (Off), Swing: 1 (Highest), Sleep: Off, " - "Health: Off, Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off", - haier.toString()); + "Model: 1 (V9014557-A), Power: On, Button: 7 (Health), " + "Mode: 4 (Heat), Temp: 30C, Fan: 1 (High), Turbo: Off, Quiet: Off, " + "Swing(V): 1 (Highest), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", + ac.toString()); uint8_t expectedState2[kHaierACYRW02StateLength] = { 0xA6, 0xE0, 0x00, 0x00, 0x00, 0x20, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x05, 0x75}; - haier.setRaw(expectedState2); + ac.setRaw(expectedState2); EXPECT_EQ( - "Power: Off, Button: 5 (Power), Mode: 4 (Heat), Temp: 30C, " - "Fan: 1 (High), Turbo: 0 (Off), Swing: 0 (Off), Sleep: Off, " - "Health: Off, Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off", - haier.toString()); + "Model: 1 (V9014557-A), Power: Off, Button: 5 (Power), " + "Mode: 4 (Heat), Temp: 30C, Fan: 1 (High), Turbo: Off, Quiet: Off, " + "Swing(V): 0 (Off), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", + ac.toString()); uint8_t expectedState3[kHaierACYRW02StateLength] = { 0xA6, 0x02, 0x00, 0x02, 0x40, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2B}; - haier.setRaw(expectedState3); + ac.setRaw(expectedState3); EXPECT_EQ( - "Power: On, Button: 1 (Temp Down), Mode: 1 (Cool), Temp: 16C, " - "Fan: 1 (High), Turbo: 0 (Off), Swing: 2 (Middle), Sleep: Off, " - "Health: On, Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off", - haier.toString()); + "Model: 1 (V9014557-A), Power: On, Button: 1 (Temp Down), " + "Mode: 1 (Cool), Temp: 16C, Fan: 1 (High), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: On, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", + ac.toString()); - // cool 25, health, fan auto, swing auto, sleep on + // cool 25, health, fan auto, vertical swing auto, sleep on uint8_t expectedState4[kHaierACYRW02StateLength] = { 0xA6, 0x9C, 0x00, 0x02, 0x40, 0xA8, 0x00, 0x20, 0x80, 0x00, 0x00, 0x00, 0x0B, 0xD7}; - haier.setRaw(expectedState4); + ac.setRaw(expectedState4); EXPECT_EQ( - "Power: On, Button: 11 (Sleep), Mode: 1 (Cool), Temp: 25C, " - "Fan: 5 (Auto), Turbo: 0 (Off), Swing: 12 (Auto), Sleep: On, " - "Health: On, Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off", - haier.toString()); + "Model: 1 (V9014557-A), Power: On, Button: 11 (Sleep), " + "Mode: 1 (Cool), Temp: 25C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 12 (Auto), Swing(H): 0 (Middle), Sleep: On, Health: On, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", + ac.toString()); - // cool 25, health, fan 3, swing auto, sleep on + // cool 25, health, fan 3, vertical swing auto, sleep on uint8_t expectedState5[kHaierACYRW02StateLength] = { 0xA6, 0x9C, 0x00, 0x02, 0x40, 0x27, 0x36, 0x20, 0x80, 0x00, 0x00, 0x00, 0x04, 0x85}; - haier.setRaw(expectedState5); + ac.setRaw(expectedState5); EXPECT_EQ( - "Power: On, Button: 4 (Fan), Mode: 1 (Cool), Temp: 25C, " - "Fan: 1 (High), Turbo: 0 (Off), Swing: 12 (Auto), Sleep: On, " - "Health: On, Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off", - haier.toString()); + "Model: 1 (V9014557-A), Power: On, Button: 4 (Fan), " + "Mode: 1 (Cool), Temp: 25C, Fan: 1 (High), Turbo: Off, Quiet: Off, " + "Swing(V): 12 (Auto), Swing(H): 0 (Middle), Sleep: On, Health: On, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", + ac.toString()); } // Tests for decodeHaierAC(). @@ -823,7 +942,7 @@ TEST(TestDecodeHaierAC, RealExample1) { EXPECT_EQ( "Command: 1 (On), Mode: 1 (Cool), Temp: 16C, Fan: 1 (Low), " - "Swing: 0 (Off), Sleep: Off, Health: Off, " + "Swing(V): 0 (Off), Sleep: Off, Health: Off, " "Clock: 00:01, On Timer: Off, Off Timer: Off", IRAcUtils::resultAcToString(&irsend.capture)); stdAc::state_t r, p; @@ -864,13 +983,13 @@ TEST(TestDecodeHaierAC, RealExample2) { EXPECT_FALSE(irsend.capture.repeat); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); - IRHaierAC haier(kGpioUnused); - haier.setRaw(irsend.capture.state); + IRHaierAC ac(kGpioUnused); + ac.setRaw(irsend.capture.state); EXPECT_EQ( "Command: 6 (Temp Up), Mode: 1 (Cool), Temp: 22C, Fan: 1 (Low), " - "Swing: 0 (Off), Sleep: Off, Health: Off, " + "Swing(V): 0 (Off), Sleep: Off, Health: Off, " "Clock: 00:01, On Timer: Off, Off Timer: Off", - haier.toString()); + ac.toString()); } // Decode a "real" example message. @@ -907,13 +1026,13 @@ TEST(TestDecodeHaierAC, RealExample3) { EXPECT_FALSE(irsend.capture.repeat); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); - IRHaierAC haier(kGpioUnused); - haier.setRaw(irsend.capture.state); + IRHaierAC ac(kGpioUnused); + ac.setRaw(irsend.capture.state); EXPECT_EQ( "Command: 12 (Health), Mode: 1 (Cool), Temp: 30C, Fan: 1 (Low), " - "Swing: 0 (Off), Sleep: Off, Health: On, " + "Swing(V): 0 (Off), Sleep: Off, Health: On, " "Clock: 00:09, On Timer: Off, Off Timer: Off", - haier.toString()); + ac.toString()); } // Decode normal "synthetic" messages. @@ -977,13 +1096,14 @@ TEST(TestDecodeHaierAC_YRW02, RealExample) { EXPECT_FALSE(irsend.capture.repeat); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); - IRHaierACYRW02 haier(kGpioUnused); - haier.setRaw(irsend.capture.state); + IRHaierACYRW02 ac(kGpioUnused); + ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 17C, " - "Fan: 1 (High), Turbo: 0 (Off), Swing: 2 (Middle), Sleep: Off, " - "Health: On, Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off", - haier.toString()); + "Model: 1 (V9014557-A), Power: On, Button: 5 (Power), " + "Mode: 1 (Cool), Temp: 17C, Fan: 1 (High), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: On, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", + ac.toString()); } // Default state of the remote needed to include hidden data. @@ -998,7 +1118,7 @@ TEST(TestHaierAcIssues, Issue668) { ac._irsend.reset(); char expected_on[] = "Command: 1 (On), Mode: 1 (Cool), Temp: 25C, Fan: 1 (Low), " - "Swing: 0 (Off), Sleep: Off, Health: Off, Clock: 00:00, " + "Swing(V): 0 (Off), Sleep: Off, Health: Off, Clock: 00:00, " "On Timer: Off, Off Timer: Off"; // State taken from real capture: // https://github.com/crankyoldgit/IRremoteESP8266/issues/668#issuecomment-483531895 @@ -1036,7 +1156,7 @@ TEST(TestHaierAcIssues, Issue668) { ac._irsend.reset(); char expected_temp_plus_one[] = "Command: 6 (Temp Up), Mode: 1 (Cool), Temp: 26C, Fan: 1 (Low), " - "Swing: 0 (Off), Sleep: Off, Health: Off, Clock: 00:00, " + "Swing(V): 0 (Off), Sleep: Off, Health: Off, Clock: 00:00, " "On Timer: Off, Off Timer: Off"; // State taken from real capture: // https://github.com/crankyoldgit/IRremoteESP8266/issues/668#issuecomment-483531895 @@ -1060,7 +1180,7 @@ TEST(TestHaierAcIssues, Issue668) { ac._irsend.reset(); char expected_temp_minus_one[] = "Command: 7 (Temp Down), Mode: 1 (Cool), Temp: 25C, Fan: 1 (Low), " - "Swing: 0 (Off), Sleep: Off, Health: Off, Clock: 00:00, " + "Swing(V): 0 (Off), Sleep: Off, Health: Off, Clock: 00:00, " "On Timer: Off, Off Timer: Off"; ASSERT_EQ(26, ac.getTemp()); ac.setTemp(ac.getTemp() - 1); @@ -1081,7 +1201,7 @@ TEST(TestHaierACClass, toCommon) { ac.setMode(kHaierAcCool); ac.setTemp(20); ac.setFan(kHaierAcFanHigh); - ac.setSwing(kHaierAcSwingChg); + ac.setSwingV(kHaierAcSwingVChg); ac.setHealth(true); ac.setSleep(true); // Now test it. @@ -1102,7 +1222,7 @@ TEST(TestHaierACClass, toCommon) { ASSERT_FALSE(ac.toCommon().quiet); ASSERT_FALSE(ac.toCommon().econo); ASSERT_FALSE(ac.toCommon().clean); - ASSERT_FALSE(ac.toCommon().beep); + ASSERT_TRUE(ac.toCommon().beep); ASSERT_EQ(-1, ac.toCommon().clock); } @@ -1112,12 +1232,14 @@ TEST(TestHaierACYRW02Class, toCommon) { ac.setMode(kHaierAcYrw02Cool); ac.setTemp(20); ac.setFan(kHaierAcYrw02FanHigh); - ac.setSwing(kHaierAcYrw02SwingTop); + ac.setSwingV(kHaierAcYrw02SwingVTop); + ac.setSwingH(kHaierAcYrw02SwingHRightMax); ac.setHealth(true); ac.setSleep(true); + ac.setTurbo(true); // Now test it. ASSERT_EQ(decode_type_t::HAIER_AC_YRW02, ac.toCommon().protocol); - ASSERT_EQ(-1, ac.toCommon().model); + ASSERT_EQ(1, ac.toCommon().model); ASSERT_TRUE(ac.toCommon().power); ASSERT_TRUE(ac.toCommon().celsius); ASSERT_EQ(20, ac.toCommon().degrees); @@ -1125,15 +1247,15 @@ TEST(TestHaierACYRW02Class, toCommon) { ASSERT_EQ(stdAc::opmode_t::kCool, ac.toCommon().mode); ASSERT_EQ(stdAc::fanspeed_t::kMax, ac.toCommon().fanspeed); ASSERT_EQ(stdAc::swingv_t::kHighest, ac.toCommon().swingv); + ASSERT_EQ(stdAc::swingh_t::kRightMax, ac.toCommon().swingh); ASSERT_EQ(0, ac.toCommon().sleep); - // Unsupported. - ASSERT_EQ(stdAc::swingh_t::kOff, ac.toCommon().swingh); - ASSERT_FALSE(ac.toCommon().turbo); - ASSERT_FALSE(ac.toCommon().light); + ASSERT_TRUE(ac.toCommon().turbo); ASSERT_FALSE(ac.toCommon().quiet); + // Unsupported. + ASSERT_FALSE(ac.toCommon().light); ASSERT_FALSE(ac.toCommon().econo); ASSERT_FALSE(ac.toCommon().clean); - ASSERT_FALSE(ac.toCommon().beep); + ASSERT_TRUE(ac.toCommon().beep); ASSERT_EQ(-1, ac.toCommon().clock); } @@ -1204,9 +1326,10 @@ TEST(TestDecodeHaierAC176, SyntheticDecode) { EXPECT_FALSE(irsend.capture.repeat); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 24C, Fan: 5 (Auto), " - "Turbo: 0 (Off), Swing: 6 (UNKNOWN), Sleep: Off, Health: Off, " - "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off", + "Model: 1 (V9014557-A), Power: On, Button: 5 (Power), " + "Mode: 1 (Cool), Temp: 24C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 6 (UNKNOWN), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", IRAcUtils::resultAcToString(&irsend.capture)); stdAc::state_t result, prev; ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev)); @@ -1245,9 +1368,10 @@ TEST(TestHaierAC176Class, BuildKnownState) { ac.setFan(kHaierAcYrw02FanHigh); EXPECT_TRUE(ac.validChecksum(ac.getRaw())); EXPECT_EQ( - "Power: On, Button: 4 (Fan), Mode: 4 (Heat), Temp: 24C, Fan: 1 (High), " - "Turbo: 0 (Off), Swing: 0 (Off), Sleep: Off, Health: On, " - "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off", + "Model: 1 (V9014557-A), Power: On, Button: 4 (Fan), " + "Mode: 4 (Heat), Temp: 24C, Fan: 1 (High), Turbo: Off, Quiet: Off, " + "Swing(V): 0 (Off), Swing(H): 0 (Middle), Sleep: Off, Health: On, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); /* Disabled pending: https://github.com/crankyoldgit/IRremoteESP8266/issues/1480#issuecomment-885636790 @@ -1323,56 +1447,91 @@ TEST(TestHaierAC176Class, Timers) { // Real data. // Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1480#issuecomment-894804106 - const uint8_t timer30m[22] = { + const uint8_t timer30m[kHaierAC176StateLength] = { 0xA6, 0x82, 0x00, 0x40, 0x00, 0xA0, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x10, 0x36, 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB7}; - const uint8_t timeroff[22] = { + const uint8_t timeroff[kHaierAC176StateLength] = { 0xA6, 0x82, 0x00, 0x00, 0x40, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x18, 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB7}; // https://docs.google.com/spreadsheets/d/1wdOVS08wgK2pEP7hTZLYMmrQ9FZVmLpZF2HjNQaVxlU/edit#gid=0&range=A65 - const uint8_t timeroffthenon[22] = { + const uint8_t timeroffthenon[kHaierAC176StateLength] = { 0xA6, 0x82, 0x00, 0xA0, 0x40, 0xA0, 0x1E, 0x08, 0x00, 0x00, 0x00, 0x00, 0x10, 0xDE, 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB7}; ac.setRaw(timer30m); EXPECT_EQ(kHaierAcYrw02OnTimer, ac.getTimerMode()); EXPECT_EQ( - "Power: Off, Button: 0 (Temp Up), Mode: 0 (Auto), Temp: 24C, " - "Fan: 5 (Auto), Turbo: 0 (Off), Swing: 2 (Middle), Sleep: Off, " - "Health: Off, Timer Mode: 2 (On), On Timer: 00:30, Off Timer: Off", + "Model: 1 (V9014557-A), Power: Off, Button: 16 (Timer), " + "Mode: 0 (Auto), Temp: 24C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Timer Mode: 2 (On), On Timer: 00:30, Off Timer: Off, Lock: Off", ac.toString()); ac.setRaw(timeroff); EXPECT_EQ(kHaierAcYrw02NoTimers, ac.getTimerMode()); EXPECT_EQ( - "Power: On, Button: 0 (Temp Up), Mode: 0 (Auto), Temp: 24C, " - "Fan: 5 (Auto), Turbo: 0 (Off), Swing: 2 (Middle), Sleep: Off, " - "Health: Off, Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off", + "Model: 1 (V9014557-A), Power: On, Button: 16 (Timer), " + "Mode: 0 (Auto), Temp: 24C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); ac.setRaw(timeroffthenon); EXPECT_EQ( - "Power: On, Button: 0 (Temp Up), Mode: 0 (Auto), Temp: 24C, " - "Fan: 5 (Auto), Turbo: 0 (Off), Swing: 2 (Middle), Sleep: Off, " - "Health: Off, Timer Mode: 5 (Off-On), On Timer: 08:00, Off Timer: 00:30", + "Model: 1 (V9014557-A), Power: On, Button: 16 (Timer), " + "Mode: 0 (Auto), Temp: 24C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Timer Mode: 5 (Off-On), On Timer: 08:00, Off Timer: 00:30, Lock: Off", ac.toString()); ac.setTimerMode(kHaierAcYrw02OnThenOffTimer); EXPECT_EQ( - "Power: On, Button: 0 (Temp Up), Mode: 0 (Auto), Temp: 24C, " - "Fan: 5 (Auto), Turbo: 0 (Off), Swing: 2 (Middle), Sleep: Off, " - "Health: Off, Timer Mode: 4 (On-Off), On Timer: 08:00, Off Timer: 00:30", + "Model: 1 (V9014557-A), Power: On, Button: 16 (Timer), " + "Mode: 0 (Auto), Temp: 24C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Timer Mode: 4 (On-Off), On Timer: 08:00, Off Timer: 00:30, Lock: Off", ac.toString()); ac.setTimerMode(kHaierAcYrw02OffTimer); EXPECT_EQ(0, ac.getOnTimer()); EXPECT_EQ(30, ac.getOffTimer()); EXPECT_EQ( - "Power: On, Button: 0 (Temp Up), Mode: 0 (Auto), Temp: 24C, " - "Fan: 5 (Auto), Turbo: 0 (Off), Swing: 2 (Middle), Sleep: Off, " - "Health: Off, Timer Mode: 1 (Off), On Timer: Off, Off Timer: 00:30", + "Model: 1 (V9014557-A), Power: On, Button: 16 (Timer), " + "Mode: 0 (Auto), Temp: 24C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Timer Mode: 1 (Off), On Timer: Off, Off Timer: 00:30, Lock: Off", ac.toString()); ac.setTimerMode(kHaierAcYrw02NoTimers); EXPECT_EQ(0, ac.getOnTimer()); EXPECT_EQ(0, ac.getOffTimer()); EXPECT_EQ( - "Power: On, Button: 0 (Temp Up), Mode: 0 (Auto), Temp: 24C, " - "Fan: 5 (Auto), Turbo: 0 (Off), Swing: 2 (Middle), Sleep: Off, " - "Health: Off, Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off", + "Model: 1 (V9014557-A), Power: On, Button: 16 (Timer), " + "Mode: 0 (Auto), Temp: 24C, Fan: 5 (Auto), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", + ac.toString()); +} + +TEST(TestHaierAC176Class, Models) { + IRHaierAC176 ac(kGpioUnused); + ac.begin(); + EXPECT_EQ(haier_ac176_remote_model_t::V9014557_A, ac.getModel()); + + ac.setButton(kHaierAcYrw02ButtonTempUp); + ac.setModel(haier_ac176_remote_model_t::V9014557_B); + EXPECT_EQ(haier_ac176_remote_model_t::V9014557_B, ac.getModel()); + EXPECT_EQ(kHaierAcYrw02ButtonCFAB, ac.getButton()); + + ac.setButton(kHaierAcYrw02ButtonTempDown); + ac.setModel(haier_ac176_remote_model_t::V9014557_A); + EXPECT_EQ(haier_ac176_remote_model_t::V9014557_A, ac.getModel()); + EXPECT_EQ(kHaierAcYrw02ButtonCFAB, ac.getButton()); + + // Real data. + const uint8_t setmodelb[kHaierAC176StateLength] = { + 0x59, 0x82, 0x00, 0x00, 0x40, 0x60, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0x00, 0x1A, 0x55, 0xB7, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x77}; + ac.setRaw(setmodelb); + EXPECT_EQ(haier_ac176_remote_model_t::V9014557_B, ac.getModel()); + EXPECT_EQ( + "Model: 2 (V9014557-B), Power: On, Button: 26 (Celsius/Fahrenheit), " + "Mode: 6 (Fan), Temp: 24C, Fan: 3 (Low), Turbo: Off, Quiet: Off, " + "Swing(V): 2 (Middle), Swing(H): 0 (Middle), Sleep: Off, Health: Off, " + "Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off", ac.toString()); } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Mirage_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Mirage_test.cpp index 2530afc5c..ad08918e2 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Mirage_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Mirage_test.cpp @@ -1,5 +1,6 @@ -// Copyright 2020 David Conran +// Copyright 2020-2021 David Conran +#include "ir_Mirage.h" #include "IRac.h" #include "IRrecv.h" #include "IRrecv_test.h" @@ -11,7 +12,7 @@ TEST(TestUtils, Housekeeping) { ASSERT_EQ("MIRAGE", typeToString(decode_type_t::MIRAGE)); ASSERT_EQ(decode_type_t::MIRAGE, strToDecodeType("MIRAGE")); ASSERT_TRUE(hasACState(decode_type_t::MIRAGE)); - ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::MIRAGE)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::MIRAGE)); ASSERT_EQ(kMirageBits, IRsend::defaultBits(decode_type_t::MIRAGE)); ASSERT_EQ(kMirageMinRepeat, IRsend::minRepeats(decode_type_t::MIRAGE)); } @@ -55,7 +56,9 @@ TEST(TestDecodeMirage, RealExample) { ASSERT_EQ(kMirageBits, irsend.capture.bits); EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "", + "Model: 1 (KKG9AC1), Power: On, Mode: 2 (Cool), Temp: 25C, " + "Fan: 0 (Auto), Turbo: Off, Sleep: Off, Light: Off, " + "Swing(V): 0 (Off), Clock: 14:16", IRAcUtils::resultAcToString(&irsend.capture)); } @@ -70,13 +73,14 @@ TEST(TestDecodeMirage, SyntheticExample) { irsend.sendMirage(expected); irsend.makeDecodeResult(); - ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(decode_type_t::MIRAGE, irsend.capture.decode_type); ASSERT_EQ(kMirageBits, irsend.capture.bits); EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "", + "Model: 1 (KKG9AC1), Power: On, Mode: 2 (Cool), Temp: 25C, " + "Fan: 0 (Auto), Turbo: Off, Sleep: Off, Light: Off, " + "Swing(V): 0 (Off), Clock: 14:16", IRAcUtils::resultAcToString(&irsend.capture)); } @@ -119,6 +123,469 @@ TEST(TestDecodeMirage, RealExampleWithDodgyHardwareCapture) { ASSERT_EQ(kMirageBits, irsend.capture.bits); EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "", + "Model: 1 (KKG9AC1), Power: On, Mode: 2 (Cool), Temp: 25C, " + "Fan: 0 (Auto), Turbo: Off, Sleep: Off, Light: Off, " + "Swing(V): 0 (Off), Clock: 14:16", IRAcUtils::resultAcToString(&irsend.capture)); } + +TEST(TestMirageAcClass, Power) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + ac.setModel(mirage_ac_remote_model_t::KKG9AC1); + ac.on(); + EXPECT_TRUE(ac.getPower()); + ac.on(); + EXPECT_TRUE(ac.getPower()); + + ac.off(); + EXPECT_FALSE(ac.getPower()); + ac.off(); + EXPECT_FALSE(ac.getPower()); + + ac.setPower(true); + EXPECT_TRUE(ac.getPower()); + + ac.setPower(false); + EXPECT_FALSE(ac.getPower()); + + const uint8_t on[kMirageStateLength] = { + 0x56, 0x75, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x14, 0x26}; + ac.setRaw(on); + EXPECT_TRUE(ac.getPower()); + const uint8_t off[kMirageStateLength] = { + 0x56, 0x6C, 0x00, 0x00, 0x21, 0xD8, 0x00, 0x00, + 0x0C, 0x00, 0x0C, 0x2C, 0x23, 0x01, 0x61}; + ac.setRaw(off); + EXPECT_FALSE(ac.getPower()); + + ac.setModel(mirage_ac_remote_model_t::KKG29AC1); + ac.on(); + EXPECT_TRUE(ac.getPower()); + ac.off(); + EXPECT_FALSE(ac.getPower()); + ac.setPower(true); + EXPECT_TRUE(ac.getPower()); + ac.setPower(false); + EXPECT_FALSE(ac.getPower()); +} + +TEST(TestMirageAcClass, OperatingMode) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + ac.setMode(kMirageAcCool); + EXPECT_EQ(kMirageAcCool, ac.getMode()); + ac.setMode(kMirageAcHeat); + EXPECT_EQ(kMirageAcHeat, ac.getMode()); + ac.setMode(kMirageAcDry); + EXPECT_EQ(kMirageAcDry, ac.getMode()); + ac.setMode(kMirageAcFan); + EXPECT_EQ(kMirageAcFan, ac.getMode()); + ac.setMode(kMirageAcRecycle); + EXPECT_EQ(kMirageAcRecycle, ac.getMode()); + ac.setMode(255); + EXPECT_EQ(kMirageAcCool, ac.getMode()); +} + +TEST(TestMirageAcClass, HumanReadable) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + // Tests for the KKG9AC1 model. + EXPECT_EQ( + "Model: 1 (KKG9AC1), Power: On, Mode: 2 (Cool), Temp: 16C, " + "Fan: 0 (Auto), Turbo: Off, Sleep: Off, Light: Off, " + "Swing(V): 13 (Auto), Clock: 00:00", + ac.toString()); + // Ref: https://docs.google.com/spreadsheets/d/1Ucu9mOOIIJoWQjUJq_VCvwgV3EwKaRk8K2AuZgccYEk/edit#gid=0&range=C7 + // 0x56710000201A00000C000C26010041 + const uint8_t cool_21c_auto[kMirageStateLength] = { + 0x56, 0x71, 0x00, 0x00, 0x20, 0x1A, 0x00, 0x00, + 0x0C, 0x00, 0x0C, 0x26, 0x01, 0x00, 0x41}; + ac.setRaw(cool_21c_auto); + EXPECT_EQ( + "Model: 1 (KKG9AC1), Power: On, Mode: 2 (Cool), Temp: 21C, " + "Fan: 0 (Auto), Turbo: Off, Sleep: Off, Light: Off, " + "Swing(V): 13 (Auto), Clock: 00:01", + ac.toString()); + + const uint8_t SyntheticExample[kMirageStateLength] = { + 0x56, 0x75, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x16, 0x14, 0x26}; + ac.setRaw(SyntheticExample); + EXPECT_EQ( + "Model: 1 (KKG9AC1), Power: On, Mode: 2 (Cool), Temp: 25C, " + "Fan: 0 (Auto), Turbo: Off, Sleep: Off, Light: Off, " + "Swing(V): 0 (Off), Clock: 14:16", + ac.toString()); + + // Tests for the KKG29AC1 model. + ac.setModel(mirage_ac_remote_model_t::KKG29AC1); + EXPECT_EQ( + "Model: 2 (KKG29AC1), Power: On, Mode: 2 (Cool), Temp: 25C, " + "Fan: 0 (Auto), Turbo: Off, Sleep: Off, Quiet: Off, Light: -, " + "Swing(V): Off, Swing(H): Off, " + "Filter: Off, Clean: -, On Timer: Off, Off Timer: Off, " + "IFeel: Off", + ac.toString()); +} + +TEST(TestMirageAcClass, Temperature) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + ac.setTemp(0); + EXPECT_EQ(kMirageAcMinTemp, ac.getTemp()); + + ac.setTemp(255); + EXPECT_EQ(kMirageAcMaxTemp, ac.getTemp()); + + ac.setTemp(kMirageAcMinTemp); + EXPECT_EQ(kMirageAcMinTemp, ac.getTemp()); + + ac.setTemp(kMirageAcMaxTemp); + EXPECT_EQ(kMirageAcMaxTemp, ac.getTemp()); + + ac.setTemp(kMirageAcMinTemp - 1); + EXPECT_EQ(kMirageAcMinTemp, ac.getTemp()); + + ac.setTemp(kMirageAcMaxTemp + 1); + EXPECT_EQ(kMirageAcMaxTemp, ac.getTemp()); + + ac.setTemp(17); + EXPECT_EQ(17, ac.getTemp()); + + ac.setTemp(21); + EXPECT_EQ(21, ac.getTemp()); + + ac.setTemp(25); + EXPECT_EQ(25, ac.getTemp()); + + ac.setTemp(30); + EXPECT_EQ(30, ac.getTemp()); +} + +TEST(TestMirageAcClass, FanSpeed) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + ac.setFan(kMirageAcFanAuto); + EXPECT_EQ(kMirageAcFanAuto, ac.getFan()); + ac.setFan(kMirageAcFanLow); + EXPECT_EQ(kMirageAcFanLow, ac.getFan()); + ac.setFan(kMirageAcFanMed); + EXPECT_EQ(kMirageAcFanMed, ac.getFan()); + ac.setFan(kMirageAcFanHigh); + EXPECT_EQ(kMirageAcFanHigh, ac.getFan()); + + ac.setFan(255); + EXPECT_EQ(kMirageAcFanAuto, ac.getFan()); +} + +TEST(TestMirageAcClass, Turbo) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + ac.setModel(mirage_ac_remote_model_t::KKG9AC1); + ac.setTurbo(true); + EXPECT_TRUE(ac.getTurbo()); + ac.setTurbo(false); + EXPECT_FALSE(ac.getTurbo()); + ac.setTurbo(true); + EXPECT_TRUE(ac.getTurbo()); + + ac.setModel(mirage_ac_remote_model_t::KKG29AC1); + ac.setTurbo(true); + EXPECT_TRUE(ac.getTurbo()); + ac.setTurbo(false); + EXPECT_FALSE(ac.getTurbo()); + ac.setTurbo(true); + EXPECT_TRUE(ac.getTurbo()); +} + +TEST(TestMirageAcClass, Light) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + ac.setModel(mirage_ac_remote_model_t::KKG9AC1); + ac.setLight(true); + EXPECT_TRUE(ac.getLight()); + ac.setLight(false); + EXPECT_FALSE(ac.getLight()); + ac.setLight(true); + EXPECT_TRUE(ac.getLight()); + + ac.setModel(mirage_ac_remote_model_t::KKG29AC1); + ac.setLight(true); + EXPECT_TRUE(ac.getLight()); + ac.setLight(false); + EXPECT_FALSE(ac.getLight()); + ac.setLight(true); + EXPECT_TRUE(ac.getLight()); +} + +TEST(TestMirageAcClass, Sleep) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + ac.setModel(mirage_ac_remote_model_t::KKG9AC1); + ac.setSleep(true); + EXPECT_TRUE(ac.getSleep()); + ac.setSleep(false); + EXPECT_FALSE(ac.getSleep()); + ac.setSleep(true); + EXPECT_TRUE(ac.getSleep()); + + ac.setModel(mirage_ac_remote_model_t::KKG29AC1); + ac.setSleep(true); + EXPECT_TRUE(ac.getSleep()); + ac.setSleep(false); + EXPECT_FALSE(ac.getSleep()); + ac.setSleep(true); + EXPECT_TRUE(ac.getSleep()); +} + +TEST(TestMirageAcClass, Clock) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + ac.setModel(mirage_ac_remote_model_t::KKG9AC1); // This model supports time. + ac.setClock(0); + EXPECT_EQ(0, ac.getClock()); + ac.setClock(12 * 60 * 60 + 30 * 60 + 59); // aka. 12:30:59 + EXPECT_EQ(12 * 60 * 60 + 30 * 60 + 59, ac.getClock()); + ac.setClock(23 * 60 * 60 + 59 * 60 + 59); // aka. 23:59:59 + EXPECT_EQ(23 * 60 * 60 + 59 * 60 + 59, ac.getClock()); + ac.setClock(24 * 60 * 60); // aka. 24:00:00 + EXPECT_EQ(23 * 60 * 60 + 59 * 60 + 59, ac.getClock()); // aka. 23:59:59 + + ac.setModel(mirage_ac_remote_model_t::KKG29AC1); // This model has no clock. + EXPECT_EQ(0, ac.getClock()); + ac.setClock(12 * 60 * 60 + 30 * 60 + 59); // aka. 12:30:59 + EXPECT_EQ(0, ac.getClock()); +} + +TEST(TestMirageAcClass, Checksums) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + const uint8_t SyntheticExample[kMirageStateLength] = { + 0x56, 0x75, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x16, 0x14, 0x26}; + EXPECT_TRUE(IRMirageAc::validChecksum(SyntheticExample)); + EXPECT_EQ(0x26, IRMirageAc::calculateChecksum(SyntheticExample)); +} + +TEST(TestMirageAcClass, SwingV) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + // Set the model to one with full swingv support. + ac.setModel(mirage_ac_remote_model_t::KKG9AC1); + + ac.setSwingV(kMirageAcSwingVAuto); + EXPECT_EQ(kMirageAcSwingVAuto, ac.getSwingV()); + + ac.setSwingV(kMirageAcSwingVHigh); + EXPECT_EQ(kMirageAcSwingVHigh, ac.getSwingV()); + + ac.setSwingV(0xFF); + EXPECT_EQ(kMirageAcSwingVAuto, ac.getSwingV()); + + ac.setSwingV(kMirageAcSwingVLowest); + EXPECT_EQ(kMirageAcSwingVLowest, ac.getSwingV()); + + ac.setSwingV(kMirageAcSwingVLowest - 1); + EXPECT_EQ(kMirageAcSwingVAuto, ac.getSwingV()); + + // Set the model to one with limited swingv support. + ac.setModel(mirage_ac_remote_model_t::KKG29AC1); + + ac.setSwingV(kMirageAcSwingVAuto); + EXPECT_EQ(kMirageAcSwingVAuto, ac.getSwingV()); + ac.setSwingV(kMirageAcSwingVOff); + EXPECT_EQ(kMirageAcSwingVOff, ac.getSwingV()); + ac.setSwingV(kMirageAcSwingVHigh); + EXPECT_EQ(kMirageAcSwingVAuto, ac.getSwingV()); + ac.setSwingV(0xFF); + EXPECT_EQ(kMirageAcSwingVAuto, ac.getSwingV()); + ac.setSwingV(kMirageAcSwingVOff); + EXPECT_EQ(kMirageAcSwingVOff, ac.getSwingV()); +} + +TEST(TestMirageAcClass, SwingH) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + ac.setModel(mirage_ac_remote_model_t::KKG9AC1); + ac.setSwingH(true); + EXPECT_FALSE(ac.getSwingH()); + ac.setSwingH(false); + EXPECT_FALSE(ac.getSwingH()); + ac.setSwingH(true); + EXPECT_FALSE(ac.getSwingH()); + + ac.setModel(mirage_ac_remote_model_t::KKG29AC1); + ac.setSwingH(true); + EXPECT_TRUE(ac.getSwingH()); + ac.setSwingH(false); + EXPECT_FALSE(ac.getSwingH()); + ac.setSwingH(true); + EXPECT_TRUE(ac.getSwingH()); +} + +TEST(TestMirageAcClass, Filter) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + ac.setModel(mirage_ac_remote_model_t::KKG9AC1); // No Support + ac.setFilter(true); + EXPECT_FALSE(ac.getFilter()); + ac.setFilter(false); + EXPECT_FALSE(ac.getFilter()); + ac.setFilter(true); + EXPECT_FALSE(ac.getFilter()); + + ac.setModel(mirage_ac_remote_model_t::KKG29AC1); // Supported + ac.setFilter(true); + EXPECT_TRUE(ac.getFilter()); + ac.setFilter(false); + EXPECT_FALSE(ac.getFilter()); + ac.setFilter(true); + EXPECT_TRUE(ac.getFilter()); +} + +TEST(TestMirageAcClass, Quiet) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + ac.setModel(mirage_ac_remote_model_t::KKG9AC1); // No Support + ac.setQuiet(true); + EXPECT_FALSE(ac.getQuiet()); + ac.setQuiet(false); + EXPECT_FALSE(ac.getQuiet()); + ac.setQuiet(true); + EXPECT_FALSE(ac.getQuiet()); + + ac.setModel(mirage_ac_remote_model_t::KKG29AC1); // Supported + ac.setQuiet(true); + EXPECT_TRUE(ac.getQuiet()); + ac.setQuiet(false); + EXPECT_FALSE(ac.getQuiet()); + ac.setQuiet(true); + EXPECT_TRUE(ac.getQuiet()); +} + +TEST(TestMirageAcClass, CleanToggle) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + ac.setModel(mirage_ac_remote_model_t::KKG9AC1); + ac.setCleanToggle(true); + EXPECT_FALSE(ac.getCleanToggle()); + ac.setCleanToggle(false); + EXPECT_FALSE(ac.getCleanToggle()); + ac.setCleanToggle(true); + EXPECT_FALSE(ac.getCleanToggle()); + + ac.setModel(mirage_ac_remote_model_t::KKG29AC1); + ac.setCleanToggle(true); + EXPECT_TRUE(ac.getCleanToggle()); + ac.setCleanToggle(false); + EXPECT_FALSE(ac.getCleanToggle()); + ac.setCleanToggle(true); + EXPECT_TRUE(ac.getCleanToggle()); + ac.send(); // Should be reset when sent. + EXPECT_FALSE(ac.getCleanToggle()); +} + +TEST(TestMirageAcClass, Timers) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + ac.setModel(mirage_ac_remote_model_t::KKG9AC1); // No timer support + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_EQ(0, ac.getOffTimer()); + ac.setOnTimer(12 * 60 + 37); // 12:37 + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_EQ(0, ac.getOffTimer()); + ac.setOffTimer(17 * 60 + 5); // 17:05 + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_EQ(0, ac.getOffTimer()); + + ac.setModel(mirage_ac_remote_model_t::KKG29AC1); // Timer supported + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_EQ(0, ac.getOffTimer()); + + ac.setOnTimer(12 * 60 + 37); // 12:37 + EXPECT_EQ(12 * 60 + 37, ac.getOnTimer()); + EXPECT_EQ(0, ac.getOffTimer()); + + ac.setOffTimer(17 * 60 + 5); // 17:05 + EXPECT_EQ(17 * 60 + 5, ac.getOffTimer()); + EXPECT_EQ(12 * 60 + 37, ac.getOnTimer()); + ac.setOnTimer(0); // Off/Disabled + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_EQ(17 * 60 + 5, ac.getOffTimer()); + ac.setOffTimer(0); // Off/Disabled + EXPECT_EQ(0, ac.getOffTimer()); + EXPECT_EQ(0, ac.getOnTimer()); + + ac.setOnTimer(12 * 60 + 37); // 12:37 + ac.setOffTimer(17 * 60 + 5); // 17:05 + ac.setModel(mirage_ac_remote_model_t::KKG9AC1); // No timer support + EXPECT_EQ(0, ac.getOffTimer()); + EXPECT_EQ(0, ac.getOnTimer()); +} + +TEST(TestMirageAcClass, IFeelAndSensorTemp) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + + ac.setModel(mirage_ac_remote_model_t::KKG9AC1); // No support + EXPECT_FALSE(ac.getIFeel()); + EXPECT_EQ(0, ac.getSensorTemp()); + ac.setIFeel(true); + EXPECT_FALSE(ac.getIFeel()); + EXPECT_EQ(0, ac.getSensorTemp()); + ac.setSensorTemp(20); // 20C + EXPECT_FALSE(ac.getIFeel()); + EXPECT_EQ(0, ac.getSensorTemp()); + + ac.setModel(mirage_ac_remote_model_t::KKG29AC1); // Supported + EXPECT_FALSE(ac.getIFeel()); + EXPECT_EQ(0, ac.getSensorTemp()); + ac.setIFeel(true); + EXPECT_TRUE(ac.getIFeel()); + EXPECT_EQ(0, ac.getSensorTemp()); + ac.setSensorTemp(25); // 25C + EXPECT_TRUE(ac.getIFeel()); + EXPECT_EQ(25, ac.getSensorTemp()); + ac.setIFeel(false); + EXPECT_FALSE(ac.getIFeel()); +} + +TEST(TestMirageAcClass, getModel) { + IRMirageAc ac(kGpioUnused); + ac.begin(); + const uint8_t KKG9AC1[kMirageStateLength] = { + 0x56, 0x6C, 0x00, 0x00, 0x20, 0xD8, 0x00, 0x00, + 0x0C, 0x32, 0x0B, 0x00, 0x32, 0x0F, 0x64}; + EXPECT_EQ(mirage_ac_remote_model_t::KKG9AC1, IRMirageAc::getModel(KKG9AC1)); + + // https://github.com/crankyoldgit/IRremoteESP8266/issues/1573#issuecomment-955722044 + const uint8_t KKG29AC1[kMirageStateLength] = { + 0x56, 0x74, 0x00, 0x00, 0x12, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D}; + EXPECT_EQ(mirage_ac_remote_model_t::KKG29AC1, IRMirageAc::getModel(KKG29AC1)); + + // https://github.com/crankyoldgit/IRremoteESP8266/issues/1573#issuecomment-962362540 + const uint8_t KKG29AC1_2[kMirageStateLength] = { + 0x56, 0x72, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19}; + EXPECT_EQ(mirage_ac_remote_model_t::KKG29AC1, + IRMirageAc::getModel(KKG29AC1_2)); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Rhoss_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Rhoss_test.cpp new file mode 100644 index 000000000..855b9a48c --- /dev/null +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Rhoss_test.cpp @@ -0,0 +1,396 @@ +// Copyright 2021 Tom Rosenback + +#include "IRac.h" +#include "ir_Rhoss.h" +#include "IRrecv.h" +#include "IRrecv_test.h" +#include "IRsend.h" +#include "IRsend_test.h" +#include "IRutils.h" +#include "gtest/gtest.h" + +TEST(TestUtils, Housekeeping) { + ASSERT_EQ("RHOSS", typeToString(decode_type_t::RHOSS)); + ASSERT_EQ(decode_type_t::RHOSS, strToDecodeType("RHOSS")); + ASSERT_TRUE(hasACState(decode_type_t::RHOSS)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::RHOSS)); +} + +// Test sending typical data only. +TEST(TestSendRhoss, SendDataOnly) { + IRsendTest irsend(kGpioUnused); + irsend.begin(); + + uint8_t expectedState[kRhossStateLength] = { + 0xAA, 0x05, 0x60, 0x00, 0x50, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x33 }; + + irsend.reset(); + irsend.sendRhoss(expectedState); + + EXPECT_EQ( + "f38000d50" + "m3042s4248" + "m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457m648s1545" + "m648s1545m648s457m648s1545m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s1545m648s1545m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s1545m648s457m648s1545m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s1545" + "m648s457m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s1545m648s1545m648s457m648s457m648s1545m648s1545m648s457m648s457" + "m648s457m648" + "s100000", + irsend.outputStr()); +} + +// Test send typical data with repeats +TEST(TestSendRhoss, SendWithRepeats) { + IRsendTest irsend(kGpioUnused); + irsend.begin(); + + irsend.reset(); + +uint8_t expectedState[kRhossStateLength] = { + 0xAA, 0x05, 0x60, 0x00, 0x50, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x33 }; + + irsend.sendRhoss(expectedState, kRhossStateLength, 0); // 0 repeats. + EXPECT_EQ( + "f38000d50" + "m3042s4248" + "m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457m648s1545" + "m648s1545m648s457m648s1545m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s1545m648s1545m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s1545m648s457m648s1545m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s1545" + "m648s457m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s1545m648s1545m648s457m648s457m648s1545m648s1545m648s457m648s457" + "m648s457m648" + "s100000", + irsend.outputStr()); + + irsend.sendRhoss(expectedState, kRhossStateLength, 2); // 2 repeats. + EXPECT_EQ( + "f38000d50" + "m3042s4248" + "m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457m648s1545" + "m648s1545m648s457m648s1545m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s1545m648s1545m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s1545m648s457m648s1545m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s1545" + "m648s457m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s1545m648s1545m648s457m648s457m648s1545m648s1545m648s457m648s457" + "m648s457m648" + "s100000" + "m3042s4248" + "m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457m648s1545" + "m648s1545m648s457m648s1545m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s1545m648s1545m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s1545m648s457m648s1545m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s1545" + "m648s457m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s1545m648s1545m648s457m648s457m648s1545m648s1545m648s457m648s457" + "m648s457m648" + "s100000" + "m3042s4248" + "m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457m648s1545" + "m648s1545m648s457m648s1545m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s1545m648s1545m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s1545m648s457m648s1545m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s1545" + "m648s457m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457" + "m648s1545m648s1545m648s457m648s457m648s1545m648s1545m648s457m648s457" + "m648s457m648" + "s100000", + irsend.outputStr()); +} + +// Test send raw data +TEST(TestSendRhoss, RawData) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + irsend.reset(); + + // Power on, mode cool, temp 20, fan auto, swing off + const uint16_t rawData[197] = { + 3044, 4248, + 648, 458, 650, 1540, 646, 458, 650, 1538, + 650, 458, 650, 1538, 650, 458, 650, 1540, // byte 0 + 648, 458, 650, 458, 650, 1540, 646, 484, + 624, 456, 650, 456, 650, 456, 650, 456, // byte 1 + 650, 456, 650, 456, 650, 456, 650, 456, + 650, 458, 650, 1540, 650, 1538, 650, 456, // byte 2 + 650, 456, 650, 456, 650, 456, 650, 458, + 650, 456, 650, 456, 650, 456, 650, 458, // byte 3 + 650, 458, 650, 456, 650, 458, 650, 458, + 650, 458, 650, 1538, 650, 458, 650, 458, // byte 4 + 650, 458, 648, 458, 674, 434, 648, 458, + 672, 434, 648, 458, 650, 458, 648, 1540, // byte 5 + 672, 434, 650, 458, 672, 1518, 644, 488, + 622, 1540, 644, 464, 672, 1516, 672, 434, // byte 6 + 672, 434, 672, 434, 650, 458, 648, 458, + 672, 434, 674, 434, 672, 434, 650, 458, // byte 7 + 672, 434, 648, 458, 650, 458, 672, 434, + 672, 436, 648, 458, 648, 456, 650, 458, // byte 8 + 650, 458, 650, 456, 674, 434, 650, 458, + 650, 456, 650, 458, 674, 432, 650, 458, // byte 9 + 650, 456, 650, 456, 650, 458, 648, 458, + 674, 432, 650, 456, 674, 434, 650, 458, // byte 10 + 650, 458, 650, 1538, 650, 458, 650, 458, + 650, 456, 650, 458, 650, 456, 650, 458, // byte 11 + 650, 456, + 650 }; // UNKNOWN 93E7BDB2 + + irsend.sendRaw(rawData, 197, 38); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(RHOSS, irsend.capture.decode_type); + EXPECT_EQ(kRhossBits, irsend.capture.bits); + + uint8_t expected[kRhossStateLength] = { + 0xAA, 0x04, 0x60, 0x00, 0x20, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x02 }; + EXPECT_STATE_EQ(expected, irsend.capture.state, kRhossBits); + + EXPECT_EQ( + "Power: On, Mode: 2 (Cool), Temp: 20C, Fan: 0 (Auto), Swing(V): Off", + IRAcUtils::resultAcToString(&irsend.capture)); + + stdAc::state_t r, p; + ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); +} + +// Test synthetic decode +TEST(TestDecodeRhoss, SyntheticSelfDecode) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(0); + IRRhossAc ac(0); + + uint8_t expectedState[kRhossStateLength] = { + 0xAA, 0x05, 0x60, 0x00, 0x50, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x33 }; + + irsend.begin(); + irsend.reset(); + irsend.sendRhoss(expectedState); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(RHOSS, irsend.capture.decode_type); + EXPECT_EQ(kRhossBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + ac.setRaw(irsend.capture.state); + EXPECT_EQ( + "Power: On, Mode: 5 (Auto), Temp: 21C, Fan: 0 (Auto), Swing(V): Off", + ac.toString()); +} + +// Test strict decoding +TEST(TestDecodeRhoss, StrictDecode) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(0); + IRRhossAc ac(0); + + uint8_t expectedState[kRhossStateLength] = { + 0xAA, 0x05, 0x60, 0x00, 0x50, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x33 }; + + irsend.begin(); + irsend.reset(); + irsend.sendRhoss(expectedState); + irsend.makeDecodeResult(); + ASSERT_TRUE( + irrecv.decodeRhoss(&irsend.capture, + kStartOffset, kRhossBits, true)); + EXPECT_EQ(RHOSS, irsend.capture.decode_type); + EXPECT_EQ(kRhossBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + ac.setRaw(irsend.capture.state); + EXPECT_EQ( + "Power: On, Mode: 5 (Auto), Temp: 21C, Fan: 0 (Auto), Swing(V): Off", + ac.toString()); +} + +// Tests for IRRhossAc class. + +TEST(TestRhossAcClass, Power) { + IRRhossAc ac(0); + ac.begin(); + + ac.on(); + EXPECT_TRUE(ac.getPower()); + + ac.off(); + EXPECT_FALSE(ac.getPower()); + + ac.setPower(true); + EXPECT_TRUE(ac.getPower()); + + ac.setPower(false); + EXPECT_FALSE(ac.getPower()); +} + +TEST(TestRhossAcClass, Temperature) { + IRRhossAc ac(0); + ac.begin(); + + ac.setTemp(0); + EXPECT_EQ(kRhossTempMin, ac.getTemp()); + + ac.setTemp(255); + EXPECT_EQ(kRhossTempMax, ac.getTemp()); + + ac.setTemp(kRhossTempMin); + EXPECT_EQ(kRhossTempMin, ac.getTemp()); + + ac.setTemp(kRhossTempMax); + EXPECT_EQ(kRhossTempMax, ac.getTemp()); + + ac.setTemp(kRhossTempMin - 1); + EXPECT_EQ(kRhossTempMin, ac.getTemp()); + + ac.setTemp(kRhossTempMax + 1); + EXPECT_EQ(kRhossTempMax, ac.getTemp()); + + ac.setTemp(17); + EXPECT_EQ(17, ac.getTemp()); + + ac.setTemp(21); + EXPECT_EQ(21, ac.getTemp()); + + ac.setTemp(25); + EXPECT_EQ(25, ac.getTemp()); + + ac.setTemp(29); + EXPECT_EQ(29, ac.getTemp()); +} + + +TEST(TestRhossAcClass, OperatingMode) { + IRRhossAc ac(0); + ac.begin(); + + ac.setMode(kRhossModeAuto); + EXPECT_EQ(kRhossModeAuto, ac.getMode()); + + ac.setMode(kRhossModeCool); + EXPECT_EQ(kRhossModeCool, ac.getMode()); + + ac.setMode(kRhossModeHeat); + EXPECT_EQ(kRhossModeHeat, ac.getMode()); + + ac.setMode(kRhossModeDry); + EXPECT_EQ(kRhossModeDry, ac.getMode()); + + ac.setMode(kRhossModeFan); + EXPECT_EQ(kRhossModeFan, ac.getMode()); + + ac.setMode(kRhossModeAuto + 1); + EXPECT_EQ(kRhossDefaultMode, ac.getMode()); + + ac.setMode(255); + EXPECT_EQ(kRhossDefaultMode, ac.getMode()); +} + +TEST(TestRhossAcClass, FanSpeed) { + IRRhossAc ac(0); + ac.begin(); + + ac.setFan(0); + EXPECT_EQ(kRhossFanAuto, ac.getFan()); + + ac.setFan(255); + EXPECT_EQ(kRhossFanAuto, ac.getFan()); + + ac.setFan(kRhossFanMax); + EXPECT_EQ(kRhossFanMax, ac.getFan()); + + ac.setFan(kRhossFanMax + 1); + EXPECT_EQ(kRhossFanAuto, ac.getFan()); + + ac.setFan(kRhossFanMax - 1); + EXPECT_EQ(kRhossFanMax - 1, ac.getFan()); + + ac.setFan(1); + EXPECT_EQ(1, ac.getFan()); + + ac.setFan(1); + EXPECT_EQ(1, ac.getFan()); + + ac.setFan(3); + EXPECT_EQ(3, ac.getFan()); +} + +TEST(TestRhossAcClass, Swing) { + IRRhossAc ac(0); + ac.begin(); + + ac.setSwing(false); + EXPECT_FALSE(ac.getSwing()); + + ac.setSwing(true); + EXPECT_TRUE(ac.getSwing()); +} + +TEST(TestRhossAcClass, Checksums) { + uint8_t state[kRhossStateLength] = { + 0xAA, 0x05, 0x60, 0x00, 0x50, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x33 }; + + ASSERT_EQ(0x33, IRRhossAc::calcChecksum(state)); + EXPECT_TRUE(IRRhossAc::validChecksum(state)); + // Change the array so the checksum is invalid. + state[0] ^= 0xFF; + EXPECT_FALSE(IRRhossAc::validChecksum(state)); + // Restore the previous change, and change another byte. + state[0] ^= 0xFF; + state[4] ^= 0xFF; + EXPECT_FALSE(IRRhossAc::validChecksum(state)); + state[4] ^= 0xFF; + EXPECT_TRUE(IRRhossAc::validChecksum(state)); + + // Additional known good states. + uint8_t knownGood1[kRhossStateLength] = { + 0xAA, 0x06, 0x60, 0x00, 0x50, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x34 }; + EXPECT_TRUE(IRRhossAc::validChecksum(knownGood1)); + ASSERT_EQ(0x34, IRRhossAc::calcChecksum(knownGood1)); + + uint8_t knownGood2[kRhossStateLength] = { + 0xAA, 0x07, 0x60, 0x00, 0x50, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x35 }; + EXPECT_TRUE(IRRhossAc::validChecksum(knownGood2)); + ASSERT_EQ(0x35, IRRhossAc::calcChecksum(knownGood2)); + + uint8_t knownGood3[kRhossStateLength] = { + 0xAA, 0x07, 0x60, 0x00, 0x53, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x38 }; + EXPECT_TRUE(IRRhossAc::validChecksum(knownGood3)); + ASSERT_EQ(0x38, IRRhossAc::calcChecksum(knownGood3)); + + // Validate calculation of checksum, + // same as knownGood3 except for the checksum. + uint8_t knownBad[kRhossStateLength] = { + 0xAA, 0x07, 0x60, 0x00, 0x53, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00 }; + EXPECT_FALSE(IRRhossAc::validChecksum(knownBad)); + IRRhossAc ac(0); + ac.setRaw(knownBad); + EXPECT_STATE_EQ(knownGood3, ac.getRaw(), kRhossBits); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Samsung_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Samsung_test.cpp index a4e0503cd..061067421 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Samsung_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Samsung_test.cpp @@ -426,16 +426,37 @@ TEST(TestIRSamsungAcClass, SetAndGetPower) { TEST(TestIRSamsungAcClass, SetAndGetSwing) { IRSamsungAc ac(kGpioUnused); + + // Vertical ac.setSwing(true); EXPECT_TRUE(ac.getSwing()); + EXPECT_FALSE(ac.getSwingH()); ac.setSwing(false); EXPECT_FALSE(ac.getSwing()); + EXPECT_FALSE(ac.getSwingH()); ac.setSwing(true); EXPECT_TRUE(ac.getSwing()); + EXPECT_FALSE(ac.getSwingH()); + // Horizontal + ac.setSwingH(true); + EXPECT_TRUE(ac.getSwing()); + EXPECT_TRUE(ac.getSwingH()); + ac.setSwingH(false); + EXPECT_TRUE(ac.getSwing()); + EXPECT_FALSE(ac.getSwingH()); + ac.setSwingH(true); + EXPECT_TRUE(ac.getSwing()); + EXPECT_TRUE(ac.getSwingH()); + + ac.setSwing(false); + EXPECT_FALSE(ac.getSwing()); + EXPECT_TRUE(ac.getSwingH()); + ac.setSwingH(false); + EXPECT_FALSE(ac.getSwing()); + EXPECT_FALSE(ac.getSwingH()); // Real examples from: // https://github.com/crankyoldgit/IRremoteESP8266/issues/505#issuecomment-424036602 - // TODO(Hollako): Explain why state[9] lowest bit changes between on and off. const uint8_t expected_off[kSamsungAcStateLength] = { 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, 0x01, 0xE2, 0xFE, 0x71, 0x80, 0x11, 0xF0}; @@ -576,14 +597,24 @@ TEST(TestIRSamsungAcClass, SetAndGetPowerful) { EXPECT_EQ(kSamsungAcFanTurbo, ac.getFan()); ac.setPowerful(false); EXPECT_FALSE(ac.getPowerful()); - EXPECT_EQ(kSamsungAcFanAuto, ac.getFan()); - // Breeze and Powerful/Turbo are mutually exclusive. + // Breeze, Econo, and Powerful/Turbo are mutually exclusive. ac.setPowerful(true); EXPECT_TRUE(ac.getPowerful()); + EXPECT_FALSE(ac.getBreeze()); + EXPECT_FALSE(ac.getEcono()); ac.setBreeze(true); EXPECT_TRUE(ac.getBreeze()); EXPECT_FALSE(ac.getPowerful()); + EXPECT_FALSE(ac.getEcono()); + ac.setEcono(true); + EXPECT_TRUE(ac.getEcono()); + EXPECT_FALSE(ac.getBreeze()); + EXPECT_FALSE(ac.getPowerful()); + ac.setPowerful(true); + EXPECT_TRUE(ac.getPowerful()); + EXPECT_FALSE(ac.getBreeze()); + EXPECT_FALSE(ac.getEcono()); // Actual powerful on & off states from: // https://github.com/crankyoldgit/IRremoteESP8266/issues/734#issuecomment-500120270 @@ -594,9 +625,10 @@ TEST(TestIRSamsungAcClass, SetAndGetPowerful) { EXPECT_TRUE(ac.getPowerful()); EXPECT_EQ(kSamsungAcFanTurbo, ac.getFan()); EXPECT_EQ( - "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 7 (Turbo), Swing: Off, " - "Beep: Off, Clean: Off, Quiet: Off, Powerful: On, Breeze: Off, " - "Light: On, Ion: Off", + "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 7 (Turbo), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: On, " + "Econo: Off, Breeze: Off, Light: On, Ion: Off", ac.toString()); uint8_t off[kSamsungAcStateLength] = { @@ -606,9 +638,10 @@ TEST(TestIRSamsungAcClass, SetAndGetPowerful) { EXPECT_FALSE(ac.getPowerful()); EXPECT_NE(kSamsungAcFanTurbo, ac.getFan()); EXPECT_EQ( - "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), Swing: Off, " - "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, " - "Light: On, Ion: Off", + "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: Off, Light: On, Ion: Off", ac.toString()); } @@ -633,6 +666,44 @@ TEST(TestIRSamsungAcClass, QuietAndPowerfulAreMutuallyExclusive) { EXPECT_NE(kSamsungAcFanTurbo, ac.getFan()); } +TEST(TestIRSamsungAcClass, SetAndGetEcono) { + IRSamsungAc ac(kGpioUnused); + ac.begin(); + EXPECT_FALSE(ac.getEcono()); + ac.setFan(kSamsungAcFanMed); + ac.setSwing(false); + ac.setEcono(true); + EXPECT_TRUE(ac.getEcono()); + EXPECT_FALSE(ac.getBreeze()); + EXPECT_FALSE(ac.getPowerful()); + EXPECT_TRUE(ac.getSwing()); // Econo turns on swingv. + EXPECT_EQ(kSamsungAcFanAuto, ac.getFan()); // And sets the fan to Auto. + ac.setEcono(false); + EXPECT_FALSE(ac.getEcono()); + EXPECT_FALSE(ac.getBreeze()); + EXPECT_FALSE(ac.getPowerful()); + + // Breeze, Econo, and Powerful/Turbo are mutually exclusive. + // But that is tested in `SetAndGetPowerful` + + // Actual econo on state from: + // https://cryptpad.fr/sheet/#/2/sheet/view/r9k8pmELYEjLyC71cD7EsThEYgKGLJygREZ5pVfNkS8/ + // Row: 33 + uint8_t on[kSamsungAcStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0xD2, 0xAE, 0x7F, 0x80, 0x11, 0xF0}; + ac.setRaw(on, kSamsungAcStateLength); + EXPECT_TRUE(ac.getEcono()); + EXPECT_TRUE(ac.getSwing()); + EXPECT_EQ(kSamsungAcFanAuto, ac.getFan()); + EXPECT_EQ( + "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), " + "Swing(V): On, Swing(H): Off, Beep: -, Clean: -, " + "Quiet: Off, Powerful: Off, Econo: On, Breeze: Off, " + "Light: On, Ion: Off", + ac.toString()); +} + TEST(TestIRSamsungAcClass, ChecksumCalculation) { IRSamsungAc ac(kGpioUnused); @@ -668,9 +739,10 @@ TEST(TestIRSamsungAcClass, ChecksumCalculation) { TEST(TestIRSamsungAcClass, HumanReadable) { IRSamsungAc ac(kGpioUnused); EXPECT_EQ( - "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 2 (Low), Swing: On, " - "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, " - "Light: On, Ion: Off", + "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 2 (Low), " + "Swing(V): On, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, Econo: Off, " + "Breeze: Off, Light: On, Ion: Off", ac.toString()); ac.setTemp(kSamsungAcMaxTemp); ac.setMode(kSamsungAcHeat); @@ -680,28 +752,32 @@ TEST(TestIRSamsungAcClass, HumanReadable) { ac.setBeep(true); ac.setClean(true); EXPECT_EQ( - "Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 5 (High), Swing: Off, " - "Beep: On, Clean: On, Quiet: Off, Powerful: Off, Breeze: Off, " - "Light: On, Ion: Off", + "Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 5 (High), " + "Swing(V): Off, Swing(H): Off, " + "Beep: Toggle, Clean: Toggle, Quiet: Off, Powerful: Off, Econo: Off, " + "Breeze: Off, Light: On, Ion: Off", ac.toString()); ac.setQuiet(true); EXPECT_EQ( - "Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 0 (Auto), Swing: Off, " - "Beep: On, Clean: On, Quiet: On, Powerful: Off, Breeze: Off, " + "Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 0 (Auto), " + "Swing(V): Off, Swing(H): Off, Beep: Toggle, " + "Clean: Toggle, Quiet: On, Powerful: Off, Econo: Off, Breeze: Off, " "Light: On, Ion: Off", ac.toString()); ac.setQuiet(false); ac.setPowerful(true); EXPECT_EQ( - "Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 7 (Turbo), Swing: Off, " - "Beep: On, Clean: On, Quiet: Off, Powerful: On, Breeze: Off, " + "Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 7 (Turbo), " + "Swing(V): Off, Swing(H): Off, Beep: Toggle, " + "Clean: Toggle, Quiet: Off, Powerful: On, Econo: Off, Breeze: Off, " "Light: On, Ion: Off", ac.toString()); ac.setIon(true); ac.setDisplay(false); EXPECT_EQ( - "Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 7 (Turbo), Swing: Off, " - "Beep: On, Clean: On, Quiet: Off, Powerful: On, Breeze: Off, " + "Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 7 (Turbo), " + "Swing(V): Off, Swing(H): Off, Beep: Toggle, " + "Clean: Toggle, Quiet: Off, Powerful: On, Econo: Off, Breeze: Off, " "Light: Off, Ion: On", ac.toString()); } @@ -802,9 +878,10 @@ TEST(TestDecodeSamsungAC, DecodeRealExample) { IRSamsungAc ac(kGpioUnused); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 2 (Low), Swing: On, " - "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, " - "Light: On, Ion: Off", + "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 2 (Low), " + "Swing(V): On, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: Off, Light: On, Ion: Off", ac.toString()); } @@ -852,9 +929,10 @@ TEST(TestDecodeSamsungAC, DecodeRealExample2) { IRSamsungAc ac(kGpioUnused); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), Swing: Off, " - "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, " - "Light: On, Ion: Off", + "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: Off, Light: On, Ion: Off", ac.toString()); } @@ -912,9 +990,10 @@ TEST(TestDecodeSamsungAC, DecodePowerOnSample) { IRSamsungAc ac(kGpioUnused); ac.setRaw(irsend.capture.state, kSamsungAcExtendedStateLength); EXPECT_EQ( - "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), Swing: Off, " - "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, " - "Light: On, Ion: Off", + "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: Off, Light: On, Ion: Off", ac.toString()); } @@ -973,9 +1052,10 @@ TEST(TestDecodeSamsungAC, DecodePowerOffSample) { IRSamsungAc ac(kGpioUnused); ac.setRaw(irsend.capture.state, kSamsungAcExtendedStateLength); EXPECT_EQ( - "Power: Off, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), Swing: Off, " - "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, " - "Light: On, Ion: Off", + "Power: Off, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: Off, Light: On, Ion: Off", ac.toString()); } @@ -1021,9 +1101,10 @@ TEST(TestDecodeSamsungAC, DecodeHeatSample) { IRSamsungAc ac(kGpioUnused); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 4 (Heat), Temp: 17C, Fan: 0 (Auto), Swing: On, " - "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, " - "Light: On, Ion: Off", + "Power: On, Mode: 4 (Heat), Temp: 17C, Fan: 0 (Auto), " + "Swing(V): On, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: Off, Light: On, Ion: Off", ac.toString()); } @@ -1066,9 +1147,10 @@ TEST(TestDecodeSamsungAC, DecodeCoolSample) { EXPECT_EQ(kSamsungAcBits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 0 (Auto), Swing: Off, " - "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, " - "Light: On, Ion: Off", + "Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 0 (Auto), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: Off, Light: On, Ion: Off", IRAcUtils::resultAcToString(&irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); @@ -1127,9 +1209,10 @@ TEST(TestDecodeSamsungAC, Issue604DecodeExtended) { IRSamsungAc ac(kGpioUnused); ac.setRaw(irsend.capture.state, irsend.capture.bits / 8); EXPECT_EQ( - "Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 0 (Auto), Swing: Off, " - "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, " - "Light: On, Ion: Off", + "Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 0 (Auto), " + "Swing(V): On, Swing(H): On, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: Off, Light: On, Ion: Off", ac.toString()); } @@ -1311,8 +1394,10 @@ TEST(TestIRSamsungAcClass, Issue604SendPowerHack) { "m586s436m586s436m586s436m586s436m586s436m586s436m586s436m586s436" "m586s2886"; std::string text = "Power: On, Mode: 1 (Cool), Temp: 23C, Fan: 4 (Med), " - "Swing: On, Beep: Off, Clean: Off, Quiet: Off, " - "Powerful: Off, Breeze: Off, Light: On, Ion: Off"; + "Swing(V): On, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, " + "Powerful: Off, Econo: Off, Breeze: Off, " + "Light: On, Ion: Off"; // Don't do a setPower()/on()/off() as that will trigger the special message. // So it should only be the normal "settings" message. ac.setTemp(23); @@ -1445,9 +1530,10 @@ TEST(TestDecodeSamsungAC, Issue734QuietSetting) { IRSamsungAc ac(0); ac.setRaw(irsend.capture.state, irsend.capture.bits / 8); EXPECT_EQ( - "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), Swing: Off, " - "Beep: Off, Clean: Off, Quiet: On, Powerful: Off, Breeze: Off, " - "Light: On, Ion: Off", + "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: On, Powerful: Off, " + "Econo: Off, Breeze: Off, Light: On, Ion: Off", ac.toString()); // Make sure the ac class state is in something wildly different first. @@ -1468,9 +1554,10 @@ TEST(TestDecodeSamsungAC, Issue734QuietSetting) { ac.setClean(false); ac.setQuiet(true); EXPECT_EQ( - "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), Swing: Off, " - "Beep: Off, Clean: Off, Quiet: On, Powerful: Off, Breeze: Off, " - "Light: On, Ion: Off", + "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: On, Powerful: Off, " + "Econo: Off, Breeze: Off, Light: On, Ion: Off", ac.toString()); // Check it matches the known good/expected state. EXPECT_STATE_EQ(expectedState, ac.getRaw(), kSamsungAcBits); @@ -1519,9 +1606,10 @@ TEST(TestDecodeSamsungAC, Issue734PowerfulOff) { IRSamsungAc ac(0); ac.setRaw(irsend.capture.state, irsend.capture.bits / 8); EXPECT_EQ( - "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), Swing: Off, " - "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, " - "Light: On, Ion: Off", + "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: Off, Light: On, Ion: Off", ac.toString()); } @@ -1553,9 +1641,10 @@ TEST(TestIRSamsungAcClass, SetAndGetBreeze) { ac.setRaw(on); ASSERT_TRUE(ac.getBreeze()); EXPECT_EQ( - "Power: On, Mode: 3 (Fan), Temp: 24C, Fan: 0 (Auto), Swing: Off, " - "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: On, " - "Light: On, Ion: Off", + "Power: On, Mode: 3 (Fan), Temp: 24C, Fan: 0 (Auto), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: On, Light: On, Ion: Off", ac.toString()); // MODE FAN, 24C WINDFREE OFF, FAN = LOW const uint8_t off[14] = { @@ -1564,9 +1653,10 @@ TEST(TestIRSamsungAcClass, SetAndGetBreeze) { ac.setRaw(off); ASSERT_FALSE(ac.getBreeze()); EXPECT_EQ( - "Power: On, Mode: 3 (Fan), Temp: 24C, Fan: 2 (Low), Swing: Off, " - "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, " - "Light: On, Ion: Off", + "Power: On, Mode: 3 (Fan), Temp: 24C, Fan: 2 (Low), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: Off, Light: On, Ion: Off", ac.toString()); } @@ -1614,9 +1704,10 @@ TEST(TestDecodeSamsungAC, Issue1227VeryPoorSignal) { EXPECT_EQ(kSamsungAcBits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "Power: On, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto), Swing: Off, " - "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, " - "Light: Off, Ion: Off", + "Power: On, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: Off, Light: Off, Ion: Off", IRAcUtils::resultAcToString(&irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); @@ -1671,3 +1762,362 @@ TEST(TestIRSamsungAcClass, SectionChecksums) { EXPECT_EQ(IRSamsungAc::getSectionChecksum(extended_off + 14), IRSamsungAc::calcSectionChecksum(extended_off + 14)); } + +TEST(TestIRSamsungAcClass, Issue1648) { + IRSamsungAc ac(kGpioUnused); + IRrecv irrecv(kGpioUnused); + const uint8_t onState[kSamsungAcExtendedStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xC2, 0xFE, 0x71, 0x90, 0x15, 0xF0}; + const String onText = "Power: On, Mode: 1 (Cool), Temp: 25C, Fan: 2 (Low), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, " + "Powerful: Off, Econo: Off, Breeze: Off, " + "Light: On, Ion: Off"; + const uint8_t extended_offState[kSamsungAcExtendedStateLength] = { + 0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0, + 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xE2, 0xFE, 0x71, 0x90, 0x15, 0xC0}; + const uint8_t short_offState[kSamsungAcStateLength] = { + 0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0, + 0x01, 0xE2, 0xFE, 0x71, 0x90, 0x15, 0xC0}; + const String offText = "Power: Off, Mode: 1 (Cool), Temp: 25C, Fan: 2 (Low), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, " + "Powerful: Off, Econo: Off, Breeze: Off, " + "Light: On, Ion: Off"; + const uint8_t coolState[kSamsungAcStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, + 0x01, 0xC2, 0xFE, 0x71, 0x90, 0x15, 0xF0}; + + // "setup()"" from provided code. + ac.begin(); // User code + ac.off(); // User code + ac.setFan(kSamsungAcFanLow); // User code + ac.setMode(kSamsungAcCool); // User code + ac.setTemp(25); // User code + ac.setSwing(false); // User code + + // Go through "loop()" from provided code. + for (uint8_t i = 0; i < 2; i++) { + ac.on(); // User code + ac.send(); // User code + + // Verify what was sent. + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&ac._irsend.capture)); + EXPECT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type); + EXPECT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits); + EXPECT_STATE_EQ(onState, ac._irsend.capture.state, ac._irsend.capture.bits); + EXPECT_EQ(onText, IRAcUtils::resultAcToString(&ac._irsend.capture)); + EXPECT_TRUE(ac._lastsentpowerstate); + ac._irsend.reset(); + + ac.setMode(kSamsungAcCool); // User code + ac.send(); // User code + + // Verify what was sent. + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&ac._irsend.capture)); + EXPECT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type); + EXPECT_EQ(kSamsungAcBits, ac._irsend.capture.bits); + EXPECT_STATE_EQ(coolState, ac._irsend.capture.state, + ac._irsend.capture.bits); + EXPECT_EQ(onText, IRAcUtils::resultAcToString(&ac._irsend.capture)); + ac._irsend.reset(); + EXPECT_TRUE(ac._lastsentpowerstate); + EXPECT_FALSE(ac._forceextended); + + ac.off(); // User code + ac.send(); // User code + + // Verify what was sent. + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&ac._irsend.capture)); + EXPECT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type); + EXPECT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits); + EXPECT_STATE_EQ(extended_offState, ac._irsend.capture.state, + ac._irsend.capture.bits); + EXPECT_EQ(offText, IRAcUtils::resultAcToString(&ac._irsend.capture)); + EXPECT_FALSE(ac._lastsentpowerstate); + ac._irsend.reset(); + + ac.off(); // User code + ac.send(); // User code + + // Verify what was sent. + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&ac._irsend.capture)); + EXPECT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type); + EXPECT_EQ(kSamsungAcBits, ac._irsend.capture.bits); + EXPECT_STATE_EQ(short_offState, ac._irsend.capture.state, + ac._irsend.capture.bits); + EXPECT_EQ(offText, IRAcUtils::resultAcToString(&ac._irsend.capture)); + EXPECT_FALSE(ac._lastsentpowerstate); + ac._irsend.reset(); + // End of "loop()" code. + } + + // Data from https://github.com/crankyoldgit/IRremoteESP8266/issues/1648#issuecomment-950822399 + const uint8_t expectedState[kSamsungAcExtendedStateLength] = { + 0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0, + 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x12, 0xAF, 0x71, 0x80, 0x15, 0xC0}; + const String expectedText = "Power: Off, Mode: 1 (Cool), Temp: 24C, " + "Fan: 2 (Low), Swing(V): On, Swing(H): Off, " + "Beep: -, Clean: -, " + "Quiet: Off, Powerful: Off, Econo: Off, " + "Breeze: Off, Light: On, Ion: Off"; + + ac.stateReset(); + ac.setRaw(expectedState, kSamsungAcExtendedStateLength); + EXPECT_EQ(expectedText, ac.toString()); + + // Try to generate the same message. + ac.stateReset(); + ac.off(); + ac.setMode(kSamsungAcCool); + ac.setTemp(24); + ac.setFan(kSamsungAcFanLow); + ac.setSwing(true); + ac.setBeep(false); + ac.setClean(false); + ac.setQuiet(false); + ac.setPowerful(false); + ac.setBreeze(false); + ac.setDisplay(true); + ac.setIon(false); + EXPECT_EQ(expectedText, ac.toString()); + + ac.send(); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&ac._irsend.capture)); + EXPECT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type); + EXPECT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, ac._irsend.capture.state, + ac._irsend.capture.bits); + EXPECT_EQ(expectedText, IRAcUtils::resultAcToString(&ac._irsend.capture)); + ac._irsend.reset(); +} + +TEST(TestIRSamsungAcClass, Timers) { + IRSamsungAc ac(kGpioUnused); + ac.begin(); + + // https://github.com/crankyoldgit/IRremoteESP8266/issues/1277#issuecomment-961836703 + const uint8_t on_timer_30m[kSamsungAcExtendedStateLength] = { + 0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0, + 0x01, 0xA2, 0x0F, 0x30, 0x00, 0x02, 0x00, + 0x01, 0x02, 0xFF, 0x71, 0x40, 0x11, 0xC0}; + const uint8_t off_timer_1h_on_timer_10m[kSamsungAcExtendedStateLength] = { + 0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0, + 0x01, 0x92, 0x8F, 0x10, 0x00, 0x06, 0x00, + 0x01, 0x02, 0xFF, 0x71, 0x40, 0x11, 0xC0}; + const uint8_t off_timer_1h_on_timer_0m[kSamsungAcExtendedStateLength] = { + 0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0, + 0x01, 0xA2, 0x8F, 0x00, 0x00, 0x06, 0x00, + 0x01, 0x02, 0xFF, 0x71, 0x40, 0x11, 0xC0}; + + ac.setRaw(on_timer_30m, kSamsungAcExtendedStateLength); + EXPECT_EQ( + "Power: Off, Mode: 1 (Cool), Temp: 20C, Fan: 0 (Auto), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: Off, Light: On, Ion: Off, On Timer: 00:30", + ac.toString()); + ac.setRaw(off_timer_1h_on_timer_10m, kSamsungAcExtendedStateLength); + EXPECT_EQ( + "Power: Off, Mode: 1 (Cool), Temp: 20C, Fan: 0 (Auto), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: Off, " + "Light: On, Ion: Off, On Timer: 00:10, Off Timer: 01:00", + ac.toString()); + ac.setRaw(off_timer_1h_on_timer_0m, kSamsungAcExtendedStateLength); + EXPECT_EQ( + "Power: Off, Mode: 1 (Cool), Temp: 20C, Fan: 0 (Auto), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: Off, " + "Light: On, Ion: Off, On Timer: 00:00, Off Timer: 01:00", + ac.toString()); + + // https://cryptpad.fr/sheet/#/2/sheet/view/r9k8pmELYEjLyC71cD7EsThEYgKGLJygREZ5pVfNkS8/ + // Row 155 + const uint8_t off_timer_11h_on_timer_6h[kSamsungAcExtendedStateLength] = { + 0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0, + 0x01, 0x62, 0x8F, 0x05, 0x03, 0x06, 0x00, + 0x01, 0x02, 0xFF, 0x71, 0x40, 0x11, 0xC0}; + ac.setRaw(off_timer_11h_on_timer_6h, kSamsungAcExtendedStateLength); + EXPECT_EQ( + "Power: Off, Mode: 1 (Cool), Temp: 20C, Fan: 0 (Auto), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: Off, " + "Light: On, Ion: Off, On Timer: 06:00, Off Timer: 11:00", + ac.toString()); + + ac.stateReset(false); + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_EQ(0, ac.getOffTimer()); + + ac.setOnTimer(0); + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_EQ(0, ac.getOffTimer()); + + ac.setOffTimer(0); + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_EQ(0, ac.getOffTimer()); + + // On Timer only + ac.setOnTimer(30); + EXPECT_EQ(30, ac.getOnTimer()); + EXPECT_EQ(0, ac.getOffTimer()); + + ac.setOnTimer(90); // 1h30m + EXPECT_EQ(90, ac.getOnTimer()); + EXPECT_EQ(0, ac.getOffTimer()); + + ac.setOnTimer(85); // 1h25m -> 1h20m + EXPECT_EQ(80, ac.getOnTimer()); + EXPECT_EQ(0, ac.getOffTimer()); + + ac.setOnTimer(23 * 60 + 59); // 23:59 + EXPECT_EQ(23 * 60 + 50, ac.getOnTimer()); // 23:50 + EXPECT_EQ(0, ac.getOffTimer()); + + ac.setOnTimer(24 * 60 + 30); // 24:30 + EXPECT_EQ(24 * 60, ac.getOnTimer()); // 24:00 (Max) + EXPECT_EQ(0, ac.getOffTimer()); + + // Off Timer only + ac.setOnTimer(0); + ac.setOffTimer(0); + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_EQ(0, ac.getOffTimer()); + + ac.setOffTimer(30); + EXPECT_EQ(30, ac.getOffTimer()); + EXPECT_EQ(0, ac.getOnTimer()); + + ac.setOffTimer(90); // 1h30m + EXPECT_EQ(90, ac.getOffTimer()); + EXPECT_EQ(0, ac.getOnTimer()); + + ac.setOffTimer(85); // 1h25m -> 1h20m + EXPECT_EQ(80, ac.getOffTimer()); + EXPECT_EQ(0, ac.getOnTimer()); + + ac.setOffTimer(23 * 60 + 59); // 23:59 + EXPECT_EQ(23 * 60 + 50, ac.getOffTimer()); // 23:50 + EXPECT_EQ(0, ac.getOnTimer()); + + ac.setOffTimer(24 * 60 + 30); // 24:30 + EXPECT_EQ(24 * 60, ac.getOffTimer()); // 24:00 (Max) + EXPECT_EQ(0, ac.getOnTimer()); + + // Both Timers + ac.setOnTimer(24 * 60); // 24:00 + EXPECT_EQ(24 * 60, ac.getOnTimer()); // 24:00 (Max) + EXPECT_EQ(24 * 60, ac.getOffTimer()); // 24:00 (Max) + + ac.setOnTimer(1 * 60 + 30); // 1:30 + ac.setOffTimer(11 * 60); // 11:00 + EXPECT_EQ(1 * 60 + 30, ac.getOnTimer()); + EXPECT_EQ(11 * 60, ac.getOffTimer()); +} + +TEST(TestIRSamsungAcClass, Sleep) { + IRSamsungAc ac(kGpioUnused); + ac.begin(); + + // https://cryptpad.fr/sheet/#/2/sheet/view/r9k8pmELYEjLyC71cD7EsThEYgKGLJygREZ5pVfNkS8/ + const uint8_t sleep_8h[kSamsungAcExtendedStateLength] = { + 0x02, 0x82, 0x0F, 0x00, 0x00, 0x10, 0xF0, + 0x01, 0xA2, 0x0F, 0x04, 0x00, 0x0C, 0x00, + 0x01, 0xE2, 0xFE, 0x71, 0x40, 0x11, 0xF0}; + ac.setRaw(sleep_8h, kSamsungAcExtendedStateLength); + EXPECT_EQ(8 * 60, ac.getSleepTimer()); + EXPECT_EQ(0, ac.getOffTimer()); + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_EQ( + "Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 0 (Auto), " + "Swing(V): Off, Swing(H): Off, " + "Beep: -, Clean: -, Quiet: Off, Powerful: Off, " + "Econo: Off, Breeze: Off, " + "Light: On, Ion: Off, Sleep Timer: 08:00", + ac.toString()); + + ac.stateReset(false); + EXPECT_EQ(0, ac.getSleepTimer()); + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_EQ(0, ac.getOffTimer()); + + ac.setOnTimer(60); + ac.setOffTimer(90); + EXPECT_EQ(0, ac.getSleepTimer()); + EXPECT_EQ(60, ac.getOnTimer()); + EXPECT_EQ(90, ac.getOffTimer()); + + ac.setSleepTimer(120); + EXPECT_EQ(120, ac.getSleepTimer()); + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_EQ(0, ac.getOffTimer()); + + ac.setSleepTimer(24 * 60 + 31); // 24h31m + EXPECT_EQ(24 * 60, ac.getSleepTimer()); // 24h (Max) + + ac.setSleepTimer(35); // 45m + EXPECT_EQ(30, ac.getSleepTimer()); // 30m (Only stored in 10m increments). + + ac.setOnTimer(60); // Seting an On Timer should clear the sleep setting. + EXPECT_EQ(0, ac.getSleepTimer()); + EXPECT_EQ(60, ac.getOnTimer()); + + ac.setSleepTimer(120); + ac.setOffTimer(90); // Setting an Off Timer will clear the sleep setting. + EXPECT_EQ(0, ac.getSleepTimer()); + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_EQ(90, ac.getOffTimer()); +} + +TEST(TestIRSamsungAcClass, BuildKnownSleepSate) { + // For https://github.com/crankyoldgit/IRremoteESP8266/issues/1277#issuecomment-965047193 + IRSamsungAc ac(kGpioUnused); + IRrecv irrecv(kGpioUnused); + ac.begin(); + const uint8_t expectedState[kSamsungAcExtendedStateLength] = { + 0x02, 0x82, 0x0F, 0x00, 0x00, 0x10, 0xF0, + 0x01, 0xA2, 0x0F, 0x04, 0x00, 0x0C, 0x00, + 0x01, 0xD2, 0xFE, 0x71, 0x50, 0x41, 0xF0}; + const char expectedStr[] = "Power: On, Mode: 4 (Heat), Temp: 21C, " + "Fan: 0 (Auto), Swing(V): Off, Swing(H): Off, Beep: -, Clean: -, " + "Quiet: Off, Powerful: Off, Econo: Off, Breeze: Off, " + "Light: On, Ion: Off, Sleep Timer: 08:00"; + ac.setPower(true); + ac.setMode(kSamsungAcHeat); + ac.setTemp(21); + ac.setFan(kSamsungAcFanAuto); + ac.setSwing(false); + ac.setSwingH(false); + ac.setBeep(false); + ac.setClean(false); + ac.setQuiet(false); + ac.setPowerful(false); + ac.setEcono(false); + ac.setBreeze(false); + ac.setDisplay(true); + ac.setIon(false); + ac.setSleepTimer(8 * 60); + EXPECT_EQ(expectedStr, ac.toString()); + ac.send(); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&ac._irsend.capture)); + EXPECT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type); + EXPECT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, ac._irsend.capture.state, + ac._irsend.capture.bits); + EXPECT_EQ(expectedStr, IRAcUtils::resultAcToString(&ac._irsend.capture)); + ac._irsend.reset(); +} diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Sharp_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Sharp_test.cpp index bf08c644a..a2acafb9c 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Sharp_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Sharp_test.cpp @@ -410,8 +410,8 @@ TEST(TestDecodeSharpAc, RealExample) { EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( "Model: 1 (A907), " - "Power: On, Mode: 2 (Cool), Temp: 27C, Fan: 2 (Auto), Turbo: Off, " - "Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off", + "Power: On, Mode: 2 (Cool), Temp: 27C, Fan: 2 (Auto), " + "Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off", IRAcUtils::resultAcToString(&irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); @@ -561,7 +561,7 @@ TEST(TestSharpAcClass, OperatingMode) { // Check toString() says Fan rather than Auto. EXPECT_EQ( "Model: 2 (A705), Power: Off, Mode: 0 (Fan), Temp: 15C, Fan: 2 (Auto), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Light: -, Clean: Off", + "Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Light: -, Clean: Off", ac.toString()); } @@ -615,8 +615,8 @@ TEST(TestSharpAcClass, ReconstructKnownState) { EXPECT_STATE_EQ(on_auto_auto, ac.getRaw(), kSharpAcBits); EXPECT_EQ( "Model: 1 (A907), " - "Power: On, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), Turbo: Off, " - "Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off", + "Power: On, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), Swing(V): 0 (N/A), " + "Turbo: Off, Ion: Off, Econo: -, Clean: Off", ac.toString()); uint8_t cool_auto_28[kSharpAcStateLength] = { @@ -629,8 +629,8 @@ TEST(TestSharpAcClass, ReconstructKnownState) { ac.setTemp(28); EXPECT_EQ( "Model: 1 (A907), " - "Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 2 (Auto), Turbo: Off, " - "Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off", + "Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 2 (Auto), Swing(V): 0 (N/A), " + "Turbo: Off, Ion: Off, Econo: -, Clean: Off", ac.toString()); EXPECT_STATE_EQ(cool_auto_28, ac.getRaw(), kSharpAcBits); } @@ -647,8 +647,8 @@ TEST(TestSharpAcClass, KnownStates) { ac.setRaw(off_auto_auto); EXPECT_EQ( "Model: 1 (A907), " - "Power: Off, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), Turbo: Off, " - "Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off", + "Power: Off, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), " + "Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off", ac.toString()); uint8_t on_auto_auto[kSharpAcStateLength] = { 0xAA, 0x5A, 0xCF, 0x10, 0x00, 0x11, 0x20, 0x00, 0x08, 0x80, 0x00, 0xE0, @@ -657,8 +657,8 @@ TEST(TestSharpAcClass, KnownStates) { ac.setRaw(on_auto_auto); EXPECT_EQ( "Model: 1 (A907), " - "Power: On, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), Turbo: Off, " - "Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off", + "Power: On, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), Swing(V): 0 (N/A), " + "Turbo: Off, Ion: Off, Econo: -, Clean: Off", ac.toString()); uint8_t cool_auto_28[kSharpAcStateLength] = { 0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x22, 0x00, 0x08, 0x80, 0x04, 0xE0, @@ -667,8 +667,8 @@ TEST(TestSharpAcClass, KnownStates) { ac.setRaw(cool_auto_28); EXPECT_EQ( "Model: 1 (A907), " - "Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 2 (Auto), Turbo: Off, " - "Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off", + "Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 2 (Auto), Swing(V): 0 (N/A), " + "Turbo: Off, Ion: Off, Econo: -, Clean: Off", ac.toString()); uint8_t cool_fan1_28[kSharpAcStateLength] = { 0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x42, 0x00, 0x08, 0x80, 0x05, 0xE0, @@ -677,8 +677,8 @@ TEST(TestSharpAcClass, KnownStates) { ac.setRaw(cool_fan1_28); EXPECT_EQ( "Model: 1 (A907), " - "Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 4 (Low), Turbo: Off, " - "Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off", + "Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 4 (Low), Swing(V): 0 (N/A), " + "Turbo: Off, Ion: Off, Econo: -, Clean: Off", ac.toString()); uint8_t cool_fan2_28[kSharpAcStateLength] = { 0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x32, 0x00, 0x08, 0x80, 0x05, 0xE0, @@ -688,7 +688,7 @@ TEST(TestSharpAcClass, KnownStates) { EXPECT_EQ( "Model: 1 (A907), " "Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 3 (Medium), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off", + "Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off", ac.toString()); uint8_t cool_fan3_28[kSharpAcStateLength] = { 0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x52, 0x00, 0x08, 0x80, 0x05, 0xE0, @@ -698,7 +698,7 @@ TEST(TestSharpAcClass, KnownStates) { EXPECT_EQ( "Model: 1 (A907), " "Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 5 (UNKNOWN), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off", + "Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off", ac.toString()); uint8_t cool_fan4_28[kSharpAcStateLength] = { 0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x72, 0x00, 0x08, 0x80, 0x05, 0xE0, @@ -707,8 +707,8 @@ TEST(TestSharpAcClass, KnownStates) { ac.setRaw(cool_fan4_28); EXPECT_EQ( "Model: 1 (A907), " - "Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 7 (High), Turbo: Off, " - "Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off", + "Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 7 (High), Swing(V): 0 (N/A), " + "Turbo: Off, Ion: Off, Econo: -, Clean: Off", ac.toString()); uint8_t cool_fan4_28_ion_on[kSharpAcStateLength] = { 0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x61, 0x72, 0x08, 0x08, 0x80, 0x00, 0xE4, @@ -717,8 +717,8 @@ TEST(TestSharpAcClass, KnownStates) { ac.setRaw(cool_fan4_28_ion_on); EXPECT_EQ( "Model: 1 (A907), " - "Power: -, Mode: 2 (Cool), Temp: 28C, Fan: 7 (High), Turbo: Off, " - "Swing(V) Toggle: Off, Ion: On, Econo: -, Clean: Off", + "Power: -, Mode: 2 (Cool), Temp: 28C, Fan: 7 (High), Swing(V): 0 (N/A), " + "Turbo: Off, Ion: On, Econo: -, Clean: Off", ac.toString()); /* Unsupported / Not yet reverse engineered. uint8_t cool_fan4_28_eco1[kSharpAcStateLength] = { @@ -735,8 +735,8 @@ TEST(TestSharpAcClass, KnownStates) { ac.setRaw(dry_auto); EXPECT_EQ( "Model: 1 (A907), " - "Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto), Turbo: Off, " - "Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off", + "Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto), Swing(V): 0 (N/A), " + "Turbo: Off, Ion: Off, Econo: -, Clean: Off", ac.toString()); } @@ -747,6 +747,7 @@ TEST(TestSharpAcClass, toCommon) { ac.setMode(kSharpAcCool); ac.setTemp(20); ac.setFan(kSharpAcFanMax); + ac.setSwingV(kSharpAcSwingVOff); // Now test it. ASSERT_EQ(decode_type_t::SHARP_AC, ac.toCommon().protocol); ASSERT_TRUE(ac.toCommon().power); @@ -755,8 +756,8 @@ TEST(TestSharpAcClass, toCommon) { ASSERT_EQ(stdAc::opmode_t::kCool, ac.toCommon().mode); ASSERT_EQ(stdAc::fanspeed_t::kMax, ac.toCommon().fanspeed); ASSERT_EQ(sharp_ac_remote_model_t::A705, ac.toCommon().model); - // Unsupported. ASSERT_EQ(stdAc::swingv_t::kOff, ac.toCommon().swingv); + // Unsupported. ASSERT_EQ(stdAc::swingh_t::kOff, ac.toCommon().swingh); ASSERT_FALSE(ac.toCommon().turbo); ASSERT_FALSE(ac.toCommon().quiet); @@ -868,20 +869,20 @@ TEST(TestSharpAcClass, Turbo) { EXPECT_EQ(kSharpAcFanMax, ac.getFan()); EXPECT_EQ( "Model: 3 (A903), " - "Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), Turbo: On, " - "Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off", + "Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), " + "Swing(V): 0 (N/A), Turbo: On, Ion: On, Light: -, Clean: Off", ac.toString()); ac.setRaw(off_state); EXPECT_FALSE(ac.getTurbo()); EXPECT_EQ( "Model: 3 (A903), " - "Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), Turbo: Off, " - "Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off", + "Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), " + "Swing(V): 0 (N/A), Turbo: Off, Ion: On, Light: -, Clean: Off", ac.toString()); } -TEST(TestSharpAcClass, SwingToggle) { +TEST(TestSharpAcClass, Swings) { IRSharpAc ac(kGpioUnused); ac.begin(); @@ -906,6 +907,70 @@ TEST(TestSharpAcClass, SwingToggle) { ac.setRaw(off_state); EXPECT_FALSE(ac.getSwingToggle()); + + // Vertical + ac.setSwingV(kSharpAcSwingVToggle); + EXPECT_EQ(kSharpAcSwingVToggle, ac.getSwingV()); + EXPECT_TRUE(ac.getSwingToggle()); + + ac.setSwingV(kSharpAcSwingVHigh); + EXPECT_EQ(kSharpAcSwingVHigh, ac.getSwingV()); + EXPECT_FALSE(ac.getSwingToggle()); + + ac.setSwingV(0xFF); // Doesn't change if invalid position given. + EXPECT_EQ(kSharpAcSwingVHigh, ac.getSwingV()); + + ac.setSwingV(kSharpAcSwingVMid); + EXPECT_EQ(kSharpAcSwingVMid, ac.getSwingV()); + EXPECT_FALSE(ac.getSwingToggle()); + + ac.setSwingV(kSharpAcSwingVLow); + EXPECT_EQ(kSharpAcSwingVLow, ac.getSwingV()); + EXPECT_FALSE(ac.getSwingToggle()); + + ac.setSwingV(kSharpAcSwingVIgnore); + EXPECT_EQ(kSharpAcSwingVIgnore, ac.getSwingV()); + EXPECT_FALSE(ac.getSwingToggle()); + + // Lowest/Coanda only works in Heat mode. + ac.setMode(kSharpAcCool); + ac.setSwingV(kSharpAcSwingVLowest); + EXPECT_EQ(kSharpAcSwingVLow, ac.getSwingV()); + EXPECT_FALSE(ac.getSwingToggle()); + ac.setModel(sharp_ac_remote_model_t::A907); // Model A907 has heat mode. + ac.setMode(kSharpAcHeat); + EXPECT_EQ(kSharpAcHeat, ac.getMode()); + ac.setSwingV(kSharpAcSwingVLowest); + EXPECT_EQ(kSharpAcSwingVLowest, ac.getSwingV()); + + // Check we can force Coanda in Cool mode. + ac.setMode(kSharpAcCool); + ASSERT_EQ(kSharpAcSwingVCoanda, kSharpAcSwingVLowest); + ac.setSwingV(kSharpAcSwingVCoanda, true); + EXPECT_EQ(kSharpAcSwingVCoanda, ac.getSwingV()); + EXPECT_FALSE(ac.getSwingToggle()); + EXPECT_EQ(kSharpAcCool, ac.getMode()); + + // Real messages/states + // ref: https://github.com/crankyoldgit/IRremoteESP8266/discussions/1590#discussioncomment-1254748 + ac.stateReset(); + const uint8_t coanda_heat_on[13] = { + 0xAA, 0x5A, 0xCF, 0x10, 0xC8, 0x31, 0x21, + 0x0A, 0x0E, 0x80, 0x06, 0xF4, 0x81}; + ac.setRaw(coanda_heat_on); + EXPECT_EQ( + "Model: 3 (A903), Power: On, Mode: 1 (Heat), Temp: 23C, Fan: 2 (Auto), " + "Swing(V): 6 (Lowest), Turbo: Off, Ion: On, Light: -, Clean: Off", + ac.toString()); + + const uint8_t coanda_cool_on[13] = { + 0xAA, 0x5A, 0xCF, 0x10, 0xC7, 0x31, 0x22, + 0x0A, 0x0E, 0x80, 0x06, 0xF4, 0x41}; + ac.setRaw(coanda_cool_on); + EXPECT_EQ( + "Model: 3 (A903), Power: On, Mode: 2 (Cool), Temp: 22C, Fan: 2 (Auto), " + "Swing(V): 6 (Highest), Turbo: Off, Ion: On, Light: -, Clean: Off", + ac.toString()); } TEST(TestSharpAcClass, Ion) { @@ -1005,8 +1070,8 @@ TEST(TestSharpAcClass, Timers) { EXPECT_TRUE(ac.isPowerSpecial()); EXPECT_EQ( "Model: 3 (A903), " - "Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), Turbo: Off, " - "Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off, Off Timer: 08:30", + "Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), Swing(V): 0 (N/A), " + "Turbo: Off, Ion: On, Light: -, Clean: Off, Off Timer: 08:30", ac.toString()); // ref: https://docs.google.com/spreadsheets/d/1otzVFM5_tegrZ4ROCLgQ_jvJaWCDlZs1vC-YuR1FFXM/edit#gid=0&range=E80 @@ -1020,7 +1085,7 @@ TEST(TestSharpAcClass, Timers) { EXPECT_TRUE(ac.isPowerSpecial()); EXPECT_EQ( "Model: 3 (A903), Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off, " + "Swing(V): 0 (N/A), Turbo: Off, Ion: On, Light: -, Clean: Off, " "On Timer: 12:00", ac.toString()); } @@ -1058,13 +1123,13 @@ TEST(TestSharpAcClass, Clean) { EXPECT_TRUE(ac.getClean()); EXPECT_EQ( "Model: 3 (A903), Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Light: -, Clean: On", + "Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Light: -, Clean: On", ac.toString()); ac.setRaw(clean_off_state); EXPECT_FALSE(ac.getClean()); EXPECT_EQ( "Model: 3 (A903), Power: On, Mode: 2 (Cool), Temp: 25C, Fan: 7 (High), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Light: -, Clean: Off", + "Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Light: -, Clean: Off", ac.toString()); // Try constructing the clean on state. @@ -1084,13 +1149,13 @@ TEST(TestSharpAcClass, Clean) { ac.setPower(false); EXPECT_EQ( "Model: 1 (A907), Power: Off, Mode: 2 (Cool), Temp: 25C, Fan: 7 (High), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off", + "Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off", ac.toString()); // Clean ON ac.setClean(true); EXPECT_EQ( "Model: 1 (A907), Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: On", + "Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: On", ac.toString()); // Clean OFF (state is identical to `off_msg`). // i.e. It just clears the clean settings & turns off the device. @@ -1098,25 +1163,25 @@ TEST(TestSharpAcClass, Clean) { ac.setPower(false, true); EXPECT_EQ( "Model: 1 (A907), Power: Off, Mode: 2 (Cool), Temp: 25C, Fan: 7 (High), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off", + "Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off", ac.toString()); // Clean ON ac.setClean(true); EXPECT_EQ( "Model: 1 (A907), Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: On", + "Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: On", ac.toString()); // AC OFF ac.off(); EXPECT_EQ( "Model: 1 (A907), Power: Off, Mode: 2 (Cool), Temp: 25C, Fan: 7 (High), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off", + "Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off", ac.toString()); // AC ON (Mode Cool, Temp 25, Ion OFF, Fan 7) ac.on(); EXPECT_EQ( "Model: 1 (A907), Power: On, Mode: 2 (Cool), Temp: 25C, Fan: 7 (High), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off", + "Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off", ac.toString()); } @@ -1126,7 +1191,7 @@ TEST(TestSharpAcClass, Issue1309) { ac.stateReset(); EXPECT_EQ( "Model: 1 (A907), Power: Off, Mode: 0 (Auto), Temp: 15C, Fan: 0 (UNKNOWN), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off", + "Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off", ac.toString()); const uint8_t issue1309_on[13] = { @@ -1135,7 +1200,7 @@ TEST(TestSharpAcClass, Issue1309) { ac.setRaw(issue1309_on); EXPECT_EQ( "Model: 2 (A705), Power: On, Mode: 2 (Cool), Temp: 16C, Fan: 2 (Auto), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Light: -, Clean: Off", + "Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Light: -, Clean: Off", ac.toString()); EXPECT_STATE_EQ(issue1309_on, ac.getRaw(), kSharpAcBits); @@ -1147,7 +1212,7 @@ TEST(TestSharpAcClass, Issue1309) { ac.on(); EXPECT_EQ( "Model: 2 (A705), Power: On, Mode: 2 (Cool), Temp: 16C, Fan: 2 (Auto), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Light: -, Clean: Off", + "Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Light: -, Clean: Off", ac.toString()); } @@ -1200,13 +1265,13 @@ TEST(TestSharpAcClass, Issue1387Power) { EXPECT_STATE_EQ(real_off, ac.getRaw(), kSharpAcBits); EXPECT_EQ( "Model: 3 (A903), Power: Off, Mode: 2 (Cool), Temp: 27C, Fan: 3 (Low), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off", + "Swing(V): 0 (N/A), Turbo: Off, Ion: On, Light: -, Clean: Off", ac.toString()); // Create the same off state. ac.setPower(true, ac.getPower()); EXPECT_STATE_EQ(real_on, ac.getRaw(), kSharpAcBits); EXPECT_EQ( "Model: 3 (A903), Power: On, Mode: 2 (Cool), Temp: 27C, Fan: 3 (Low), " - "Turbo: Off, Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off", + "Swing(V): 0 (N/A), Turbo: Off, Ion: On, Light: -, Clean: Off", ac.toString()); } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Tcl_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Tcl_test.cpp index da3fefc8c..b7ab5301f 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Tcl_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Tcl_test.cpp @@ -10,8 +10,18 @@ // General housekeeping TEST(TestTcl112Ac, Housekeeping) { - ASSERT_EQ("TCL112AC", typeToString(TCL112AC)); - ASSERT_TRUE(hasACState(TCL112AC)); + ASSERT_EQ("TCL112AC", typeToString(decode_type_t::TCL112AC)); + ASSERT_EQ(decode_type_t::TCL112AC, strToDecodeType("TCL112AC")); + ASSERT_TRUE(hasACState(decode_type_t::TCL112AC)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::TCL112AC)); + ASSERT_EQ(kTcl112AcBits, IRsend::defaultBits(decode_type_t::TCL112AC)); + ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::TCL112AC)); + ASSERT_EQ(tcl_ac_remote_model_t::TAC09CHSD, IRac::strToModel("TAC09CHSD")); + ASSERT_EQ(irutils::modelToStr(decode_type_t::TCL112AC, + tcl_ac_remote_model_t::TAC09CHSD), "TAC09CHSD"); + ASSERT_EQ(tcl_ac_remote_model_t::GZ055BE1, IRac::strToModel("GZ055BE1")); + ASSERT_EQ(irutils::modelToStr(decode_type_t::TCL112AC, + tcl_ac_remote_model_t::GZ055BE1), "GZ055BE1"); } // Tests for decodeTcl112Ac(). @@ -63,9 +73,10 @@ TEST(TestDecodeTcl112Ac, DecodeRealExample) { EXPECT_EQ(kTcl112AcBits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "Type: 1, Power: On, Mode: 3 (Cool), Temp: 24C, Fan: 0 (Auto), " - "Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, " - "Light: On", + "Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 24C, " + "Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, " + "Econo: Off, Health: Off, Turbo: Off, Light: On, " + "On Timer: Off, Off Timer: Off", IRAcUtils::resultAcToString(&irsend.capture)); } @@ -106,27 +117,31 @@ TEST(TestTcl112AcClass, Temperature) { IRTcl112Ac ac(kGpioUnused); ac.setRaw(temp16C); EXPECT_EQ( - "Type: 1, Power: On, Mode: 3 (Cool), Temp: 16C, Fan: 0 (Auto), " - "Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, " - "Light: On", + "Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 16C, " + "Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, " + "Econo: Off, Health: Off, Turbo: Off, Light: On, " + "On Timer: Off, Off Timer: Off", ac.toString()); ac.setRaw(temp16point5C); EXPECT_EQ( - "Type: 1, Power: On, Mode: 3 (Cool), Temp: 16.5C, Fan: 0 (Auto), " - "Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, " - "Light: On", + "Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 16.5C, " + "Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, " + "Econo: Off, Health: Off, Turbo: Off, Light: On, " + "On Timer: Off, Off Timer: Off", ac.toString()); ac.setRaw(temp19point5C); EXPECT_EQ( - "Type: 1, Power: On, Mode: 3 (Cool), Temp: 19.5C, Fan: 0 (Auto), " - "Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, " - "Light: On", + "Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 19.5C, " + "Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, " + "Econo: Off, Health: Off, Turbo: Off, Light: On, " + "On Timer: Off, Off Timer: Off", ac.toString()); ac.setRaw(temp31C); EXPECT_EQ( - "Type: 1, Power: On, Mode: 3 (Cool), Temp: 31C, Fan: 0 (Auto), " - "Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, " - "Light: On", + "Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 31C, " + "Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, " + "Econo: Off, Health: Off, Turbo: Off, Light: On, " + "On Timer: Off, Off Timer: Off", ac.toString()); ac.setTemp(kTcl112AcTempMin); @@ -206,9 +221,10 @@ TEST(TestTcl112AcClass, OperatingMode) { 0x07, 0x00, 0x00, 0x00, 0x00, 0x80, 0x48}; ac.setRaw(automode); EXPECT_EQ( - "Type: 1, Power: On, Mode: 8 (Auto), Temp: 24C, Fan: 0 (Auto), " - "Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, " - "Light: On", + "Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 8 (Auto), Temp: 24C, " + "Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, " + "Econo: Off, Health: Off, Turbo: Off, Light: On, " + "On Timer: Off, Off Timer: Off", ac.toString()); } @@ -236,9 +252,10 @@ TEST(TestTcl112AcClass, Power) { 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xCB}; ac.setRaw(on); EXPECT_EQ( - "Type: 1, Power: On, Mode: 3 (Cool), Temp: 16C, Fan: 0 (Auto), " - "Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, " - "Light: On", + "Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 16C, " + "Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, " + "Econo: Off, Health: Off, Turbo: Off, Light: On, " + "On Timer: Off, Off Timer: Off", ac.toString()); const uint8_t off[kTcl112AcStateLength] = { @@ -246,9 +263,10 @@ TEST(TestTcl112AcClass, Power) { 0x07, 0x40, 0x00, 0x00, 0x00, 0x80, 0xCB}; ac.setRaw(off); EXPECT_EQ( - "Type: 1, Power: Off, Mode: 3 (Cool), Temp: 24C, Fan: 0 (Auto), " - "Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, " - "Light: On", + "Model: 1 (TAC09CHSD), Type: 1, Power: Off, Mode: 3 (Cool), Temp: 24C, " + "Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, " + "Econo: Off, Health: Off, Turbo: Off, Light: On, " + "On Timer: Off, Off Timer: Off", ac.toString()); } @@ -263,15 +281,17 @@ TEST(TestTcl112AcClass, Checksum) { EXPECT_EQ(0xCB, ac.calcChecksum(temp16C)); ac.setRaw(temp16C); EXPECT_EQ( - "Type: 1, Power: On, Mode: 3 (Cool), Temp: 16C, Fan: 0 (Auto), " - "Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, " - "Light: On", + "Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 16C, " + "Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, " + "Econo: Off, Health: Off, Turbo: Off, Light: On, " + "On Timer: Off, Off Timer: Off", ac.toString()); ac.setRaw(temp31C); EXPECT_EQ( - "Type: 1, Power: On, Mode: 3 (Cool), Temp: 31C, Fan: 0 (Auto), " - "Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, " - "Light: On", + "Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 31C, " + "Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, " + "Econo: Off, Health: Off, Turbo: Off, Light: On, " + "On Timer: Off, Off Timer: Off", ac.toString()); EXPECT_EQ(0xBC, ac.calcChecksum(temp31C)); @@ -337,12 +357,22 @@ TEST(TestTcl112AcClass, SwingVertical) { IRTcl112Ac ac(kGpioUnused); ac.begin(); - ac.setSwingVertical(true); - EXPECT_TRUE(ac.getSwingVertical()); - ac.setSwingVertical(false); - EXPECT_EQ(false, ac.getSwingVertical()); - ac.setSwingVertical(true); - EXPECT_TRUE(ac.getSwingVertical()); + ac.setSwingVertical(kTcl112AcSwingVOff); + EXPECT_EQ(kTcl112AcSwingVOff, ac.getSwingVertical()); + ac.setSwingVertical(kTcl112AcSwingVOn); + EXPECT_EQ(kTcl112AcSwingVOn, ac.getSwingVertical()); + ac.setSwingVertical(kTcl112AcSwingVHigh); + EXPECT_EQ(kTcl112AcSwingVHigh, ac.getSwingVertical()); + ac.setSwingVertical(kTcl112AcSwingVOff); + EXPECT_EQ(kTcl112AcSwingVOff, ac.getSwingVertical()); + ac.setSwingVertical(0xFF); // Unused value so shouldn't change from previous. + EXPECT_EQ(kTcl112AcSwingVOff, ac.getSwingVertical()); + + const uint8_t highest[kTcl112AcStateLength] = { + 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03, + 0x0F, 0x08, 0x00, 0x00, 0x00, 0x00, 0x53}; + ac.setRaw(highest); + EXPECT_EQ(kTcl112AcSwingVHighest, ac.getSwingVertical()); } TEST(TestTcl112AcClass, Turbo) { @@ -405,6 +435,7 @@ TEST(TestTcl112AcClass, Quiet_Mute) { TEST(TestTcl112AcClass, toCommon) { IRTcl112Ac ac(kGpioUnused); + ac.setModel(tcl_ac_remote_model_t::TAC09CHSD); ac.setPower(true); ac.setMode(kTcl112AcCool); ac.setTemp(20); @@ -418,7 +449,7 @@ TEST(TestTcl112AcClass, toCommon) { ac.setQuiet(false); // Now test it. ASSERT_EQ(decode_type_t::TCL112AC, ac.toCommon().protocol); - ASSERT_EQ(-1, ac.toCommon().model); + ASSERT_EQ(1, ac.toCommon().model); ASSERT_TRUE(ac.toCommon().power); ASSERT_TRUE(ac.toCommon().celsius); ASSERT_EQ(20, ac.toCommon().degrees); @@ -485,9 +516,10 @@ TEST(TestDecodeTcl112Ac, Issue744) { IRTcl112Ac ac(kGpioUnused); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Type: 1, Power: On, Mode: 3 (Cool), Temp: 23C, Fan: 0 (Auto), " - "Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, " - "Light: On", + "Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 23C, " + "Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, " + "Econo: Off, Health: Off, Turbo: Off, Light: On, " + "On Timer: Off, Off Timer: Off", ac.toString()); } @@ -527,7 +559,7 @@ TEST(TestDecodeTcl112Ac, Issue1528) { EXPECT_EQ(kTcl112AcBits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "Type: 2, Quiet: On", + "Model: 1 (TAC09CHSD), Type: 2, Quiet: On", IRAcUtils::resultAcToString(&irsend.capture)); } @@ -536,7 +568,6 @@ TEST(TestTcl112AcClass, SendingQuiet) { IRTcl112Ac ac(kGpioUnused); IRrecv capture(kGpioUnused); - ac.begin(); ac.on(); ac.setTemp(24); @@ -559,16 +590,116 @@ TEST(TestTcl112AcClass, SendingQuiet) { ASSERT_EQ(TCL112AC, ac._irsend.capture.decode_type); ASSERT_EQ(kTcl112AcBits, ac._irsend.capture.bits); ASSERT_EQ( - "Type: 2, Quiet: On", + "Model: 1 (TAC09CHSD), Type: 2, Quiet: On", IRAcUtils::resultAcToString(&ac._irsend.capture)); // Second message. // TCL112 uses the Mitsubishi112 decoder. // Skip first message. EXPECT_TRUE(capture.decodeMitsubishi112(&ac._irsend.capture, 229)); - ASSERT_EQ(TCL112AC, ac._irsend.capture.decode_type); - ASSERT_EQ(kTcl112AcBits, ac._irsend.capture.bits); + EXPECT_EQ(TCL112AC, ac._irsend.capture.decode_type); + EXPECT_EQ(kTcl112AcBits, ac._irsend.capture.bits); ASSERT_EQ( - "Type: 1, Power: On, Mode: 3 (Cool), Temp: 24C, Fan: 0 (Auto), " - "Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, " - "Light: Off", IRAcUtils::resultAcToString(&ac._irsend.capture)); + "Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 24C, " + "Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, " + "Econo: Off, Health: Off, Turbo: Off, Light: Off, " + "On Timer: Off, Off Timer: Off", + IRAcUtils::resultAcToString(&ac._irsend.capture)); +} + +TEST(TestTcl112AcClass, isTcl) { + const uint8_t tcl_temp16C[kTcl112AcStateLength] = { + 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xCB}; + EXPECT_TRUE(IRTcl112Ac::isTcl(tcl_temp16C)); + const uint8_t tcl_temp31C[kTcl112AcStateLength] = { + 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xBC}; + EXPECT_TRUE(IRTcl112Ac::isTcl(tcl_temp31C)); + const uint8_t issue1528[kTcl112AcStateLength] = { + 0x23, 0xCB, 0x26, 0x02, 0x00, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85}; + EXPECT_TRUE(IRTcl112Ac::isTcl(issue1528)); + // Ref: https://cociweb.info/container/hvac_ir_recapture_2719.log + const uint8_t teknopoint[14] = { + 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03, + 0x0F, 0x38, 0x00, 0x00, 0x00, 0x00, 0x83}; + EXPECT_FALSE(IRTcl112Ac::isTcl(teknopoint)); +} + +TEST(TestTcl112AcClass, Timers) { + IRTcl112Ac ac(kGpioUnused); + + ac.stateReset(); + ac.setOnTimer(0); + ac.setOffTimer(0); + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_EQ(0, ac.getOffTimer()); + EXPECT_FALSE(ac._.TimerIndicator); + EXPECT_FALSE(ac._.OnTimerEnabled); + EXPECT_FALSE(ac._.OffTimerEnabled); + + ac.setOnTimer(7 * 60); + EXPECT_EQ(7 * 60, ac.getOnTimer()); + EXPECT_TRUE(ac._.TimerIndicator); + EXPECT_TRUE(ac._.OnTimerEnabled); + EXPECT_FALSE(ac._.OffTimerEnabled); + + ac.setOnTimer(0); + EXPECT_EQ(0, ac.getOnTimer()); + EXPECT_FALSE(ac._.TimerIndicator); + EXPECT_FALSE(ac._.OnTimerEnabled); + EXPECT_FALSE(ac._.OffTimerEnabled); + + ac.setOffTimer(13 * 60); // Beyond max. + EXPECT_EQ(12 * 60, ac.getOffTimer()); + EXPECT_TRUE(ac._.TimerIndicator); + EXPECT_FALSE(ac._.OnTimerEnabled); + EXPECT_TRUE(ac._.OffTimerEnabled); + + ac.setOffTimer(0); + EXPECT_EQ(0, ac.getOffTimer()); + EXPECT_FALSE(ac._.TimerIndicator); + EXPECT_FALSE(ac._.OnTimerEnabled); + EXPECT_FALSE(ac._.OffTimerEnabled); + + // Real messages/states + // Per https://github.com/crankyoldgit/IRremoteESP8266/issues/1486#issuecomment-917545485 + + const uint8_t ontimer_1h[14] = { + 0x23, 0xCB, 0x26, 0x01, 0x00, 0x34, 0x03, + 0x00, 0x78, 0x00, 0x06, 0x00, 0x00, 0xCA}; + ac.setRaw(ontimer_1h); + EXPECT_EQ(60, ac.getOnTimer()); + EXPECT_TRUE(ac._.TimerIndicator); + EXPECT_TRUE(ac._.OnTimerEnabled); + EXPECT_FALSE(ac._.OffTimerEnabled); + + const uint8_t ontimer_4h[14] = { + 0x23, 0xCB, 0x26, 0x01, 0x00, 0x34, 0x03, + 0x00, 0x78, 0x00, 0x18, 0x00, 0x00, 0xDC}; + ac.setRaw(ontimer_4h); + EXPECT_EQ(240, ac.getOnTimer()); + EXPECT_TRUE(ac._.TimerIndicator); + EXPECT_TRUE(ac._.OnTimerEnabled); + EXPECT_FALSE(ac._.OffTimerEnabled); + EXPECT_EQ( + "Model: 2 (GZ055BE1), Type: 1, Power: On, Mode: 3 (Cool), Temp: 31C, " + "Fan: 0 (Auto), Swing(V): 7 (Swing), " + "On Timer: 04:00, Off Timer: Off", + ac.toString()); + + const uint8_t offtimer_2h[14] = { + 0x23, 0xCB, 0x26, 0x01, 0x00, 0x2C, 0x08, + 0x07, 0x78, 0x0C, 0x00, 0x00, 0x00, 0xD4}; + + ac.setRaw(offtimer_2h); + EXPECT_EQ(120, ac.getOffTimer()); + EXPECT_TRUE(ac._.TimerIndicator); + EXPECT_FALSE(ac._.OnTimerEnabled); + EXPECT_TRUE(ac._.OffTimerEnabled); + EXPECT_EQ( + "Model: 2 (GZ055BE1), Type: 1, Power: On, Mode: 8 (Auto), Temp: 24C, " + "Fan: 0 (Auto), Swing(V): 7 (Swing), " + "On Timer: Off, Off Timer: 02:00", + ac.toString()); } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Teknopoint_test.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Teknopoint_test.cpp index 009b2a41b..74f29d146 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Teknopoint_test.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/test/ir_Teknopoint_test.cpp @@ -44,7 +44,9 @@ TEST(TestDecodeTeknopoint, RealExample) { ASSERT_EQ(kTeknopointBits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "", + "Model: 2 (GZ055BE1), Type: 1, Power: On, Mode: 3 (Cool), Temp: 16C, " + "Fan: 0 (Auto), Swing(V): 1 (Highest), " + "On Timer: Off, Off Timer: Off", IRAcUtils::resultAcToString(&irsend.capture)); } @@ -67,7 +69,9 @@ TEST(TestDecodeTeknopoint, SyntheticExample) { ASSERT_EQ(kTeknopointBits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "", + "Model: 2 (GZ055BE1), Type: 1, Power: On, Mode: 3 (Cool), Temp: 16C, " + "Fan: 0 (Auto), Swing(V): 1 (Highest), " + "On Timer: Off, Off Timer: Off", IRAcUtils::resultAcToString(&irsend.capture)); EXPECT_EQ( @@ -95,7 +99,7 @@ TEST(TestUtils, Housekeeping) { ASSERT_EQ("TEKNOPOINT", typeToString(decode_type_t::TEKNOPOINT)); ASSERT_EQ(decode_type_t::TEKNOPOINT, strToDecodeType("TEKNOPOINT")); ASSERT_TRUE(hasACState(decode_type_t::TEKNOPOINT)); - ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::TEKNOPOINT)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::TEKNOPOINT)); ASSERT_EQ(kTeknopointBits, IRsend::defaultBits(decode_type_t::TEKNOPOINT)); ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::TEKNOPOINT)); } diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/Makefile b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/Makefile index b30d1207c..15f192efd 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/Makefile +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/Makefile @@ -1,7 +1,11 @@ # SYNOPSIS: # -# make [all] - makes everything. -# make clean - removes all files generated by make. +# make [all] - makes everything. +# make TARGET - makes the given target. +# make run_tests - makes everything and runs all test +# make run-% - run specific test file (exclude .py) +# replace % with given test file +# make clean - removes all files generated by make. # Please tweak the following variable definitions as needed by your # project, except GTEST_HEADERS, which you can use in your own targets @@ -37,6 +41,10 @@ run_tests : all echo "PASS: \o/ \o/ All unit tests passed. \o/ \o/"; \ fi +run-% : all + echo "RUNNING: $*"; \ + python3 ./$*.py; + clean : rm -f *.o *.pyc gc_decode mode2_decode diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/auto_analyse_raw_data.py b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/auto_analyse_raw_data.py index aa5c990a9..e061d3c42 100755 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/auto_analyse_raw_data.py +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/auto_analyse_raw_data.py @@ -85,6 +85,7 @@ class RawIRMessage(): bits = len(binary_str) rev_binary_str = binary_str[::-1] rev_num = int(rev_binary_str, 2) + # pylint: disable=C0209 self.output.write("\n Bits: %d\n" " Hex: %s (MSB first)\n" " %s (LSB first)\n" @@ -95,22 +96,21 @@ class RawIRMessage(): (bits, ("0x{0:0%dX}" % (bits / 4)).format(num), ("0x{0:0%dX}" % (bits / 4)).format(rev_num), num, rev_num, binary_str, rev_binary_str)) + # pylint: enable=C0209 def add_data_code(self, bin_str, name="", footer=True): """Add the common "data" sequence of code to send the bulk of a message.""" # pylint: disable=no-self-use code = [] nbits = len(bin_str) - code.append(" // Data Section #%d" % self.section_count) - code.append(" // e.g. data = 0x%X, nbits = %d" % (int(bin_str, 2), - nbits)) - code.append(" sendData(k%sBitMark, k%sOneSpace, k%sBitMark, " - "k%sZeroSpace, send_data, %d, true);" % - (name, name, name, name, nbits)) - code.append(" send_data >>= %d;" % nbits) + code.append(f" // Data Section #{self.section_count}") + code.append(f" // e.g. data = 0x{int(bin_str, 2):X}, nbits = {nbits}") + code.append(f" sendData(k{name}BitMark, k{name}OneSpace, k{name}BitMark," + f" k{name}ZeroSpace, send_data, {nbits}, true);") + code.append(f" send_data >>= {nbits};") if footer: code.append(" // Footer") - code.append(" mark(k%sBitMark);" % name) + code.append(f" mark(k{name}BitMark);") return code def add_data_decode_code(self, bin_str, name="", footer=True): @@ -120,21 +120,20 @@ class RawIRMessage(): nbits = len(bin_str) code.extend([ "", - " // Data Section #%d" % self.section_count, - " // e.g. data_result.data = 0x%X, nbits = %d" % (int(bin_str, 2), - nbits), - " data_result = matchData(&(results->rawbuf[offset]), %s," % nbits, - " k%sBitMark, k%sOneSpace," % (name, name), - " k%sBitMark, k%sZeroSpace);" % (name, name), + f" // Data Section #{self.section_count}", + f" // e.g. data_result.data = 0x{int(bin_str, 2):X}, nbits = {nbits}", + f" data_result = matchData(&(results->rawbuf[offset]), {nbits},", + f" k{name}BitMark, k{name}OneSpace,", + f" k{name}BitMark, k{name}ZeroSpace);", " offset += data_result.used;", " if (data_result.success == false) return false; // Fail", - " data <<= %s; // Make room for the new bits of data." % nbits, + f" data <<= {nbits}; // Make room for the new bits of data.", " data |= data_result.data;"]) if footer: code.extend([ "", " // Footer", - " if (!matchMark(results->rawbuf[offset++], k%sBitMark))" % name, + f" if (!matchMark(results->rawbuf[offset++], k{name}BitMark))", " return false;"]) return code @@ -148,26 +147,28 @@ class RawIRMessage(): ambles = {} firstmark = ambles.get("firstmark", 0) firstspace = ambles.get("firstspace", 0) - lastmark = ambles.get("lastmark", "k%sBitMark" % name) + lastmark = ambles.get("lastmark", f"k{name}BitMark") lastspace = ambles.get("lastspace", "kDefaultMessageGap") - code.append( - " // Data Section #%d" % self.section_count) + code.append(f" // Data Section #{self.section_count}") if nbits % 8: code.append(" // DANGER: Nr. of bits is not a multiple of 8. " "This section won't work!") code.extend([ " // e.g.", - " // bits = %d; bytes = %d;" % (nbits, nbytes), + f" // bits = {nbits}; bytes = {int(nbytes)};", + # pylint: disable=C0209 " // *(data + pos) = {0x%s};" % ( ", 0x".join("%02X" % int(bin_str[i:i + 8], 2) for i in range(0, len(bin_str), 8))), - " sendGeneric(%s, %s," % (firstmark, firstspace), - " k%sBitMark, k%sOneSpace," % (name, name), - " k%sBitMark, k%sZeroSpace," % (name, name), - " %s, %s," % (lastmark, lastspace), - " data + pos, %d, // Bytes" % nbytes, - " k%sFreq, true, kNoRepeat, kDutyDefault);" % name, - " pos += %d; // Adjust by how many bytes of data we sent" % nbytes]) + # pylint: enable=C0209 + f" sendGeneric({firstmark}, {firstspace},", + f" k{name}BitMark, k{name}OneSpace,", + f" k{name}BitMark, k{name}ZeroSpace,", + f" {lastmark}, {lastspace},", + f" data + pos, {int(nbytes)}, // Bytes", + f" k{name}Freq, true, kNoRepeat, kDutyDefault);", + f" pos += {int(nbytes)};" + f" // Adjust by how many bytes of data we sent"]) return code def add_data_byte_decode_code(self, bin_str, name="", ambles=None): @@ -183,36 +184,37 @@ class RawIRMessage(): ambles = {} firstmark = ambles.get("firstmark", 0) firstspace = ambles.get("firstspace", 0) - lastmark = ambles.get("lastmark", "k%sBitMark" % name) + lastmark = ambles.get("lastmark", f"k{name}BitMark") lastspace = ambles.get("lastspace", "kDefaultMessageGap") code.extend([ "", - " // Data Section #%d" % self.section_count, + f" // Data Section #{self.section_count}", " // e.g.", - " // bits = %d; bytes = %d;" % (nbits, nbytes), + f" // bits = {nbits}; bytes = {int(nbytes)};", + # pylint: disable=C0209 " // *(results->state + pos) = {0x%s};" % ( ", 0x".join("%02X" % int(bin_str[i:i + 8], 2) for i in range(0, len(bin_str), 8))), + # pylint: enable=C0209 " used = matchGeneric(results->rawbuf + offset, results->state + pos,", - " results->rawlen - offset, %d," % nbits, - " %s, %s," % (firstmark, firstspace), - " k%sBitMark, k%sOneSpace," % (name, name), - " k%sBitMark, k%sZeroSpace," % (name, name), - " %s, %s, true);" % (lastmark, lastspace), + f" results->rawlen - offset, {nbits},", + f" {firstmark}, {firstspace},", + f" k{name}BitMark, k{name}OneSpace,", + f" k{name}BitMark, k{name}ZeroSpace,", + f" {lastmark}, {lastspace}, true);", " if (used == 0) return false; // We failed to find any data.", " offset += used; // Adjust for how much of the message we read.", - " pos += %d; // Adjust by how many bytes of data we read" % nbytes]) + f" pos += {int(nbytes)};" + " // Adjust by how many bytes of data we read"]) return code def _calc_values(self): """Calculate the values which describe the standard timings for the protocol.""" if self.verbose: - self.output.write("Potential Mark Candidates:\n" - "%s\n" - "Potential Space Candidates:\n" - "%s\n" % (str(self.marks), str(self.spaces))) + self.output.write(f"Potential Mark Candidates:\n{self.marks}\n" + f"Potential Space Candidates:\n{self.spaces}\n") # The bit mark is likely to be the smallest mark. self.bit_mark = self.marks[-1] if len(self.marks) > 2: # Possible leader mark? @@ -305,8 +307,8 @@ def convert_rawdata(data_str): results.append(int(timing)) except ValueError as non_numeric: raise ValueError( - "Raw Data contains a non-numeric value of '%s'." % - timing) from non_numeric + f"Raw Data contains a non-numeric value of '{timing}'." + ) from non_numeric return results @@ -326,35 +328,33 @@ def dump_constants(message, defines, name="", output=sys.stdout): zero_space = avg_list(message.space_buckets[message.zero_space]) output.write("Guessing key value:\n" - "k%sHdrMark = %d\n" - "k%sHdrSpace = %d\n" - "k%sBitMark = %d\n" - "k%sOneSpace = %d\n" - "k%sZeroSpace = %d\n" % (name, hdr_mark, name, hdr_space, - name, bit_mark, name, one_space, - name, zero_space)) - defines.append("const uint16_t k%sHdrMark = %d;" % (name, hdr_mark)) - defines.append("const uint16_t k%sBitMark = %d;" % (name, bit_mark)) - defines.append("const uint16_t k%sHdrSpace = %d;" % (name, hdr_space)) - defines.append("const uint16_t k%sOneSpace = %d;" % (name, one_space)) - defines.append("const uint16_t k%sZeroSpace = %d;" % (name, zero_space)) + f"k{name}HdrMark = {hdr_mark}\n" + f"k{name}HdrSpace = {hdr_space}\n" + f"k{name}BitMark = {bit_mark}\n" + f"k{name}OneSpace = {one_space}\n" + f"k{name}ZeroSpace = {zero_space}\n") + defines.append(f"const uint16_t k{name}HdrMark = {hdr_mark};") + defines.append(f"const uint16_t k{name}BitMark = {bit_mark};") + defines.append(f"const uint16_t k{name}HdrSpace = {hdr_space};") + defines.append(f"const uint16_t k{name}OneSpace = {one_space};") + defines.append(f"const uint16_t k{name}ZeroSpace = {zero_space};") if ldr_mark: - output.write("k%sLdrMark = %d\n" % (name, ldr_mark)) - defines.append("const uint16_t k%sLdrMark = %d;" % (name, ldr_mark)) + output.write(f"k{name}LdrMark = {ldr_mark}\n") + defines.append(f"const uint16_t k{name}LdrMark = {ldr_mark};") avg_gaps = [avg_list(message.space_buckets[x]) for x in message.gaps] if len(message.gaps) == 1: - output.write("k%sSpaceGap = %d\n" % (name, avg_gaps[0])) - defines.append("const uint16_t k%sSpaceGap = %d;" % (name, avg_gaps[0])) + output.write(f"k{name}SpaceGap = {avg_gaps[0]}\n") + defines.append(f"const uint16_t k{name}SpaceGap = {avg_gaps[0]};") else: count = 0 for gap in avg_gaps: # We probably (still) have a gap in the protocol. count = count + 1 - output.write("k%sSpaceGap%d = %d\n" % (name, count, gap)) - defines.append("const uint16_t k%sSpaceGap%d = %d;" % (name, count, gap)) - defines.append("const uint16_t k%sFreq = 38000; " - "// Hz. (Guessing the most common frequency.)" % name) + output.write(f"k{name}SpaceGap{count} = {gap}\n") + defines.append(f"const uint16_t k{name}SpaceGap{count} = {gap};") + defines.append(f"const uint16_t k{name}Freq = 38000; " + "// Hz. (Guessing the most common frequency.)") def parse_and_report(rawdata_str, margin, gen_code=False, name="", @@ -374,7 +374,7 @@ def parse_and_report(rawdata_str, margin, gen_code=False, name="", # Parse the input. rawdata = convert_rawdata(rawdata_str) - output.write("Found %d timing entries.\n" % len(rawdata)) + output.write(f"Found {len(rawdata)} timing entries.\n") message = RawIRMessage(margin, rawdata, output) output.write("\nGuessing encoding type:\n") @@ -410,17 +410,17 @@ def decode_data(message, defines, code, name="", output=sys.stdout): code["sendcomhead"].extend([ "", - "#if SEND_%s" % def_name.upper(), + f"#if SEND_{def_name.upper()}", SAFE64NOTE, - "/// Send a %s formatted message." % name, + f"/// Send a {name} formatted message.", "/// Status: ALPHA / Untested."]) code["send"].extend([ "/// @param[in] data containing the IR command.", - "/// @param[in] nbits Nr. of bits to send. usually k%sBits" % name, + f"/// @param[in] nbits Nr. of bits to send. usually k{name}Bits", "/// @param[in] repeat Nr. of times the message is to be repeated.", - "void IRsend::send%s(const uint64_t data, const uint16_t" - " nbits, const uint16_t repeat) {" % def_name, - " enableIROut(k%sFreq);" % name, + f"void IRsend::send{def_name}(const uint64_t data, const uint16_t" + " nbits, const uint16_t repeat) {", + f" enableIROut(k{name}Freq);", " for (uint16_t r = 0; r <= repeat; r++) {", " uint64_t send_data = data;"]) code["send64+"].extend([ @@ -431,21 +431,21 @@ def decode_data(message, defines, code, name="", output=sys.stdout): CODEGEN, "/// @endcode", "/// @param[in] nbytes Nr. of bytes of data in the array." - " (>=k%sStateLength)" % name, + f" (>=k{name}StateLength)", "/// @param[in] repeat Nr. of times the message is to be repeated.", - "void IRsend::send%s(const uint8_t data[], const uint16_t nbytes," - " const uint16_t repeat) {" % def_name, + f"void IRsend::send{def_name}(const uint8_t data[]," + " const uint16_t nbytes, const uint16_t repeat) {", " for (uint16_t r = 0; r <= repeat; r++) {", " uint16_t pos = 0;"]) code["sendcomfoot"].extend([ " }", "}", - "#endif // SEND_%s" % def_name.upper()]) + f"#endif // SEND_{def_name.upper()}"]) code["recvcomhead"].extend([ "", - "#if DECODE_%s" % def_name.upper(), + f"#if DECODE_{def_name.upper()}", SAFE64NOTE, - "/// Decode the supplied %s message." % name, + f"/// Decode the supplied {name} message.", "/// Status: ALPHA / Untested.", "/// @param[in,out] results Ptr to the data to decode &" " where to store the decode", @@ -456,11 +456,11 @@ def decode_data(message, defines, code, name="", output=sys.stdout): "/// @param[in] strict Flag indicating if we should perform strict" " matching.", "/// @return A boolean. True if it can decode it, false if it can't.", - "bool IRrecv::decode%s(decode_results *results, uint16_t offset," - " const uint16_t nbits, const bool strict) {" % def_name, - " if (results->rawlen < 2 * nbits + k%sOverhead - offset)" % name, + f"bool IRrecv::decode{def_name}(decode_results *results, uint16_t offset," + " const uint16_t nbits, const bool strict) {", + f" if (results->rawlen < 2 * nbits + k{name}Overhead - offset)", " return false; // Too short a message to match.", - " if (strict && nbits != k%sBits)" % name, + f" if (strict && nbits != k{name}Bits)", " return false;", ""]) code["recv"].extend([ @@ -472,7 +472,7 @@ def decode_data(message, defines, code, name="", output=sys.stdout): code["recvcomfoot"].extend([ " return true;", "}", - "#endif // DECODE_%s" % def_name.upper()]) + f"#endif // DECODE_{def_name.upper()}"]) # states are: # HM: Header/Leader mark @@ -496,24 +496,24 @@ def decode_data(message, defines, code, name="", output=sys.stdout): code["recv"].extend(message.add_data_decode_code(binary_value, name, False)) message.section_count = message.section_count + 1 - code_info["lastmark"] = "k%s%sdrMark" % (name, mark_type) + code_info["lastmark"] = f"k{name}{mark_type}drMark" total_bits = total_bits + binary_value - code_info["firstmark"] = "k%s%sdrMark" % (name, mark_type) + code_info["firstmark"] = f"k{name}{mark_type}drMark" binary_value = add_bit(binary_value, "reset") - output.write("k%s%sdrMark+" % (name, mark_type)) - code["send"].extend([" // %seader" % mark_type, - " mark(k%s%sdrMark);" % (name, mark_type)]) + output.write(f"k{name}{mark_type}drMark+") + code["send"].extend([f" // {mark_type}eader", + f" mark(k{name}{mark_type}drMark);"]) code["recv"].extend([ "", - " // %seader" % mark_type, - " if (!matchMark(results->rawbuf[offset++], k%s%sdrMark))" % ( - name, mark_type), + f" // {mark_type}eader", + " if (!matchMark(results->rawbuf[offset++]," + f" k{name}{mark_type}drMark))", " return false;"]) # Handle header spaces. elif message.is_hdr_space(usec) and not message.is_one_space(usec): if binary64_value: - code_info["lastspace"] = "k%sHdrSpace" % name + code_info["lastspace"] = f"k{name}HdrSpace" message.section_count = message.section_count - 1 code["send64+"].extend(message.add_data_byte_code(binary64_value, name, code_info)) @@ -529,39 +529,39 @@ def decode_data(message, defines, code, name="", output=sys.stdout): total_bits = total_bits + binary_value code["send"].extend(message.add_data_code(binary_value, name)) code["recv"].extend(message.add_data_decode_code(binary_value, name)) - code_info["lastspace"] = "k%sHdrSpace" % name + code_info["lastspace"] = f"k{name}HdrSpace" message.section_count = message.section_count + 1 binary_value = binary64_value = add_bit(binary_value, "reset") output.write("UNEXPECTED->") state = "HS" - output.write("k%sHdrSpace+" % name) - code["send"].append(" space(k%sHdrSpace);" % name) + output.write(f"k{name}HdrSpace+") + code["send"].append(f" space(k{name}HdrSpace);") code["recv"].extend([ - " if (!matchSpace(results->rawbuf[offset++], k%sHdrSpace))" % name, + f" if (!matchSpace(results->rawbuf[offset++], k{name}HdrSpace))", " return false;"]) - code_info["firstspace"] = "k%sHdrSpace" % name + code_info["firstspace"] = f"k{name}HdrSpace" # Handle bit marks. elif message.is_bit_mark(usec) and count % 2: if state not in ("HS", "BS"): - output.write("k%sBitMark(UNEXPECTED)" % name) + output.write(f"k{name}BitMark(UNEXPECTED)") state = "BM" # Handle "zero" spaces elif message.is_zero_space(usec): if state != "BM": - output.write("k%sZeroSpace(UNEXPECTED)" % name) + output.write(f"k{name}ZeroSpace(UNEXPECTED)") state = "BS" binary_value = binary64_value = add_bit(binary_value, 0, output) # Handle "one" spaces elif message.is_one_space(usec): if state != "BM": - output.write("k%sOneSpace(UNEXPECTED)" % name) + output.write(f"k{name}OneSpace(UNEXPECTED)") state = "BS" binary_value = binary64_value = add_bit(binary_value, 1, output) elif message.is_gap(usec): if state != "BM": output.write("UNEXPECTED->") - output.write("GAP(%d)" % usec) - code_info["lastspace"] = "k%sSpaceGap" % name + output.write(f"GAP({usec})") + code_info["lastspace"] = f"k{name}SpaceGap" if binary64_value: code["send64+"].extend(message.add_data_byte_code(binary64_value, name, code_info)) @@ -579,19 +579,19 @@ def decode_data(message, defines, code, name="", output=sys.stdout): " // Gap"]) code["send"].extend([" // Gap"]) if state == "BM": - code["send"].extend([" mark(k%sBitMark);" % name]) + code["send"].extend([f" mark(k{name}BitMark);"]) code["recv"].extend([ - " if (!matchMark(results->rawbuf[offset++], k%sBitMark))" % name, + f" if (!matchMark(results->rawbuf[offset++], k{name}BitMark))", " return false;"]) - code["send"].append(" space(k%sSpaceGap);" % name) + code["send"].append(f" space(k{name}SpaceGap);") code["recv"].extend([ - " if (!matchSpace(results->rawbuf[offset++], k%sSpaceGap))" % name, + f" if (!matchSpace(results->rawbuf[offset++], k{name}SpaceGap))", " return false;"]) total_bits = total_bits + binary_value binary_value = binary64_value = add_bit(binary_value, "reset") state = "GS" else: - output.write("UNKNOWN(%d)" % usec) + output.write(f"UNKNOWN({usec})") state = "UNK" count = count + 1 if binary64_value: @@ -611,7 +611,7 @@ def decode_data(message, defines, code, name="", output=sys.stdout): code["recv"].extend([ "", " // Success", - " results->decode_type = decode_type_t::%s;" % def_name.upper(), + f" results->decode_type = decode_type_t::{def_name.upper()};", " results->bits = nbits;", " results->value = data;", " results->command = 0;", @@ -619,19 +619,18 @@ def decode_data(message, defines, code, name="", output=sys.stdout): code["recv64+"].extend([ "", " // Success", - " results->decode_type = decode_type_t::%s;" % def_name.upper(), + f" results->decode_type = decode_type_t::{def_name.upper()};", " results->bits = nbits;"]) total_bits = total_bits + binary_value - output.write("\nTotal Nr. of suspected bits: %d\n" % len(total_bits)) - defines.append("const uint16_t k%sBits = %d;" - " // Move to IRremoteESP8266.h" % (name, len(total_bits))) + output.write(f"\nTotal Nr. of suspected bits: {len(total_bits)}\n") + defines.append(f"const uint16_t k{name}Bits = {len(total_bits)};" + " // Move to IRremoteESP8266.h") if len(total_bits) > 64: - defines.append("const uint16_t k%sStateLength = %d;" - " // Move to IRremoteESP8266.h" % - (name, len(total_bits) / 8)) - defines.append("const uint16_t k%sOverhead = %d;" % - (name, message.rawlen - 2 * len(total_bits))) + defines.append(f"const uint16_t k{name}StateLength = " + f"{int(len(total_bits) / 8)}; // Move to IRremoteESP8266.h") + defines.append(f"const uint16_t k{name}Overhead = " + f"{message.rawlen - 2 * len(total_bits)};") return total_bits @@ -645,9 +644,9 @@ def generate_code(defines, code, bits_str, name="", output=sys.stdout): output.write("\nGenerating a VERY rough code outline:\n\n" "// Copyright 2020 David Conran (crankyoldgit)\n" "/// @file\n" - "/// @brief Support for %s protocol\n\n" + f"/// @brief Support for {def_name} protocol\n\n" "// Supports:\n" - "// Brand: %s, Model: TODO add device and remote\n\n" + f"// Brand: {def_name}, Model: TODO add device and remote\n\n" '#include "IRrecv.h"\n' '#include "IRsend.h"\n' '#include "IRutils.h"\n\n' @@ -656,9 +655,9 @@ def generate_code(defines, code, bits_str, name="", output=sys.stdout): "// See https://github.com/crankyoldgit/IRremoteESP8266/wiki/" "Adding-support-for-a-new-IR-protocol\n" "// for details of how to include this in the library." - "\n" % (def_name, def_name)) + "\n") for line in defines: - output.write("%s\n" % line) + output.write(f"{line}\n") if len(bits_str) > 64: # Will it fit in a uint64_t? output.write("// DANGER: More than 64 bits detected. A uint64_t for " @@ -668,18 +667,21 @@ def generate_code(defines, code, bits_str, name="", output=sys.stdout): for line in code["sendcomhead"] + code["send"] + code["sendcomfoot"]: if line == SAFE64NOTE: line = "// Function should be safe up to 64 bits." - output.write("%s\n" % line) + output.write(f"{line}\n") if len(bits_str) > 64: # Will it fit in a uint64_t? for line in code["sendcomhead"] + code["send64+"] + code["sendcomfoot"]: if line == SAFE64NOTE: - line = "// Alternative >64bit function to send %s messages\n" % \ - def_name.upper() + "// Function should be safe over 64 bits." + line = (f"// Alternative >64bit function to send {def_name.upper()}" + " messages\n" + "// Function should be safe over 64 bits.") elif line == CODEGEN: + # pylint: disable=C0209 line = "/// uint8_t data[k%sStateLength] = {0x%s};" % ( name, ", 0x".join("%02X" % int(bits_str[i:i + 8], 2) for i in range(0, len(bits_str), 8))) - output.write("%s\n" % line) + # pylint: enable=C0209 + output.write(f"{line}\n") if len(bits_str) > 64: # Will it fit in a uint64_t? output.write("\n// DANGER: More than 64 bits detected. A uint64_t for " "'data' won't work!") @@ -689,7 +691,7 @@ def generate_code(defines, code, bits_str, name="", output=sys.stdout): for line in code["recvcomhead"] + code["recv"] + code["recvcomfoot"]: if line == SAFE64NOTE: line = "// Function should be safe up to 64 bits." - output.write("%s\n" % line) + output.write(f"{line}\n") # Display the > 64bit version's decode code if len(bits_str) > 64: # Is it too big for a uint64_t? @@ -699,7 +701,7 @@ def generate_code(defines, code, bits_str, name="", output=sys.stdout): for line in code["recvcomhead"] + code["recv64+"] + code["recvcomfoot"]: if line == SAFE64NOTE: line = "// Function should be safe over 64 bits." - output.write("%s\n" % line) + output.write(f"{line}\n") def add_rawdata_args(parser): """Add the arguments for feeding in the rawdata string(s).""" diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/generate_irtext_h.sh b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/generate_irtext_h.sh index df2baee06..b0d9855c4 100755 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/generate_irtext_h.sh +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/generate_irtext_h.sh @@ -24,12 +24,26 @@ cat >${OUTPUT} << EOF // Constant text to be shared across all object files. // This means there is only one copy of the character/string/text etc. +#ifdef ESP8266 +class __FlashStringHelper; +#define IRTEXT_CONST_PTR_CAST(PTR)\\ + reinterpret_cast(PTR) +#define IRTEXT_CONST_PTR(NAME) const __FlashStringHelper* const NAME +#else // ESP8266 +#define IRTEXT_CONST_PTR_CAST(PTR) PTR +#define IRTEXT_CONST_PTR(NAME) const char* const NAME +#endif // ESP8266 + EOF # Parse and output contents of INPUT file. sed 's/ PROGMEM//' ${INPUT} | egrep "^(const )?char" | cut -f1 -d= | sed 's/ $/;/;s/^/extern /' | sort -u >> ${OUTPUT} - +egrep '^\s{,10}IRTEXT_CONST_STRING\(' ${INPUT} | cut -f2 -d\( | cut -f1 -d, | + sed 's/^/extern IRTEXT_CONST_PTR\(/;s/$/\);/' | sort -u >> ${OUTPUT} +egrep '^\s{,10}IRTEXT_CONST_BLOB_DECL\(' ${INPUT} | + cut -f2 -d\( | cut -f1 -d\) | + sed 's/^/extern IRTEXT_CONST_PTR\(/;s/$/\);/' | sort -u >> ${OUTPUT} # Footer cat >> ${OUTPUT} << EOF diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/mkkeywords b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/mkkeywords index 84f2a46fd..e050e4964 100755 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/mkkeywords +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/mkkeywords @@ -31,7 +31,8 @@ cat << EndOfTextEndOfTextEndOfText EndOfTextEndOfTextEndOfText CLASSES=$(egrep -h "^ *((enum|class) |} [a-zA-Z0-9_]+_t;$)" src/*.h | - sed 's/^ *//;s/enum class//;s/\;$//' | cut -d' ' -f2 | sort -u) + sed 's/^ *//;s/enum class//;s/\;$//' | cut -d' ' -f2 | sort -u | + grep -v "^__") for i in ${CLASSES}; do echo -e "${i}\tKEYWORD1" done | sort -du @@ -59,13 +60,15 @@ cat << EndOfTextEndOfTextEndOfText ####################################### EndOfTextEndOfTextEndOfText -LITERALS=$(grep "^#define [A-Z]" src/*.cpp src/*.h | +LITERALS=$(grep -h "^#define [A-Z]" src/*.cpp src/*.h | while read ignore define ignore; do echo ${define}; done | sort -u | grep -v [\(\)] | grep -v ^_ | grep -v _\$ | grep -v VIRTUAL) -CONSTS=$(grep "^const " src/*.cpp src/*.h | - sed -E 's/\[.*\] =.*//;s/ =.*//;s/^.* \*?k/k/') +CONSTS=$(grep -h "^const " src/*.cpp src/*.h | + sed -E 's/\[.*\] =.*//;s/ =.*//;s/^.* \*?k/k/'; + grep -h "^IRTEXT_CONST_" src/*.cpp src/*.h | + sed -E 's/IRTEXT_CONST_\S+\(//;s/,.*//;s/\).*//') ENUMS=$(cat src/*.h | while read a b; do if [[ ${a} == "};" ]]; then ENUM=0; @@ -76,7 +79,7 @@ ENUMS=$(cat src/*.h | while read a b; do if [[ ${a} == "enum" ]]; then ENUM=1; fi; - done) + done | grep -v "^//") for i in ${LITERALS} ${CONSTS} ${ENUMS}; do echo -e "${i}\tLITERAL1" done | sort -u diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/raw_to_pronto_code.py b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/raw_to_pronto_code.py index 307ae7121..8d8fc815c 100755 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/raw_to_pronto_code.py +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/tools/raw_to_pronto_code.py @@ -1,4 +1,4 @@ -#!/usr/bin/python + #!/usr/bin/python """Convert IRremoteESP8266's Raw data output into Pronto Code.""" # # Copyright 2020 David Conran @@ -16,7 +16,7 @@ def parse_and_report(rawdata_str, hertz=38000, end_usecs=100000, # Parse the input. rawdata = convert_rawdata(rawdata_str) if verbose: - output.write("Found %d timing entries.\n" % len(rawdata)) + output.write(f"Found {len(rawdata)} timing entries.\n") # Do we need to pad out the rawdata to make it even in length? if end_usecs > 0 and len(rawdata) % 2 == 1: @@ -26,29 +26,29 @@ def parse_and_report(rawdata_str, hertz=38000, end_usecs=100000, # Work out the frequency code. pronto_freq = int(1000000.0 / (hertz * 0.241246)) if verbose: - output.write("Pronto frequency is %X (%d Hz).\n" % (pronto_freq, hertz)) - result.append("%04X" % pronto_freq) + output.write(f"Pronto frequency is {pronto_freq:X} ({hertz} Hz).\n") + result.append(f"{pronto_freq:04X}") period = 1000000.0 / max(1, hertz) if verbose: - output.write("Pronto period is %f uSecs.\n" % period) + output.write(f"Pronto period is {period} uSecs.\n") # Add the lengths to the code. if use_initial: - result.append("%04x" % int(len(rawdata) / 2)) # Initial burst code length - result.append("%04x" % 0) # No Repeat code length + result.append(f"{int(len(rawdata) / 2):04x}") # Initial burst code length + result.append("0000") # No Repeat code length else: - result.append("%04x" % 0) # No Initial burst code length - result.append("%04x" % int(len(rawdata) / 2)) # Repeat code length + result.append("0000") # No Initial burst code length + result.append(f"{int(len(rawdata) / 2):04x}") # Repeat code length # Add the data. if verbose: - output.write("Raw data: %s " % rawdata) + output.write(f"Raw data: {rawdata} ") for i in rawdata: - result.append("%04x" % int(i / period)) + result.append(f"{int(i / period):04x}") if generate_code: - output.write("uint16_t pronto[%d] = {0x%s};\n" % (len(result), - ", 0x".join(result))) + output.write(f"uint16_t pronto[{len(result)}] = " + f"{{0x{', 0x'.join(result)}}};\n") else: - output.write("Pronto code = '%s'\n" % " ".join(result)) + output.write(f"Pronto code = '{' '.join(result)}'\n") # pylint: enable=too-many-arguments diff --git a/lib/lib_basic/IRremoteESP8266/library.json b/lib/lib_basic/IRremoteESP8266/library.json index f905e1c2f..6ac0ca58a 100644 --- a/lib/lib_basic/IRremoteESP8266/library.json +++ b/lib/lib_basic/IRremoteESP8266/library.json @@ -1,6 +1,6 @@ { "name": "IRremoteESP8266", - "version": "2.7.19", + "version": "2.8.0", "keywords": "infrared, ir, remote, esp8266, esp32", "description": "Send and receive infrared signals with multiple protocols (ESP8266/ESP32)", "repository": @@ -48,8 +48,6 @@ "frameworks": "arduino", "platforms": ["espressif8266", "espressif32"], - - "build": { "srcDir": "IRremoteESP8266/src", "flags": [ "-I$PROJECT_DIR/include", "-includetasmota_options.h" ] diff --git a/lib/lib_basic/OneWire-Stickbreaker-20190506-1.1/OneWire.h b/lib/lib_basic/OneWire-Stickbreaker-20190506-1.1/OneWire.h index eb20f2b20..edb31d1eb 100644 --- a/lib/lib_basic/OneWire-Stickbreaker-20190506-1.1/OneWire.h +++ b/lib/lib_basic/OneWire-Stickbreaker-20190506-1.1/OneWire.h @@ -211,12 +211,16 @@ void directModeInput(IO_REG_TYPE pin) ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown); } #elif ESP_IDF_VERSION_MAJOR > 3 // ESP32-S2 needs IDF 4.2 or later - uint32_t rtc_reg(rtc_io_desc[pin].reg); + int rtcio_num = rtc_io_number_get((gpio_num_t)pin); - if ( rtc_reg ) // RTC pins PULL settings - { - ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[pin].mux); - ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[pin].pullup | rtc_io_desc[pin].pulldown); + if (rtcio_num >= 0) { + uint32_t rtc_reg(rtc_io_desc[rtcio_num].reg); + + if ( rtc_reg ) // RTC pins PULL settings + { + ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtcio_num].mux); + ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtcio_num].pullup | rtc_io_desc[rtcio_num].pulldown); + } } #endif @@ -253,12 +257,16 @@ void directModeOutput(IO_REG_TYPE pin) ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown); } #elif ESP_IDF_VERSION_MAJOR > 3 // ESP32-S2 needs IDF 4.2 or later - uint32_t rtc_reg(rtc_io_desc[pin].reg); + int rtcio_num = rtc_io_number_get((gpio_num_t)pin); - if ( rtc_reg ) // RTC pins PULL settings - { - ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[pin].mux); - ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[pin].pullup | rtc_io_desc[pin].pulldown); + if (rtcio_num >= 0) { + uint32_t rtc_reg(rtc_io_desc[rtcio_num].reg); + + if ( rtc_reg ) // RTC pins PULL settings + { + ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtcio_num].mux); + ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_io_desc[rtcio_num].pullup | rtc_io_desc[rtcio_num].pulldown); + } } #endif diff --git a/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.cpp b/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.cpp index fb223680b..e09ab71a8 100644 --- a/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.cpp +++ b/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.cpp @@ -633,6 +633,12 @@ LVGL_PARAMS *Renderer::lvgl_pars(void) { return &lvgl_param; } +void Renderer::ep_update_mode(uint8_t mode) { +} + +void Renderer::ep_update_area(uint16_t xp, uint16_t yp, uint16_t width, uint16_t height, uint8_t mode) { +} + // #ifndef USE_DISPLAY_LVGL_ONLY @@ -642,6 +648,18 @@ void VButton::xdrawButton(bool inverted) { wr_redir=0; } +void VButton::xinitButtonUL(Renderer *renderer, int16_t gxp, int16_t gyp, uint16_t gxs, uint16_t gys, uint16_t outline,\ + uint16_t fill, uint16_t textcolor , char *label, uint8_t textsize) { + + initButtonUL(renderer, gxp, gyp, gxs, gys, outline, fill, textcolor, label, textsize); + + spars.xp = gxp; + spars.yp = gyp; + spars.xs = gxs; + spars.ys = gys; + +} + boolean VButton::didhit(int16_t x, int16_t y) { return ((x >= spars.xp) && (x < (int16_t) (spars.xp + spars.xs)) && (y >= spars.yp) && (y < (int16_t) (spars.yp + spars.ys))); diff --git a/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.h b/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.h index 49f4d7b5e..3e3304fbb 100644 --- a/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.h +++ b/lib/lib_display/Display_Renderer-gemu-1.0/src/renderer.h @@ -88,6 +88,8 @@ public: virtual void Splash(void); virtual char *devname(void); virtual LVGL_PARAMS *lvgl_pars(void); + virtual void ep_update_mode(uint8_t mode); + virtual void ep_update_area(uint16_t xp, uint16_t yp, uint16_t width, uint16_t height, uint8_t mode); void setDrawMode(uint8_t mode); uint8_t drawmode; @@ -144,6 +146,8 @@ class VButton : public Adafruit_GFX_Button { boolean didhit(int16_t x, int16_t y); uint16_t UpdateSlider(int16_t x, int16_t y); void SliderInit(Renderer *rend, uint16_t xp, uint16_t yp, uint16_t xs, uint16_t ys, uint16_t nelem, uint16_t bgcol, uint16_t frcol, uint16_t barcol); + void xinitButtonUL(Renderer *renderer, int16_t gxp, int16_t gyp, uint16_t gxs, uint16_t gys, uint16_t outline,\ + uint16_t fill, uint16_t textcolor , char *label, uint8_t textsize); }; // #endif // USE_DISPLAY_LVGL_ONLY diff --git a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/ILI9488.cpp b/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/ILI9488.cpp deleted file mode 100644 index 8b801feb1..000000000 --- a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/ILI9488.cpp +++ /dev/null @@ -1,1164 +0,0 @@ -/*************************************************** - STM32 Support added by Jaret Burkett at OSHlab.com - - This is our library for the Adafruit ILI9488 Breakout and Shield - ----> http://www.adafruit.com/products/1651 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ -#include -#include "ILI9488.h" -#include - -// if using software spi this optimizes the code - -#ifdef ESP32 -#define ILI9488_DIMMER -#undef ESP32_PWM_CHANNEL -#define ESP32_PWM_CHANNEL 1 -#endif - -#define ILI9488_START start(); -#define ILI9488_STOP stop(); - -const uint16_t ili9488_colors[]={ILI9488_BLACK,ILI9488_WHITE,ILI9488_RED,ILI9488_GREEN,ILI9488_BLUE,ILI9488_CYAN,ILI9488_MAGENTA,\ - ILI9488_YELLOW,ILI9488_NAVY,ILI9488_DARKGREEN,ILI9488_DARKCYAN,ILI9488_MAROON,ILI9488_PURPLE,ILI9488_OLIVE,\ -ILI9488_LIGHTGREY,ILI9488_DARKGREY,ILI9488_ORANGE,ILI9488_GREENYELLOW,ILI9488_PINK}; - -// Constructor when using software SPI. All output pins are configurable. -ILI9488::ILI9488(int8_t cs,int8_t mosi,int8_t sclk,int8_t bp) : Renderer(ILI9488_TFTWIDTH, ILI9488_TFTHEIGHT) { - _cs = cs; - _mosi = mosi; - _sclk = sclk; - _bp = bp; - _hwspi = 0; -} - -/* - -CPU Clock = 80 Mhz -max clock of display is 15 Mhz (66ns sclk cycle) -so cpu/8 => 10 Mhz should be ok - -HSPI CLK 5 GPIO14 -HSPI /CS 8 GPIO15 -HSPI MOSI 7 GPIO13 -HSPI MISO 6 GPIO12 - - -GPIO names for your easy reference: -GPIO0: PERIPHS_IO_MUX_GPIO0_U -GPIO1: PERIPHS_IO_MUX_U0TXD_U -GPIO2: PERIPHS_IO_MUX_GPIO2_U -GPIO3: PERIPHS_IO_MUX_U0RXD_U -GPIO4: PERIPHS_IO_MUX_GPIO4_U -GPIO5: PERIPHS_IO_MUX_GPIO5_U -GPIO6: PERIPHS_IO_MUX_SD_CLK_U -GPIO7: PERIPHS_IO_MUX_SD_DATA0_U -GPIO8: PERIPHS_IO_MUX_SD_DATA1_U -GPIO9: PERIPHS_IO_MUX_SD_DATA2_U -GPIO10: PERIPHS_IO_MUX_SD_DATA3_U -GPIO11: PERIPHS_IO_MUX_SD_CMD_U -GPIO12: PERIPHS_IO_MUX_MTDI_U -GPIO13: PERIPHS_IO_MUX_MTCK_U -GPIO14: PERIPHS_IO_MUX_MTMS_U -GPIO15: PERIPHS_IO_MUX_MTDO_U -*/ - -uint8_t ili9488_start; - -#ifndef ESP32 -// ESP8266 -#include "spi_register.h" -#define SWSPI_OPTMODE -// this enables the 27 bit packed mode -#define RGB_PACK_MODE - -uint32_t ili9488_clock; -uint32_t ili9488_usr; -uint32_t ili9488_usr1; -uint32_t ili9488_usr2; -uint32_t ili9488_spi1c; -uint32_t ili9488_spi1c1; -uint32_t ili9488_spi1p; -uint32_t ili9488_gpmux; -uint32_t ili9488_mtdo; - - -uint32_t ili9488_clock_prev; -uint32_t ili9488_usr_prev; -uint32_t ili9488_usr1_prev; -uint32_t ili9488_usr2_prev; -uint32_t ili9488_spi1c_prev; -uint32_t ili9488_spi1c1_prev; -uint32_t ili9488_spi1p_prev; -uint32_t ili9488_gpmux_prev; -uint32_t ili9488_mtdo_prev; - -// code from espressif SDK -/****************************************************************************** - * FunctionName : spi_lcd_mode_init - * Description : SPI master initial function for driving LCD 3 wire spi -*******************************************************************************/ -void ILI9488::spi_lcd_mode_init(void) { - - ili9488_clock_prev=SPI1CLK; - ili9488_usr_prev=SPI1U; - ili9488_usr1_prev=SPI1U1; - ili9488_usr2_prev=SPI1U2; - ili9488_spi1c_prev=SPI1C; - ili9488_spi1c1_prev=SPI1C1; - ili9488_spi1p_prev=SPI1P; - ili9488_gpmux_prev=GPMUX; - ili9488_mtdo_prev=READ_PERI_REG(PERIPHS_IO_MUX_MTDO_U); - - SPI1U = SPIUMOSI | SPIUDUPLEX | SPIUSSE; - SPI1U1=0; - SPI1C = 0; - SPI1C1 = 0; - - //bit9 of PERIPHS_IO_MUX should be cleared when HSPI clock doesn't equal CPU clock - //bit8 of PERIPHS_IO_MUX should be cleared when SPI clock doesn't equal CPU clock - - WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); //clear bit9 - //PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2);//configure miso to spi mode - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2);//configure mosi to spi mode - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2);//configure sclk to spi mode - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2);//configure cs to spi mode - -// the current implementation leaves about 1 us between transfers ???? -// due to lack of documentation i could not find the reason -// skipping this would double the speed !!! - - //SET_PERI_REG_MASK(SPI_USER(1), SPI_CS_SETUP|SPI_CS_HOLD|SPI_USR_COMMAND); - - SET_PERI_REG_MASK(SPI_USER(1), SPI_USR_COMMAND); - - CLEAR_PERI_REG_MASK(SPI_USER(1), SPI_FLASH_MODE); - // SPI clock=CPU clock/8 => 10 Mhz - /* - WRITE_PERI_REG(SPI_CLOCK(1), - ((1&SPI_CLKDIV_PRE)<>1)&0x7f; - - ILI9488_START - - regvalue= ((8&SPI_USR_COMMAND_BITLEN)<>1)|0x80; - - ILI9488_START - - regvalue= ((8&SPI_USR_COMMAND_BITLEN)<>= 1) { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - if(d&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - } - WRITE_PERI_REG( PIN_OUT_SET, 1<<_cs); -} -#else -// ESP32 section -void ILI9488::writedata(uint8_t d) { - ILI9488_START - fastSPIwrite(d,1); -} - -void ILI9488::writecommand(uint8_t c) { - ILI9488_START - fastSPIwrite(c,0); -} - -#include "soc/spi_reg.h" -#include "soc/spi_struct.h" -#include "esp32-hal-spi.h" -#include "esp32-hal.h" -#include "soc/spi_struct.h" - -#define RGB_PACK_MODE - -// since ardunio transferBits ia completely disfunctional -// we use our own hardware driver for 9 bit spi -void ILI9488::fastSPIwrite(uint8_t d,uint8_t dc) { - digitalWrite( _cs, LOW); - - uint32_t regvalue=d>>1; - if (dc) regvalue|=0x80; - else regvalue&=0x7f; - if (d&1) regvalue|=0x8000; - - REG_SET_BIT(SPI_USER_REG(3), SPI_USR_MOSI); - REG_WRITE(SPI_MOSI_DLEN_REG(3), 9 - 1); - uint32_t *dp=(uint32_t*)SPI_W0_REG(3); - *dp=regvalue; - REG_SET_BIT(SPI_CMD_REG(3), SPI_USR); - while (REG_GET_FIELD(SPI_CMD_REG(3), SPI_USR)); - - digitalWrite( _cs, HIGH); -} - -SPISettings ili9488_spiSettings; - -void ILI9488::start(void) { - if (ili9488_start) return; - SPI.beginTransaction(ili9488_spiSettings); - ili9488_start=1; -} -void ILI9488::stop(void) { - if (!ili9488_start) return; - SPI.endTransaction(); - ili9488_start=0; -} -#endif - - -uint16_t ILI9488::GetColorFromIndex(uint8_t index) { - if (index>=sizeof(ili9488_colors)/2) index=0; - return ili9488_colors[index]; -} - -void ILI9488::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) { - setRotation(rot); - invertDisplay(false); - setTextWrap(false); // Allow text to run off edges - cp437(true); - setTextFont(font&3); - setTextSize(size&7); - setTextColor(ILI9488_WHITE,ILI9488_BLACK); - setCursor(0,0); - fillScreen(ILI9488_BLACK); - ILI9488_STOP -} - -void ILI9488::DisplayOnff(int8_t on) { - if (on) { - writecommand(ILI9488_DISPON); //Display on - - if (_bp>=0) { - #ifdef ILI9488_DIMMER - ledcWrite(ESP32_PWM_CHANNEL,dimmer); - #else - digitalWrite(_bp,HIGH); - #endif - /* - writecommand(ILI9488_WRCTRLD); - writedata(0x0c); - writecommand(ILI9488_CAPC9); - writedata(0x3f);*/ - } - } else { - writecommand(ILI9488_DISPOFF); - - if (_bp>=0) { -#ifdef ILI9488_DIMMER - ledcWrite(ESP32_PWM_CHANNEL,0); -#else - digitalWrite(_bp,LOW); -#endif - } - //writecommand(ILI9488_WRCTRLD); - //writedata(0x04); - - } - ILI9488_STOP -} - -// dimmer 0-100 -void ILI9488::dim(uint8_t dim) { - dimmer = dim; - if (dimmer>15) dimmer=15; - dimmer=((float)dimmer/15.0)*255.0; -#ifdef ESP32 - ledcWrite(ESP32_PWM_CHANNEL,dimmer); -#endif -} - -void ILI9488::begin(void) { - pinMode(_cs, OUTPUT); - digitalWrite(_cs,HIGH); - pinMode(_sclk, OUTPUT); - pinMode(_mosi, OUTPUT); - if (_bp>=0) { -#ifdef ILI9488_DIMMER - ledcSetup(ESP32_PWM_CHANNEL,4000,8); - ledcAttachPin(_bp,ESP32_PWM_CHANNEL); - ledcWrite(ESP32_PWM_CHANNEL,128); -#else - pinMode(_bp, OUTPUT); - digitalWrite(_bp,HIGH); -#endif - } - -#ifndef ESP32 - if ((_sclk==14) && (_mosi==13) && (_cs==15)) { - // we use hardware spi - SPI.begin(); - _hwspi=1; - spi_lcd_mode_init(); - } else { - // we must use software spi - _hwspi=0; - } -#else - SPI.begin(_sclk,-1,_mosi, -1); - ili9488_spiSettings = SPISettings(10000000, MSBFIRST, SPI_MODE3); - _hwspi=1; -#endif - - ILI9488_START - delay(1); - - writecommand(0xE0); - writedata(0x00); - writedata(0x03); - writedata(0x09); - writedata(0x08); - writedata(0x16); - writedata(0x0A); - writedata(0x3F); - writedata(0x78); - writedata(0x4C); - writedata(0x09); - writedata(0x0A); - writedata(0x08); - writedata(0x16); - writedata(0x1A); - writedata(0x0F); - - - writecommand(0XE1); - writedata(0x00); - writedata(0x16); - writedata(0x19); - writedata(0x03); - writedata(0x0F); - writedata(0x05); - writedata(0x32); - writedata(0x45); - writedata(0x46); - writedata(0x04); - writedata(0x0E); - writedata(0x0D); - writedata(0x35); - writedata(0x37); - writedata(0x0F); - - writecommand(0XC0); //Power Control 1 - writedata(0x17); //Vreg1out - writedata(0x15); //Verg2out - - writecommand(0xC1); //Power Control 2 - writedata(0x41); //VGH,VGL - - writecommand(0xC5); //Power Control 3 - writedata(0x00); - writedata(0x12); //Vcom - writedata(0x80); - - writecommand(0x36); //Memory Access - writedata(0x48); - - writecommand(0x3A); // Interface Pixel Format - writedata(0x66); //18 bit - - writecommand(0XB0); // Interface Mode Control - writedata(0x80); //SDO NOT USE - - writecommand(0xB1); //Frame rate - writedata(0xA0); //60Hz - - writecommand(0xB4); //Display Inversion Control - writedata(0x02); //2-dot - - writecommand(0XB6); //Display Function Control RGB/MCU Interface Control - writedata(0x02); //MCU - writedata(0x02); //Source,Gate scan dieection - - writecommand(0XE9); // Set Image Functio - writedata(0x00); // Disable 24 bit data - - writecommand(0xF7); // Adjust Control - writedata(0xA9); - writedata(0x51); - writedata(0x2C); - writedata(0x82); // D7 stream, loose - - writecommand(ILI9488_SLPOUT); //Exit Sleep - delay(120); - writecommand(ILI9488_DISPON); //Display on - - ILI9488_STOP -} -/* -void ILI9488::setScrollArea(uint16_t topFixedArea, uint16_t bottomFixedArea){ - writecommand(0x33); // Vertical scroll definition - writedata(topFixedArea >> 8); - writedata(topFixedArea); - writedata((_height - topFixedArea - bottomFixedArea) >> 8); - writedata(_height - topFixedArea - bottomFixedArea); - writedata(bottomFixedArea >> 8); - writedata(bottomFixedArea); - ILI9488_STOP -} -void ILI9488::scroll(uint16_t pixels){ - writecommand(0x37); // Vertical scrolling start address - writedata(pixels >> 8); - writedata(pixels); - ILI9488_STOP -}*/ - -void ILI9488::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { - if (!x0 && !y0 && !x1 && !y1) { - x0=0; - y0=0; - x1=_width; - y1=_height; - } - setAddrWindow_int(x0, y0, x1-1, y1-1); -} - -void ILI9488::setAddrWindow_int(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { -uint8_t flag=0; - - if (!x0 && !y0 && !x1 && !y1) { - x0=0; - y0=0; - x1=_width; - y1=_height; - flag=1; - } - - if (x1>_width) x1=_width; - if (y1>_height) y1=_height; - - writecommand(ILI9488_CASET); // Column addr set - writedata(x0 >> 8); - writedata(x0 & 0xFF); // XSTART - writedata(x1 >> 8); - writedata(x1 & 0xFF); // XEND - - writecommand(ILI9488_PASET); // Row addr set - writedata(y0>>8); - writedata(y0 &0xff); // YSTART - writedata(y1>>8); - writedata(y1 &0xff); // YEND - - writecommand(ILI9488_RAMWR); // write to RAM - if (flag) ILI9488_STOP -} - -/* -void ILI9488::drawImage(const uint8_t* img, uint16_t x, uint16_t y, uint16_t w, uint16_t h){ -return; - // rudimentary clipping (drawChar w/big text requires this) - if((x >= _width) || (y >= _height)) return; - if((x + w - 1) >= _width) w = _width - x; - if((y + h - 1) >= _height) h = _height - y; - - setAddrWindow(x, y, x+w-1, y+h-1); - - // uint8_t hi = color >> 8, lo = color; - - #if defined(USE_FAST_PINIO) && !defined (_VARIANT_ARDUINO_STM32_) - *dcport |= dcpinmask; - *csport &= ~cspinmask; - #else - digitalWrite(_dc, HIGH); - digitalWrite(_cs, LOW); - #endif - uint8_t linebuff[w*3+1]; - uint16_t pixels = w*h; - // uint16_t count = 0; - uint32_t count = 0; - for (uint16_t i = 0; i < h; i++) { - uint16_t pixcount = 0; - for (uint16_t o = 0; o < w; o++) { - uint8_t b1 = img[count]; - count++; - uint8_t b2 = img[count]; - count++; - uint16_t color = b1 << 8 | b2; - linebuff[pixcount] = (((color & 0xF800) >> 11)* 255) / 31; - pixcount++; - linebuff[pixcount] = (((color & 0x07E0) >> 5) * 255) / 63; - pixcount++; - linebuff[pixcount] = ((color & 0x001F)* 255) / 31; - pixcount++; - } // for row - #if defined (__STM32F1__) - SPI.dmaSend(linebuff, w*3); - #else - for(uint16_t b = 0; b < w*3; b++){ - spiwrite(linebuff[b]); - } - #endif - - }// for col - #if defined(USE_FAST_PINIO) && !defined (_VARIANT_ARDUINO_STM32_) - *csport |= cspinmask; - #else - digitalWrite(_cs, HIGH); - #endif - - if (hwSPI) spi_end(); -} -*/ - -void ILI9488::pushColor(uint16_t color) { - write16BitColor(color); - ILI9488_STOP -} - -#if 1 -void ILI9488::pushColors(uint16_t *data, uint16_t len, boolean first) { - uint16_t color; - uint8_t buff[len*3+1]; - uint16_t count = 0; - uint8_t lencount = len; - while(lencount--) { - color = *data++; - buff[count] = (((color & 0xF800) >> 11)* 255) / 31; - count++; - buff[count] = (((color & 0x07E0) >> 5) * 255) / 63; - count++; - buff[count] = ((color & 0x001F)* 255) / 31; - count++; - } - - for(uint16_t b = 0; b < len*3; b++){ - writedata(buff[b]); - } - - ILI9488_STOP - -} -#else - -void ILI9488::pushColors(uint16_t *data, uint8_t len, boolean first) { - uint16_t color; - - while (len--) { - write16BitColor(*data++); - } - ILI9488_STOP -} -#endif - -void ILI9488::write16BitColor(uint16_t color){ - // #if (__STM32F1__) - // uint8_t buff[4] = { - // (((color & 0xF800) >> 11)* 255) / 31, - // (((color & 0x07E0) >> 5) * 255) / 63, - // ((color & 0x001F)* 255) / 31 - // }; - // SPI.dmaSend(buff, 3); - // #else - uint8_t r = (color & 0xF800) >> 11; - uint8_t g = (color & 0x07E0) >> 5; - uint8_t b = color & 0x001F; - - r = (r * 255) / 31; - g = (g * 255) / 63; - b = (b * 255) / 31; - - #ifndef SWSPI_OPTMODE - writedata(r); - writedata(g); - writedata(b); - #else - if (_hwspi) { - writedata(r); - writedata(g); - writedata(b); - } else { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_cs); - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - - for(uint8_t bit = 0x80; bit; bit >>= 1) { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - if(r&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - } - - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - - for(uint8_t bit = 0x80; bit; bit >>= 1) { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - if(g&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - } - - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - - for(uint8_t bit = 0x80; bit; bit >>= 1) { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - if(b&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - } - WRITE_PERI_REG( PIN_OUT_SET, 1<<_cs); - } - - #endif - ILI9488_STOP -} - -void ILI9488::drawPixel(int16_t x, int16_t y, uint16_t color) { - - if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return; - - setAddrWindow_int(x,y,x+1,y+1); - write16BitColor(color); - ILI9488_STOP -} - -void ILI9488::drawFastVLine(int16_t x, int16_t y, int16_t h, - uint16_t color) { - - // Rudimentary clipping - if((x >= _width) || (y >= _height)) return; - - if((y+h-1) >= _height) - h = _height-y; - - setAddrWindow_int(x, y, x, y+h-1); - - uint8_t r = (color & 0xF800) >> 11; - uint8_t g = (color & 0x07E0) >> 5; - uint8_t b = color & 0x001F; - - r = (r * 255) / 31; - g = (g * 255) / 63; - b = (b * 255) / 31; - - while (h--) { - #ifndef SWSPI_OPTMODE - writedata(r); - writedata(g); - writedata(b); - #else - if (_hwspi) { - writedata(r); - writedata(g); - writedata(b); - } else { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_cs); - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - - for(uint8_t bit = 0x80; bit; bit >>= 1) { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - if(r&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - } - - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - - for(uint8_t bit = 0x80; bit; bit >>= 1) { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - if(g&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - } - - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - - for(uint8_t bit = 0x80; bit; bit >>= 1) { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - if(b&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - } - WRITE_PERI_REG( PIN_OUT_SET, 1<<_cs); - } - #endif - } - ILI9488_STOP -} - -void ILI9488::drawFastHLine(int16_t x, int16_t y, int16_t w, - uint16_t color) { - - // Rudimentary clipping - if((x >= _width) || (y >= _height)) return; - if((x+w-1) >= _width) w = _width-x; - - setAddrWindow_int(x, y, x+w-1, y); - - uint8_t r = (color & 0xF800) >> 11; - uint8_t g = (color & 0x07E0) >> 5; - uint8_t b = color & 0x001F; - - r = (r * 255) / 31; - g = (g * 255) / 63; - b = (b * 255) / 31; - - while (w--) { -#ifndef SWSPI_OPTMODE - writedata(r); - writedata(g); - writedata(b); -#else - if (_hwspi) { - writedata(r); - writedata(g); - writedata(b); - } else { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_cs); - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - - for(uint8_t bit = 0x80; bit; bit >>= 1) { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - if(r&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - } - - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - - for(uint8_t bit = 0x80; bit; bit >>= 1) { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - if(g&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - } - - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - - for(uint8_t bit = 0x80; bit; bit >>= 1) { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - if(b&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - } - WRITE_PERI_REG( PIN_OUT_SET, 1<<_cs); - } -#endif - } - ILI9488_STOP -} - -// this moves 460 kbytes -// now at 475 ms with 13,3 Mhz clock -void ILI9488::fillScreen(uint16_t color) { - //uint32_t time=millis(); - fillRect(0, 0, _width, _height, color); - //time=millis()-time; - //Serial.printf("time %d ms\n",time); - ILI9488_STOP -} - - -//#define WAIT_9BITS asm_nop_9bits(); -#define WAIT_9BITS -//#define WAIT_BEFORE while(*((uint32_t *)0x60000100)&SPI_USR); //waiting for spi module available -#define WAIT_SPI_READY while(READ_PERI_REG(SPI_CMD(1))&SPI_USR); - -//#define WAIT_SPI_READY - -//#define DIAG_PIN_SET WRITE_PERI_REG( PIN_OUT_SET, 1<<2); -//#define DIAG_PIN_CLR WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<2); -#define DIAG_PIN_SET -#define DIAG_PIN_CLR - -//#define WRITE_PERI_REG(addr, val) (*((volatile uint32_t *)ETS_UNCACHED_ADDR(addr))) = (uint32_t)(val) - - -// CMD 0x60000200-1*0x100 -// SPI_USER2 0x60000200-1*0x100 + 0x24 - -//#define WRITE_SPI_REG WRITE_PERI_REG(0x60000124, regvalue_r);SET_PERI_REG_MASK(0x60000100, SPI_USR); -// THIS TAKES 1 us => 80 cpu clock cycles !!!!!!!!!!!!!!!!!!!!!!!!!! -// probably the memw causes this delay -#define WRITE_SPI_REG(A) WRITE_PERI_REG(SPI_USER2(1), A); SET_PERI_REG_MASK(SPI_CMD(1), SPI_USR); - -//#define WRITE_SPI_REG(A) *((uint32_t *)0x60000124)=A; *((uint32_t *)0x60000100)|=SPI_USR; - -//#define WRITE_SPI_REG - - - -// extremely strange => if this code is merged into pack_rgb() the software crashes -// swap bytes -uint32_t ulswap(uint32_t data) { -union { - uint32_t l; - uint8_t b[4]; -} data_; - - data_.l = data; - // MSBFIRST Byte first - data = (data_.b[3] | (data_.b[2] << 8) | (data_.b[1] << 16) | (data_.b[0] << 24)); - return data; -} - -// pack RGB into uint32 -uint32_t pack_rgb(uint32_t r, uint32_t g, uint32_t b) { - uint32_t data; - data=r<<23; - data|=g<<14; - data|=b<<5; - data|=0b10000000010000000010000000000000; - return ulswap(data); -} - -#ifndef ESP32 -// fill a rectangle -void ILI9488::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { - - ILI9488_START - // rudimentary clipping (drawChar w/big text requires this) - if((x >= _width) || (y >= _height)) return; - if((x + w - 1) >= _width) w = _width - x; - if((y + h - 1) >= _height) h = _height - y; - - setAddrWindow_int(x, y, x+w-1, y+h-1); - //ILI9488_START - - uint8_t r = (color & 0xF800) >> 11; - uint8_t g = (color & 0x07E0) >> 5; - uint8_t b = color & 0x001F; - - r = (r * 255) / 31; - g = (g * 255) / 63; - b = (b * 255) / 31; - - uint32_t regvalue_r,regvalue_g,regvalue_b; - uint32_t data; - - if (_hwspi) { - // precalculate the register values for rgb - -#ifndef RGB_PACK_MODE - uint8_t bytetemp; - bytetemp=(r>>1)|0x80; - regvalue_r= ((8&SPI_USR_COMMAND_BITLEN)<>1)|0x80; - regvalue_g= ((8&SPI_USR_COMMAND_BITLEN)<>1)|0x80; - regvalue_b= ((8&SPI_USR_COMMAND_BITLEN)< MSBFIRST - SPI1U = SPIUMOSI; - SPI1C1 = 0; - data=pack_rgb(r,g,b); - -#endif - } - - for(y=h; y>0; y--) { - delay(0); - for(x=w; x>0; x--) { - -#ifndef SWSPI_OPTMODE - writedata(r); - writedata(g); - writedata(b); -#else - if (_hwspi) { - //noInterrupts(); -#ifdef RGB_PACK_MODE - while(SPI1CMD & SPIBUSY) {} - SPI1W0 = data; - SPI1CMD |= SPIBUSY; -#else - DIAG_PIN_CLR - WAIT_SPI_READY - DIAG_PIN_SET - - WRITE_SPI_REG(regvalue_r) - WAIT_9BITS - - DIAG_PIN_CLR - WAIT_SPI_READY - DIAG_PIN_SET - - WRITE_SPI_REG(regvalue_g) - WAIT_9BITS - - DIAG_PIN_CLR - WAIT_SPI_READY - DIAG_PIN_SET - - WRITE_SPI_REG(regvalue_b) - WAIT_9BITS - - //interrupts(); -#endif - } else { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_cs); - - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - - for(uint8_t bit = 0x80; bit; bit >>= 1) { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - if(r&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - } - - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - - for(uint8_t bit = 0x80; bit; bit >>= 1) { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - if(g&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - } - - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - - for(uint8_t bit = 0x80; bit; bit >>= 1) { - WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_sclk); - if(b&bit) WRITE_PERI_REG( PIN_OUT_SET, 1<<_mosi); - else WRITE_PERI_REG( PIN_OUT_CLEAR, 1<<_mosi); - WRITE_PERI_REG( PIN_OUT_SET, 1<<_sclk); - } - WRITE_PERI_REG( PIN_OUT_SET, 1<<_cs); - } - #endif - - } - - } -#ifdef RGB_PACK_MODE - // reinit old mode - while(SPI1CMD & SPIBUSY) {} - ILI9488_STOP - //spi_lcd_mode_init(); -#endif - -} -#else -// ESP32 -void ILI9488::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { - - // rudimentary clipping (drawChar w/big text requires this) - if((x >= _width) || (y >= _height)) return; - if((x + w - 1) >= _width) w = _width - x; - if((y + h - 1) >= _height) h = _height - y; - - setAddrWindow_int(x, y, x+w-1, y+h-1); - - uint8_t r = (color & 0xF800) >> 11; - uint8_t g = (color & 0x07E0) >> 5; - uint8_t b = color & 0x001F; - - r = (r * 255) / 31; - g = (g * 255) / 63; - b = (b * 255) / 31; - -#ifdef RGB_PACK_MODE - // init 27 bit mode - uint32_t data=pack_rgb(r,g,b); - REG_SET_BIT(SPI_USER_REG(3), SPI_USR_MOSI); - REG_WRITE(SPI_MOSI_DLEN_REG(3), 27 - 1); - uint32_t *dp=(uint32_t*)SPI_W0_REG(3); - digitalWrite( _cs, LOW); -#endif - - for(y=h; y>0; y--) { - for(x=w; x>0; x--) { - #ifndef RGB_PACK_MODE - writedata(r); - writedata(g); - writedata(b); - #else - while (REG_GET_FIELD(SPI_CMD_REG(3), SPI_USR)); - *dp=data; - REG_SET_BIT(SPI_CMD_REG(3), SPI_USR); - #endif - } - } - -#ifdef RGB_PACK_MODE - while (REG_GET_FIELD(SPI_CMD_REG(3), SPI_USR)); - digitalWrite( _cs, HIGH); -#endif - - ILI9488_STOP -} -#endif - - -// Pass 8-bit (each) R,G,B, get back 16-bit packed color -uint16_t ILI9488::color565(uint8_t r, uint8_t g, uint8_t b) { - return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); -} - - -#define MADCTL_MY 0x80 -#define MADCTL_MX 0x40 -#define MADCTL_MV 0x20 -#define MADCTL_ML 0x10 -#define MADCTL_RGB 0x00 -#define MADCTL_BGR 0x08 -#define MADCTL_MH 0x04 - -void ILI9488::setRotation(uint8_t m) { - - writecommand(ILI9488_MADCTL); - rotation = m % 4; // can't be higher than 3 - switch (rotation) { - case 0: - writedata(MADCTL_MX | MADCTL_BGR); - _width = ILI9488_TFTWIDTH; - _height = ILI9488_TFTHEIGHT; - break; - case 1: - writedata(MADCTL_MV | MADCTL_BGR); - _width = ILI9488_TFTHEIGHT; - _height = ILI9488_TFTWIDTH; - break; - case 2: - writedata(MADCTL_MY | MADCTL_BGR); - _width = ILI9488_TFTWIDTH; - _height = ILI9488_TFTHEIGHT; - break; - case 3: - writedata(MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR); - _width = ILI9488_TFTHEIGHT; - _height = ILI9488_TFTWIDTH; - break; - } - ILI9488_STOP -} - - -void ILI9488::invertDisplay(boolean i) { - writecommand(i ? ILI9488_INVON : ILI9488_INVOFF); - ILI9488_STOP -} diff --git a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/ILI9488.h b/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/ILI9488.h deleted file mode 100644 index bed25c5f8..000000000 --- a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/ILI9488.h +++ /dev/null @@ -1,174 +0,0 @@ -/*************************************************** - STM32 Support added by Jaret Burkett at OSHlab.com - - This is our library for the Adafruit ILI9488 Breakout and Shield - ----> http://www.adafruit.com/products/1651 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ - -#ifndef _ILI9488H_ -#define _ILI9488H_ - -#if ARDUINO >= 100 - #include "Arduino.h" - #include "Print.h" -#else - #include "WProgram.h" -#endif -#include -#ifdef __AVR - #include -#elif defined(ESP8266) - #include -#endif - -#ifdef ARDUINO_STM32_FEATHER -typedef volatile uint32 RwReg; -#endif -#if defined (__AVR__) || defined(TEENSYDUINO) || defined (__arm__) || defined (__STM32F1__) -#define USE_FAST_PINIO -#endif - -#define ILI9488_TFTWIDTH 320 -#define ILI9488_TFTHEIGHT 480 - -#define ILI9488_NOP 0x00 -#define ILI9488_SWRESET 0x01 -#define ILI9488_RDDID 0x04 -#define ILI9488_RDDST 0x09 - -#define ILI9488_SLPIN 0x10 -#define ILI9488_SLPOUT 0x11 -#define ILI9488_PTLON 0x12 -#define ILI9488_NORON 0x13 - -#define ILI9488_RDMODE 0x0A -#define ILI9488_RDMADCTL 0x0B -#define ILI9488_RDPIXFMT 0x0C -#define ILI9488_RDIMGFMT 0x0D -#define ILI9488_RDSELFDIAG 0x0F - -#define ILI9488_INVOFF 0x20 -#define ILI9488_INVON 0x21 -#define ILI9488_GAMMASET 0x26 -#define ILI9488_DISPOFF 0x28 -#define ILI9488_DISPON 0x29 - -#define ILI9488_CASET 0x2A -#define ILI9488_PASET 0x2B -#define ILI9488_RAMWR 0x2C -#define ILI9488_RAMRD 0x2E - -#define ILI9488_PTLAR 0x30 -#define ILI9488_MADCTL 0x36 -#define ILI9488_PIXFMT 0x3A - -#define ILI9488_WRCTRLD 0x53 -#define ILI9488_CAPC9 0xCF - -#define ILI9488_FRMCTR1 0xB1 -#define ILI9488_FRMCTR2 0xB2 -#define ILI9488_FRMCTR3 0xB3 -#define ILI9488_INVCTR 0xB4 -#define ILI9488_DFUNCTR 0xB6 - -#define ILI9488_PWCTR1 0xC0 -#define ILI9488_PWCTR2 0xC1 -#define ILI9488_PWCTR3 0xC2 -#define ILI9488_PWCTR4 0xC3 -#define ILI9488_PWCTR5 0xC4 -#define ILI9488_VMCTR1 0xC5 -#define ILI9488_VMCTR2 0xC7 - -#define ILI9488_RDID1 0xDA -#define ILI9488_RDID2 0xDB -#define ILI9488_RDID3 0xDC -#define ILI9488_RDID4 0xDD - -#define ILI9488_GMCTRP1 0xE0 -#define ILI9488_GMCTRN1 0xE1 -/* -#define ILI9488_PWCTR6 0xFC - -*/ - -#define PIN_OUT_SET 0x60000304 -#define PIN_OUT_CLEAR 0x60000308 - -// Color definitions -#define ILI9488_BLACK 0x0000 /* 0, 0, 0 */ -#define ILI9488_NAVY 0x000F /* 0, 0, 128 */ -#define ILI9488_DARKGREEN 0x03E0 /* 0, 128, 0 */ -#define ILI9488_DARKCYAN 0x03EF /* 0, 128, 128 */ -#define ILI9488_MAROON 0x7800 /* 128, 0, 0 */ -#define ILI9488_PURPLE 0x780F /* 128, 0, 128 */ -#define ILI9488_OLIVE 0x7BE0 /* 128, 128, 0 */ -#define ILI9488_LIGHTGREY 0xC618 /* 192, 192, 192 */ -#define ILI9488_DARKGREY 0x7BEF /* 128, 128, 128 */ -#define ILI9488_BLUE 0x001F /* 0, 0, 255 */ -#define ILI9488_GREEN 0x07E0 /* 0, 255, 0 */ -#define ILI9488_CYAN 0x07FF /* 0, 255, 255 */ -#define ILI9488_RED 0xF800 /* 255, 0, 0 */ -#define ILI9488_MAGENTA 0xF81F /* 255, 0, 255 */ -#define ILI9488_YELLOW 0xFFE0 /* 255, 255, 0 */ -#define ILI9488_WHITE 0xFFFF /* 255, 255, 255 */ -#define ILI9488_ORANGE 0xFD20 /* 255, 165, 0 */ -#define ILI9488_GREENYELLOW 0xAFE5 /* 173, 255, 47 */ -#define ILI9488_PINK 0xF81F - - - - -class ILI9488 : public Renderer { - - public: - - ILI9488(int8_t cs,int8_t mosi,int8_t sclk,int8_t bp); - - void begin(void); - void DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font); - void setAddrWindow_int(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); - void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); - void setScrollArea(uint16_t topFixedArea, uint16_t bottomFixedArea); - void scroll(uint16_t pixels); - void pushColor(uint16_t color); - void pushColors(uint16_t *data, uint16_t len, boolean first); - //void drawImage(const uint8_t* img, uint16_t x, uint16_t y, uint16_t w, uint16_t h); - void fillScreen(uint16_t color); - void drawPixel(int16_t x, int16_t y, uint16_t color); - void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); - void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); - void fillRect(int16_t x, int16_t y, int16_t w, int16_t h,uint16_t color); - void setRotation(uint8_t r); - void invertDisplay(boolean i); - uint16_t color565(uint8_t r, uint8_t g, uint8_t b); - uint16_t GetColorFromIndex(uint8_t index); - void DisplayOnff(int8_t on); - void writecommand(uint8_t c); - void writedata(uint8_t d); - void write16BitColor(uint16_t color); - void commandList(uint8_t *addr); - void hw_spi_init(); - void dim(uint8_t contrast); - - private: - uint8_t tabcolor; - uint8_t dimmer; - void fastSPIwrite(uint8_t d,uint8_t dc); - void spi_lcd_mode_init(void); - void start(void); - void stop(void); - int8_t _cs, _mosi, _sclk, _bp, _hwspi; - -}; - -#endif diff --git a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/README.md b/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/README.md deleted file mode 100644 index fd203455b..000000000 --- a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/README.md +++ /dev/null @@ -1,8 +0,0 @@ -### ILI9488 Arduino Library -This library is for support for the 320x480 tft controller over 4 wire SPI. It is based heavily on the [Adafruit_ILI9341](https://github.com/adafruit/Adafruit_ILI9341) library and is designed to work with the [Adafruit_GFX library](https://github.com/adafruit/Adafruit-GFX-Library). - -I have made some heavy modifications, as the typical Adafruit TFT libraries are designed to work with 16bit color (RGB565), and the ILI9488 can only do 24bit (RGB888) color in 4 wire SPI mode. You can still use the library EXACTLY like you would for 16bit mode color, the colors are converted before sending to the display. What this means is, things will be slower than normal. Not only do you have to write twice as many pixels as a normal 240x320 display, 153,600px (320x480) vs 76,800px (240x320), but you also have to do a lightweight conversion on each color, and write 3 bytes vs 2bytes per pixel. - -For this reason, I do not recommend an AVR based Arduino for this library, although it will still work. I highly recommend a faster microcontroller based on ARM such as the Teensy, [STM32duino](https://github.com/rogerclarkmelbourne/Arduino_STM32), Arduino Zero, or the Arduing Due. - -On the STM32duino, DMA is supported and is therefore much faster. \ No newline at end of file diff --git a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/examples/graphicstest/graphicstest.ino b/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/examples/graphicstest/graphicstest.ino deleted file mode 100644 index 30b0cbd9a..000000000 --- a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/examples/graphicstest/graphicstest.ino +++ /dev/null @@ -1,350 +0,0 @@ -/*************************************************** - This is our GFX example for the Adafruit ILI9488 Breakout and Shield - ----> http://www.adafruit.com/products/1651 - - Check out the links above for our tutorials and wiring diagrams - These displays use SPI to communicate, 4 or 5 pins are required to - interface (RST is optional) - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by Limor Fried/Ladyada for Adafruit Industries. - MIT license, all text above must be included in any redistribution - ****************************************************/ - - -#include "SPI.h" -#include -#include - -#define TFT_CS PA1 -#define TFT_DC PB3 -#define TFT_LED PB0 -#define TFT_RST PB4 - -// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC -ILI9488 tft = ILI9488(TFT_CS, TFT_DC, TFT_RST); -// If using the breakout, change pins as desired -//Adafruit_ILI9488 tft = Adafruit_ILI9488(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO); - -void setup() { - Serial.begin(9600); - Serial.println("ILI9488 Test!"); - - tft.begin(); - - // read diagnostics (optional but can help debug problems) - uint8_t x = tft.readcommand8(ILI9488_RDMODE); - Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX); - x = tft.readcommand8(ILI9488_RDMADCTL); - Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX); - x = tft.readcommand8(ILI9488_RDPIXFMT); - Serial.print("Pixel Format: 0x"); Serial.println(x, HEX); - x = tft.readcommand8(ILI9488_RDIMGFMT); - Serial.print("Image Format: 0x"); Serial.println(x, HEX); - x = tft.readcommand8(ILI9488_RDSELFDIAG); - Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); - - Serial.println(F("Benchmark Time (microseconds)")); - - Serial.print(F("Screen fill ")); - Serial.println(testFillScreen()); - delay(500); - - Serial.print(F("Text ")); - Serial.println(testText()); - delay(3000); - - Serial.print(F("Lines ")); - Serial.println(testLines(ILI9488_CYAN)); - delay(500); - - Serial.print(F("Horiz/Vert Lines ")); - Serial.println(testFastLines(ILI9488_RED, ILI9488_BLUE)); - delay(500); - - Serial.print(F("Rectangles (outline) ")); - Serial.println(testRects(ILI9488_GREEN)); - delay(500); - - Serial.print(F("Rectangles (filled) ")); - Serial.println(testFilledRects(ILI9488_YELLOW, ILI9488_MAGENTA)); - delay(500); - - Serial.print(F("Circles (filled) ")); - Serial.println(testFilledCircles(10, ILI9488_MAGENTA)); - - Serial.print(F("Circles (outline) ")); - Serial.println(testCircles(10, ILI9488_WHITE)); - delay(500); - - Serial.print(F("Triangles (outline) ")); - Serial.println(testTriangles()); - delay(500); - - Serial.print(F("Triangles (filled) ")); - Serial.println(testFilledTriangles()); - delay(500); - - Serial.print(F("Rounded rects (outline) ")); - Serial.println(testRoundRects()); - delay(500); - - Serial.print(F("Rounded rects (filled) ")); - Serial.println(testFilledRoundRects()); - delay(500); - - Serial.println(F("Done!")); - -} - - -void loop(void) { - for(uint8_t rotation=0; rotation<4; rotation++) { - tft.setRotation(rotation); - testText(); - delay(1000); - } -} - -unsigned long testFillScreen() { - unsigned long start = micros(); - tft.fillScreen(ILI9488_BLACK); - tft.fillScreen(ILI9488_RED); - tft.fillScreen(ILI9488_GREEN); - tft.fillScreen(ILI9488_BLUE); - tft.fillScreen(ILI9488_BLACK); - return micros() - start; -} - -unsigned long testText() { - tft.fillScreen(ILI9488_BLACK); - unsigned long start = micros(); - tft.setCursor(0, 0); - tft.setTextColor(ILI9488_WHITE); tft.setTextSize(1); - tft.println("Hello World!"); - tft.setTextColor(ILI9488_YELLOW); tft.setTextSize(2); - tft.println(1234.56); - tft.setTextColor(ILI9488_RED); tft.setTextSize(3); - tft.println(0xDEADBEEF, HEX); - tft.println(); - tft.setTextColor(ILI9488_GREEN); - tft.setTextSize(5); - tft.println("Groop"); - tft.setTextSize(2); - tft.println("I implore thee,"); - tft.setTextSize(1); - tft.println("my foonting turlingdromes."); - tft.println("And hooptiously drangle me"); - tft.println("with crinkly bindlewurdles,"); - tft.println("Or I will rend thee"); - tft.println("in the gobberwarts"); - tft.println("with my blurglecruncheon,"); - tft.println("see if I don't!"); - return micros() - start; -} - -unsigned long testLines(uint16_t color) { - unsigned long start, t; - int x1, y1, x2, y2, - w = tft.width(), - h = tft.height(); - - tft.fillScreen(ILI9488_BLACK); - - x1 = y1 = 0; - y2 = h - 1; - start = micros(); - for(x2=0; x20; i-=6) { - i2 = i / 2; - start = micros(); - tft.fillRect(cx-i2, cy-i2, i, i, color1); - t += micros() - start; - // Outlines are not included in timing results - tft.drawRect(cx-i2, cy-i2, i, i, color2); - } - - return t; -} - -unsigned long testFilledCircles(uint8_t radius, uint16_t color) { - unsigned long start; - int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2; - - tft.fillScreen(ILI9488_BLACK); - start = micros(); - for(x=radius; x10; i-=5) { - start = micros(); - tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, - tft.color565(0, i, i)); - t += micros() - start; - tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i, - tft.color565(i, i, 0)); - } - - return t; -} - -unsigned long testRoundRects() { - unsigned long start; - int w, i, i2, - cx = tft.width() / 2 - 1, - cy = tft.height() / 2 - 1; - - tft.fillScreen(ILI9488_BLACK); - w = min(tft.width(), tft.height()); - start = micros(); - for(i=0; i20; i-=6) { - i2 = i / 2; - tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0)); - } - - return micros() - start; -} diff --git a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/keywords.txt b/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/keywords.txt deleted file mode 100644 index 44c83b06f..000000000 --- a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/keywords.txt +++ /dev/null @@ -1,30 +0,0 @@ -####################################### -# Syntax Coloring Map -####################################### - -####################################### -# Datatypes (KEYWORD1) -####################################### - -ILI9488 KEYWORD1 - - -####################################### -# Methods and Functions (KEYWORD2) -####################################### - -setRotation KEYWORD2 -setAddrWindow KEYWORD2 -pushColor KEYWORD2 -drawPixel KEYWORD2 -drawFastVLine KEYWORD2 -drawFastHLine KEYWORD2 -fillRect KEYWORD2 -setRotation KEYWORD2 -setRotation KEYWORD2 -height KEYWORD2 -width KEYWORD2 -invertDisplay KEYWORD2 -drawImage KEYWORD2 -setScrollArea KEYWORD2 -scroll KEYWORD2 diff --git a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/library.properties b/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/library.properties deleted file mode 100644 index a8ae043a7..000000000 --- a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=ILI9488 -version=1.0.2 -author=Jaret Burkett -maintainer=Jaret Burkett -sentence=Library for ILI9488 displays -paragraph=Library for ILI9488 displays -category=Display -url=https://github.com/jaretburkett/ILI9488 -architectures=* diff --git a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/spi_register.h b/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/spi_register.h deleted file mode 100644 index 340559ae1..000000000 --- a/lib/lib_display/JaretBurkett_ILI9488-gemu-1.0/spi_register.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2010 - 2011 Espressif System - * - */ - -#ifndef SPI_REGISTER_H_INCLUDED -#define SPI_REGISTER_H_INCLUDED - -#define REG_SPI_BASE(i) (0x60000200-i*0x100) -#define SPI_CMD(i) (REG_SPI_BASE(i) + 0x0) -#define SPI_USR (BIT(18)) - -#define SPI_ADDR(i) (REG_SPI_BASE(i) + 0x4) - -#define SPI_CTRL(i) (REG_SPI_BASE(i) + 0x8) -#define SPI_WR_BIT_ORDER (BIT(26)) -#define SPI_RD_BIT_ORDER (BIT(25)) -#define SPI_QIO_MODE (BIT(24)) -#define SPI_DIO_MODE (BIT(23)) -#define SPI_QOUT_MODE (BIT(20)) -#define SPI_DOUT_MODE (BIT(14)) -#define SPI_FASTRD_MODE (BIT(13)) - - - -#define SPI_RD_STATUS(i) (REG_SPI_BASE(i) + 0x10) - -#define SPI_CTRL2(i) (REG_SPI_BASE(i) + 0x14) - -#define SPI_CS_DELAY_NUM 0x0000000F -#define SPI_CS_DELAY_NUM_S 28 -#define SPI_CS_DELAY_MODE 0x00000003 -#define SPI_CS_DELAY_MODE_S 26 -#define SPI_MOSI_DELAY_NUM 0x00000007 -#define SPI_MOSI_DELAY_NUM_S 23 -#define SPI_MOSI_DELAY_MODE 0x00000003 -#define SPI_MOSI_DELAY_MODE_S 21 -#define SPI_MISO_DELAY_NUM 0x00000007 -#define SPI_MISO_DELAY_NUM_S 18 -#define SPI_MISO_DELAY_MODE 0x00000003 -#define SPI_MISO_DELAY_MODE_S 16 -#define SPI_CK_OUT_HIGH_MODE 0x0000000F -#define SPI_CK_OUT_HIGH_MODE_S 12 -#define SPI_CK_OUT_LOW_MODE 0x0000000F -#define SPI_CK_OUT_LOW_MODE_S 8 - -#define SPI_CLOCK(i) (REG_SPI_BASE(i) + 0x18) -#define SPI_CLK_EQU_SYSCLK (BIT(31)) -#define SPI_CLKDIV_PRE 0x00001FFF -#define SPI_CLKDIV_PRE_S 18 -#define SPI_CLKCNT_N 0x0000003F -#define SPI_CLKCNT_N_S 12 -#define SPI_CLKCNT_H 0x0000003F -#define SPI_CLKCNT_H_S 6 -#define SPI_CLKCNT_L 0x0000003F -#define SPI_CLKCNT_L_S 0 - -#define SPI_USER(i) (REG_SPI_BASE(i) + 0x1C) -#define SPI_USR_COMMAND (BIT(31)) -#define SPI_USR_ADDR (BIT(30)) -#define SPI_USR_DUMMY (BIT(29)) -#define SPI_USR_MISO (BIT(28)) -#define SPI_USR_MOSI (BIT(27)) - -#define SPI_USR_MOSI_HIGHPART (BIT(25)) -#define SPI_USR_MISO_HIGHPART (BIT(24)) - - -#define SPI_SIO (BIT(16)) -#define SPI_FWRITE_QIO (BIT(15)) -#define SPI_FWRITE_DIO (BIT(14)) -#define SPI_FWRITE_QUAD (BIT(13)) -#define SPI_FWRITE_DUAL (BIT(12)) -#define SPI_WR_BYTE_ORDER (BIT(11)) -#define SPI_RD_BYTE_ORDER (BIT(10)) -#define SPI_CK_OUT_EDGE (BIT(7)) -#define SPI_CK_I_EDGE (BIT(6)) -#define SPI_CS_SETUP (BIT(5)) -#define SPI_CS_HOLD (BIT(4)) -#define SPI_FLASH_MODE (BIT(2)) -#define SPI_DOUTDIN (BIT(0)) - -#define SPI_USER1(i) (REG_SPI_BASE(i) + 0x20) -#define SPI_USR_ADDR_BITLEN 0x0000003F -#define SPI_USR_ADDR_BITLEN_S 26 -#define SPI_USR_MOSI_BITLEN 0x000001FF -#define SPI_USR_MOSI_BITLEN_S 17 -#define SPI_USR_MISO_BITLEN 0x000001FF -#define SPI_USR_MISO_BITLEN_S 8 - -#define SPI_USR_DUMMY_CYCLELEN 0x000000FF -#define SPI_USR_DUMMY_CYCLELEN_S 0 - -#define SPI_USER2(i) (REG_SPI_BASE(i) + 0x24) -#define SPI_USR_COMMAND_BITLEN 0x0000000F -#define SPI_USR_COMMAND_BITLEN_S 28 -#define SPI_USR_COMMAND_VALUE 0x0000FFFF -#define SPI_USR_COMMAND_VALUE_S 0 - -#define SPI_WR_STATUS(i) (REG_SPI_BASE(i) + 0x28) -#define SPI_PIN(i) (REG_SPI_BASE(i) + 0x2C) -#define SPI_CS2_DIS (BIT(2)) -#define SPI_CS1_DIS (BIT(1)) -#define SPI_CS0_DIS (BIT(0)) -#define SPI_IDLE_EDGE (BIT(29)) - -#define SPI_SLAVE(i) (REG_SPI_BASE(i) + 0x30) -#define SPI_SYNC_RESET (BIT(31)) -#define SPI_SLAVE_MODE (BIT(30)) -#define SPI_SLV_WR_RD_BUF_EN (BIT(29)) -#define SPI_SLV_WR_RD_STA_EN (BIT(28)) -#define SPI_SLV_CMD_DEFINE (BIT(27)) -#define SPI_TRANS_CNT 0x0000000F -#define SPI_TRANS_CNT_S 23 -#define SPI_TRANS_DONE_EN (BIT(9)) -#define SPI_SLV_WR_STA_DONE_EN (BIT(8)) -#define SPI_SLV_RD_STA_DONE_EN (BIT(7)) -#define SPI_SLV_WR_BUF_DONE_EN (BIT(6)) -#define SPI_SLV_RD_BUF_DONE_EN (BIT(5)) - - - -#define SLV_SPI_INT_EN 0x0000001f -#define SLV_SPI_INT_EN_S 5 - -#define SPI_TRANS_DONE (BIT(4)) -#define SPI_SLV_WR_STA_DONE (BIT(3)) -#define SPI_SLV_RD_STA_DONE (BIT(2)) -#define SPI_SLV_WR_BUF_DONE (BIT(1)) -#define SPI_SLV_RD_BUF_DONE (BIT(0)) - -#define SPI_SLAVE1(i) (REG_SPI_BASE(i) + 0x34) -#define SPI_SLV_STATUS_BITLEN 0x0000001F -#define SPI_SLV_STATUS_BITLEN_S 27 -#define SPI_SLV_BUF_BITLEN 0x000001FF -#define SPI_SLV_BUF_BITLEN_S 16 -#define SPI_SLV_RD_ADDR_BITLEN 0x0000003F -#define SPI_SLV_RD_ADDR_BITLEN_S 10 -#define SPI_SLV_WR_ADDR_BITLEN 0x0000003F -#define SPI_SLV_WR_ADDR_BITLEN_S 4 - -#define SPI_SLV_WRSTA_DUMMY_EN (BIT(3)) -#define SPI_SLV_RDSTA_DUMMY_EN (BIT(2)) -#define SPI_SLV_WRBUF_DUMMY_EN (BIT(1)) -#define SPI_SLV_RDBUF_DUMMY_EN (BIT(0)) - - - -#define SPI_SLAVE2(i) (REG_SPI_BASE(i) + 0x38) -#define SPI_SLV_WRBUF_DUMMY_CYCLELEN 0X000000FF -#define SPI_SLV_WRBUF_DUMMY_CYCLELEN_S 24 -#define SPI_SLV_RDBUF_DUMMY_CYCLELEN 0X000000FF -#define SPI_SLV_RDBUF_DUMMY_CYCLELEN_S 16 -#define SPI_SLV_WRSTR_DUMMY_CYCLELEN 0X000000FF -#define SPI_SLV_WRSTR_DUMMY_CYCLELEN_S 8 -#define SPI_SLV_RDSTR_DUMMY_CYCLELEN 0x000000FF -#define SPI_SLV_RDSTR_DUMMY_CYCLELEN_S 0 - -#define SPI_SLAVE3(i) (REG_SPI_BASE(i) + 0x3C) -#define SPI_SLV_WRSTA_CMD_VALUE 0x000000FF -#define SPI_SLV_WRSTA_CMD_VALUE_S 24 -#define SPI_SLV_RDSTA_CMD_VALUE 0x000000FF -#define SPI_SLV_RDSTA_CMD_VALUE_S 16 -#define SPI_SLV_WRBUF_CMD_VALUE 0x000000FF -#define SPI_SLV_WRBUF_CMD_VALUE_S 8 -#define SPI_SLV_RDBUF_CMD_VALUE 0x000000FF -#define SPI_SLV_RDBUF_CMD_VALUE_S 0 - -#define SPI_W0(i) (REG_SPI_BASE(i) +0x40) -#define SPI_W1(i) (REG_SPI_BASE(i) +0x44) -#define SPI_W2(i) (REG_SPI_BASE(i) +0x48) -#define SPI_W3(i) (REG_SPI_BASE(i) +0x4C) -#define SPI_W4(i) (REG_SPI_BASE(i) +0x50) -#define SPI_W5(i) (REG_SPI_BASE(i) +0x54) -#define SPI_W6(i) (REG_SPI_BASE(i) +0x58) -#define SPI_W7(i) (REG_SPI_BASE(i) +0x5C) -#define SPI_W8(i) (REG_SPI_BASE(i) +0x60) -#define SPI_W9(i) (REG_SPI_BASE(i) +0x64) -#define SPI_W10(i) (REG_SPI_BASE(i) +0x68) -#define SPI_W11(i) (REG_SPI_BASE(i) +0x6C) -#define SPI_W12(i) (REG_SPI_BASE(i) +0x70) -#define SPI_W13(i) (REG_SPI_BASE(i) +0x74) -#define SPI_W14(i) (REG_SPI_BASE(i) +0x78) -#define SPI_W15(i) (REG_SPI_BASE(i) +0x7C) - -#define SPI_EXT3(i) (REG_SPI_BASE(i) + 0xFC) -#define SPI_INT_HOLD_ENA 0x00000003 -#define SPI_INT_HOLD_ENA_S 0 -#endif // SPI_REGISTER_H_INCLUDED diff --git a/lib/lib_display/UDisplay/uDisplay.cpp b/lib/lib_display/UDisplay/uDisplay.cpp index aa2dae903..6f48d5796 100755 --- a/lib/lib_display/UDisplay/uDisplay.cpp +++ b/lib/lib_display/UDisplay/uDisplay.cpp @@ -343,6 +343,7 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { Serial.printf("SPED: %d\n", spi_speed*1000000); Serial.printf("Pixels: %d\n", col_mode); Serial.printf("SaMode: %d\n", sa_mode); + Serial.printf("DMA-Mode: %d\n", lvgl_param.use_dma); Serial.printf("opts: %02x,%02x,%02x\n", saw_3, dim_op, startline); diff --git a/lib/lib_display/UDisplay/uDisplay.h b/lib/lib_display/UDisplay/uDisplay.h index 8ce012bf5..3dbc5aed7 100755 --- a/lib/lib_display/UDisplay/uDisplay.h +++ b/lib/lib_display/UDisplay/uDisplay.h @@ -68,10 +68,12 @@ enum uColorType { uCOLOR_BW, uCOLOR_COLOR }; #define SPI_BEGIN_TRANSACTION if (spi_nr <= 2) beginTransaction(spiSettings); #define SPI_END_TRANSACTION if (spi_nr <= 2) endTransaction(); -#define SPI_CS_LOW if (spi_cs >= 0) GPIO_CLR(spi_cs); -#define SPI_CS_HIGH if (spi_cs >= 0) GPIO_SET(spi_cs); -#define SPI_DC_LOW if (spi_dc >= 0) GPIO_CLR(spi_dc); -#define SPI_DC_HIGH if (spi_dc >= 0) GPIO_SET(spi_dc); + +#define SPI_CS_LOW if (spi_cs >= 0) GPIO_CLR_SLOW(spi_cs); +#define SPI_CS_HIGH if (spi_cs >= 0) GPIO_SET_SLOW(spi_cs); +#define SPI_DC_LOW if (spi_dc >= 0) GPIO_CLR_SLOW(spi_dc); +#define SPI_DC_HIGH if (spi_dc >= 0) GPIO_SET_SLOW(spi_dc); + #define ESP32_PWM_CHANNEL 1 diff --git a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.h b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.h index 1be54ff5f..3c947b5ca 100644 --- a/lib/lib_div/LibTeleinfo/src/LibTeleinfo.h +++ b/lib/lib_div/LibTeleinfo/src/LibTeleinfo.h @@ -149,6 +149,7 @@ class TInfo uint8_t valuesDump(void); char * valueGet(char * name, char * value); char * valueGet_P(const char * name, char * value); + int labelCount(); boolean listDelete(); unsigned char calcChecksum(char *etiquette, char *valeur, char *horodate=NULL) ; @@ -157,7 +158,6 @@ class TInfo ValueList * valueAdd (char * name, char * value, uint8_t checksum, uint8_t * flags, char * horodate=NULL); boolean valueRemove (char * name); boolean valueRemoveFlagged(uint8_t flags); - int labelCount(); uint32_t horodate2Timestamp( char * pdate) ; void customLabel( char * plabel, char * pvalue, uint8_t * pflags) ; ValueList * checkLine(char * pline) ; diff --git a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp index ff87d3112..6f66915f3 100755 --- a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp +++ b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.cpp @@ -204,6 +204,8 @@ void WiFiClientSecure_light::_clear() { _ta_P = nullptr; _ta_size = 0; _max_thunkstack_use = 0; + _alpn_names = nullptr; + _alpn_num = 0; } // Constructor @@ -949,8 +951,6 @@ extern "C" { // we support only P256 EC curve for AWS IoT, no EC curve for Letsencrypt unless forced br_ssl_engine_set_ec(&cc->eng, &br_ec_p256_m15); // TODO #endif - static const char * alpn_mqtt = "mqtt"; - br_ssl_engine_set_protocol_names(&cc->eng, &alpn_mqtt, 1); } } @@ -983,6 +983,9 @@ bool WiFiClientSecure_light::_connectSSL(const char* hostName) { _eng = &_sc->eng; // Allocation/deallocation taken care of by the _sc shared_ptr br_ssl_client_base_init(_sc.get()); + if (_alpn_names && _alpn_num > 0) { + br_ssl_engine_set_protocol_names(_eng, _alpn_names, _alpn_num); + } // ============================================================ // Allocatte and initialize Decoder Context diff --git a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.h b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.h index d0ff43407..3736749ab 100755 --- a/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.h +++ b/lib/lib_ssl/tls_mini/src/WiFiClientSecureLightBearSSL.h @@ -93,6 +93,12 @@ class WiFiClientSecure_light : public WiFiClient { void setTrustAnchor(const br_x509_trust_anchor *ta, size_t ta_size); + void setALPN(const char **names, size_t num) { + // set ALPN extensions, used mostly by AWS IoT on port 443. Need to be static pointers + _alpn_names = names; + _alpn_num = num; + } + // Sets the requested buffer size for transmit and receive void setBufferSizes(int recv, int xmit); @@ -165,6 +171,10 @@ class WiFiClientSecure_light : public WiFiClient { // record the maximum use of ThunkStack for monitoring size_t _max_thunkstack_use; + // ALPN + const char ** _alpn_names; + size_t _alpn_num; + }; #define ERR_OOM -1000 @@ -237,6 +247,44 @@ class WiFiClientSecure_light : public WiFiClient { // #define BR_ERR_X509_WEAK_PUBLIC_KEY 60 // #define BR_ERR_X509_NOT_TRUSTED 62 +// Alert types for TLSContentType.ALERT messages +// See RFC 8466, section B.2 + +// CLOSE_NOTIFY = 0 +// UNEXPECTED_MESSAGE = 10 +// BAD_RECORD_MAC = 20 +// DECRYPTION_FAILED = 21 +// RECORD_OVERFLOW = 22 +// DECOMPRESSION_FAILURE = 30 +// HANDSHAKE_FAILURE = 40 +// NO_CERTIFICATE = 41 +// BAD_CERTIFICATE = 42 +// UNSUPPORTED_CERTIFICATE = 43 +// CERTIFICATE_REVOKED = 44 +// CERTIFICATE_EXPIRED = 45 +// CERTIFICATE_UNKNOWN = 46 +// ILLEGAL_PARAMETER = 47 +// UNKNOWN_CA = 48 +// ACCESS_DENIED = 49 +// DECODE_ERROR = 50 +// DECRYPT_ERROR = 51 +// EXPORT_RESTRICTION = 60 +// PROTOCOL_VERSION = 70 +// INSUFFICIENT_SECURITY = 71 +// INTERNAL_ERROR = 80 +// INAPPROPRIATE_FALLBACK = 86 +// USER_CANCELED = 90 +// NO_RENEGOTIATION = 100 +// MISSING_EXTENSION = 109 +// UNSUPPORTED_EXTENSION = 110 +// CERTIFICATE_UNOBTAINABLE = 111 +// UNRECOGNIZED_NAME = 112 +// BAD_CERTIFICATE_STATUS_RESPONSE = 113 +// BAD_CERTIFICATE_HASH_VALUE = 114 +// UNKNOWN_PSK_IDENTITY = 115 +// CERTIFICATE_REQUIRED = 116 +// NO_APPLICATION_PROTOCOL = 120 + }; #endif // USE_TLS diff --git a/lib/libesp32/Berry-HttpClientLight/src/HTTPUpdateLight.cpp b/lib/libesp32/Berry-HttpClientLight/src/HTTPUpdateLight.cpp new file mode 100644 index 000000000..694502ea5 --- /dev/null +++ b/lib/libesp32/Berry-HttpClientLight/src/HTTPUpdateLight.cpp @@ -0,0 +1,471 @@ +/** + * + * @file HTTPUpdate.cpp based om ESP8266HTTPUpdate.cpp + * @date 16.10.2018 + * @author Markus Sattler + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the ESP32 Http Updater. + * + * 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 + * + */ + +#include "HTTPUpdateLight.h" +#include + +#include +#include // get running partition + +// 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}; + +// To do extern "C" uint32_t _SPIFFS_start; +// To do extern "C" uint32_t _SPIFFS_end; + +HTTPUpdateLight::HTTPUpdateLight(void) + : _httpClientTimeout(8000), _ledPin(-1) +{ + _followRedirects = HTTPC_STRICT_FOLLOW_REDIRECTS; +} + +HTTPUpdateLight::HTTPUpdateLight(int httpClientTimeout) + : _httpClientTimeout(httpClientTimeout), _ledPin(-1) +{ + _followRedirects = HTTPC_STRICT_FOLLOW_REDIRECTS; +} + +HTTPUpdateLight::~HTTPUpdateLight(void) +{ +} + +// HTTPUpdateResult HTTPUpdateLight::update(WiFiClient& client, const String& url, const String& currentVersion) +// { +// HTTPClient http; +// if(!http.begin(client, url)) +// { +// return HTTP_UPDATE_FAILED; +// } +// return handleUpdate(http, currentVersion, false); +// } + +// HTTPUpdateResult HTTPUpdateLight::updateSpiffs(HTTPClient& httpClient, const String& currentVersion) +// { +// return handleUpdate(httpClient, currentVersion, true); +// } + +// HTTPUpdateResult HTTPUpdateLight::updateSpiffs(WiFiClient& client, const String& url, const String& currentVersion) +// { +// HTTPClient http; +// if(!http.begin(client, url)) +// { +// return HTTP_UPDATE_FAILED; +// } +// return handleUpdate(http, currentVersion, true); +// } + +HTTPUpdateResult HTTPUpdateLight::update(HTTPClientLight& httpClient, + const String& currentVersion) +{ + return handleUpdate(httpClient, currentVersion, false); +} + +// HTTPUpdateResult HTTPUpdateLight::update(WiFiClient& client, const String& host, uint16_t port, const String& uri, +// const String& currentVersion) +// { +// HTTPClient http; +// if(!http.begin(client, host, port, uri)) +// { +// return HTTP_UPDATE_FAILED; +// } +// return handleUpdate(http, currentVersion, false); +// } + +/** + * return error code as int + * @return int error code + */ +int HTTPUpdateLight::getLastError(void) +{ + return _lastError; +} + +/** + * return error code as String + * @return String error + */ +String HTTPUpdateLight::getLastErrorString(void) +{ + + if(_lastError == 0) { + return String(); // no error + } + + // error from Update class + if(_lastError > 0) { + StreamString error; + Update.printError(error); + error.trim(); // remove line ending + return String("Update error: ") + error; + } + + // error from http client + if(_lastError > -100) { + return String("HTTP error: ") + HTTPClientLight::errorToString(_lastError); + } + + switch(_lastError) { + case HTTP_UE_TOO_LESS_SPACE: + return "Not Enough space"; + case HTTP_UE_SERVER_NOT_REPORT_SIZE: + return "Server Did Not Report Size"; + case HTTP_UE_SERVER_FILE_NOT_FOUND: + return "File Not Found (404)"; + case HTTP_UE_SERVER_FORBIDDEN: + return "Forbidden (403)"; + case HTTP_UE_SERVER_WRONG_HTTP_CODE: + return "Wrong HTTP Code"; + case HTTP_UE_SERVER_FAULTY_MD5: + return "Wrong MD5"; + case HTTP_UE_BIN_VERIFY_HEADER_FAILED: + return "Verify Bin Header Failed"; + case HTTP_UE_BIN_FOR_WRONG_FLASH: + return "New Binary Does Not Fit Flash Size"; + case HTTP_UE_NO_PARTITION: + return "Partition Could Not be Found"; + } + + return String(); +} + +extern String getSketchSHA256(); +// String getSketchSHA256() { +// const size_t HASH_LEN = 32; // SHA-256 digest length + +// uint8_t sha_256[HASH_LEN] = { 0 }; + +// // get sha256 digest for running partition +// if(esp_partition_get_sha256(esp_ota_get_running_partition(), sha_256) == 0) { +// char buffer[2 * HASH_LEN + 1]; + +// for(size_t index = 0; index < HASH_LEN; index++) { +// uint8_t nibble = (sha_256[index] & 0xf0) >> 4; +// buffer[2 * index] = nibble < 10 ? char(nibble + '0') : char(nibble - 10 + 'A'); + +// nibble = sha_256[index] & 0x0f; +// buffer[2 * index + 1] = nibble < 10 ? char(nibble + '0') : char(nibble - 10 + 'A'); +// } + +// buffer[2 * HASH_LEN] = '\0'; + +// return String(buffer); +// } else { + +// return String(); +// } +// } + +/** + * + * @param http HTTPClientLight * + * @param currentVersion const char * + * @return HTTPUpdateResult + */ +HTTPUpdateResult HTTPUpdateLight::handleUpdate(HTTPClientLight& http, const String& currentVersion, bool spiffs) +{ + + HTTPUpdateResult ret = HTTP_UPDATE_FAILED; + + // use HTTP/1.0 for update since the update handler not support any transfer Encoding + http.useHTTP10(true); + http.setTimeout(_httpClientTimeout); + http.setFollowRedirects(_followRedirects); + http.setUserAgent("ESP32-http-Update"); + http.addHeader("Cache-Control", "no-cache"); + http.addHeader("x-ESP32-STA-MAC", WiFi.macAddress()); + http.addHeader("x-ESP32-AP-MAC", WiFi.softAPmacAddress()); + http.addHeader("x-ESP32-free-space", String(ESP.getFreeSketchSpace())); + http.addHeader("x-ESP32-sketch-size", String(ESP.getSketchSize())); + String sketchMD5 = ESP.getSketchMD5(); + if(sketchMD5.length() != 0) { + http.addHeader("x-ESP32-sketch-md5", sketchMD5); + } + // Add also a SHA256 + String sketchSHA256 = getSketchSHA256(); + if(sketchSHA256.length() != 0) { + http.addHeader("x-ESP32-sketch-sha256", sketchSHA256); + } + http.addHeader("x-ESP32-chip-size", String(ESP.getFlashChipSize())); + http.addHeader("x-ESP32-sdk-version", ESP.getSdkVersion()); + + if(spiffs) { + http.addHeader("x-ESP32-mode", "spiffs"); + } else { + http.addHeader("x-ESP32-mode", "sketch"); + } + + if(currentVersion && currentVersion[0] != 0x00) { + http.addHeader("x-ESP32-version", currentVersion); + } + + const char * headerkeys[] = { "x-MD5" }; + size_t headerkeyssize = sizeof(headerkeys) / sizeof(char*); + + // track these headers + http.collectHeaders(headerkeys, headerkeyssize); + + uint32_t http_connect_time = millis(); + + int code = http.GET(); + int len = http.getSize(); + + // Add specific logging for Tasmota + if (len < 0) { + if (len <= -1000) { + AddLog(LOG_LEVEL_INFO, "OTA: TLS connection error %d after %d ms", -len - 1000, millis() - http_connect_time); + } else if (len == -1) { + AddLog(LOG_LEVEL_INFO, "OTA: Connection timeout after %d ms", len, millis() - http_connect_time); + } else { + AddLog(LOG_LEVEL_INFO, "OTA: Connection error %d after %d ms", len, millis() - http_connect_time); + } + } else { + AddLog(LOG_LEVEL_DEBUG, PSTR("OTA: Connected in %d ms, stack low mark %d"), + millis() - http_connect_time, uxTaskGetStackHighWaterMark(nullptr)); + } + + if(code <= 0) { + // log_e("HTTP error: %s\n", http.errorToString(code).c_str()); + _lastError = code; + http.end(); + return HTTP_UPDATE_FAILED; + } + + + log_d("Header read fin.\n"); + log_d("Server header:\n"); + log_d(" - code: %d\n", code); + log_d(" - len: %d\n", len); + + if(http.hasHeader("x-MD5")) { + log_d(" - MD5: %s\n", http.header("x-MD5").c_str()); + } + + log_d("ESP32 info:\n"); + log_d(" - free Space: %d\n", ESP.getFreeSketchSpace()); + log_d(" - current Sketch Size: %d\n", ESP.getSketchSize()); + + if(currentVersion && currentVersion[0] != 0x00) { + log_d(" - current version: %s\n", currentVersion.c_str() ); + } + + switch(code) { + case HTTP_CODE_OK: ///< OK (Start Update) + if(len > 0) { + bool startUpdate = true; + if(spiffs) { + const esp_partition_t* _partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, NULL); + if(!_partition){ + _lastError = HTTP_UE_NO_PARTITION; + return HTTP_UPDATE_FAILED; + } + + if(len > _partition->size) { + log_e("spiffsSize to low (%d) needed: %d\n", _partition->size, len); + startUpdate = false; + } + } else { + int sketchFreeSpace = ESP.getFreeSketchSpace(); + if(!sketchFreeSpace){ + _lastError = HTTP_UE_NO_PARTITION; + return HTTP_UPDATE_FAILED; + } + + if(len > sketchFreeSpace) { + log_e("FreeSketchSpace to low (%d) needed: %d\n", sketchFreeSpace, len); + startUpdate = false; + } + } + + if(!startUpdate) { + _lastError = HTTP_UE_TOO_LESS_SPACE; + ret = HTTP_UPDATE_FAILED; + } else { + // Warn main app we're starting up... + if (_cbStart) { + _cbStart(); + } + + WiFiClient * tcp = http.getStreamPtr(); + +// To do? WiFiUDP::stopAll(); +// To do? WiFiClient::stopAllExcept(tcp); + + delay(100); + + int command; + + if(spiffs) { + command = U_SPIFFS; + log_d("runUpdate spiffs...\n"); + } else { + command = U_FLASH; + log_d("runUpdate flash...\n"); + } + + if(!spiffs) { +/* To do + uint8_t buf[4]; + if(tcp->peekBytes(&buf[0], 4) != 4) { + log_e("peekBytes magic header failed\n"); + _lastError = HTTP_UE_BIN_VERIFY_HEADER_FAILED; + http.end(); + return HTTP_UPDATE_FAILED; + } +*/ + + // check for valid first magic byte +// if(buf[0] != 0xE9) { + if(tcp->peek() != 0xE9) { + log_e("Magic header does not start with 0xE9\n"); + _lastError = HTTP_UE_BIN_VERIFY_HEADER_FAILED; + http.end(); + return HTTP_UPDATE_FAILED; + + } +/* To do + uint32_t bin_flash_size = ESP.magicFlashChipSize((buf[3] & 0xf0) >> 4); + + // check if new bin fits to SPI flash + if(bin_flash_size > ESP.getFlashChipRealSize()) { + log_e("New binary does not fit SPI Flash size\n"); + _lastError = HTTP_UE_BIN_FOR_WRONG_FLASH; + http.end(); + return HTTP_UPDATE_FAILED; + } +*/ + } + if(runUpdate(*tcp, len, http.header("x-MD5"), command)) { + ret = HTTP_UPDATE_OK; + log_d("Update ok\n"); + http.end(); + // Warn main app we're all done + if (_cbEnd) { + _cbEnd(); + } + + if(_rebootOnUpdate && !spiffs) { + ESP.restart(); + } + + } else { + ret = HTTP_UPDATE_FAILED; + log_e("Update failed\n"); + } + } + } else { + _lastError = HTTP_UE_SERVER_NOT_REPORT_SIZE; + ret = HTTP_UPDATE_FAILED; + log_e("Content-Length was 0 or wasn't set by Server?!\n"); + } + break; + case HTTP_CODE_NOT_MODIFIED: + ///< Not Modified (No updates) + ret = HTTP_UPDATE_NO_UPDATES; + break; + case HTTP_CODE_NOT_FOUND: + _lastError = HTTP_UE_SERVER_FILE_NOT_FOUND; + ret = HTTP_UPDATE_FAILED; + break; + case HTTP_CODE_FORBIDDEN: + _lastError = HTTP_UE_SERVER_FORBIDDEN; + ret = HTTP_UPDATE_FAILED; + break; + default: + _lastError = HTTP_UE_SERVER_WRONG_HTTP_CODE; + ret = HTTP_UPDATE_FAILED; + AddLog(LOG_LEVEL_INFO, "OTA: unsupported HTTP return code %i", code); + // log_e("HTTP Code is (%d)\n", code); + break; + } + + http.end(); + return ret; +} + +/** + * write Update to flash + * @param in Stream& + * @param size uint32_t + * @param md5 String + * @return true if Update ok + */ +bool HTTPUpdateLight::runUpdate(Stream& in, uint32_t size, String md5, int command) +{ + + StreamString error; + + if (_cbProgress) { + Update.onProgress(_cbProgress); + } + + if(!Update.begin(size, command, _ledPin, _ledOn)) { + _lastError = Update.getError(); + Update.printError(error); + error.trim(); // remove line ending + log_e("Update.begin failed! (%s)\n", error.c_str()); + return false; + } + + if (_cbProgress) { + _cbProgress(0, size); + } + + if(md5.length()) { + if(!Update.setMD5(md5.c_str())) { + _lastError = HTTP_UE_SERVER_FAULTY_MD5; + log_e("Update.setMD5 failed! (%s)\n", md5.c_str()); + return false; + } + } + +// To do: the SHA256 could be checked if the server sends it + + if(Update.writeStream(in) != size) { + _lastError = Update.getError(); + Update.printError(error); + error.trim(); // remove line ending + log_e("Update.writeStream failed! (%s)\n", error.c_str()); + return false; + } + + if (_cbProgress) { + _cbProgress(size, size); + } + + if(!Update.end()) { + _lastError = Update.getError(); + Update.printError(error); + error.trim(); // remove line ending + log_e("Update.end failed! (%s)\n", error.c_str()); + return false; + } + + return true; +} + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_HTTPUPDATE) +HTTPUpdateLight httpUpdateLight; +#endif diff --git a/lib/libesp32/Berry-HttpClientLight/src/HTTPUpdateLight.h b/lib/libesp32/Berry-HttpClientLight/src/HTTPUpdateLight.h new file mode 100644 index 000000000..cbed38bd6 --- /dev/null +++ b/lib/libesp32/Berry-HttpClientLight/src/HTTPUpdateLight.h @@ -0,0 +1,140 @@ +/** + * + * @file HTTPUpdate.h based on ESP8266HTTPUpdate.h + * @date 16.10.2018 + * @author Markus Sattler + * + * Copyright (c) 2015 Markus Sattler. All rights reserved. + * This file is part of the ESP32 Http Updater. + * + * 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 + * + */ + +#ifndef ___HTTP_UPDATE_LIGHT_H___ +#define ___HTTP_UPDATE_LIGHT_H___ + +#include +#include +#include +#include +#include +#include +#include + +/// note we use HTTP client errors too so we start at 100 +// #define HTTP_UE_TOO_LESS_SPACE (-100) +// #define HTTP_UE_SERVER_NOT_REPORT_SIZE (-101) +// #define HTTP_UE_SERVER_FILE_NOT_FOUND (-102) +// #define HTTP_UE_SERVER_FORBIDDEN (-103) +// #define HTTP_UE_SERVER_WRONG_HTTP_CODE (-104) +// #define HTTP_UE_SERVER_FAULTY_MD5 (-105) +// #define HTTP_UE_BIN_VERIFY_HEADER_FAILED (-106) +// #define HTTP_UE_BIN_FOR_WRONG_FLASH (-107) +// #define HTTP_UE_NO_PARTITION (-108) + +// enum HTTPUpdateResult { +// HTTP_UPDATE_FAILED, +// HTTP_UPDATE_NO_UPDATES, +// HTTP_UPDATE_OK +// }; + +// typedef HTTPUpdateResult t_httpUpdate_return; // backward compatibility + +// using HTTPUpdateStartCB = std::function; +// using HTTPUpdateEndCB = std::function; +// using HTTPUpdateErrorCB = std::function; +// using HTTPUpdateProgressCB = std::function; + +class HTTPUpdateLight +{ +public: + HTTPUpdateLight(void); + HTTPUpdateLight(int httpClientTimeout); + ~HTTPUpdateLight(void); + + void rebootOnUpdate(bool reboot) + { + _rebootOnUpdate = reboot; + } + + /** + * set redirect follow mode. See `followRedirects_t` enum for avaliable modes. + * @param follow + */ + void setFollowRedirects(followRedirects_t follow) + { + _followRedirects = follow; + } + + void setLedPin(int ledPin = -1, uint8_t ledOn = HIGH) + { + _ledPin = ledPin; + _ledOn = ledOn; + } + + // t_httpUpdate_return update(WiFiClient& client, const String& url, const String& currentVersion = ""); + + // t_httpUpdate_return update(WiFiClient& client, const String& host, uint16_t port, const String& uri = "/", + // const String& currentVersion = ""); + + // t_httpUpdate_return updateSpiffs(WiFiClient& client, const String& url, const String& currentVersion = ""); + + t_httpUpdate_return update(HTTPClientLight& httpClient, + const String& currentVersion = ""); + + // t_httpUpdate_return updateSpiffs(HTTPClient &httpClient, const String ¤tVersion = ""); + + // Notification callbacks + void onStart(HTTPUpdateStartCB cbOnStart) { _cbStart = cbOnStart; } + void onEnd(HTTPUpdateEndCB cbOnEnd) { _cbEnd = cbOnEnd; } + void onError(HTTPUpdateErrorCB cbOnError) { _cbError = cbOnError; } + void onProgress(HTTPUpdateProgressCB cbOnProgress) { _cbProgress = cbOnProgress; } + + int getLastError(void); + String getLastErrorString(void); + +protected: + t_httpUpdate_return handleUpdate(HTTPClientLight& http, const String& currentVersion, bool spiffs = false); + bool runUpdate(Stream& in, uint32_t size, String md5, int command = U_FLASH); + + // Set the error and potentially use a CB to notify the application + void _setLastError(int err) { + _lastError = err; + if (_cbError) { + _cbError(err); + } + } + int _lastError; + bool _rebootOnUpdate = true; +private: + int _httpClientTimeout; + followRedirects_t _followRedirects; + + // Callbacks + HTTPUpdateStartCB _cbStart; + HTTPUpdateEndCB _cbEnd; + HTTPUpdateErrorCB _cbError; + HTTPUpdateProgressCB _cbProgress; + + int _ledPin; + uint8_t _ledOn; +}; + +#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_HTTPUPDATE) +extern HTTPUpdateLight httpUpdateLight; +#endif + +#endif /* ___HTTP_UPDATE_LIGHT_H___ */ diff --git a/lib/libesp32/Berry/default/be_animate_lib.c b/lib/libesp32/Berry/default/be_animate_lib.c new file mode 100644 index 000000000..db6052653 --- /dev/null +++ b/lib/libesp32/Berry/default/be_animate_lib.c @@ -0,0 +1,712 @@ +/******************************************************************** + * Berry module `animate` + * + * To use: `import animate` + * + *******************************************************************/ +#include "be_constobj.h" + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Animate_rotate_init, /* name */ + be_nested_proto( + 12, /* nstack */ + 5, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_string("init", 380752755, 4), + /* K1 */ be_nested_string("closure", 1548407746, 7), + /* K2 */ be_nested_string("code", -114201356, 4), + /* K3 */ be_nested_string("push", -2022703139, 4), + /* K4 */ be_nested_string("animate", -409180496, 7), + /* K5 */ be_nested_string("ins_ramp", 1068049360, 8), + /* K6 */ be_nested_string("ins_goto", 1342843963, 8), + /* K7 */ be_const_int(0), + }), + (be_nested_const_str("init", 380752755, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[25]) { /* code */ + 0x60140003, // 0000 GETGBL R5 G3 + 0x5C180000, // 0001 MOVE R6 R0 + 0x7C140200, // 0002 CALL R5 1 + 0x8C140B00, // 0003 GETMET R5 R5 K0 + 0x7C140200, // 0004 CALL R5 1 + 0x90020201, // 0005 SETMBR R0 K1 R1 + 0x88140102, // 0006 GETMBR R5 R0 K2 + 0x8C140B03, // 0007 GETMET R5 R5 K3 + 0xB81E0800, // 0008 GETNGBL R7 K4 + 0x8C1C0F05, // 0009 GETMET R7 R7 K5 + 0x5C240400, // 000A MOVE R9 R2 + 0x5C280600, // 000B MOVE R10 R3 + 0x5C2C0800, // 000C MOVE R11 R4 + 0x7C1C0800, // 000D CALL R7 4 + 0x7C140400, // 000E CALL R5 2 + 0x88140102, // 000F GETMBR R5 R0 K2 + 0x8C140B03, // 0010 GETMET R5 R5 K3 + 0xB81E0800, // 0011 GETNGBL R7 K4 + 0x8C1C0F06, // 0012 GETMET R7 R7 K6 + 0x58240007, // 0013 LDCONST R9 K7 + 0x58280007, // 0014 LDCONST R10 K7 + 0x582C0007, // 0015 LDCONST R11 K7 + 0x7C1C0800, // 0016 CALL R7 4 + 0x7C140400, // 0017 CALL R5 2 + 0x80000000, // 0018 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Animate_rotate +********************************************************************/ +extern const bclass be_class_Animate_engine; +be_local_class(Animate_rotate, + 0, + &be_class_Animate_engine, + be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("init", 380752755, 4, -1), be_const_closure(Animate_rotate_init_closure) }, + })), + (be_nested_const_str("Animate_rotate", -787188142, 14)) +); + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Animate_from_to_init, /* name */ + be_nested_proto( + 12, /* nstack */ + 5, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_string("init", 380752755, 4), + /* K1 */ be_nested_string("closure", 1548407746, 7), + /* K2 */ be_nested_string("code", -114201356, 4), + /* K3 */ be_nested_string("push", -2022703139, 4), + /* K4 */ be_nested_string("animate", -409180496, 7), + /* K5 */ be_nested_string("ins_ramp", 1068049360, 8), + }), + (be_nested_const_str("init", 380752755, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[16]) { /* code */ + 0x60140003, // 0000 GETGBL R5 G3 + 0x5C180000, // 0001 MOVE R6 R0 + 0x7C140200, // 0002 CALL R5 1 + 0x8C140B00, // 0003 GETMET R5 R5 K0 + 0x7C140200, // 0004 CALL R5 1 + 0x90020201, // 0005 SETMBR R0 K1 R1 + 0x88140102, // 0006 GETMBR R5 R0 K2 + 0x8C140B03, // 0007 GETMET R5 R5 K3 + 0xB81E0800, // 0008 GETNGBL R7 K4 + 0x8C1C0F05, // 0009 GETMET R7 R7 K5 + 0x5C240400, // 000A MOVE R9 R2 + 0x5C280600, // 000B MOVE R10 R3 + 0x5C2C0800, // 000C MOVE R11 R4 + 0x7C1C0800, // 000D CALL R7 4 + 0x7C140400, // 000E CALL R5 2 + 0x80000000, // 000F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Animate_from_to +********************************************************************/ +extern const bclass be_class_Animate_engine; +be_local_class(Animate_from_to, + 0, + &be_class_Animate_engine, + be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("init", 380752755, 4, -1), be_const_closure(Animate_from_to_init_closure) }, + })), + (be_nested_const_str("Animate_from_to", 1699049867, 15)) +); + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Animate_back_forth_init, /* name */ + be_nested_proto( + 12, /* nstack */ + 5, /* argc */ + 0, /* 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_string("init", 380752755, 4), + /* K1 */ be_nested_string("closure", 1548407746, 7), + /* K2 */ be_nested_string("code", -114201356, 4), + /* K3 */ be_nested_string("push", -2022703139, 4), + /* K4 */ be_nested_string("animate", -409180496, 7), + /* K5 */ be_nested_string("ins_ramp", 1068049360, 8), + /* K6 */ be_const_int(2), + /* K7 */ be_nested_string("ins_goto", 1342843963, 8), + /* K8 */ be_const_int(0), + }), + (be_nested_const_str("init", 380752755, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[34]) { /* code */ + 0x60140003, // 0000 GETGBL R5 G3 + 0x5C180000, // 0001 MOVE R6 R0 + 0x7C140200, // 0002 CALL R5 1 + 0x8C140B00, // 0003 GETMET R5 R5 K0 + 0x7C140200, // 0004 CALL R5 1 + 0x90020201, // 0005 SETMBR R0 K1 R1 + 0x88140102, // 0006 GETMBR R5 R0 K2 + 0x8C140B03, // 0007 GETMET R5 R5 K3 + 0xB81E0800, // 0008 GETNGBL R7 K4 + 0x8C1C0F05, // 0009 GETMET R7 R7 K5 + 0x5C240400, // 000A MOVE R9 R2 + 0x5C280600, // 000B MOVE R10 R3 + 0x0C2C0906, // 000C DIV R11 R4 K6 + 0x7C1C0800, // 000D CALL R7 4 + 0x7C140400, // 000E CALL R5 2 + 0x88140102, // 000F GETMBR R5 R0 K2 + 0x8C140B03, // 0010 GETMET R5 R5 K3 + 0xB81E0800, // 0011 GETNGBL R7 K4 + 0x8C1C0F05, // 0012 GETMET R7 R7 K5 + 0x5C240600, // 0013 MOVE R9 R3 + 0x5C280400, // 0014 MOVE R10 R2 + 0x0C2C0906, // 0015 DIV R11 R4 K6 + 0x7C1C0800, // 0016 CALL R7 4 + 0x7C140400, // 0017 CALL R5 2 + 0x88140102, // 0018 GETMBR R5 R0 K2 + 0x8C140B03, // 0019 GETMET R5 R5 K3 + 0xB81E0800, // 001A GETNGBL R7 K4 + 0x8C1C0F07, // 001B GETMET R7 R7 K7 + 0x58240008, // 001C LDCONST R9 K8 + 0x58280008, // 001D LDCONST R10 K8 + 0x582C0008, // 001E LDCONST R11 K8 + 0x7C1C0800, // 001F CALL R7 4 + 0x7C140400, // 0020 CALL R5 2 + 0x80000000, // 0021 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Animate_back_forth +********************************************************************/ +extern const bclass be_class_Animate_engine; +be_local_class(Animate_back_forth, + 0, + &be_class_Animate_engine, + be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("init", 380752755, 4, -1), be_const_closure(Animate_back_forth_init_closure) }, + })), + (be_nested_const_str("Animate_back_forth", 5319526, 18)) +); + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Animate_ins_goto_init, /* name */ + be_nested_proto( + 4, /* nstack */ + 4, /* argc */ + 0, /* 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_string("pc_rel", 991921176, 6), + /* K1 */ be_nested_string("pc_abs", 920256495, 6), + /* K2 */ be_nested_string("duration", 799079693, 8), + }), + (be_nested_const_str("init", 380752755, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x90020403, // 0002 SETMBR R0 K2 R3 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Animate_ins_goto +********************************************************************/ +be_local_class(Animate_ins_goto, + 3, + NULL, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("pc_rel", 991921176, 6, -1), be_const_var(0) }, + { be_nested_key("duration", 799079693, 8, -1), be_const_var(2) }, + { be_nested_key("pc_abs", 920256495, 6, -1), be_const_var(1) }, + { be_nested_key("init", 380752755, 4, 2), be_const_closure(Animate_ins_goto_init_closure) }, + })), + (be_nested_const_str("Animate_ins_goto", 1667367043, 16)) +); + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Animate_ins_ramp_init, /* name */ + be_nested_proto( + 4, /* nstack */ + 4, /* argc */ + 0, /* 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_string("a", -468965076, 1), + /* K1 */ be_nested_string("b", -418632219, 1), + /* K2 */ be_nested_string("duration", 799079693, 8), + }), + (be_nested_const_str("init", 380752755, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x90020403, // 0002 SETMBR R0 K2 R3 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Animate_ins_ramp +********************************************************************/ +be_local_class(Animate_ins_ramp, + 3, + NULL, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("a", -468965076, 1, -1), be_const_var(0) }, + { be_nested_key("b", -418632219, 1, 2), be_const_var(1) }, + { be_nested_key("duration", 799079693, 8, -1), be_const_var(2) }, + { be_nested_key("init", 380752755, 4, -1), be_const_closure(Animate_ins_ramp_init_closure) }, + })), + (be_nested_const_str("Animate_ins_ramp", 785058280, 16)) +); + +/******************************************************************** +** Solidified function: run +********************************************************************/ +be_local_closure(Animate_engine_run, /* name */ + be_nested_proto( + 6, /* nstack */ + 3, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_string("tasmota", 424643812, 7), + /* K1 */ be_nested_string("millis", 1214679063, 6), + /* K2 */ be_nested_string("value", 1113510858, 5), + /* K3 */ be_nested_string("ins_time", -1314721743, 8), + /* K4 */ be_nested_string("running", 343848780, 7), + /* K5 */ be_nested_string("add_driver", 1654458371, 10), + }), + (be_nested_const_str("run", 718098122, 3)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[19]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0203, // 0001 EQ R3 R1 R3 + 0x780E0003, // 0002 JMPF R3 #0007 + 0xB80E0000, // 0003 GETNGBL R3 K0 + 0x8C0C0701, // 0004 GETMET R3 R3 K1 + 0x7C0C0200, // 0005 CALL R3 1 + 0x5C040600, // 0006 MOVE R1 R3 + 0x4C0C0000, // 0007 LDNIL R3 + 0x200C0403, // 0008 NE R3 R2 R3 + 0x780E0000, // 0009 JMPF R3 #000B + 0x90020402, // 000A SETMBR R0 K2 R2 + 0x90020601, // 000B SETMBR R0 K3 R1 + 0x500C0200, // 000C LDBOOL R3 1 0 + 0x90020803, // 000D SETMBR R0 K4 R3 + 0xB80E0000, // 000E GETNGBL R3 K0 + 0x8C0C0705, // 000F GETMET R3 R3 K5 + 0x5C140000, // 0010 MOVE R5 R0 + 0x7C0C0400, // 0011 CALL R3 2 + 0x80000000, // 0012 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Animate_engine_init, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 0, /* 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_string("code", -114201356, 4), + /* K1 */ be_nested_string("pc", 1313756516, 2), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_string("ins_time", -1314721743, 8), + /* K4 */ be_nested_string("running", 343848780, 7), + }), + (be_nested_const_str("init", 380752755, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 8]) { /* code */ + 0x60040012, // 0000 GETGBL R1 G18 + 0x7C040000, // 0001 CALL R1 0 + 0x90020001, // 0002 SETMBR R0 K0 R1 + 0x90020302, // 0003 SETMBR R0 K1 K2 + 0x90020702, // 0004 SETMBR R0 K3 K2 + 0x50040000, // 0005 LDBOOL R1 0 0 + 0x90020801, // 0006 SETMBR R0 K4 R1 + 0x80000000, // 0007 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: autorun +********************************************************************/ +be_local_closure(Animate_engine_autorun, /* name */ + be_nested_proto( + 7, /* nstack */ + 3, /* argc */ + 0, /* 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_string("run", 718098122, 3), + /* K1 */ be_nested_string("tasmota", 424643812, 7), + /* K2 */ be_nested_string("add_driver", 1654458371, 10), + }), + (be_nested_const_str("autorun", 1447527407, 7)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 9]) { /* code */ + 0x8C0C0100, // 0000 GETMET R3 R0 K0 + 0x5C140200, // 0001 MOVE R5 R1 + 0x5C180400, // 0002 MOVE R6 R2 + 0x7C0C0600, // 0003 CALL R3 3 + 0xB80E0200, // 0004 GETNGBL R3 K1 + 0x8C0C0702, // 0005 GETMET R3 R3 K2 + 0x5C140000, // 0006 MOVE R5 R0 + 0x7C0C0400, // 0007 CALL R3 2 + 0x80000000, // 0008 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: stop +********************************************************************/ +be_local_closure(Animate_engine_stop, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 0, /* 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_string("running", 343848780, 7), + /* K1 */ be_nested_string("tasmota", 424643812, 7), + /* K2 */ be_nested_string("remove_driver", 1030243768, 13), + }), + (be_nested_const_str("stop", -883741979, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 7]) { /* code */ + 0x50040000, // 0000 LDBOOL R1 0 0 + 0x90020001, // 0001 SETMBR R0 K0 R1 + 0xB8060200, // 0002 GETNGBL R1 K1 + 0x8C040302, // 0003 GETMET R1 R1 K2 + 0x5C0C0000, // 0004 MOVE R3 R0 + 0x7C040400, // 0005 CALL R1 2 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: is_running +********************************************************************/ +be_local_closure(Animate_engine_is_running, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 0, /* 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_string("running", 343848780, 7), + }), + (be_nested_const_str("is_running", -2068120035, 10)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_50ms +********************************************************************/ +be_local_closure(Animate_engine_every_50ms, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 0, /* 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_string("animate", -409180496, 7), + }), + (be_nested_const_str("every_50ms", -1911083288, 10)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 3]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: animate +********************************************************************/ +be_local_closure(Animate_engine_animate, /* name */ + be_nested_proto( + 12, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[22]) { /* constants */ + /* K0 */ be_nested_string("running", 343848780, 7), + /* K1 */ be_nested_string("tasmota", 424643812, 7), + /* K2 */ be_nested_string("millis", 1214679063, 6), + /* K3 */ be_nested_string("ins_time", -1314721743, 8), + /* K4 */ be_nested_string("pc", 1313756516, 2), + /* K5 */ be_nested_string("code", -114201356, 4), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_string("internal_error", -1775809127, 14), + /* K8 */ be_nested_string("Animate pc is out of range", 1854929421, 26), + /* K9 */ be_nested_string("animate", -409180496, 7), + /* K10 */ be_nested_string("ins_ramp", 1068049360, 8), + /* K11 */ be_nested_string("closure", 1548407746, 7), + /* K12 */ be_nested_string("duration", 799079693, 8), + /* K13 */ be_nested_string("value", 1113510858, 5), + /* K14 */ be_nested_string("scale_uint", -1204156202, 10), + /* K15 */ be_nested_string("a", -468965076, 1), + /* K16 */ be_nested_string("b", -418632219, 1), + /* K17 */ be_const_int(1), + /* K18 */ be_nested_string("ins_goto", 1342843963, 8), + /* K19 */ be_nested_string("pc_rel", 991921176, 6), + /* K20 */ be_nested_string("pc_abs", 920256495, 6), + /* K21 */ be_nested_string("unknown instruction", 1093911841, 19), + }), + (be_nested_const_str("animate", -409180496, 7)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[99]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x740A0000, // 0001 JMPT R2 #0003 + 0x80000400, // 0002 RET 0 + 0x4C080000, // 0003 LDNIL R2 + 0x1C080202, // 0004 EQ R2 R1 R2 + 0x780A0003, // 0005 JMPF R2 #000A + 0xB80A0200, // 0006 GETNGBL R2 K1 + 0x8C080502, // 0007 GETMET R2 R2 K2 + 0x7C080200, // 0008 CALL R2 1 + 0x5C040400, // 0009 MOVE R1 R2 + 0x50080200, // 000A LDBOOL R2 1 0 + 0x780A0054, // 000B JMPF R2 #0061 + 0x88080103, // 000C GETMBR R2 R0 K3 + 0x04080202, // 000D SUB R2 R1 R2 + 0x880C0104, // 000E GETMBR R3 R0 K4 + 0x6010000C, // 000F GETGBL R4 G12 + 0x88140105, // 0010 GETMBR R5 R0 K5 + 0x7C100200, // 0011 CALL R4 1 + 0x280C0604, // 0012 GE R3 R3 R4 + 0x780E0002, // 0013 JMPF R3 #0017 + 0x500C0000, // 0014 LDBOOL R3 0 0 + 0x90020003, // 0015 SETMBR R0 K0 R3 + 0x70020049, // 0016 JMP #0061 + 0x880C0104, // 0017 GETMBR R3 R0 K4 + 0x140C0706, // 0018 LT R3 R3 K6 + 0x780E0000, // 0019 JMPF R3 #001B + 0xB0060F08, // 001A RAISE 1 K7 K8 + 0x880C0104, // 001B GETMBR R3 R0 K4 + 0x88100105, // 001C GETMBR R4 R0 K5 + 0x940C0803, // 001D GETIDX R3 R4 R3 + 0x6014000F, // 001E GETGBL R5 G15 + 0x5C180600, // 001F MOVE R6 R3 + 0xB81E1200, // 0020 GETNGBL R7 K9 + 0x881C0F0A, // 0021 GETMBR R7 R7 K10 + 0x7C140400, // 0022 CALL R5 2 + 0x78160020, // 0023 JMPF R5 #0045 + 0x8810010B, // 0024 GETMBR R4 R0 K11 + 0x8814070C, // 0025 GETMBR R5 R3 K12 + 0x14140405, // 0026 LT R5 R2 R5 + 0x7816000E, // 0027 JMPF R5 #0037 + 0xB8160200, // 0028 GETNGBL R5 K1 + 0x8C140B0E, // 0029 GETMET R5 R5 K14 + 0x5C1C0400, // 002A MOVE R7 R2 + 0x58200006, // 002B LDCONST R8 K6 + 0x8824070C, // 002C GETMBR R9 R3 K12 + 0x8828070F, // 002D GETMBR R10 R3 K15 + 0x882C0710, // 002E GETMBR R11 R3 K16 + 0x7C140C00, // 002F CALL R5 6 + 0x90021A05, // 0030 SETMBR R0 K13 R5 + 0x78120002, // 0031 JMPF R4 #0035 + 0x5C140800, // 0032 MOVE R5 R4 + 0x8818010D, // 0033 GETMBR R6 R0 K13 + 0x7C140200, // 0034 CALL R5 1 + 0x7002002A, // 0035 JMP #0061 + 0x7002000C, // 0036 JMP #0044 + 0x88140710, // 0037 GETMBR R5 R3 K16 + 0x90021A05, // 0038 SETMBR R0 K13 R5 + 0x78120002, // 0039 JMPF R4 #003D + 0x5C140800, // 003A MOVE R5 R4 + 0x8818010D, // 003B GETMBR R6 R0 K13 + 0x7C140200, // 003C CALL R5 1 + 0x88140104, // 003D GETMBR R5 R0 K4 + 0x00140B11, // 003E ADD R5 R5 K17 + 0x90020805, // 003F SETMBR R0 K4 R5 + 0x8814070C, // 0040 GETMBR R5 R3 K12 + 0x04140405, // 0041 SUB R5 R2 R5 + 0x04140205, // 0042 SUB R5 R1 R5 + 0x90020605, // 0043 SETMBR R0 K3 R5 + 0x7002001A, // 0044 JMP #0060 + 0x6010000F, // 0045 GETGBL R4 G15 + 0x5C140600, // 0046 MOVE R5 R3 + 0xB81A1200, // 0047 GETNGBL R6 K9 + 0x88180D12, // 0048 GETMBR R6 R6 K18 + 0x7C100400, // 0049 CALL R4 2 + 0x78120013, // 004A JMPF R4 #005F + 0x8810070C, // 004B GETMBR R4 R3 K12 + 0x14100404, // 004C LT R4 R2 R4 + 0x78120001, // 004D JMPF R4 #0050 + 0x70020011, // 004E JMP #0061 + 0x7002000D, // 004F JMP #005E + 0x88100713, // 0050 GETMBR R4 R3 K19 + 0x20100906, // 0051 NE R4 R4 K6 + 0x78120004, // 0052 JMPF R4 #0058 + 0x88100104, // 0053 GETMBR R4 R0 K4 + 0x88140713, // 0054 GETMBR R5 R3 K19 + 0x00100805, // 0055 ADD R4 R4 R5 + 0x90020804, // 0056 SETMBR R0 K4 R4 + 0x70020001, // 0057 JMP #005A + 0x88100714, // 0058 GETMBR R4 R3 K20 + 0x90020804, // 0059 SETMBR R0 K4 R4 + 0x8810070C, // 005A GETMBR R4 R3 K12 + 0x04100404, // 005B SUB R4 R2 R4 + 0x04100204, // 005C SUB R4 R1 R4 + 0x90020604, // 005D SETMBR R0 K3 R4 + 0x70020000, // 005E JMP #0060 + 0xB0060F15, // 005F RAISE 1 K7 K21 + 0x7001FFA8, // 0060 JMP #000A + 0x8808010D, // 0061 GETMBR R2 R0 K13 + 0x80040400, // 0062 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Animate_engine +********************************************************************/ +be_local_class(Animate_engine, + 6, + NULL, + be_nested_map(13, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("code", -114201356, 4, -1), be_const_var(0) }, + { be_nested_key("run", 718098122, 3, 4), be_const_closure(Animate_engine_run_closure) }, + { be_nested_key("running", 343848780, 7, 8), be_const_var(4) }, + { be_nested_key("init", 380752755, 4, -1), be_const_closure(Animate_engine_init_closure) }, + { be_nested_key("autorun", 1447527407, 7, -1), be_const_closure(Animate_engine_autorun_closure) }, + { be_nested_key("value", 1113510858, 5, -1), be_const_var(5) }, + { be_nested_key("stop", -883741979, 4, 3), be_const_closure(Animate_engine_stop_closure) }, + { be_nested_key("pc", 1313756516, 2, -1), be_const_var(2) }, + { be_nested_key("is_running", -2068120035, 10, 11), be_const_closure(Animate_engine_is_running_closure) }, + { be_nested_key("every_50ms", -1911083288, 10, 10), be_const_closure(Animate_engine_every_50ms_closure) }, + { be_nested_key("animate", -409180496, 7, -1), be_const_closure(Animate_engine_animate_closure) }, + { be_nested_key("closure", 1548407746, 7, -1), be_const_var(1) }, + { be_nested_key("ins_time", -1314721743, 8, 9), be_const_var(3) }, + })), + (be_nested_const_str("Animate_engine", 1498417667, 14)) +); + +/******************************************************************** +** Solidified module: animate +********************************************************************/ +be_local_module(animate, + "animate", + be_nested_map(6, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("rotate", -1510671094, 6, 2), be_const_class(be_class_Animate_rotate) }, + { be_nested_key("from_to", 21625507, 7, 3), be_const_class(be_class_Animate_from_to) }, + { be_nested_key("back_forth", -1629925234, 10, -1), be_const_class(be_class_Animate_back_forth) }, + { be_nested_key("ins_goto", 1342843963, 8, -1), be_const_class(be_class_Animate_ins_goto) }, + { be_nested_key("ins_ramp", 1068049360, 8, -1), be_const_class(be_class_Animate_ins_ramp) }, + { be_nested_key("engine", -301606853, 6, -1), be_const_class(be_class_Animate_engine) }, + })) +); +BE_EXPORT_VARIABLE be_define_const_native_module(animate); +/********************************************************************/ diff --git a/lib/libesp32/Berry/default/be_autoconf_lib.c b/lib/libesp32/Berry/default/be_autoconf_lib.c new file mode 100644 index 000000000..3d864a988 --- /dev/null +++ b/lib/libesp32/Berry/default/be_autoconf_lib.c @@ -0,0 +1,1394 @@ +/******************************************************************** + * Tasmota lib + * + * To use: `import autoconf` + * + *******************************************************************/ +#include "be_constobj.h" + + +/******************************************************************** +** Solidified function: page_autoconf_ctl +********************************************************************/ +be_local_closure(page_autoconf_ctl, /* name */ + be_nested_proto( + 13, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[41]) { /* constants */ + /* K0 */ be_nested_string("webserver", 1572454038, 9), + /* K1 */ be_nested_string("string", 398550328, 6), + /* K2 */ be_nested_string("path", -2071507658, 4), + /* K3 */ be_nested_string("check_privileged_access", -602033328, 23), + /* K4 */ be_nested_string("has_arg", 424878688, 7), + /* K5 */ be_nested_string("reapply", -516027964, 7), + /* K6 */ be_nested_string("tasmota", 424643812, 7), + /* K7 */ be_nested_string("log", 1062293841, 3), + /* K8 */ be_nested_string("CFG: removing first time marker", 2125556683, 31), + /* K9 */ be_const_int(2), + /* K10 */ be_nested_string("clear_first_time", 632769909, 16), + /* K11 */ be_nested_string("redirect", 389758641, 8), + /* K12 */ be_nested_string("/?rst=", 580074707, 6), + /* K13 */ be_nested_string("zip", -1417514060, 3), + /* K14 */ be_nested_string("CFG: removing autoconf files", -280262326, 28), + /* K15 */ be_nested_string("delete_all_configs", -1912899718, 18), + /* K16 */ be_nested_string("arg", 1047474471, 3), + /* K17 */ be_nested_string("reset", 1695364032, 5), + /* K18 */ be_nested_string("format", -1180859054, 6), + /* K19 */ be_nested_string("https://raw.githubusercontent.com/tasmota/autoconf/main/%s/%s.autoconf", -1551440987, 70), + /* K20 */ be_nested_string("arch", -1342162999, 4), + /* K21 */ be_nested_string("CFG: downloading '%s'", 589480701, 21), + /* K22 */ be_nested_string("%s.autoconf", -734583772, 11), + /* K23 */ be_nested_string("webclient", -218578150, 9), + /* K24 */ be_nested_string("begin", 1748273790, 5), + /* K25 */ be_nested_string("GET", -1763262857, 3), + /* K26 */ be_nested_string("return code=%i", 2127454401, 14), + /* K27 */ be_nested_string("connection_error", 1358926260, 16), + /* K28 */ be_nested_string("write_file", -1117308417, 10), + /* K29 */ be_nested_string("close", 667630371, 5), + /* K30 */ be_nested_string("value_error", 773297791, 11), + /* K31 */ be_nested_string("Unknown command", 1830905432, 15), + /* K32 */ be_nested_string("CFG: Exception> '%s' - %s", 1228874553, 25), + /* K33 */ be_nested_string("content_start", -1357458227, 13), + /* K34 */ be_nested_string("Parameter error", -454925258, 15), + /* K35 */ be_nested_string("content_send_style", 1087907647, 18), + /* K36 */ be_nested_string("content_send", 1673733649, 12), + /* K37 */ be_nested_string("

Exception:
'%s'
%s

", -42402214, 59), + /* K38 */ be_nested_string("content_button", 1956476087, 14), + /* K39 */ be_nested_string("BUTTON_CONFIGURATION", 70820856, 20), + /* K40 */ be_nested_string("content_stop", 658554751, 12), + }), + (be_nested_const_str("page_autoconf_ctl", -1841585800, 17)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[117]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0xA40E0400, // 0002 IMPORT R3 K2 + 0x8C100303, // 0003 GETMET R4 R1 K3 + 0x7C100200, // 0004 CALL R4 1 + 0x74120001, // 0005 JMPT R4 #0008 + 0x4C100000, // 0006 LDNIL R4 + 0x80040800, // 0007 RET 1 R4 + 0xA802004E, // 0008 EXBLK 0 #0058 + 0x8C100304, // 0009 GETMET R4 R1 K4 + 0x58180005, // 000A LDCONST R6 K5 + 0x7C100400, // 000B CALL R4 2 + 0x7812000A, // 000C JMPF R4 #0018 + 0xB8120C00, // 000D GETNGBL R4 K6 + 0x8C100907, // 000E GETMET R4 R4 K7 + 0x58180008, // 000F LDCONST R6 K8 + 0x581C0009, // 0010 LDCONST R7 K9 + 0x7C100600, // 0011 CALL R4 3 + 0x8C10010A, // 0012 GETMET R4 R0 K10 + 0x7C100200, // 0013 CALL R4 1 + 0x8C10030B, // 0014 GETMET R4 R1 K11 + 0x5818000C, // 0015 LDCONST R6 K12 + 0x7C100400, // 0016 CALL R4 2 + 0x7002003D, // 0017 JMP #0056 + 0x8C100304, // 0018 GETMET R4 R1 K4 + 0x5818000D, // 0019 LDCONST R6 K13 + 0x7C100400, // 001A CALL R4 2 + 0x78120038, // 001B JMPF R4 #0055 + 0xB8120C00, // 001C GETNGBL R4 K6 + 0x8C100907, // 001D GETMET R4 R4 K7 + 0x5818000E, // 001E LDCONST R6 K14 + 0x581C0009, // 001F LDCONST R7 K9 + 0x7C100600, // 0020 CALL R4 3 + 0x8C10010F, // 0021 GETMET R4 R0 K15 + 0x7C100200, // 0022 CALL R4 1 + 0x8C100310, // 0023 GETMET R4 R1 K16 + 0x5818000D, // 0024 LDCONST R6 K13 + 0x7C100400, // 0025 CALL R4 2 + 0x20140911, // 0026 NE R5 R4 K17 + 0x78160026, // 0027 JMPF R5 #004F + 0x8C140512, // 0028 GETMET R5 R2 K18 + 0x581C0013, // 0029 LDCONST R7 K19 + 0xB8220C00, // 002A GETNGBL R8 K6 + 0x8C201114, // 002B GETMET R8 R8 K20 + 0x7C200200, // 002C CALL R8 1 + 0x5C240800, // 002D MOVE R9 R4 + 0x7C140800, // 002E CALL R5 4 + 0xB81A0C00, // 002F GETNGBL R6 K6 + 0x8C180D07, // 0030 GETMET R6 R6 K7 + 0x8C200512, // 0031 GETMET R8 R2 K18 + 0x58280015, // 0032 LDCONST R10 K21 + 0x5C2C0A00, // 0033 MOVE R11 R5 + 0x7C200600, // 0034 CALL R8 3 + 0x58240009, // 0035 LDCONST R9 K9 + 0x7C180600, // 0036 CALL R6 3 + 0x8C180512, // 0037 GETMET R6 R2 K18 + 0x58200016, // 0038 LDCONST R8 K22 + 0x5C240800, // 0039 MOVE R9 R4 + 0x7C180600, // 003A CALL R6 3 + 0xB81E2E00, // 003B GETNGBL R7 K23 + 0x7C1C0000, // 003C CALL R7 0 + 0x8C200F18, // 003D GETMET R8 R7 K24 + 0x5C280A00, // 003E MOVE R10 R5 + 0x7C200400, // 003F CALL R8 2 + 0x8C200F19, // 0040 GETMET R8 R7 K25 + 0x7C200200, // 0041 CALL R8 1 + 0x542600C7, // 0042 LDINT R9 200 + 0x20241009, // 0043 NE R9 R8 R9 + 0x78260004, // 0044 JMPF R9 #004A + 0x8C240512, // 0045 GETMET R9 R2 K18 + 0x582C001A, // 0046 LDCONST R11 K26 + 0x5C301000, // 0047 MOVE R12 R8 + 0x7C240600, // 0048 CALL R9 3 + 0xB0063609, // 0049 RAISE 1 K27 R9 + 0x8C240F1C, // 004A GETMET R9 R7 K28 + 0x5C2C0C00, // 004B MOVE R11 R6 + 0x7C240400, // 004C CALL R9 2 + 0x8C240F1D, // 004D GETMET R9 R7 K29 + 0x7C240200, // 004E CALL R9 1 + 0x8C14010A, // 004F GETMET R5 R0 K10 + 0x7C140200, // 0050 CALL R5 1 + 0x8C14030B, // 0051 GETMET R5 R1 K11 + 0x581C000C, // 0052 LDCONST R7 K12 + 0x7C140400, // 0053 CALL R5 2 + 0x70020000, // 0054 JMP #0056 + 0xB0063D1F, // 0055 RAISE 1 K30 K31 + 0xA8040001, // 0056 EXBLK 1 1 + 0x7002001B, // 0057 JMP #0074 + 0xAC100002, // 0058 CATCH R4 0 2 + 0x70020018, // 0059 JMP #0073 + 0x60180001, // 005A GETGBL R6 G1 + 0x8C1C0512, // 005B GETMET R7 R2 K18 + 0x58240020, // 005C LDCONST R9 K32 + 0x5C280800, // 005D MOVE R10 R4 + 0x5C2C0A00, // 005E MOVE R11 R5 + 0x7C1C0800, // 005F CALL R7 4 + 0x7C180200, // 0060 CALL R6 1 + 0x8C180321, // 0061 GETMET R6 R1 K33 + 0x58200022, // 0062 LDCONST R8 K34 + 0x7C180400, // 0063 CALL R6 2 + 0x8C180323, // 0064 GETMET R6 R1 K35 + 0x7C180200, // 0065 CALL R6 1 + 0x8C180324, // 0066 GETMET R6 R1 K36 + 0x8C200512, // 0067 GETMET R8 R2 K18 + 0x58280025, // 0068 LDCONST R10 K37 + 0x5C2C0800, // 0069 MOVE R11 R4 + 0x5C300A00, // 006A MOVE R12 R5 + 0x7C200800, // 006B CALL R8 4 + 0x7C180400, // 006C CALL R6 2 + 0x8C180326, // 006D GETMET R6 R1 K38 + 0x88200327, // 006E GETMBR R8 R1 K39 + 0x7C180400, // 006F CALL R6 2 + 0x8C180328, // 0070 GETMET R6 R1 K40 + 0x7C180200, // 0071 CALL R6 1 + 0x70020000, // 0072 JMP #0074 + 0xB0080000, // 0073 RAISE 2 R0 R0 + 0x80000000, // 0074 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: autoexec +********************************************************************/ +be_local_closure(autoexec, /* name */ + be_nested_proto( + 9, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[32]) { /* constants */ + /* K0 */ be_nested_string("_archive", -290407892, 8), + /* K1 */ be_nested_string("path", -2071507658, 4), + /* K2 */ be_nested_string("#init.bat", -997372219, 9), + /* K3 */ be_nested_string("is_first_time", 275242384, 13), + /* K4 */ be_nested_string("exists", 1002329533, 6), + /* K5 */ be_nested_string("set_first_time", -1183719746, 14), + /* K6 */ be_nested_string("run_bat", -1758063998, 7), + /* K7 */ be_nested_string("tasmota", 424643812, 7), + /* K8 */ be_nested_string("log", 1062293841, 3), + /* K9 */ be_nested_string("CFG: 'init.bat' done, restarting", 1569670677, 32), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_string("cmd", -158181397, 3), + /* K12 */ be_nested_string("Restart 1", -790511441, 9), + /* K13 */ be_nested_string("#display.ini", 182218220, 12), + /* K14 */ be_nested_string("gpio", -1656812038, 4), + /* K15 */ be_nested_string("pin_used", -261112684, 8), + /* K16 */ be_nested_string("OPTION_A", 1133299440, 8), + /* K17 */ be_nested_string("display.ini", -1648793295, 11), + /* K18 */ be_nested_string("CFG: skipping 'display.ini' because already present in file-system", -329418032, 66), + /* K19 */ be_nested_string("display", 1164572437, 7), + /* K20 */ be_nested_string("r", -150190315, 1), + /* K21 */ be_nested_string("read", -824204347, 4), + /* K22 */ be_nested_string("close", 667630371, 5), + /* K23 */ be_nested_string("start", 1697318111, 5), + /* K24 */ be_nested_string("#autoexec.bat", -912076799, 13), + /* K25 */ be_nested_string("CFG: running ", -1816632762, 13), + /* K26 */ be_const_int(3), + /* K27 */ be_nested_string("CFG: ran ", -715396824, 10), + /* K28 */ be_nested_string("#autoexec.be", 1181757091, 12), + /* K29 */ be_nested_string("CFG: loading ", -284605793, 13), + /* K30 */ be_nested_string("load", -435725847, 4), + /* K31 */ be_nested_string("CFG: loaded ", -584693758, 13), + }), + (be_nested_const_str("autoexec", -618105405, 8)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[107]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x4C080000, // 0001 LDNIL R2 + 0x1C040202, // 0002 EQ R1 R1 R2 + 0x78060000, // 0003 JMPF R1 #0005 + 0x80000200, // 0004 RET 0 + 0xA4060200, // 0005 IMPORT R1 K1 + 0x88080100, // 0006 GETMBR R2 R0 K0 + 0x00080502, // 0007 ADD R2 R2 K2 + 0x8C0C0103, // 0008 GETMET R3 R0 K3 + 0x7C0C0200, // 0009 CALL R3 1 + 0x780E0012, // 000A JMPF R3 #001E + 0x8C0C0304, // 000B GETMET R3 R1 K4 + 0x5C140400, // 000C MOVE R5 R2 + 0x7C0C0400, // 000D CALL R3 2 + 0x780E000E, // 000E JMPF R3 #001E + 0x8C0C0105, // 000F GETMET R3 R0 K5 + 0x7C0C0200, // 0010 CALL R3 1 + 0x8C0C0106, // 0011 GETMET R3 R0 K6 + 0x5C140400, // 0012 MOVE R5 R2 + 0x7C0C0400, // 0013 CALL R3 2 + 0xB80E0E00, // 0014 GETNGBL R3 K7 + 0x8C0C0708, // 0015 GETMET R3 R3 K8 + 0x58140009, // 0016 LDCONST R5 K9 + 0x5818000A, // 0017 LDCONST R6 K10 + 0x7C0C0600, // 0018 CALL R3 3 + 0xB80E0E00, // 0019 GETNGBL R3 K7 + 0x8C0C070B, // 001A GETMET R3 R3 K11 + 0x5814000C, // 001B LDCONST R5 K12 + 0x7C0C0400, // 001C CALL R3 2 + 0x80000600, // 001D RET 0 + 0x880C0100, // 001E GETMBR R3 R0 K0 + 0x000C070D, // 001F ADD R3 R3 K13 + 0x5C080600, // 0020 MOVE R2 R3 + 0xB80E1C00, // 0021 GETNGBL R3 K14 + 0x8C0C070F, // 0022 GETMET R3 R3 K15 + 0xB8161C00, // 0023 GETNGBL R5 K14 + 0x88140B10, // 0024 GETMBR R5 R5 K16 + 0x5818000A, // 0025 LDCONST R6 K10 + 0x7C0C0600, // 0026 CALL R3 3 + 0x780E0019, // 0027 JMPF R3 #0042 + 0x8C0C0304, // 0028 GETMET R3 R1 K4 + 0x5C140400, // 0029 MOVE R5 R2 + 0x7C0C0400, // 002A CALL R3 2 + 0x780E0015, // 002B JMPF R3 #0042 + 0x8C0C0304, // 002C GETMET R3 R1 K4 + 0x58140011, // 002D LDCONST R5 K17 + 0x7C0C0400, // 002E CALL R3 2 + 0x780E0005, // 002F JMPF R3 #0036 + 0xB80E0E00, // 0030 GETNGBL R3 K7 + 0x8C0C0708, // 0031 GETMET R3 R3 K8 + 0x58140012, // 0032 LDCONST R5 K18 + 0x5818000A, // 0033 LDCONST R6 K10 + 0x7C0C0600, // 0034 CALL R3 3 + 0x7002000B, // 0035 JMP #0042 + 0xA40E2600, // 0036 IMPORT R3 K19 + 0x60100011, // 0037 GETGBL R4 G17 + 0x5C140400, // 0038 MOVE R5 R2 + 0x58180014, // 0039 LDCONST R6 K20 + 0x7C100400, // 003A CALL R4 2 + 0x8C140915, // 003B GETMET R5 R4 K21 + 0x7C140200, // 003C CALL R5 1 + 0x8C180916, // 003D GETMET R6 R4 K22 + 0x7C180200, // 003E CALL R6 1 + 0x8C180717, // 003F GETMET R6 R3 K23 + 0x5C200A00, // 0040 MOVE R8 R5 + 0x7C180400, // 0041 CALL R6 2 + 0x880C0100, // 0042 GETMBR R3 R0 K0 + 0x000C0718, // 0043 ADD R3 R3 K24 + 0x5C080600, // 0044 MOVE R2 R3 + 0x8C0C0304, // 0045 GETMET R3 R1 K4 + 0x5C140400, // 0046 MOVE R5 R2 + 0x7C0C0400, // 0047 CALL R3 2 + 0x780E000C, // 0048 JMPF R3 #0056 + 0xB80E0E00, // 0049 GETNGBL R3 K7 + 0x8C0C0708, // 004A GETMET R3 R3 K8 + 0x00163202, // 004B ADD R5 K25 R2 + 0x5818001A, // 004C LDCONST R6 K26 + 0x7C0C0600, // 004D CALL R3 3 + 0x8C0C0106, // 004E GETMET R3 R0 K6 + 0x5C140400, // 004F MOVE R5 R2 + 0x7C0C0400, // 0050 CALL R3 2 + 0xB80E0E00, // 0051 GETNGBL R3 K7 + 0x8C0C0708, // 0052 GETMET R3 R3 K8 + 0x00163602, // 0053 ADD R5 K27 R2 + 0x5818001A, // 0054 LDCONST R6 K26 + 0x7C0C0600, // 0055 CALL R3 3 + 0x880C0100, // 0056 GETMBR R3 R0 K0 + 0x000C071C, // 0057 ADD R3 R3 K28 + 0x5C080600, // 0058 MOVE R2 R3 + 0x8C0C0304, // 0059 GETMET R3 R1 K4 + 0x5C140400, // 005A MOVE R5 R2 + 0x7C0C0400, // 005B CALL R3 2 + 0x780E000C, // 005C JMPF R3 #006A + 0xB80E0E00, // 005D GETNGBL R3 K7 + 0x8C0C0708, // 005E GETMET R3 R3 K8 + 0x00163A02, // 005F ADD R5 K29 R2 + 0x5818001A, // 0060 LDCONST R6 K26 + 0x7C0C0600, // 0061 CALL R3 3 + 0xB80E3C00, // 0062 GETNGBL R3 K30 + 0x5C100400, // 0063 MOVE R4 R2 + 0x7C0C0200, // 0064 CALL R3 1 + 0xB80E0E00, // 0065 GETNGBL R3 K7 + 0x8C0C0708, // 0066 GETMET R3 R3 K8 + 0x00163E02, // 0067 ADD R5 K31 R2 + 0x5818001A, // 0068 LDCONST R6 K26 + 0x7C0C0600, // 0069 CALL R3 3 + 0x80000000, // 006A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: run_bat +********************************************************************/ +be_local_closure(run_bat, /* name */ + be_nested_proto( + 13, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_nested_string("string", 398550328, 6), + /* K1 */ be_nested_string("r", -150190315, 1), + /* K2 */ be_nested_string("readline", 1212709927, 8), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_string("\n", 252472541, 1), + /* K5 */ be_nested_string("tasmota", 424643812, 7), + /* K6 */ be_nested_string("cmd", -158181397, 3), + /* K7 */ be_nested_string("close", 667630371, 5), + /* K8 */ be_nested_string("format", -1180859054, 6), + /* K9 */ be_nested_string("CFG: could not run %s (%s - %s)", 1428829580, 31), + }), + (be_nested_const_str("run_bat", -1758063998, 7)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[54]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x4C0C0000, // 0001 LDNIL R3 + 0xA8020023, // 0002 EXBLK 0 #0027 + 0x60100011, // 0003 GETGBL R4 G17 + 0x5C140200, // 0004 MOVE R5 R1 + 0x58180001, // 0005 LDCONST R6 K1 + 0x7C100400, // 0006 CALL R4 2 + 0x5C0C0800, // 0007 MOVE R3 R4 + 0x50100200, // 0008 LDBOOL R4 1 0 + 0x78120018, // 0009 JMPF R4 #0023 + 0x8C100702, // 000A GETMET R4 R3 K2 + 0x7C100200, // 000B CALL R4 1 + 0x6014000C, // 000C GETGBL R5 G12 + 0x5C180800, // 000D MOVE R6 R4 + 0x7C140200, // 000E CALL R5 1 + 0x1C140B03, // 000F EQ R5 R5 K3 + 0x78160000, // 0010 JMPF R5 #0012 + 0x70020010, // 0011 JMP #0023 + 0x5415FFFE, // 0012 LDINT R5 -1 + 0x94140805, // 0013 GETIDX R5 R4 R5 + 0x1C140B04, // 0014 EQ R5 R5 K4 + 0x78160002, // 0015 JMPF R5 #0019 + 0x5415FFFD, // 0016 LDINT R5 -2 + 0x40160605, // 0017 CONNECT R5 K3 R5 + 0x94100805, // 0018 GETIDX R4 R4 R5 + 0x6014000C, // 0019 GETGBL R5 G12 + 0x5C180800, // 001A MOVE R6 R4 + 0x7C140200, // 001B CALL R5 1 + 0x24140B03, // 001C GT R5 R5 K3 + 0x78160003, // 001D JMPF R5 #0022 + 0xB8160A00, // 001E GETNGBL R5 K5 + 0x8C140B06, // 001F GETMET R5 R5 K6 + 0x5C1C0800, // 0020 MOVE R7 R4 + 0x7C140400, // 0021 CALL R5 2 + 0x7001FFE4, // 0022 JMP #0008 + 0x8C100707, // 0023 GETMET R4 R3 K7 + 0x7C100200, // 0024 CALL R4 1 + 0xA8040001, // 0025 EXBLK 1 1 + 0x7002000D, // 0026 JMP #0035 + 0xAC100002, // 0027 CATCH R4 0 2 + 0x7002000A, // 0028 JMP #0034 + 0x60180001, // 0029 GETGBL R6 G1 + 0x8C1C0508, // 002A GETMET R7 R2 K8 + 0x58240009, // 002B LDCONST R9 K9 + 0x5C280200, // 002C MOVE R10 R1 + 0x5C2C0800, // 002D MOVE R11 R4 + 0x5C300A00, // 002E MOVE R12 R5 + 0x7C1C0A00, // 002F CALL R7 5 + 0x7C180200, // 0030 CALL R6 1 + 0x8C180707, // 0031 GETMET R6 R3 K7 + 0x7C180200, // 0032 CALL R6 1 + 0x70020000, // 0033 JMP #0035 + 0xB0080000, // 0034 RAISE 2 R0 R0 + 0x80000000, // 0035 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: page_autoconf_mgr +********************************************************************/ +be_local_closure(page_autoconf_mgr, /* name */ + be_nested_proto( + 19, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[39]) { /* constants */ + /* K0 */ be_nested_string("webserver", 1572454038, 9), + /* K1 */ be_nested_string("string", 398550328, 6), + /* K2 */ be_nested_string("check_privileged_access", -602033328, 23), + /* K3 */ be_nested_string("content_start", -1357458227, 13), + /* K4 */ be_nested_string("Auto-configuration", 1665006109, 18), + /* K5 */ be_nested_string("content_send_style", 1087907647, 18), + /* K6 */ be_nested_string("content_send", 1673733649, 12), + /* K7 */ be_nested_string("

 (This feature requires an internet connection)

", -1575700810, 74), + /* K8 */ be_nested_string("get_current_module_path", -1088293888, 23), + /* K9 */ be_nested_string("tr", 1195724803, 2), + /* K10 */ be_nested_string("get_current_module_name", -1915696556, 23), + /* K11 */ be_nested_string("_", -636741266, 1), + /* K12 */ be_nested_string(" ", 621580159, 1), + /* K13 */ be_nested_string("_error", 1132109656, 6), + /* K14 */ be_nested_string("<Error: apply new or remove>", -1439459347, 34), + /* K15 */ be_nested_string("<None>", -1692801798, 12), + /* K16 */ be_nested_string("
", 842307168, 77), + /* K17 */ be_nested_string("format", -1180859054, 6), + /* K18 */ be_nested_string(" Current auto-configuration", -82466516, 82), + /* K19 */ be_nested_string("

Current configuration:

%s

", -179311535, 46), + /* K20 */ be_nested_string("

", 232646018, 57), + /* K22 */ be_nested_string("", -1147033080, 82), + /* K23 */ be_nested_string("

", -748395557, 11), + /* K24 */ be_nested_string("

", 2052843416, 25), + /* K25 */ be_nested_string(" Select new auto-configuration", 1926223891, 80), + /* K26 */ be_nested_string("

", -502554737, 94), + /* K28 */ be_nested_string("
", 1336654704, 49), + /* K29 */ be_nested_string("

", 1863865923, 16), + /* K35 */ be_nested_string("", 1205771629, 72), + /* K36 */ be_nested_string("content_button", 1956476087, 14), + /* K37 */ be_nested_string("BUTTON_CONFIGURATION", 70820856, 20), + /* K38 */ be_nested_string("content_stop", 658554751, 12), + }), + (be_nested_const_str("page_autoconf_mgr", -651030265, 17)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[124]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0x8C0C0302, // 0002 GETMET R3 R1 K2 + 0x7C0C0200, // 0003 CALL R3 1 + 0x740E0001, // 0004 JMPT R3 #0007 + 0x4C0C0000, // 0005 LDNIL R3 + 0x80040600, // 0006 RET 1 R3 + 0x8C0C0303, // 0007 GETMET R3 R1 K3 + 0x58140004, // 0008 LDCONST R5 K4 + 0x7C0C0400, // 0009 CALL R3 2 + 0x8C0C0305, // 000A GETMET R3 R1 K5 + 0x7C0C0200, // 000B CALL R3 1 + 0x8C0C0306, // 000C GETMET R3 R1 K6 + 0x58140007, // 000D LDCONST R5 K7 + 0x7C0C0400, // 000E CALL R3 2 + 0x8C0C0108, // 000F GETMET R3 R0 K8 + 0x7C0C0200, // 0010 CALL R3 1 + 0x780E0006, // 0011 JMPF R3 #0019 + 0x8C100509, // 0012 GETMET R4 R2 K9 + 0x8C18010A, // 0013 GETMET R6 R0 K10 + 0x7C180200, // 0014 CALL R6 1 + 0x581C000B, // 0015 LDCONST R7 K11 + 0x5820000C, // 0016 LDCONST R8 K12 + 0x7C100800, // 0017 CALL R4 4 + 0x70020004, // 0018 JMP #001E + 0x8810010D, // 0019 GETMBR R4 R0 K13 + 0x78120001, // 001A JMPF R4 #001D + 0x5810000E, // 001B LDCONST R4 K14 + 0x70020000, // 001C JMP #001E + 0x5810000F, // 001D LDCONST R4 K15 + 0x8C140306, // 001E GETMET R5 R1 K6 + 0x581C0010, // 001F LDCONST R7 K16 + 0x7C140400, // 0020 CALL R5 2 + 0x8C140306, // 0021 GETMET R5 R1 K6 + 0x8C1C0511, // 0022 GETMET R7 R2 K17 + 0x58240012, // 0023 LDCONST R9 K18 + 0x7C1C0400, // 0024 CALL R7 2 + 0x7C140400, // 0025 CALL R5 2 + 0x8C140306, // 0026 GETMET R5 R1 K6 + 0x8C1C0511, // 0027 GETMET R7 R2 K17 + 0x58240013, // 0028 LDCONST R9 K19 + 0x5C280800, // 0029 MOVE R10 R4 + 0x7C1C0600, // 002A CALL R7 3 + 0x7C140400, // 002B CALL R5 2 + 0x780E000B, // 002C JMPF R3 #0039 + 0x8C140306, // 002D GETMET R5 R1 K6 + 0x581C0014, // 002E LDCONST R7 K20 + 0x7C140400, // 002F CALL R5 2 + 0x8C140306, // 0030 GETMET R5 R1 K6 + 0x581C0015, // 0031 LDCONST R7 K21 + 0x7C140400, // 0032 CALL R5 2 + 0x8C140306, // 0033 GETMET R5 R1 K6 + 0x581C0016, // 0034 LDCONST R7 K22 + 0x7C140400, // 0035 CALL R5 2 + 0x8C140306, // 0036 GETMET R5 R1 K6 + 0x581C0017, // 0037 LDCONST R7 K23 + 0x7C140400, // 0038 CALL R5 2 + 0x8C140306, // 0039 GETMET R5 R1 K6 + 0x581C0018, // 003A LDCONST R7 K24 + 0x7C140400, // 003B CALL R5 2 + 0x8C140306, // 003C GETMET R5 R1 K6 + 0x581C0010, // 003D LDCONST R7 K16 + 0x7C140400, // 003E CALL R5 2 + 0x8C140306, // 003F GETMET R5 R1 K6 + 0x8C1C0511, // 0040 GETMET R7 R2 K17 + 0x58240019, // 0041 LDCONST R9 K25 + 0x7C1C0400, // 0042 CALL R7 2 + 0x7C140400, // 0043 CALL R5 2 + 0x8C140306, // 0044 GETMET R5 R1 K6 + 0x581C001A, // 0045 LDCONST R7 K26 + 0x7C140400, // 0046 CALL R5 2 + 0x8C140306, // 0047 GETMET R5 R1 K6 + 0x581C001B, // 0048 LDCONST R7 K27 + 0x7C140400, // 0049 CALL R5 2 + 0x8C140306, // 004A GETMET R5 R1 K6 + 0x581C001C, // 004B LDCONST R7 K28 + 0x7C140400, // 004C CALL R5 2 + 0x8C140306, // 004D GETMET R5 R1 K6 + 0x581C001D, // 004E LDCONST R7 K29 + 0x7C140400, // 004F CALL R5 2 + 0x8C14011E, // 0050 GETMET R5 R0 K30 + 0x7C140200, // 0051 CALL R5 1 + 0x8C180306, // 0052 GETMET R6 R1 K6 + 0x5820001F, // 0053 LDCONST R8 K31 + 0x7C180400, // 0054 CALL R6 2 + 0x60180010, // 0055 GETGBL R6 G16 + 0x5C1C0A00, // 0056 MOVE R7 R5 + 0x7C180200, // 0057 CALL R6 1 + 0xA802000D, // 0058 EXBLK 0 #0067 + 0x5C1C0C00, // 0059 MOVE R7 R6 + 0x7C1C0000, // 005A CALL R7 0 + 0x8C200306, // 005B GETMET R8 R1 K6 + 0x8C280511, // 005C GETMET R10 R2 K17 + 0x58300020, // 005D LDCONST R12 K32 + 0x5C340E00, // 005E MOVE R13 R7 + 0x8C380509, // 005F GETMET R14 R2 K9 + 0x5C400E00, // 0060 MOVE R16 R7 + 0x5844000B, // 0061 LDCONST R17 K11 + 0x5848000C, // 0062 LDCONST R18 K12 + 0x7C380800, // 0063 CALL R14 4 + 0x7C280800, // 0064 CALL R10 4 + 0x7C200400, // 0065 CALL R8 2 + 0x7001FFF1, // 0066 JMP #0059 + 0x58180021, // 0067 LDCONST R6 K33 + 0xAC180200, // 0068 CATCH R6 1 0 + 0xB0080000, // 0069 RAISE 2 R0 R0 + 0x8C180306, // 006A GETMET R6 R1 K6 + 0x58200022, // 006B LDCONST R8 K34 + 0x7C180400, // 006C CALL R6 2 + 0x8C180306, // 006D GETMET R6 R1 K6 + 0x58200023, // 006E LDCONST R8 K35 + 0x7C180400, // 006F CALL R6 2 + 0x8C180306, // 0070 GETMET R6 R1 K6 + 0x58200017, // 0071 LDCONST R8 K23 + 0x7C180400, // 0072 CALL R6 2 + 0x8C180306, // 0073 GETMET R6 R1 K6 + 0x58200018, // 0074 LDCONST R8 K24 + 0x7C180400, // 0075 CALL R6 2 + 0x8C180324, // 0076 GETMET R6 R1 K36 + 0x88200325, // 0077 GETMBR R8 R1 K37 + 0x7C180400, // 0078 CALL R6 2 + 0x8C180326, // 0079 GETMET R6 R1 K38 + 0x7C180200, // 007A CALL R6 1 + 0x80000000, // 007B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_current_module_name +********************************************************************/ +be_local_closure(get_current_module_name, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 0, /* 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_string("_archive", -290407892, 8), + /* K1 */ be_const_int(0), + }), + (be_nested_const_str("get_current_module_name", -1915696556, 23)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 5]) { /* code */ + 0x5405FFF5, // 0000 LDINT R1 -10 + 0x40060201, // 0001 CONNECT R1 K1 R1 + 0x88080100, // 0002 GETMBR R2 R0 K0 + 0x94040401, // 0003 GETIDX R1 R2 R1 + 0x80040200, // 0004 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: delete_all_configs +********************************************************************/ +be_local_closure(delete_all_configs, /* name */ + be_nested_proto( + 10, /* nstack */ + 1, /* argc */ + 0, /* 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_string("path", -2071507658, 4), + /* K1 */ be_nested_string("string", 398550328, 6), + /* K2 */ be_nested_string("listdir", 2005220720, 7), + /* K3 */ be_nested_string("/", 705468254, 1), + /* K4 */ be_nested_string("find", -1108310694, 4), + /* K5 */ be_nested_string(".autoconf", -1770288208, 9), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_string("remove", -611183107, 6), + /* K8 */ be_nested_string("stop_iteration", -121173395, 14), + }), + (be_nested_const_str("delete_all_configs", -1912899718, 18)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[25]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0x8C0C0302, // 0002 GETMET R3 R1 K2 + 0x58140003, // 0003 LDCONST R5 K3 + 0x7C0C0400, // 0004 CALL R3 2 + 0x60100010, // 0005 GETGBL R4 G16 + 0x5C140600, // 0006 MOVE R5 R3 + 0x7C100200, // 0007 CALL R4 1 + 0xA802000B, // 0008 EXBLK 0 #0015 + 0x5C140800, // 0009 MOVE R5 R4 + 0x7C140000, // 000A CALL R5 0 + 0x8C180504, // 000B GETMET R6 R2 K4 + 0x5C200A00, // 000C MOVE R8 R5 + 0x58240005, // 000D LDCONST R9 K5 + 0x7C180600, // 000E CALL R6 3 + 0x24180D06, // 000F GT R6 R6 K6 + 0x781A0002, // 0010 JMPF R6 #0014 + 0x8C180307, // 0011 GETMET R6 R1 K7 + 0x5C200A00, // 0012 MOVE R8 R5 + 0x7C180400, // 0013 CALL R6 2 + 0x7001FFF3, // 0014 JMP #0009 + 0x58100008, // 0015 LDCONST R4 K8 + 0xAC100200, // 0016 CATCH R4 1 0 + 0xB0080000, // 0017 RAISE 2 R0 R0 + 0x80000000, // 0018 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_first_time +********************************************************************/ +be_local_closure(set_first_time, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 0, /* 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_string("/.autoconf", -2082892903, 10), + /* K1 */ be_nested_string("w", -234078410, 1), + /* K2 */ be_nested_string("close", 667630371, 5), + }), + (be_nested_const_str("set_first_time", -1183719746, 14)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 7]) { /* code */ + 0x60040011, // 0000 GETGBL R1 G17 + 0x58080000, // 0001 LDCONST R2 K0 + 0x580C0001, // 0002 LDCONST R3 K1 + 0x7C040400, // 0003 CALL R1 2 + 0x8C080302, // 0004 GETMET R2 R1 K2 + 0x7C080200, // 0005 CALL R2 1 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: load_templates +********************************************************************/ +be_local_closure(load_templates, /* name */ + be_nested_proto( + 15, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[21]) { /* constants */ + /* K0 */ be_nested_string("string", 398550328, 6), + /* K1 */ be_nested_string("json", 916562499, 4), + /* K2 */ be_nested_string("format", -1180859054, 6), + /* K3 */ be_nested_string("https://raw.githubusercontent.com/tasmota/autoconf/main/%s_manifest.json", -637415251, 72), + /* K4 */ be_nested_string("tasmota", 424643812, 7), + /* K5 */ be_nested_string("arch", -1342162999, 4), + /* K6 */ be_nested_string("log", 1062293841, 3), + /* K7 */ be_nested_string("CFG: loading '%s'", -2009661199, 17), + /* K8 */ be_const_int(3), + /* K9 */ be_nested_string("webclient", -218578150, 9), + /* K10 */ be_nested_string("begin", 1748273790, 5), + /* K11 */ be_nested_string("GET", -1763262857, 3), + /* K12 */ be_nested_string("CFG: return_code=%i", 2059897320, 19), + /* K13 */ be_const_int(2), + /* K14 */ be_nested_string("get_string", -99119327, 10), + /* K15 */ be_nested_string("close", 667630371, 5), + /* K16 */ be_nested_string("load", -435725847, 4), + /* K17 */ be_nested_string("CFG: loaded '%s'", 1699028828, 16), + /* K18 */ be_nested_string("find", -1108310694, 4), + /* K19 */ be_nested_string("files", 1055342736, 5), + /* K20 */ be_nested_string("CFG: exception '%s' - '%s'", -199559383, 26), + }), + (be_nested_const_str("load_templates", -781097163, 14)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[86]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0xA8020042, // 0002 EXBLK 0 #0046 + 0x8C0C0302, // 0003 GETMET R3 R1 K2 + 0x58140003, // 0004 LDCONST R5 K3 + 0xB81A0800, // 0005 GETNGBL R6 K4 + 0x8C180D05, // 0006 GETMET R6 R6 K5 + 0x7C180200, // 0007 CALL R6 1 + 0x7C0C0600, // 0008 CALL R3 3 + 0xB8120800, // 0009 GETNGBL R4 K4 + 0x8C100906, // 000A GETMET R4 R4 K6 + 0x8C180302, // 000B GETMET R6 R1 K2 + 0x58200007, // 000C LDCONST R8 K7 + 0x5C240600, // 000D MOVE R9 R3 + 0x7C180600, // 000E CALL R6 3 + 0x581C0008, // 000F LDCONST R7 K8 + 0x7C100600, // 0010 CALL R4 3 + 0xB8121200, // 0011 GETNGBL R4 K9 + 0x7C100000, // 0012 CALL R4 0 + 0x8C14090A, // 0013 GETMET R5 R4 K10 + 0x5C1C0600, // 0014 MOVE R7 R3 + 0x7C140400, // 0015 CALL R5 2 + 0x8C14090B, // 0016 GETMET R5 R4 K11 + 0x7C140200, // 0017 CALL R5 1 + 0x541A00C7, // 0018 LDINT R6 200 + 0x20180A06, // 0019 NE R6 R5 R6 + 0x781A000A, // 001A JMPF R6 #0026 + 0xB81A0800, // 001B GETNGBL R6 K4 + 0x8C180D06, // 001C GETMET R6 R6 K6 + 0x8C200302, // 001D GETMET R8 R1 K2 + 0x5828000C, // 001E LDCONST R10 K12 + 0x5C2C0A00, // 001F MOVE R11 R5 + 0x7C200600, // 0020 CALL R8 3 + 0x5824000D, // 0021 LDCONST R9 K13 + 0x7C180600, // 0022 CALL R6 3 + 0x4C180000, // 0023 LDNIL R6 + 0xA8040001, // 0024 EXBLK 1 1 + 0x80040C00, // 0025 RET 1 R6 + 0x8C18090E, // 0026 GETMET R6 R4 K14 + 0x7C180200, // 0027 CALL R6 1 + 0x8C1C090F, // 0028 GETMET R7 R4 K15 + 0x7C1C0200, // 0029 CALL R7 1 + 0x8C1C0510, // 002A GETMET R7 R2 K16 + 0x5C240C00, // 002B MOVE R9 R6 + 0x7C1C0400, // 002C CALL R7 2 + 0xB8220800, // 002D GETNGBL R8 K4 + 0x8C201106, // 002E GETMET R8 R8 K6 + 0x8C280302, // 002F GETMET R10 R1 K2 + 0x58300011, // 0030 LDCONST R12 K17 + 0x60340008, // 0031 GETGBL R13 G8 + 0x5C380E00, // 0032 MOVE R14 R7 + 0x7C340200, // 0033 CALL R13 1 + 0x7C280600, // 0034 CALL R10 3 + 0x582C0008, // 0035 LDCONST R11 K8 + 0x7C200600, // 0036 CALL R8 3 + 0x8C200F12, // 0037 GETMET R8 R7 K18 + 0x58280013, // 0038 LDCONST R10 K19 + 0x7C200400, // 0039 CALL R8 2 + 0x6024000F, // 003A GETGBL R9 G15 + 0x5C281000, // 003B MOVE R10 R8 + 0x602C0012, // 003C GETGBL R11 G18 + 0x7C240400, // 003D CALL R9 2 + 0x78260001, // 003E JMPF R9 #0041 + 0xA8040001, // 003F EXBLK 1 1 + 0x80041000, // 0040 RET 1 R8 + 0x4C240000, // 0041 LDNIL R9 + 0xA8040001, // 0042 EXBLK 1 1 + 0x80041200, // 0043 RET 1 R9 + 0xA8040001, // 0044 EXBLK 1 1 + 0x7002000E, // 0045 JMP #0055 + 0xAC0C0002, // 0046 CATCH R3 0 2 + 0x7002000B, // 0047 JMP #0054 + 0xB8160800, // 0048 GETNGBL R5 K4 + 0x8C140B06, // 0049 GETMET R5 R5 K6 + 0x8C1C0302, // 004A GETMET R7 R1 K2 + 0x58240014, // 004B LDCONST R9 K20 + 0x5C280600, // 004C MOVE R10 R3 + 0x5C2C0800, // 004D MOVE R11 R4 + 0x7C1C0800, // 004E CALL R7 4 + 0x5820000D, // 004F LDCONST R8 K13 + 0x7C140600, // 0050 CALL R5 3 + 0x4C140000, // 0051 LDNIL R5 + 0x80040A00, // 0052 RET 1 R5 + 0x70020000, // 0053 JMP #0055 + 0xB0080000, // 0054 RAISE 2 R0 R0 + 0x80000000, // 0055 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: web_add_config_button +********************************************************************/ +be_local_closure(web_add_config_button, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 0, /* 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_string("webserver", 1572454038, 9), + /* K1 */ be_nested_string("content_send", 1673733649, 12), + /* K2 */ be_nested_string("

", 452285201, 120), + }), + (be_nested_const_str("web_add_config_button", 639674325, 21)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 5]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080301, // 0001 GETMET R2 R1 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x7C080400, // 0003 CALL R2 2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: is_first_time +********************************************************************/ +be_local_closure(is_first_time, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 0, /* 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_string("path", -2071507658, 4), + /* K1 */ be_nested_string("exists", 1002329533, 6), + /* K2 */ be_nested_string("/.autoconf", -2082892903, 10), + }), + (be_nested_const_str("is_first_time", 275242384, 13)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 8]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080301, // 0001 GETMET R2 R1 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x7C080400, // 0003 CALL R2 2 + 0x780A0000, // 0004 JMPF R2 #0006 + 0x50080001, // 0005 LDBOOL R2 0 1 + 0x50080200, // 0006 LDBOOL R2 1 0 + 0x80040400, // 0007 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(init, /* name */ + be_nested_proto( + 12, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[17]) { /* constants */ + /* K0 */ be_nested_str_literal("path"), + /* K1 */ be_nested_str_literal("string"), + /* K2 */ be_nested_str_literal("listdir"), + /* K3 */ be_nested_str_literal("/"), + /* K4 */ be_nested_str_literal("tasmota"), + /* K5 */ be_nested_str_literal("add_driver"), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_literal("find"), + /* K8 */ be_nested_str_literal(".autoconf"), + /* K9 */ be_nested_str_literal("format"), + /* K10 */ be_nested_str_literal("CFG: multiple autoconf files found, aborting ('%s' + '%s')"), + /* K11 */ be_nested_str_literal("_error"), + /* K12 */ be_const_int(1), + /* K13 */ be_nested_str_literal("log"), + /* K14 */ be_nested_str_literal("CFG: no '*.autoconf' file found"), + /* K15 */ be_const_int(2), + /* K16 */ be_nested_str_literal("_archive"), + }), + (be_nested_const_str("init", 380752755, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[51]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0x8C0C0302, // 0002 GETMET R3 R1 K2 + 0x58140003, // 0003 LDCONST R5 K3 + 0x7C0C0400, // 0004 CALL R3 2 + 0x4C100000, // 0005 LDNIL R4 + 0xB8160800, // 0006 GETNGBL R5 K4 + 0x8C140B05, // 0007 GETMET R5 R5 K5 + 0x5C1C0000, // 0008 MOVE R7 R0 + 0x7C140400, // 0009 CALL R5 2 + 0x58140006, // 000A LDCONST R5 K6 + 0x6018000C, // 000B GETGBL R6 G12 + 0x5C1C0600, // 000C MOVE R7 R3 + 0x7C180200, // 000D CALL R6 1 + 0x14180A06, // 000E LT R6 R5 R6 + 0x781A0016, // 000F JMPF R6 #0027 + 0x8C180507, // 0010 GETMET R6 R2 K7 + 0x94200605, // 0011 GETIDX R8 R3 R5 + 0x58240008, // 0012 LDCONST R9 K8 + 0x7C180600, // 0013 CALL R6 3 + 0x24180D06, // 0014 GT R6 R6 K6 + 0x781A000E, // 0015 JMPF R6 #0025 + 0x4C180000, // 0016 LDNIL R6 + 0x20180806, // 0017 NE R6 R4 R6 + 0x781A000A, // 0018 JMPF R6 #0024 + 0x60180001, // 0019 GETGBL R6 G1 + 0x8C1C0509, // 001A GETMET R7 R2 K9 + 0x5824000A, // 001B LDCONST R9 K10 + 0x5C280800, // 001C MOVE R10 R4 + 0x942C0605, // 001D GETIDX R11 R3 R5 + 0x7C1C0800, // 001E CALL R7 4 + 0x7C180200, // 001F CALL R6 1 + 0x50180200, // 0020 LDBOOL R6 1 0 + 0x90021606, // 0021 SETMBR R0 K11 R6 + 0x4C180000, // 0022 LDNIL R6 + 0x80040C00, // 0023 RET 1 R6 + 0x94100605, // 0024 GETIDX R4 R3 R5 + 0x00140B0C, // 0025 ADD R5 R5 K12 + 0x7001FFE3, // 0026 JMP #000B + 0x4C180000, // 0027 LDNIL R6 + 0x1C180806, // 0028 EQ R6 R4 R6 + 0x781A0006, // 0029 JMPF R6 #0031 + 0xB81A0800, // 002A GETNGBL R6 K4 + 0x8C180D0D, // 002B GETMET R6 R6 K13 + 0x5820000E, // 002C LDCONST R8 K14 + 0x5824000F, // 002D LDCONST R9 K15 + 0x7C180600, // 002E CALL R6 3 + 0x4C180000, // 002F LDNIL R6 + 0x80040C00, // 0030 RET 1 R6 + 0x90022004, // 0031 SETMBR R0 K16 R4 + 0x80000000, // 0032 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: preinit +********************************************************************/ +be_local_closure(preinit, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_nested_string("_archive", -290407892, 8), + /* K1 */ be_nested_string("path", -2071507658, 4), + /* K2 */ be_nested_string("#preinit.be", 687035716, 11), + /* K3 */ be_nested_string("exists", 1002329533, 6), + /* K4 */ be_nested_string("tasmota", 424643812, 7), + /* K5 */ be_nested_string("log", 1062293841, 3), + /* K6 */ be_nested_string("CFG: loading ", -284605793, 13), + /* K7 */ be_const_int(3), + /* K8 */ be_nested_string("load", -435725847, 4), + /* K9 */ be_nested_string("CFG: loaded ", -584693758, 13), + }), + (be_nested_const_str("preinit", -1572960196, 7)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[26]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x4C080000, // 0001 LDNIL R2 + 0x1C040202, // 0002 EQ R1 R1 R2 + 0x78060000, // 0003 JMPF R1 #0005 + 0x80000200, // 0004 RET 0 + 0xA4060200, // 0005 IMPORT R1 K1 + 0x88080100, // 0006 GETMBR R2 R0 K0 + 0x00080502, // 0007 ADD R2 R2 K2 + 0x8C0C0303, // 0008 GETMET R3 R1 K3 + 0x5C140400, // 0009 MOVE R5 R2 + 0x7C0C0400, // 000A CALL R3 2 + 0x780E000C, // 000B JMPF R3 #0019 + 0xB80E0800, // 000C GETNGBL R3 K4 + 0x8C0C0705, // 000D GETMET R3 R3 K5 + 0x00160C02, // 000E ADD R5 K6 R2 + 0x58180007, // 000F LDCONST R6 K7 + 0x7C0C0600, // 0010 CALL R3 3 + 0xB80E1000, // 0011 GETNGBL R3 K8 + 0x5C100400, // 0012 MOVE R4 R2 + 0x7C0C0200, // 0013 CALL R3 1 + 0xB80E0800, // 0014 GETNGBL R3 K4 + 0x8C0C0705, // 0015 GETMET R3 R3 K5 + 0x00161202, // 0016 ADD R5 K9 R2 + 0x58180007, // 0017 LDCONST R6 K7 + 0x7C0C0600, // 0018 CALL R3 3 + 0x80000000, // 0019 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: reset +********************************************************************/ +be_local_closure(reset, /* name */ + be_nested_proto( + 12, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_nested_string("path", -2071507658, 4), + /* K1 */ be_nested_string("string", 398550328, 6), + /* K2 */ be_nested_string("listdir", 2005220720, 7), + /* K3 */ be_nested_string("/", 705468254, 1), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_string("find", -1108310694, 4), + /* K6 */ be_nested_string(".autoconf", -1770288208, 9), + /* K7 */ be_nested_string("remove", -611183107, 6), + /* K8 */ be_nested_string("format", -1180859054, 6), + /* K9 */ be_nested_string("CFG: removed file '%s'", 2048602473, 22), + /* K10 */ be_const_int(1), + /* K11 */ be_nested_string("_archive", -290407892, 8), + /* K12 */ be_nested_string("_error", 1132109656, 6), + }), + (be_nested_const_str("reset", 1695364032, 5)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[35]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0x8C0C0302, // 0002 GETMET R3 R1 K2 + 0x58140003, // 0003 LDCONST R5 K3 + 0x7C0C0400, // 0004 CALL R3 2 + 0x4C100000, // 0005 LDNIL R4 + 0x58140004, // 0006 LDCONST R5 K4 + 0x6018000C, // 0007 GETGBL R6 G12 + 0x5C1C0600, // 0008 MOVE R7 R3 + 0x7C180200, // 0009 CALL R6 1 + 0x14180A06, // 000A LT R6 R5 R6 + 0x781A0011, // 000B JMPF R6 #001E + 0x94180605, // 000C GETIDX R6 R3 R5 + 0x8C1C0505, // 000D GETMET R7 R2 K5 + 0x5C240C00, // 000E MOVE R9 R6 + 0x58280006, // 000F LDCONST R10 K6 + 0x7C1C0600, // 0010 CALL R7 3 + 0x241C0F04, // 0011 GT R7 R7 K4 + 0x781E0008, // 0012 JMPF R7 #001C + 0x8C1C0307, // 0013 GETMET R7 R1 K7 + 0x5C240C00, // 0014 MOVE R9 R6 + 0x7C1C0400, // 0015 CALL R7 2 + 0x601C0001, // 0016 GETGBL R7 G1 + 0x8C200508, // 0017 GETMET R8 R2 K8 + 0x58280009, // 0018 LDCONST R10 K9 + 0x5C2C0C00, // 0019 MOVE R11 R6 + 0x7C200600, // 001A CALL R8 3 + 0x7C1C0200, // 001B CALL R7 1 + 0x00140B0A, // 001C ADD R5 R5 K10 + 0x7001FFE8, // 001D JMP #0007 + 0x4C180000, // 001E LDNIL R6 + 0x90021606, // 001F SETMBR R0 K11 R6 + 0x4C180000, // 0020 LDNIL R6 + 0x90021806, // 0021 SETMBR R0 K12 R6 + 0x80000000, // 0022 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: web_add_handler +********************************************************************/ +be_local_closure(web_add_handler, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 2]) { + 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_string("page_autoconf_mgr", -651030265, 17), + }), + (be_nested_const_str("", 607256038, 8)), + ((bstring*) &be_const_str_input), + ( &(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 + }) + ), + 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_string("page_autoconf_ctl", -1841585800, 17), + }), + (be_nested_const_str("", 607256038, 8)), + ((bstring*) &be_const_str_input), + ( &(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[ 5]) { /* constants */ + /* K0 */ be_nested_string("webserver", 1572454038, 9), + /* K1 */ be_nested_string("on", 1630810064, 2), + /* K2 */ be_nested_string("/ac", -390315318, 3), + /* K3 */ be_nested_string("HTTP_GET", 1722467738, 8), + /* K4 */ be_nested_string("HTTP_POST", 1999554144, 9), + }), + (be_nested_const_str("web_add_handler", -304792334, 15)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[13]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080301, // 0001 GETMET R2 R1 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x84140000, // 0003 CLOSURE R5 P0 + 0x88180303, // 0004 GETMBR R6 R1 K3 + 0x7C080800, // 0005 CALL R2 4 + 0x8C080301, // 0006 GETMET R2 R1 K1 + 0x58100002, // 0007 LDCONST R4 K2 + 0x84140001, // 0008 CLOSURE R5 P1 + 0x88180304, // 0009 GETMBR R6 R1 K4 + 0x7C080800, // 000A CALL R2 4 + 0xA0000000, // 000B CLOSE R0 + 0x80000000, // 000C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: clear_first_time +********************************************************************/ +be_local_closure(clear_first_time, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 0, /* 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_string("path", -2071507658, 4), + /* K1 */ be_nested_string("remove", -611183107, 6), + /* K2 */ be_nested_string("/.autoconf", -2082892903, 10), + }), + (be_nested_const_str("clear_first_time", 632769909, 16)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 5]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080301, // 0001 GETMET R2 R1 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x7C080400, // 0003 CALL R2 2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_current_module_path +********************************************************************/ +be_local_closure(get_current_module_path, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 0, /* 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_string("_archive", -290407892, 8), + }), + (be_nested_const_str("get_current_module_path", -1088293888, 23)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Autoconf +********************************************************************/ +be_local_class(Autoconf, + 2, + NULL, + be_nested_map(18, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("page_autoconf_ctl", -1841585800, 17, -1), be_const_closure(page_autoconf_ctl_closure) }, + { be_nested_key("autoexec", -618105405, 8, -1), be_const_closure(autoexec_closure) }, + { be_nested_key("run_bat", -1758063998, 7, 6), be_const_closure(run_bat_closure) }, + { be_nested_key("page_autoconf_mgr", -651030265, 17, -1), be_const_closure(page_autoconf_mgr_closure) }, + { be_nested_key("get_current_module_name", -1915696556, 23, -1), be_const_closure(get_current_module_name_closure) }, + { be_nested_key("delete_all_configs", -1912899718, 18, 13), be_const_closure(delete_all_configs_closure) }, + { be_nested_key("set_first_time", -1183719746, 14, -1), be_const_closure(set_first_time_closure) }, + { be_nested_key("load_templates", -781097163, 14, -1), be_const_closure(load_templates_closure) }, + { be_nested_key("_archive", -290407892, 8, -1), be_const_var(0) }, + { be_nested_key("web_add_config_button", 639674325, 21, -1), be_const_closure(web_add_config_button_closure) }, + { be_nested_key("is_first_time", 275242384, 13, -1), be_const_closure(is_first_time_closure) }, + { be_nested_key("init", 380752755, 4, -1), be_const_closure(init_closure) }, + { be_nested_key("preinit", -1572960196, 7, 5), be_const_closure(preinit_closure) }, + { be_nested_key("reset", 1695364032, 5, 17), be_const_closure(reset_closure) }, + { be_nested_key("web_add_handler", -304792334, 15, 4), be_const_closure(web_add_handler_closure) }, + { be_nested_key("clear_first_time", 632769909, 16, 11), be_const_closure(clear_first_time_closure) }, + { be_nested_key("_error", 1132109656, 6, -1), be_const_var(1) }, + { be_nested_key("get_current_module_path", -1088293888, 23, -1), be_const_closure(get_current_module_path_closure) }, + })), + (be_nested_const_str("Autoconf", 984011268, 8)) +); + +/******************************************************************** +** Solidified function: _anonymous_ +********************************************************************/ +be_local_closure(_anonymous_, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_const_class(be_class_Autoconf), + }), + (be_nested_const_str("_anonymous_", 1957281476, 11)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 5]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0xB4000000, // 0001 CLASS K0 + 0x5C080200, // 0002 MOVE R2 R1 + 0x7C080000, // 0003 CALL R2 0 + 0x80040400, // 0004 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified module: autoconf +********************************************************************/ +be_local_module(autoconf, + "autoconf", + be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("init", 380752755, 4, -1), be_const_closure(_anonymous__closure) }, + })) +); +BE_EXPORT_VARIABLE be_define_const_native_module(autoconf); +/********************************************************************/ diff --git a/lib/libesp32/Berry/default/be_display_lib.c b/lib/libesp32/Berry/default/be_display_lib.c new file mode 100644 index 000000000..2d8bf9ff7 --- /dev/null +++ b/lib/libesp32/Berry/default/be_display_lib.c @@ -0,0 +1,29 @@ +/******************************************************************** + * Tasmota lib + * + * To use: `import display` + * + * Initialize Universal Display driver + *******************************************************************/ +#include "be_constobj.h" + +#ifdef USE_DISPLAY + +// Tasmota specific + +extern int be_disp_start(bvm *vm); + +/******************************************************************** +** Solidified module: display +********************************************************************/ +be_local_module(display, + "display", + be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("start", 1697318111, 5, -1), be_const_func(be_disp_start) }, + })) +); +BE_EXPORT_VARIABLE be_define_const_native_module(display); +/********************************************************************/ + +#endif // USE_DISPLAY \ No newline at end of file diff --git a/lib/libesp32/Berry/default/be_leds_animator_lib.c b/lib/libesp32/Berry/default/be_leds_animator_lib.c new file mode 100644 index 000000000..c5783edb9 --- /dev/null +++ b/lib/libesp32/Berry/default/be_leds_animator_lib.c @@ -0,0 +1,381 @@ +/******************************************************************** + * Berry class `Leds_animator` + * + *******************************************************************/ +#include "be_constobj.h" + +#ifdef USE_WS2812 + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Leds_animator_init, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_string("strip", -48555823, 5), + /* K1 */ be_nested_string("bri", 2112284244, 3), + /* K2 */ be_nested_string("running", 343848780, 7), + /* K3 */ be_nested_string("pixel_count", -1855836553, 11), + /* K4 */ be_nested_string("animators", 279858213, 9), + /* K5 */ be_nested_string("clear", 1550717474, 5), + /* K6 */ be_nested_string("tasmota", 424643812, 7), + /* K7 */ be_nested_string("add_driver", 1654458371, 10), + }), + (be_nested_const_str("init", 380752755, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[18]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x540A0031, // 0001 LDINT R2 50 + 0x90020202, // 0002 SETMBR R0 K1 R2 + 0x50080000, // 0003 LDBOOL R2 0 0 + 0x90020402, // 0004 SETMBR R0 K2 R2 + 0x8C080303, // 0005 GETMET R2 R1 K3 + 0x7C080200, // 0006 CALL R2 1 + 0x90020602, // 0007 SETMBR R0 K3 R2 + 0x60080012, // 0008 GETGBL R2 G18 + 0x7C080000, // 0009 CALL R2 0 + 0x90020802, // 000A SETMBR R0 K4 R2 + 0x8C080105, // 000B GETMET R2 R0 K5 + 0x7C080200, // 000C CALL R2 1 + 0xB80A0C00, // 000D GETNGBL R2 K6 + 0x8C080507, // 000E GETMET R2 R2 K7 + 0x5C100000, // 000F MOVE R4 R0 + 0x7C080400, // 0010 CALL R2 2 + 0x80000000, // 0011 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_bri +********************************************************************/ +be_local_closure(Leds_animator_set_bri, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 0, /* 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_string("bri", 2112284244, 3), + }), + (be_nested_const_str("set_bri", -1505848517, 7)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: stop +********************************************************************/ +be_local_closure(Leds_animator_stop, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 0, /* 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_string("running", 343848780, 7), + }), + (be_nested_const_str("stop", -883741979, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 3]) { /* code */ + 0x50040000, // 0000 LDBOOL R1 0 0 + 0x90020001, // 0001 SETMBR R0 K0 R1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: animate +********************************************************************/ +be_local_closure(Leds_animator_animate, /* name */ + be_nested_proto( + 1, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + (be_nested_const_str("animate", -409180496, 7)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove +********************************************************************/ +be_local_closure(Leds_animator_remove, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 0, /* 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_string("tasmota", 424643812, 7), + /* K1 */ be_nested_string("remove_driver", 1030243768, 13), + }), + (be_nested_const_str("remove", -611183107, 6)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 5]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x5C0C0000, // 0002 MOVE R3 R0 + 0x7C040400, // 0003 CALL R1 2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_50ms +********************************************************************/ +be_local_closure(Leds_animator_every_50ms, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 0, /* 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_string("running", 343848780, 7), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_string("animators", 279858213, 9), + /* K3 */ be_nested_string("is_running", -2068120035, 10), + /* K4 */ be_nested_string("animate", -409180496, 7), + /* K5 */ be_const_int(1), + /* K6 */ be_nested_string("remove", -611183107, 6), + }), + (be_nested_const_str("every_50ms", -1911083288, 10)), + ((bstring*) &be_const_str_input), + ( &(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: get_bri +********************************************************************/ +be_local_closure(Leds_animator_get_bri, /* name */ + be_nested_proto( + 3, /* nstack */ + 2, /* argc */ + 0, /* 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_string("bri", 2112284244, 3), + }), + (be_nested_const_str("get_bri", 2041809895, 7)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 2]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x80040400, // 0001 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start +********************************************************************/ +be_local_closure(Leds_animator_start, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 0, /* 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_string("running", 343848780, 7), + }), + (be_nested_const_str("start", 1697318111, 5)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 3]) { /* code */ + 0x50040200, // 0000 LDBOOL R1 1 0 + 0x90020001, // 0001 SETMBR R0 K0 R1 + 0x80000000, // 0002 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_anim +********************************************************************/ +be_local_closure(Leds_animator_add_anim, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 0, /* 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_string("animators", 279858213, 9), + /* K1 */ be_nested_string("push", -2022703139, 4), + /* K2 */ be_nested_string("run", 718098122, 3), + }), + (be_nested_const_str("add_anim", -314304628, 8)), + ((bstring*) &be_const_str_input), + ( &(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 +********************************************************************/ +be_local_closure(Leds_animator_clear, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 0, /* 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_string("stop", -883741979, 4), + /* K1 */ be_nested_string("strip", -48555823, 5), + /* K2 */ be_nested_string("clear", 1550717474, 5), + }), + (be_nested_const_str("clear", 1550717474, 5)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 6]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x88040101, // 0002 GETMBR R1 R0 K1 + 0x8C040302, // 0003 GETMET R1 R1 K2 + 0x7C040200, // 0004 CALL R1 1 + 0x80000000, // 0005 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Leds_animator +********************************************************************/ +be_local_class(Leds_animator, + 5, + NULL, + be_nested_map(15, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("init", 380752755, 4, 7), be_const_closure(Leds_animator_init_closure) }, + { be_nested_key("set_bri", -1505848517, 7, -1), be_const_closure(Leds_animator_set_bri_closure) }, + { be_nested_key("stop", -883741979, 4, -1), be_const_closure(Leds_animator_stop_closure) }, + { be_nested_key("strip", -48555823, 5, 4), be_const_var(0) }, + { be_nested_key("animators", 279858213, 9, 12), be_const_var(4) }, + { be_nested_key("animate", -409180496, 7, -1), be_const_closure(Leds_animator_animate_closure) }, + { be_nested_key("remove", -611183107, 6, -1), be_const_closure(Leds_animator_remove_closure) }, + { be_nested_key("running", 343848780, 7, -1), be_const_var(3) }, + { be_nested_key("every_50ms", -1911083288, 10, -1), be_const_closure(Leds_animator_every_50ms_closure) }, + { be_nested_key("bri", 2112284244, 3, 6), be_const_var(2) }, + { be_nested_key("get_bri", 2041809895, 7, -1), be_const_closure(Leds_animator_get_bri_closure) }, + { be_nested_key("start", 1697318111, 5, -1), be_const_closure(Leds_animator_start_closure) }, + { be_nested_key("add_anim", -314304628, 8, 13), be_const_closure(Leds_animator_add_anim_closure) }, + { be_nested_key("pixel_count", -1855836553, 11, -1), be_const_var(1) }, + { be_nested_key("clear", 1550717474, 5, 1), be_const_closure(Leds_animator_clear_closure) }, + })), + (be_nested_const_str("Leds_animator", 142168673, 13)) +); +/*******************************************************************/ + +void be_load_Leds_animator_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Leds_animator); + be_setglobal(vm, "Leds_animator"); + be_pop(vm, 1); +} + +#endif // USE_WS2812 diff --git a/lib/libesp32/Berry/default/be_leds_lib.c b/lib/libesp32/Berry/default/be_leds_lib.c new file mode 100644 index 000000000..a4442df37 --- /dev/null +++ b/lib/libesp32/Berry/default/be_leds_lib.c @@ -0,0 +1,619 @@ +/******************************************************************** + * Berry class `Leds` + * + *******************************************************************/ +#include "be_constobj.h" + +#ifdef USE_WS2812 + +/******************************************************************** +** Solidified function: get_pixel_color +********************************************************************/ +be_local_closure(Leds_get_pixel_color, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 0, /* 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_literal("call_native"), + }), + (be_nested_const_str("get_pixel_color", 337490048, 15)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 5]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x5412000A, // 0001 LDINT R4 11 + 0x5C140200, // 0002 MOVE R5 R1 + 0x7C080600, // 0003 CALL R2 3 + 0x80040400, // 0004 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: pixels_buffer +********************************************************************/ +be_local_closure(Leds_pixels_buffer, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 0, /* 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_literal("call_native"), + }), + (be_nested_const_str("pixels_buffer", 1229555807, 13)), + ((bstring*) &be_const_str_input), + ( &(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 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: clear +********************************************************************/ +be_local_closure(Leds_clear, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 0, /* 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_literal("clear_to"), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str_literal("show"), + }), + (be_nested_const_str("clear", 1550717474, 5)), + ((bstring*) &be_const_str_input), + ( &(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: init +********************************************************************/ +be_local_closure(Leds_init, /* name */ + be_nested_proto( + 11, /* nstack */ + 5, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[11]) { /* constants */ + /* K0 */ be_nested_str_literal("gamma"), + /* K1 */ be_nested_str_literal("pin"), + /* K2 */ be_nested_str_literal("WS2812"), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_literal("valuer_error"), + /* K5 */ be_nested_str_literal("no GPIO specified for neopixelbus"), + /* K6 */ be_nested_str_literal("ctor"), + /* K7 */ be_nested_str_literal("_p"), + /* K8 */ be_nested_str_literal("internal_error"), + /* K9 */ be_nested_str_literal("couldn't not initialize noepixelbus"), + /* K10 */ be_nested_str_literal("begin"), + }), + (be_nested_const_str("init", 380752755, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[32]) { /* code */ + 0x50140200, // 0000 LDBOOL R5 1 0 + 0x90020005, // 0001 SETMBR R0 K0 R5 + 0x4C140000, // 0002 LDNIL R5 + 0x1C140405, // 0003 EQ R5 R2 R5 + 0x78160008, // 0004 JMPF R5 #000E + 0x8C140501, // 0005 GETMET R5 R2 K1 + 0x881C0502, // 0006 GETMBR R7 R2 K2 + 0x7C140400, // 0007 CALL R5 2 + 0x28140B03, // 0008 GE R5 R5 K3 + 0x78160003, // 0009 JMPF R5 #000E + 0x8C140501, // 000A GETMET R5 R2 K1 + 0x881C0502, // 000B GETMBR R7 R2 K2 + 0x7C140400, // 000C CALL R5 2 + 0x5C080A00, // 000D MOVE R2 R5 + 0x4C140000, // 000E LDNIL R5 + 0x1C140405, // 000F EQ R5 R2 R5 + 0x78160000, // 0010 JMPF R5 #0012 + 0xB0060905, // 0011 RAISE 1 K4 K5 + 0x8C140106, // 0012 GETMET R5 R0 K6 + 0x5C1C0200, // 0013 MOVE R7 R1 + 0x5C200400, // 0014 MOVE R8 R2 + 0x5C240600, // 0015 MOVE R9 R3 + 0x5C280800, // 0016 MOVE R10 R4 + 0x7C140A00, // 0017 CALL R5 5 + 0x88140107, // 0018 GETMBR R5 R0 K7 + 0x4C180000, // 0019 LDNIL R6 + 0x1C140A06, // 001A EQ R5 R5 R6 + 0x78160000, // 001B JMPF R5 #001D + 0xB0061109, // 001C RAISE 1 K8 K9 + 0x8C14010A, // 001D GETMET R5 R0 K10 + 0x7C140200, // 001E CALL R5 1 + 0x80000000, // 001F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_pixel_color +********************************************************************/ +be_local_closure(Leds_set_pixel_color, /* name */ + be_nested_proto( + 12, /* nstack */ + 4, /* argc */ + 0, /* 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_literal("call_native"), + /* K1 */ be_nested_str_literal("to_gamma"), + }), + (be_nested_const_str("set_pixel_color", 1275248356, 15)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 9]) { /* code */ + 0x8C100100, // 0000 GETMET R4 R0 K0 + 0x541A0009, // 0001 LDINT R6 10 + 0x5C1C0200, // 0002 MOVE R7 R1 + 0x8C200101, // 0003 GETMET R8 R0 K1 + 0x5C280400, // 0004 MOVE R10 R2 + 0x5C2C0600, // 0005 MOVE R11 R3 + 0x7C200600, // 0006 CALL R8 3 + 0x7C100800, // 0007 CALL R4 4 + 0x80000000, // 0008 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: begin +********************************************************************/ +be_local_closure(Leds_begin, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 0, /* 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_literal("call_native"), + /* K1 */ be_const_int(1), + }), + (be_nested_const_str("begin", 1748273790, 5)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x580C0001, // 0001 LDCONST R3 K1 + 0x7C040400, // 0002 CALL R1 2 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: to_gamma +********************************************************************/ +be_local_closure(Leds_to_gamma, /* name */ + be_nested_proto( + 12, /* nstack */ + 3, /* argc */ + 0, /* 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_literal("tasmota"), + /* K1 */ be_nested_str_literal("scale_uint"), + /* K2 */ be_const_int(0), + /* K3 */ be_const_int(16711680), + /* K4 */ be_nested_str_literal("gamma"), + /* K5 */ be_nested_str_literal("light"), + /* K6 */ be_nested_str_literal("gamma8"), + }), + (be_nested_const_str("to_gamma", 1597139862, 8)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[67]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x200C0403, // 0001 NE R3 R2 R3 + 0x780E0001, // 0002 JMPF R3 #0005 + 0x5C0C0400, // 0003 MOVE R3 R2 + 0x70020000, // 0004 JMP #0006 + 0x540E0063, // 0005 LDINT R3 100 + 0x5C080600, // 0006 MOVE R2 R3 + 0xB80E0000, // 0007 GETNGBL R3 K0 + 0x8C0C0701, // 0008 GETMET R3 R3 K1 + 0x5C140400, // 0009 MOVE R5 R2 + 0x58180002, // 000A LDCONST R6 K2 + 0x541E0063, // 000B LDINT R7 100 + 0x58200002, // 000C LDCONST R8 K2 + 0x2C240303, // 000D AND R9 R1 K3 + 0x542A000F, // 000E LDINT R10 16 + 0x3C24120A, // 000F SHR R9 R9 R10 + 0x7C0C0C00, // 0010 CALL R3 6 + 0xB8120000, // 0011 GETNGBL R4 K0 + 0x8C100901, // 0012 GETMET R4 R4 K1 + 0x5C180400, // 0013 MOVE R6 R2 + 0x581C0002, // 0014 LDCONST R7 K2 + 0x54220063, // 0015 LDINT R8 100 + 0x58240002, // 0016 LDCONST R9 K2 + 0x542AFEFF, // 0017 LDINT R10 65280 + 0x2C28020A, // 0018 AND R10 R1 R10 + 0x542E0007, // 0019 LDINT R11 8 + 0x3C28140B, // 001A SHR R10 R10 R11 + 0x7C100C00, // 001B CALL R4 6 + 0xB8160000, // 001C GETNGBL R5 K0 + 0x8C140B01, // 001D GETMET R5 R5 K1 + 0x5C1C0400, // 001E MOVE R7 R2 + 0x58200002, // 001F LDCONST R8 K2 + 0x54260063, // 0020 LDINT R9 100 + 0x58280002, // 0021 LDCONST R10 K2 + 0x542E00FE, // 0022 LDINT R11 255 + 0x2C2C020B, // 0023 AND R11 R1 R11 + 0x7C140C00, // 0024 CALL R5 6 + 0x88180104, // 0025 GETMBR R6 R0 K4 + 0x781A0013, // 0026 JMPF R6 #003B + 0xB81A0A00, // 0027 GETNGBL R6 K5 + 0x8C180D06, // 0028 GETMET R6 R6 K6 + 0x5C200600, // 0029 MOVE R8 R3 + 0x7C180400, // 002A CALL R6 2 + 0x541E000F, // 002B LDINT R7 16 + 0x38180C07, // 002C SHL R6 R6 R7 + 0xB81E0A00, // 002D GETNGBL R7 K5 + 0x8C1C0F06, // 002E GETMET R7 R7 K6 + 0x5C240800, // 002F MOVE R9 R4 + 0x7C1C0400, // 0030 CALL R7 2 + 0x54220007, // 0031 LDINT R8 8 + 0x381C0E08, // 0032 SHL R7 R7 R8 + 0x30180C07, // 0033 OR R6 R6 R7 + 0xB81E0A00, // 0034 GETNGBL R7 K5 + 0x8C1C0F06, // 0035 GETMET R7 R7 K6 + 0x5C240A00, // 0036 MOVE R9 R5 + 0x7C1C0400, // 0037 CALL R7 2 + 0x30180C07, // 0038 OR R6 R6 R7 + 0x80040C00, // 0039 RET 1 R6 + 0x70020006, // 003A JMP #0042 + 0x541A000F, // 003B LDINT R6 16 + 0x38180606, // 003C SHL R6 R3 R6 + 0x541E0007, // 003D LDINT R7 8 + 0x381C0807, // 003E SHL R7 R4 R7 + 0x30180C07, // 003F OR R6 R6 R7 + 0x30180C05, // 0040 OR R6 R6 R5 + 0x80040C00, // 0041 RET 1 R6 + 0x80000000, // 0042 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: pixel_count +********************************************************************/ +be_local_closure(Leds_pixel_count, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 0, /* 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_literal("call_native"), + }), + (be_nested_const_str("pixel_count", -1855836553, 11)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E0007, // 0001 LDINT R3 8 + 0x7C040400, // 0002 CALL R1 2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: can_show +********************************************************************/ +be_local_closure(Leds_can_show, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 0, /* 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_literal("call_native"), + /* K1 */ be_const_int(3), + }), + (be_nested_const_str("can_show", 960091187, 8)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x580C0001, // 0001 LDCONST R3 K1 + 0x7C040400, // 0002 CALL R1 2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: pixel_size +********************************************************************/ +be_local_closure(Leds_pixel_size, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 0, /* 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_literal("call_native"), + }), + (be_nested_const_str("pixel_size", -2085831511, 10)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E0006, // 0001 LDINT R3 7 + 0x7C040400, // 0002 CALL R1 2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: dirty +********************************************************************/ +be_local_closure(Leds_dirty, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 0, /* 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_literal("call_native"), + }), + (be_nested_const_str("dirty", -1627386213, 5)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E0004, // 0001 LDINT R3 5 + 0x7C040400, // 0002 CALL R1 2 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: show +********************************************************************/ +be_local_closure(Leds_show, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 0, /* 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_literal("call_native"), + /* K1 */ be_const_int(2), + }), + (be_nested_const_str("show", -1454906820, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x580C0001, // 0001 LDCONST R3 K1 + 0x7C040400, // 0002 CALL R1 2 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: clear_to +********************************************************************/ +be_local_closure(Leds_clear_to, /* name */ + be_nested_proto( + 10, /* nstack */ + 3, /* argc */ + 0, /* 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_literal("call_native"), + /* K1 */ be_nested_str_literal("to_gamma"), + }), + (be_nested_const_str("clear_to", -766965166, 8)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 8]) { /* code */ + 0x8C0C0100, // 0000 GETMET R3 R0 K0 + 0x54160008, // 0001 LDINT R5 9 + 0x8C180101, // 0002 GETMET R6 R0 K1 + 0x5C200200, // 0003 MOVE R8 R1 + 0x5C240400, // 0004 MOVE R9 R2 + 0x7C180600, // 0005 CALL R6 3 + 0x7C0C0600, // 0006 CALL R3 3 + 0x80000000, // 0007 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: is_dirty +********************************************************************/ +be_local_closure(Leds_is_dirty, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 0, /* 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_literal("call_native"), + }), + (be_nested_const_str("is_dirty", 418034110, 8)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 4]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E0003, // 0001 LDINT R3 4 + 0x7C040400, // 0002 CALL R1 2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: ctor +********************************************************************/ +be_local_closure(Leds_ctor, /* name */ + be_nested_proto( + 10, /* nstack */ + 4, /* argc */ + 0, /* 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_literal("call_native"), + /* K1 */ be_const_int(0), + }), + (be_nested_const_str("ctor", 375399343, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[16]) { /* code */ + 0x4C100000, // 0000 LDNIL R4 + 0x1C100604, // 0001 EQ R4 R3 R4 + 0x78120005, // 0002 JMPF R4 #0009 + 0x8C100100, // 0003 GETMET R4 R0 K0 + 0x58180001, // 0004 LDCONST R6 K1 + 0x5C1C0200, // 0005 MOVE R7 R1 + 0x5C200400, // 0006 MOVE R8 R2 + 0x7C100800, // 0007 CALL R4 4 + 0x70020005, // 0008 JMP #000F + 0x8C100100, // 0009 GETMET R4 R0 K0 + 0x58180001, // 000A LDCONST R6 K1 + 0x5C1C0200, // 000B MOVE R7 R1 + 0x5C200400, // 000C MOVE R8 R2 + 0x5C240600, // 000D MOVE R9 R3 + 0x7C100A00, // 000E CALL R4 5 + 0x80000000, // 000F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Leds +********************************************************************/ +extern const bclass be_class_Leds_ntv; +be_local_class(Leds, + 1, + &be_class_Leds_ntv, + be_nested_map(16, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("get_pixel_color", 337490048, 15, -1), be_const_closure(Leds_get_pixel_color_closure) }, + { be_nested_key("ctor", 375399343, 4, -1), be_const_closure(Leds_ctor_closure) }, + { be_nested_key("clear", 1550717474, 5, 8), be_const_closure(Leds_clear_closure) }, + { be_nested_key("init", 380752755, 4, 13), be_const_closure(Leds_init_closure) }, + { be_nested_key("set_pixel_color", 1275248356, 15, -1), be_const_closure(Leds_set_pixel_color_closure) }, + { be_nested_key("is_dirty", 418034110, 8, -1), be_const_closure(Leds_is_dirty_closure) }, + { be_nested_key("to_gamma", 1597139862, 8, -1), be_const_closure(Leds_to_gamma_closure) }, + { be_nested_key("pixel_count", -1855836553, 11, -1), be_const_closure(Leds_pixel_count_closure) }, + { be_nested_key("clear_to", -766965166, 8, -1), be_const_closure(Leds_clear_to_closure) }, + { be_nested_key("pixel_size", -2085831511, 10, -1), be_const_closure(Leds_pixel_size_closure) }, + { be_nested_key("gamma", -802614262, 5, -1), be_const_var(0) }, + { be_nested_key("dirty", -1627386213, 5, -1), be_const_closure(Leds_dirty_closure) }, + { be_nested_key("show", -1454906820, 4, -1), be_const_closure(Leds_show_closure) }, + { be_nested_key("can_show", 960091187, 8, -1), be_const_closure(Leds_can_show_closure) }, + { be_nested_key("begin", 1748273790, 5, 5), be_const_closure(Leds_begin_closure) }, + { be_nested_key("pixels_buffer", 1229555807, 13, 1), be_const_closure(Leds_pixels_buffer_closure) }, + })), + be_str_literal("Leds") +); +/*******************************************************************/ + +void be_load_Leds_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Leds); + be_setglobal(vm, "Leds"); + be_pop(vm, 1); +} + +#endif // USE_WS2812 diff --git a/lib/libesp32/Berry/default/be_leds_matrix_lib.c b/lib/libesp32/Berry/default/be_leds_matrix_lib.c new file mode 100644 index 000000000..1aafb3db4 --- /dev/null +++ b/lib/libesp32/Berry/default/be_leds_matrix_lib.c @@ -0,0 +1,185 @@ +/******************************************************************** + * Berry class `Leds_matrix` + * + *******************************************************************/ +#include "be_constobj.h" + +#ifdef USE_WS2812 + +/******************************************************************** +** Solidified function: get_alternate +********************************************************************/ +be_local_closure(Leds_matrix_get_alternate, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 0, /* 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_literal("alternate"), + }), + (be_nested_const_str("get_alternate", 1450148894, 13)), + ((bstring*) &be_const_str_input), + ( &(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 */ + 0, /* 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_literal("alternate"), + }), + (be_nested_const_str("set_alternate", 1709680562, 13)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 2]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x80000000, // 0001 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_matrix_pixel_color +********************************************************************/ +be_local_closure(Leds_matrix_set_matrix_pixel_color, /* name */ + be_nested_proto( + 10, /* nstack */ + 5, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_literal("alternate"), + /* K1 */ be_const_int(2), + /* K2 */ be_nested_str_literal("set_pixel_color"), + /* K3 */ be_nested_str_literal("w"), + /* K4 */ be_nested_str_literal("h"), + /* K5 */ be_const_int(1), + }), + (be_nested_const_str("set_matrix_pixel_color", 1197149462, 22)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[23]) { /* code */ + 0x88140100, // 0000 GETMBR R5 R0 K0 + 0x7816000C, // 0001 JMPF R5 #000F + 0x10140301, // 0002 MOD R5 R1 K1 + 0x7816000A, // 0003 JMPF R5 #000F + 0x8C140102, // 0004 GETMET R5 R0 K2 + 0x881C0103, // 0005 GETMBR R7 R0 K3 + 0x081C0207, // 0006 MUL R7 R1 R7 + 0x88200104, // 0007 GETMBR R8 R0 K4 + 0x001C0E08, // 0008 ADD R7 R7 R8 + 0x041C0E02, // 0009 SUB R7 R7 R2 + 0x041C0F05, // 000A SUB R7 R7 K5 + 0x5C200600, // 000B MOVE R8 R3 + 0x5C240800, // 000C MOVE R9 R4 + 0x7C140800, // 000D CALL R5 4 + 0x70020006, // 000E JMP #0016 + 0x8C140102, // 000F GETMET R5 R0 K2 + 0x881C0103, // 0010 GETMBR R7 R0 K3 + 0x081C0207, // 0011 MUL R7 R1 R7 + 0x001C0E02, // 0012 ADD R7 R7 R2 + 0x5C200600, // 0013 MOVE R8 R3 + 0x5C240800, // 0014 MOVE R9 R4 + 0x7C140800, // 0015 CALL R5 4 + 0x80000000, // 0016 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Leds_matrix_init, /* name */ + be_nested_proto( + 10, /* nstack */ + 5, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_literal("w"), + /* K1 */ be_nested_str_literal("h"), + /* K2 */ be_nested_str_literal("alternate"), + /* K3 */ be_nested_str_literal("init"), + }), + (be_nested_const_str("init", 380752755, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[13]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x50140000, // 0002 LDBOOL R5 0 0 + 0x90020405, // 0003 SETMBR R0 K2 R5 + 0x60140003, // 0004 GETGBL R5 G3 + 0x5C180000, // 0005 MOVE R6 R0 + 0x7C140200, // 0006 CALL R5 1 + 0x8C140B03, // 0007 GETMET R5 R5 K3 + 0x081C0202, // 0008 MUL R7 R1 R2 + 0x5C200600, // 0009 MOVE R8 R3 + 0x5C240800, // 000A MOVE R9 R4 + 0x7C140800, // 000B CALL R5 4 + 0x80000000, // 000C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Leds_matrix +********************************************************************/ +extern const bclass be_class_Leds; +be_local_class(Leds_matrix, + 3, + &be_class_Leds, + be_nested_map(7, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("init", 380752755, 4, 3), be_const_closure(Leds_matrix_init_closure) }, + { be_nested_key("h", -317966505, 1, -1), be_const_var(0) }, + { be_nested_key("set_alternate", 1709680562, 13, 6), be_const_closure(Leds_matrix_set_alternate_closure) }, + { be_nested_key("set_matrix_pixel_color", 1197149462, 22, 4), be_const_closure(Leds_matrix_set_matrix_pixel_color_closure) }, + { be_nested_key("w", -234078410, 1, -1), be_const_var(1) }, + { be_nested_key("get_alternate", 1450148894, 13, 0), be_const_closure(Leds_matrix_get_alternate_closure) }, + { be_nested_key("alternate", 1140253277, 9, -1), be_const_var(2) }, + })), + be_str_literal("Leds_matrix") +); +/*******************************************************************/ + +void be_load_Leds_matrix_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Leds_matrix); + be_setglobal(vm, "Leds_matrix"); + be_pop(vm, 1); +} + + +#endif // USE_WS2812 diff --git a/lib/libesp32/Berry/default/be_leds_ntv_lib.c b/lib/libesp32/Berry/default/be_leds_ntv_lib.c new file mode 100644 index 000000000..5affc1c71 --- /dev/null +++ b/lib/libesp32/Berry/default/be_leds_ntv_lib.c @@ -0,0 +1,54 @@ +/******************************************************************** + * Berry class `neopixelbus_ntv` + * + *******************************************************************/ +/* + +class Leds_ntv + var _p # pointer to internal object of type `NeoPixelBus(uint16_t countPixels, uint8_t pin)` + var _t # type of led strip + static WS2812_GRB = 1 + static WS2812_GRBW = 2 + static SK6812_GRB = 3 + static SK6812_GRBW = 4 + + # skeleton for native call + def call_native() end +end + +*/ +#include "be_constobj.h" + +#ifdef USE_WS2812 + +extern int be_neopixelbus_call_native(bvm *vm); + + +/******************************************************************** +** Solidified class: Leds_ntv +********************************************************************/ +be_local_class(Leds_ntv, + 2, + NULL, + be_nested_map(7, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("WS2812_GRB", 1736405692, 10, 5), be_const_int(1) }, + { be_nested_key("_p", 1594591802, 2, -1), be_const_var(0) }, + { be_nested_key("WS2812_GRBW", -660477967, 11, 3), be_const_int(2) }, + { be_nested_key("call_native", 1389147405, 11, -1), be_const_func(be_neopixelbus_call_native) }, + { be_nested_key("SK6812_GRBW", 81157857, 11, -1), be_const_int(4) }, + { be_nested_key("_t", 1527481326, 2, -1), be_const_var(1) }, + { be_nested_key("SK6812_GRB", 1159411308, 10, 1), be_const_int(3) }, + })), + be_str_literal("Leds_ntv") +); +/*******************************************************************/ + +void be_load_Leds_ntv_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Leds_ntv); + be_setglobal(vm, "Leds_ntv"); + be_pop(vm, 1); +} + +// be_const_func(be_neopixelbus_call_native) +#endif // USE_WS2812 diff --git a/lib/libesp32/Berry/default/be_modtab.c b/lib/libesp32/Berry/default/be_modtab.c index 46b5528a9..5f04457ac 100644 --- a/lib/libesp32/Berry/default/be_modtab.c +++ b/lib/libesp32/Berry/default/be_modtab.c @@ -25,14 +25,19 @@ be_extern_native_module(strict); /* Tasmota specific */ be_extern_native_module(python_compat); +be_extern_native_module(re); be_extern_native_module(persist); +be_extern_native_module(autoconf); +be_extern_native_module(tapp); be_extern_native_module(light); be_extern_native_module(gpio); +be_extern_native_module(display); be_extern_native_module(energy); be_extern_native_module(webserver); be_extern_native_module(flash); be_extern_native_module(path); be_extern_native_module(unishox); +be_extern_native_module(animate); #ifdef USE_LVGL be_extern_native_module(lv); #endif // USE_LVGL @@ -83,9 +88,17 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = { /* user-defined modules register start */ &be_native_module(python_compat), + &be_native_module(re), &be_native_module(path), &be_native_module(persist), +#ifdef USE_AUTOCONF + &be_native_module(autoconf), +#endif // USE_AUTOCONF + &be_native_module(tapp), &be_native_module(gpio), +#ifdef USE_DISPLAY + &be_native_module(display), +#endif // USE_DISPLAY #ifdef USE_LIGHT &be_native_module(light), #endif @@ -93,6 +106,7 @@ BERRY_LOCAL const bntvmodule* const be_module_table[] = { #ifdef USE_UNISHOX_COMPRESSION &be_native_module(unishox), #endif // USE_UNISHOX_COMPRESSION + &be_native_module(animate), #ifdef USE_LVGL &be_native_module(lv), @@ -122,6 +136,10 @@ extern void be_load_AXP192_class(bvm *vm); extern void be_load_md5_lib(bvm *vm); extern void be_load_webclient_lib(bvm *vm); extern void be_load_crypto_lib(bvm *vm); +extern void be_load_Leds_ntv_class(bvm *vm); +extern void be_load_Leds_class(bvm *vm); +extern void be_load_Leds_matrix_class(bvm *vm); +extern void be_load_Leds_animator_class(bvm *vm); extern void be_load_ctypes_lib(bvm *vm); extern void be_load_ctypes_energy_definitions_lib(bvm *vm); @@ -176,6 +194,12 @@ BERRY_API void be_load_custom_libs(bvm *vm) #if defined(USE_ONEWIRE) || defined(USE_DS18x20) be_load_onewirelib(vm); #endif +#ifdef USE_WS2812 + be_load_Leds_ntv_class(vm); + be_load_Leds_class(vm); + be_load_Leds_matrix_class(vm); + be_load_Leds_animator_class(vm); +#endif // USE_WS2812 #ifdef USE_I2S_AUDIO_BERRY be_load_driver_audio_lib(vm); #endif diff --git a/lib/libesp32/Berry/default/be_path_tasmota_lib.c b/lib/libesp32/Berry/default/be_path_tasmota_lib.c index c4208203f..81711a053 100644 --- a/lib/libesp32/Berry/default/be_path_tasmota_lib.c +++ b/lib/libesp32/Berry/default/be_path_tasmota_lib.c @@ -18,13 +18,17 @@ #include "be_sys.h" #include +extern int m_path_listdir(bvm *vm); + static int m_path_exists(bvm *vm) { const char *path = NULL; if (be_top(vm) >= 1 && be_isstring(vm, 1)) { path = be_tostring(vm, 1); + be_pushbool(vm, be_isexist(path)); + } else { + be_pushbool(vm, bfalse); } - be_pushbool(vm, be_isexist(path)); be_return(vm); } extern time_t be_last_modified(void *hfile); @@ -43,10 +47,24 @@ static int m_path_last_modified(bvm *vm) be_return_nil(vm); } +static int m_path_remove(bvm *vm) +{ + const char *path = NULL; + if (be_top(vm) >= 1 && be_isstring(vm, 1)) { + path = be_tostring(vm, 1); + be_pushbool(vm, be_unlink(path)); + } else { + be_pushbool(vm, bfalse); + } + be_return(vm); +} + /* @const_object_info_begin module path (scope: global, file: tasmota_path) { exists, func(m_path_exists) last_modified, func(m_path_last_modified) + listdir, func(m_path_listdir) + remove, func(m_path_remove) } @const_object_info_end */ #include "../generate/be_fixed_tasmota_path.h" diff --git a/lib/libesp32/Berry/default/be_port.cpp b/lib/libesp32/Berry/default/be_port.cpp index 88815a000..5da10f47e 100644 --- a/lib/libesp32/Berry/default/be_port.cpp +++ b/lib/libesp32/Berry/default/be_port.cpp @@ -18,7 +18,9 @@ // Local pointer for file managment #ifdef USE_UFILESYS #include - extern FS *ufsp; + #include "ZipReadFS.h" + extern FS *ffsp; + FS zip_ufsp(ZipReadFSImplPtr(new ZipReadFSImpl(&ffsp))); #endif // USE_UFILESYS /* this file contains configuration for the file system. */ @@ -95,10 +97,42 @@ BERRY_API void be_writebuffer(const char *buffer, size_t length) // be_fwrite(stdout, buffer, length); } + +extern "C" { + int m_path_listdir(bvm *vm) + { + if (be_top(vm) >= 1 && be_isstring(vm, 1)) { + const char *path = be_tostring(vm, 1); + be_newobject(vm, "list"); + + File dir = ffsp->open(path, "r"); + if (dir) { + dir.rewindDirectory(); + while (1) { + File entry = dir.openNextFile(); + if (!entry) { + break; + } + const char * fn = entry.name(); + if (strcmp(fn, ".") && strcmp(fn, "..")) { + be_pushstring(vm, fn); + be_data_push(vm, -2); + be_pop(vm, 1); + } + + } + } + be_pop(vm, 1); + be_return(vm); + + } + be_return_nil(vm); + } +} + BERRY_API char* be_readstring(char *buffer, size_t size) { - return 0; - // return be_fgets(stdin, buffer, (int)size); + return be_fgets(stdin, buffer, (int)size); } /* use the standard library implementation file API. */ @@ -106,7 +140,7 @@ BERRY_API char* be_readstring(char *buffer, size_t size) void* be_fopen(const char *filename, const char *modes) { #ifdef USE_UFILESYS - if (ufsp != nullptr && filename != nullptr && modes != nullptr) { + if (filename != nullptr && modes != nullptr) { char fname2[strlen(filename) + 2]; if (filename[0] == '/') { strcpy(fname2, filename); // copy unchanged @@ -115,7 +149,7 @@ void* be_fopen(const char *filename, const char *modes) strcpy(fname2 + 1, filename); // prepend with '/' } // Serial.printf("be_fopen filename=%s, modes=%s\n", filename, modes); - File f = ufsp->open(fname2, modes); // returns an object, not a pointer + File f = zip_ufsp.open(fname2, modes); // returns an object, not a pointer if (f) { File * f_ptr = new File(f); // copy to dynamic object *f_ptr = f; // TODO is this necessary? @@ -127,11 +161,24 @@ void* be_fopen(const char *filename, const char *modes) // return fopen(filename, modes); } +// Tasmota specific, get the underlying Arduino File +File * be_get_arduino_file(void *hfile) +{ +#ifdef USE_UFILESYS + if (hfile != nullptr) { + File * f_ptr = (File*) hfile; + return f_ptr; + } +#endif // USE_UFILESYS + return nullptr; + // return fopen(filename, modes); +} + int be_fclose(void *hfile) { #ifdef USE_UFILESYS // Serial.printf("be_fclose\n"); - if (ufsp != nullptr && hfile != nullptr) { + if (hfile != nullptr) { File * f_ptr = (File*) hfile; f_ptr->close(); delete f_ptr; @@ -146,7 +193,7 @@ size_t be_fwrite(void *hfile, const void *buffer, size_t length) { #ifdef USE_UFILESYS // Serial.printf("be_fwrite %d\n", length); - if (ufsp != nullptr && hfile != nullptr && buffer != nullptr) { + if (hfile != nullptr && buffer != nullptr) { File * f_ptr = (File*) hfile; return f_ptr->write((const uint8_t*) buffer, length); } @@ -159,7 +206,7 @@ size_t be_fread(void *hfile, void *buffer, size_t length) { #ifdef USE_UFILESYS // Serial.printf("be_fread %d\n", length); - if (ufsp != nullptr && hfile != nullptr && buffer != nullptr) { + if (hfile != nullptr && buffer != nullptr) { File * f_ptr = (File*) hfile; int32_t ret = f_ptr->read((uint8_t*) buffer, length); if (ret >= 0) { @@ -175,13 +222,19 @@ size_t be_fread(void *hfile, void *buffer, size_t length) char* be_fgets(void *hfile, void *buffer, int size) { #ifdef USE_UFILESYS - // Serial.printf("be_fgets %d\n", size); + if (size <= 2) { return nullptr; } // can't work if size is 2 or less + // Serial.printf("be_fgets size=%d hfile=%p buf=%p\n", size, hfile, buffer); uint8_t * buf = (uint8_t*) buffer; - if (ufsp != nullptr && hfile != nullptr && buffer != nullptr && size > 0) { + if (hfile != nullptr && buffer != nullptr && size > 0) { File * f_ptr = (File*) hfile; - int ret = f_ptr->readBytesUntil('\n', buf, size - 1); + int ret = f_ptr->readBytesUntil('\n', buf, size - 2); + // Serial.printf("be_fgets ret=%d\n", ret); if (ret >= 0) { buf[ret] = 0; // add string terminator + if (ret > 0 && ret < size - 2) { + buf[ret] = '\n'; + buf[ret+1] = 0; + } return (char*) buffer; } } @@ -194,7 +247,7 @@ int be_fseek(void *hfile, long offset) { #ifdef USE_UFILESYS // Serial.printf("be_fseek %d\n", offset); - if (ufsp != nullptr && hfile != nullptr) { + if (hfile != nullptr) { File * f_ptr = (File*) hfile; if (f_ptr->seek(offset)) { return 0; // success @@ -209,7 +262,7 @@ long int be_ftell(void *hfile) { #ifdef USE_UFILESYS // Serial.printf("be_ftell\n"); - if (ufsp != nullptr && hfile != nullptr) { + if (hfile != nullptr) { File * f_ptr = (File*) hfile; return f_ptr->position(); } @@ -222,7 +275,7 @@ long int be_fflush(void *hfile) { #ifdef USE_UFILESYS // Serial.printf("be_fflush\n"); - if (ufsp != nullptr && hfile != nullptr) { + if (hfile != nullptr) { File * f_ptr = (File*) hfile; f_ptr->flush(); } @@ -235,7 +288,7 @@ size_t be_fsize(void *hfile) { #ifdef USE_UFILESYS // Serial.printf("be_fsize\n"); - if (ufsp != nullptr && hfile != nullptr) { + if (hfile != nullptr) { File * f_ptr = (File*) hfile; return f_ptr->size(); } @@ -251,7 +304,7 @@ size_t be_fsize(void *hfile) extern "C" time_t be_last_modified(void *hfile) { #ifdef USE_UFILESYS - if (ufsp != nullptr && hfile != nullptr) { + if (hfile != nullptr) { File * f_ptr = (File*) hfile; return f_ptr->getLastWrite(); } @@ -262,16 +315,29 @@ extern "C" time_t be_last_modified(void *hfile) int be_isexist(const char *filename) { #ifdef USE_UFILESYS - if (ufsp != nullptr) { - char fname2[strlen(filename) + 2]; - if (filename[0] == '/') { - strcpy(fname2, filename); // copy unchanged - } else { - fname2[0] = '/'; - strcpy(fname2 + 1, filename); // prepend with '/' - } - return ufsp->exists(fname2); + char fname2[strlen(filename) + 2]; + if (filename[0] == '/') { + strcpy(fname2, filename); // copy unchanged + } else { + fname2[0] = '/'; + strcpy(fname2 + 1, filename); // prepend with '/' } + return zip_ufsp.exists(fname2); +#endif // USE_UFILESYS + return 0; +} + +int be_unlink(const char *filename) +{ +#ifdef USE_UFILESYS + char fname2[strlen(filename) + 2]; + if (filename[0] == '/') { + strcpy(fname2, filename); // copy unchanged + } else { + fname2[0] = '/'; + strcpy(fname2 + 1, filename); // prepend with '/' + } + return zip_ufsp.remove(fname2); #endif // USE_UFILESYS return 0; } diff --git a/lib/libesp32/Berry/default/be_re_lib.c b/lib/libesp32/Berry/default/be_re_lib.c new file mode 100644 index 000000000..bc28c0e67 --- /dev/null +++ b/lib/libesp32/Berry/default/be_re_lib.c @@ -0,0 +1,254 @@ +/******************************************************************** + * Tasmota lib + * + * To use: `import re` + * + * Regex using re1.5 + *******************************************************************/ +#include "be_constobj.h" +#include "be_mem.h" +#include "re1.5.h" + +/******************************************************************** +# Berry skeleton for `re` module +# + +class re_pattern + var _p # comobj containing the compiled bytecode for the pattern + + def search() end + def match() end + def split() end +end + +re = module("re") + +re.compile = def (regex_str) end # native +re.match = def (regex_str, str) end # native +re.search = def (regex_str, str) end # native +re.split = def (regex_str, str) end # native + + +*******************************************************************/ + +extern const bclass be_class_re_pattern; + +int be_free_comobj(bvm* vm) { + int argc = be_top(vm); + if (argc > 0) { + void * obj = be_tocomptr(vm, 1); + if (obj != NULL) { be_os_free(obj); } + } + be_return_nil(vm); +} + +// Native functions be_const_func() +// Berry: `re.compile(pattern:string) -> instance(be_pattern)` +int be_re_compile(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 1 && be_isstring(vm, 1)) { + const char * regex_str = be_tostring(vm, 1); + int sz = re1_5_sizecode(regex_str); + if (sz < 0) { + be_raise(vm, "internal_error", "error in regex"); + } + + ByteProg *code = be_os_malloc(sizeof(ByteProg) + sz); + int ret = re1_5_compilecode(code, regex_str); + if (ret != 0) { + be_raise(vm, "internal_error", "error in regex"); + } + be_pushntvclass(vm, &be_class_re_pattern); + be_call(vm, 0); + be_newcomobj(vm, code, &be_free_comobj); + be_setmember(vm, -2, "_p"); + be_pop(vm, 1); + be_return(vm); + } + be_raise(vm, "type_error", NULL); +} + + +int be_re_match_search_run(bvm *vm, ByteProg *code, const char *hay, bbool is_anchored) { + Subject subj = {hay, hay + strlen(hay)}; + + int sub_els = (code->sub + 1) * 2; + const char *sub[sub_els]; + + if (!re1_5_recursiveloopprog(code, &subj, sub, sub_els, is_anchored)) { + be_return_nil(vm); // no match + } + + be_newobject(vm, "list"); + int k; + for(k = sub_els; k > 0; k--) + if(sub[k-1]) + break; + for (int i = 0; i < k; i += 2) { + be_pushnstring(vm, sub[i], sub[i+1] - sub[i]); + be_data_push(vm, -2); + be_pop(vm, 1); + } + be_pop(vm, 1); // remove list + be_return(vm); // return list object +} + +int be_re_match_search(bvm *vm, bbool is_anchored) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isstring(vm, 1) && be_isstring(vm, 2)) { + const char * regex_str = be_tostring(vm, 1); + const char * hay = be_tostring(vm, 2); + int sz = re1_5_sizecode(regex_str); + if (sz < 0) { + be_raise(vm, "internal_error", "error in regex"); + } + + ByteProg *code = be_os_malloc(sizeof(ByteProg) + sz); + int ret = re1_5_compilecode(code, regex_str); + if (ret != 0) { + be_raise(vm, "internal_error", "error in regex"); + } + return be_re_match_search_run(vm, code, hay, is_anchored); + } + be_raise(vm, "type_error", NULL); +} + +// Berry: `re.match(value:int | s:string) -> nil` +int be_re_match(bvm *vm) { + return be_re_match_search(vm, btrue); +} +// Berry: `re.search(value:int | s:string) -> nil` +int be_re_search(bvm *vm) { + return be_re_match_search(vm, bfalse); +} + +// Berry: `re_pattern.search(s:string) -> list(string)` +int re_pattern_search(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isstring(vm, 2)) { + const char * hay = be_tostring(vm, 2); + be_getmember(vm, 1, "_p"); + ByteProg * code = (ByteProg*) be_tocomptr(vm, -1); + return be_re_match_search_run(vm, code, hay, bfalse); + } + be_raise(vm, "type_error", NULL); +} + +// Berry: `re_pattern.match(s:string) -> list(string)` +int re_pattern_match(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isstring(vm, 2)) { + const char * hay = be_tostring(vm, 2); + be_getmember(vm, 1, "_p"); + ByteProg * code = (ByteProg*) be_tocomptr(vm, -1); + return be_re_match_search_run(vm, code, hay, btrue); + } + be_raise(vm, "type_error", NULL); +} + + +int re_pattern_split_run(bvm *vm, ByteProg *code, const char *hay, int split_limit) { + Subject subj = {hay, hay + strlen(hay)}; + + int sub_els = (code->sub + 1) * 2; + const char *sub[sub_els]; + + be_newobject(vm, "list"); + while (1) { + if (split_limit == 0 || !re1_5_recursiveloopprog(code, &subj, sub, sub_els, bfalse)) { + be_pushnstring(vm, subj.begin, subj.end - subj.begin); + be_data_push(vm, -2); + be_pop(vm, 1); + break; + } + + if (sub[0] == NULL || sub[1] == NULL || sub[0] == sub[1]) { + be_raise(vm, "internal_error", "can't match"); + } + be_pushnstring(vm, subj.begin, sub[0] - subj.begin); + be_data_push(vm, -2); + be_pop(vm, 1); + subj.begin = sub[1]; + split_limit--; + } + be_pop(vm, 1); // remove list + be_return(vm); // return list object +} + +// Berry: `re_pattern.split(s:string [, split_limit:int]) -> list(string)` +int re_pattern_split(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isstring(vm, 2)) { + int split_limit = -1; + if (argc >= 3) { + split_limit = be_toint(vm, 3); + } + const char * hay = be_tostring(vm, 2); + be_getmember(vm, 1, "_p"); + ByteProg * code = (ByteProg*) be_tocomptr(vm, -1); + + return re_pattern_split_run(vm, code, hay, split_limit); + } + be_raise(vm, "type_error", NULL); +} + +// Berry: `re.split(pattern:string, s:string [, split_limit:int]) -> list(string)` +int be_re_split(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isstring(vm, 1) && be_isstring(vm, 2)) { + const char * regex_str = be_tostring(vm, 1); + const char * hay = be_tostring(vm, 2); + int split_limit = -1; + if (argc >= 3) { + split_limit = be_toint(vm, 3); + } + int sz = re1_5_sizecode(regex_str); + if (sz < 0) { + be_raise(vm, "internal_error", "error in regex"); + } + + ByteProg *code = be_os_malloc(sizeof(ByteProg) + sz); + int ret = re1_5_compilecode(code, regex_str); + if (ret != 0) { + be_raise(vm, "internal_error", "error in regex"); + } + return re_pattern_split_run(vm, code, hay, split_limit); + } + be_raise(vm, "type_error", NULL); +} + +/******************************************************************** +** Solidified module: re +********************************************************************/ +be_local_module(re, + "re", + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("compile", 1000265118, 7, -1), be_const_func(be_re_compile) }, + { be_nested_key("search", -2144130903, 6, -1), be_const_func(be_re_search) }, + { be_nested_key("match", 2116038550, 5, 0), be_const_func(be_re_match) }, + { be_nested_key("split", -2017972765, 5, -1), be_const_func(be_re_split) }, + })) +); +BE_EXPORT_VARIABLE be_define_const_native_module(re); +/********************************************************************/ + +// =================================================================== + +/******************************************************************** +** Solidified class: re_pattern +********************************************************************/ +be_local_class(re_pattern, + 1, + NULL, + be_nested_map(4, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("_p", 1594591802, 2, -1), be_const_var(0) }, + { be_nested_key("search", -2144130903, 6, -1), be_const_func(re_pattern_search) }, + { be_nested_key("match", 2116038550, 5, 0), be_const_func(re_pattern_match) }, + { be_nested_key("split", -2017972765, 5, -1), be_const_func(re_pattern_split) }, + })), + (be_nested_const_str("re_pattern", 2041968961, 10)) +); +/*******************************************************************/ + diff --git a/lib/libesp32/Berry/default/be_tapp_lib.c b/lib/libesp32/Berry/default/be_tapp_lib.c new file mode 100644 index 000000000..7a8cbe693 --- /dev/null +++ b/lib/libesp32/Berry/default/be_tapp_lib.c @@ -0,0 +1,164 @@ +/******************************************************************** + * Tasmota App manager + * + * To use: `import tapp` + * + *******************************************************************/ +#include "be_constobj.h" + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(init, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 0, /* 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_string("tasmota", 424643812, 7), + /* K1 */ be_nested_string("add_driver", 1654458371, 10), + }), + (be_nested_const_str("init", 380752755, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 5]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x5C0C0000, // 0002 MOVE R3 R0 + 0x7C040400, // 0003 CALL R1 2 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: autoexec +********************************************************************/ +be_local_closure(autoexec, /* name */ + be_nested_proto( + 11, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_nested_string("path", -2071507658, 4), + /* K1 */ be_nested_string("string", 398550328, 6), + /* K2 */ be_nested_string("listdir", 2005220720, 7), + /* K3 */ be_nested_string("/", 705468254, 1), + /* K4 */ be_nested_string("find", -1108310694, 4), + /* K5 */ be_nested_string(".tapp", 1363391594, 5), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_string("format", -1180859054, 6), + /* K8 */ be_nested_string("TAP: found Tasmota App '%s'", -1651814898, 27), + /* K9 */ be_nested_string("tasmota", 424643812, 7), + /* K10 */ be_nested_string("load", -435725847, 4), + /* K11 */ be_nested_string("#autoexec.be", 1181757091, 12), + /* K12 */ be_nested_string("stop_iteration", -121173395, 14), + }), + (be_nested_const_str("autoexec", -618105405, 8)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[32]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA40A0200, // 0001 IMPORT R2 K1 + 0x8C0C0302, // 0002 GETMET R3 R1 K2 + 0x58140003, // 0003 LDCONST R5 K3 + 0x7C0C0400, // 0004 CALL R3 2 + 0x60100010, // 0005 GETGBL R4 G16 + 0x5C140600, // 0006 MOVE R5 R3 + 0x7C100200, // 0007 CALL R4 1 + 0xA8020012, // 0008 EXBLK 0 #001C + 0x5C140800, // 0009 MOVE R5 R4 + 0x7C140000, // 000A CALL R5 0 + 0x8C180504, // 000B GETMET R6 R2 K4 + 0x5C200A00, // 000C MOVE R8 R5 + 0x58240005, // 000D LDCONST R9 K5 + 0x7C180600, // 000E CALL R6 3 + 0x24180D06, // 000F GT R6 R6 K6 + 0x781A0009, // 0010 JMPF R6 #001B + 0x60180001, // 0011 GETGBL R6 G1 + 0x8C1C0507, // 0012 GETMET R7 R2 K7 + 0x58240008, // 0013 LDCONST R9 K8 + 0x5C280A00, // 0014 MOVE R10 R5 + 0x7C1C0600, // 0015 CALL R7 3 + 0x7C180200, // 0016 CALL R6 1 + 0xB81A1200, // 0017 GETNGBL R6 K9 + 0x8C180D0A, // 0018 GETMET R6 R6 K10 + 0x00200B0B, // 0019 ADD R8 R5 K11 + 0x7C180400, // 001A CALL R6 2 + 0x7001FFEC, // 001B JMP #0009 + 0x5810000C, // 001C LDCONST R4 K12 + 0xAC100200, // 001D CATCH R4 1 0 + 0xB0080000, // 001E RAISE 2 R0 R0 + 0x80000000, // 001F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Tapp +********************************************************************/ +be_local_class(Tapp, + 0, + NULL, + be_nested_map(2, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("init", 380752755, 4, -1), be_const_closure(init_closure) }, + { be_nested_key("autoexec", -618105405, 8, 0), be_const_closure(autoexec_closure) }, + })), + (be_nested_const_str("Tapp", 2012315062, 4)) +); + +/******************************************************************** +** Solidified function: _anonymous_ +********************************************************************/ +be_local_closure(_anonymous_, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_const_class(be_class_Tapp), + }), + (be_nested_const_str("_anonymous_", 1957281476, 11)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[ 5]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0xB4000000, // 0001 CLASS K0 + 0x5C080200, // 0002 MOVE R2 R1 + 0x7C080000, // 0003 CALL R2 0 + 0x80040400, // 0004 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified module: tapp +********************************************************************/ +be_local_module(tapp, + "tapp", + be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_nested_key("init", 380752755, 4, -1), be_const_closure(_anonymous__closure) }, + })) +); +BE_EXPORT_VARIABLE be_define_const_native_module(tapp); +/********************************************************************/ diff --git a/lib/libesp32/Berry/default/be_tasmotalib.c b/lib/libesp32/Berry/default/be_tasmotalib.c index a1094079e..76720b7b4 100644 --- a/lib/libesp32/Berry/default/be_tasmotalib.c +++ b/lib/libesp32/Berry/default/be_tasmotalib.c @@ -12,6 +12,7 @@ extern struct dummy_struct be_tasmota_global_struct; extern struct dummy_struct be_tasmota_settings_struct; extern int l_getFreeHeap(bvm *vm); +extern int l_arch(bvm *vm); extern int l_publish(bvm *vm); extern int l_publish_result(bvm *vm); extern int l_cmd(bvm *vm); @@ -31,6 +32,8 @@ extern int l_scaleuint(bvm *vm); extern int l_logInfo(bvm *vm); extern int l_save(bvm *vm); +extern int l_read_sensors(bvm *vm); + extern int l_respCmnd(bvm *vm); extern int l_respCmndStr(bvm *vm); extern int l_respCmndDone(bvm *vm); @@ -140,22 +143,26 @@ be_local_closure(init, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[11]) { /* constants */ - /* K0 */ be_nested_string("global", 503252654, 6), - /* K1 */ be_nested_string("ctypes_bytes_dyn", 915205307, 16), - /* K2 */ be_nested_string("_global_addr", 533766721, 12), - /* K3 */ be_nested_string("_global_def", 646007001, 11), - /* K4 */ be_nested_string("introspect", 164638290, 10), - /* K5 */ be_nested_string("_settings_ptr", 1825772182, 13), - /* K6 */ be_nested_string("get", 1410115415, 3), + ( &(const bvalue[15]) { /* constants */ + /* K0 */ be_nested_str_literal("global"), + /* K1 */ be_nested_str_literal("ctypes_bytes_dyn"), + /* K2 */ be_nested_str_literal("_global_addr"), + /* K3 */ be_nested_str_literal("_global_def"), + /* K4 */ be_nested_str_literal("introspect"), + /* K5 */ be_nested_str_literal("_settings_ptr"), + /* K6 */ be_nested_str_literal("get"), /* K7 */ be_const_int(0), - /* K8 */ be_nested_string("settings", 1745255176, 8), - /* K9 */ be_nested_string("toptr", -915119842, 5), - /* K10 */ be_nested_string("_settings_def", -519406989, 13), + /* K8 */ be_nested_str_literal("settings"), + /* K9 */ be_nested_str_literal("toptr"), + /* K10 */ be_nested_str_literal("_settings_def"), + /* K11 */ be_nested_str_literal("wd"), + /* K12 */ be_nested_str_literal(""), + /* K13 */ be_nested_str_literal("_debug_present"), + /* K14 */ be_nested_str_literal("debug"), }), - ((bstring*) &be_const_str_init), - (be_nested_const_str("tasmota.be", 1128870755, 10)), - ( &(const binstruction[23]) { /* code */ + (be_nested_const_str("init", 380752755, 4)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[36]) { /* code */ 0xB8060200, // 0000 GETNGBL R1 K1 0x88080102, // 0001 GETMBR R2 R0 K2 0x880C0103, // 0002 GETMBR R3 R0 K3 @@ -178,7 +185,20 @@ be_local_closure(init, /* name */ 0x8814010A, // 0013 GETMBR R5 R0 K10 0x7C0C0400, // 0014 CALL R3 2 0x90021003, // 0015 SETMBR R0 K8 R3 - 0x80000000, // 0016 RET 0 + 0x9002170C, // 0016 SETMBR R0 K11 K12 + 0x500C0000, // 0017 LDBOOL R3 0 0 + 0x90021A03, // 0018 SETMBR R0 K13 R3 + 0xA8020004, // 0019 EXBLK 0 #001F + 0xA40E1C00, // 001A IMPORT R3 K14 + 0x50100200, // 001B LDBOOL R4 1 0 + 0x90021A04, // 001C SETMBR R0 K13 R4 + 0xA8040001, // 001D EXBLK 1 1 + 0x70020003, // 001E JMP #0023 + 0xAC0C0000, // 001F CATCH R3 0 0 + 0x70020000, // 0020 JMP #0022 + 0x70020000, // 0021 JMP #0023 + 0xB0080000, // 0022 RAISE 2 R0 R0 + 0x80000000, // 0023 RET 0 }) ) ); @@ -849,7 +869,7 @@ be_local_closure(time_str, /* name */ ********************************************************************/ be_local_closure(load, /* name */ be_nested_proto( - 15, /* nstack */ + 19, /* nstack */ 2, /* argc */ 0, /* varg */ 0, /* has upvals */ @@ -857,116 +877,144 @@ be_local_closure(load, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[18]) { /* constants */ - /* K0 */ be_nested_string("string", 398550328, 6), - /* K1 */ be_nested_string("path", -2071507658, 4), - /* K2 */ be_nested_string("find", -1108310694, 4), - /* K3 */ be_nested_string(".", 722245873, 1), - /* K4 */ be_const_int(0), - /* K5 */ be_nested_string(".be", 1325797348, 3), - /* K6 */ be_nested_string("split", -2017972765, 5), - /* K7 */ be_const_int(1), - /* K8 */ be_nested_string("be", 942383232, 2), - /* K9 */ be_nested_string("bec", 1336821081, 3), - /* K10 */ be_nested_string("io_error", 1970281036, 8), - /* K11 */ be_nested_string("file extension is not '.be' or '.bec'", -1199247657, 37), - /* K12 */ be_nested_string("c", -435409838, 1), - /* K13 */ be_nested_string("last_modified", 772177145, 13), - /* K14 */ be_nested_string("file", -1427482813, 4), - /* K15 */ be_nested_string("save", -855671224, 4), - /* K16 */ be_nested_string("format", -1180859054, 6), - /* K17 */ be_nested_string("BRY: could not save compiled file %s (%s)", 736659787, 41), + ( &(const bvalue[21]) { /* constants */ + /* K0 */ be_nested_str_literal("string"), + /* K1 */ be_nested_str_literal("path"), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_literal("/"), + /* K4 */ be_nested_str_literal("split"), + /* K5 */ be_nested_str_literal("#"), + /* K6 */ be_const_int(1), + /* K7 */ be_nested_str_literal("find"), + /* K8 */ be_nested_str_literal("."), + /* K9 */ be_nested_str_literal(".be"), + /* K10 */ be_nested_str_literal(".bec"), + /* K11 */ be_nested_str_literal("io_error"), + /* K12 */ be_nested_str_literal("file extension is not '.be' or '.bec'"), + /* K13 */ be_nested_str_literal("last_modified"), + /* K14 */ be_nested_str_literal("c"), + /* K15 */ be_nested_str_literal("wd"), + /* K16 */ be_nested_str_literal(""), + /* K17 */ be_nested_str_literal("file"), + /* K18 */ be_nested_str_literal("save"), + /* K19 */ be_nested_str_literal("format"), + /* K20 */ be_nested_str_literal("BRY: could not save compiled file %s (%s)"), }), (be_nested_const_str("load", -435725847, 4)), ((bstring*) &be_const_str_input), - ( &(const binstruction[87]) { /* code */ + ( &(const binstruction[112]) { /* code */ 0xA40A0000, // 0000 IMPORT R2 K0 0xA40E0200, // 0001 IMPORT R3 K1 - 0x8C100502, // 0002 GETMET R4 R2 K2 - 0x5C180200, // 0003 MOVE R6 R1 - 0x581C0003, // 0004 LDCONST R7 K3 - 0x7C100600, // 0005 CALL R4 3 - 0x14100904, // 0006 LT R4 R4 K4 - 0x78120000, // 0007 JMPF R4 #0009 - 0x00040305, // 0008 ADD R1 R1 K5 - 0x8C100506, // 0009 GETMET R4 R2 K6 - 0x5C180200, // 000A MOVE R6 R1 - 0x581C0003, // 000B LDCONST R7 K3 - 0x7C100600, // 000C CALL R4 3 - 0x6014000C, // 000D GETGBL R5 G12 - 0x5C180800, // 000E MOVE R6 R4 - 0x7C140200, // 000F CALL R5 1 - 0x18140B07, // 0010 LE R5 R5 K7 - 0x74160007, // 0011 JMPT R5 #001A - 0x5415FFFE, // 0012 LDINT R5 -1 - 0x94140805, // 0013 GETIDX R5 R4 R5 - 0x20140B08, // 0014 NE R5 R5 K8 - 0x78160004, // 0015 JMPF R5 #001B - 0x5415FFFE, // 0016 LDINT R5 -1 - 0x94140805, // 0017 GETIDX R5 R4 R5 - 0x20140B09, // 0018 NE R5 R5 K9 - 0x78160000, // 0019 JMPF R5 #001B - 0xB006150B, // 001A RAISE 1 K10 K11 - 0x5415FFFE, // 001B LDINT R5 -1 - 0x94140205, // 001C GETIDX R5 R1 R5 - 0x1C140B0C, // 001D EQ R5 R5 K12 - 0x8C18070D, // 001E GETMET R6 R3 K13 - 0x5C200200, // 001F MOVE R8 R1 - 0x7C180400, // 0020 CALL R6 2 - 0x78160005, // 0021 JMPF R5 #0028 - 0x4C1C0000, // 0022 LDNIL R7 - 0x1C1C0C07, // 0023 EQ R7 R6 R7 - 0x781E0001, // 0024 JMPF R7 #0027 - 0x501C0000, // 0025 LDBOOL R7 0 0 - 0x80040E00, // 0026 RET 1 R7 - 0x70020013, // 0027 JMP #003C - 0x8C1C070D, // 0028 GETMET R7 R3 K13 - 0x0024030C, // 0029 ADD R9 R1 K12 - 0x7C1C0400, // 002A CALL R7 2 - 0x4C200000, // 002B LDNIL R8 - 0x1C200C08, // 002C EQ R8 R6 R8 - 0x78220004, // 002D JMPF R8 #0033 - 0x4C200000, // 002E LDNIL R8 - 0x1C200E08, // 002F EQ R8 R7 R8 - 0x78220001, // 0030 JMPF R8 #0033 - 0x50200000, // 0031 LDBOOL R8 0 0 - 0x80041000, // 0032 RET 1 R8 - 0x4C200000, // 0033 LDNIL R8 - 0x20200E08, // 0034 NE R8 R7 R8 - 0x78220005, // 0035 JMPF R8 #003C - 0x4C200000, // 0036 LDNIL R8 - 0x1C200C08, // 0037 EQ R8 R6 R8 - 0x74220001, // 0038 JMPT R8 #003B - 0x28200E06, // 0039 GE R8 R7 R6 - 0x78220000, // 003A JMPF R8 #003C - 0x50140200, // 003B LDBOOL R5 1 0 - 0x601C000D, // 003C GETGBL R7 G13 - 0x5C200200, // 003D MOVE R8 R1 - 0x5824000E, // 003E LDCONST R9 K14 - 0x7C1C0400, // 003F CALL R7 2 - 0x74160011, // 0040 JMPT R5 #0053 - 0xA8020005, // 0041 EXBLK 0 #0048 - 0x8C20010F, // 0042 GETMET R8 R0 K15 - 0x0028030C, // 0043 ADD R10 R1 K12 - 0x5C2C0E00, // 0044 MOVE R11 R7 - 0x7C200600, // 0045 CALL R8 3 - 0xA8040001, // 0046 EXBLK 1 1 - 0x7002000A, // 0047 JMP #0053 - 0xAC200001, // 0048 CATCH R8 0 1 - 0x70020007, // 0049 JMP #0052 - 0x60240001, // 004A GETGBL R9 G1 - 0x8C280510, // 004B GETMET R10 R2 K16 - 0x58300011, // 004C LDCONST R12 K17 - 0x0034030C, // 004D ADD R13 R1 K12 - 0x5C381000, // 004E MOVE R14 R8 - 0x7C280800, // 004F CALL R10 4 - 0x7C240200, // 0050 CALL R9 1 - 0x70020000, // 0051 JMP #0053 - 0xB0080000, // 0052 RAISE 2 R0 R0 - 0x5C200E00, // 0053 MOVE R8 R7 - 0x7C200000, // 0054 CALL R8 0 - 0x50200200, // 0055 LDBOOL R8 1 0 - 0x80041000, // 0056 RET 1 R8 + 0x6010000C, // 0002 GETGBL R4 G12 + 0x5C140200, // 0003 MOVE R5 R1 + 0x7C100200, // 0004 CALL R4 1 + 0x1C100902, // 0005 EQ R4 R4 K2 + 0x78120001, // 0006 JMPF R4 #0009 + 0x50100000, // 0007 LDBOOL R4 0 0 + 0x80040800, // 0008 RET 1 R4 + 0x94100302, // 0009 GETIDX R4 R1 K2 + 0x20100903, // 000A NE R4 R4 K3 + 0x78120000, // 000B JMPF R4 #000D + 0x00060601, // 000C ADD R1 K3 R1 + 0x8C100504, // 000D GETMET R4 R2 K4 + 0x5C180200, // 000E MOVE R6 R1 + 0x581C0005, // 000F LDCONST R7 K5 + 0x7C100600, // 0010 CALL R4 3 + 0x94140902, // 0011 GETIDX R5 R4 K2 + 0x5419FFFE, // 0012 LDINT R6 -1 + 0x94180806, // 0013 GETIDX R6 R4 R6 + 0x601C000C, // 0014 GETGBL R7 G12 + 0x5C200800, // 0015 MOVE R8 R4 + 0x7C1C0200, // 0016 CALL R7 1 + 0x241C0F06, // 0017 GT R7 R7 K6 + 0x8C200507, // 0018 GETMET R8 R2 K7 + 0x5C280C00, // 0019 MOVE R10 R6 + 0x582C0008, // 001A LDCONST R11 K8 + 0x7C200600, // 001B CALL R8 3 + 0x14201102, // 001C LT R8 R8 K2 + 0x78220001, // 001D JMPF R8 #0020 + 0x00040309, // 001E ADD R1 R1 K9 + 0x00180D09, // 001F ADD R6 R6 K9 + 0x5421FFFC, // 0020 LDINT R8 -3 + 0x5425FFFE, // 0021 LDINT R9 -1 + 0x40201009, // 0022 CONNECT R8 R8 R9 + 0x94200C08, // 0023 GETIDX R8 R6 R8 + 0x1C201109, // 0024 EQ R8 R8 K9 + 0x5425FFFB, // 0025 LDINT R9 -4 + 0x5429FFFE, // 0026 LDINT R10 -1 + 0x4024120A, // 0027 CONNECT R9 R9 R10 + 0x94240C09, // 0028 GETIDX R9 R6 R9 + 0x1C24130A, // 0029 EQ R9 R9 K10 + 0x5C281000, // 002A MOVE R10 R8 + 0x742A0002, // 002B JMPT R10 #002F + 0x5C281200, // 002C MOVE R10 R9 + 0x742A0000, // 002D JMPT R10 #002F + 0xB006170C, // 002E RAISE 1 K11 K12 + 0x8C28070D, // 002F GETMET R10 R3 K13 + 0x5C300A00, // 0030 MOVE R12 R5 + 0x7C280400, // 0031 CALL R10 2 + 0x78260005, // 0032 JMPF R9 #0039 + 0x4C2C0000, // 0033 LDNIL R11 + 0x1C2C140B, // 0034 EQ R11 R10 R11 + 0x782E0001, // 0035 JMPF R11 #0038 + 0x502C0000, // 0036 LDBOOL R11 0 0 + 0x80041600, // 0037 RET 1 R11 + 0x70020013, // 0038 JMP #004D + 0x8C2C070D, // 0039 GETMET R11 R3 K13 + 0x0034030E, // 003A ADD R13 R1 K14 + 0x7C2C0400, // 003B CALL R11 2 + 0x4C300000, // 003C LDNIL R12 + 0x1C30140C, // 003D EQ R12 R10 R12 + 0x78320004, // 003E JMPF R12 #0044 + 0x4C300000, // 003F LDNIL R12 + 0x1C30160C, // 0040 EQ R12 R11 R12 + 0x78320001, // 0041 JMPF R12 #0044 + 0x50300000, // 0042 LDBOOL R12 0 0 + 0x80041800, // 0043 RET 1 R12 + 0x4C300000, // 0044 LDNIL R12 + 0x2030160C, // 0045 NE R12 R11 R12 + 0x78320005, // 0046 JMPF R12 #004D + 0x4C300000, // 0047 LDNIL R12 + 0x1C30140C, // 0048 EQ R12 R10 R12 + 0x74320001, // 0049 JMPT R12 #004C + 0x2830160A, // 004A GE R12 R11 R10 + 0x78320000, // 004B JMPF R12 #004D + 0x50240200, // 004C LDBOOL R9 1 0 + 0x781E0002, // 004D JMPF R7 #0051 + 0x002C0B05, // 004E ADD R11 R5 K5 + 0x90021E0B, // 004F SETMBR R0 K15 R11 + 0x70020000, // 0050 JMP #0052 + 0x90021F10, // 0051 SETMBR R0 K15 K16 + 0x602C000D, // 0052 GETGBL R11 G13 + 0x5C300200, // 0053 MOVE R12 R1 + 0x58340011, // 0054 LDCONST R13 K17 + 0x7C2C0400, // 0055 CALL R11 2 + 0x5C301200, // 0056 MOVE R12 R9 + 0x74320013, // 0057 JMPT R12 #006C + 0x5C300E00, // 0058 MOVE R12 R7 + 0x74320011, // 0059 JMPT R12 #006C + 0xA8020005, // 005A EXBLK 0 #0061 + 0x8C300112, // 005B GETMET R12 R0 K18 + 0x0038030E, // 005C ADD R14 R1 K14 + 0x5C3C1600, // 005D MOVE R15 R11 + 0x7C300600, // 005E CALL R12 3 + 0xA8040001, // 005F EXBLK 1 1 + 0x7002000A, // 0060 JMP #006C + 0xAC300001, // 0061 CATCH R12 0 1 + 0x70020007, // 0062 JMP #006B + 0x60340001, // 0063 GETGBL R13 G1 + 0x8C380513, // 0064 GETMET R14 R2 K19 + 0x58400014, // 0065 LDCONST R16 K20 + 0x0044030E, // 0066 ADD R17 R1 K14 + 0x5C481800, // 0067 MOVE R18 R12 + 0x7C380800, // 0068 CALL R14 4 + 0x7C340200, // 0069 CALL R13 1 + 0x70020000, // 006A JMP #006C + 0xB0080000, // 006B RAISE 2 R0 R0 + 0x5C301600, // 006C MOVE R12 R11 + 0x7C300000, // 006D CALL R12 0 + 0x50300200, // 006E LDBOOL R12 1 0 + 0x80041800, // 006F RET 1 R12 }) ) ); @@ -1610,7 +1658,7 @@ be_local_closure(gc, /* name */ ********************************************************************/ be_local_closure(event, /* name */ be_nested_proto( - 21, /* nstack */ + 20, /* nstack */ 6, /* argc */ 0, /* varg */ 0, /* has upvals */ @@ -1620,23 +1668,23 @@ be_local_closure(event, /* name */ 1, /* has constants */ ( &(const bvalue[23]) { /* constants */ /* K0 */ be_nested_string("introspect", 164638290, 10), - /* K1 */ be_nested_string("debug", 1483009432, 5), - /* K2 */ be_nested_string("string", 398550328, 6), - /* K3 */ be_nested_string("every_50ms", -1911083288, 10), - /* K4 */ be_nested_string("run_deferred", 371594696, 12), - /* K5 */ be_nested_string("cmd", -158181397, 3), - /* K6 */ be_nested_string("exec_cmd", 493567399, 8), - /* K7 */ be_nested_string("tele", -820509235, 4), - /* K8 */ be_nested_string("exec_tele", 1020751601, 9), - /* K9 */ be_nested_string("rule", -64077613, 4), - /* K10 */ be_nested_string("exec_rules", 1445221092, 10), - /* K11 */ be_nested_string("gc", 1042313471, 2), - /* K12 */ be_nested_string("_drivers", -1034638311, 8), - /* K13 */ be_const_int(0), - /* K14 */ be_nested_string("get", 1410115415, 3), - /* K15 */ be_nested_string("function", -1630125495, 8), - /* K16 */ be_nested_string("format", -1180859054, 6), - /* K17 */ be_nested_string("BRY: Exception> '%s' - %s", -2047976332, 25), + /* K1 */ be_nested_string("string", 398550328, 6), + /* K2 */ be_nested_string("every_50ms", -1911083288, 10), + /* K3 */ be_nested_string("run_deferred", 371594696, 12), + /* K4 */ be_nested_string("cmd", -158181397, 3), + /* K5 */ be_nested_string("exec_cmd", 493567399, 8), + /* K6 */ be_nested_string("tele", -820509235, 4), + /* K7 */ be_nested_string("exec_tele", 1020751601, 9), + /* K8 */ be_nested_string("rule", -64077613, 4), + /* K9 */ be_nested_string("exec_rules", 1445221092, 10), + /* K10 */ be_nested_string("gc", 1042313471, 2), + /* K11 */ be_nested_string("_drivers", -1034638311, 8), + /* K12 */ be_const_int(0), + /* K13 */ be_nested_string("get", 1410115415, 3), + /* K14 */ be_nested_string("function", -1630125495, 8), + /* K15 */ be_nested_string("format", -1180859054, 6), + /* K16 */ be_nested_string("BRY: Exception> '%s' - %s", -2047976332, 25), + /* K17 */ be_nested_string("debug", 1483009432, 5), /* K18 */ be_nested_string("traceback", -909779187, 9), /* K19 */ be_const_int(1), /* K20 */ be_nested_string("save_before_restart", 1253239338, 19), @@ -1644,99 +1692,99 @@ be_local_closure(event, /* name */ /* K22 */ be_nested_string("save", -855671224, 4), }), (be_nested_const_str("event", -30355297, 5)), - (be_nested_const_str("tasmota.be", 1128870755, 10)), + ((bstring*) &be_const_str_input), ( &(const binstruction[91]) { /* code */ 0xA41A0000, // 0000 IMPORT R6 K0 0xA41E0200, // 0001 IMPORT R7 K1 - 0xA4220400, // 0002 IMPORT R8 K2 - 0x1C240303, // 0003 EQ R9 R1 K3 - 0x78260001, // 0004 JMPF R9 #0007 - 0x8C240104, // 0005 GETMET R9 R0 K4 - 0x7C240200, // 0006 CALL R9 1 - 0x50240000, // 0007 LDBOOL R9 0 0 - 0x1C280305, // 0008 EQ R10 R1 K5 - 0x782A0006, // 0009 JMPF R10 #0011 - 0x8C280106, // 000A GETMET R10 R0 K6 - 0x5C300400, // 000B MOVE R12 R2 - 0x5C340600, // 000C MOVE R13 R3 - 0x5C380800, // 000D MOVE R14 R4 - 0x7C280800, // 000E CALL R10 4 - 0x80041400, // 000F RET 1 R10 - 0x70020043, // 0010 JMP #0055 - 0x1C280307, // 0011 EQ R10 R1 K7 - 0x782A0004, // 0012 JMPF R10 #0018 - 0x8C280108, // 0013 GETMET R10 R0 K8 - 0x5C300800, // 0014 MOVE R12 R4 - 0x7C280400, // 0015 CALL R10 2 - 0x80041400, // 0016 RET 1 R10 - 0x7002003C, // 0017 JMP #0055 - 0x1C280309, // 0018 EQ R10 R1 K9 - 0x782A0004, // 0019 JMPF R10 #001F - 0x8C28010A, // 001A GETMET R10 R0 K10 - 0x5C300800, // 001B MOVE R12 R4 - 0x7C280400, // 001C CALL R10 2 - 0x80041400, // 001D RET 1 R10 - 0x70020035, // 001E JMP #0055 - 0x1C28030B, // 001F EQ R10 R1 K11 - 0x782A0003, // 0020 JMPF R10 #0025 - 0x8C28010B, // 0021 GETMET R10 R0 K11 - 0x7C280200, // 0022 CALL R10 1 - 0x80041400, // 0023 RET 1 R10 - 0x7002002F, // 0024 JMP #0055 - 0x8828010C, // 0025 GETMBR R10 R0 K12 - 0x782A002D, // 0026 JMPF R10 #0055 - 0x5828000D, // 0027 LDCONST R10 K13 - 0x602C000C, // 0028 GETGBL R11 G12 - 0x8830010C, // 0029 GETMBR R12 R0 K12 - 0x7C2C0200, // 002A CALL R11 1 - 0x142C140B, // 002B LT R11 R10 R11 - 0x782E0027, // 002C JMPF R11 #0055 - 0x882C010C, // 002D GETMBR R11 R0 K12 - 0x942C160A, // 002E GETIDX R11 R11 R10 - 0x8C300D0E, // 002F GETMET R12 R6 K14 - 0x5C381600, // 0030 MOVE R14 R11 - 0x5C3C0200, // 0031 MOVE R15 R1 - 0x7C300600, // 0032 CALL R12 3 - 0x60340004, // 0033 GETGBL R13 G4 - 0x5C381800, // 0034 MOVE R14 R12 - 0x7C340200, // 0035 CALL R13 1 - 0x1C341B0F, // 0036 EQ R13 R13 K15 - 0x7836001A, // 0037 JMPF R13 #0053 - 0xA802000C, // 0038 EXBLK 0 #0046 - 0x5C341800, // 0039 MOVE R13 R12 - 0x5C381600, // 003A MOVE R14 R11 - 0x5C3C0400, // 003B MOVE R15 R2 - 0x5C400600, // 003C MOVE R16 R3 - 0x5C440800, // 003D MOVE R17 R4 - 0x5C480A00, // 003E MOVE R18 R5 - 0x7C340A00, // 003F CALL R13 5 - 0x5C241A00, // 0040 MOVE R9 R13 - 0x78260001, // 0041 JMPF R9 #0044 - 0xA8040001, // 0042 EXBLK 1 1 - 0x70020010, // 0043 JMP #0055 - 0xA8040001, // 0044 EXBLK 1 1 - 0x7002000C, // 0045 JMP #0053 - 0xAC340002, // 0046 CATCH R13 0 2 - 0x70020009, // 0047 JMP #0052 - 0x603C0001, // 0048 GETGBL R15 G1 - 0x8C401110, // 0049 GETMET R16 R8 K16 - 0x58480011, // 004A LDCONST R18 K17 + 0x1C200302, // 0002 EQ R8 R1 K2 + 0x78220001, // 0003 JMPF R8 #0006 + 0x8C200103, // 0004 GETMET R8 R0 K3 + 0x7C200200, // 0005 CALL R8 1 + 0x50200000, // 0006 LDBOOL R8 0 0 + 0x1C240304, // 0007 EQ R9 R1 K4 + 0x78260006, // 0008 JMPF R9 #0010 + 0x8C240105, // 0009 GETMET R9 R0 K5 + 0x5C2C0400, // 000A MOVE R11 R2 + 0x5C300600, // 000B MOVE R12 R3 + 0x5C340800, // 000C MOVE R13 R4 + 0x7C240800, // 000D CALL R9 4 + 0x80041200, // 000E RET 1 R9 + 0x70020044, // 000F JMP #0055 + 0x1C240306, // 0010 EQ R9 R1 K6 + 0x78260004, // 0011 JMPF R9 #0017 + 0x8C240107, // 0012 GETMET R9 R0 K7 + 0x5C2C0800, // 0013 MOVE R11 R4 + 0x7C240400, // 0014 CALL R9 2 + 0x80041200, // 0015 RET 1 R9 + 0x7002003D, // 0016 JMP #0055 + 0x1C240308, // 0017 EQ R9 R1 K8 + 0x78260004, // 0018 JMPF R9 #001E + 0x8C240109, // 0019 GETMET R9 R0 K9 + 0x5C2C0800, // 001A MOVE R11 R4 + 0x7C240400, // 001B CALL R9 2 + 0x80041200, // 001C RET 1 R9 + 0x70020036, // 001D JMP #0055 + 0x1C24030A, // 001E EQ R9 R1 K10 + 0x78260003, // 001F JMPF R9 #0024 + 0x8C24010A, // 0020 GETMET R9 R0 K10 + 0x7C240200, // 0021 CALL R9 1 + 0x80041200, // 0022 RET 1 R9 + 0x70020030, // 0023 JMP #0055 + 0x8824010B, // 0024 GETMBR R9 R0 K11 + 0x7826002E, // 0025 JMPF R9 #0055 + 0x5824000C, // 0026 LDCONST R9 K12 + 0x6028000C, // 0027 GETGBL R10 G12 + 0x882C010B, // 0028 GETMBR R11 R0 K11 + 0x7C280200, // 0029 CALL R10 1 + 0x1428120A, // 002A LT R10 R9 R10 + 0x782A0028, // 002B JMPF R10 #0055 + 0x8828010B, // 002C GETMBR R10 R0 K11 + 0x94281409, // 002D GETIDX R10 R10 R9 + 0x8C2C0D0D, // 002E GETMET R11 R6 K13 + 0x5C341400, // 002F MOVE R13 R10 + 0x5C380200, // 0030 MOVE R14 R1 + 0x7C2C0600, // 0031 CALL R11 3 + 0x60300004, // 0032 GETGBL R12 G4 + 0x5C341600, // 0033 MOVE R13 R11 + 0x7C300200, // 0034 CALL R12 1 + 0x1C30190E, // 0035 EQ R12 R12 K14 + 0x7832001B, // 0036 JMPF R12 #0053 + 0xA802000C, // 0037 EXBLK 0 #0045 + 0x5C301600, // 0038 MOVE R12 R11 + 0x5C341400, // 0039 MOVE R13 R10 + 0x5C380400, // 003A MOVE R14 R2 + 0x5C3C0600, // 003B MOVE R15 R3 + 0x5C400800, // 003C MOVE R16 R4 + 0x5C440A00, // 003D MOVE R17 R5 + 0x7C300A00, // 003E CALL R12 5 + 0x5C201800, // 003F MOVE R8 R12 + 0x78220001, // 0040 JMPF R8 #0043 + 0xA8040001, // 0041 EXBLK 1 1 + 0x70020011, // 0042 JMP #0055 + 0xA8040001, // 0043 EXBLK 1 1 + 0x7002000D, // 0044 JMP #0053 + 0xAC300002, // 0045 CATCH R12 0 2 + 0x7002000A, // 0046 JMP #0052 + 0x60380001, // 0047 GETGBL R14 G1 + 0x8C3C0F0F, // 0048 GETMET R15 R7 K15 + 0x58440010, // 0049 LDCONST R17 K16 + 0x5C481800, // 004A MOVE R18 R12 0x5C4C1A00, // 004B MOVE R19 R13 - 0x5C501C00, // 004C MOVE R20 R14 - 0x7C400800, // 004D CALL R16 4 - 0x7C3C0200, // 004E CALL R15 1 - 0x8C3C0F12, // 004F GETMET R15 R7 K18 + 0x7C3C0800, // 004C CALL R15 4 + 0x7C380200, // 004D CALL R14 1 + 0xA43A2200, // 004E IMPORT R14 K17 + 0x8C3C1D12, // 004F GETMET R15 R14 K18 0x7C3C0200, // 0050 CALL R15 1 0x70020000, // 0051 JMP #0053 0xB0080000, // 0052 RAISE 2 R0 R0 - 0x00281513, // 0053 ADD R10 R10 K19 - 0x7001FFD2, // 0054 JMP #0028 - 0x1C280314, // 0055 EQ R10 R1 K20 - 0x782A0002, // 0056 JMPF R10 #005A - 0xA42A2A00, // 0057 IMPORT R10 K21 - 0x8C2C1516, // 0058 GETMET R11 R10 K22 - 0x7C2C0200, // 0059 CALL R11 1 - 0x80041200, // 005A RET 1 R9 + 0x00241313, // 0053 ADD R9 R9 K19 + 0x7001FFD1, // 0054 JMP #0027 + 0x1C240314, // 0055 EQ R9 R1 K20 + 0x78260002, // 0056 JMPF R9 #005A + 0xA4262A00, // 0057 IMPORT R9 K21 + 0x8C281316, // 0058 GETMET R10 R9 K22 + 0x7C280200, // 0059 CALL R10 1 + 0x80041000, // 005A RET 1 R8 }) ) ); @@ -1831,6 +1879,102 @@ be_local_closure(exec_cmd, /* name */ ); /*******************************************************************/ +/******************************************************************** +** Solidified function: hs2rgb +********************************************************************/ +be_local_closure(hs2rgb, /* name */ + be_nested_proto( + 17, /* nstack */ + 3, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_string("tasmota", 424643812, 7), + /* K2 */ be_nested_string("scale_uint", -1204156202, 10), + /* K3 */ be_const_int(1), + /* K4 */ be_const_int(2), + /* K5 */ be_const_int(3), + }), + (be_nested_const_str("hs2rgb", 1040816349, 6)), + ((bstring*) &be_const_str_input), + ( &(const binstruction[68]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x1C0C0403, // 0001 EQ R3 R2 R3 + 0x780E0000, // 0002 JMPF R3 #0004 + 0x540A00FE, // 0003 LDINT R2 255 + 0x540E00FE, // 0004 LDINT R3 255 + 0x541200FE, // 0005 LDINT R4 255 + 0x541600FE, // 0006 LDINT R5 255 + 0x541A0167, // 0007 LDINT R6 360 + 0x10040206, // 0008 MOD R1 R1 R6 + 0x24180500, // 0009 GT R6 R2 K0 + 0x781A0031, // 000A JMPF R6 #003D + 0x541A003B, // 000B LDINT R6 60 + 0x0C180206, // 000C DIV R6 R1 R6 + 0x541E003B, // 000D LDINT R7 60 + 0x101C0207, // 000E MOD R7 R1 R7 + 0x542200FE, // 000F LDINT R8 255 + 0x04201002, // 0010 SUB R8 R8 R2 + 0xB8260200, // 0011 GETNGBL R9 K1 + 0x8C241302, // 0012 GETMET R9 R9 K2 + 0x5C2C0E00, // 0013 MOVE R11 R7 + 0x58300000, // 0014 LDCONST R12 K0 + 0x5436003B, // 0015 LDINT R13 60 + 0x543A00FE, // 0016 LDINT R14 255 + 0x5C3C1000, // 0017 MOVE R15 R8 + 0x7C240C00, // 0018 CALL R9 6 + 0xB82A0200, // 0019 GETNGBL R10 K1 + 0x8C281502, // 001A GETMET R10 R10 K2 + 0x5C300E00, // 001B MOVE R12 R7 + 0x58340000, // 001C LDCONST R13 K0 + 0x543A003B, // 001D LDINT R14 60 + 0x5C3C1000, // 001E MOVE R15 R8 + 0x544200FE, // 001F LDINT R16 255 + 0x7C280C00, // 0020 CALL R10 6 + 0x1C2C0D00, // 0021 EQ R11 R6 K0 + 0x782E0002, // 0022 JMPF R11 #0026 + 0x5C141400, // 0023 MOVE R5 R10 + 0x5C101000, // 0024 MOVE R4 R8 + 0x70020016, // 0025 JMP #003D + 0x1C2C0D03, // 0026 EQ R11 R6 K3 + 0x782E0002, // 0027 JMPF R11 #002B + 0x5C0C1200, // 0028 MOVE R3 R9 + 0x5C101000, // 0029 MOVE R4 R8 + 0x70020011, // 002A JMP #003D + 0x1C2C0D04, // 002B EQ R11 R6 K4 + 0x782E0002, // 002C JMPF R11 #0030 + 0x5C0C1000, // 002D MOVE R3 R8 + 0x5C101400, // 002E MOVE R4 R10 + 0x7002000C, // 002F JMP #003D + 0x1C2C0D05, // 0030 EQ R11 R6 K5 + 0x782E0002, // 0031 JMPF R11 #0035 + 0x5C0C1000, // 0032 MOVE R3 R8 + 0x5C141200, // 0033 MOVE R5 R9 + 0x70020007, // 0034 JMP #003D + 0x542E0003, // 0035 LDINT R11 4 + 0x1C2C0C0B, // 0036 EQ R11 R6 R11 + 0x782E0002, // 0037 JMPF R11 #003B + 0x5C0C1400, // 0038 MOVE R3 R10 + 0x5C141000, // 0039 MOVE R5 R8 + 0x70020001, // 003A JMP #003D + 0x5C141000, // 003B MOVE R5 R8 + 0x5C101200, // 003C MOVE R4 R9 + 0x541A000F, // 003D LDINT R6 16 + 0x38180606, // 003E SHL R6 R3 R6 + 0x541E0007, // 003F LDINT R7 8 + 0x381C0A07, // 0040 SHL R7 R5 R7 + 0x30180C07, // 0041 OR R6 R6 R7 + 0x30180C04, // 0042 OR R6 R6 R4 + 0x80040C00, // 0043 RET 1 R6 + }) + ) +); +/*******************************************************************/ #include "../generate/be_fixed_be_class_tasmota.h" @@ -1855,6 +1999,8 @@ class be_class_tasmota (scope: global, name: Tasmota) { global, var settings, var cmd_res, var + wd, var + _debug_present, var _global_def, comptr(&be_tasmota_global_struct) _settings_def, comptr(&be_tasmota_settings_struct) @@ -1865,6 +2011,7 @@ class be_class_tasmota (scope: global, name: Tasmota) { kv, closure(kv_closure) get_free_heap, func(l_getFreeHeap) + arch, func(l_arch) publish, func(l_publish) publish_result, func(l_publish_result) _cmd, func(l_cmd) @@ -1884,6 +2031,8 @@ class be_class_tasmota (scope: global, name: Tasmota) { log, func(l_logInfo) save, func(l_save) + read_sensors, func(l_read_sensors) + resp_cmnd, func(l_respCmnd) resp_cmnd_str, func(l_respCmndStr) resp_cmnd_done, func(l_respCmndDone) @@ -1924,6 +2073,8 @@ class be_class_tasmota (scope: global, name: Tasmota) { wire_scan, closure(wire_scan_closure) time_str, closure(time_str_closure) + hs2rgb, closure(hs2rgb_closure) + cb_dispatch, closure(cb_dispatch_closure) gen_cb, closure(gen_cb_closure) diff --git a/lib/libesp32/Berry/default/be_webclient_lib.c b/lib/libesp32/Berry/default/be_webclient_lib.c index bc24705d6..0e4b66e90 100644 --- a/lib/libesp32/Berry/default/be_webclient_lib.c +++ b/lib/libesp32/Berry/default/be_webclient_lib.c @@ -21,6 +21,7 @@ extern int wc_addheader(bvm *vm); extern int wc_GET(bvm *vm); extern int wc_POST(bvm *vm); extern int wc_getstring(bvm *vm); +extern int wc_writefile(bvm *vm); extern int wc_getsize(bvm *vm); #include "../generate/be_fixed_be_class_webclient.h" @@ -48,6 +49,7 @@ class be_class_webclient (scope: global, name: webclient) { GET, func(wc_GET) POST, func(wc_POST) get_string, func(wc_getstring) + write_file, func(wc_writefile) get_size, func(wc_getsize) } @const_object_info_end */ diff --git a/lib/libesp32/Berry/default/berry_conf.h b/lib/libesp32/Berry/default/berry_conf.h index 3360b9082..d2284ac31 100644 --- a/lib/libesp32/Berry/default/berry_conf.h +++ b/lib/libesp32/Berry/default/berry_conf.h @@ -100,6 +100,12 @@ **/ #define BE_STACK_FREE_MIN 20 +/* Macro: BE_STACK_START + * Set the starting size of the stack at VM creation. + * Default: 50 + **/ +#define BE_STACK_START 100 + /* Macro: BE_CONST_SEARCH_SIZE * Constants in function are limited to 255. However the compiler * will look for a maximum of pre-existing constants to avoid @@ -187,13 +193,20 @@ #define BE_USE_TIME_MODULE 0 #define BE_USE_OS_MODULE 0 #define BE_USE_GLOBAL_MODULE 1 -#define BE_USE_SYS_MODULE 0 -#define BE_USE_DEBUG_MODULE 1 +#define BE_USE_SYS_MODULE 1 +#define BE_USE_DEBUG_MODULE 0 #define BE_USE_GC_MODULE 1 -#define BE_USE_SOLIDIFY_MODULE 1 +#define BE_USE_SOLIDIFY_MODULE 0 #define BE_USE_INTROSPECT_MODULE 1 #define BE_USE_STRICT_MODULE 1 +#ifdef USE_BERRY_DEBUG + #undef BE_USE_DEBUG_MODULE + #undef BE_USE_SOLIDIFY_MODULE + #define BE_USE_DEBUG_MODULE 1 + #define BE_USE_SOLIDIFY_MODULE 1 +#endif // USE_BERRY_DEBUG + /* Macro: BE_EXPLICIT_XXX * If these macros are defined, the corresponding function will * use the version defined by these macros. These macro definitions diff --git a/lib/libesp32/Berry/default/embedded/Animate.be b/lib/libesp32/Berry/default/embedded/Animate.be new file mode 100644 index 000000000..279fd39ed --- /dev/null +++ b/lib/libesp32/Berry/default/embedded/Animate.be @@ -0,0 +1,189 @@ +# +# class Animate +# +# Animation framework +# + +animate = module("animate") + +# state-machine: from val a to b +class Animate_ins_ramp + var a # starting value + var b # end value + var duration # duration in milliseconds + + def init(a,b,duration) + self.a = a + self.b = b + self.duration = duration + end +end +animate.ins_ramp = Animate_ins_ramp + +# state-machine: pause and goto +class Animate_ins_goto + var pc_rel # relative PC, -1 previous instruction, 1 next instruction, 0 means see pc_abs + var pc_abs # absolute PC, only if pc_rel == 0, address if next instruction + var duration # pause in milliseconds before goto, -1 means infinite (state-machine can be changed externally) + + def init(pc_rel, pc_abs, duration) + self.pc_rel = pc_rel + self.pc_abs = pc_abs + self.duration = duration + end +end +animate.ins_goto = Animate_ins_goto + +class Animate_engine + var code # array of state-machine instructions + var closure # closure to call with the new value + var pc # program-counter + var ins_time # absolute time when the current instruction started + var running # is the animation running? allows fast return + var value # current value + + def init() + self.code = [] + self.pc = 0 # start at instruction 0 + self.ins_time = 0 + self.running = false # not running by default + # + end + + # run but needs external calls to `animate()` + # cur_time:int (opt) current timestamp in ms, defaults to `tasmota.millis()` + # val:int (opt) starting value, default to `nil` + def run(cur_time, val) + if cur_time == nil cur_time = tasmota.millis() end + if (val != nil) self.value = val end + self.ins_time = cur_time + + self.running = true + tasmota.add_driver(self) + end + + # runs autonomously in the Tasmota event loop + def autorun(cur_time, val) + self.run(cur_time, val) + tasmota.add_driver(self) + end + + def stop() + self.running = false + tasmota.remove_driver(self) + end + + def is_running() + return self.running + end + + def every_50ms() + self.animate() + end + + def animate(cur_time) # time in milliseconds, optional, defaults to `tasmota.millis()` + if !self.running return end + if cur_time == nil cur_time = tasmota.millis() end + # run through instructions + while true + var sub_index = cur_time - self.ins_time # time since the beginning of current instruction + # + # make sure PC is valid + if self.pc >= size(self.code) + self.running = false + break + end + # + if self.pc < 0 raise "internal_error", "Animate pc is out of range" end + var ins = self.code[self.pc] + + # Instruction Ramp + if isinstance(ins, animate.ins_ramp) + var f = self.closure # assign to a local variable to not call a method + if sub_index < ins.duration + # we're still in the ramp + self.value = tasmota.scale_uint(sub_index, 0, ins.duration, ins.a, ins.b) + # call closure + if f f(self.value) end # call closure, need try? TODO + break + else + self.value = ins.b + if f f(self.value) end # set to last value + self.pc += 1 # next instruction + self.ins_time = cur_time - (sub_index - ins.duration) + end + + # Instruction Goto + elif isinstance(ins, animate.ins_goto) + if sub_index < ins.duration + break + else + if ins.pc_rel != 0 + self.pc += ins.pc_rel + else + self.pc = ins.pc_abs + end + self.ins_time = cur_time - (sub_index - ins.duration) + end + + # Invalid + else + raise "internal_error", "unknown instruction" + end + end + return self.value + + end +end +animate.engine = Animate_engine + +class Animate_from_to : Animate_engine + + def init(closure, from, to, duration) + super(self).init() + self.closure = closure + self.code.push(animate.ins_ramp(from, to, duration)) + end + +end +animate.from_to = Animate_from_to + +#- +a=Animate_from_to(nil, 0, 100, 5000) +a.autorun() +-# + +class Animate_rotate : Animate_engine + + def init(closure, from, to, duration) + super(self).init() + self.closure = closure + self.code.push(animate.ins_ramp(from, to, duration)) + self.code.push(animate.ins_goto(0, 0, 0)) # goto abs pc = 0 without any pause + end + +end +animate.rotate = Animate_rotate + +#- +a=Animate_rotate(nil, 0, 100, 5000) +a.autorun() +-# + +class Animate_back_forth : Animate_engine + + def init(closure, from, to, duration) + super(self).init() + self.closure = closure + self.code.push(animate.ins_ramp(from, to, duration / 2)) + self.code.push(animate.ins_ramp(to, from, duration / 2)) + self.code.push(animate.ins_goto(0, 0, 0)) # goto abs pc = 0 without any pause + end + +end +animate.back_forth = Animate_back_forth + +#- +a=Animate_back_forth(nil, 0, 100, 5000) +a.autorun() +-# diff --git a/lib/libesp32/Berry/default/embedded/Tasmota.be b/lib/libesp32/Berry/default/embedded/Tasmota.be index 5bccfa66c..814af338f 100644 --- a/lib/libesp32/Berry/default/embedded/Tasmota.be +++ b/lib/libesp32/Berry/default/embedded/Tasmota.be @@ -24,9 +24,11 @@ class Tasmota var _cb var wire1 var wire2 - var cmd_res # store the command result, nil if disables, true if capture enabled, contains return value - var global # mapping to TasmotaGlobal + var cmd_res # store the command result, nil if disables, true if capture enabled, contains return value + var global # mapping to TasmotaGlobal var settings + var wd # when load() is called, `tasmota.wd` contains the name of the archive. Ex: `/M5StickC.autoconf#` + var _debug_present # is `import debug` present? def init() # instanciate the mapping object to TasmotaGlobal @@ -36,6 +38,13 @@ class Tasmota if settings_addr self.settings = ctypes_bytes_dyn(introspect.toptr(settings_addr), self._settings_def) end + self.wd = "" + self._debug_present = false + try + import debug + self._debug_present = true + except .. + end end # create a specific sub-class for rules: pattern(string) -> closure @@ -324,21 +333,39 @@ class Tasmota import string import path - # if the filename has no '.' append '.be' - if string.find(f, '.') < 0 + # fail if empty string + if size(f) == 0 return false end + # Ex: f = 'app.zip#autoexec' + + # add leading '/' if absent + if f[0] != '/' f = '/' + f end + # Ex: f = '/app.zip#autoexec' + + var f_items = string.split(f, '#') + var f_prefix = f_items[0] + var f_suffix = f_items[-1] # last token + var f_archive = size(f_items) > 1 # is the file in an archive + + # if no dot, add the default '.be' extension + if string.find(f_suffix, '.') < 0 # does the final file has a '.' f += ".be" + f_suffix += ".be" end + # Ex: f = '/app.zip#autoexec.be' + + # if the filename has no '.' append '.be' + var suffix_be = f_suffix[-3..-1] == '.be' + var suffix_bec = f_suffix[-4..-1] == '.bec' + # Ex: f = '/app.zip#autoexec.be', f_suffix = 'autoexec.be', suffix_be = true, suffix_bec = false # check that the file ends with '.be' of '.bec' - var fl = string.split(f,'.') - if (size(fl) <= 1 || (fl[-1] != 'be' && fl[-1] != 'bec')) + if !suffix_be && !suffix_bec raise "io_error", "file extension is not '.be' or '.bec'" end - var is_bytecode = f[-1] == 'c' # file is Berry source and not bytecode - var f_time = path.last_modified(f) + var f_time = path.last_modified(f_prefix) - if is_bytecode + if suffix_bec if f_time == nil return false end # file does not exist # f is the right file, continue else @@ -348,13 +375,20 @@ class Tasmota # bytecode exists and is more recent than berry source, use bytecode ##### temporarily disable loading from bec file # f = f + "c" # use bytecode name - is_bytecode = true + suffix_bec = true end end + # recall the working directory + if f_archive + self.wd = f_prefix + "#" + else + self.wd = "" + end + var c = compile(f, 'file') # save the compiled bytecode - if !is_bytecode + if !suffix_bec && !f_archive try self.save(f + 'c', c) except .. as e @@ -369,7 +403,6 @@ class Tasmota def event(event_type, cmd, idx, payload, raw) import introspect - import debug import string if event_type=='every_50ms' self.run_deferred() end #- first run deferred events -# @@ -390,7 +423,10 @@ class Tasmota if done break end except .. as e,m print(string.format("BRY: Exception> '%s' - %s", e, m)) - debug.traceback() + if self._debug_present + import debug + debug.traceback() + end end end i += 1 @@ -482,4 +518,52 @@ class Tasmota raise "internal_error", "No callback available" end + #- convert hue/sat to rgb -# + #- hue:int in range 0..359 -# + #- sat:int (optional) in range 0..255 -# + #- returns int: 0xRRGGBB -# + def hs2rgb(hue,sat) + if sat == nil sat = 255 end + var r = 255 # default to white + var b = 255 + var g = 255 + # we take brightness at 100%, brightness should be set separately + hue = hue % 360 # normalize to 0..359 + + if sat > 0 + var i = hue / 60 # quadrant 0..5 + var f = hue % 60 # 0..59 + var p = 255 - sat + var q = tasmota.scale_uint(f, 0, 60, 255, p) # 0..59 + var t = tasmota.scale_uint(f, 0, 60, p, 255) + + if i == 0 + # r = 255 + g = t + b = p + elif i == 1 + r = q + # g = 255 + b = p + elif i == 2 + r = p + #g = 255 + b = t + elif i == 3 + r = p + g = q + #b = 255 + elif i == 4 + r = t + g = p + #b = 255 + else + #r = 255 + g = p + b = q + end + end + + return (r << 16) | (g << 8) | b + end end diff --git a/lib/libesp32/Berry/default/embedded/autoconf.be b/lib/libesp32/Berry/default/embedded/autoconf.be new file mode 100644 index 000000000..8489c7447 --- /dev/null +++ b/lib/libesp32/Berry/default/embedded/autoconf.be @@ -0,0 +1,389 @@ +#- autocong module for Berry -# +#- -# +#- To solidify: -# +#- + # load only persis_module and persist_module.init + import autoconf + solidify.dump(autoconf_module) + # copy and paste into `be_autoconf_lib.c` +-# +#- + +# For external compile: + +display = module("display") +self = nil +tasmota = nil +def load() end + +-# + +var autoconf_module = module("autoconf") + +autoconf_module.init = def (m) + + class Autoconf + var _archive + var _error + + def init() + import path + import string + + var dir = path.listdir("/") + var entry + tasmota.add_driver(self) + + var i = 0 + while i < size(dir) + if string.find(dir[i], ".autoconf") > 0 # does the file contain '*.autoconf', >0 to skip `.autoconf` + if entry != nil + # we have multiple configuration files, not allowed + print(string.format("CFG: multiple autoconf files found, aborting ('%s' + '%s')", entry, dir[i])) + self._error = true + return nil + end + entry = dir[i] + end + i += 1 + end + + if entry == nil + tasmota.log("CFG: no '*.autoconf' file found", 2) + return nil + end + + self._archive = entry + end + + + # #################################################################################################### + # Manage first time marker + # #################################################################################################### + def is_first_time() + import path + return !path.exists("/.autoconf") + end + def set_first_time() + var f = open("/.autoconf", "w") + f.close() + end + def clear_first_time() + import path + path.remove("/.autoconf") + end + + # #################################################################################################### + # Delete all autoconfig files present + # #################################################################################################### + def delete_all_configs() + import path + import string + var dir = path.listdir("/") + + for d:dir + if string.find(d, ".autoconf") > 0 # does the file contain '*.autoconf' + path.remove(d) + end + end + end + + # #################################################################################################### + # Get current module + # contains the name of the archive without leading `/`, ex: `M5Stack_Fire.autoconf` + # or `nil` if none + # #################################################################################################### + def get_current_module_path() + return self._archive + end + def get_current_module_name() + return self._archive[0..-10] + end + + # #################################################################################################### + # Load templates from Github + # #################################################################################################### + def load_templates() + import string + import json + try + var url = string.format("https://raw.githubusercontent.com/tasmota/autoconf/main/%s_manifest.json", tasmota.arch()) + tasmota.log(string.format("CFG: loading '%s'", url), 3) + # load the template + var cl = webclient() + cl.begin(url) + var r = cl.GET() + if r != 200 + tasmota.log(string.format("CFG: return_code=%i", r), 2) + return nil + end + var s = cl.get_string() + cl.close() + # convert to json + var j = json.load(s) + tasmota.log(string.format("CFG: loaded '%s'", str(j)), 3) + + var t = j.find("files") + if isinstance(t, list) + return t + end + + return nil + except .. as e, m + tasmota.log(string.format("CFG: exception '%s' - '%s'", e, m), 2) + return nil + end + end + + # #################################################################################################### + # Init web handlers + # #################################################################################################### + # Displays a "Autocong" button on the configuration page + def web_add_config_button() + import webserver + webserver.content_send("

") + end + + + # This HTTP GET manager controls which web controls are displayed + def page_autoconf_mgr() + import webserver + import string + if !webserver.check_privileged_access() return nil end + + webserver.content_start('Auto-configuration') + webserver.content_send_style() + webserver.content_send("

 (This feature requires an internet connection)

") + + var cur_module = self.get_current_module_path() + var cur_module_display = cur_module ? string.tr(self.get_current_module_name(), "_", " ") : self._error ? "<Error: apply new or remove>" : "<None>" + + webserver.content_send("
") + webserver.content_send(string.format(" Current auto-configuration")) + webserver.content_send(string.format("

Current configuration:

%s

", cur_module_display)) + + if cur_module + # add button to reapply template + webserver.content_send("

") + webserver.content_send("") + webserver.content_send("

") + end + webserver.content_send("

") + + webserver.content_send("
") + webserver.content_send(string.format(" Select new auto-configuration")) + + webserver.content_send("

") + webserver.content_send("
") + webserver.content_send("

") + + webserver.content_send("") + # webserver.content_send(string.format("", ota_num)) + webserver.content_send("

") + + + webserver.content_send("

") + webserver.content_button(webserver.BUTTON_CONFIGURATION) + webserver.content_stop() + end + + # #################################################################################################### + # Web controller + # + # Applies the changes and restart + # #################################################################################################### + # This HTTP POST manager handles the submitted web form data + def page_autoconf_ctl() + import webserver + import string + import path + if !webserver.check_privileged_access() return nil end + + try + if webserver.has_arg("reapply") + tasmota.log("CFG: removing first time marker", 2); + # print("CFG: removing first time marker") + self.clear_first_time() + #- and force restart -# + webserver.redirect("/?rst=") + + elif webserver.has_arg("zip") + # remove any remaining autoconf file + tasmota.log("CFG: removing autoconf files", 2); + # print("CFG: removing autoconf files") + self.delete_all_configs() + + # get the name of the configuration file + var arch_name = webserver.arg("zip") + + if arch_name != "reset" + var url = string.format("https://raw.githubusercontent.com/tasmota/autoconf/main/%s/%s.autoconf", tasmota.arch(), arch_name) + tasmota.log(string.format("CFG: downloading '%s'", url), 2); + + var local_file = string.format("%s.autoconf", arch_name) + + # download file and write directly to file system + var cl = webclient() + cl.begin(url) + var r = cl.GET() + if r != 200 raise "connection_error", string.format("return code=%i", r) end + cl.write_file(local_file) + cl.close() + end + + # remove marker to reapply template + self.clear_first_time() + + #- and force restart -# + webserver.redirect("/?rst=") + else + raise "value_error", "Unknown command" + end + except .. as e, m + print(string.format("CFG: 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 + + # Add HTTP POST and GET handlers + def web_add_handler() + import webserver + webserver.on('/ac', / -> self.page_autoconf_mgr(), webserver.HTTP_GET) + webserver.on('/ac', / -> self.page_autoconf_ctl(), webserver.HTTP_POST) + end + + + # reset the configuration information (but don't restart) + # i.e. remove any autoconf file + def reset() + import path + import string + + var dir = path.listdir("/") + var entry + + var i = 0 + while i < size(dir) + var fname = dir[i] + if string.find(fname, ".autoconf") > 0 # does the file contain '*.autoconf' + path.remove(fname) + print(string.format("CFG: removed file '%s'", fname)) + end + i += 1 + end + + self._archive = nil + self._error = nil + end + + # called by the synthetic event `preinit` + def preinit() + if self._archive == nil return end + # try to launch `preinit.be` + import path + + var fname = self._archive + '#preinit.be' + if path.exists(fname) + tasmota.log("CFG: loading "+fname, 3) + load(fname) + tasmota.log("CFG: loaded "+fname, 3) + end + end + + def run_bat(fname) # read a '*.bat' file and run each command + import string + var f + try + f = open(fname, "r") # open file in read-only mode, it is expected to exist + while true + var line = f.readline() # read each line, can contain a terminal '\n', empty if end of file + if size(line) == 0 break end # end of file + + if line[-1] == "\n" line = line[0..-2] end # remove any trailing '\n' + if size(line) > 0 + tasmota.cmd(line) # run the command + end + end + f.close() # close, we don't expect exception with read-only, could be added later though + except .. as e, m + print(string.format('CFG: could not run %s (%s - %s)', fname, e, m)) + f.close() + end + end + + # called by the synthetic event `autoexec` + def autoexec() + if self._archive == nil return end + # try to launch `preinit.be` + import path + + # Step 1. if first run, only apply `init.bat` + var fname = self._archive + '#init.bat' + if self.is_first_time() && path.exists(fname) + # create the '.autoconf' file to avoid running it again, even if it crashed + self.set_first_time() + + # if path.exists(fname) # we know it exists from initial test + self.run_bat(fname) + tasmota.log("CFG: 'init.bat' done, restarting", 2) + tasmota.cmd("Restart 1") + return # if init was run, force a restart anyways and don't run the remaining code + # end + end + + # Step 2. if 'display.ini' is present, launch Universal Display + fname = self._archive + '#display.ini' + if gpio.pin_used(gpio.OPTION_A, 2) && path.exists(fname) + if path.exists("display.ini") + tasmota.log("CFG: skipping 'display.ini' because already present in file-system", 2) + else + import display + var f = open(fname,"r") + var desc = f.read() + f.close() + display.start(desc) + end + end + + # Step 3. if 'autoexec.bat' is present, run it + fname = self._archive + '#autoexec.bat' + if path.exists(fname) + tasmota.log("CFG: running "+fname, 3) + self.run_bat(fname) + tasmota.log("CFG: ran "+fname, 3) + end + + # Step 4. if 'autoexec.be' is present, load it + fname = self._archive + '#autoexec.be' + if path.exists(fname) + tasmota.log("CFG: loading "+fname, 3) + load(fname) + tasmota.log("CFG: loaded "+fname, 3) + end + end + end + + return Autoconf() # return an instance of this class +end + +aa = autoconf_module.init(autoconf_module) +import webserver +webserver.on('/ac2', / -> aa.page_autoconf_mgr(), webserver.HTTP_GET) +return autoconf_module diff --git a/lib/libesp32/Berry/default/embedded/leds.be b/lib/libesp32/Berry/default/embedded/leds.be new file mode 100644 index 000000000..289ad1118 --- /dev/null +++ b/lib/libesp32/Berry/default/embedded/leds.be @@ -0,0 +1,196 @@ +# class Leds +# +# for adressable leds like NoePixel + + +# Native commands +# 00 : ctor (leds:int, gpio:int) -> void +# 01 : begin void -> void +# 02 : show void -> void +# 03 : CanShow void -> bool +# 04 : IsDirty void -> bool +# 05 : Dirty void -> void +# 06 : Pixels void -> bytes() (mapped to the buffer) +# 07 : PixelSize void -> int +# 08 : PixelCount void -> int +# 09 : ClearTo (color:??) -> void +# 10 : SetPixelColor (idx:int, color:??) -> void +# 11 : GetPixelColor (idx:int) -> color:?? +# 20 : RotateLeft (rot:int [, first:int, last:int]) -> void +# 21 : RotateRight (rot:int [, first:int, last:int]) -> void +# 22 : ShiftLeft (rot:int [, first:int, last:int]) -> void +# 23 : ShiftRight (rot:int [, first:int, last:int]) -> void + + +class Leds : Leds_ntv + var gamma # if true, apply gamma (true is default) + # leds:int = number of leds of the strip + # gpio:int (optional) = GPIO for NeoPixel. If not specified, takes the WS2812 gpio + # type:int (optional) = Type of LED, defaults to WS2812 RGB + # rmt:int (optional) = RMT hardware channel to use, leave default unless you have a good reason + def init(leds, gpio, type, rmt) # rmt is optional + self.gamma = true # gamma is enabled by default, it should be disabled explicitly if needed + + if gpio == nil && gpio.pin(gpio.WS2812) >= 0 + gpio = gpio.pin(gpio.WS2812) + end + + # if no GPIO, abort + if gpio == nil + raise "valuer_error", "no GPIO specified for neopixelbus" + end + + # initialize the structure + self.ctor(leds, gpio, type, rmt) + + if self._p == nil raise "internal_error", "couldn't not initialize noepixelbus" end + + # call begin + self.begin() + + end + + def clear() + self.clear_to(0x000000) + self.show() + end + + def ctor(leds, gpio, rmt) + if rmt == nil + self.call_native(0, leds, gpio) + else + self.call_native(0, leds, gpio, rmt) + end + end + def begin() + self.call_native(1) + end + def show() + self.call_native(2) + end + def can_show() + return self.call_native(3) + end + def is_dirty() + return self.call_native(4) + end + def dirty() + self.call_native(5) + end + def pixels_buffer() + return self.call_native(6) + end + def pixel_size() + return self.call_native(7) + end + def pixel_count() + return self.call_native(8) + end + def clear_to(col, bri) + self.call_native(9, self.to_gamma(col, bri)) + end + def set_pixel_color(idx, col, bri) + self.call_native(10, idx, self.to_gamma(col, bri)) + end + def get_pixel_color(idx) + return self.call_native(11, idx) + end + # def rotate_left(rot, first, last) + # self.call_native(20, rot, first, last) + # end + # def rotate_right(rot, first, last) + # self.call_native(21, rot, first, last) + # end + # def shift_left(rot, first, last) + # self.call_native(22, rot, first, last) + # end + # def shift_right(rot, first, last) + # self.call_native(22, rot, first, last) + # end + + # apply gamma and bri + def to_gamma(rgbw, bri) + bri = (bri != nil) ? bri : 100 + var r = tasmota.scale_uint(bri, 0, 100, 0, (rgbw & 0xFF0000) >> 16) + var g = tasmota.scale_uint(bri, 0, 100, 0, (rgbw & 0x00FF00) >> 8) + var b = tasmota.scale_uint(bri, 0, 100, 0, (rgbw & 0x0000FF)) + if self.gamma + return light.gamma8(r) << 16 | + light.gamma8(g) << 8 | + light.gamma8(b) + else + return r << 16 | + g << 8 | + b + end + end +end + +#- + +var s = Leds(25, gpio.pin(gpio.WS2812, 1)) +s.clear_to(0x300000) +s.show() +i = 0 + +def anim() + s.clear_to(0x300000) + s.set_pixel_color(i, 0x004000) + s.show() + i = (i + 1) % 25 + tasmota.set_timer(200, anim) +end +anim() + +-# + +class Leds_matrix : Leds + var h, w + var alternate # are rows in alternate mode (even/odd are reversed) + + def init(w, h, gpio, rmt) + self.w = w + self.h = h + self.alternate = false + super(self).init(w * h, gpio, rmt) + end + + def set_alternate(alt) + self.alternate = alt + end + def get_alternate() + return self.alternate + end + + def set_matrix_pixel_color(x, y, col, bri) + if self.alternate && x % 2 + # reversed line + self.set_pixel_color(x * self.w + self.h - y - 1, col, bri) + else + self.set_pixel_color(x * self.w + y, col, bri) + end + end +end + +#- + +var s = Leds_matrix(5, 5, gpio.pin(gpio.WS2812, 1)) +s.set_alternate(true) +s.clear_to(0x300000) +s.show() +x = 0 +y = 0 + +def anim() + s.clear_to(0x300000) + s.set_matrix_pixel_color(x, y, 0x004000) + s.show() + y = (y + 1) % 5 + if y == 0 + x = (x + 1) % 5 + end + tasmota.set_timer(200, anim) +end +anim() + +-# diff --git a/lib/libesp32/Berry/default/embedded/leds_animator.be b/lib/libesp32/Berry/default/embedded/leds_animator.be new file mode 100644 index 000000000..1ed25b491 --- /dev/null +++ b/lib/libesp32/Berry/default/embedded/leds_animator.be @@ -0,0 +1,70 @@ +# class Leds_animator + +class Leds_animator + var strip # neopixelbus object + var pixel_count # number of pixels in the strip + var bri # brightness of the animation, 0..100, default 50 + var running # is the animation running + var animators # animators list + + def init(strip) + self.strip = strip + self.bri = 50 # percentage of brightness 0..100 + self.running = false + self.pixel_count = strip.pixel_count() + self.animators = [] + # + self.clear() # clear all leds first + # + tasmota.add_driver(self) + end + + def add_anim(anim) + self.animators.push(anim) + anim.run() # start the animator + end + + def clear() + self.stop() + self.strip.clear() + end + def start() + self.running = true + end + def stop() + self.running = false + end + + def set_bri(bri) + self.bri = bri + end + def get_bri(bri) + return self.bri + end + + def every_50ms() + if self.running + # run animators first + var i = 0 + while i < size(self.animators) + var anim = self.animators[i] + if anim.is_running() + anim.animate() + i += 1 + else + self.animators.remove(i) # remove any finished animator + end + end + # tirgger animate and display + self.animate() + end + end + + def animate() + # placeholder - do nothing by default + end + + def remove() + tasmota.remove_driver(self) + end +end diff --git a/lib/libesp32/Berry/default/embedded/tapp.be b/lib/libesp32/Berry/default/embedded/tapp.be new file mode 100644 index 000000000..3c3528e3a --- /dev/null +++ b/lib/libesp32/Berry/default/embedded/tapp.be @@ -0,0 +1,35 @@ +#- Tasmota apps module for Berry -# +#- -# + +var tapp_module = module("tapp") + +tapp_module.init = def (m) + + class Tapp + + def init() + tasmota.add_driver(self) + end + + def autoexec() + import path + import string + + var dir = path.listdir("/") + + for d: dir + if string.find(d, ".tapp") > 0 + print(string.format("TAP: found Tasmota App '%s'", d)) + tasmota.load(d + "#autoexec.be") + end + end + end + end + + return Tapp() # return an instance of this class +end + +# aa = autoconf_module.init(autoconf_module) +# import webserver +# webserver.on('/ac2', / -> aa.page_autoconf_mgr(), webserver.HTTP_GET) +return tapp_module diff --git a/lib/libesp32/Berry/generate/be_const_strtab.h b/lib/libesp32/Berry/generate/be_const_strtab.h index 18fc29fcf..cee6bc29d 100644 --- a/lib/libesp32/Berry/generate/be_const_strtab.h +++ b/lib/libesp32/Berry/generate/be_const_strtab.h @@ -1,340 +1,350 @@ -extern const bcstring be_const_str_size; -extern const bcstring be_const_str_type; -extern const bcstring be_const_str_has_arg; -extern const bcstring be_const_str_remove; -extern const bcstring be_const_str_SERIAL_6E1; -extern const bcstring be_const_str_SERIAL_8O1; -extern const bcstring be_const_str_cosh; -extern const bcstring be_const_str_global; -extern const bcstring be_const_str_last_modified; -extern const bcstring be_const_str_public_key; -extern const bcstring be_const_str_dac_voltage; -extern const bcstring be_const_str_set_power; -extern const bcstring be_const_str_url_encode; -extern const bcstring be_const_str_SERIAL_7N2; -extern const bcstring be_const_str_content_button; -extern const bcstring be_const_str__cb; -extern const bcstring be_const_str_atan; -extern const bcstring be_const_str_dot_p2; -extern const bcstring be_const_str_iter; -extern const bcstring be_const_str_remove_timer; -extern const bcstring be_const_str_select; -extern const bcstring be_const_str_setmember; -extern const bcstring be_const_str_top; -extern const bcstring be_const_str_decrypt; -extern const bcstring be_const_str_gamma10; -extern const bcstring be_const_str_i2c_enabled; -extern const bcstring be_const_str_on; -extern const bcstring be_const_str_pin_mode; +extern const bcstring be_const_str_SERIAL_6N2; +extern const bcstring be_const_str__begin_transmission; +extern const bcstring be_const_str_set_light; +extern const bcstring be_const_str_time_reached; +extern const bcstring be_const_str_SERIAL_5E2; +extern const bcstring be_const_str___lower__; extern const bcstring be_const_str_SERIAL_7O1; -extern const bcstring be_const_str_chars_in_string; -extern const bcstring be_const_str_wifi; -extern const bcstring be_const_str_SERIAL_5N2; -extern const bcstring be_const_str_allocated; -extern const bcstring be_const_str_set_timer; -extern const bcstring be_const_str_SERIAL_8N2; -extern const bcstring be_const_str_ceil; -extern const bcstring be_const_str_clear; -extern const bcstring be_const_str_wire1; -extern const bcstring be_const_str_resp_cmnd_failed; -extern const bcstring be_const_str_SERIAL_5E1; +extern const bcstring be_const_str_getbits; +extern const bcstring be_const_str_input; +extern const bcstring be_const_str_dot_size; +extern const bcstring be_const_str_publish_result; +extern const bcstring be_const_str_web_send_decimal; +extern const bcstring be_const_str_def; +extern const bcstring be_const_str__cmd; +extern const bcstring be_const_str_begin; +extern const bcstring be_const_str_resp_cmnd; +extern const bcstring be_const_str_assert; +extern const bcstring be_const_str_set; +extern const bcstring be_const_str_tag; +extern const bcstring be_const_str_check_privileged_access; +extern const bcstring be_const_str_kv; +extern const bcstring be_const_str_publish; +extern const bcstring be_const_str_read32; +extern const bcstring be_const_str_load; +extern const bcstring be_const_str_read13; +extern const bcstring be_const_str_search; +extern const bcstring be_const_str_dac_voltage; +extern const bcstring be_const_str_finish; +extern const bcstring be_const_str_hex; +extern const bcstring be_const_str_isinstance; +extern const bcstring be_const_str_rand; +extern const bcstring be_const_str_POST; +extern const bcstring be_const_str_SERIAL_6E2; extern const bcstring be_const_str_classname; extern const bcstring be_const_str__global_def; -extern const bcstring be_const_str_event; -extern const bcstring be_const_str_pin; -extern const bcstring be_const_str_response_append; -extern const bcstring be_const_str_else; -extern const bcstring be_const_str__rules; -extern const bcstring be_const_str_deinit; -extern const bcstring be_const_str_end; -extern const bcstring be_const_str___upper__; -extern const bcstring be_const_str_char; -extern const bcstring be_const_str_add_header; -extern const bcstring be_const_str_OneWire; -extern const bcstring be_const_str_deg; -extern const bcstring be_const_str_digital_read; -extern const bcstring be_const_str_srand; -extern const bcstring be_const_str_close; -extern const bcstring be_const_str_enabled; -extern const bcstring be_const_str_read13; -extern const bcstring be_const_str_AudioOutput; -extern const bcstring be_const_str_copy; -extern const bcstring be_const_str_exp; -extern const bcstring be_const_str_remove_rule; -extern const bcstring be_const_str_gen_cb; -extern const bcstring be_const_str_opt_neq; -extern const bcstring be_const_str_assert; -extern const bcstring be_const_str_isinstance; -extern const bcstring be_const_str_pow; -extern const bcstring be_const_str_count; -extern const bcstring be_const_str_read_bytes; -extern const bcstring be_const_str_web_send; -extern const bcstring be_const_str_classof; -extern const bcstring be_const_str_cos; -extern const bcstring be_const_str_redirect; -extern const bcstring be_const_str_write_bytes; -extern const bcstring be_const_str_rand; -extern const bcstring be_const_str_class; -extern const bcstring be_const_str_cb_dispatch; -extern const bcstring be_const_str_ctypes_bytes_dyn; -extern const bcstring be_const_str_floor; -extern const bcstring be_const_str_number; -extern const bcstring be_const_str_toptr; -extern const bcstring be_const_str_SERIAL_5N1; -extern const bcstring be_const_str__def; -extern const bcstring be_const_str_find_op; -extern const bcstring be_const_str_wire_scan; -extern const bcstring be_const_str_get_switch; -extern const bcstring be_const_str__read; -extern const bcstring be_const_str_member; -extern const bcstring be_const_str_target_search; -extern const bcstring be_const_str_traceback; -extern const bcstring be_const_str_static; -extern const bcstring be_const_str_opt_eq; -extern const bcstring be_const_str_fromptr; -extern const bcstring be_const_str_getbits; -extern const bcstring be_const_str_setbits; -extern const bcstring be_const_str_stop; -extern const bcstring be_const_str_issubclass; -extern const bcstring be_const_str_flush; -extern const bcstring be_const_str_I2C_Driver; -extern const bcstring be_const_str_atan2; -extern const bcstring be_const_str_resp_cmnd_str; -extern const bcstring be_const_str__settings_def; -extern const bcstring be_const_str_name; -extern const bcstring be_const_str_acos; -extern const bcstring be_const_str_asin; -extern const bcstring be_const_str_members; -extern const bcstring be_const_str_split; -extern const bcstring be_const_str_exists; -extern const bcstring be_const_str_super; -extern const bcstring be_const_str_EC_C25519; -extern const bcstring be_const_str_calldepth; -extern const bcstring be_const_str_ctypes_bytes; -extern const bcstring be_const_str_get_free_heap; -extern const bcstring be_const_str_bus; -extern const bcstring be_const_str_log; -extern const bcstring be_const_str_raise; -extern const bcstring be_const_str_bytes; -extern const bcstring be_const_str_set; -extern const bcstring be_const_str_SERIAL_6N1; -extern const bcstring be_const_str__cmd; -extern const bcstring be_const_str_dot_size; -extern const bcstring be_const_str_SERIAL_5O1; -extern const bcstring be_const_str_AES_GCM; -extern const bcstring be_const_str_AudioFileSourceFS; -extern const bcstring be_const_str_sinh; -extern const bcstring be_const_str_time_str; -extern const bcstring be_const_str_cmd; -extern const bcstring be_const_str_tostring; -extern const bcstring be_const_str__buffer; -extern const bcstring be_const_str_exec_tele; -extern const bcstring be_const_str_except; -extern const bcstring be_const_str_dot_len; -extern const bcstring be_const_str_AudioGeneratorMP3; -extern const bcstring be_const_str__global_addr; -extern const bcstring be_const_str_SERIAL_6E2; -extern const bcstring be_const_str_SERIAL_7E1; -extern const bcstring be_const_str_SERIAL_8O2; -extern const bcstring be_const_str_get; -extern const bcstring be_const_str_SERIAL_8E2; -extern const bcstring be_const_str_init; -extern const bcstring be_const_str_module; -extern const bcstring be_const_str_skip; -extern const bcstring be_const_str__ptr; -extern const bcstring be_const_str_find; -extern const bcstring be_const_str_item; -extern const bcstring be_const_str_GET; -extern const bcstring be_const_str_format; -extern const bcstring be_const_str_sqrt; -extern const bcstring be_const_str_byte; -extern const bcstring be_const_str_true; -extern const bcstring be_const_str__write; -extern const bcstring be_const_str_content_send_style; -extern const bcstring be_const_str_rtc; -extern const bcstring be_const_str_Wire; -extern const bcstring be_const_str_digital_write; -extern const bcstring be_const_str_get_light; -extern const bcstring be_const_str_SERIAL_8N1; -extern const bcstring be_const_str_read12; -extern const bcstring be_const_str_exec_cmd; -extern const bcstring be_const_str_remove_cmd; -extern const bcstring be_const_str_str; -extern const bcstring be_const_str_available; -extern const bcstring be_const_str_read24; -extern const bcstring be_const_str_scale_uint; -extern const bcstring be_const_str_try_rule; -extern const bcstring be_const_str_publish_result; -extern const bcstring be_const_str_state; -extern const bcstring be_const_str_strftime; -extern const bcstring be_const_str_toupper; -extern const bcstring be_const_str_; -extern const bcstring be_const_str_break; -extern const bcstring be_const_str_SERIAL_6N2; -extern const bcstring be_const_str_resolvecmnd; -extern const bcstring be_const_str_AudioOutputI2S; -extern const bcstring be_const_str_SERIAL_5O2; -extern const bcstring be_const_str_erase; -extern const bcstring be_const_str_lower; -extern const bcstring be_const_str_fromstring; -extern const bcstring be_const_str_print; -extern const bcstring be_const_str_def; -extern const bcstring be_const_str__request_from; -extern const bcstring be_const_str_read8; -extern const bcstring be_const_str_detect; -extern const bcstring be_const_str_dump; -extern const bcstring be_const_str_isrunning; -extern const bcstring be_const_str_push; -extern const bcstring be_const_str_time_dump; -extern const bcstring be_const_str_return; -extern const bcstring be_const_str_nil; -extern const bcstring be_const_str_remove_driver; -extern const bcstring be_const_str_SERIAL_7E2; -extern const bcstring be_const_str_add_driver; -extern const bcstring be_const_str_keys; -extern const bcstring be_const_str_run_deferred; -extern const bcstring be_const_str_SERIAL_8E1; -extern const bcstring be_const_str_delay; -extern const bcstring be_const_str_depower; -extern const bcstring be_const_str_imin; -extern const bcstring be_const_str_write8; -extern const bcstring be_const_str_add; -extern const bcstring be_const_str_add_cmd; -extern const bcstring be_const_str_add_rule; -extern const bcstring be_const_str_compile; -extern const bcstring be_const_str_geti; -extern const bcstring be_const_str_upper; -extern const bcstring be_const_str_webclient; -extern const bcstring be_const_str_has; -extern const bcstring be_const_str_codedump; -extern const bcstring be_const_str_reduce; -extern const bcstring be_const_str_as; -extern const bcstring be_const_str_get_size; -extern const bcstring be_const_str_tag; -extern const bcstring be_const_str_opt_connect; -extern const bcstring be_const_str__get_cb; -extern const bcstring be_const_str_try; -extern const bcstring be_const_str_while; -extern const bcstring be_const_str_gc; -extern const bcstring be_const_str_begin; -extern const bcstring be_const_str_kv; extern const bcstring be_const_str_open; -extern const bcstring be_const_str_web_send_decimal; -extern const bcstring be_const_str_cmd_res; -extern const bcstring be_const_str_settings; -extern const bcstring be_const_str_insert; -extern const bcstring be_const_str___iterator__; -extern const bcstring be_const_str_asstring; -extern const bcstring be_const_str_get_option; -extern const bcstring be_const_str_SERIAL_7N1; -extern const bcstring be_const_str_call; -extern const bcstring be_const_str_eth; -extern const bcstring be_const_str_if; -extern const bcstring be_const_str_int; -extern const bcstring be_const_str_time_reached; -extern const bcstring be_const_str_dot_p1; -extern const bcstring be_const_str_concat; -extern const bcstring be_const_str_content_flush; -extern const bcstring be_const_str_list; -extern const bcstring be_const_str_map; -extern const bcstring be_const_str_for; -extern const bcstring be_const_str_dot_p; -extern const bcstring be_const_str_set_timeouts; -extern const bcstring be_const_str_SERIAL_7O2; -extern const bcstring be_const_str_POST; -extern const bcstring be_const_str_abs; -extern const bcstring be_const_str_reverse; -extern const bcstring be_const_str_set_useragent; -extern const bcstring be_const_str_wire2; -extern const bcstring be_const_str_hex; -extern const bcstring be_const_str_set_light; -extern const bcstring be_const_str_SERIAL_5E2; -extern const bcstring be_const_str_seti; -extern const bcstring be_const_str_opt_add; -extern const bcstring be_const_str_content_send; -extern const bcstring be_const_str_real; -extern const bcstring be_const_str_publish; -extern const bcstring be_const_str_reset_search; -extern const bcstring be_const_str_log10; -extern const bcstring be_const_str__drivers; -extern const bcstring be_const_str_resp_cmnd_error; -extern const bcstring be_const_str_arg; -extern const bcstring be_const_str_collect; -extern const bcstring be_const_str_loop; -extern const bcstring be_const_str_wire; -extern const bcstring be_const_str_dot_w; -extern const bcstring be_const_str_addr; -extern const bcstring be_const_str_tob64; -extern const bcstring be_const_str_scan; -extern const bcstring be_const_str_set_auth; -extern const bcstring be_const_str_AudioFileSource; -extern const bcstring be_const_str_arg_name; -extern const bcstring be_const_str_contains; -extern const bcstring be_const_str_content_stop; -extern const bcstring be_const_str_nan; -extern const bcstring be_const_str_MD5; -extern const bcstring be_const_str_gamma8; -extern const bcstring be_const_str_isnan; -extern const bcstring be_const_str_pin_used; -extern const bcstring be_const_str_read; +extern const bcstring be_const_str_redirect; +extern const bcstring be_const_str_AES_GCM; +extern const bcstring be_const_str_resp_cmnd_failed; extern const bcstring be_const_str_reverse_gamma10; -extern const bcstring be_const_str_SERIAL_6O2; -extern const bcstring be_const_str_check_privileged_access; -extern const bcstring be_const_str_load; -extern const bcstring be_const_str_resize; -extern const bcstring be_const_str_content_start; -extern const bcstring be_const_str_write; -extern const bcstring be_const_str_AudioGenerator; -extern const bcstring be_const_str_AudioGeneratorWAV; -extern const bcstring be_const_str_range; -extern const bcstring be_const_str_encrypt; -extern const bcstring be_const_str_exec_rules; -extern const bcstring be_const_str_fromb64; -extern const bcstring be_const_str_get_power; -extern const bcstring be_const_str_serial; -extern const bcstring be_const_str__available; -extern const bcstring be_const_str_finish; -extern const bcstring be_const_str_attrdump; -extern const bcstring be_const_str_continue; -extern const bcstring be_const_str_do; +extern const bcstring be_const_str_strftime; +extern const bcstring be_const_str_insert; extern const bcstring be_const_str_false; +extern const bcstring be_const_str_arg_size; +extern const bcstring be_const_str_serial; +extern const bcstring be_const_str_OneWire; +extern const bcstring be_const_str_scale_uint; +extern const bcstring be_const_str_return; +extern const bcstring be_const_str_wire; +extern const bcstring be_const_str_write_bytes; +extern const bcstring be_const_str__global_addr; +extern const bcstring be_const_str_exec_tele; +extern const bcstring be_const_str_target_search; +extern const bcstring be_const_str_gamma8; +extern const bcstring be_const_str_pi; +extern const bcstring be_const_str_state; +extern const bcstring be_const_str_depower; +extern const bcstring be_const_str_init; +extern const bcstring be_const_str_member; +extern const bcstring be_const_str__end_transmission; +extern const bcstring be_const_str_digital_read; +extern const bcstring be_const_str_imin; +extern const bcstring be_const_str_hs2rgb; +extern const bcstring be_const_str_keys; +extern const bcstring be_const_str_real; +extern const bcstring be_const_str_sin; +extern const bcstring be_const_str_SERIAL_7N1; +extern const bcstring be_const_str_ctypes_bytes; +extern const bcstring be_const_str_ctypes_bytes_dyn; +extern const bcstring be_const_str_raise; +extern const bcstring be_const_str_GET; +extern const bcstring be_const_str__settings_def; +extern const bcstring be_const_str_read24; +extern const bcstring be_const_str_cos; +extern const bcstring be_const_str_remove_driver; +extern const bcstring be_const_str__settings_ptr; +extern const bcstring be_const_str_memory; +extern const bcstring be_const_str_set_auth; +extern const bcstring be_const_str_content_send_style; +extern const bcstring be_const_str_class; +extern const bcstring be_const_str_SERIAL_7E2; +extern const bcstring be_const_str_shared_key; +extern const bcstring be_const_str_tanh; +extern const bcstring be_const_str_nil; +extern const bcstring be_const_str_get_power; +extern const bcstring be_const_str_last_modified; +extern const bcstring be_const_str_resolvecmnd; +extern const bcstring be_const_str__read; +extern const bcstring be_const_str_atan; +extern const bcstring be_const_str_content_button; +extern const bcstring be_const_str_setbits; +extern const bcstring be_const_str_upper; +extern const bcstring be_const_str_contains; +extern const bcstring be_const_str_time_str; +extern const bcstring be_const_str_arch; +extern const bcstring be_const_str_fromptr; +extern const bcstring be_const_str_push; +extern const bcstring be_const_str_srand; +extern const bcstring be_const_str_geti; +extern const bcstring be_const_str_seti; +extern const bcstring be_const_str_add_cmd; +extern const bcstring be_const_str_cmd; +extern const bcstring be_const_str_get_switch; +extern const bcstring be_const_str_size; +extern const bcstring be_const_str_try; +extern const bcstring be_const_str_web_send; +extern const bcstring be_const_str_except; +extern const bcstring be_const_str_SERIAL_5O1; +extern const bcstring be_const_str_SERIAL_8E2; +extern const bcstring be_const_str__available; +extern const bcstring be_const_str_codedump; +extern const bcstring be_const_str_wire2; +extern const bcstring be_const_str_dump; +extern const bcstring be_const_str_exec_cmd; +extern const bcstring be_const_str_add; +extern const bcstring be_const_str_exp; +extern const bcstring be_const_str_isrunning; +extern const bcstring be_const_str_remove_rule; +extern const bcstring be_const_str_run_deferred; +extern const bcstring be_const_str_scan; +extern const bcstring be_const_str_for; +extern const bcstring be_const_str_set_timer; +extern const bcstring be_const_str_url_encode; +extern const bcstring be_const_str_addr; +extern const bcstring be_const_str___upper__; +extern const bcstring be_const_str_loop; +extern const bcstring be_const_str_AudioGeneratorWAV; +extern const bcstring be_const_str_chars_in_string; +extern const bcstring be_const_str_cosh; +extern const bcstring be_const_str_import; +extern const bcstring be_const_str_SERIAL_5N2; +extern const bcstring be_const_str_type; +extern const bcstring be_const_str_clear; +extern const bcstring be_const_str_SERIAL_8N1; +extern const bcstring be_const_str_issubclass; +extern const bcstring be_const_str_remove_timer; +extern const bcstring be_const_str_sinh; +extern const bcstring be_const_str_AudioGeneratorMP3; +extern const bcstring be_const_str_Wire; +extern const bcstring be_const_str_get_light; +extern const bcstring be_const_str_get_option; +extern const bcstring be_const_str_list; +extern const bcstring be_const_str_stop; +extern const bcstring be_const_str_try_rule; +extern const bcstring be_const_str_webclient; +extern const bcstring be_const_str_dot_p2; +extern const bcstring be_const_str_has; +extern const bcstring be_const_str__request_from; +extern const bcstring be_const_str_setrange; +extern const bcstring be_const_str_I2C_Driver; +extern const bcstring be_const_str_ceil; +extern const bcstring be_const_str_else; +extern const bcstring be_const_str_concat; +extern const bcstring be_const_str_set_power; extern const bcstring be_const_str_tomap; +extern const bcstring be_const_str_resp_cmnd_error; +extern const bcstring be_const_str_add_header; +extern const bcstring be_const_str_eth; +extern const bcstring be_const_str_write_bit; +extern const bcstring be_const_str_exists; +extern const bcstring be_const_str_pow; +extern const bcstring be_const_str_select; +extern const bcstring be_const_str_allocated; +extern const bcstring be_const_str_classof; +extern const bcstring be_const_str_if; +extern const bcstring be_const_str_SERIAL_5E1; +extern const bcstring be_const_str_arg; +extern const bcstring be_const_str_cb_dispatch; +extern const bcstring be_const_str_response_append; +extern const bcstring be_const_str_pin_used; +extern const bcstring be_const_str_write; +extern const bcstring be_const_str_write8; +extern const bcstring be_const_str_SERIAL_6O2; +extern const bcstring be_const_str_log; +extern const bcstring be_const_str_pin_mode; +extern const bcstring be_const_str_read12; +extern const bcstring be_const_str_resp_cmnd_str; +extern const bcstring be_const_str_abs; +extern const bcstring be_const_str_digital_write; +extern const bcstring be_const_str_static; +extern const bcstring be_const_str_bytes; +extern const bcstring be_const_str_find_op; +extern const bcstring be_const_str_call; +extern const bcstring be_const_str_cmd_res; +extern const bcstring be_const_str_opt_eq; +extern const bcstring be_const_str_save; extern const bcstring be_const_str_find_key_i; +extern const bcstring be_const_str__cb; +extern const bcstring be_const_str_Tasmota; +extern const bcstring be_const_str_public_key; +extern const bcstring be_const_str_as; +extern const bcstring be_const_str_dot_w; +extern const bcstring be_const_str_SERIAL_8O1; +extern const bcstring be_const_str_compile; +extern const bcstring be_const_str_range; +extern const bcstring be_const_str_add_rule; +extern const bcstring be_const_str__ptr; +extern const bcstring be_const_str_delay; extern const bcstring be_const_str_pop; extern const bcstring be_const_str_reset; +extern const bcstring be_const_str_wire_scan; +extern const bcstring be_const_str_reset_search; extern const bcstring be_const_str_tolower; -extern const bcstring be_const_str_sin; -extern const bcstring be_const_str_input; -extern const bcstring be_const_str_resp_cmnd; -extern const bcstring be_const_str_Tasmota; -extern const bcstring be_const_str_rad; -extern const bcstring be_const_str_read32; -extern const bcstring be_const_str__begin_transmission; -extern const bcstring be_const_str_pi; -extern const bcstring be_const_str_save; -extern const bcstring be_const_str_shared_key; -extern const bcstring be_const_str_write_bit; -extern const bcstring be_const_str__settings_ptr; -extern const bcstring be_const_str_search; +extern const bcstring be_const_str_SERIAL_7O2; +extern const bcstring be_const_str_asin; +extern const bcstring be_const_str_nan; +extern const bcstring be_const_str_deg; +extern const bcstring be_const_str_log10; +extern const bcstring be_const_str_char; +extern const bcstring be_const_str_get_size; extern const bcstring be_const_str_opt_call; -extern const bcstring be_const_str_setrange; -extern const bcstring be_const_str_var; -extern const bcstring be_const_str_resp_cmnd_done; -extern const bcstring be_const_str_tan; -extern const bcstring be_const_str_update; -extern const bcstring be_const_str_get_string; -extern const bcstring be_const_str_setitem; -extern const bcstring be_const_str_memory; -extern const bcstring be_const_str_tanh; -extern const bcstring be_const_str_SERIAL_6O1; -extern const bcstring be_const_str__end_transmission; -extern const bcstring be_const_str__timers; -extern const bcstring be_const_str_counters; +extern const bcstring be_const_str_end; +extern const bcstring be_const_str_SERIAL_7N2; +extern const bcstring be_const_str_time_dump; +extern const bcstring be_const_str_listdir; +extern const bcstring be_const_str_wifi; +extern const bcstring be_const_str_read_bytes; +extern const bcstring be_const_str_reverse; +extern const bcstring be_const_str_SERIAL_6E1; +extern const bcstring be_const_str_SERIAL_5O2; +extern const bcstring be_const_str_SERIAL_8E1; +extern const bcstring be_const_str_asstring; +extern const bcstring be_const_str_deinit; +extern const bcstring be_const_str_encrypt; +extern const bcstring be_const_str_iter; extern const bcstring be_const_str_millis; -extern const bcstring be_const_str_import; -extern const bcstring be_const_str___lower__; -extern const bcstring be_const_str_yield; -extern const bcstring be_const_str__ccmd; -extern const bcstring be_const_str_arg_size; -extern const bcstring be_const_str_imax; +extern const bcstring be_const_str_AudioOutput; +extern const bcstring be_const_str_members; +extern const bcstring be_const_str_rtc; +extern const bcstring be_const_str_SERIAL_6N1; +extern const bcstring be_const_str__write; +extern const bcstring be_const_str_content_start; +extern const bcstring be_const_str_module; +extern const bcstring be_const_str_item; +extern const bcstring be_const_str_remove_cmd; +extern const bcstring be_const_str_MD5; +extern const bcstring be_const_str_sqrt; +extern const bcstring be_const_str_SERIAL_5N1; +extern const bcstring be_const_str_break; +extern const bcstring be_const_str_map; +extern const bcstring be_const_str_setmember; +extern const bcstring be_const_str_tostring; +extern const bcstring be_const_str_AudioGenerator; +extern const bcstring be_const_str_while; +extern const bcstring be_const_str_event; +extern const bcstring be_const_str_resp_cmnd_done; +extern const bcstring be_const_str_AudioOutputI2S; +extern const bcstring be_const_str_has_arg; +extern const bcstring be_const_str_floor; +extern const bcstring be_const_str_read; +extern const bcstring be_const_str_remove; +extern const bcstring be_const_str_calldepth; +extern const bcstring be_const_str_lower; +extern const bcstring be_const_str_path; +extern const bcstring be_const_str_gamma10; +extern const bcstring be_const_str_get; extern const bcstring be_const_str_elif; +extern const bcstring be_const_str__buffer; +extern const bcstring be_const_str_exec_rules; +extern const bcstring be_const_str_pin; +extern const bcstring be_const_str_collect; +extern const bcstring be_const_str_enabled; +extern const bcstring be_const_str_global; +extern const bcstring be_const_str_acos; +extern const bcstring be_const_str_content_stop; +extern const bcstring be_const_str_read8; +extern const bcstring be_const_str_wire1; +extern const bcstring be_const_str_fromstring; +extern const bcstring be_const_str_setitem; +extern const bcstring be_const_str__debug_present; +extern const bcstring be_const_str_erase; +extern const bcstring be_const_str_i2c_enabled; +extern const bcstring be_const_str_resize; +extern const bcstring be_const_str_decrypt; +extern const bcstring be_const_str_escape; +extern const bcstring be_const_str_isnan; +extern const bcstring be_const_str_skip; +extern const bcstring be_const_str_var; +extern const bcstring be_const_str_dot_p; +extern const bcstring be_const_str_write_file; +extern const bcstring be_const_str_copy; +extern const bcstring be_const_str_str; +extern const bcstring be_const_str_super; +extern const bcstring be_const_str_update; +extern const bcstring be_const_str__def; +extern const bcstring be_const_str__drivers; +extern const bcstring be_const_str_imax; +extern const bcstring be_const_str_add_driver; +extern const bcstring be_const_str_dot_len; +extern const bcstring be_const_str_SERIAL_6O1; +extern const bcstring be_const_str_attrdump; +extern const bcstring be_const_str_on; +extern const bcstring be_const_str_rad; +extern const bcstring be_const_str_bus; +extern const bcstring be_const_str_yield; +extern const bcstring be_const_str_top; +extern const bcstring be_const_str_get_string; +extern const bcstring be_const_str_read_sensors; +extern const bcstring be_const_str_settings; +extern const bcstring be_const_str__get_cb; +extern const bcstring be_const_str_int; +extern const bcstring be_const_str_opt_neq; +extern const bcstring be_const_str_gen_cb; +extern const bcstring be_const_str__timers; +extern const bcstring be_const_str_continue; +extern const bcstring be_const_str_SERIAL_7E1; +extern const bcstring be_const_str_AudioFileSource; +extern const bcstring be_const_str_format; +extern const bcstring be_const_str_EC_C25519; +extern const bcstring be_const_str_close; +extern const bcstring be_const_str_content_flush; +extern const bcstring be_const_str_reduce; +extern const bcstring be_const_str_tr; +extern const bcstring be_const_str_available; +extern const bcstring be_const_str_traceback; +extern const bcstring be_const_str_opt_add; +extern const bcstring be_const_str_SERIAL_8N2; +extern const bcstring be_const_str_wd; +extern const bcstring be_const_str___iterator__; +extern const bcstring be_const_str_fromb64; +extern const bcstring be_const_str_number; +extern const bcstring be_const_str_print; +extern const bcstring be_const_str_set_useragent; +extern const bcstring be_const_str_tan; +extern const bcstring be_const_str_do; +extern const bcstring be_const_str_; +extern const bcstring be_const_str_opt_connect; +extern const bcstring be_const_str__rules; +extern const bcstring be_const_str_dot_p1; +extern const bcstring be_const_str_find; +extern const bcstring be_const_str_name; +extern const bcstring be_const_str_toptr; +extern const bcstring be_const_str_arg_name; +extern const bcstring be_const_str_byte; +extern const bcstring be_const_str_gc; +extern const bcstring be_const_str_count; +extern const bcstring be_const_str_counters; +extern const bcstring be_const_str_tob64; +extern const bcstring be_const_str_AudioFileSourceFS; +extern const bcstring be_const_str_get_free_heap; +extern const bcstring be_const_str_atan2; +extern const bcstring be_const_str_set_timeouts; +extern const bcstring be_const_str_toupper; +extern const bcstring be_const_str__ccmd; +extern const bcstring be_const_str_content_send; +extern const bcstring be_const_str_flush; +extern const bcstring be_const_str_true; +extern const bcstring be_const_str_detect; +extern const bcstring be_const_str_SERIAL_8O2; +extern const bcstring be_const_str_split; diff --git a/lib/libesp32/Berry/generate/be_const_strtab_def.h b/lib/libesp32/Berry/generate/be_const_strtab_def.h index 09b11b23d..16488ae94 100644 --- a/lib/libesp32/Berry/generate/be_const_strtab_def.h +++ b/lib/libesp32/Berry/generate/be_const_strtab_def.h @@ -1,508 +1,523 @@ -be_define_const_str(size, "size", 597743964u, 0, 4, &be_const_str_type); -be_define_const_str(type, "type", 1361572173u, 0, 4, NULL); -be_define_const_str(has_arg, "has_arg", 424878688u, 0, 7, NULL); -be_define_const_str(remove, "remove", 3683784189u, 0, 6, NULL); -be_define_const_str(SERIAL_6E1, "SERIAL_6E1", 334249486u, 0, 10, &be_const_str_SERIAL_8O1); -be_define_const_str(SERIAL_8O1, "SERIAL_8O1", 289122742u, 0, 10, NULL); -be_define_const_str(cosh, "cosh", 4099687964u, 0, 4, &be_const_str_global); -be_define_const_str(global, "global", 503252654u, 0, 6, &be_const_str_last_modified); -be_define_const_str(last_modified, "last_modified", 772177145u, 0, 13, &be_const_str_public_key); -be_define_const_str(public_key, "public_key", 4169142980u, 0, 10, NULL); -be_define_const_str(dac_voltage, "dac_voltage", 1552257222u, 0, 11, &be_const_str_set_power); -be_define_const_str(set_power, "set_power", 549820893u, 0, 9, &be_const_str_url_encode); -be_define_const_str(url_encode, "url_encode", 528392145u, 0, 10, NULL); -be_define_const_str(SERIAL_7N2, "SERIAL_7N2", 1874282627u, 0, 10, &be_const_str_content_button); -be_define_const_str(content_button, "content_button", 1956476087u, 0, 14, NULL); -be_define_const_str(_cb, "_cb", 4043300367u, 0, 3, &be_const_str_atan); -be_define_const_str(atan, "atan", 108579519u, 0, 4, NULL); -be_define_const_str(dot_p2, ".p2", 232398067u, 0, 3, &be_const_str_iter); -be_define_const_str(iter, "iter", 3124256359u, 0, 4, &be_const_str_remove_timer); -be_define_const_str(remove_timer, "remove_timer", 4141472215u, 0, 12, &be_const_str_select); -be_define_const_str(select, "select", 297952813u, 0, 6, &be_const_str_setmember); -be_define_const_str(setmember, "setmember", 1432909441u, 0, 9, &be_const_str_top); -be_define_const_str(top, "top", 2802900028u, 0, 3, NULL); -be_define_const_str(decrypt, "decrypt", 2886974618u, 0, 7, &be_const_str_gamma10); -be_define_const_str(gamma10, "gamma10", 3472052483u, 0, 7, &be_const_str_i2c_enabled); -be_define_const_str(i2c_enabled, "i2c_enabled", 218388101u, 0, 11, &be_const_str_on); -be_define_const_str(on, "on", 1630810064u, 0, 2, &be_const_str_pin_mode); -be_define_const_str(pin_mode, "pin_mode", 3258314030u, 0, 8, NULL); -be_define_const_str(SERIAL_7O1, "SERIAL_7O1", 1823802675u, 0, 10, &be_const_str_chars_in_string); -be_define_const_str(chars_in_string, "chars_in_string", 3148785132u, 0, 15, &be_const_str_wifi); -be_define_const_str(wifi, "wifi", 120087624u, 0, 4, NULL); -be_define_const_str(SERIAL_5N2, "SERIAL_5N2", 3363364537u, 0, 10, &be_const_str_allocated); -be_define_const_str(allocated, "allocated", 429986098u, 0, 9, &be_const_str_set_timer); -be_define_const_str(set_timer, "set_timer", 2135414533u, 0, 9, NULL); -be_define_const_str(SERIAL_8N2, "SERIAL_8N2", 2386074854u, 0, 10, &be_const_str_ceil); -be_define_const_str(ceil, "ceil", 1659167240u, 0, 4, &be_const_str_clear); -be_define_const_str(clear, "clear", 1550717474u, 0, 5, &be_const_str_wire1); -be_define_const_str(wire1, "wire1", 3212721419u, 0, 5, NULL); -be_define_const_str(resp_cmnd_failed, "resp_cmnd_failed", 2136281562u, 0, 16, NULL); -be_define_const_str(SERIAL_5E1, "SERIAL_5E1", 1163775235u, 0, 10, &be_const_str_classname); -be_define_const_str(classname, "classname", 1998589948u, 0, 9, NULL); -be_define_const_str(_global_def, "_global_def", 646007001u, 0, 11, &be_const_str_event); -be_define_const_str(event, "event", 4264611999u, 0, 5, &be_const_str_pin); -be_define_const_str(pin, "pin", 1866532500u, 0, 3, &be_const_str_response_append); -be_define_const_str(response_append, "response_append", 450346371u, 0, 15, &be_const_str_else); -be_define_const_str(else, "else", 3183434736u, 52, 4, NULL); -be_define_const_str(_rules, "_rules", 4266217105u, 0, 6, &be_const_str_deinit); -be_define_const_str(deinit, "deinit", 2345559592u, 0, 6, &be_const_str_end); -be_define_const_str(end, "end", 1787721130u, 56, 3, NULL); -be_define_const_str(__upper__, "__upper__", 3612202883u, 0, 9, NULL); -be_define_const_str(char, "char", 2823553821u, 0, 4, NULL); -be_define_const_str(add_header, "add_header", 927130612u, 0, 10, NULL); -be_define_const_str(OneWire, "OneWire", 2298990722u, 0, 7, &be_const_str_deg); -be_define_const_str(deg, "deg", 3327754271u, 0, 3, &be_const_str_digital_read); -be_define_const_str(digital_read, "digital_read", 3585496928u, 0, 12, &be_const_str_srand); -be_define_const_str(srand, "srand", 465518633u, 0, 5, NULL); -be_define_const_str(close, "close", 667630371u, 0, 5, &be_const_str_enabled); -be_define_const_str(enabled, "enabled", 49525662u, 0, 7, NULL); -be_define_const_str(read13, "read13", 12887293u, 0, 6, NULL); -be_define_const_str(AudioOutput, "AudioOutput", 3257792048u, 0, 11, &be_const_str_copy); -be_define_const_str(copy, "copy", 3848464964u, 0, 4, &be_const_str_exp); -be_define_const_str(exp, "exp", 1923516200u, 0, 3, &be_const_str_remove_rule); -be_define_const_str(remove_rule, "remove_rule", 3456211328u, 0, 11, NULL); -be_define_const_str(gen_cb, "gen_cb", 3245227551u, 0, 6, NULL); -be_define_const_str(opt_neq, "!=", 2428715011u, 0, 2, &be_const_str_assert); -be_define_const_str(assert, "assert", 2774883451u, 0, 6, &be_const_str_isinstance); -be_define_const_str(isinstance, "isinstance", 3669352738u, 0, 10, NULL); -be_define_const_str(pow, "pow", 1479764693u, 0, 3, NULL); -be_define_const_str(count, "count", 967958004u, 0, 5, &be_const_str_read_bytes); -be_define_const_str(read_bytes, "read_bytes", 3576733173u, 0, 10, NULL); -be_define_const_str(web_send, "web_send", 2989941448u, 0, 8, NULL); -be_define_const_str(classof, "classof", 1796577762u, 0, 7, &be_const_str_cos); -be_define_const_str(cos, "cos", 4220379804u, 0, 3, &be_const_str_redirect); -be_define_const_str(redirect, "redirect", 389758641u, 0, 8, &be_const_str_write_bytes); -be_define_const_str(write_bytes, "write_bytes", 1227543792u, 0, 11, NULL); -be_define_const_str(rand, "rand", 2711325910u, 0, 4, &be_const_str_class); -be_define_const_str(class, "class", 2872970239u, 57, 5, NULL); -be_define_const_str(cb_dispatch, "cb_dispatch", 1741510499u, 0, 11, &be_const_str_ctypes_bytes_dyn); -be_define_const_str(ctypes_bytes_dyn, "ctypes_bytes_dyn", 915205307u, 0, 16, NULL); -be_define_const_str(floor, "floor", 3102149661u, 0, 5, &be_const_str_number); -be_define_const_str(number, "number", 467038368u, 0, 6, &be_const_str_toptr); -be_define_const_str(toptr, "toptr", 3379847454u, 0, 5, NULL); -be_define_const_str(SERIAL_5N1, "SERIAL_5N1", 3313031680u, 0, 10, &be_const_str__def); -be_define_const_str(_def, "_def", 1985022181u, 0, 4, &be_const_str_find_op); -be_define_const_str(find_op, "find_op", 3766713376u, 0, 7, &be_const_str_wire_scan); -be_define_const_str(wire_scan, "wire_scan", 2671275880u, 0, 9, NULL); -be_define_const_str(get_switch, "get_switch", 164821028u, 0, 10, NULL); -be_define_const_str(_read, "_read", 346717030u, 0, 5, &be_const_str_member); -be_define_const_str(member, "member", 719708611u, 0, 6, &be_const_str_target_search); -be_define_const_str(target_search, "target_search", 1947846553u, 0, 13, &be_const_str_traceback); -be_define_const_str(traceback, "traceback", 3385188109u, 0, 9, &be_const_str_static); -be_define_const_str(static, "static", 3532702267u, 71, 6, NULL); -be_define_const_str(opt_eq, "==", 2431966415u, 0, 2, &be_const_str_fromptr); -be_define_const_str(fromptr, "fromptr", 666189689u, 0, 7, &be_const_str_getbits); -be_define_const_str(getbits, "getbits", 3094168979u, 0, 7, NULL); -be_define_const_str(setbits, "setbits", 2762408167u, 0, 7, NULL); -be_define_const_str(stop, "stop", 3411225317u, 0, 4, NULL); -be_define_const_str(issubclass, "issubclass", 4078395519u, 0, 10, NULL); -be_define_const_str(flush, "flush", 3002334877u, 0, 5, NULL); -be_define_const_str(I2C_Driver, "I2C_Driver", 1714501658u, 0, 10, NULL); -be_define_const_str(atan2, "atan2", 3173440503u, 0, 5, &be_const_str_resp_cmnd_str); -be_define_const_str(resp_cmnd_str, "resp_cmnd_str", 737845590u, 0, 13, NULL); -be_define_const_str(_settings_def, "_settings_def", 3775560307u, 0, 13, NULL); -be_define_const_str(name, "name", 2369371622u, 0, 4, NULL); -be_define_const_str(acos, "acos", 1006755615u, 0, 4, &be_const_str_asin); -be_define_const_str(asin, "asin", 4272848550u, 0, 4, &be_const_str_members); -be_define_const_str(members, "members", 937576464u, 0, 7, &be_const_str_split); -be_define_const_str(split, "split", 2276994531u, 0, 5, NULL); -be_define_const_str(exists, "exists", 1002329533u, 0, 6, &be_const_str_super); -be_define_const_str(super, "super", 4152230356u, 0, 5, NULL); -be_define_const_str(EC_C25519, "EC_C25519", 95492591u, 0, 9, &be_const_str_calldepth); -be_define_const_str(calldepth, "calldepth", 3122364302u, 0, 9, &be_const_str_ctypes_bytes); -be_define_const_str(ctypes_bytes, "ctypes_bytes", 3879019703u, 0, 12, &be_const_str_get_free_heap); -be_define_const_str(get_free_heap, "get_free_heap", 625069757u, 0, 13, NULL); -be_define_const_str(bus, "bus", 1607822841u, 0, 3, &be_const_str_log); -be_define_const_str(log, "log", 1062293841u, 0, 3, &be_const_str_raise); -be_define_const_str(raise, "raise", 1593437475u, 70, 5, NULL); -be_define_const_str(bytes, "bytes", 1706151940u, 0, 5, &be_const_str_set); -be_define_const_str(set, "set", 3324446467u, 0, 3, NULL); -be_define_const_str(SERIAL_6N1, "SERIAL_6N1", 198895701u, 0, 10, &be_const_str__cmd); -be_define_const_str(_cmd, "_cmd", 3419822142u, 0, 4, NULL); -be_define_const_str(dot_size, ".size", 1965188224u, 0, 5, &be_const_str_SERIAL_5O1); -be_define_const_str(SERIAL_5O1, "SERIAL_5O1", 3782657917u, 0, 10, NULL); -be_define_const_str(AES_GCM, "AES_GCM", 3832208678u, 0, 7, &be_const_str_AudioFileSourceFS); -be_define_const_str(AudioFileSourceFS, "AudioFileSourceFS", 1839147653u, 0, 17, &be_const_str_sinh); -be_define_const_str(sinh, "sinh", 282220607u, 0, 4, &be_const_str_time_str); -be_define_const_str(time_str, "time_str", 2613827612u, 0, 8, NULL); -be_define_const_str(cmd, "cmd", 4136785899u, 0, 3, NULL); -be_define_const_str(tostring, "tostring", 2299708645u, 0, 8, NULL); -be_define_const_str(_buffer, "_buffer", 2044888568u, 0, 7, &be_const_str_exec_tele); -be_define_const_str(exec_tele, "exec_tele", 1020751601u, 0, 9, NULL); -be_define_const_str(except, "except", 950914032u, 69, 6, NULL); -be_define_const_str(dot_len, ".len", 850842136u, 0, 4, &be_const_str_AudioGeneratorMP3); -be_define_const_str(AudioGeneratorMP3, "AudioGeneratorMP3", 2199818488u, 0, 17, &be_const_str__global_addr); -be_define_const_str(_global_addr, "_global_addr", 533766721u, 0, 12, NULL); -be_define_const_str(SERIAL_6E2, "SERIAL_6E2", 317471867u, 0, 10, &be_const_str_SERIAL_7E1); -be_define_const_str(SERIAL_7E1, "SERIAL_7E1", 147718061u, 0, 10, &be_const_str_SERIAL_8O2); -be_define_const_str(SERIAL_8O2, "SERIAL_8O2", 272345123u, 0, 10, &be_const_str_get); -be_define_const_str(get, "get", 1410115415u, 0, 3, NULL); -be_define_const_str(SERIAL_8E2, "SERIAL_8E2", 2421454473u, 0, 10, &be_const_str_init); -be_define_const_str(init, "init", 380752755u, 0, 4, &be_const_str_module); -be_define_const_str(module, "module", 3617558685u, 0, 6, &be_const_str_skip); -be_define_const_str(skip, "skip", 1097563074u, 0, 4, NULL); -be_define_const_str(_ptr, "_ptr", 306235816u, 0, 4, &be_const_str_find); -be_define_const_str(find, "find", 3186656602u, 0, 4, &be_const_str_item); -be_define_const_str(item, "item", 2671260646u, 0, 4, NULL); -be_define_const_str(GET, "GET", 2531704439u, 0, 3, &be_const_str_format); -be_define_const_str(format, "format", 3114108242u, 0, 6, &be_const_str_sqrt); -be_define_const_str(sqrt, "sqrt", 2112764879u, 0, 4, NULL); -be_define_const_str(byte, "byte", 1683620383u, 0, 4, NULL); -be_define_const_str(true, "true", 1303515621u, 61, 4, NULL); -be_define_const_str(_write, "_write", 2215462825u, 0, 6, &be_const_str_content_send_style); -be_define_const_str(content_send_style, "content_send_style", 1087907647u, 0, 18, &be_const_str_rtc); -be_define_const_str(rtc, "rtc", 1070575216u, 0, 3, NULL); -be_define_const_str(Wire, "Wire", 1938276536u, 0, 4, &be_const_str_digital_write); -be_define_const_str(digital_write, "digital_write", 3435877979u, 0, 13, &be_const_str_get_light); -be_define_const_str(get_light, "get_light", 381930476u, 0, 9, NULL); -be_define_const_str(SERIAL_8N1, "SERIAL_8N1", 2369297235u, 0, 10, &be_const_str_read12); -be_define_const_str(read12, "read12", 4291076970u, 0, 6, NULL); -be_define_const_str(exec_cmd, "exec_cmd", 493567399u, 0, 8, &be_const_str_remove_cmd); -be_define_const_str(remove_cmd, "remove_cmd", 3832315702u, 0, 10, &be_const_str_str); -be_define_const_str(str, "str", 3259748752u, 0, 3, NULL); -be_define_const_str(available, "available", 1727918744u, 0, 9, &be_const_str_read24); -be_define_const_str(read24, "read24", 1808533811u, 0, 6, &be_const_str_scale_uint); -be_define_const_str(scale_uint, "scale_uint", 3090811094u, 0, 10, &be_const_str_try_rule); -be_define_const_str(try_rule, "try_rule", 1986449405u, 0, 8, NULL); -be_define_const_str(publish_result, "publish_result", 2013351252u, 0, 14, &be_const_str_state); -be_define_const_str(state, "state", 2016490230u, 0, 5, &be_const_str_strftime); -be_define_const_str(strftime, "strftime", 187738851u, 0, 8, &be_const_str_toupper); -be_define_const_str(toupper, "toupper", 3691983576u, 0, 7, NULL); -be_define_const_str(, "", 2166136261u, 0, 0, &be_const_str_break); -be_define_const_str(break, "break", 3378807160u, 58, 5, NULL); -be_define_const_str(SERIAL_6N2, "SERIAL_6N2", 148562844u, 0, 10, &be_const_str_resolvecmnd); -be_define_const_str(resolvecmnd, "resolvecmnd", 993361485u, 0, 11, NULL); -be_define_const_str(AudioOutputI2S, "AudioOutputI2S", 638031784u, 0, 14, &be_const_str_SERIAL_5O2); -be_define_const_str(SERIAL_5O2, "SERIAL_5O2", 3732325060u, 0, 10, &be_const_str_erase); -be_define_const_str(erase, "erase", 1010949589u, 0, 5, &be_const_str_lower); -be_define_const_str(lower, "lower", 3038577850u, 0, 5, NULL); -be_define_const_str(fromstring, "fromstring", 610302344u, 0, 10, NULL); -be_define_const_str(print, "print", 372738696u, 0, 5, &be_const_str_def); -be_define_const_str(def, "def", 3310976652u, 55, 3, NULL); -be_define_const_str(_request_from, "_request_from", 3965148604u, 0, 13, &be_const_str_read8); -be_define_const_str(read8, "read8", 2802788167u, 0, 5, NULL); -be_define_const_str(detect, "detect", 8884370u, 0, 6, &be_const_str_dump); -be_define_const_str(dump, "dump", 3663001223u, 0, 4, &be_const_str_isrunning); -be_define_const_str(isrunning, "isrunning", 1688182268u, 0, 9, &be_const_str_push); -be_define_const_str(push, "push", 2272264157u, 0, 4, &be_const_str_time_dump); -be_define_const_str(time_dump, "time_dump", 3330410747u, 0, 9, &be_const_str_return); -be_define_const_str(return, "return", 2246981567u, 60, 6, NULL); -be_define_const_str(nil, "nil", 228849900u, 63, 3, NULL); -be_define_const_str(remove_driver, "remove_driver", 1030243768u, 0, 13, NULL); -be_define_const_str(SERIAL_7E2, "SERIAL_7E2", 97385204u, 0, 10, &be_const_str_add_driver); -be_define_const_str(add_driver, "add_driver", 1654458371u, 0, 10, &be_const_str_keys); -be_define_const_str(keys, "keys", 4182378701u, 0, 4, &be_const_str_run_deferred); -be_define_const_str(run_deferred, "run_deferred", 371594696u, 0, 12, NULL); -be_define_const_str(SERIAL_8E1, "SERIAL_8E1", 2371121616u, 0, 10, &be_const_str_delay); -be_define_const_str(delay, "delay", 1322381784u, 0, 5, &be_const_str_depower); -be_define_const_str(depower, "depower", 3563819571u, 0, 7, &be_const_str_imin); -be_define_const_str(imin, "imin", 2714127864u, 0, 4, &be_const_str_write8); -be_define_const_str(write8, "write8", 3133991532u, 0, 6, NULL); -be_define_const_str(add, "add", 993596020u, 0, 3, &be_const_str_add_cmd); -be_define_const_str(add_cmd, "add_cmd", 3361630879u, 0, 7, &be_const_str_add_rule); -be_define_const_str(add_rule, "add_rule", 596540743u, 0, 8, NULL); -be_define_const_str(compile, "compile", 1000265118u, 0, 7, &be_const_str_geti); -be_define_const_str(geti, "geti", 2381006490u, 0, 4, &be_const_str_upper); -be_define_const_str(upper, "upper", 176974407u, 0, 5, &be_const_str_webclient); -be_define_const_str(webclient, "webclient", 4076389146u, 0, 9, NULL); -be_define_const_str(has, "has", 3988721635u, 0, 3, NULL); -be_define_const_str(codedump, "codedump", 1786337906u, 0, 8, NULL); -be_define_const_str(reduce, "reduce", 2002030311u, 0, 6, NULL); -be_define_const_str(as, "as", 1579491469u, 67, 2, NULL); -be_define_const_str(get_size, "get_size", 2803644713u, 0, 8, &be_const_str_tag); -be_define_const_str(tag, "tag", 2516003219u, 0, 3, NULL); -be_define_const_str(opt_connect, "..", 2748622605u, 0, 2, NULL); -be_define_const_str(_get_cb, "_get_cb", 1448849122u, 0, 7, &be_const_str_try); -be_define_const_str(try, "try", 2887626766u, 68, 3, &be_const_str_while); -be_define_const_str(while, "while", 231090382u, 53, 5, NULL); -be_define_const_str(gc, "gc", 1042313471u, 0, 2, NULL); -be_define_const_str(begin, "begin", 1748273790u, 0, 5, &be_const_str_kv); -be_define_const_str(kv, "kv", 1497177492u, 0, 2, &be_const_str_open); -be_define_const_str(open, "open", 3546203337u, 0, 4, &be_const_str_web_send_decimal); -be_define_const_str(web_send_decimal, "web_send_decimal", 1407210204u, 0, 16, NULL); -be_define_const_str(cmd_res, "cmd_res", 921166762u, 0, 7, &be_const_str_settings); -be_define_const_str(settings, "settings", 1745255176u, 0, 8, NULL); -be_define_const_str(insert, "insert", 3332609576u, 0, 6, NULL); -be_define_const_str(__iterator__, "__iterator__", 3884039703u, 0, 12, &be_const_str_asstring); -be_define_const_str(asstring, "asstring", 1298225088u, 0, 8, &be_const_str_get_option); -be_define_const_str(get_option, "get_option", 2123730033u, 0, 10, NULL); -be_define_const_str(SERIAL_7N1, "SERIAL_7N1", 1891060246u, 0, 10, &be_const_str_call); -be_define_const_str(call, "call", 3018949801u, 0, 4, &be_const_str_eth); -be_define_const_str(eth, "eth", 2191266556u, 0, 3, &be_const_str_if); -be_define_const_str(if, "if", 959999494u, 50, 2, NULL); -be_define_const_str(int, "int", 2515107422u, 0, 3, &be_const_str_time_reached); -be_define_const_str(time_reached, "time_reached", 2075136773u, 0, 12, NULL); -be_define_const_str(dot_p1, ".p1", 249175686u, 0, 3, &be_const_str_concat); -be_define_const_str(concat, "concat", 4124019837u, 0, 6, &be_const_str_content_flush); -be_define_const_str(content_flush, "content_flush", 214922475u, 0, 13, &be_const_str_list); -be_define_const_str(list, "list", 217798785u, 0, 4, &be_const_str_map); -be_define_const_str(map, "map", 3751997361u, 0, 3, &be_const_str_for); -be_define_const_str(for, "for", 2901640080u, 54, 3, NULL); -be_define_const_str(dot_p, ".p", 1171526419u, 0, 2, &be_const_str_set_timeouts); -be_define_const_str(set_timeouts, "set_timeouts", 3732850900u, 0, 12, NULL); -be_define_const_str(SERIAL_7O2, "SERIAL_7O2", 1840580294u, 0, 10, NULL); -be_define_const_str(POST, "POST", 1929554311u, 0, 4, &be_const_str_abs); -be_define_const_str(abs, "abs", 709362235u, 0, 3, &be_const_str_reverse); -be_define_const_str(reverse, "reverse", 558918661u, 0, 7, &be_const_str_set_useragent); -be_define_const_str(set_useragent, "set_useragent", 612237244u, 0, 13, &be_const_str_wire2); -be_define_const_str(wire2, "wire2", 3229499038u, 0, 5, NULL); -be_define_const_str(hex, "hex", 4273249610u, 0, 3, &be_const_str_set_light); +be_define_const_str(SERIAL_6N2, "SERIAL_6N2", 148562844u, 0, 10, &be_const_str__begin_transmission); +be_define_const_str(_begin_transmission, "_begin_transmission", 2779461176u, 0, 19, &be_const_str_set_light); be_define_const_str(set_light, "set_light", 3176076152u, 0, 9, NULL); -be_define_const_str(SERIAL_5E2, "SERIAL_5E2", 1180552854u, 0, 10, &be_const_str_seti); -be_define_const_str(seti, "seti", 1500556254u, 0, 4, NULL); -be_define_const_str(opt_add, "+", 772578730u, 0, 1, &be_const_str_content_send); -be_define_const_str(content_send, "content_send", 1673733649u, 0, 12, &be_const_str_real); -be_define_const_str(real, "real", 3604983901u, 0, 4, NULL); -be_define_const_str(publish, "publish", 264247304u, 0, 7, &be_const_str_reset_search); -be_define_const_str(reset_search, "reset_search", 1350414305u, 0, 12, NULL); -be_define_const_str(log10, "log10", 2346846000u, 0, 5, NULL); -be_define_const_str(_drivers, "_drivers", 3260328985u, 0, 8, &be_const_str_resp_cmnd_error); -be_define_const_str(resp_cmnd_error, "resp_cmnd_error", 2404088863u, 0, 15, NULL); -be_define_const_str(arg, "arg", 1047474471u, 0, 3, &be_const_str_collect); -be_define_const_str(collect, "collect", 2399039025u, 0, 7, &be_const_str_loop); -be_define_const_str(loop, "loop", 3723446379u, 0, 4, NULL); -be_define_const_str(wire, "wire", 4082753944u, 0, 4, NULL); -be_define_const_str(dot_w, ".w", 1255414514u, 0, 2, &be_const_str_addr); -be_define_const_str(addr, "addr", 1087856498u, 0, 4, &be_const_str_tob64); -be_define_const_str(tob64, "tob64", 373777640u, 0, 5, NULL); -be_define_const_str(scan, "scan", 3974641896u, 0, 4, &be_const_str_set_auth); -be_define_const_str(set_auth, "set_auth", 1057170930u, 0, 8, NULL); -be_define_const_str(AudioFileSource, "AudioFileSource", 2959980058u, 0, 15, &be_const_str_arg_name); -be_define_const_str(arg_name, "arg_name", 1345046155u, 0, 8, &be_const_str_contains); -be_define_const_str(contains, "contains", 1825239352u, 0, 8, &be_const_str_content_stop); -be_define_const_str(content_stop, "content_stop", 658554751u, 0, 12, NULL); -be_define_const_str(nan, "nan", 797905850u, 0, 3, NULL); -be_define_const_str(MD5, "MD5", 1935726387u, 0, 3, &be_const_str_gamma8); -be_define_const_str(gamma8, "gamma8", 3802843830u, 0, 6, &be_const_str_isnan); -be_define_const_str(isnan, "isnan", 2981347434u, 0, 5, &be_const_str_pin_used); -be_define_const_str(pin_used, "pin_used", 4033854612u, 0, 8, &be_const_str_read); -be_define_const_str(read, "read", 3470762949u, 0, 4, &be_const_str_reverse_gamma10); -be_define_const_str(reverse_gamma10, "reverse_gamma10", 739112262u, 0, 15, NULL); -be_define_const_str(SERIAL_6O2, "SERIAL_6O2", 316486129u, 0, 10, &be_const_str_check_privileged_access); -be_define_const_str(check_privileged_access, "check_privileged_access", 3692933968u, 0, 23, &be_const_str_load); -be_define_const_str(load, "load", 3859241449u, 0, 4, &be_const_str_resize); -be_define_const_str(resize, "resize", 3514612129u, 0, 6, NULL); -be_define_const_str(content_start, "content_start", 2937509069u, 0, 13, &be_const_str_write); -be_define_const_str(write, "write", 3190202204u, 0, 5, NULL); -be_define_const_str(AudioGenerator, "AudioGenerator", 1839297342u, 0, 14, NULL); -be_define_const_str(AudioGeneratorWAV, "AudioGeneratorWAV", 2746509368u, 0, 17, &be_const_str_range); -be_define_const_str(range, "range", 4208725202u, 0, 5, NULL); -be_define_const_str(encrypt, "encrypt", 2194327650u, 0, 7, &be_const_str_exec_rules); -be_define_const_str(exec_rules, "exec_rules", 1445221092u, 0, 10, &be_const_str_fromb64); -be_define_const_str(fromb64, "fromb64", 2717019639u, 0, 7, &be_const_str_get_power); -be_define_const_str(get_power, "get_power", 3009799377u, 0, 9, &be_const_str_serial); -be_define_const_str(serial, "serial", 3687697785u, 0, 6, NULL); -be_define_const_str(_available, "_available", 1306196581u, 0, 10, &be_const_str_finish); -be_define_const_str(finish, "finish", 1494643858u, 0, 6, NULL); -be_define_const_str(attrdump, "attrdump", 1521571304u, 0, 8, &be_const_str_continue); -be_define_const_str(continue, "continue", 2977070660u, 59, 8, &be_const_str_do); -be_define_const_str(do, "do", 1646057492u, 65, 2, NULL); -be_define_const_str(false, "false", 184981848u, 62, 5, NULL); -be_define_const_str(tomap, "tomap", 612167626u, 0, 5, NULL); -be_define_const_str(find_key_i, "find_key_i", 850136726u, 0, 10, NULL); -be_define_const_str(pop, "pop", 1362321360u, 0, 3, &be_const_str_reset); -be_define_const_str(reset, "reset", 1695364032u, 0, 5, &be_const_str_tolower); -be_define_const_str(tolower, "tolower", 1042520049u, 0, 7, NULL); -be_define_const_str(sin, "sin", 3761252941u, 0, 3, NULL); -be_define_const_str(input, "input", 4191711099u, 0, 5, &be_const_str_resp_cmnd); +be_define_const_str(time_reached, "time_reached", 2075136773u, 0, 12, NULL); +be_define_const_str(SERIAL_5E2, "SERIAL_5E2", 1180552854u, 0, 10, &be_const_str___lower__); +be_define_const_str(__lower__, "__lower__", 123855590u, 0, 9, NULL); +be_define_const_str(SERIAL_7O1, "SERIAL_7O1", 1823802675u, 0, 10, &be_const_str_getbits); +be_define_const_str(getbits, "getbits", 3094168979u, 0, 7, &be_const_str_input); +be_define_const_str(input, "input", 4191711099u, 0, 5, NULL); +be_define_const_str(dot_size, ".size", 1965188224u, 0, 5, &be_const_str_publish_result); +be_define_const_str(publish_result, "publish_result", 2013351252u, 0, 14, &be_const_str_web_send_decimal); +be_define_const_str(web_send_decimal, "web_send_decimal", 1407210204u, 0, 16, &be_const_str_def); +be_define_const_str(def, "def", 3310976652u, 55, 3, NULL); +be_define_const_str(_cmd, "_cmd", 3419822142u, 0, 4, &be_const_str_begin); +be_define_const_str(begin, "begin", 1748273790u, 0, 5, &be_const_str_resp_cmnd); be_define_const_str(resp_cmnd, "resp_cmnd", 2869459626u, 0, 9, NULL); -be_define_const_str(Tasmota, "Tasmota", 4047617668u, 0, 7, &be_const_str_rad); -be_define_const_str(rad, "rad", 1358899048u, 0, 3, &be_const_str_read32); +be_define_const_str(assert, "assert", 2774883451u, 0, 6, &be_const_str_set); +be_define_const_str(set, "set", 3324446467u, 0, 3, &be_const_str_tag); +be_define_const_str(tag, "tag", 2516003219u, 0, 3, NULL); +be_define_const_str(check_privileged_access, "check_privileged_access", 3692933968u, 0, 23, &be_const_str_kv); +be_define_const_str(kv, "kv", 1497177492u, 0, 2, &be_const_str_publish); +be_define_const_str(publish, "publish", 264247304u, 0, 7, &be_const_str_read32); be_define_const_str(read32, "read32", 1741276240u, 0, 6, NULL); -be_define_const_str(_begin_transmission, "_begin_transmission", 2779461176u, 0, 19, &be_const_str_pi); -be_define_const_str(pi, "pi", 1213090802u, 0, 2, NULL); -be_define_const_str(save, "save", 3439296072u, 0, 4, &be_const_str_shared_key); -be_define_const_str(shared_key, "shared_key", 2200833624u, 0, 10, &be_const_str_write_bit); -be_define_const_str(write_bit, "write_bit", 2660990436u, 0, 9, NULL); -be_define_const_str(_settings_ptr, "_settings_ptr", 1825772182u, 0, 13, &be_const_str_search); +be_define_const_str(load, "load", 3859241449u, 0, 4, &be_const_str_read13); +be_define_const_str(read13, "read13", 12887293u, 0, 6, &be_const_str_search); be_define_const_str(search, "search", 2150836393u, 0, 6, NULL); -be_define_const_str(opt_call, "()", 685372826u, 0, 2, &be_const_str_setrange); -be_define_const_str(setrange, "setrange", 3794019032u, 0, 8, &be_const_str_var); -be_define_const_str(var, "var", 2317739966u, 64, 3, NULL); -be_define_const_str(resp_cmnd_done, "resp_cmnd_done", 2601874875u, 0, 14, NULL); -be_define_const_str(tan, "tan", 2633446552u, 0, 3, &be_const_str_update); -be_define_const_str(update, "update", 672109684u, 0, 6, NULL); -be_define_const_str(get_string, "get_string", 4195847969u, 0, 10, &be_const_str_setitem); -be_define_const_str(setitem, "setitem", 1554834596u, 0, 7, NULL); -be_define_const_str(memory, "memory", 2229924270u, 0, 6, &be_const_str_tanh); -be_define_const_str(tanh, "tanh", 153638352u, 0, 4, NULL); -be_define_const_str(SERIAL_6O1, "SERIAL_6O1", 266153272u, 0, 10, &be_const_str__end_transmission); -be_define_const_str(_end_transmission, "_end_transmission", 3237480400u, 0, 17, &be_const_str__timers); -be_define_const_str(_timers, "_timers", 2600100916u, 0, 7, NULL); -be_define_const_str(counters, "counters", 4095866864u, 0, 8, NULL); -be_define_const_str(millis, "millis", 1214679063u, 0, 6, NULL); +be_define_const_str(dac_voltage, "dac_voltage", 1552257222u, 0, 11, &be_const_str_finish); +be_define_const_str(finish, "finish", 1494643858u, 0, 6, &be_const_str_hex); +be_define_const_str(hex, "hex", 4273249610u, 0, 3, &be_const_str_isinstance); +be_define_const_str(isinstance, "isinstance", 3669352738u, 0, 10, &be_const_str_rand); +be_define_const_str(rand, "rand", 2711325910u, 0, 4, NULL); +be_define_const_str(POST, "POST", 1929554311u, 0, 4, &be_const_str_SERIAL_6E2); +be_define_const_str(SERIAL_6E2, "SERIAL_6E2", 317471867u, 0, 10, NULL); +be_define_const_str(classname, "classname", 1998589948u, 0, 9, NULL); +be_define_const_str(_global_def, "_global_def", 646007001u, 0, 11, &be_const_str_open); +be_define_const_str(open, "open", 3546203337u, 0, 4, &be_const_str_redirect); +be_define_const_str(redirect, "redirect", 389758641u, 0, 8, NULL); +be_define_const_str(AES_GCM, "AES_GCM", 3832208678u, 0, 7, &be_const_str_resp_cmnd_failed); +be_define_const_str(resp_cmnd_failed, "resp_cmnd_failed", 2136281562u, 0, 16, &be_const_str_reverse_gamma10); +be_define_const_str(reverse_gamma10, "reverse_gamma10", 739112262u, 0, 15, NULL); +be_define_const_str(strftime, "strftime", 187738851u, 0, 8, NULL); +be_define_const_str(insert, "insert", 3332609576u, 0, 6, &be_const_str_false); +be_define_const_str(false, "false", 184981848u, 62, 5, NULL); +be_define_const_str(arg_size, "arg_size", 3310243257u, 0, 8, &be_const_str_serial); +be_define_const_str(serial, "serial", 3687697785u, 0, 6, NULL); +be_define_const_str(OneWire, "OneWire", 2298990722u, 0, 7, &be_const_str_scale_uint); +be_define_const_str(scale_uint, "scale_uint", 3090811094u, 0, 10, NULL); +be_define_const_str(return, "return", 2246981567u, 60, 6, NULL); +be_define_const_str(wire, "wire", 4082753944u, 0, 4, &be_const_str_write_bytes); +be_define_const_str(write_bytes, "write_bytes", 1227543792u, 0, 11, NULL); +be_define_const_str(_global_addr, "_global_addr", 533766721u, 0, 12, &be_const_str_exec_tele); +be_define_const_str(exec_tele, "exec_tele", 1020751601u, 0, 9, &be_const_str_target_search); +be_define_const_str(target_search, "target_search", 1947846553u, 0, 13, NULL); +be_define_const_str(gamma8, "gamma8", 3802843830u, 0, 6, &be_const_str_pi); +be_define_const_str(pi, "pi", 1213090802u, 0, 2, &be_const_str_state); +be_define_const_str(state, "state", 2016490230u, 0, 5, NULL); +be_define_const_str(depower, "depower", 3563819571u, 0, 7, &be_const_str_init); +be_define_const_str(init, "init", 380752755u, 0, 4, &be_const_str_member); +be_define_const_str(member, "member", 719708611u, 0, 6, NULL); +be_define_const_str(_end_transmission, "_end_transmission", 3237480400u, 0, 17, &be_const_str_digital_read); +be_define_const_str(digital_read, "digital_read", 3585496928u, 0, 12, &be_const_str_imin); +be_define_const_str(imin, "imin", 2714127864u, 0, 4, NULL); +be_define_const_str(hs2rgb, "hs2rgb", 1040816349u, 0, 6, &be_const_str_keys); +be_define_const_str(keys, "keys", 4182378701u, 0, 4, &be_const_str_real); +be_define_const_str(real, "real", 3604983901u, 0, 4, &be_const_str_sin); +be_define_const_str(sin, "sin", 3761252941u, 0, 3, NULL); +be_define_const_str(SERIAL_7N1, "SERIAL_7N1", 1891060246u, 0, 10, NULL); +be_define_const_str(ctypes_bytes, "ctypes_bytes", 3879019703u, 0, 12, &be_const_str_ctypes_bytes_dyn); +be_define_const_str(ctypes_bytes_dyn, "ctypes_bytes_dyn", 915205307u, 0, 16, &be_const_str_raise); +be_define_const_str(raise, "raise", 1593437475u, 70, 5, NULL); +be_define_const_str(GET, "GET", 2531704439u, 0, 3, &be_const_str__settings_def); +be_define_const_str(_settings_def, "_settings_def", 3775560307u, 0, 13, &be_const_str_read24); +be_define_const_str(read24, "read24", 1808533811u, 0, 6, NULL); +be_define_const_str(cos, "cos", 4220379804u, 0, 3, &be_const_str_remove_driver); +be_define_const_str(remove_driver, "remove_driver", 1030243768u, 0, 13, NULL); +be_define_const_str(_settings_ptr, "_settings_ptr", 1825772182u, 0, 13, &be_const_str_memory); +be_define_const_str(memory, "memory", 2229924270u, 0, 6, &be_const_str_set_auth); +be_define_const_str(set_auth, "set_auth", 1057170930u, 0, 8, NULL); +be_define_const_str(content_send_style, "content_send_style", 1087907647u, 0, 18, &be_const_str_class); +be_define_const_str(class, "class", 2872970239u, 57, 5, NULL); +be_define_const_str(SERIAL_7E2, "SERIAL_7E2", 97385204u, 0, 10, &be_const_str_shared_key); +be_define_const_str(shared_key, "shared_key", 2200833624u, 0, 10, &be_const_str_tanh); +be_define_const_str(tanh, "tanh", 153638352u, 0, 4, &be_const_str_nil); +be_define_const_str(nil, "nil", 228849900u, 63, 3, NULL); +be_define_const_str(get_power, "get_power", 3009799377u, 0, 9, &be_const_str_last_modified); +be_define_const_str(last_modified, "last_modified", 772177145u, 0, 13, &be_const_str_resolvecmnd); +be_define_const_str(resolvecmnd, "resolvecmnd", 993361485u, 0, 11, NULL); +be_define_const_str(_read, "_read", 346717030u, 0, 5, NULL); +be_define_const_str(atan, "atan", 108579519u, 0, 4, &be_const_str_content_button); +be_define_const_str(content_button, "content_button", 1956476087u, 0, 14, &be_const_str_setbits); +be_define_const_str(setbits, "setbits", 2762408167u, 0, 7, &be_const_str_upper); +be_define_const_str(upper, "upper", 176974407u, 0, 5, NULL); +be_define_const_str(contains, "contains", 1825239352u, 0, 8, &be_const_str_time_str); +be_define_const_str(time_str, "time_str", 2613827612u, 0, 8, NULL); +be_define_const_str(arch, "arch", 2952804297u, 0, 4, &be_const_str_fromptr); +be_define_const_str(fromptr, "fromptr", 666189689u, 0, 7, &be_const_str_push); +be_define_const_str(push, "push", 2272264157u, 0, 4, &be_const_str_srand); +be_define_const_str(srand, "srand", 465518633u, 0, 5, NULL); +be_define_const_str(geti, "geti", 2381006490u, 0, 4, &be_const_str_seti); +be_define_const_str(seti, "seti", 1500556254u, 0, 4, NULL); +be_define_const_str(add_cmd, "add_cmd", 3361630879u, 0, 7, &be_const_str_cmd); +be_define_const_str(cmd, "cmd", 4136785899u, 0, 3, NULL); +be_define_const_str(get_switch, "get_switch", 164821028u, 0, 10, &be_const_str_size); +be_define_const_str(size, "size", 597743964u, 0, 4, NULL); +be_define_const_str(try, "try", 2887626766u, 68, 3, NULL); +be_define_const_str(web_send, "web_send", 2989941448u, 0, 8, &be_const_str_except); +be_define_const_str(except, "except", 950914032u, 69, 6, NULL); +be_define_const_str(SERIAL_5O1, "SERIAL_5O1", 3782657917u, 0, 10, &be_const_str_SERIAL_8E2); +be_define_const_str(SERIAL_8E2, "SERIAL_8E2", 2421454473u, 0, 10, &be_const_str__available); +be_define_const_str(_available, "_available", 1306196581u, 0, 10, NULL); +be_define_const_str(codedump, "codedump", 1786337906u, 0, 8, &be_const_str_wire2); +be_define_const_str(wire2, "wire2", 3229499038u, 0, 5, NULL); +be_define_const_str(dump, "dump", 3663001223u, 0, 4, &be_const_str_exec_cmd); +be_define_const_str(exec_cmd, "exec_cmd", 493567399u, 0, 8, NULL); +be_define_const_str(add, "add", 993596020u, 0, 3, &be_const_str_exp); +be_define_const_str(exp, "exp", 1923516200u, 0, 3, &be_const_str_isrunning); +be_define_const_str(isrunning, "isrunning", 1688182268u, 0, 9, &be_const_str_remove_rule); +be_define_const_str(remove_rule, "remove_rule", 3456211328u, 0, 11, &be_const_str_run_deferred); +be_define_const_str(run_deferred, "run_deferred", 371594696u, 0, 12, &be_const_str_scan); +be_define_const_str(scan, "scan", 3974641896u, 0, 4, &be_const_str_for); +be_define_const_str(for, "for", 2901640080u, 54, 3, NULL); +be_define_const_str(set_timer, "set_timer", 2135414533u, 0, 9, &be_const_str_url_encode); +be_define_const_str(url_encode, "url_encode", 528392145u, 0, 10, NULL); +be_define_const_str(addr, "addr", 1087856498u, 0, 4, NULL); +be_define_const_str(__upper__, "__upper__", 3612202883u, 0, 9, &be_const_str_loop); +be_define_const_str(loop, "loop", 3723446379u, 0, 4, NULL); +be_define_const_str(AudioGeneratorWAV, "AudioGeneratorWAV", 2746509368u, 0, 17, &be_const_str_chars_in_string); +be_define_const_str(chars_in_string, "chars_in_string", 3148785132u, 0, 15, &be_const_str_cosh); +be_define_const_str(cosh, "cosh", 4099687964u, 0, 4, &be_const_str_import); be_define_const_str(import, "import", 288002260u, 66, 6, NULL); -be_define_const_str(__lower__, "__lower__", 123855590u, 0, 9, &be_const_str_yield); -be_define_const_str(yield, "yield", 1821831854u, 0, 5, NULL); -be_define_const_str(_ccmd, "_ccmd", 2163421413u, 0, 5, &be_const_str_arg_size); -be_define_const_str(arg_size, "arg_size", 3310243257u, 0, 8, NULL); -be_define_const_str(imax, "imax", 3084515410u, 0, 4, NULL); +be_define_const_str(SERIAL_5N2, "SERIAL_5N2", 3363364537u, 0, 10, &be_const_str_type); +be_define_const_str(type, "type", 1361572173u, 0, 4, NULL); +be_define_const_str(clear, "clear", 1550717474u, 0, 5, NULL); +be_define_const_str(SERIAL_8N1, "SERIAL_8N1", 2369297235u, 0, 10, &be_const_str_issubclass); +be_define_const_str(issubclass, "issubclass", 4078395519u, 0, 10, &be_const_str_remove_timer); +be_define_const_str(remove_timer, "remove_timer", 4141472215u, 0, 12, &be_const_str_sinh); +be_define_const_str(sinh, "sinh", 282220607u, 0, 4, NULL); +be_define_const_str(AudioGeneratorMP3, "AudioGeneratorMP3", 2199818488u, 0, 17, &be_const_str_Wire); +be_define_const_str(Wire, "Wire", 1938276536u, 0, 4, &be_const_str_get_light); +be_define_const_str(get_light, "get_light", 381930476u, 0, 9, NULL); +be_define_const_str(get_option, "get_option", 2123730033u, 0, 10, &be_const_str_list); +be_define_const_str(list, "list", 217798785u, 0, 4, &be_const_str_stop); +be_define_const_str(stop, "stop", 3411225317u, 0, 4, &be_const_str_try_rule); +be_define_const_str(try_rule, "try_rule", 1986449405u, 0, 8, NULL); +be_define_const_str(webclient, "webclient", 4076389146u, 0, 9, NULL); +be_define_const_str(dot_p2, ".p2", 232398067u, 0, 3, &be_const_str_has); +be_define_const_str(has, "has", 3988721635u, 0, 3, NULL); +be_define_const_str(_request_from, "_request_from", 3965148604u, 0, 13, &be_const_str_setrange); +be_define_const_str(setrange, "setrange", 3794019032u, 0, 8, NULL); +be_define_const_str(I2C_Driver, "I2C_Driver", 1714501658u, 0, 10, NULL); +be_define_const_str(ceil, "ceil", 1659167240u, 0, 4, &be_const_str_else); +be_define_const_str(else, "else", 3183434736u, 52, 4, NULL); +be_define_const_str(concat, "concat", 4124019837u, 0, 6, &be_const_str_set_power); +be_define_const_str(set_power, "set_power", 549820893u, 0, 9, NULL); +be_define_const_str(tomap, "tomap", 612167626u, 0, 5, NULL); +be_define_const_str(resp_cmnd_error, "resp_cmnd_error", 2404088863u, 0, 15, NULL); +be_define_const_str(add_header, "add_header", 927130612u, 0, 10, &be_const_str_eth); +be_define_const_str(eth, "eth", 2191266556u, 0, 3, &be_const_str_write_bit); +be_define_const_str(write_bit, "write_bit", 2660990436u, 0, 9, NULL); +be_define_const_str(exists, "exists", 1002329533u, 0, 6, &be_const_str_pow); +be_define_const_str(pow, "pow", 1479764693u, 0, 3, &be_const_str_select); +be_define_const_str(select, "select", 297952813u, 0, 6, NULL); +be_define_const_str(allocated, "allocated", 429986098u, 0, 9, &be_const_str_classof); +be_define_const_str(classof, "classof", 1796577762u, 0, 7, &be_const_str_if); +be_define_const_str(if, "if", 959999494u, 50, 2, NULL); +be_define_const_str(SERIAL_5E1, "SERIAL_5E1", 1163775235u, 0, 10, &be_const_str_arg); +be_define_const_str(arg, "arg", 1047474471u, 0, 3, &be_const_str_cb_dispatch); +be_define_const_str(cb_dispatch, "cb_dispatch", 1741510499u, 0, 11, &be_const_str_response_append); +be_define_const_str(response_append, "response_append", 450346371u, 0, 15, NULL); +be_define_const_str(pin_used, "pin_used", 4033854612u, 0, 8, &be_const_str_write); +be_define_const_str(write, "write", 3190202204u, 0, 5, &be_const_str_write8); +be_define_const_str(write8, "write8", 3133991532u, 0, 6, NULL); +be_define_const_str(SERIAL_6O2, "SERIAL_6O2", 316486129u, 0, 10, &be_const_str_log); +be_define_const_str(log, "log", 1062293841u, 0, 3, NULL); +be_define_const_str(pin_mode, "pin_mode", 3258314030u, 0, 8, &be_const_str_read12); +be_define_const_str(read12, "read12", 4291076970u, 0, 6, &be_const_str_resp_cmnd_str); +be_define_const_str(resp_cmnd_str, "resp_cmnd_str", 737845590u, 0, 13, NULL); +be_define_const_str(abs, "abs", 709362235u, 0, 3, &be_const_str_digital_write); +be_define_const_str(digital_write, "digital_write", 3435877979u, 0, 13, &be_const_str_static); +be_define_const_str(static, "static", 3532702267u, 71, 6, NULL); +be_define_const_str(bytes, "bytes", 1706151940u, 0, 5, &be_const_str_find_op); +be_define_const_str(find_op, "find_op", 3766713376u, 0, 7, NULL); +be_define_const_str(call, "call", 3018949801u, 0, 4, NULL); +be_define_const_str(cmd_res, "cmd_res", 921166762u, 0, 7, NULL); +be_define_const_str(opt_eq, "==", 2431966415u, 0, 2, NULL); +be_define_const_str(save, "save", 3439296072u, 0, 4, NULL); +be_define_const_str(find_key_i, "find_key_i", 850136726u, 0, 10, NULL); +be_define_const_str(_cb, "_cb", 4043300367u, 0, 3, NULL); +be_define_const_str(Tasmota, "Tasmota", 4047617668u, 0, 7, &be_const_str_public_key); +be_define_const_str(public_key, "public_key", 4169142980u, 0, 10, NULL); +be_define_const_str(as, "as", 1579491469u, 67, 2, NULL); +be_define_const_str(dot_w, ".w", 1255414514u, 0, 2, &be_const_str_SERIAL_8O1); +be_define_const_str(SERIAL_8O1, "SERIAL_8O1", 289122742u, 0, 10, &be_const_str_compile); +be_define_const_str(compile, "compile", 1000265118u, 0, 7, &be_const_str_range); +be_define_const_str(range, "range", 4208725202u, 0, 5, NULL); +be_define_const_str(add_rule, "add_rule", 596540743u, 0, 8, NULL); +be_define_const_str(_ptr, "_ptr", 306235816u, 0, 4, &be_const_str_delay); +be_define_const_str(delay, "delay", 1322381784u, 0, 5, &be_const_str_pop); +be_define_const_str(pop, "pop", 1362321360u, 0, 3, &be_const_str_reset); +be_define_const_str(reset, "reset", 1695364032u, 0, 5, &be_const_str_wire_scan); +be_define_const_str(wire_scan, "wire_scan", 2671275880u, 0, 9, NULL); +be_define_const_str(reset_search, "reset_search", 1350414305u, 0, 12, &be_const_str_tolower); +be_define_const_str(tolower, "tolower", 1042520049u, 0, 7, NULL); +be_define_const_str(SERIAL_7O2, "SERIAL_7O2", 1840580294u, 0, 10, &be_const_str_asin); +be_define_const_str(asin, "asin", 4272848550u, 0, 4, &be_const_str_nan); +be_define_const_str(nan, "nan", 797905850u, 0, 3, NULL); +be_define_const_str(deg, "deg", 3327754271u, 0, 3, NULL); +be_define_const_str(log10, "log10", 2346846000u, 0, 5, NULL); +be_define_const_str(char, "char", 2823553821u, 0, 4, &be_const_str_get_size); +be_define_const_str(get_size, "get_size", 2803644713u, 0, 8, NULL); +be_define_const_str(opt_call, "()", 685372826u, 0, 2, &be_const_str_end); +be_define_const_str(end, "end", 1787721130u, 56, 3, NULL); +be_define_const_str(SERIAL_7N2, "SERIAL_7N2", 1874282627u, 0, 10, &be_const_str_time_dump); +be_define_const_str(time_dump, "time_dump", 3330410747u, 0, 9, NULL); +be_define_const_str(listdir, "listdir", 2005220720u, 0, 7, &be_const_str_wifi); +be_define_const_str(wifi, "wifi", 120087624u, 0, 4, NULL); +be_define_const_str(read_bytes, "read_bytes", 3576733173u, 0, 10, &be_const_str_reverse); +be_define_const_str(reverse, "reverse", 558918661u, 0, 7, NULL); +be_define_const_str(SERIAL_6E1, "SERIAL_6E1", 334249486u, 0, 10, NULL); +be_define_const_str(SERIAL_5O2, "SERIAL_5O2", 3732325060u, 0, 10, &be_const_str_SERIAL_8E1); +be_define_const_str(SERIAL_8E1, "SERIAL_8E1", 2371121616u, 0, 10, &be_const_str_asstring); +be_define_const_str(asstring, "asstring", 1298225088u, 0, 8, &be_const_str_deinit); +be_define_const_str(deinit, "deinit", 2345559592u, 0, 6, NULL); +be_define_const_str(encrypt, "encrypt", 2194327650u, 0, 7, NULL); +be_define_const_str(iter, "iter", 3124256359u, 0, 4, &be_const_str_millis); +be_define_const_str(millis, "millis", 1214679063u, 0, 6, NULL); +be_define_const_str(AudioOutput, "AudioOutput", 3257792048u, 0, 11, &be_const_str_members); +be_define_const_str(members, "members", 937576464u, 0, 7, &be_const_str_rtc); +be_define_const_str(rtc, "rtc", 1070575216u, 0, 3, NULL); +be_define_const_str(SERIAL_6N1, "SERIAL_6N1", 198895701u, 0, 10, &be_const_str__write); +be_define_const_str(_write, "_write", 2215462825u, 0, 6, &be_const_str_content_start); +be_define_const_str(content_start, "content_start", 2937509069u, 0, 13, &be_const_str_module); +be_define_const_str(module, "module", 3617558685u, 0, 6, NULL); +be_define_const_str(item, "item", 2671260646u, 0, 4, &be_const_str_remove_cmd); +be_define_const_str(remove_cmd, "remove_cmd", 3832315702u, 0, 10, NULL); +be_define_const_str(MD5, "MD5", 1935726387u, 0, 3, &be_const_str_sqrt); +be_define_const_str(sqrt, "sqrt", 2112764879u, 0, 4, NULL); +be_define_const_str(SERIAL_5N1, "SERIAL_5N1", 3313031680u, 0, 10, &be_const_str_break); +be_define_const_str(break, "break", 3378807160u, 58, 5, NULL); +be_define_const_str(map, "map", 3751997361u, 0, 3, &be_const_str_setmember); +be_define_const_str(setmember, "setmember", 1432909441u, 0, 9, &be_const_str_tostring); +be_define_const_str(tostring, "tostring", 2299708645u, 0, 8, NULL); +be_define_const_str(AudioGenerator, "AudioGenerator", 1839297342u, 0, 14, &be_const_str_while); +be_define_const_str(while, "while", 231090382u, 53, 5, NULL); +be_define_const_str(event, "event", 4264611999u, 0, 5, &be_const_str_resp_cmnd_done); +be_define_const_str(resp_cmnd_done, "resp_cmnd_done", 2601874875u, 0, 14, NULL); +be_define_const_str(AudioOutputI2S, "AudioOutputI2S", 638031784u, 0, 14, &be_const_str_has_arg); +be_define_const_str(has_arg, "has_arg", 424878688u, 0, 7, NULL); +be_define_const_str(floor, "floor", 3102149661u, 0, 5, &be_const_str_read); +be_define_const_str(read, "read", 3470762949u, 0, 4, &be_const_str_remove); +be_define_const_str(remove, "remove", 3683784189u, 0, 6, NULL); +be_define_const_str(calldepth, "calldepth", 3122364302u, 0, 9, &be_const_str_lower); +be_define_const_str(lower, "lower", 3038577850u, 0, 5, &be_const_str_path); +be_define_const_str(path, "path", 2223459638u, 0, 4, NULL); +be_define_const_str(gamma10, "gamma10", 3472052483u, 0, 7, &be_const_str_get); +be_define_const_str(get, "get", 1410115415u, 0, 3, &be_const_str_elif); be_define_const_str(elif, "elif", 3232090307u, 51, 4, NULL); +be_define_const_str(_buffer, "_buffer", 2044888568u, 0, 7, &be_const_str_exec_rules); +be_define_const_str(exec_rules, "exec_rules", 1445221092u, 0, 10, &be_const_str_pin); +be_define_const_str(pin, "pin", 1866532500u, 0, 3, NULL); +be_define_const_str(collect, "collect", 2399039025u, 0, 7, NULL); +be_define_const_str(enabled, "enabled", 49525662u, 0, 7, &be_const_str_global); +be_define_const_str(global, "global", 503252654u, 0, 6, NULL); +be_define_const_str(acos, "acos", 1006755615u, 0, 4, &be_const_str_content_stop); +be_define_const_str(content_stop, "content_stop", 658554751u, 0, 12, &be_const_str_read8); +be_define_const_str(read8, "read8", 2802788167u, 0, 5, &be_const_str_wire1); +be_define_const_str(wire1, "wire1", 3212721419u, 0, 5, NULL); +be_define_const_str(fromstring, "fromstring", 610302344u, 0, 10, &be_const_str_setitem); +be_define_const_str(setitem, "setitem", 1554834596u, 0, 7, NULL); +be_define_const_str(_debug_present, "_debug_present", 4063411725u, 0, 14, &be_const_str_erase); +be_define_const_str(erase, "erase", 1010949589u, 0, 5, &be_const_str_i2c_enabled); +be_define_const_str(i2c_enabled, "i2c_enabled", 218388101u, 0, 11, &be_const_str_resize); +be_define_const_str(resize, "resize", 3514612129u, 0, 6, NULL); +be_define_const_str(decrypt, "decrypt", 2886974618u, 0, 7, &be_const_str_escape); +be_define_const_str(escape, "escape", 2652972038u, 0, 6, &be_const_str_isnan); +be_define_const_str(isnan, "isnan", 2981347434u, 0, 5, &be_const_str_skip); +be_define_const_str(skip, "skip", 1097563074u, 0, 4, &be_const_str_var); +be_define_const_str(var, "var", 2317739966u, 64, 3, NULL); +be_define_const_str(dot_p, ".p", 1171526419u, 0, 2, &be_const_str_write_file); +be_define_const_str(write_file, "write_file", 3177658879u, 0, 10, NULL); +be_define_const_str(copy, "copy", 3848464964u, 0, 4, &be_const_str_str); +be_define_const_str(str, "str", 3259748752u, 0, 3, &be_const_str_super); +be_define_const_str(super, "super", 4152230356u, 0, 5, &be_const_str_update); +be_define_const_str(update, "update", 672109684u, 0, 6, NULL); +be_define_const_str(_def, "_def", 1985022181u, 0, 4, &be_const_str__drivers); +be_define_const_str(_drivers, "_drivers", 3260328985u, 0, 8, NULL); +be_define_const_str(imax, "imax", 3084515410u, 0, 4, NULL); +be_define_const_str(add_driver, "add_driver", 1654458371u, 0, 10, NULL); +be_define_const_str(dot_len, ".len", 850842136u, 0, 4, &be_const_str_SERIAL_6O1); +be_define_const_str(SERIAL_6O1, "SERIAL_6O1", 266153272u, 0, 10, &be_const_str_attrdump); +be_define_const_str(attrdump, "attrdump", 1521571304u, 0, 8, &be_const_str_on); +be_define_const_str(on, "on", 1630810064u, 0, 2, &be_const_str_rad); +be_define_const_str(rad, "rad", 1358899048u, 0, 3, NULL); +be_define_const_str(bus, "bus", 1607822841u, 0, 3, NULL); +be_define_const_str(yield, "yield", 1821831854u, 0, 5, NULL); +be_define_const_str(top, "top", 2802900028u, 0, 3, NULL); +be_define_const_str(get_string, "get_string", 4195847969u, 0, 10, &be_const_str_read_sensors); +be_define_const_str(read_sensors, "read_sensors", 892689201u, 0, 12, NULL); +be_define_const_str(settings, "settings", 1745255176u, 0, 8, NULL); +be_define_const_str(_get_cb, "_get_cb", 1448849122u, 0, 7, &be_const_str_int); +be_define_const_str(int, "int", 2515107422u, 0, 3, NULL); +be_define_const_str(opt_neq, "!=", 2428715011u, 0, 2, &be_const_str_gen_cb); +be_define_const_str(gen_cb, "gen_cb", 3245227551u, 0, 6, NULL); +be_define_const_str(_timers, "_timers", 2600100916u, 0, 7, &be_const_str_continue); +be_define_const_str(continue, "continue", 2977070660u, 59, 8, NULL); +be_define_const_str(SERIAL_7E1, "SERIAL_7E1", 147718061u, 0, 10, NULL); +be_define_const_str(AudioFileSource, "AudioFileSource", 2959980058u, 0, 15, &be_const_str_format); +be_define_const_str(format, "format", 3114108242u, 0, 6, NULL); +be_define_const_str(EC_C25519, "EC_C25519", 95492591u, 0, 9, &be_const_str_close); +be_define_const_str(close, "close", 667630371u, 0, 5, &be_const_str_content_flush); +be_define_const_str(content_flush, "content_flush", 214922475u, 0, 13, &be_const_str_reduce); +be_define_const_str(reduce, "reduce", 2002030311u, 0, 6, &be_const_str_tr); +be_define_const_str(tr, "tr", 1195724803u, 0, 2, NULL); +be_define_const_str(available, "available", 1727918744u, 0, 9, NULL); +be_define_const_str(traceback, "traceback", 3385188109u, 0, 9, NULL); +be_define_const_str(opt_add, "+", 772578730u, 0, 1, &be_const_str_SERIAL_8N2); +be_define_const_str(SERIAL_8N2, "SERIAL_8N2", 2386074854u, 0, 10, &be_const_str_wd); +be_define_const_str(wd, "wd", 1531424278u, 0, 2, NULL); +be_define_const_str(__iterator__, "__iterator__", 3884039703u, 0, 12, &be_const_str_fromb64); +be_define_const_str(fromb64, "fromb64", 2717019639u, 0, 7, NULL); +be_define_const_str(number, "number", 467038368u, 0, 6, &be_const_str_print); +be_define_const_str(print, "print", 372738696u, 0, 5, &be_const_str_set_useragent); +be_define_const_str(set_useragent, "set_useragent", 612237244u, 0, 13, &be_const_str_tan); +be_define_const_str(tan, "tan", 2633446552u, 0, 3, &be_const_str_do); +be_define_const_str(do, "do", 1646057492u, 65, 2, NULL); +be_define_const_str(, "", 2166136261u, 0, 0, &be_const_str_opt_connect); +be_define_const_str(opt_connect, "..", 2748622605u, 0, 2, &be_const_str__rules); +be_define_const_str(_rules, "_rules", 4266217105u, 0, 6, NULL); +be_define_const_str(dot_p1, ".p1", 249175686u, 0, 3, &be_const_str_find); +be_define_const_str(find, "find", 3186656602u, 0, 4, &be_const_str_name); +be_define_const_str(name, "name", 2369371622u, 0, 4, &be_const_str_toptr); +be_define_const_str(toptr, "toptr", 3379847454u, 0, 5, NULL); +be_define_const_str(arg_name, "arg_name", 1345046155u, 0, 8, &be_const_str_byte); +be_define_const_str(byte, "byte", 1683620383u, 0, 4, &be_const_str_gc); +be_define_const_str(gc, "gc", 1042313471u, 0, 2, NULL); +be_define_const_str(count, "count", 967958004u, 0, 5, &be_const_str_counters); +be_define_const_str(counters, "counters", 4095866864u, 0, 8, &be_const_str_tob64); +be_define_const_str(tob64, "tob64", 373777640u, 0, 5, NULL); +be_define_const_str(AudioFileSourceFS, "AudioFileSourceFS", 1839147653u, 0, 17, &be_const_str_get_free_heap); +be_define_const_str(get_free_heap, "get_free_heap", 625069757u, 0, 13, NULL); +be_define_const_str(atan2, "atan2", 3173440503u, 0, 5, NULL); +be_define_const_str(set_timeouts, "set_timeouts", 3732850900u, 0, 12, &be_const_str_toupper); +be_define_const_str(toupper, "toupper", 3691983576u, 0, 7, NULL); +be_define_const_str(_ccmd, "_ccmd", 2163421413u, 0, 5, &be_const_str_content_send); +be_define_const_str(content_send, "content_send", 1673733649u, 0, 12, &be_const_str_flush); +be_define_const_str(flush, "flush", 3002334877u, 0, 5, &be_const_str_true); +be_define_const_str(true, "true", 1303515621u, 61, 4, NULL); +be_define_const_str(detect, "detect", 8884370u, 0, 6, NULL); +be_define_const_str(SERIAL_8O2, "SERIAL_8O2", 272345123u, 0, 10, &be_const_str_split); +be_define_const_str(split, "split", 2276994531u, 0, 5, NULL); static const bstring* const m_string_table[] = { - (const bstring *)&be_const_str_size, - (const bstring *)&be_const_str_has_arg, - NULL, - (const bstring *)&be_const_str_remove, - (const bstring *)&be_const_str_SERIAL_6E1, - (const bstring *)&be_const_str_cosh, - (const bstring *)&be_const_str_dac_voltage, - NULL, - (const bstring *)&be_const_str_SERIAL_7N2, - (const bstring *)&be_const_str__cb, - (const bstring *)&be_const_str_dot_p2, - (const bstring *)&be_const_str_decrypt, + (const bstring *)&be_const_str_SERIAL_6N2, + (const bstring *)&be_const_str_time_reached, + (const bstring *)&be_const_str_SERIAL_5E2, (const bstring *)&be_const_str_SERIAL_7O1, - (const bstring *)&be_const_str_SERIAL_5N2, - (const bstring *)&be_const_str_SERIAL_8N2, - (const bstring *)&be_const_str_resp_cmnd_failed, - (const bstring *)&be_const_str_SERIAL_5E1, + (const bstring *)&be_const_str_dot_size, NULL, + (const bstring *)&be_const_str__cmd, + (const bstring *)&be_const_str_assert, + (const bstring *)&be_const_str_check_privileged_access, + (const bstring *)&be_const_str_load, + (const bstring *)&be_const_str_dac_voltage, + (const bstring *)&be_const_str_POST, + (const bstring *)&be_const_str_classname, (const bstring *)&be_const_str__global_def, - (const bstring *)&be_const_str__rules, - (const bstring *)&be_const_str___upper__, - (const bstring *)&be_const_str_char, - (const bstring *)&be_const_str_add_header, + (const bstring *)&be_const_str_AES_GCM, + (const bstring *)&be_const_str_strftime, + (const bstring *)&be_const_str_insert, + (const bstring *)&be_const_str_arg_size, (const bstring *)&be_const_str_OneWire, - (const bstring *)&be_const_str_close, - (const bstring *)&be_const_str_read13, - (const bstring *)&be_const_str_AudioOutput, - (const bstring *)&be_const_str_gen_cb, - (const bstring *)&be_const_str_opt_neq, - (const bstring *)&be_const_str_pow, - (const bstring *)&be_const_str_count, - (const bstring *)&be_const_str_web_send, + (const bstring *)&be_const_str_return, + (const bstring *)&be_const_str_wire, + (const bstring *)&be_const_str__global_addr, + (const bstring *)&be_const_str_gamma8, + (const bstring *)&be_const_str_depower, + (const bstring *)&be_const_str__end_transmission, + (const bstring *)&be_const_str_hs2rgb, + (const bstring *)&be_const_str_SERIAL_7N1, + (const bstring *)&be_const_str_ctypes_bytes, NULL, - (const bstring *)&be_const_str_classof, - (const bstring *)&be_const_str_rand, - (const bstring *)&be_const_str_cb_dispatch, - (const bstring *)&be_const_str_floor, - (const bstring *)&be_const_str_SERIAL_5N1, + NULL, + NULL, + (const bstring *)&be_const_str_GET, + (const bstring *)&be_const_str_cos, + NULL, + (const bstring *)&be_const_str__settings_ptr, + (const bstring *)&be_const_str_content_send_style, + (const bstring *)&be_const_str_SERIAL_7E2, + (const bstring *)&be_const_str_get_power, + (const bstring *)&be_const_str__read, + (const bstring *)&be_const_str_atan, + (const bstring *)&be_const_str_contains, + (const bstring *)&be_const_str_arch, + (const bstring *)&be_const_str_geti, + (const bstring *)&be_const_str_add_cmd, (const bstring *)&be_const_str_get_switch, NULL, - (const bstring *)&be_const_str__read, - (const bstring *)&be_const_str_opt_eq, + (const bstring *)&be_const_str_try, NULL, - (const bstring *)&be_const_str_setbits, - (const bstring *)&be_const_str_stop, - (const bstring *)&be_const_str_issubclass, - (const bstring *)&be_const_str_flush, - (const bstring *)&be_const_str_I2C_Driver, - (const bstring *)&be_const_str_atan2, - (const bstring *)&be_const_str__settings_def, - (const bstring *)&be_const_str_name, - (const bstring *)&be_const_str_acos, - (const bstring *)&be_const_str_exists, - (const bstring *)&be_const_str_EC_C25519, - (const bstring *)&be_const_str_bus, - (const bstring *)&be_const_str_bytes, - NULL, - (const bstring *)&be_const_str_SERIAL_6N1, - (const bstring *)&be_const_str_dot_size, - (const bstring *)&be_const_str_AES_GCM, - (const bstring *)&be_const_str_cmd, - (const bstring *)&be_const_str_tostring, - (const bstring *)&be_const_str__buffer, - (const bstring *)&be_const_str_except, - (const bstring *)&be_const_str_dot_len, - (const bstring *)&be_const_str_SERIAL_6E2, - (const bstring *)&be_const_str_SERIAL_8E2, - (const bstring *)&be_const_str__ptr, - (const bstring *)&be_const_str_GET, - NULL, - (const bstring *)&be_const_str_byte, - NULL, - (const bstring *)&be_const_str_true, - (const bstring *)&be_const_str__write, - (const bstring *)&be_const_str_Wire, - (const bstring *)&be_const_str_SERIAL_8N1, - (const bstring *)&be_const_str_exec_cmd, - (const bstring *)&be_const_str_available, - (const bstring *)&be_const_str_publish_result, - (const bstring *)&be_const_str_, - NULL, - (const bstring *)&be_const_str_SERIAL_6N2, - (const bstring *)&be_const_str_AudioOutputI2S, - (const bstring *)&be_const_str_fromstring, - (const bstring *)&be_const_str_print, - (const bstring *)&be_const_str__request_from, - (const bstring *)&be_const_str_detect, - (const bstring *)&be_const_str_nil, - (const bstring *)&be_const_str_remove_driver, - (const bstring *)&be_const_str_SERIAL_7E2, - (const bstring *)&be_const_str_SERIAL_8E1, - (const bstring *)&be_const_str_add, - NULL, - (const bstring *)&be_const_str_compile, - (const bstring *)&be_const_str_has, + (const bstring *)&be_const_str_web_send, + (const bstring *)&be_const_str_SERIAL_5O1, (const bstring *)&be_const_str_codedump, - (const bstring *)&be_const_str_reduce, - (const bstring *)&be_const_str_as, - (const bstring *)&be_const_str_get_size, - (const bstring *)&be_const_str_opt_connect, - (const bstring *)&be_const_str__get_cb, - (const bstring *)&be_const_str_gc, - (const bstring *)&be_const_str_begin, - (const bstring *)&be_const_str_cmd_res, - (const bstring *)&be_const_str_insert, - (const bstring *)&be_const_str___iterator__, - (const bstring *)&be_const_str_SERIAL_7N1, - (const bstring *)&be_const_str_int, - (const bstring *)&be_const_str_dot_p1, - (const bstring *)&be_const_str_dot_p, - (const bstring *)&be_const_str_SERIAL_7O2, - NULL, - (const bstring *)&be_const_str_POST, - (const bstring *)&be_const_str_hex, - (const bstring *)&be_const_str_SERIAL_5E2, - (const bstring *)&be_const_str_opt_add, - (const bstring *)&be_const_str_publish, - (const bstring *)&be_const_str_log10, - (const bstring *)&be_const_str__drivers, - NULL, - (const bstring *)&be_const_str_arg, - (const bstring *)&be_const_str_wire, - (const bstring *)&be_const_str_dot_w, - (const bstring *)&be_const_str_scan, - (const bstring *)&be_const_str_AudioFileSource, - (const bstring *)&be_const_str_nan, - (const bstring *)&be_const_str_MD5, - (const bstring *)&be_const_str_SERIAL_6O2, - (const bstring *)&be_const_str_content_start, - (const bstring *)&be_const_str_AudioGenerator, - NULL, + (const bstring *)&be_const_str_dump, + (const bstring *)&be_const_str_add, + (const bstring *)&be_const_str_set_timer, + (const bstring *)&be_const_str_addr, + (const bstring *)&be_const_str___upper__, (const bstring *)&be_const_str_AudioGeneratorWAV, - (const bstring *)&be_const_str_encrypt, - (const bstring *)&be_const_str__available, - (const bstring *)&be_const_str_attrdump, - (const bstring *)&be_const_str_false, - (const bstring *)&be_const_str_tomap, - (const bstring *)&be_const_str_find_key_i, - (const bstring *)&be_const_str_pop, - (const bstring *)&be_const_str_sin, + (const bstring *)&be_const_str_SERIAL_5N2, + (const bstring *)&be_const_str_clear, + (const bstring *)&be_const_str_SERIAL_8N1, + (const bstring *)&be_const_str_AudioGeneratorMP3, + (const bstring *)&be_const_str_get_option, + (const bstring *)&be_const_str_webclient, + (const bstring *)&be_const_str_dot_p2, + (const bstring *)&be_const_str__request_from, NULL, - (const bstring *)&be_const_str_input, - (const bstring *)&be_const_str_Tasmota, - (const bstring *)&be_const_str__begin_transmission, + (const bstring *)&be_const_str_I2C_Driver, + NULL, + (const bstring *)&be_const_str_ceil, + (const bstring *)&be_const_str_concat, + (const bstring *)&be_const_str_tomap, + (const bstring *)&be_const_str_resp_cmnd_error, + (const bstring *)&be_const_str_add_header, + (const bstring *)&be_const_str_exists, + (const bstring *)&be_const_str_allocated, + (const bstring *)&be_const_str_SERIAL_5E1, + (const bstring *)&be_const_str_pin_used, + (const bstring *)&be_const_str_SERIAL_6O2, + (const bstring *)&be_const_str_pin_mode, + (const bstring *)&be_const_str_abs, + (const bstring *)&be_const_str_bytes, + (const bstring *)&be_const_str_call, + (const bstring *)&be_const_str_cmd_res, + (const bstring *)&be_const_str_opt_eq, (const bstring *)&be_const_str_save, - (const bstring *)&be_const_str__settings_ptr, + NULL, + (const bstring *)&be_const_str_find_key_i, + (const bstring *)&be_const_str__cb, + (const bstring *)&be_const_str_Tasmota, + (const bstring *)&be_const_str_as, + (const bstring *)&be_const_str_dot_w, + (const bstring *)&be_const_str_add_rule, + (const bstring *)&be_const_str__ptr, + (const bstring *)&be_const_str_reset_search, + (const bstring *)&be_const_str_SERIAL_7O2, + (const bstring *)&be_const_str_deg, + (const bstring *)&be_const_str_log10, + (const bstring *)&be_const_str_char, (const bstring *)&be_const_str_opt_call, - (const bstring *)&be_const_str_resp_cmnd_done, - (const bstring *)&be_const_str_tan, - (const bstring *)&be_const_str_get_string, - (const bstring *)&be_const_str_memory, - (const bstring *)&be_const_str_SERIAL_6O1, - (const bstring *)&be_const_str_counters, - (const bstring *)&be_const_str_millis, - (const bstring *)&be_const_str_import, - (const bstring *)&be_const_str___lower__, - (const bstring *)&be_const_str__ccmd, + (const bstring *)&be_const_str_SERIAL_7N2, + (const bstring *)&be_const_str_listdir, + (const bstring *)&be_const_str_read_bytes, + (const bstring *)&be_const_str_SERIAL_6E1, + NULL, + (const bstring *)&be_const_str_SERIAL_5O2, + NULL, + (const bstring *)&be_const_str_encrypt, + (const bstring *)&be_const_str_iter, + (const bstring *)&be_const_str_AudioOutput, + (const bstring *)&be_const_str_SERIAL_6N1, + (const bstring *)&be_const_str_item, + (const bstring *)&be_const_str_MD5, + (const bstring *)&be_const_str_SERIAL_5N1, + (const bstring *)&be_const_str_map, + (const bstring *)&be_const_str_AudioGenerator, + (const bstring *)&be_const_str_event, + (const bstring *)&be_const_str_AudioOutputI2S, + (const bstring *)&be_const_str_floor, + (const bstring *)&be_const_str_calldepth, + (const bstring *)&be_const_str_gamma10, + (const bstring *)&be_const_str__buffer, + (const bstring *)&be_const_str_collect, + (const bstring *)&be_const_str_enabled, + (const bstring *)&be_const_str_acos, + (const bstring *)&be_const_str_fromstring, + (const bstring *)&be_const_str__debug_present, + (const bstring *)&be_const_str_decrypt, + (const bstring *)&be_const_str_dot_p, + (const bstring *)&be_const_str_copy, + (const bstring *)&be_const_str__def, (const bstring *)&be_const_str_imax, - (const bstring *)&be_const_str_elif + (const bstring *)&be_const_str_add_driver, + (const bstring *)&be_const_str_dot_len, + (const bstring *)&be_const_str_bus, + (const bstring *)&be_const_str_yield, + NULL, + (const bstring *)&be_const_str_top, + (const bstring *)&be_const_str_get_string, + NULL, + NULL, + (const bstring *)&be_const_str_settings, + NULL, + (const bstring *)&be_const_str__get_cb, + (const bstring *)&be_const_str_opt_neq, + (const bstring *)&be_const_str__timers, + (const bstring *)&be_const_str_SERIAL_7E1, + (const bstring *)&be_const_str_AudioFileSource, + (const bstring *)&be_const_str_EC_C25519, + (const bstring *)&be_const_str_available, + (const bstring *)&be_const_str_traceback, + (const bstring *)&be_const_str_opt_add, + (const bstring *)&be_const_str___iterator__, + (const bstring *)&be_const_str_number, + (const bstring *)&be_const_str_, + (const bstring *)&be_const_str_dot_p1, + (const bstring *)&be_const_str_arg_name, + (const bstring *)&be_const_str_count, + (const bstring *)&be_const_str_AudioFileSourceFS, + NULL, + (const bstring *)&be_const_str_atan2, + (const bstring *)&be_const_str_set_timeouts, + (const bstring *)&be_const_str__ccmd, + (const bstring *)&be_const_str_detect, + (const bstring *)&be_const_str_SERIAL_8O2 }; static const struct bconststrtab m_const_string_table = { - .size = 159, - .count = 318, + .size = 164, + .count = 328, .table = m_string_table }; diff --git a/lib/libesp32/Berry/generate/be_fixed_be_class_list.h b/lib/libesp32/Berry/generate/be_fixed_be_class_list.h index 300efcce0..2450de9a2 100644 --- a/lib/libesp32/Berry/generate/be_fixed_be_class_list.h +++ b/lib/libesp32/Berry/generate/be_fixed_be_class_list.h @@ -1,32 +1,33 @@ #include "be_constobj.h" static be_define_const_map_slots(be_class_list_map) { - { be_const_key(concat, -1), be_const_func(m_concat) }, - { be_const_key(push, -1), be_const_func(m_push) }, - { be_const_key(insert, 1), be_const_func(m_insert) }, - { be_const_key(find, -1), be_const_func(m_find) }, - { be_const_key(remove, 9), be_const_func(m_remove) }, - { be_const_key(clear, -1), be_const_func(m_clear) }, - { be_const_key(size, -1), be_const_func(m_size) }, - { be_const_key(resize, 13), be_const_func(m_resize) }, - { be_const_key(copy, -1), be_const_func(m_copy) }, - { be_const_key(pop, -1), be_const_func(m_pop) }, - { be_const_key(tostring, 3), be_const_func(m_tostring) }, - { be_const_key(opt_eq, -1), be_const_func(m_equal) }, + { be_const_key(opt_add, -1), be_const_func(m_merge) }, { be_const_key(init, -1), be_const_func(m_init) }, - { be_const_key(dot_p, 17), be_const_var(0) }, + { be_const_key(opt_connect, 11), be_const_func(m_connect) }, + { be_const_key(tostring, 2), be_const_func(m_tostring) }, + { be_const_key(pop, 6), be_const_func(m_pop) }, + { be_const_key(insert, -1), be_const_func(m_insert) }, + { be_const_key(size, -1), be_const_func(m_size) }, + { be_const_key(remove, 12), be_const_func(m_remove) }, + { be_const_key(find, -1), be_const_func(m_find) }, + { be_const_key(push, 1), be_const_func(m_push) }, + { be_const_key(item, 5), be_const_func(m_item) }, + { be_const_key(concat, -1), be_const_func(m_concat) }, + { be_const_key(dot_p, -1), be_const_var(0) }, + { be_const_key(iter, -1), be_const_func(m_iter) }, + { be_const_key(copy, -1), be_const_func(m_copy) }, + { be_const_key(reverse, 13), be_const_func(m_reverse) }, + { be_const_key(keys, -1), be_const_func(m_keys) }, + { be_const_key(resize, 16), be_const_func(m_resize) }, { be_const_key(setitem, -1), be_const_func(m_setitem) }, - { be_const_key(opt_connect, 4), be_const_func(m_connect) }, - { be_const_key(opt_neq, -1), be_const_func(m_nequal) }, - { be_const_key(opt_add, 18), be_const_func(m_merge) }, - { be_const_key(iter, 20), be_const_func(m_iter) }, - { be_const_key(item, -1), be_const_func(m_item) }, - { be_const_key(reverse, -1), be_const_func(m_reverse) }, + { be_const_key(opt_neq, 7), be_const_func(m_nequal) }, + { be_const_key(clear, -1), be_const_func(m_clear) }, + { be_const_key(opt_eq, -1), be_const_func(m_equal) }, }; static be_define_const_map( be_class_list_map, - 21 + 22 ); BE_EXPORT_VARIABLE be_define_const_class( diff --git a/lib/libesp32/Berry/generate/be_fixed_be_class_tasmota.h b/lib/libesp32/Berry/generate/be_fixed_be_class_tasmota.h index a9f54b4b4..c931a3bc0 100644 --- a/lib/libesp32/Berry/generate/be_fixed_be_class_tasmota.h +++ b/lib/libesp32/Berry/generate/be_fixed_be_class_tasmota.h @@ -1,90 +1,95 @@ #include "be_constobj.h" static be_define_const_map_slots(be_class_tasmota_map) { - { be_const_key(set_light, -1), be_const_closure(set_light_closure) }, - { be_const_key(gc, -1), be_const_closure(gc_closure) }, - { be_const_key(remove_cmd, -1), be_const_closure(remove_cmd_closure) }, - { be_const_key(set_timer, 42), be_const_closure(set_timer_closure) }, - { be_const_key(_settings_ptr, -1), be_const_comptr(&Settings) }, - { be_const_key(set_power, -1), be_const_func(l_setpower) }, - { be_const_key(remove_driver, -1), be_const_closure(remove_driver_closure) }, - { be_const_key(try_rule, -1), be_const_closure(try_rule_closure) }, - { be_const_key(find_op, 58), be_const_closure(find_op_closure) }, - { be_const_key(resp_cmnd_str, -1), be_const_func(l_respCmndStr) }, - { be_const_key(find_key_i, -1), be_const_closure(find_key_i_closure) }, - { be_const_key(_cb, 3), be_const_var(0) }, - { be_const_key(web_send, -1), be_const_func(l_webSend) }, - { be_const_key(log, 1), be_const_func(l_logInfo) }, - { be_const_key(get_switch, 50), be_const_func(l_getswitch) }, - { be_const_key(_ccmd, 19), be_const_var(1) }, - { be_const_key(eth, -1), be_const_func(l_eth) }, - { be_const_key(_settings_def, -1), be_const_comptr(&be_tasmota_settings_struct) }, - { be_const_key(init, 39), be_const_closure(init_closure) }, - { be_const_key(strftime, -1), be_const_func(l_strftime) }, - { be_const_key(kv, -1), be_const_closure(kv_closure) }, { be_const_key(resp_cmnd_done, -1), be_const_func(l_respCmndDone) }, - { be_const_key(cmd_res, 67), be_const_var(2) }, - { be_const_key(wire1, 43), be_const_var(3) }, - { be_const_key(get_light, -1), be_const_closure(get_light_closure) }, - { be_const_key(resp_cmnd_error, 62), be_const_func(l_respCmndError) }, - { be_const_key(publish_result, 9), be_const_func(l_publish_result) }, - { be_const_key(gen_cb, -1), be_const_closure(gen_cb_closure) }, - { be_const_key(yield, -1), be_const_func(l_yield) }, - { be_const_key(add_rule, -1), be_const_closure(add_rule_closure) }, - { be_const_key(settings, -1), be_const_var(4) }, - { be_const_key(chars_in_string, -1), be_const_closure(chars_in_string_closure) }, - { be_const_key(resp_cmnd, 31), be_const_func(l_respCmnd) }, - { be_const_key(exec_tele, 68), be_const_closure(exec_tele_closure) }, - { be_const_key(exec_rules, 51), be_const_closure(exec_rules_closure) }, - { be_const_key(load, -1), be_const_closure(load_closure) }, - { be_const_key(remove_rule, 22), be_const_closure(remove_rule_closure) }, - { be_const_key(_rules, 18), be_const_var(5) }, - { be_const_key(publish, -1), be_const_func(l_publish) }, - { be_const_key(get_option, 15), be_const_func(l_getoption) }, - { be_const_key(global, -1), be_const_var(6) }, - { be_const_key(add_driver, 33), be_const_closure(add_driver_closure) }, - { be_const_key(cmd, -1), be_const_closure(cmd_closure) }, - { be_const_key(add_cmd, -1), be_const_closure(add_cmd_closure) }, - { be_const_key(run_deferred, -1), be_const_closure(run_deferred_closure) }, - { be_const_key(get_free_heap, -1), be_const_func(l_getFreeHeap) }, - { be_const_key(wifi, -1), be_const_func(l_wifi) }, - { be_const_key(time_dump, -1), be_const_func(l_time_dump) }, - { be_const_key(rtc, 24), be_const_func(l_rtc) }, - { be_const_key(cb_dispatch, -1), be_const_closure(cb_dispatch_closure) }, - { be_const_key(_get_cb, -1), be_const_func(l_get_cb) }, - { be_const_key(resp_cmnd_failed, 72), be_const_func(l_respCmndFailed) }, - { be_const_key(wire_scan, -1), be_const_closure(wire_scan_closure) }, - { be_const_key(exec_cmd, -1), be_const_closure(exec_cmd_closure) }, - { be_const_key(_cmd, 46), be_const_func(l_cmd) }, - { be_const_key(remove_timer, -1), be_const_closure(remove_timer_closure) }, - { be_const_key(time_str, 34), be_const_closure(time_str_closure) }, - { be_const_key(response_append, -1), be_const_func(l_respAppend) }, - { be_const_key(web_send_decimal, 60), be_const_func(l_webSendDecimal) }, - { be_const_key(_drivers, 71), be_const_var(7) }, - { be_const_key(delay, -1), be_const_func(l_delay) }, + { be_const_key(resolvecmnd, 42), be_const_func(l_resolveCmnd) }, + { be_const_key(add_driver, -1), be_const_closure(add_driver_closure) }, + { be_const_key(gc, -1), be_const_closure(gc_closure) }, + { be_const_key(find_op, -1), be_const_closure(find_op_closure) }, + { be_const_key(scale_uint, 15), be_const_func(l_scaleuint) }, + { be_const_key(try_rule, -1), be_const_closure(try_rule_closure) }, { be_const_key(time_reached, -1), be_const_func(l_timereached) }, - { be_const_key(_global_def, -1), be_const_comptr(&be_tasmota_global_struct) }, - { be_const_key(resolvecmnd, -1), be_const_func(l_resolveCmnd) }, - { be_const_key(_timers, -1), be_const_var(8) }, - { be_const_key(event, 7), be_const_closure(event_closure) }, - { be_const_key(wire2, -1), be_const_var(9) }, - { be_const_key(scale_uint, -1), be_const_func(l_scaleuint) }, - { be_const_key(get_power, 73), be_const_func(l_getpower) }, + { be_const_key(web_send, -1), be_const_func(l_webSend) }, + { be_const_key(eth, 21), be_const_func(l_eth) }, + { be_const_key(get_switch, 34), be_const_func(l_getswitch) }, + { be_const_key(set_power, -1), be_const_func(l_setpower) }, + { be_const_key(_drivers, 50), be_const_var(0) }, + { be_const_key(_rules, -1), be_const_var(1) }, + { be_const_key(_ccmd, 6), be_const_var(2) }, + { be_const_key(time_dump, -1), be_const_func(l_time_dump) }, + { be_const_key(gen_cb, 17), be_const_closure(gen_cb_closure) }, + { be_const_key(cmd_res, 20), be_const_var(3) }, + { be_const_key(set_light, 63), be_const_closure(set_light_closure) }, { be_const_key(millis, -1), be_const_func(l_millis) }, - { be_const_key(save, 44), be_const_func(l_save) }, + { be_const_key(global, -1), be_const_var(4) }, + { be_const_key(exec_tele, 67), be_const_closure(exec_tele_closure) }, + { be_const_key(_settings_ptr, -1), be_const_comptr(&Settings) }, + { be_const_key(get_power, -1), be_const_func(l_getpower) }, + { be_const_key(_cb, 57), be_const_var(5) }, + { be_const_key(save, -1), be_const_func(l_save) }, + { be_const_key(run_deferred, -1), be_const_closure(run_deferred_closure) }, + { be_const_key(i2c_enabled, 9), be_const_func(l_i2cenabled) }, + { be_const_key(remove_driver, -1), be_const_closure(remove_driver_closure) }, + { be_const_key(event, -1), be_const_closure(event_closure) }, + { be_const_key(find_key_i, -1), be_const_closure(find_key_i_closure) }, + { be_const_key(web_send_decimal, -1), be_const_func(l_webSendDecimal) }, + { be_const_key(get_free_heap, 3), be_const_func(l_getFreeHeap) }, + { be_const_key(wire_scan, -1), be_const_closure(wire_scan_closure) }, + { be_const_key(init, -1), be_const_closure(init_closure) }, + { be_const_key(wd, -1), be_const_var(6) }, + { be_const_key(_debug_present, -1), be_const_var(7) }, + { be_const_key(time_str, 45), be_const_closure(time_str_closure) }, + { be_const_key(remove_rule, 71), be_const_closure(remove_rule_closure) }, + { be_const_key(memory, 62), be_const_func(l_memory) }, + { be_const_key(wifi, -1), be_const_func(l_wifi) }, + { be_const_key(get_option, 44), be_const_func(l_getoption) }, + { be_const_key(rtc, -1), be_const_func(l_rtc) }, + { be_const_key(load, 72), be_const_closure(load_closure) }, + { be_const_key(chars_in_string, -1), be_const_closure(chars_in_string_closure) }, + { be_const_key(cmd, -1), be_const_closure(cmd_closure) }, + { be_const_key(publish, 43), be_const_func(l_publish) }, + { be_const_key(resp_cmnd_error, 18), be_const_func(l_respCmndError) }, + { be_const_key(add_cmd, -1), be_const_closure(add_cmd_closure) }, + { be_const_key(_settings_def, -1), be_const_comptr(&be_tasmota_settings_struct) }, + { be_const_key(strftime, 4), be_const_func(l_strftime) }, + { be_const_key(add_rule, 41), be_const_closure(add_rule_closure) }, + { be_const_key(wire2, -1), be_const_var(8) }, + { be_const_key(settings, -1), be_const_var(9) }, + { be_const_key(exec_rules, -1), be_const_closure(exec_rules_closure) }, + { be_const_key(cb_dispatch, -1), be_const_closure(cb_dispatch_closure) }, + { be_const_key(yield, 68), be_const_func(l_yield) }, + { be_const_key(_get_cb, 75), be_const_func(l_get_cb) }, + { be_const_key(wire1, 33), be_const_var(10) }, + { be_const_key(resp_cmnd, -1), be_const_func(l_respCmnd) }, + { be_const_key(resp_cmnd_failed, 16), be_const_func(l_respCmndFailed) }, { be_const_key(_global_addr, -1), be_const_comptr(&TasmotaGlobal) }, - { be_const_key(memory, -1), be_const_func(l_memory) }, - { be_const_key(i2c_enabled, -1), be_const_func(l_i2cenabled) }, + { be_const_key(hs2rgb, -1), be_const_closure(hs2rgb_closure) }, + { be_const_key(resp_cmnd_str, 76), be_const_func(l_respCmndStr) }, + { be_const_key(_global_def, -1), be_const_comptr(&be_tasmota_global_struct) }, + { be_const_key(kv, 74), be_const_closure(kv_closure) }, + { be_const_key(delay, -1), be_const_func(l_delay) }, + { be_const_key(remove_cmd, 19), be_const_closure(remove_cmd_closure) }, + { be_const_key(set_timer, -1), be_const_closure(set_timer_closure) }, + { be_const_key(_cmd, 54), be_const_func(l_cmd) }, + { be_const_key(publish_result, -1), be_const_func(l_publish_result) }, + { be_const_key(log, -1), be_const_func(l_logInfo) }, + { be_const_key(arch, -1), be_const_func(l_arch) }, + { be_const_key(remove_timer, 66), be_const_closure(remove_timer_closure) }, + { be_const_key(_timers, -1), be_const_var(11) }, + { be_const_key(read_sensors, -1), be_const_func(l_read_sensors) }, + { be_const_key(exec_cmd, -1), be_const_closure(exec_cmd_closure) }, + { be_const_key(response_append, -1), be_const_func(l_respAppend) }, + { be_const_key(get_light, -1), be_const_closure(get_light_closure) }, }; static be_define_const_map( be_class_tasmota_map, - 74 + 79 ); BE_EXPORT_VARIABLE be_define_const_class( be_class_tasmota, - 10, + 12, NULL, Tasmota ); diff --git a/lib/libesp32/Berry/generate/be_fixed_be_class_webclient.h b/lib/libesp32/Berry/generate/be_fixed_be_class_webclient.h index 6a7044c15..15eaa21d7 100644 --- a/lib/libesp32/Berry/generate/be_fixed_be_class_webclient.h +++ b/lib/libesp32/Berry/generate/be_fixed_be_class_webclient.h @@ -1,26 +1,27 @@ #include "be_constobj.h" static be_define_const_map_slots(be_class_webclient_map) { - { be_const_key(url_encode, 3), be_const_func(wc_urlencode) }, - { be_const_key(POST, -1), be_const_func(wc_POST) }, - { be_const_key(dot_p, -1), be_const_var(0) }, - { be_const_key(begin, 5), be_const_func(wc_begin) }, - { be_const_key(set_useragent, 2), be_const_func(wc_set_useragent) }, - { be_const_key(set_auth, 12), be_const_func(wc_set_auth) }, { be_const_key(close, -1), be_const_func(wc_close) }, - { be_const_key(add_header, 9), be_const_func(wc_addheader) }, - { be_const_key(get_size, -1), be_const_func(wc_getsize) }, + { be_const_key(get_string, 5), be_const_func(wc_getstring) }, + { be_const_key(dot_w, 11), be_const_var(0) }, + { be_const_key(dot_p, 13), be_const_var(1) }, + { be_const_key(add_header, 10), be_const_func(wc_addheader) }, + { be_const_key(url_encode, -1), be_const_func(wc_urlencode) }, + { be_const_key(POST, -1), be_const_func(wc_POST) }, + { be_const_key(GET, 6), be_const_func(wc_GET) }, { be_const_key(deinit, -1), be_const_func(wc_deinit) }, + { be_const_key(get_size, -1), be_const_func(wc_getsize) }, { be_const_key(set_timeouts, -1), be_const_func(wc_set_timeouts) }, - { be_const_key(GET, 13), be_const_func(wc_GET) }, - { be_const_key(init, -1), be_const_func(wc_init) }, - { be_const_key(dot_w, -1), be_const_var(1) }, - { be_const_key(get_string, 11), be_const_func(wc_getstring) }, + { be_const_key(set_auth, -1), be_const_func(wc_set_auth) }, + { be_const_key(set_useragent, -1), be_const_func(wc_set_useragent) }, + { be_const_key(init, 0), be_const_func(wc_init) }, + { be_const_key(begin, -1), be_const_func(wc_begin) }, + { be_const_key(write_file, -1), be_const_func(wc_writefile) }, }; static be_define_const_map( be_class_webclient_map, - 15 + 16 ); BE_EXPORT_VARIABLE be_define_const_class( diff --git a/lib/libesp32/Berry/generate/be_fixed_string.h b/lib/libesp32/Berry/generate/be_fixed_string.h index eb1e5cf58..9710edd7f 100644 --- a/lib/libesp32/Berry/generate/be_fixed_string.h +++ b/lib/libesp32/Berry/generate/be_fixed_string.h @@ -1,20 +1,22 @@ #include "be_constobj.h" static be_define_const_map_slots(m_libstring_map) { - { be_const_key(tolower, -1), be_const_func(str_tolower) }, - { be_const_key(count, -1), be_const_func(str_count) }, - { be_const_key(hex, -1), be_const_func(str_i2hex) }, - { be_const_key(split, 5), be_const_func(str_split) }, + { be_const_key(char, -1), be_const_func(str_char) }, + { be_const_key(tr, -1), be_const_func(str_tr) }, + { be_const_key(count, 4), be_const_func(str_count) }, + { be_const_key(format, 7), be_const_func(str_format) }, + { be_const_key(escape, -1), be_const_func(str_escape) }, { be_const_key(byte, -1), be_const_func(str_byte) }, - { be_const_key(char, 6), be_const_func(str_char) }, - { be_const_key(toupper, 1), be_const_func(str_toupper) }, + { be_const_key(toupper, -1), be_const_func(str_toupper) }, + { be_const_key(hex, -1), be_const_func(str_i2hex) }, { be_const_key(find, -1), be_const_func(str_find) }, - { be_const_key(format, -1), be_const_func(str_format) }, + { be_const_key(split, 1), be_const_func(str_split) }, + { be_const_key(tolower, -1), be_const_func(str_tolower) }, }; static be_define_const_map( m_libstring_map, - 9 + 11 ); static be_define_const_module( diff --git a/lib/libesp32/Berry/generate/be_fixed_sys.h b/lib/libesp32/Berry/generate/be_fixed_sys.h index 12eff88ab..91403719c 100644 --- a/lib/libesp32/Berry/generate/be_fixed_sys.h +++ b/lib/libesp32/Berry/generate/be_fixed_sys.h @@ -1,2 +1,17 @@ #include "be_constobj.h" +static be_define_const_map_slots(m_libsys_map) { + { be_const_key(path, -1), be_const_func(m_path) }, +}; + +static be_define_const_map( + m_libsys_map, + 1 +); + +static be_define_const_module( + m_libsys, + "sys" +); + +BE_EXPORT_VARIABLE be_define_const_native_module(sys); diff --git a/lib/libesp32/Berry/generate/be_fixed_tasmota_path.h b/lib/libesp32/Berry/generate/be_fixed_tasmota_path.h index 4689021c4..90ae43054 100644 --- a/lib/libesp32/Berry/generate/be_fixed_tasmota_path.h +++ b/lib/libesp32/Berry/generate/be_fixed_tasmota_path.h @@ -1,13 +1,15 @@ #include "be_constobj.h" static be_define_const_map_slots(m_libpath_map) { - { be_const_key(exists, -1), be_const_func(m_path_exists) }, - { be_const_key(last_modified, 0), be_const_func(m_path_last_modified) }, + { be_const_key(listdir, -1), be_const_func(m_path_listdir) }, + { be_const_key(last_modified, 2), be_const_func(m_path_last_modified) }, + { be_const_key(exists, 3), be_const_func(m_path_exists) }, + { be_const_key(remove, -1), be_const_func(m_path_remove) }, }; static be_define_const_map( m_libpath_map, - 2 + 4 ); static be_define_const_module( diff --git a/lib/libesp32/Berry/src/be_baselib.c b/lib/libesp32/Berry/src/be_baselib.c index f80b321b1..6e92b47be 100644 --- a/lib/libesp32/Berry/src/be_baselib.c +++ b/lib/libesp32/Berry/src/be_baselib.c @@ -340,6 +340,17 @@ static int l_str(bvm *vm) be_return(vm); } +static int l_bool(bvm *vm) +{ + if (be_top(vm)) { + be_pushbool(vm, be_tobool(vm, 1)); + } else { + be_pushbool(vm, bfalse); + } + be_return(vm); +} + + static int l_size(bvm *vm) { if (be_top(vm) && be_isstring(vm, 1)) { @@ -462,9 +473,10 @@ void be_load_baselib(bvm *vm) } /* call must be added later to respect order of builtins */ -void be_load_baselib_call(bvm *vm) +void be_load_baselib_next(bvm *vm) { be_regfunc(vm, "call", l_call); + be_regfunc(vm, "bool", l_bool); } #else extern const bclass be_class_list; @@ -497,6 +509,7 @@ vartab m_builtin (scope: local) { range, class(be_class_range) bytes, class(be_class_bytes) call, func(l_call) + bool, func(l_bool) } @const_object_info_end */ #include "../generate/be_fixed_m_builtin.h" diff --git a/lib/libesp32/Berry/src/be_bytecode.c b/lib/libesp32/Berry/src/be_bytecode.c index 521317e63..9f9283fbe 100644 --- a/lib/libesp32/Berry/src/be_bytecode.c +++ b/lib/libesp32/Berry/src/be_bytecode.c @@ -23,7 +23,7 @@ #define MAGIC_NUMBER1 0xBE #define MAGIC_NUMBER2 0xCD #define MAGIC_NUMBER3 0xFE -#define BYTECODE_VERSION 2 +#define BYTECODE_VERSION 3 #define USE_64BIT_INT (BE_INTGER_TYPE == 2 \ || BE_INTGER_TYPE == 1 && LONG_MAX == 9223372036854775807L) @@ -425,7 +425,7 @@ static void load_class(bvm *vm, void *fp, bvalue *v, int version) be_incrtop(vm); if (load_proto(vm, fp, (bproto**)&var_toobj(value), -3, version)) { /* actual method */ - be_method_bind(vm, c, name, var_toobj(value)); + be_method_bind(vm, c, name, var_toobj(value), bfalse); } else { /* no proto, static member set to nil */ be_member_bind(vm, c, name, bfalse); diff --git a/lib/libesp32/Berry/src/be_class.c b/lib/libesp32/Berry/src/be_class.c index a6b94a1cf..a960d4b24 100644 --- a/lib/libesp32/Berry/src/be_class.c +++ b/lib/libesp32/Berry/src/be_class.c @@ -75,7 +75,7 @@ void be_member_bind(bvm *vm, bclass *c, bstring *name, bbool var) } } -void be_method_bind(bvm *vm, bclass *c, bstring *name, bproto *p) +void be_method_bind(bvm *vm, bclass *c, bstring *name, bproto *p, bbool is_static) { bclosure *cl; bvalue *attr; @@ -87,6 +87,9 @@ void be_method_bind(bvm *vm, bclass *c, bstring *name, bproto *p) cl = be_newclosure(vm, p->nupvals); cl->proto = p; var_setclosure(attr, cl); + if (is_static) { + func_setstatic(attr); + } } void be_prim_method_bind(bvm *vm, bclass *c, bstring *name, bntvfunc f) @@ -217,18 +220,18 @@ static binstance* newobject(bvm *vm, bclass *c) /* Instanciate new instance from stack with argc parameters */ /* Pushes the constructor on the stack to be executed if a construtor is found */ /* Returns true if a constructor is found */ -bbool be_class_newobj(bvm *vm, bclass *c, bvalue *reg, int argc, int mode) +bbool be_class_newobj(bvm *vm, bclass *c, int32_t pos, int argc, int mode) { bvalue init; - size_t pos = reg - vm->reg; binstance *obj = newobject(vm, c); /* create empty object hierarchy from class hierarchy */ - reg = vm->reg + pos - mode; /* the stack may have changed, mode=1 when class is instanciated from module #104 */ - var_setinstance(reg, obj); - var_setinstance(reg + mode, obj); /* copy to reg and reg+1 if mode==1 */ + // reg = vm->reg + pos - mode; /* the stack may have changed, mode=1 when class is instanciated from module #104 */ + var_setinstance(vm->reg + pos, obj); + var_setinstance(vm->reg + pos - mode, obj); /* copy to reg and reg+1 if mode==1 */ /* find constructor */ obj = instance_member(vm, obj, str_literal(vm, "init"), &init); if (obj && var_type(&init) != MT_VARIABLE) { /* copy argv */ + bvalue * reg; for (reg = vm->reg + pos + 1; argc > 0; --argc) { reg[argc] = reg[argc - 2]; } diff --git a/lib/libesp32/Berry/src/be_class.h b/lib/libesp32/Berry/src/be_class.h index 6a114f53b..59abbab30 100644 --- a/lib/libesp32/Berry/src/be_class.h +++ b/lib/libesp32/Berry/src/be_class.h @@ -53,12 +53,12 @@ bclass* be_newclass(bvm *vm, bstring *name, bclass *super); void be_class_compress(bvm *vm, bclass *c); int be_class_attribute(bvm *vm, bclass *c, bstring *attr); void be_member_bind(bvm *vm, bclass *c, bstring *name, bbool var); -void be_method_bind(bvm *vm, bclass *c, bstring *name, bproto *p); +void be_method_bind(bvm *vm, bclass *c, bstring *name, bproto *p, bbool is_static); void be_prim_method_bind(bvm *vm, bclass *c, bstring *name, bntvfunc f); void be_closure_method_bind(bvm *vm, bclass *c, bstring *name, bclosure *cl); int be_class_closure_count(bclass *c); void be_class_upvalue_init(bvm *vm, bclass *c); -bbool be_class_newobj(bvm *vm, bclass *c, bvalue *argv, int argc, int mode); +bbool be_class_newobj(bvm *vm, bclass *c, int32_t pos, int argc, int mode); int be_instance_member_simple(bvm *vm, binstance *obj, bstring *name, bvalue *dst); int be_instance_member(bvm *vm, binstance *obj, bstring *name, bvalue *dst); int be_class_member(bvm *vm, bclass *obj, bstring *name, bvalue *dst); diff --git a/lib/libesp32/Berry/src/be_code.c b/lib/libesp32/Berry/src/be_code.c index b0feff4e1..40e067265 100644 --- a/lib/libesp32/Berry/src/be_code.c +++ b/lib/libesp32/Berry/src/be_code.c @@ -335,12 +335,15 @@ static void free_suffix(bfuncinfo *finfo, bexpdesc *e) } } -static int suffix_destreg(bfuncinfo *finfo, bexpdesc *e1, int dst) +static int suffix_destreg(bfuncinfo *finfo, bexpdesc *e1, int dst, bbool no_reg_reuse) { int cand_dst = dst; /* candidate for new dst */ int nlocal = be_list_count(finfo->local); int reg1 = (e1->v.ss.tt == ETREG) ? e1->v.ss.obj : -1; /* check if obj is ETREG or -1 */ int reg2 = (!isK(e1->v.ss.idx) && e1->v.ss.idx >= nlocal) ? e1->v.ss.idx : -1; /* check if idx is ETREG or -1 */ + if (no_reg_reuse) { /* if no_reg_reuse flag, then don't reuse any register, this is useful for compound assignments */ + reg1 = reg2 = -1; + } if (reg1 >= 0 && reg2 >= 0) { /* both are ETREG, we keep the lowest and discard the other */ @@ -364,9 +367,9 @@ static int suffix_destreg(bfuncinfo *finfo, bexpdesc *e1, int dst) return dst; } -static int code_suffix(bfuncinfo *finfo, bopcode op, bexpdesc *e, int dst) +static int code_suffix(bfuncinfo *finfo, bopcode op, bexpdesc *e, int dst, bbool no_reg_reuse) { - dst = suffix_destreg(finfo, e, dst); + dst = suffix_destreg(finfo, e, dst, no_reg_reuse); if (dst > finfo->freereg) { dst = finfo->freereg; } @@ -400,6 +403,7 @@ static bbool constint(bfuncinfo *finfo, bint i) /* At exit, If dst is `freereg`, the register is allocated */ static int var2reg(bfuncinfo *finfo, bexpdesc *e, int dst) { + bbool no_reg_reuse = (dst >= 0); /* if dst reg is explicitly specified, do not optimize register allocation */ if (dst < 0) { /* if unspecified, allocate a new register if needed */ dst = finfo->freereg; } @@ -434,10 +438,10 @@ static int var2reg(bfuncinfo *finfo, bexpdesc *e, int dst) codeABx(finfo, OP_GETUPV, dst, e->v.idx); break; case ETMEMBER: - dst = code_suffix(finfo, OP_GETMBR, e, dst); + dst = code_suffix(finfo, OP_GETMBR, e, dst, no_reg_reuse); break; case ETINDEX: - dst = code_suffix(finfo, OP_GETIDX, e, dst); + dst = code_suffix(finfo, OP_GETIDX, e, dst, no_reg_reuse); break; case ETLOCAL: case ETREG: case ETCONST: return e->v.idx; @@ -479,6 +483,7 @@ static int exp2reg(bfuncinfo *finfo, bexpdesc *e, int dst) /* Returns the destination register, guaranteed to be ETREG */ static int codedestreg(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2, int dst) { + if (dst < 0) { dst = finfo->freereg; } int cand_dst = dst; int con1 = e1->type == ETREG, con2 = e2->type == ETREG; @@ -506,7 +511,6 @@ static int codedestreg(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2, int dst) /* On exit, e1 is guaranteed to be ETREG, which may have been allocated */ static void binaryexp(bfuncinfo *finfo, bopcode op, bexpdesc *e1, bexpdesc *e2, int dst) { - if (dst < 0) { dst = finfo->freereg; } int src1 = exp2reg(finfo, e1, dst); /* potentially force the target for src1 reg */ int src2 = exp2anyreg(finfo, e2); dst = codedestreg(finfo, e1, e2, dst); @@ -561,7 +565,10 @@ static void unaryexp(bfuncinfo *finfo, bopcode op, bexpdesc *e) { int src = exp2anyreg(finfo, e); int dst = e->type == ETREG ? src : be_code_allocregs(finfo, 1); - codeABC(finfo, op, dst, src, 0); + if (!(op == OP_MOVE && src == dst)) { + /* skip if MOVE from same src / dst */ + codeABC(finfo, op, dst, src, 0); + } e->type = ETREG; e->v.idx = dst; } @@ -569,7 +576,7 @@ static void unaryexp(bfuncinfo *finfo, bopcode op, bexpdesc *e) /* Apply not to conditional expression */ /* If literal compute the value */ /* Or invert t/f subexpressions */ -static void code_not(bexpdesc *e) +static void code_not(bfuncinfo *finfo, bexpdesc *e) { switch (e->type) { case ETINT: e->v.i = e->v.i == 0; break; @@ -578,6 +585,7 @@ static void code_not(bexpdesc *e) case ETBOOL: e->v.i = !e->v.i; break; case ETSTRING: e->v.i = 0; break; default: { + unaryexp(finfo, OP_MOVE, e); int temp = e->t; e->t = e->f; e->f = temp; @@ -620,7 +628,7 @@ int be_code_unop(bfuncinfo *finfo, int op, bexpdesc *e) { switch (op) { case OptNot: - code_not(e); break; + code_not(finfo, e); break; case OptFlip: /* do nothing */ return code_flip(finfo, e); case OptSub: @@ -719,7 +727,7 @@ int be_code_getmethod(bfuncinfo *finfo, bexpdesc *e) { int dst = finfo->freereg; be_assert(e->type == ETMEMBER); - dst = code_suffix(finfo, OP_GETMET, e, dst); + dst = code_suffix(finfo, OP_GETMET, e, dst, bfalse); /* method [object] args */ be_code_allocregs(finfo, dst == finfo->freereg ? 2 : 1); return dst; diff --git a/lib/libesp32/Berry/src/be_constobj.h b/lib/libesp32/Berry/src/be_constobj.h index a565d83f9..87ab6eecf 100644 --- a/lib/libesp32/Berry/src/be_constobj.h +++ b/lib/libesp32/Berry/src/be_constobj.h @@ -38,6 +38,11 @@ extern "C" { .type = BE_FUNCTION \ } +#define be_const_static_func(_func) { \ + .v.nf = (_func), \ + .type = BE_FUNCTION | BE_FUNC_STATIC \ +} + #define be_const_nil() { \ .v.i = 0, \ .type = BE_NIL \ @@ -88,6 +93,11 @@ extern "C" { .type = BE_CLOSURE \ } +#define be_const_static_closure(_closure) { \ + .v.c = &(_closure), \ + .type = BE_CLOSURE | BE_FUNC_STATIC \ +} + #define be_const_module(_module) { \ .v.c = &(_module), \ .type = BE_MODULE \ @@ -217,6 +227,16 @@ const bntvmodule be_native_module(_module) = { \ .data = _items \ } +#define be_nested_str_literal(_str) \ + { \ + { .s=(be_nested_const_str(_str, 0, sizeof(_str)-1 )) \ + }, \ + BE_STRING \ + } + +#define be_str_literal(_str) \ + be_nested_const_str(_str, 0, sizeof(_str)-1 ) + #define be_nested_string(_str, _hash, _len) \ { \ { .s=(be_nested_const_str(_str, _hash, _len )) \ @@ -244,6 +264,11 @@ const bntvmodule be_native_module(_module) = { \ BE_FUNCTION \ } +#define be_const_static_func(_func) { \ + bvaldata(_func), \ + BE_FUNCTION | BE_FUNC_STATIC \ +} + #define be_const_nil() { \ bvaldata(0), \ BE_NIL \ @@ -294,6 +319,11 @@ const bntvmodule be_native_module(_module) = { \ BE_CLOSURE \ } +#define be_const_static_closure(_closure) { \ + bvaldata(&(_closure)), \ + BE_CLOSURE | BE_FUNC_STATIC \ +} + #define be_const_module(_module) { \ bvaldata(&(_module)), \ BE_MODULE \ diff --git a/lib/libesp32/Berry/src/be_debuglib.c b/lib/libesp32/Berry/src/be_debuglib.c index 13c15f50e..153af55fb 100644 --- a/lib/libesp32/Berry/src/be_debuglib.c +++ b/lib/libesp32/Berry/src/be_debuglib.c @@ -169,6 +169,7 @@ static int m_counters(bvm *vm) map_insert(vm, "set", vm->counter_set); map_insert(vm, "try", vm->counter_try); map_insert(vm, "raise", vm->counter_exc); + map_insert(vm, "objects", vm->counter_gc_kept); be_pop(vm, 1); be_return(vm); } diff --git a/lib/libesp32/Berry/src/be_exec.c b/lib/libesp32/Berry/src/be_exec.c index 8ed0bc8f1..7b741e4ff 100644 --- a/lib/libesp32/Berry/src/be_exec.c +++ b/lib/libesp32/Berry/src/be_exec.c @@ -74,6 +74,9 @@ struct filebuf { void be_throw(bvm *vm, int errorcode) { +#if BE_USE_PERF_COUNTERS + vm->counter_exc++; +#endif if (vm->errjmp) { vm->errjmp->status = errorcode; exec_throw(vm->errjmp); diff --git a/lib/libesp32/Berry/src/be_gc.c b/lib/libesp32/Berry/src/be_gc.c index 0475de7b3..b3cf7ab98 100644 --- a/lib/libesp32/Berry/src/be_gc.c +++ b/lib/libesp32/Berry/src/be_gc.c @@ -348,7 +348,7 @@ static void free_instance(bvm *vm, bgcobject *obj) static void free_object(bvm *vm, bgcobject *obj) { - switch (obj->type) { + switch (var_type(obj)) { case BE_STRING: free_lstring(vm, obj); break; /* long string */ case BE_CLASS: be_free(vm, obj, sizeof(bclass)); break; case BE_INSTANCE: free_instance(vm, obj); break; @@ -497,6 +497,9 @@ static void delete_white(bvm *vm) prev->next = next; } free_object(vm, node); +#if BE_USE_PERF_COUNTERS + vm->counter_gc_freed++; +#endif } else { gc_setwhite(node); prev = node; @@ -537,6 +540,10 @@ void be_gc_collect(bvm *vm) if (vm->gc.status & GC_HALT) { return; /* the GC cannot run for some reason */ } +#if BE_USE_PERF_COUNTERS + vm->counter_gc_kept = 0; + vm->counter_gc_freed = 0; +#endif #if BE_USE_OBSERVABILITY_HOOK if (vm->obshook != NULL) (*vm->obshook)(vm, BE_OBS_GC_START, vm->gc.usage); @@ -559,6 +566,6 @@ void be_gc_collect(bvm *vm) vm->gc.threshold = next_threshold(vm->gc); #if BE_USE_OBSERVABILITY_HOOK if (vm->obshook != NULL) - (*vm->obshook)(vm, BE_OBS_GC_END, vm->gc.usage); + (*vm->obshook)(vm, BE_OBS_GC_END, vm->gc.usage, vm->counter_gc_kept, vm->counter_gc_freed); #endif } diff --git a/lib/libesp32/Berry/src/be_gc.h b/lib/libesp32/Berry/src/be_gc.h index b1b204c13..0e0ce9e82 100644 --- a/lib/libesp32/Berry/src/be_gc.h +++ b/lib/libesp32/Berry/src/be_gc.h @@ -10,8 +10,6 @@ #include "be_object.h" -#define BE_GCOBJECT BE_STRING - #define gc_object(o) cast(bgcobject*, o) #define gc_cast(o, t, T) ((o) && (o)->type == (t) ? (T*)(o) : NULL) #define cast_proto(o) gc_cast(o, BE_PROTO, bproto) @@ -37,7 +35,11 @@ if (!gc_isconst(o)) { \ #define gc_setwhite(o) gc_setmark((o), GC_WHITE) #define gc_setgray(o) gc_setmark((o), GC_GRAY) -#define gc_setdark(o) gc_setmark((o), GC_DARK) +#if BE_USE_PERF_COUNTERS + #define gc_setdark(o) { vm->counter_gc_kept++; gc_setmark((o), GC_DARK); } +#else + #define gc_setdark(o) gc_setmark((o), GC_DARK) +#endif #define gc_isfixed(o) (((o)->marked & GC_FIXED) != 0) #define gc_setfixed(o) ((o)->marked |= GC_FIXED) #define gc_clearfixed(o) ((o)->marked &= ~GC_FIXED) diff --git a/lib/libesp32/Berry/src/be_libs.c b/lib/libesp32/Berry/src/be_libs.c index 0c55717f3..a9a2f0e39 100644 --- a/lib/libesp32/Berry/src/be_libs.c +++ b/lib/libesp32/Berry/src/be_libs.c @@ -8,7 +8,7 @@ #include "be_libs.h" extern void be_load_baselib(bvm *vm); -extern void be_load_baselib_call(bvm *vm); +extern void be_load_baselib_next(bvm *vm); extern void be_load_listlib(bvm *vm); extern void be_load_maplib(bvm *vm); extern void be_load_rangelib(bvm *vm); @@ -24,6 +24,6 @@ void be_loadlibs(bvm *vm) be_load_rangelib(vm); be_load_filelib(vm); be_load_byteslib(vm); - be_load_baselib_call(vm); + be_load_baselib_next(vm); #endif } diff --git a/lib/libesp32/Berry/src/be_listlib.c b/lib/libesp32/Berry/src/be_listlib.c index cc8c8d8d4..b584aef90 100644 --- a/lib/libesp32/Berry/src/be_listlib.c +++ b/lib/libesp32/Berry/src/be_listlib.c @@ -333,18 +333,27 @@ static int m_merge(bvm *vm) be_return(vm); /* return self */ } -static void connect(bvm *vm, bvalue *begin, bvalue *end) +static void connect(bvm *vm, bvalue *begin, bvalue *end, const char * delimiter, bbool first_element) { size_t l0 = be_strlen(vm, -1), len = l0; + size_t d = delimiter ? strlen(delimiter) : 0; /* len of delimiter */ char *buf, *p; bvalue *it; for (it = begin; it < end; ++it) { - len += str_len(var_tostr(it)); + len += str_len(var_tostr(it)) + d; + } + if (first_element) { + len -= d; /* remove size for first delimiter non needed */ } buf = be_pushbuffer(vm, len); memcpy(buf, be_tostring(vm, -2), l0); p = buf + l0; for (it = begin; it < end; ++it) { + if ((it != begin || !first_element) && delimiter) { + /* add delimiter */ + memcpy(p, delimiter, d); + p += d; + } bstring *s = var_tostr(it); size_t l = str_len(s); memcpy(p, str(s), l); @@ -355,15 +364,24 @@ static void connect(bvm *vm, bvalue *begin, bvalue *end) be_pop(vm, 2); } -static void list_concat(bvm *vm, blist *list) +static void list_concat(bvm *vm, blist *list, const char * delimiter) { bvalue *it, *begin = be_list_data(list); bvalue *end = be_list_end(list); be_pushstring(vm, ""); /* push a empty string */ + bbool first_element = btrue; for (it = begin; it < end;) { for (; it < end && var_isstr(it); ++it); - connect(vm, begin, it); /* connect string list */ + if (begin < it) { + connect(vm, begin, it, delimiter, first_element); /* connect string list */ + first_element = bfalse; + } if (it < end) { + if (delimiter && !first_element) { + be_pushstring(vm, delimiter); + be_strconcat(vm, -2); + be_pop(vm, 1); + } /* connect other value */ var_setval(vm->top, it); be_incrtop(vm); @@ -371,6 +389,7 @@ static void list_concat(bvm *vm, blist *list) be_strconcat(vm, -2); be_pop(vm, 1); begin = ++it; + first_element = bfalse; } } } @@ -378,10 +397,15 @@ static void list_concat(bvm *vm, blist *list) static int m_concat(bvm *vm) { bvalue *value; + int top = be_top(vm); be_getmember(vm, 1, ".p"); list_check_data(vm, 1); value = be_indexof(vm, -1); - list_concat(vm, var_toobj(value)); + const char * delimiter = NULL; + if (top >= 2) { + delimiter = be_tostring(vm, 2); + } + list_concat(vm, var_toobj(value), delimiter); be_return(vm); } @@ -432,6 +456,19 @@ static int list_equal(bvm *vm, bbool iseq) be_return(vm); } +static int m_keys(bvm *vm) +{ + be_getmember(vm, 1, ".p"); + list_check_data(vm, 1); + int size = be_data_size(vm, -1); + be_getbuiltin(vm, "range"); + be_pushint(vm, 0); + be_pushint(vm, size - 1); + be_call(vm, 2); + be_pop(vm, 2); + be_return(vm); +} + static int m_equal(bvm *vm) { return list_equal(vm, btrue); @@ -463,6 +500,7 @@ void be_load_listlib(bvm *vm) { "concat", m_concat }, { "reverse", m_reverse }, { "copy", m_copy }, + { "keys", m_keys }, { "..", m_connect }, { "+", m_merge }, { "==", m_equal }, @@ -491,6 +529,7 @@ class be_class_list (scope: global, name: list) { concat, func(m_concat) reverse, func(m_reverse) copy, func(m_copy) + keys, func(m_keys) .., func(m_connect) +, func(m_merge) ==, func(m_equal) diff --git a/lib/libesp32/Berry/src/be_map.c b/lib/libesp32/Berry/src/be_map.c index a11614680..004406f46 100644 --- a/lib/libesp32/Berry/src/be_map.c +++ b/lib/libesp32/Berry/src/be_map.c @@ -346,5 +346,7 @@ bmapnode* be_map_val2node(bvalue *value) void be_map_release(bvm *vm, bmap *map) { (void)vm; - resize(vm, map, map->count ? map->count : 1); + if (!gc_isconst(map)) { + resize(vm, map, map->count ? map->count : 1); + } } diff --git a/lib/libesp32/Berry/src/be_object.h b/lib/libesp32/Berry/src/be_object.h index f5b878531..e19d766d6 100644 --- a/lib/libesp32/Berry/src/be_object.h +++ b/lib/libesp32/Berry/src/be_object.h @@ -11,25 +11,34 @@ #include "berry.h" /* basic types, do not change value */ -#define BE_NONE (-1) /* unknown type */ -#define BE_COMPTR (-2) /* common pointer */ -#define BE_INDEX (-3) /* index for instance variable, previously BE_INT */ #define BE_NIL 0 #define BE_INT 1 #define BE_REAL 2 #define BE_BOOL 3 -#define BE_FUNCTION 4 -#define BE_STRING 5 /* from this type can be gced, see BE_GCOBJECT */ -#define BE_CLASS 6 -#define BE_INSTANCE 7 -#define BE_PROTO 8 -#define BE_LIST 9 -#define BE_MAP 10 -#define BE_MODULE 11 -#define BE_COMOBJ 12 /* common object */ +#define BE_NONE 4 /* unknown type */ +#define BE_COMPTR 5 /* common pointer */ +#define BE_INDEX 6 /* index for instance variable, previously BE_INT */ +#define BE_FUNCTION 7 + +#define BE_GCOBJECT 16 /* from this type can be gced */ + +#define BE_STRING 16 +#define BE_CLASS 17 +#define BE_INSTANCE 18 +#define BE_PROTO 19 +#define BE_LIST 20 +#define BE_MAP 21 +#define BE_MODULE 22 +#define BE_COMOBJ 23 /* common object */ + #define BE_NTVFUNC ((0 << 5) | BE_FUNCTION) #define BE_CLOSURE ((1 << 5) | BE_FUNCTION) #define BE_NTVCLOS ((2 << 5) | BE_FUNCTION) +#define BE_FUNC_STATIC (1 << 7) + +#define func_isstatic(o) (((o)->type & BE_FUNC_STATIC) != 0) +#define func_setstatic(o) ((o)->type |= BE_FUNC_STATIC) +#define func_clearstatic(o) ((o)->type &= ~BE_FUNC_STATIC) #define array_count(a) (sizeof(a) / sizeof((a)[0])) @@ -187,7 +196,7 @@ typedef const char* (*breader)(void*, size_t*); #define cast_bool(_v) cast(bbool, _v) #define basetype(_t) ((_t) & 0x1F) -#define var_type(_v) ((_v)->type) +#define var_type(_v) ((_v)->type & 0x7F) #define var_basetype(_v) basetype((_v)->type) #define var_istype(_v, _t) (var_type(_v) == _t) #define var_settype(_v, _t) ((_v)->type = _t) diff --git a/lib/libesp32/Berry/src/be_parser.c b/lib/libesp32/Berry/src/be_parser.c index 664f24b92..d2f2d7af5 100644 --- a/lib/libesp32/Berry/src/be_parser.c +++ b/lib/libesp32/Berry/src/be_parser.c @@ -1422,12 +1422,28 @@ static void class_static_assignment_expr(bparser *parser, bexpdesc *e, bstring * } } +static void classdef_stmt(bparser *parser, bclass *c, bbool is_static) +{ + bexpdesc e; + bstring *name; + bproto *proto; + /* 'def' ID '(' varlist ')' block 'end' */ + scan_next_token(parser); /* skip 'def' */ + name = func_name(parser, &e, 1); + check_class_attr(parser, c, name); + proto = funcbody(parser, name, is_static ? 0 : FUNC_METHOD); + be_method_bind(parser->vm, c, proto->name, proto, is_static); + be_stackpop(parser->vm, 1); +} + static void classstatic_stmt(bparser *parser, bclass *c, bexpdesc *e) { bstring *name; /* 'static' ID ['=' expr] {',' ID ['=' expr] } */ scan_next_token(parser); /* skip 'static' */ - if (match_id(parser, name) != NULL) { + if (next_type(parser) == KeyDef) { /* 'static' 'def' ... */ + classdef_stmt(parser, c, btrue); + } else if (match_id(parser, name) != NULL) { check_class_attr(parser, c, name); be_member_bind(parser->vm, c, name, bfalse); class_static_assignment_expr(parser, e, name); @@ -1446,20 +1462,6 @@ static void classstatic_stmt(bparser *parser, bclass *c, bexpdesc *e) } } -static void classdef_stmt(bparser *parser, bclass *c) -{ - bexpdesc e; - bstring *name; - bproto *proto; - /* 'def' ID '(' varlist ')' block 'end' */ - scan_next_token(parser); /* skip 'def' */ - name = func_name(parser, &e, 1); - check_class_attr(parser, c, name); - proto = funcbody(parser, name, FUNC_METHOD); - be_method_bind(parser->vm, c, proto->name, proto); - be_stackpop(parser->vm, 1); -} - static void class_inherit(bparser *parser, bexpdesc *e) { if (next_type(parser) == OptColon) { /* ':' */ @@ -1479,7 +1481,7 @@ static void class_block(bparser *parser, bclass *c, bexpdesc *e) switch (next_type(parser)) { case KeyVar: classvar_stmt(parser, c); break; case KeyStatic: classstatic_stmt(parser, c, e); break; - case KeyDef: classdef_stmt(parser, c); break; + case KeyDef: classdef_stmt(parser, c, bfalse); break; case OptSemic: scan_next_token(parser); break; default: push_error(parser, "unexpected token '%s'", token2str(parser)); diff --git a/lib/libesp32/Berry/src/be_solidifylib.c b/lib/libesp32/Berry/src/be_solidifylib.c index d72e3aff5..402db4547 100644 --- a/lib/libesp32/Berry/src/be_solidifylib.c +++ b/lib/libesp32/Berry/src/be_solidifylib.c @@ -25,7 +25,7 @@ extern const bclass be_class_map; #include #ifndef INST_BUF_SIZE -#define INST_BUF_SIZE 96 +#define INST_BUF_SIZE 288 #endif #define logbuf(...) snprintf(__lbuf, sizeof(__lbuf), __VA_ARGS__) @@ -41,6 +41,9 @@ static void m_solidify_bvalue(bvm *vm, bvalue * value, const char *classname, co static void m_solidify_map(bvm *vm, bmap * map, const char *class_name) { + // compact first + be_map_release(vm, map); + logfmt(" be_nested_map(%i,\n", map->count); logfmt(" ( (struct bmapnode*) &(const bmapnode[]) {\n"); @@ -115,17 +118,23 @@ static void m_solidify_bvalue(bvm *vm, bvalue * value, const char *classname, co break; case BE_STRING: { - logfmt("be_nested_string(\""); - be_writestring(str(var_tostr(value))); size_t len = strlen(str(var_tostr(value))); if (len >= 255) { be_raise(vm, "internal_error", "Strings greater than 255 chars not supported yet"); } - logfmt("\", %i, %zu)", be_strhash(var_tostr(value)), len >= 255 ? 255 : len); + be_pushstring(vm, str(var_tostr(value))); + be_toescape(vm, -1, 'u'); + logfmt("be_nested_str_literal(%s)", be_tostring(vm, -1)); + // logfmt("be_nested_string(%s", be_tostring(vm, -1)); + // be_pop(vm, 1); + // logfmt(", %i, %zu)", be_strhash(var_tostr(value)), len >= 255 ? 255 : len); } break; case BE_CLOSURE: - logfmt("be_const_closure(%s_closure)", str(((bclosure*) var_toobj(value))->proto->name)); + logfmt("be_const_%sclosure(%s%s%s_closure)", + func_isstatic(value) ? "static_" : "", + classname ? classname : "", classname ? "_" : "", + str(((bclosure*) var_toobj(value))->proto->name)); break; case BE_CLASS: logfmt("be_const_class(be_class_%s)", str(((bclass*) var_toobj(value))->name)); @@ -134,7 +143,9 @@ static void m_solidify_bvalue(bvm *vm, bvalue * value, const char *classname, co logfmt("be_const_comptr(&be_ntv_%s_%s)", classname ? classname : "unknown", key ? key : "unknown"); break; case BE_NTVFUNC: - logfmt("be_const_func(be_ntv_%s_%s)", classname ? classname : "unknown", key ? key : "unknown"); + logfmt("be_const_%sfunc(be_ntv_%s_%s)", + func_isstatic(value) ? "static_" : "", + classname ? classname : "unknown", key ? key : "unknown"); break; case BE_INSTANCE: { @@ -194,7 +205,7 @@ static void m_solidify_proto_inner_class(bvm *vm, bproto *pr, int builtins) static void m_solidify_proto(bvm *vm, bproto *pr, const char * func_name, int builtins, int indent) { // const char * func_name = str(pr->name); - const char * func_source = str(pr->source); + // const char * func_source = str(pr->source); logfmt("%*sbe_nested_proto(\n", indent, ""); indent += 2; @@ -269,7 +280,7 @@ static void m_solidify_proto(bvm *vm, bproto *pr, const char * func_name, int bu } -static void m_solidify_closure(bvm *vm, bclosure *cl, int builtins) +static void m_solidify_closure(bvm *vm, bclosure *cl, const char * classname, int builtins) { bproto *pr = cl->proto; const char * func_name = str(pr->name); @@ -287,7 +298,9 @@ static void m_solidify_closure(bvm *vm, bclosure *cl, int builtins) logfmt("** Solidified function: %s\n", func_name); logfmt("********************************************************************/\n"); - logfmt("be_local_closure(%s, /* name */\n", func_name); + logfmt("be_local_closure(%s%s%s, /* name */\n", + classname ? classname : "", classname ? "_" : "", + func_name); m_solidify_proto(vm, pr, func_name, builtins, indent); logfmt("\n"); @@ -308,7 +321,7 @@ static void m_solidify_subclass(bvm *vm, bclass *cl, int builtins) while ((node = be_map_next(cl->members, &iter)) != NULL) { if (var_isstr(&node->key) && var_isclosure(&node->value)) { bclosure *f = var_toobj(&node->value); - m_solidify_closure(vm, f, builtins); + m_solidify_closure(vm, f, class_name, builtins); } } } @@ -338,7 +351,7 @@ static void m_solidify_subclass(bvm *vm, bclass *cl, int builtins) logfmt(" NULL,\n"); } - logfmt(" (be_nested_const_str(\"%s\", %i, %i))\n", class_name, be_strhash(cl->name), str_len(cl->name)); + logfmt(" be_str_literal(\"%s\")\n", class_name); logfmt(");\n"); } @@ -362,14 +375,18 @@ static void m_solidify_module(bvm *vm, bmodule *ml, int builtins) const char * module_name = be_module_name(ml); if (!module_name) { module_name = ""; } - /* iterate on members to dump closures */ + /* iterate on members to dump closures and classes */ if (ml->table) { bmapnode *node; bmapiter iter = be_map_iter(); while ((node = be_map_next(ml->table, &iter)) != NULL) { if (var_isstr(&node->key) && var_isclosure(&node->value)) { bclosure *f = var_toobj(&node->value); - m_solidify_closure(vm, f, builtins); + m_solidify_closure(vm, f, NULL, builtins); + } + if (var_isstr(&node->key) && var_isclass(&node->value)) { + bclass *cl = var_toobj(&node->value); + m_solidify_subclass(vm, cl, builtins); } } } @@ -403,7 +420,7 @@ static int m_dump(bvm *vm) if (be_top(vm) >= 1) { bvalue *v = be_indexof(vm, 1); if (var_isclosure(v)) { - m_solidify_closure(vm, var_toobj(v), be_builtin_count(vm)); + m_solidify_closure(vm, var_toobj(v), NULL, be_builtin_count(vm)); } else if (var_isclass(v)) { m_solidify_class(vm, var_toobj(v), be_builtin_count(vm)); } else if (var_ismodule(v)) { diff --git a/lib/libesp32/Berry/src/be_string.c b/lib/libesp32/Berry/src/be_string.c index b6890a937..798437420 100644 --- a/lib/libesp32/Berry/src/be_string.c +++ b/lib/libesp32/Berry/src/be_string.c @@ -57,12 +57,18 @@ int be_eqstr(bstring *s1, bstring *s2) } /* const short strings */ if (gc_isconst(s1) || gc_isconst(s2)) { /* one of the two string is short const */ - if (cast(bcstring*, s1)->hash && cast(bcstring*, s2)->hash) { - return 0; /* if they both have a hash, then we know they are different */ + uint32_t hash1 = cast(bcstring*, s1)->hash; + uint32_t hash2 = cast(bcstring*, s2)->hash; + if (hash1 && hash2 && hash1 != hash2) { + return 0; /* if hash differ, since we know both are non-null */ } + /* if hash are equals, there might be a chance that they are different */ + /* This can happen with solidified code that a same string is present more than once */ + /* so just considering that two strings with the same hash must be same pointer, this is no more true */ return !strcmp(str(s1), str(s2)); } + /* if both strings are in-memory, they can't be equal without having the same pointer */ return 0; } diff --git a/lib/libesp32/Berry/src/be_strlib.c b/lib/libesp32/Berry/src/be_strlib.c index 3a079fa22..e82ec3cf2 100644 --- a/lib/libesp32/Berry/src/be_strlib.c +++ b/lib/libesp32/Berry/src/be_strlib.c @@ -788,6 +788,53 @@ static int str_toupper(bvm *vm) { return str_touplower(vm, btrue); } +static int str_tr(bvm *vm) +{ + if (be_top(vm) == 3 && be_isstring(vm, 1) && be_isstring(vm, 2) && be_isstring(vm, 3)) { + const char *p, *s = be_tostring(vm, 1); + const char *t1 = be_tostring(vm, 2); + const char *t2 = be_tostring(vm, 3); + if (strlen(t2) < strlen(t1)) { + be_raise(vm, "value_error", "invalid translation pattern"); + } + size_t len = (size_t)be_strlen(vm, 1); + char *buf, *q; + buf = be_pushbuffer(vm, len); + /* convert each char */ + for (p = s, q = buf; *p != '\0'; ++p, ++q) { + const char *p1, *p2; + *q = *p; /* default to no change */ + for (p1=t1, p2=t2; *p1 != '\0'; ++p1, ++p2) { + if (*p == *p1) { + *q = *p2; + break; + } + } + } + be_pushnstring(vm, buf, len); /* make escape string from buffer */ + be_remove(vm, 2); /* remove buffer */ + be_return(vm); + } + be_return_nil(vm); +} + +static int str_escape(bvm *vm) +{ + int top = be_top(vm); + if (top >= 1 && be_isstring(vm, 1)) { + int quote = 'u'; + if (top >= 2 && be_isbool(vm, 2)) { + if (be_tobool(vm, 1)) { + quote = 'x'; + } + } + be_tostring(vm, 1); + be_toescape(vm, 1, quote); + be_pushvalue(vm, 1); + be_return(vm); + } + be_return_nil(vm); +} #if !BE_USE_PRECOMPILED_OBJECT be_native_module_attr_table(string) { @@ -800,6 +847,8 @@ be_native_module_attr_table(string) { be_native_module_function("char", str_char), be_native_module_function("tolower", str_tolower), be_native_module_function("toupper", str_toupper), + be_native_module_function("tr", str_tr), + be_native_module_function("escape", str_escape), }; be_define_native_module(string, NULL); @@ -815,6 +864,8 @@ module string (scope: global, depend: BE_USE_STRING_MODULE) { char, func(str_char) tolower, func(str_tolower) toupper, func(str_toupper) + tr, func(str_tr) + escape, func(str_escape) } @const_object_info_end */ #include "../generate/be_fixed_string.h" diff --git a/lib/libesp32/Berry/src/be_vm.c b/lib/libesp32/Berry/src/be_vm.c index 83d1d5cfb..f00cc128a 100644 --- a/lib/libesp32/Berry/src/be_vm.c +++ b/lib/libesp32/Berry/src/be_vm.c @@ -142,7 +142,7 @@ _vm->cf->status = PRIM_FUNC; \ } -static void prep_closure(bvm *vm, bvalue *reg, int argc, int mode); +static void prep_closure(bvm *vm, int32_t pos, int argc, int mode); static void attribute_error(bvm *vm, const char *t, bvalue *b, bvalue *c) { @@ -453,8 +453,8 @@ BERRY_API bvm* be_vm_new(void) be_stack_init(vm, &vm->refstack, sizeof(binstance*)); be_stack_init(vm, &vm->exceptstack, sizeof(struct bexecptframe)); be_stack_init(vm, &vm->tracestack, sizeof(bcallsnapshot)); - vm->stack = be_malloc(vm, sizeof(bvalue) * BE_STACK_FREE_MIN); - vm->stacktop = vm->stack + BE_STACK_FREE_MIN; + vm->stack = be_malloc(vm, sizeof(bvalue) * BE_STACK_START); + vm->stacktop = vm->stack + BE_STACK_START; vm->reg = vm->stack; vm->top = vm->reg; be_globalvar_init(vm); @@ -472,6 +472,8 @@ BERRY_API bvm* be_vm_new(void) vm->counter_set = 0; vm->counter_try = 0; vm->counter_exc = 0; + vm->counter_gc_kept = 0; + vm->counter_gc_freed = 0; #endif return vm; } @@ -852,16 +854,29 @@ newframe: /* a new call frame */ bvalue *a = RA(); *a = a_temp; if (basetype(type) == BE_FUNCTION) { - /* check if the object is a superinstance, if so get the lowest possible subclass */ - while (obj->sub) { - obj = obj->sub; + if (func_isstatic(a)) { + /* static method, don't bother with the instance */ + a[1] = a_temp; + var_settype(a, NOT_METHOD); + } else { + /* this is a real method (i.e. non-static) */ + /* check if the object is a superinstance, if so get the lowest possible subclass */ + while (obj->sub) { + obj = obj->sub; + } + var_setinstance(&a[1], obj); /* replace superinstance by lowest subinstance */ } - var_setinstance(&a[1], obj); /* replace superinstance by lowest subinstance */ } else { vm_error(vm, "attribute_error", "class '%s' has no method '%s'", str(be_instance_name(obj)), str(var_tostr(c))); } + } else if (var_isclass(b) && var_isstr(c)) { + class_attribute(vm, b, c, &a_temp); + reg = vm->reg; + bvalue *a = RA(); + a[1] = a_temp; + var_settype(a, NOT_METHOD); } else if (var_ismodule(b) && var_isstr(c)) { module_attribute(vm, b, c, &a_temp); reg = vm->reg; @@ -891,9 +906,14 @@ newframe: /* a new call frame */ dispatch(); } if (var_isclass(a) && var_isstr(b)) { + /* if value is a function, we mark it as a static to distinguish from methods */ bclass *obj = var_toobj(a); bstring *attr = var_tostr(b); - if (!be_class_setmember(vm, obj, attr, c)) { + bvalue c_static = *c; + if (var_isfunction(&c_static)) { + c_static.type = func_setstatic(&c_static); + } + if (!be_class_setmember(vm, obj, attr, &c_static)) { reg = vm->reg; vm_error(vm, "attribute_error", "class '%s' cannot assign to static attribute '%s'", @@ -1017,9 +1037,6 @@ newframe: /* a new call frame */ dispatch(); } opcase(RAISE): { -#if BE_USE_PERF_COUNTERS - vm->counter_exc++; -#endif if (IGET_RA(ins) < 2) { /* A==2 means no arguments are passed to RAISE, i.e. rethrow with current exception */ bvalue *top = vm->top; top[0] = *RKB(); /* push the exception value to top */ @@ -1062,10 +1079,11 @@ newframe: /* a new call frame */ ++var, --argc, mode = 1; goto recall; case BE_CLASS: - if (be_class_newobj(vm, var_toobj(var), var, ++argc, mode)) { /* instanciate object and find constructor */ + if (be_class_newobj(vm, var_toobj(var), var - reg, ++argc, mode)) { /* instanciate object and find constructor */ reg = vm->reg + mode; /* constructor found */ mode = 0; var = RA() + 1; /* to next register */ + reg = vm->reg; goto recall; /* call constructor */ } break; @@ -1101,7 +1119,7 @@ newframe: /* a new call frame */ // *(reg + proto->argc - 1) = *(vm->top-2); /* change the vararg argument to now contain the list instance */ // vm->top = top_save; /* restore top of stack pointer */ // } - prep_closure(vm, var, argc, mode); + prep_closure(vm, var - reg, argc, mode); reg = vm->reg; /* `reg` has changed, now new base register */ goto newframe; /* continue execution of the closure */ } @@ -1163,14 +1181,13 @@ newframe: /* a new call frame */ } } -static void prep_closure(bvm *vm, bvalue *reg, int argc, int mode) +static void prep_closure(bvm *vm, int32_t pos, int argc, int mode) { bvalue *v, *end; - bproto *proto = var2cl(reg)->proto; - push_closure(vm, reg, proto->nstack, mode); - v = vm->reg + argc; + bproto *proto = var2cl(vm->reg + pos)->proto; + push_closure(vm, vm->reg + pos, proto->nstack, mode); end = vm->reg + proto->argc; - for (; v <= end; ++v) { + for (v = vm->reg + argc; v <= end; ++v) { var_setnil(v); } if (proto->varg) { /* there are vararg at the last argument, build the list */ @@ -1189,7 +1206,7 @@ static void prep_closure(bvm *vm, bvalue *reg, int argc, int mode) } } -static void do_closure(bvm *vm, bvalue *reg, int argc) +static void do_closure(bvm *vm, int32_t pos, int argc) { // bvalue *v, *end; // bproto *proto = var2cl(reg)->proto; @@ -1199,31 +1216,31 @@ static void do_closure(bvm *vm, bvalue *reg, int argc) // for (; v <= end; ++v) { // var_setnil(v); // } - prep_closure(vm, reg, argc, 0); + prep_closure(vm, pos, argc, 0); vm_exec(vm); } -static void do_ntvclos(bvm *vm, bvalue *reg, int argc) +static void do_ntvclos(bvm *vm, int32_t pos, int argc) { - bntvclos *f = var_toobj(reg); - push_native(vm, reg, argc, 0); + bntvclos *f = var_toobj(vm->reg + pos); + push_native(vm, vm->reg + pos, argc, 0); f->f(vm); /* call C primitive function */ ret_native(vm); } -static void do_ntvfunc(bvm *vm, bvalue *reg, int argc) +static void do_ntvfunc(bvm *vm, int32_t pos, int argc) { - bntvfunc f = var_tontvfunc(reg); - push_native(vm, reg, argc, 0); + bntvfunc f = var_tontvfunc(vm->reg + pos); + push_native(vm, vm->reg + pos, argc, 0); f(vm); /* call C primitive function */ ret_native(vm); } -static void do_class(bvm *vm, bvalue *reg, int argc) +static void do_class(bvm *vm, int32_t pos, int argc) { - if (be_class_newobj(vm, var_toobj(reg), reg, ++argc, 0)) { + if (be_class_newobj(vm, var_toobj(vm->reg + pos), pos, ++argc, 0)) { be_incrtop(vm); - be_dofunc(vm, reg + 1, argc); + be_dofunc(vm, vm->reg + pos + 1, argc); be_stackpop(vm, 1); } } @@ -1232,11 +1249,12 @@ void be_dofunc(bvm *vm, bvalue *v, int argc) { be_assert(vm->reg <= v && v < vm->stacktop); be_assert(vm->stack <= vm->reg && vm->reg < vm->stacktop); + int32_t pos = v - vm->reg; switch (var_type(v)) { - case BE_CLASS: do_class(vm, v, argc); break; - case BE_CLOSURE: do_closure(vm, v, argc); break; - case BE_NTVCLOS: do_ntvclos(vm, v, argc); break; - case BE_NTVFUNC: do_ntvfunc(vm, v, argc); break; + case BE_CLASS: do_class(vm, pos, argc); break; + case BE_CLOSURE: do_closure(vm, pos, argc); break; + case BE_NTVCLOS: do_ntvclos(vm, pos, argc); break; + case BE_NTVFUNC: do_ntvfunc(vm, pos, argc); break; default: call_error(vm, v); } } diff --git a/lib/libesp32/Berry/src/be_vm.h b/lib/libesp32/Berry/src/be_vm.h index 5890ecd41..4d98c590f 100644 --- a/lib/libesp32/Berry/src/be_vm.h +++ b/lib/libesp32/Berry/src/be_vm.h @@ -112,6 +112,8 @@ struct bvm { uint32_t counter_set; /* counter for SETMBR */ uint32_t counter_try; /* counter for `try` statement */ uint32_t counter_exc; /* counter for raised exceptions */ + uint32_t counter_gc_kept; /* counter for objects scanned by last gc */ + uint32_t counter_gc_freed; /* counter for objects freed by last gc */ #endif #if BE_USE_DEBUG_HOOK bvalue hook; diff --git a/lib/libesp32/Berry/tests/bool.be b/lib/libesp32/Berry/tests/bool.be index 670f9bfd8..807d36148 100644 --- a/lib/libesp32/Berry/tests/bool.be +++ b/lib/libesp32/Berry/tests/bool.be @@ -16,3 +16,24 @@ def test(a, b) end end test(true, true) + +# bug in unary +def f(i) + var j = !i # bug if i is erroneously modified + return i +end +assert(f(1) == 1) + +#- addind bool() function -# +assert(bool() == false) +assert(bool(0) == false) +assert(bool(0.0) == false) +assert(bool(false) == false) +assert(bool(nil) == false) + +assert(bool(-1) == true) +assert(bool(3.5) == true) +assert(bool('') == true) +assert(bool('a') == true) +assert(bool(list) == true) +assert(bool(list()) == true) diff --git a/lib/libesp32/Berry/tests/class_const.be b/lib/libesp32/Berry/tests/class_const.be index dda433174..7c986bff0 100644 --- a/lib/libesp32/Berry/tests/class_const.be +++ b/lib/libesp32/Berry/tests/class_const.be @@ -65,8 +65,26 @@ assert(type(a.g) == 'function') assert(type(a.h) == 'function') assert_attribute_error("a.g(1,2)") -assert(a.h(1) == 'instance') -# A.h(1) - error +assert(a.h(1) == 'int') +assert(A.h(1) == 'int') + + +class A + var a + static def g(x, y) return [x,y] end + static h = def (x, y) return [x,y] end + def init() self.a = 1 end + def f(x, y) return type(self) end +end +a=A() +assert(type(a.g) == 'function') +assert(type(a.h) == 'function') +assert(type(A.g) == 'function') +assert(type(A.h) == 'function') +assert(a.g(1,2) == [1,2]) +assert(a.h(1,2) == [1,2]) +assert(A.g(1,2) == [1,2]) +assert(A.h(1,2) == [1,2]) #- test static initializers -# class A @@ -91,3 +109,11 @@ assert(a.f == [1]) assert(a.g == A.g) assert(a.aa == nil) assert(a.ab == nil) + +#- used to fail for subclasses -# +class A static a=1 end +class B:A static a=A def f() end static b=1 static c=A end +assert(A.a == 1) +assert(B.a == A) +assert(B.b == 1) +assert(B.c == A) diff --git a/lib/libesp32/Berry/tests/list.be b/lib/libesp32/Berry/tests/list.be index a6ec7ecc7..d0b9099ba 100644 --- a/lib/libesp32/Berry/tests/list.be +++ b/lib/libesp32/Berry/tests/list.be @@ -72,3 +72,58 @@ assert(l2 == [2, 3]) assert(l1+[2] == [0, 1, 2]) assert([-1]+l1 == [-1, 0, 1]) assert(l1 == [0, 1]) + +#- find -# +#- if no argument return nil -# +assert([].find() == nil) +assert([1,2].find() == nil) +assert([1,1,nil,2].find() == nil) + +#- nil if not found -# +assert([1,2].find(3) == nil) +assert([1,2].find(true) == nil) +assert([1,2].find('foo') == nil) + +#- if found -# +assert([1,2,3,4].find(1) == 0) +assert([1,2,3,4].find(2) == 1) +assert([1,2,3,4].find(3) == 2) +assert([1,2,3,4].find(4) == 3) +assert([1,2,"foo",4].find('foo') == 2) + +#- if multiple occurrences -# +assert([1,1,2,2].find(1) == 0) +assert([1,1,2,2].find(2) == 2) + +#- look for nil -# +assert([1,1,nil,2].find(nil) == 2) + +#- sub-structure -# +assert([1,[1,nil,2],3,[3]].find(3) == 2) +assert([1,[1,nil,2],3,[3]].find([3]) == 3) +assert([1,[1,nil,2],3,[3]].find([1,nil,2]) == 1) + +#- keys() -# +assert(str(["a",'b',0].keys()) == "(0..2)") +assert(str([nil].keys()) == "(0..0)") +assert(str([].keys()) == "(0..-1)") + +#- concat with delimiter -# +assert(["foo","bar",0].concat() == "foobar0") +assert([1,2,3].concat() == "123") +assert(["foo","bar",0].concat('') == "foobar0") +assert([1,2,3].concat('') == "123") + +assert(["foo","bar",0].concat('-') == "foo-bar-0") +assert([].concat('<->') == "") +assert(["foo"].concat('<->') == "foo") +assert(["foo","bar",0].concat('<->') == "foo<->bar<->0") + +assert(["","foo","bar",0].concat('<->') == "<->foo<->bar<->0") +assert(["","",1,"bar",0].concat('<->') == "<-><->1<->bar<->0") +assert(["","",1,"bar",0].concat('') == "1bar0") + +assert([1,2,3].concat('-') == "1-2-3") +assert([1,"2",3].concat('-') == "1-2-3") + +assert(["",2,3].concat('-') == "-2-3") diff --git a/lib/libesp32/Berry/tools/grammar/berry.ebnf b/lib/libesp32/Berry/tools/grammar/berry.ebnf index 1ca79a763..1b8889f80 100644 --- a/lib/libesp32/Berry/tools/grammar/berry.ebnf +++ b/lib/libesp32/Berry/tools/grammar/berry.ebnf @@ -17,7 +17,7 @@ func_body = '(' [arg_field {',' arg_field}] ')' block 'end'; arg_field = ['*'] ID; (* class define statement *) class_stmt = 'class' ID [':' ID] class_block 'end'; -class_block = {'var' ID {',' ID} | 'static' ID ['=' expr] {',' ID ['=' expr] } | func_stmt}; +class_block = {'var' ID {',' ID} | 'static' ID ['=' expr] {',' ID ['=' expr] } | 'static' func_stmt | func_stmt}; import_stmt = 'import' (ID (['as' ID] | {',' ID}) | STRING 'as' ID); (* exceptional handling statement *) try_stmt = 'try' block except_block {except_block} 'end'; diff --git a/lib/libesp32/Zip-readonly-FS/library.json b/lib/libesp32/Zip-readonly-FS/library.json new file mode 100644 index 000000000..a8c83f81b --- /dev/null +++ b/lib/libesp32/Zip-readonly-FS/library.json @@ -0,0 +1,14 @@ +{ + "name": "Zip-readonly-FS", + "version": "1.0", + "description": "Simple filesystem to open an uncompressed ZIP file and read-only", + "license": "MIT", + "homepage": "https://github.com/arendst/Tasmota", + "frameworks": "*", + "platforms": "*", + "authors": + { + "name": "Stephan Hadinger", + "maintainer": true + } + } diff --git a/lib/libesp32/Zip-readonly-FS/src/ZipReadFS.cpp b/lib/libesp32/Zip-readonly-FS/src/ZipReadFS.cpp new file mode 100644 index 000000000..2f036ad8c --- /dev/null +++ b/lib/libesp32/Zip-readonly-FS/src/ZipReadFS.cpp @@ -0,0 +1,465 @@ +/* + ZipReadFS.cpp - FS overlay to read uncompressed ZIP files + + Copyright (C) 2021 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 ESP32 + +#include "ZipReadFS.h" + +extern FS *zip_ufsp; + +#define USE_TASMOTA_LOG + +#ifdef USE_TASMOTA_LOG +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}; +#endif + +/******************************************************************** +** Convert DOS time to time_t +** from: https://opensource.apple.com/source/gcc3/gcc3-1161/fastjar/dostime.c +********************************************************************/ +time_t dos2unixtime(uint32_t dostime) + /* Return the Unix time_t value (GMT/UTC time) for the DOS format (local) + * time dostime, where dostime is a four byte value (date in most + * significant word, time in least significant word), see dostime() + * function. + */ +{ + struct tm *t; /* argument for mktime() */ + time_t clock = time(NULL); + + t = localtime(&clock); + t->tm_isdst = -1; /* let mktime() determine if DST is in effect */ + /* Convert DOS time to UNIX time_t format */ + t->tm_sec = (((int)dostime) << 1) & 0x3e; + t->tm_min = (((int)dostime) >> 5) & 0x3f; + t->tm_hour = (((int)dostime) >> 11) & 0x1f; + t->tm_mday = (int)(dostime >> 16) & 0x1f; + t->tm_mon = ((int)(dostime >> 21) & 0x0f) - 1; + t->tm_year = ((int)(dostime >> 25) & 0x7f) + 80; + + return mktime(t); +} + +/******************************************************************** +** Zip file parser +** +********************************************************************/ +template class LList; + +struct ZipHeader { + uint16_t padding; // need to offset by 16 bites so that 32 bits below are aligned to 4 bytes boundaries + uint16_t signature1; + uint16_t signature2; + uint16_t version; + uint16_t gen_purpose_flags; + uint16_t compression; + uint16_t last_mod_time; + uint16_t last_mod_date; + uint32_t crc32; + uint32_t size_compressed; + uint32_t size_uncompressed; + uint16_t filename_size; + uint16_t extra_field_size; +}; + +class ZipEntry { +public: + ZipEntry() : + file_name(), file_start(0), file_len(0), last_mod(0) + {}; + // ZipEntry(const char * fname, uint32_t start, uint32_t len) : + // file_name(fname), file_start(start), file_len(len) + // {}; + + String file_name; // name of the file as used by Berry, with all directories removed + uint32_t file_start; // offset in bytes where this file starts in the archive + uint32_t file_len; // length in bytes of the file + time_t last_mod; +}; + +class ZipArchive { +public: + ZipArchive(File * _f) : + f(_f), entries() + {}; + ~ZipArchive(void) { + f->close(); // TODO + } + + bool parse(void); + + File * f; + LList entries; +}; + +class ZipEntryFileImpl : public FileImpl { +public: + ZipEntryFileImpl(File * f) : zip(f) { } + +protected: + ZipArchive zip; +}; + +/******************************************************************** +** Neutral file overlay +** +********************************************************************/ + +class ZipReadFileImpl; +typedef std::shared_ptr ZipReadFileImplPtr; + +class ZipReadFileImpl : public FileImpl { +public: + ZipReadFileImpl(File f) { _f = f; } + virtual ~ZipReadFileImpl() {} + size_t write(const uint8_t *buf, size_t size) { + return _f.write(buf, size); + } + size_t read(uint8_t* buf, size_t size) { + return _f.read(buf, size); + } + void flush() { + _f.flush(); + } + bool seek(uint32_t pos, SeekMode mode) { + return _f.seek(pos, mode); + } + size_t position() const { + return _f.position(); + } + size_t size() const { + return _f.size(); + } + void close() { + _f.close(); + } + time_t getLastWrite() { + return _f.getLastWrite(); + } + const char* path() const { + return _f.path(); + } + const char* name() const { + return _f.name(); + } + boolean isDirectory(void) { + return _f.isDirectory(); + } + FileImplPtr openNextFile(const char* mode) { + return nullptr; // TODO + } + void rewindDirectory(void) { + return _f.rewindDirectory(); + } + operator bool() { + return (bool) _f; + } + +protected: + File _f; +}; + +/******************************************************************** +** Subfile implementation +** +** Takes a `File` object of the ZIP archive +** First byte in archive and len +********************************************************************/ + +class ZipItemImpl; +typedef std::shared_ptr ZipItemImplPtr; + +class ZipItemImpl : public FileImpl { +public: + + ZipItemImpl(File f, uint32_t first_byte, uint32_t len, time_t last_mod) { + _f = f; + _first_byte = first_byte; + _len = len; + _seek = 0; + _last_mod = last_mod; + } + + virtual ~ZipItemImpl() {} + + size_t write(const uint8_t *buf, size_t size) { + return 0; // not accepted + } + + size_t read(uint8_t* buf, size_t size) { + // AddLog(LOG_LEVEL_DEBUG, "ZIP: read bytes=%i seek=%i len=%i", size, _seek, _len); + if (_seek < _len) { + if (size + _seek > _len) { + size = _len - _seek; // always > 0 because of guarding test + } + bool bret = _f.seek(_first_byte + _seek, SeekSet); + // AddLog(LOG_LEVEL_DEBUG, "ZIP: seek_ret ret=%i zip_seek=%i", bret, _first_byte + _seek); + if (bret) { + size_t ret = _f.read(buf, size); + // AddLog(LOG_LEVEL_DEBUG, "ZIP: read done ret=%i zip_seek=%i", ret, size); + _seek += ret; + if (_seek > _len) { _seek = _len; } + return ret; + } + } + return 0; // abort + } + + void flush() { + // do nothing + } + + 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 { + AddLog(LOG_LEVEL_DEBUG, "ZIP: position return=%i", _seek); + return _seek; + } + + size_t size() const { + AddLog(LOG_LEVEL_DEBUG, "ZIP: size return=%i", _len); + return _len; + } + + void close() { + // do nothing + } + time_t getLastWrite() { + return _last_mod; + } + + const char* path() const { + return _f.path(); // TODO + } + + const char* name() const { + return _f.name(); // TODO + } + + boolean isDirectory(void) { + return false; // no directory allowed + } + + FileImplPtr openNextFile(const char* mode) { + return nullptr; // TODO + } + + void rewindDirectory(void) { + // ignore + } + + operator bool() { + return true; + } + +protected: + File _f; + uint32_t _first_byte; + uint32_t _len; + uint32_t _seek; + time_t _last_mod; +}; + +/******************************************************************** +** Zip file parser +** Implementation +********************************************************************/ + +// parse the Zip archive to extract all entries +// returns true if ok +bool ZipArchive::parse(void) { + ZipHeader header; + f->seek(0); // start of file + int32_t offset = 0; + const size_t zip_header_size = sizeof(header) - sizeof(header.padding); + + while (1) { + f->seek(offset); + int32_t bytes_read = f->read(sizeof(header.padding) + (uint8_t*) &header, zip_header_size); + if (bytes_read != zip_header_size) { + break; + } + // AddLog(LOG_LEVEL_DEBUG, "ZIG: header version=%i flags=%p compress=%i mod_time=%i mod_date=%i size=%i-%i fnamesize=%i", + // header.version, header.gen_purpose_flags, header.compression, header.last_mod_time, header.last_mod_date, + // header.size_compressed, header.size_uncompressed, header.filename_size); + // Check signature + if (header.signature1 != 0x4B50) { + AddLog(LOG_LEVEL_INFO, "ZIP: invalid zip signature"); + return false; + } + if (header.signature2 != 0x0403) { + AddLog(LOG_LEVEL_DEBUG, "ZIP: end of file section"); + break; + } + // Check no extra field + if (header.gen_purpose_flags != 0x0000) { + AddLog(LOG_LEVEL_INFO, "ZIP: invalid general purpose flags 0x%04X", header.gen_purpose_flags); + return false; + } + // Check no compression + if (header.compression != 0x0000) { + AddLog(LOG_LEVEL_INFO, "ZIP: compressed files unsupported 0x%04X", header.compression); + return false; + } + // Check size is the same for compressed and uncompressed + if (header.size_compressed != header.size_uncompressed) { + AddLog(LOG_LEVEL_INFO, "ZIP: compressed size differs from uncompressed %i - %i", header.size_compressed, header.size_uncompressed); + return false; + } + // Check file name size + if (header.filename_size > 64) { + AddLog(LOG_LEVEL_INFO, "ZIP: entry filename size too long %i", header.filename_size); + return false; + } + + // read full filename + char fname[header.filename_size + 1]; + if (f->read((uint8_t*) &fname[0], header.filename_size) != header.filename_size) { + return false; + } + fname[header.filename_size] = 0; // add NULL termination + + // Remove any directory names, and keep only what's after the last `/`` + char * fname_suffix; + char * saveptr; + fname_suffix = strtok_r(&fname[0], "#", &saveptr); + char * res = fname_suffix; + while (res) { + res = strtok_r(nullptr, "#", &saveptr); + if (res) { fname_suffix = res; } + } + offset += zip_header_size + header.filename_size + header.extra_field_size; + + ZipEntry & entry = entries.addToLast(); + entry.file_name = fname_suffix; + entry.file_start = offset; + entry.file_len = header.size_uncompressed; + entry.last_mod = dos2unixtime((header.last_mod_date << 16) | header.last_mod_time); + offset += header.size_uncompressed; + + AddLog(LOG_LEVEL_DEBUG_MORE, "ZIP: found file '%s' (%i bytes - offset %i) - next entry %i", &fname[0], header.size_uncompressed, entry.file_start, offset); + } + + return true; +} + + +/******************************************************************** +** Encapsulation of FS and File to piggyback on Arduino +** +********************************************************************/ + +FileImplPtr ZipReadFSImpl::open(const char* path, const char* mode, const bool create) { + if (*_fs == nullptr) { return nullptr; } + + if (strchr(path, '#')) { + // we don't support any other mode than "r" and no-create + if (strcmp(mode, "r") != 0 || create) { + AddLog(LOG_LEVEL_INFO, "ZIP: writing to zip is not supported"); + return ZipReadFileImplPtr(); // return an error + } + // treat as a ZIP archive + char sub_path[strlen(path)+1]; + strcpy(sub_path, path); + + // extract the suffix + char *tok; + char *prefix = strtok_r(sub_path, "#", &tok); + char *suffix = strtok_r(NULL, "", &tok); + // if suffix starts with '/', skip the first char + if (*suffix == '/') { suffix++; } + AddLog(LOG_LEVEL_DEBUG, "ZIP: prefix=%s suffix=%s", prefix, suffix); + // parse ZIP archive + File zipfile = (*_fs)->open(prefix, "r", false); + if ((bool)zipfile) { + // we could read the file + ZipArchive zip_archive = ZipArchive(&zipfile); + zip_archive.parse(); + + for (auto & entry : zip_archive.entries) { + if (entry.file_name.equals(suffix)) { + // found + AddLog(LOG_LEVEL_DEBUG, "ZIP: file '%s' in archive (start=%i - len=%i - last_mod=%i)", suffix, entry.file_start, entry.file_len, entry.last_mod); + return ZipItemImplPtr(new ZipItemImpl((*_fs)->open(prefix, "r", false), entry.file_start, entry.file_len, entry.last_mod)); + } + } + return ZipReadFileImplPtr(); // return an error + } else { + AddLog(LOG_LEVEL_INFO, "ZIP: could not open '%s'", prefix); + return ZipReadFileImplPtr(); // return an error + } + } else { + // simple file, do nothing + return ZipReadFileImplPtr(new ZipReadFileImpl((*_fs)->open(path, mode, create))); + } +} + +bool ZipReadFSImpl::exists(const char* path) { + if (*_fs == nullptr) { return false; } + + if (strchr(path, '#')) { + // treat as a ZIP archive + char sub_path[strlen(path)+1]; + strcpy(sub_path, path); + + // extract the suffix + char *tok; + char *prefix = strtok_r(sub_path, "#", &tok); + char *suffix = strtok_r(NULL, "", &tok); + // parse ZIP archive + File zipfile = (*_fs)->open(prefix, "r", false); + if ((bool)zipfile) { + // we could read the file + ZipArchive zip_archive = ZipArchive(&zipfile); + zip_archive.parse(); + + for (auto & entry : zip_archive.entries) { + if (entry.file_name.equals(suffix)) { + return true; + } + } + } + return false; + } else { + // simple file, do nothing + return (*_fs)->exists(path); + } +} + +ZipReadFSImpl::~ZipReadFSImpl() {}; + +#endif // ESP32 \ No newline at end of file diff --git a/lib/libesp32/Zip-readonly-FS/src/ZipReadFS.h b/lib/libesp32/Zip-readonly-FS/src/ZipReadFS.h new file mode 100644 index 000000000..ff0e2f997 --- /dev/null +++ b/lib/libesp32/Zip-readonly-FS/src/ZipReadFS.h @@ -0,0 +1,67 @@ + +#ifndef __ZIP_READ_FS__ +#define __ZIP_READ_FS__ + +#include + +#ifdef ESP32 + +#include +#include +#include + +class ZipReadFSImpl; +typedef std::shared_ptr ZipReadFSImplPtr; + + +class ZipReadFSImpl : public FSImpl { +public: + + ZipReadFSImpl(FS **fs) : _fs(fs) {}; + virtual ~ZipReadFSImpl(); + + FileImplPtr open(const char* path, const char* mode, const bool create); + + bool exists(const char* path); + + bool rename(const char* pathFrom, const char* pathTo) { + if (*_fs) { + return (*_fs)->rename(pathFrom, pathTo); + } else { + return false; + } + } + bool remove(const char* path) { + if (*_fs) { + return (*_fs)->remove(path); + } else { + return false; + } + } + bool mkdir(const char *path) { + if (*_fs) { + return (*_fs)->mkdir(path); + } else { + return false; + } + } + bool rmdir(const char *path) { + if (*_fs) { + return (*_fs)->rmdir(path); + } else { + return false; + } + } + void mountpoint(const char *) { + }; + const char * mountpoint() { + return nullptr; + } + +private: + FS **_fs; +}; + +#endif // ESP32 + +#endif // __ZIP_READ_FS__ diff --git a/lib/libesp32/re1.5/LICENSE b/lib/libesp32/re1.5/LICENSE new file mode 100644 index 000000000..85c4185d4 --- /dev/null +++ b/lib/libesp32/re1.5/LICENSE @@ -0,0 +1,27 @@ +// Copyright (c) 2007-2009 Russ Cox, Google Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google, Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/libesp32/re1.5/Makefile b/lib/libesp32/re1.5/Makefile new file mode 100644 index 000000000..6fe6d3f3c --- /dev/null +++ b/lib/libesp32/re1.5/Makefile @@ -0,0 +1,44 @@ +# Copyright 2007-2009 Russ Cox. All Rights Reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +CC=gcc + +CFLAGS=-g -Wall -Os +# Comment out when developing/testing +#CFLAGS=-DDEBUG -g -Wall -O0 + +TARGET=re +OFILES=\ + backtrack.o\ + compile.o\ + main.o\ + pike.o\ + recursive.o\ + recursiveloop.o\ + sub.o\ + thompson.o\ + compilecode.o\ + dumpcode.o\ + charclass.o\ + cleanmarks.o\ + util.o\ + y.tab.o\ + +HFILES=\ + re1.5.h\ + +$(TARGET): $(OFILES) + $(CC) $(CFLAGS) -o $(TARGET) $(OFILES) + +%.o: %.c $(HFILES) + $(CC) -c $(CFLAGS) $*.c + +y.tab.h y.tab.c: parse.y + bison -v -y parse.y + +test: $(TARGET) + ./run-tests $(TFLAGS) + +clean: + rm -f *.o core $(TARGET) y.tab.[ch] y.output diff --git a/lib/libesp32/re1.5/README b/lib/libesp32/re1.5/README new file mode 100644 index 000000000..d116d330d --- /dev/null +++ b/lib/libesp32/re1.5/README @@ -0,0 +1,48 @@ +What is re1.5? +============== + +re1 (http://code.google.com/p/re1/) is "toy regular expression implementation" +by Russel Cox, featuring simplicity and minimal code size unheard of in other +implementations. re2 (http://code.google.com/p/re2/) is "an efficient, +principled regular expression library" by the same author. It is robust, +full-featured, and ... bloated, comparing to re1. + +re1.5 is an attempt to start with re1 codebase and add features required for +minimalistic real-world use, while sticking to the minimal code size and +memory use. + +Why? +==== +re1.5 is intended for use in highly constrained, e.g. embedded, environments, +where offering familiar high-level string matching functionality is still +beneficial. + +Features +======== + +* Like re1, re1.5 retains design where compiled expression can be executed +(matched) by multiple backends, each with its own distinctive design and +runtime properties (complexity and memory usage). +* Unlike re1, regexes are compiled to memory-efficient bytecode. Exact size +of the bytecode can be found prior to compilation (for memory allocation). +* External API functions feature namespace prefix to improve clarity and +avoid name clashes when integrating into other projects. +* Matchers are NUL-char clean and take size of the input string as a param. +* Support for quoted chars in regex. +* Support for ^, $ assertions in regex. +* Support for "match" vs "search" operations, as common in other regex APIs. +* Support for named character classes: \d \D \s \S \w \W. + +TODO +==== + +* Support for repetition operator {n} and {n,m}. +* Support for Unicode (UTF-8). +* Support for matching flags like case-insensitive, dot matches all, +multiline, etc. +* Support for more assertions like \A, \Z. + +Author and License +================== +re1.5 is maintained by Paul Sokolovsky pfalcon at users.sourceforge.net and +licensed under BSD license, just as the original re1. diff --git a/lib/libesp32/re1.5/backtrack.c b/lib/libesp32/re1.5/backtrack.c new file mode 100644 index 000000000..160069c9d --- /dev/null +++ b/lib/libesp32/re1.5/backtrack.c @@ -0,0 +1,117 @@ +// Copyright 2007-2009 Russ Cox. All Rights Reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "re1.5.h" + +typedef struct Thread Thread; +struct Thread +{ + char *pc; + const char *sp; + Sub *sub; +}; + +static Thread +thread(char *pc, const char *sp, Sub *sub) +{ + Thread t = {pc, sp, sub}; + return t; +} + +int +re1_5_backtrack(ByteProg *prog, Subject *input, const char **subp, int nsubp, int is_anchored) +{ + enum { MAX = 1000 }; + Thread ready[MAX]; + int i, nready; + char *pc; + const char *sp; + Sub *sub; + int off; + + /* queue initial thread */ + sub = newsub(nsubp); + for(i=0; isub[i] = nil; + ready[0] = thread(HANDLE_ANCHORED(prog->insts, is_anchored), input->begin, sub); + nready = 1; + + /* run threads in stack order */ + while(nready > 0) { + --nready; /* pop state for next thread to run */ + pc = ready[nready].pc; + sp = ready[nready].sp; + sub = ready[nready].sub; + assert(sub->ref > 0); + for(;;) { + if(inst_is_consumer(*pc)) { + // If we need to match a character, but there's none left, it's fail + if(sp >= input->end) + goto Dead; + } + switch(*pc++) { + case Char: + if(*sp != *pc++) + goto Dead; + case Any: + sp++; + continue; + case Class: + case ClassNot: + if (!_re1_5_classmatch(pc, sp)) + goto Dead; + pc += *(unsigned char*)pc * 2 + 1; + sp++; + continue; + case NamedClass: + if (!_re1_5_namedclassmatch(pc, sp)) + goto Dead; + pc++; + sp++; + continue; + case Match: + for(i=0; isub[i]; + decref(sub); + return 1; + case Jmp: + off = (signed char)*pc++; + pc = pc + off; + continue; + case Split: + if(nready >= MAX) + re1_5_fatal("backtrack overflow"); + off = (signed char)*pc++; + ready[nready++] = thread(pc + off, sp, incref(sub)); +// pc = pc->x; /* continue current thread */ + continue; + case RSplit: + if(nready >= MAX) + re1_5_fatal("backtrack overflow"); + off = (signed char)*pc++; + ready[nready++] = thread(pc, sp, incref(sub)); + pc = pc + off; + continue; + case Save: + off = (unsigned char)*pc++; + sub = update(sub, off, sp); + continue; + case Bol: + if(sp != input->begin) + goto Dead; + continue; + case Eol: + if(sp != input->end) + goto Dead; + continue; + default: + re1_5_fatal("backtrack"); + } + } + Dead: + decref(sub); + } + return 0; +} + diff --git a/lib/libesp32/re1.5/charclass.c b/lib/libesp32/re1.5/charclass.c new file mode 100644 index 000000000..7f6388c93 --- /dev/null +++ b/lib/libesp32/re1.5/charclass.c @@ -0,0 +1,33 @@ +#include "re1.5.h" + +int _re1_5_classmatch(const char *pc, const char *sp) +{ + // pc points to "cnt" byte after opcode + int is_positive = (pc[-1] == Class); + int cnt = *pc++; + while (cnt--) { + if (*sp >= *pc && *sp <= pc[1]) return is_positive; + pc += 2; + } + return !is_positive; +} + +int _re1_5_namedclassmatch(const char *pc, const char *sp) +{ + // pc points to name of class + int off = (*pc >> 5) & 1; + if ((*pc | 0x20) == 'd') { + if (!(*sp >= '0' && *sp <= '9')) { + off ^= 1; + } + } else if ((*pc | 0x20) == 's') { + if (!(*sp == ' ' || (*sp >= '\t' && *sp <= '\r'))) { + off ^= 1; + } + } else { // w + if (!((*sp >= 'A' && *sp <= 'Z') || (*sp >= 'a' && *sp <= 'z') || (*sp >= '0' && *sp <= '9') || *sp == '_')) { + off ^= 1; + } + } + return off; +} diff --git a/lib/libesp32/re1.5/cleanmarks.c b/lib/libesp32/re1.5/cleanmarks.c new file mode 100644 index 000000000..afe0f91d6 --- /dev/null +++ b/lib/libesp32/re1.5/cleanmarks.c @@ -0,0 +1,39 @@ +// Copyright 2014 Paul Sokolovsky. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "re1.5.h" + +void +cleanmarks(ByteProg *prog) +{ + char *pc = prog->insts; + char *end = pc + prog->bytelen; + while (pc < end) { + *pc &= 0x7f; + switch (*pc) { + case Class: + case ClassNot: + pc += (unsigned char)pc[1] * 2; + case NamedClass: + case Jmp: + case Split: + case RSplit: + case Save: + case Char: + pc++; + break; +#ifdef DEBUG + case Bol: + case Eol: + case Any: + case Match: + break; + default: + printf("Unknown instruction 0x%02x pc %ld\n", (unsigned char)*pc, pc - prog->insts); + re1_5_fatal("cleanmarks"); +#endif + } + pc++; + } +} diff --git a/lib/libesp32/re1.5/compile.c b/lib/libesp32/re1.5/compile.c new file mode 100644 index 000000000..c5a995388 --- /dev/null +++ b/lib/libesp32/re1.5/compile.c @@ -0,0 +1,179 @@ +// Copyright 2007-2009 Russ Cox. All Rights Reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +#ifdef DEBUG + +#include "re1.5.h" + +static Inst *pc; +static int count(Regexp*); +static void emit(Regexp*); + +Prog* +compile(Regexp *r) +{ + int n; + Prog *p; + + n = count(r) + 1; + p = mal(sizeof *p + n*sizeof p->start[0]); + p->start = (Inst*)(p+1); + pc = p->start; + emit(r); + pc->opcode = Match; + pc++; + p->len = pc - p->start; + return p; +} + +// how many instructions does r need? +static int +count(Regexp *r) +{ + switch(r->type) { + default: + re1_5_fatal("bad count"); + case Alt: + return 2 + count(r->left) + count(r->right); + case Cat: + return count(r->left) + count(r->right); + case Lit: + case Dot: + return 1; + case Paren: + return 2 + count(r->left); + case Quest: + return 1 + count(r->left); + case Star: + return 2 + count(r->left); + case Plus: + return 1 + count(r->left); + } +} + +static void +emit(Regexp *r) +{ + Inst *p1, *p2, *t; + + switch(r->type) { + default: + re1_5_fatal("bad emit"); + + case Alt: + pc->opcode = Split; + p1 = pc++; + p1->x = pc; + emit(r->left); + pc->opcode = Jmp; + p2 = pc++; + p1->y = pc; + emit(r->right); + p2->x = pc; + break; + + case Cat: + emit(r->left); + emit(r->right); + break; + + case Lit: + pc->opcode = Char; + pc->c = r->ch; + pc++; + break; + + case Dot: + pc++->opcode = Any; + break; + + case Paren: + pc->opcode = Save; + pc->n = 2*r->n; + pc++; + emit(r->left); + pc->opcode = Save; + pc->n = 2*r->n + 1; + pc++; + break; + + case Quest: + pc->opcode = Split; + p1 = pc++; + p1->x = pc; + emit(r->left); + p1->y = pc; + if(r->n) { // non-greedy + t = p1->x; + p1->x = p1->y; + p1->y = t; + } + break; + + case Star: + pc->opcode = Split; + p1 = pc++; + p1->x = pc; + emit(r->left); + pc->opcode = Jmp; + pc->x = p1; + pc++; + p1->y = pc; + if(r->n) { // non-greedy + t = p1->x; + p1->x = p1->y; + p1->y = t; + } + break; + + case Plus: + p1 = pc; + emit(r->left); + pc->opcode = Split; + pc->x = p1; + p2 = pc; + pc++; + p2->y = pc; + if(r->n) { // non-greedy + t = p2->x; + p2->x = p2->y; + p2->y = t; + } + break; + } +} + +void +printprog(Prog *p) +{ + Inst *pc, *e; + + pc = p->start; + e = p->start + p->len; + + for(; pc < e; pc++) { + switch(pc->opcode) { + default: + re1_5_fatal("printprog"); + case Split: + printf("%2d. split %d, %d\n", (int)(pc-p->start), (int)(pc->x-p->start), (int)(pc->y-p->start)); + break; + case Jmp: + printf("%2d. jmp %d\n", (int)(pc-p->start), (int)(pc->x-p->start)); + break; + case Char: + printf("%2d. char %c\n", (int)(pc-p->start), pc->c); + break; + case Any: + printf("%2d. any\n", (int)(pc-p->start)); + break; + case Match: + printf("%2d. match\n", (int)(pc-p->start)); + break; + case Save: + printf("%2d. save %d\n", (int)(pc-p->start), pc->n); + } + } +} + +#endif //DEBUG diff --git a/lib/libesp32/re1.5/compilecode.c b/lib/libesp32/re1.5/compilecode.c new file mode 100644 index 000000000..50ee74a13 --- /dev/null +++ b/lib/libesp32/re1.5/compilecode.c @@ -0,0 +1,256 @@ +// Copyright 2014-2019 Paul Sokolovsky. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "re1.5.h" + +#define INSERT_CODE(at, num, pc) \ + ((code ? memmove(code + at + num, code + at, pc - at) : (void)0), pc += num) +#define REL(at, to) (to - at - 2) +#define EMIT(at, byte) (code ? (code[at] = byte) : (void)(at)) +#define PC (prog->bytelen) + +static int _compilecode(const char **re_loc, ByteProg *prog, int sizecode) +{ + const char *re = *re_loc; + char *code = sizecode ? NULL : prog->insts; + int start = PC; + int term = PC; + int alt_label = 0; + + for (; *re && *re != ')'; re++) { + switch (*re) { + case '\\': { + re++; + if (!*re) goto syntax_error; // Trailing backslash + char c = *re | 0x20; + if (c == 'd' || c == 's' || c == 'w') { + term = PC; + EMIT(PC++, NamedClass); + EMIT(PC++, *re); + prog->len++; + break; + } + if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z')) { + goto unsupported_escape; + } + } + default: + term = PC; + EMIT(PC++, Char); + EMIT(PC++, *re); + prog->len++; + break; + case '.': + term = PC; + EMIT(PC++, Any); + prog->len++; + break; + case '[': { + int cnt; + term = PC; + re++; + if (*re == '^') { + EMIT(PC++, ClassNot); + re++; + } else { + EMIT(PC++, Class); + } + PC++; // Skip "# of pairs" byte + prog->len++; + for (cnt = 0; *re != ']'; re++, cnt++) { + if (!*re) goto syntax_error; + if (*re == '\\') { + re++; + if (!*re) goto syntax_error; + if (*re != '\\' && *re != ']') goto unsupported_escape; + } + EMIT(PC++, *re); + if (re[1] == '-' && re[2] != ']') { + re += 2; + } + EMIT(PC++, *re); + } + EMIT(term + 1, cnt); + break; + } + case '(': { + term = PC; + int sub; + int capture = 1; + re++; + if (*re == '?') { + re++; + if (*re == ':') { + capture = 0; + re++; + } else { + *re_loc = re; + return RE1_5_UNSUPPORTED_SYNTAX; + } + } + + if (capture) { + sub = ++prog->sub; + EMIT(PC++, Save); + EMIT(PC++, 2 * sub); + prog->len++; + } + + int res = _compilecode(&re, prog, sizecode); + *re_loc = re; + if (res < 0) return res; + if (*re != ')') return RE1_5_SYNTAX_ERROR; + + if (capture) { + EMIT(PC++, Save); + EMIT(PC++, 2 * sub + 1); + prog->len++; + } + + break; + } + case '{': + *re_loc = re; + return RE1_5_UNSUPPORTED_SYNTAX; + case '?': + if (PC == term) goto syntax_error; // nothing to repeat + INSERT_CODE(term, 2, PC); + if (re[1] == '?') { + EMIT(term, RSplit); + re++; + } else { + EMIT(term, Split); + } + EMIT(term + 1, REL(term, PC)); + prog->len++; + term = PC; + break; + case '*': + if (PC == term) goto syntax_error; // nothing to repeat + INSERT_CODE(term, 2, PC); + EMIT(PC, Jmp); + EMIT(PC + 1, REL(PC, term)); + PC += 2; + if (re[1] == '?') { + EMIT(term, RSplit); + re++; + } else { + EMIT(term, Split); + } + EMIT(term + 1, REL(term, PC)); + prog->len += 2; + term = PC; + break; + case '+': + if (PC == term) goto syntax_error; // nothing to repeat + if (re[1] == '?') { + EMIT(PC, Split); + re++; + } else { + EMIT(PC, RSplit); + } + EMIT(PC + 1, REL(PC, term)); + PC += 2; + prog->len++; + term = PC; + break; + case '|': + if (alt_label) { + EMIT(alt_label, REL(alt_label, PC) + 1); + } + INSERT_CODE(start, 2, PC); + EMIT(PC++, Jmp); + alt_label = PC++; + EMIT(start, Split); + EMIT(start + 1, REL(start, PC)); + prog->len += 2; + term = PC; + break; + case '^': + EMIT(PC++, Bol); + prog->len++; + term = PC; + break; + case '$': + EMIT(PC++, Eol); + prog->len++; + term = PC; + break; + } + } + + if (alt_label) { + EMIT(alt_label, REL(alt_label, PC) + 1); + } + + *re_loc = re; + return RE1_5_SUCCESS; + +syntax_error: + *re_loc = re; + return RE1_5_SYNTAX_ERROR; + +unsupported_escape: + *re_loc = re; + return RE1_5_UNSUPPORTED_ESCAPE; +} + +int re1_5_sizecode(const char *re) +{ + ByteProg dummyprog = { + // Save 0, Save 1, Match; more bytes for "search" (vs "match") prefix code + .bytelen = 5 + NON_ANCHORED_PREFIX + }; + + int res = _compilecode(&re, &dummyprog, /*sizecode*/1); + if (res < 0) return res; + // If unparsed chars left + if (*re) return RE1_5_SYNTAX_ERROR; + + return dummyprog.bytelen; +} + +int re1_5_compilecode(ByteProg *prog, const char *re) +{ + prog->len = 0; + prog->bytelen = 0; + prog->sub = 0; + + // Add code to implement non-anchored operation ("search"). + // For anchored operation ("match"), this code will be just skipped. + // TODO: Implement search in much more efficient manner + prog->insts[prog->bytelen++] = RSplit; + prog->insts[prog->bytelen++] = 3; + prog->insts[prog->bytelen++] = Any; + prog->insts[prog->bytelen++] = Jmp; + prog->insts[prog->bytelen++] = -5; + prog->len += 3; + + prog->insts[prog->bytelen++] = Save; + prog->insts[prog->bytelen++] = 0; + prog->len++; + + int res = _compilecode(&re, prog, /*sizecode*/0); + if (res < 0) return res; + // If unparsed chars left + if (*re) return RE1_5_SYNTAX_ERROR; + + prog->insts[prog->bytelen++] = Save; + prog->insts[prog->bytelen++] = 1; + prog->len++; + + prog->insts[prog->bytelen++] = Match; + prog->len++; + + return RE1_5_SUCCESS; +} + +#if 0 +int main(int argc, char *argv[]) +{ + int pc = 0; + ByteProg *code = re1_5_compilecode(argv[1]); + re1_5_dumpcode(code); +} +#endif diff --git a/lib/libesp32/re1.5/dumpcode.c b/lib/libesp32/re1.5/dumpcode.c new file mode 100644 index 000000000..d7781d849 --- /dev/null +++ b/lib/libesp32/re1.5/dumpcode.c @@ -0,0 +1,65 @@ +// Copyright 2014 Paul Sokolovsky. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "re1.5.h" + +void re1_5_dumpcode(ByteProg *prog) +{ + int pc = 0; + char *code = prog->insts; + while (pc < prog->bytelen) { + printf("%2d: ", pc); + switch(code[pc++]) { + default: + assert(0); +// re1_5_fatal("printprog"); + case Split: + printf("split %d (%d)\n", pc + (signed char)code[pc] + 1, (signed char)code[pc]); + pc++; + break; + case RSplit: + printf("rsplit %d (%d)\n", pc + (signed char)code[pc] + 1, (signed char)code[pc]); + pc++; + break; + case Jmp: + printf("jmp %d (%d)\n", pc + (signed char)code[pc] + 1, (signed char)code[pc]); + pc++; + break; + case Char: + printf("char %c\n", code[pc++]); + break; + case Any: + printf("any\n"); + break; + case Class: + case ClassNot: { + int num = code[pc]; + printf("class%s %d", (code[pc - 1] == ClassNot ? "not" : ""), num); + pc++; + while (num--) { + printf(" 0x%02x-0x%02x", code[pc], code[pc + 1]); + pc += 2; + } + printf("\n"); + break; + } + case NamedClass: + printf("namedclass %c\n", code[pc++]); + break; + case Match: + printf("match\n"); + break; + case Save: + printf("save %d\n", (unsigned char)code[pc++]); + break; + case Bol: + printf("assert bol\n"); + break; + case Eol: + printf("assert eol\n"); + break; + } + } + printf("Bytes: %d, insts: %d\n", prog->bytelen, prog->len); +} diff --git a/lib/libesp32/re1.5/library.json b/lib/libesp32/re1.5/library.json new file mode 100644 index 000000000..8233b2142 --- /dev/null +++ b/lib/libesp32/re1.5/library.json @@ -0,0 +1,13 @@ +{ + "name": "re1.5", + "keywords": "esp32, re", + "description": "Regex", + "version": "0.9", + "repository": + { + "type": "git", + "url": "https://github.com/pfalcon/re1.5" + }, + "frameworks": "*", + "platforms": "*" +} \ No newline at end of file diff --git a/lib/libesp32/re1.5/main.c b/lib/libesp32/re1.5/main.c new file mode 100644 index 000000000..7d688adf1 --- /dev/null +++ b/lib/libesp32/re1.5/main.c @@ -0,0 +1,150 @@ +// Copyright 2007-2009 Russ Cox. All Rights Reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "re1.5.h" + +struct { + char *name; + int (*fn)(ByteProg*, Subject*, const char**, int, int); +} tab[] = { + {"recursive", re1_5_recursiveprog}, + {"recursiveloop", re1_5_recursiveloopprog}, + {"backtrack", re1_5_backtrack}, + {"thompson", re1_5_thompsonvm}, + {"pike", re1_5_pikevm}, +}; + +#ifdef DEBUG +int debug; +#endif +const char *re_engine; + +void +usage(void) +{ + fprintf(stderr, "Usage: re [-hmd] [-e ENGINE] ...\n" + "-h: Print help message and exit\n" + "-m: String is anchored\n" + "-e ENGINE: Specify one of: recursive recursiveloop backtrack thompson pike\n"); +#ifdef DEBUG + fprintf(stderr, + "-d: Print debug messages\n"); +#endif + exit(2); +} + +int +main(int argc, char **argv) +{ + int i, j, k, l; + int is_anchored = 0; + + argv++; + argc--; + while (argc > 0 && argv[0][0] == '-') { + char *arg; + for (arg = &argv[0][1]; *arg; arg++) { + switch (*arg) { + case 'h': + usage(); + break; + case 'm': + is_anchored = 1; + break; +#ifdef DEBUG + case 'd': + debug = 1; + break; +#endif + case 'e': + if (argv[1] == NULL) + re1_5_fatal("-e: Missing Regex engine argument"); + if (re_engine) + re1_5_fatal("-e: Regex engine already specified"); + re_engine = argv[1]; + argv++; + argc--; + break; + default: + re1_5_fatal("Unknown flag"); + } + } + argv++; + argc--; + } + + if(argc < 2) + usage(); + +#ifdef ODEBUG + // Old and unmaintained code + Regexp *re = parse(argv[0]); + printre(re); + printf("\n"); + + Prog *prog = compile(re); + printprog(prog); + printf("=============\n"); +#endif + int sz = re1_5_sizecode(argv[0]); +#ifdef DEBUG + if (debug) printf("Precalculated size: %d\n", sz); +#endif + if (sz == -1) { + re1_5_fatal("Error in regexp"); + } + + ByteProg *code = malloc(sizeof(ByteProg) + sz); + int ret = re1_5_compilecode(code, argv[0]); + if (ret != 0) { + re1_5_fatal("Error in regexp"); + } + + int sub_els = (code->sub + 1) * 2; +#ifdef DEBUG + if (debug) re1_5_dumpcode(code); +#endif + const char *sub[sub_els]; + int engine_found = 0; + for(i=1; i0; k--) + if(sub[k-1]) + break; + for(l=0; l CHAR EOL +%type alt concat repeat single line +%type count + +%% + +line: alt EOL + { + parsed_regexp = $1; + return 1; + } + +alt: + concat +| alt '|' concat + { + $$ = reg(Alt, $1, $3); + } +; + +concat: + repeat +| concat repeat + { + $$ = reg(Cat, $1, $2); + } +; + +repeat: + single +| single '*' + { + $$ = reg(Star, $1, nil); + } +| single '*' '?' + { + $$ = reg(Star, $1, nil); + $$->n = 1; + } +| single '+' + { + $$ = reg(Plus, $1, nil); + } +| single '+' '?' + { + $$ = reg(Plus, $1, nil); + $$->n = 1; + } +| single '?' + { + $$ = reg(Quest, $1, nil); + } +| single '?' '?' + { + $$ = reg(Quest, $1, nil); + $$->n = 1; + } +; + +count: + { + $$ = ++nparen; + } +; + +single: + '(' count alt ')' + { + $$ = reg(Paren, $3, nil); + $$->n = $2; + } +| '(' '?' ':' alt ')' + { + $$ = $4; + } +| CHAR + { + $$ = reg(Lit, nil, nil); + $$->ch = $1; + } +| '.' + { + $$ = reg(Dot, nil, nil); + } +; + +%% + +static char *input; +static Regexp *parsed_regexp; +static int nparen; +int gen; + +static int +yylex(void) +{ + int c; + + if(input == NULL || *input == 0) + return EOL; + c = *input++; + if(strchr("|*+?():.", c)) + return c; + yylval.c = c; + return CHAR; +} + +static void +yyerror(char *s) +{ + re1_5_fatal(s); +} + + +Regexp* +parse(char *s) +{ + Regexp *r, *dotstar; + + input = s; + parsed_regexp = nil; + nparen = 0; + if(yyparse() != 1) + yyerror("did not parse"); + if(parsed_regexp == nil) + yyerror("parser nil"); + + r = reg(Paren, parsed_regexp, nil); // $0 parens + return r; + dotstar = reg(Star, reg(Dot, nil, nil), nil); + dotstar->n = 1; // non-greedy + return reg(Cat, dotstar, r); +} + +Regexp* +reg(int type, Regexp *left, Regexp *right) +{ + Regexp *r; + + r = mal(sizeof *r); + r->type = type; + r->left = left; + r->right = right; + return r; +} + +void +printre(Regexp *r) +{ + switch(r->type) { + default: + printf("???"); + break; + + case Alt: + printf("Alt("); + printre(r->left); + printf(", "); + printre(r->right); + printf(")"); + break; + + case Cat: + printf("Cat("); + printre(r->left); + printf(", "); + printre(r->right); + printf(")"); + break; + + case Lit: + printf("Lit(%c)", r->ch); + break; + + case Dot: + printf("Dot"); + break; + + case Paren: + printf("Paren(%d, ", r->n); + printre(r->left); + printf(")"); + break; + + case Star: + if(r->n) + printf("Ng"); + printf("Star("); + printre(r->left); + printf(")"); + break; + + case Plus: + if(r->n) + printf("Ng"); + printf("Plus("); + printre(r->left); + printf(")"); + break; + + case Quest: + if(r->n) + printf("Ng"); + printf("Quest("); + printre(r->left); + printf(")"); + break; + } +} diff --git a/lib/libesp32/re1.5/pike.c b/lib/libesp32/re1.5/pike.c new file mode 100644 index 000000000..9f060fa11 --- /dev/null +++ b/lib/libesp32/re1.5/pike.c @@ -0,0 +1,176 @@ +// Copyright 2007-2009 Russ Cox. All Rights Reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "re1.5.h" + +typedef struct Thread Thread; +struct Thread +{ + char *pc; + Sub *sub; +}; + +typedef struct ThreadList ThreadList; +struct ThreadList +{ + int n; + Thread t[1]; +}; + +static Thread +thread(char *pc, Sub *sub) +{ + Thread t = {pc, sub}; + return t; +} + +static ThreadList* +threadlist(int n) +{ + return mal(sizeof(ThreadList)+n*sizeof(Thread)); +} + +static void +addthread(ThreadList *l, Thread t, Subject *input, const char *sp) +{ + int off; + if(*t.pc & 0x80) { + decref(t.sub); + return; // already on list + } + *t.pc |= 0x80; + + switch(*t.pc & 0x7f) { + default: + l->t[l->n] = t; + l->n++; + break; + case Jmp: + off = (signed char)t.pc[1]; + t.pc += 2; + addthread(l, thread(t.pc + off, t.sub), input, sp); + break; + case Split: + off = (signed char)t.pc[1]; + t.pc += 2; + addthread(l, thread(t.pc, incref(t.sub)), input, sp); + addthread(l, thread(t.pc + off, t.sub), input, sp); + break; + case RSplit: + off = (signed char)t.pc[1]; + t.pc += 2; + addthread(l, thread(t.pc + off, incref(t.sub)), input, sp); + addthread(l, thread(t.pc, t.sub), input, sp); + break; + case Save: + off = (unsigned char)t.pc[1]; + t.pc += 2; + addthread(l, thread(t.pc, update(t.sub, off, sp)), input, sp); + break; + case Bol: + if(sp == input->begin) + addthread(l, thread(t.pc + 1, t.sub), input, sp); + break; + case Eol: + if(sp == input->end) + addthread(l, thread(t.pc + 1, t.sub), input, sp); + break; + } +} + +int +re1_5_pikevm(ByteProg *prog, Subject *input, const char **subp, int nsubp, int is_anchored) +{ + int i, len; + ThreadList *clist, *nlist, *tmp; + char *pc; + const char *sp; + Sub *sub, *matched; + + matched = nil; + for(i=0; isub[i] = nil; + + len = prog->len; + clist = threadlist(len); + nlist = threadlist(len); + + cleanmarks(prog); + addthread(clist, thread(HANDLE_ANCHORED(prog->insts, is_anchored), sub), input, input->begin); + matched = 0; + for(sp=input->begin;; sp++) { + if(clist->n == 0) + break; + // printf("%d(%02x).", (int)(sp - input->begin), *sp & 0xFF); + cleanmarks(prog); + for(i=0; in; i++) { + pc = clist->t[i].pc; + sub = clist->t[i].sub; + // printf(" %d", (int)(pc - prog->insts)); + if (inst_is_consumer(*pc & 0x7f)) { + // If we need to match a character, but there's none left, + // it's fail (we don't schedule current thread for continuation) + if(sp >= input->end) { + decref(sub); + continue; + } + } + switch(*pc++ & 0x7f) { + case Char: + if(*sp != *pc++) { + decref(sub); + break; + } + case Any: + addthread: + addthread(nlist, thread(pc, sub), input, sp+1); + break; + case Class: + case ClassNot: + if (!_re1_5_classmatch(pc, sp)) { + decref(sub); + break; + } + pc += *(unsigned char*)pc * 2 + 1; + goto addthread; + case NamedClass: + if (!_re1_5_namedclassmatch(pc, sp)) { + decref(sub); + break; + } + pc++; + goto addthread; + case Match: + if(matched) + decref(matched); + matched = sub; + for(i++; i < clist->n; i++) + decref(clist->t[i].sub); + goto BreakFor; + // Jmp, Split, Save handled in addthread, so that + // machine execution matches what a backtracker would do. + // This is discussed (but not shown as code) in + // Regular Expression Matching: the Virtual Machine Approach. + } + } + BreakFor: + // printf("\n"); + tmp = clist; + clist = nlist; + nlist = tmp; + nlist->n = 0; + //if(*sp == '\0') + // break; + } + if(matched) { + for(i=0; isub[i]; + decref(matched); + return 1; + } + return 0; +} diff --git a/lib/libesp32/re1.5/re1.5.h b/lib/libesp32/re1.5/re1.5.h new file mode 100644 index 000000000..a9f255d03 --- /dev/null +++ b/lib/libesp32/re1.5/re1.5.h @@ -0,0 +1,162 @@ +// Copyright 2007-2009 Russ Cox. All Rights Reserved. +// Copyright 2014-2019 Paul Sokolovsky. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef _RE1_5_REGEXP__H +#define _RE1_5_REGEXP__H + +#include +#include +#include +#include +#include + +#define nil ((void*)0) +#define nelem(x) (sizeof(x)/sizeof((x)[0])) + +typedef struct Regexp Regexp; +typedef struct Prog Prog; +typedef struct ByteProg ByteProg; +typedef struct Inst Inst; +typedef struct Subject Subject; + +struct Regexp +{ + int type; + int n; + int ch; + Regexp *left; + Regexp *right; +}; + +enum /* Regexp.type */ +{ + Alt = 1, + Cat, + Lit, + Dot, + Paren, + Quest, + Star, + Plus, +}; + +Regexp *parse(char*); +Regexp *reg(int type, Regexp *left, Regexp *right); +void printre(Regexp*); +#ifndef re1_5_fatal +void re1_5_fatal(char*); +#endif +#ifndef re1_5_stack_chk +#define re1_5_stack_chk() +#endif +void *mal(int); + +struct Prog +{ + Inst *start; + int len; +}; + +struct ByteProg +{ + int bytelen; + int len; + int sub; + char insts[0]; +}; + +struct Inst +{ + int opcode; + int c; + int n; + Inst *x; + Inst *y; + int gen; // global state, oooh! +}; + +enum /* Inst.opcode */ +{ + // Instructions which consume input bytes (and thus fail if none left) + CONSUMERS = 1, + Char = CONSUMERS, + Any, + Class, + ClassNot, + NamedClass, + + ASSERTS = 0x50, + Bol = ASSERTS, + Eol, + + // Instructions which take relative offset as arg + JUMPS = 0x60, + Jmp = JUMPS, + Split, + RSplit, + + // Other (special) instructions + Save = 0x7e, + Match = 0x7f, +}; + +#define inst_is_consumer(inst) ((inst) < ASSERTS) +#define inst_is_jump(inst) ((inst) & 0x70 == JUMPS) + +Prog *compile(Regexp*); +void printprog(Prog*); + +extern int gen; + +enum { + MAXSUB = 20 +}; + +typedef struct Sub Sub; + +struct Sub +{ + int ref; + int nsub; + const char *sub[MAXSUB]; +}; + +Sub *newsub(int n); +Sub *incref(Sub*); +Sub *copy(Sub*); +Sub *update(Sub*, int, const char*); +void decref(Sub*); + +struct Subject { + const char *begin; + const char *end; +}; + + +#define NON_ANCHORED_PREFIX 5 +#define HANDLE_ANCHORED(bytecode, is_anchored) ((is_anchored) ? (bytecode) + NON_ANCHORED_PREFIX : (bytecode)) + +int re1_5_backtrack(ByteProg*, Subject*, const char**, int, int); +int re1_5_pikevm(ByteProg*, Subject*, const char**, int, int); +int re1_5_recursiveloopprog(ByteProg*, Subject*, const char**, int, int); +int re1_5_recursiveprog(ByteProg*, Subject*, const char**, int, int); +int re1_5_thompsonvm(ByteProg*, Subject*, const char**, int, int); + +// Return codes for re1_5_sizecode() and re1_5_compilecode() +enum { + RE1_5_SUCCESS = 0, + RE1_5_SYNTAX_ERROR = -2, + RE1_5_UNSUPPORTED_ESCAPE = -3, + RE1_5_UNSUPPORTED_SYNTAX = -4, +}; + +int re1_5_sizecode(const char *re); +int re1_5_compilecode(ByteProg *prog, const char *re); +void re1_5_dumpcode(ByteProg *prog); +void cleanmarks(ByteProg *prog); +int _re1_5_classmatch(const char *pc, const char *sp); +int _re1_5_namedclassmatch(const char *pc, const char *sp); + +#endif /*_RE1_5_REGEXP__H*/ diff --git a/lib/libesp32/re1.5/recursive.c b/lib/libesp32/re1.5/recursive.c new file mode 100644 index 000000000..466518ce3 --- /dev/null +++ b/lib/libesp32/re1.5/recursive.c @@ -0,0 +1,79 @@ +// Copyright 2007-2009 Russ Cox. All Rights Reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "re1.5.h" + +static int +recursive(char *pc, const char *sp, Subject *input, const char **subp, int nsubp) +{ + const char *old; + int off; + + if(inst_is_consumer(*pc)) { + // If we need to match a character, but there's none left, it's fail + if(sp >= input->end) + return 0; + } + + re1_5_stack_chk(); + + switch(*pc++) { + case Char: + if(*sp != *pc++) + return 0; + case Any: + return recursive(pc, sp+1, input, subp, nsubp); + case Class: + case ClassNot: + if (!_re1_5_classmatch(pc, sp)) + return 0; + pc += *(unsigned char*)pc * 2 + 1; + return recursive(pc, sp+1, input, subp, nsubp); + case NamedClass: + if (!_re1_5_namedclassmatch(pc, sp)) + return 0; + return recursive(pc+1, sp+1, input, subp, nsubp); + case Match: + return 1; + case Jmp: + off = (signed char)*pc++; + return recursive(pc + off, sp, input, subp, nsubp); + case Split: + off = (signed char)*pc++; + if(recursive(pc, sp, input, subp, nsubp)) + return 1; + return recursive(pc + off, sp, input, subp, nsubp); + case RSplit: + off = (signed char)*pc++; + if(recursive(pc + off, sp, input, subp, nsubp)) + return 1; + return recursive(pc, sp, input, subp, nsubp); + case Save: + off = (unsigned char)*pc++; + if(off >= nsubp) + return recursive(pc, sp, input, subp, nsubp); + old = subp[off]; + subp[off] = sp; + if(recursive(pc, sp, input, subp, nsubp)) + return 1; + subp[off] = old; + return 0; + case Bol: + if(sp != input->begin) + return 0; + return recursive(pc, sp, input, subp, nsubp); + case Eol: + if(sp != input->end) + return 0; + return recursive(pc, sp, input, subp, nsubp); + } + re1_5_fatal("recursive"); + return -1; +} + +int +re1_5_recursiveprog(ByteProg *prog, Subject *input, const char **subp, int nsubp, int is_anchored) +{ + return recursive(HANDLE_ANCHORED(prog->insts, is_anchored), input->begin, input, subp, nsubp); +} diff --git a/lib/libesp32/re1.5/recursiveloop.c b/lib/libesp32/re1.5/recursiveloop.c new file mode 100644 index 000000000..bb337decf --- /dev/null +++ b/lib/libesp32/re1.5/recursiveloop.c @@ -0,0 +1,86 @@ +// Copyright 2007-2009 Russ Cox. All Rights Reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "re1.5.h" + +static int +recursiveloop(char *pc, const char *sp, Subject *input, const char **subp, int nsubp) +{ + const char *old; + int off; + + re1_5_stack_chk(); + + for(;;) { + if(inst_is_consumer(*pc)) { + // If we need to match a character, but there's none left, it's fail + if(sp >= input->end) + return 0; + } + switch(*pc++) { + case Char: + if(*sp != *pc++) + return 0; + case Any: + sp++; + continue; + case Class: + case ClassNot: + if (!_re1_5_classmatch(pc, sp)) + return 0; + pc += *(unsigned char*)pc * 2 + 1; + sp++; + continue; + case NamedClass: + if (!_re1_5_namedclassmatch(pc, sp)) + return 0; + pc++; + sp++; + continue; + case Match: + return 1; + case Jmp: + off = (signed char)*pc++; + pc = pc + off; + continue; + case Split: + off = (signed char)*pc++; + if(recursiveloop(pc, sp, input, subp, nsubp)) + return 1; + pc = pc + off; + continue; + case RSplit: + off = (signed char)*pc++; + if(recursiveloop(pc + off, sp, input, subp, nsubp)) + return 1; + continue; + case Save: + off = (unsigned char)*pc++; + if(off >= nsubp) { + continue; + } + old = subp[off]; + subp[off] = sp; + if(recursiveloop(pc, sp, input, subp, nsubp)) + return 1; + subp[off] = old; + return 0; + case Bol: + if(sp != input->begin) + return 0; + continue; + case Eol: + if(sp != input->end) + return 0; + continue; + } + re1_5_fatal("recursiveloop"); + } +} + +int +re1_5_recursiveloopprog(ByteProg *prog, Subject *input, const char **subp, int nsubp, int is_anchored) +{ + return recursiveloop(HANDLE_ANCHORED(prog->insts, is_anchored), input->begin, input, subp, nsubp); +} diff --git a/lib/libesp32/re1.5/run-tests b/lib/libesp32/re1.5/run-tests new file mode 100755 index 000000000..af5568658 --- /dev/null +++ b/lib/libesp32/re1.5/run-tests @@ -0,0 +1,164 @@ +#! /usr/bin/env python3 + +RE_EXEC = "./re" + +test_suite = [ + # basics + ("search", r"abc", "abcdef"), + ("search", r"cde", "abcdef"), + ("search", r"abc*", "abdef"), + ("search", r"abc*", "abcccdef"), + ("search", r"abc+", "abdef"), + ("search", r"abc+", "abcccdef"), + + # match + ("match", r"abc", "abcdef"), + ("match", r"abc*", "abdef"), + + # search vs match distinction + ("match", r"a*", "baa"), + ("search", r"a*", "baa"), + + # nested group matching + ("match", r"(([0-9]*)([a-z]*)[0-9]*)", "1234hello567"), + ("match", r"([0-9]*)(([a-z]*)([0-9]*))", "1234hello567"), + + # non-capturing groups + ("match", r"(([0-9]*)(?:[a-z]*)[0-9]*)", "1234hello568"), + ("match", r"(?:[0-9]*)(([a-z]*)(?:[0-9]*))", "1234hello568"), + ("match", r"([0-9]*)(?:([a-z]*)(?:[0-9]*))", "1234hello568"), + ("match", r"(?:)", "1234hello568"), + ("match", r"1?:", "1:"), + + # named character classes + ("match", r"\d+", "123abc456"), + ("match", r"\s+", " \t123abc456"), + ("match", r"\w+", "123abc_456 abc"), + ("match", r"(\w+)\s+(\w+)", "ABC \t123hello456 abc"), + ("match", r"(\S+)\s+(\D+)", "ABC \thello abc456 abc"), + ("match", r"(([0-9]*)([a-z]*)\d*)", "123hello456"), + + # classes + ("match", r"[a]*", "a"), + ("search", r"([yab]*)(e*)([cd])", "xyac"), + ("search", r"([yab]*)(e*)([^y]?)$", "xyac"), + ("match", r"[-]*", "--"), + ("match", r"[-a]*", "-a-b"), + ("match", r"[-ab]*", "-a-b"), + ("match", r"[-a-c]*", "-a-b-d-"), + ("match", r"[a-]*", "-a-b"), + ("match", r"[ab-]*", "-a-b"), + ("match", r"[a-c-]*", "-a-b-d-"), + + # escaped metacharacters + ("match", r"(\?:)", ":"), + ("match", r"\(?:", "(:"), + + # non-greedy + ("match", r"a(b??)(b*)c", "abbc"), + ("match", r"a(b+?)(b*)c", "abbbc"), + ("match", r"a(b*?)(b*)c", "abbbbc"), + + # greedy + ("match", r"a(b?)(b*)c", "abbc"), + ("match", r"a(b+)(b*)c", "abbbc"), + ("match", r"a(b*)(b*)c", "abbbbc"), + + # errors + ("search", r"?", ""), + ("search", r"*", ""), + ("search", r"+", ""), + ("search", r"[", ""), + ("search", r"(", ""), + ("search", r")", ""), + ("search", "\\", ""), + ("search", "|+", ""), + ("search", "|*", ""), + ("search", "|?", ""), + ("search", "^*", ""), + ("search", "$*", ""), + ("search", "a*+", ""), + ("search", "a*?", ""), + ("search", "a**", ""), +] + +import re +import sre_constants +import subprocess +from collections import OrderedDict + +def parse_result(string, res): + name, rest = res.split(b" ", 1) + if rest == b"-no match-": + return name, None + if rest == b"REGEX ERROR": + return name, rest + assert rest.startswith(b"match ") + rest = rest[6:] + tuples = [eval(t) for t in rest.split()] + matches = tuple(string[t[0]:t[1]] for t in tuples) + return name, matches + +def fit_str(string, width): + if len(string) <= width: + return string + else: + return string[:width - 2] + ".." + +def main(): + engine_stats = OrderedDict() + for kind, regex, string in test_suite: + # run Python re to get correct result + try: + if kind == "match": + py_res = re.match(regex, string) + else: + py_res = re.search(regex, string) + if py_res is not None: + py_res = (py_res.group(0),) + py_res.groups() + except sre_constants.error: + py_res = b"REGEX ERROR" + + # run our code + try: + args = (["-m"] if kind == "match" else []) + [regex, string] + re_res = subprocess.check_output([RE_EXEC]+args, stderr=subprocess.STDOUT) + re_res = re_res.split(b'\n')[1:-1] # split lines, remove first and last + except subprocess.CalledProcessError as e: + if e.returncode == 2 and e.output == b"fatal error: Error in regexp\n": + re_res = [b"recursive REGEX ERROR", b"recursiveloop REGEX ERROR", b"backtrack REGEX ERROR", b"thompson REGEX ERROR", b"pike REGEX ERROR"] + else: + raise + + # check result of each engine + for engine in re_res: + engine_name, re_res = parse_result(string, engine) + try: + stats = engine_stats[engine_name] + except KeyError: + engine_stats[engine_name] = stats = [0, 0] + + # Thompson algo offers just boolean match/no match status + py_res_cur = py_res + re_res_cur = re_res + if engine_name == b"thompson": + if py_res is not None: + py_res_cur = True + if re_res is not None: + re_res_cur = True + + if py_res_cur == re_res_cur: + print("pass ", end="") + stats[0] += 1 + else: + print("FAIL ", end="") + stats[1] += 1 + + print("%s %-25s %-20s" % (kind[0], fit_str(regex, 25), fit_str(string, 20))) + + print("Ran %d tests, results:" % len(test_suite)) + for name, stats in engine_stats.items(): + print("%15s %2d pass %2d fail" % (str(name, encoding='utf8'), stats[0], stats[1])) + +if __name__ == "__main__": + main() diff --git a/lib/libesp32/re1.5/sub.c b/lib/libesp32/re1.5/sub.c new file mode 100644 index 000000000..7402b1175 --- /dev/null +++ b/lib/libesp32/re1.5/sub.c @@ -0,0 +1,55 @@ +// Copyright 2007-2009 Russ Cox. All Rights Reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "re1.5.h" + +Sub *freesub; + +Sub* +newsub(int n) +{ + Sub *s; + + s = freesub; + if(s != nil) + freesub = (Sub*)s->sub[0]; + else + s = mal(sizeof *s); + s->nsub = n; + s->ref = 1; + return s; +} + +Sub* +incref(Sub *s) +{ + s->ref++; + return s; +} + +Sub* +update(Sub *s, int i, const char *p) +{ + Sub *s1; + int j; + + if(s->ref > 1) { + s1 = newsub(s->nsub); + for(j=0; jnsub; j++) + s1->sub[j] = s->sub[j]; + s->ref--; + s = s1; + } + s->sub[i] = p; + return s; +} + +void +decref(Sub *s) +{ + if(--s->ref == 0) { + s->sub[0] = (char*)freesub; + freesub = s; + } +} diff --git a/lib/libesp32/re1.5/thompson.c b/lib/libesp32/re1.5/thompson.c new file mode 100644 index 000000000..ef2051b0e --- /dev/null +++ b/lib/libesp32/re1.5/thompson.c @@ -0,0 +1,152 @@ +// Copyright 2007-2009 Russ Cox. All Rights Reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "re1.5.h" + +typedef struct Thread Thread; +struct Thread +{ + char *pc; +}; + +typedef struct ThreadList ThreadList; +struct ThreadList +{ + int n; + Thread t[1]; +}; + +static Thread +thread(char *pc) +{ + Thread t = {pc}; + return t; +} + +static ThreadList* +threadlist(int n) +{ + return mal(sizeof(ThreadList)+n*sizeof(Thread)); +} + +static void +addthread(ThreadList *l, Thread t, Subject *input, const char *sp) +{ + int off; + if(*t.pc & 0x80) + return; // already on list + + *t.pc |= 0x80; + l->t[l->n] = t; + l->n++; + + switch(*t.pc & 0x7f) { + case Jmp: + off = (signed char)t.pc[1]; + t.pc += 2; + addthread(l, thread(t.pc + off), input, sp); + break; + case Split: + off = (signed char)t.pc[1]; + t.pc += 2; + addthread(l, thread(t.pc), input, sp); + addthread(l, thread(t.pc + off), input, sp); + break; + case RSplit: + off = (signed char)t.pc[1]; + t.pc += 2; + addthread(l, thread(t.pc + off), input, sp); + addthread(l, thread(t.pc), input, sp); + break; + case Save: + off = (unsigned char)t.pc[1]; + t.pc += 2; + addthread(l, thread(t.pc), input, sp); + break; + case Bol: + if(sp == input->begin) + addthread(l, thread(t.pc + 1), input, sp); + break; + case Eol: + if(sp == input->end - 1) + addthread(l, thread(t.pc + 1), input, sp); + break; + } +} + +int +re1_5_thompsonvm(ByteProg *prog, Subject *input, const char **subp, int nsubp, int is_anchored) +{ + int i, len, matched; + ThreadList *clist, *nlist, *tmp; + char *pc; + const char *sp; + + for(i=0; ilen; + clist = threadlist(len); + nlist = threadlist(len); + + if(nsubp >= 1) + subp[0] = input->begin; + cleanmarks(prog); + addthread(clist, thread(HANDLE_ANCHORED(prog->insts, is_anchored)), input, input->begin); + matched = 0; + for(sp=input->begin;; sp++) { + if(clist->n == 0) + break; + // printf("%d(%02x).", (int)(sp - input->begin), *sp & 0xFF); + cleanmarks(prog); + for(i=0; in; i++) { + pc = clist->t[i].pc; + // printf(" %d", (int)(pc - prog->insts)); + if (inst_is_consumer(*pc & 0x7f)) { + // If we need to match a character, but there's none left, + // it's fail (we don't schedule current thread for continuation) + if(sp >= input->end) + continue; + } + switch(*pc++ & 0x7f) { + case Char: + if(*sp != *pc++) + break; + case Any: + addthread: + addthread(nlist, thread(pc), input, sp); + break; + case Class: + case ClassNot: + if (!_re1_5_classmatch(pc, sp)) + break; + pc += *(unsigned char*)pc * 2 + 1; + goto addthread; + case NamedClass: + if (!_re1_5_namedclassmatch(pc, sp)) + break; + pc++; + goto addthread; + case Match: + if(nsubp >= 2) + subp[1] = sp; + matched = 1; + goto BreakFor; + // Jmp, Split, Save handled in addthread, so that + // machine execution matches what a backtracker would do. + // This is discussed (but not shown as code) in + // Regular Expression Matching: the Virtual Machine Approach. + } + } + BreakFor: + // printf("\n"); + tmp = clist; + clist = nlist; + nlist = tmp; + nlist->n = 0; + //if(sp >= input->end) + // break; + } + return matched; +} diff --git a/lib/libesp32/re1.5/util.c b/lib/libesp32/re1.5/util.c new file mode 100644 index 000000000..5b72b662a --- /dev/null +++ b/lib/libesp32/re1.5/util.c @@ -0,0 +1,24 @@ +// Copyright 2007-2009 Russ Cox. All Rights Reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "re1.5.h" + +void +re1_5_fatal(char *msg) +{ + fprintf(stderr, "fatal error: %s\n", msg); + exit(2); +} + +void* +mal(int n) +{ + void *v; + + v = malloc(n); + if(v == nil) + re1_5_fatal("out of memory"); + memset(v, 0, n); + return v; +} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_char.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_char.c index 9b712e32e..6b31814af 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_char.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_char.c @@ -309,7 +309,7 @@ const hap_val_t *hap_char_get_step_val(hap_char_t *hc) /** * @brief HAP create a characteristics */ -static hap_char_t *hap_char_create(char *type_uuid, uint32_t permission, hap_char_format_t format, hap_val_t val) +static hap_char_t *hap_char_create(const char *type_uuid, uint32_t permission, hap_char_format_t format, hap_val_t val) { __hap_char_t *new_ch; @@ -333,42 +333,42 @@ static hap_char_t *hap_char_create(char *type_uuid, uint32_t permission, hap_cha return (hap_char_t *) new_ch; } -hap_char_t *hap_char_bool_create(char *type_uuid, uint16_t perms, bool b) +hap_char_t *hap_char_bool_create(const char *type_uuid, uint16_t perms, bool b) { hap_val_t val = {.b = b}; return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_BOOL, val); } -hap_char_t *hap_char_uint8_create(char *type_uuid, uint16_t perms, uint8_t u8) +hap_char_t *hap_char_uint8_create(const char *type_uuid, uint16_t perms, uint8_t u8) { hap_val_t val = {.u = u8}; return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_UINT8, val); } -hap_char_t *hap_char_uint16_create(char *type_uuid, uint16_t perms, uint16_t u16) +hap_char_t *hap_char_uint16_create(const char *type_uuid, uint16_t perms, uint16_t u16) { hap_val_t val = {.u = u16}; return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_UINT16, val); } -hap_char_t *hap_char_uint32_create(char *type_uuid, uint16_t perms, uint32_t u32) +hap_char_t *hap_char_uint32_create(const char *type_uuid, uint16_t perms, uint32_t u32) { hap_val_t val = {.u = u32}; return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_UINT32, val); } -hap_char_t *hap_char_uint64_create(char *type_uuid, uint16_t perms, uint64_t u64) +hap_char_t *hap_char_uint64_create(const char *type_uuid, uint16_t perms, uint64_t u64) { hap_val_t val = {.i64 = u64}; return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_UINT64, val); } -hap_char_t *hap_char_int_create(char *type_uuid, uint16_t perms, int i32) +hap_char_t *hap_char_int_create(const char *type_uuid, uint16_t perms, int i32) { hap_val_t val = {.i = i32}; return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_INT, val); } -hap_char_t *hap_char_float_create(char *type_uuid, uint16_t perms, float f) +hap_char_t *hap_char_float_create(const char *type_uuid, uint16_t perms, float f) { hap_val_t val = {.f = f}; return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_FLOAT, val); } -hap_char_t *hap_char_string_create(char *type_uuid, uint16_t perms, char *s) +hap_char_t *hap_char_string_create(const char *type_uuid, uint16_t perms, const char *s) { hap_val_t val; if (s) @@ -378,7 +378,7 @@ hap_char_t *hap_char_string_create(char *type_uuid, uint16_t perms, char *s) return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_STRING, val); } -hap_char_t *hap_char_data_create(char *type_uuid, uint16_t perms, hap_data_val_t *d) +hap_char_t *hap_char_data_create(const char *type_uuid, uint16_t perms, hap_data_val_t *d) { hap_val_t val = {0}; if (d) { @@ -387,7 +387,7 @@ hap_char_t *hap_char_data_create(char *type_uuid, uint16_t perms, hap_data_val_t return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_DATA, val); } -hap_char_t *hap_char_tlv8_create(char *type_uuid, uint16_t perms, hap_tlv8_val_t *t) +hap_char_t *hap_char_tlv8_create(const char *type_uuid, uint16_t perms, hap_tlv8_val_t *t) { hap_val_t val = {0}; if (t) { diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_ip_services.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_ip_services.c index 4f5031a64..357db53d7 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_ip_services.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_ip_services.c @@ -234,7 +234,7 @@ static struct httpd_uri hap_pair_verify = { .handler = hap_http_pair_verify_handler, }; -static int hap_add_char_val_json(hap_char_format_t format, char *key, +static int hap_add_char_val_json(hap_char_format_t format, const char *key, hap_val_t *val, json_gen_str_t *jptr) { switch (format) { @@ -970,7 +970,7 @@ static int hap_http_put_characteristics(httpd_req_t *req) return HAP_SUCCESS; } -static bool hap_get_bool_url_param(char *query_str, char *key) +static bool hap_get_bool_url_param(const char *query_str, const char *key) { char val[6]; /* Max string will be "false" */ if (httpd_query_key_value(query_str, key, val, sizeof(val)) == HAP_SUCCESS) { diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_main.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_main.c index 459b6a0ed..6fe937692 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_main.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_main.c @@ -81,7 +81,7 @@ static void hap_nw_configured_sm(hap_internal_event_t event, hap_state_t *state) static void hap_common_sm(hap_internal_event_t event) { - char *reboot_reason = HAP_REBOOT_REASON_UNKNOWN; + const char *reboot_reason = HAP_REBOOT_REASON_UNKNOWN; switch (event) { case HAP_INTERNAL_EVENT_RESET_PAIRINGS: ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Resetting all Pairing Information"); @@ -149,7 +149,7 @@ static void hap_common_sm(hap_internal_event_t event) /* Wait for some time after peeforming the operations and then reboot */ ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Rebooting..."); - hap_report_event(HAP_EVENT_ACC_REBOOTING, reboot_reason, strlen(reboot_reason) + 1); + hap_report_event(HAP_EVENT_ACC_REBOOTING, (void*)reboot_reason, strlen(reboot_reason) + 1); vTaskDelay(1000 / hap_platform_os_get_msec_per_tick()); esp_restart(); } diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_serv.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_serv.c index 8c8bd9f25..0ab11ca41 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_serv.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_serv.c @@ -110,7 +110,7 @@ hap_char_t *hap_serv_get_char_by_uuid(hap_serv_t *hs, const char *uuid) /** * @brief get characteristics UUID prefix number */ - char *hap_serv_get_uuid(hap_serv_t *hs) + const char *hap_serv_get_uuid(hap_serv_t *hs) { return ((__hap_serv_t *)hs)->type_uuid; } @@ -145,7 +145,7 @@ static int hap_serv_def_bulk_read_cb(hap_read_data_t read_data[], int count, /** * @brief HAP create a service */ -hap_serv_t *hap_serv_create(char *type_uuid) +hap_serv_t *hap_serv_create(const char *type_uuid) { ESP_MFI_ASSERT(type_uuid); __hap_serv_t *_hs = hap_platform_memory_calloc(1, sizeof(__hap_serv_t)); @@ -198,7 +198,7 @@ uint32_t hap_serv_get_iid(hap_serv_t *hs) return tmp->iid; } -char *hap_serv_get_type_uuid(hap_serv_t *hs) +const char *hap_serv_get_type_uuid(hap_serv_t *hs) { if (!hs) return 0; diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_serv.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_serv.h index 8d041d85f..f3545db7a 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_serv.h +++ b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_serv.h @@ -44,7 +44,7 @@ typedef struct hap_linked_serv hap_linked_serv_t; * HAP service information */ typedef struct { - char *type_uuid; /* String that defines the type of the service. */ + const char *type_uuid; /* String that defines the type of the service. */ uint32_t iid; /* service instance ID */ @@ -69,8 +69,8 @@ typedef struct { bool hap_serv_get_hidden(hap_serv_t *hs); bool hap_serv_get_primary(hap_serv_t *hs); hap_char_t *hap_serv_get_char_by_iid(hap_serv_t *hs, int32_t iid); - char *hap_serv_get_uuid(hap_serv_t *hs); -hap_serv_t *hap_serv_create(char *type_uuid); +const char *hap_serv_get_uuid(hap_serv_t *hs); +hap_serv_t *hap_serv_create(const char *type_uuid); void hap_serv_delete(hap_serv_t *hs); int hap_serv_add_char(hap_serv_t *hs, hap_char_t *hc); #ifdef __cplusplus diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_debug.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_debug.h index 4c0ae62ee..282276e9d 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_debug.h +++ b/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_debug.h @@ -35,12 +35,12 @@ extern "C"{ #define ESP_MFI_DEBUG_FL "\n" #define CONFIG_ESP_MFI_DEBUG_ENABLE #ifdef CONFIG_ESP_MFI_DEBUG_ENABLE -#define ESP_MFI_DEBUG_ENABLE +// #define ESP_MFI_DEBUG_ENABLE #endif /* CONFIG_ESP_MFI_DEBUG_ENABLE */ #define CONFIG_ESP_MFI_ASSERT #ifdef CONFIG_ESP_MFI_ASSERT -#define ESP_MFI_ASSERT_ENABLE +// #define ESP_MFI_ASSERT_ENABLE #endif /* CONFIG_ESP_MFI_ASSERT */ #define CONFIG_MFI_DEBUG_LEVEL_INIT 0 diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap.h b/lib/libesp32_div/ESP32-HomeKit/src/hap.h index fdd80f528..1eb9f59a7 100755 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap.h +++ b/lib/libesp32_div/ESP32-HomeKit/src/hap.h @@ -234,23 +234,23 @@ typedef int (*hap_identify_routine_t) (hap_acc_t *acc); /** HAP Accessory configuration */ typedef struct { /** Name (Mandatory) */ - char *name; + const char *name; /** Model (Mandatory) */ - char *model; + const char *model; /** Manufacturer (Mandatory) */ - char *manufacturer; + const char *manufacturer; /** Serial Number (Mandatory) */ - char *serial_num; + const char *serial_num; /** Firmware Revision number in format x[.y[.z]] (Mandatory) */ - char *fw_rev; + const char *fw_rev; /** Hardware revision number in format x[.y[.z]] (Optional. Can be NULL )*/ - char *hw_rev; + const char *hw_rev; /** HAP Protocol version supported by the accessory. Should be set to "1.1" * @note The value set here will currently be ignored and assumed to be 1.1 * as it is the only protocol version currently supported. * This is valid only for the Primary accessory. */ - char *pv; + const char *pv; /** Category Identifier for the Accessory. This is valid only for the * primary accessory */ @@ -640,7 +640,7 @@ hap_serv_t *hap_acc_get_first_serv(hap_acc_t *ha); * @return Handle for the characteristic object created * @return NULL on error */ -hap_char_t *hap_char_bool_create(char *type_uuid, uint16_t perms, bool val); +hap_char_t *hap_char_bool_create(const char *type_uuid, uint16_t perms, bool val); /** * @brief Create an 8-bit unsigned integer Characteristic Object @@ -652,7 +652,7 @@ hap_char_t *hap_char_bool_create(char *type_uuid, uint16_t perms, bool val); * @return Handle for the characteristic object created * @return NULL on error */ -hap_char_t *hap_char_uint8_create(char *type_uuid, uint16_t perms, uint8_t val); +hap_char_t *hap_char_uint8_create(const char *type_uuid, uint16_t perms, uint8_t val); /** * @brief Create a 16-bit unsigned integer Characteristic Object @@ -664,7 +664,7 @@ hap_char_t *hap_char_uint8_create(char *type_uuid, uint16_t perms, uint8_t val); * @return Handle for the characteristic object created * @return NULL on error */ -hap_char_t *hap_char_uint16_create(char *type_uuid, uint16_t perms, uint16_t val); +hap_char_t *hap_char_uint16_create(const char *type_uuid, uint16_t perms, uint16_t val); /** * @brief Create a 32-bit unsigned integer Characteristic Object @@ -676,7 +676,7 @@ hap_char_t *hap_char_uint16_create(char *type_uuid, uint16_t perms, uint16_t val * @return Handle for the characteristic object created * @return NULL on error */ -hap_char_t *hap_char_uint32_create(char *type_uuid, uint16_t perms, uint32_t val); +hap_char_t *hap_char_uint32_create(const char *type_uuid, uint16_t perms, uint32_t val); /** * @brief Create a 64-bit unsigned integer Characteristic Object @@ -688,7 +688,7 @@ hap_char_t *hap_char_uint32_create(char *type_uuid, uint16_t perms, uint32_t val * @return Handle for the characteristic object created * @return NULL on error */ -hap_char_t *hap_char_uint64_create(char *type_uuid, uint16_t perms, uint64_t val); +hap_char_t *hap_char_uint64_create(const char *type_uuid, uint16_t perms, uint64_t val); /** * @brief Create a 32-bit signed integer Characteristic Object @@ -700,7 +700,7 @@ hap_char_t *hap_char_uint64_create(char *type_uuid, uint16_t perms, uint64_t val * @return Handle for the characteristic object created * @return NULL on error */ -hap_char_t *hap_char_int_create(char *type_uuid, uint16_t perms, int val); +hap_char_t *hap_char_int_create(const char *type_uuid, uint16_t perms, int val); /** * @brief Create a Floating point Characteristic Object @@ -712,7 +712,7 @@ hap_char_t *hap_char_int_create(char *type_uuid, uint16_t perms, int val); * @return Handle for the characteristic object created * @return NULL on error */ -hap_char_t *hap_char_float_create(char *type_uuid, uint16_t perms, float val); +hap_char_t *hap_char_float_create(const char *type_uuid, uint16_t perms, float val); /** * @brief Create a String Characteristic Object @@ -724,7 +724,7 @@ hap_char_t *hap_char_float_create(char *type_uuid, uint16_t perms, float val); * @return Handle for the characteristic object created * @return NULL on error */ -hap_char_t *hap_char_string_create(char *type_uuid, uint16_t perms, char *val); +hap_char_t *hap_char_string_create(const char *type_uuid, uint16_t perms, const char *val); /** * @brief Create a Data Characteristic Object @@ -736,7 +736,7 @@ hap_char_t *hap_char_string_create(char *type_uuid, uint16_t perms, char *val); * @return Handle for the characteristic object created * @return NULL on error */ -hap_char_t *hap_char_data_create(char *type_uuid, uint16_t perms, hap_data_val_t *val); +hap_char_t *hap_char_data_create(const char *type_uuid, uint16_t perms, hap_data_val_t *val); /** * @brief Create a TLV8 Characteristic Object @@ -748,7 +748,7 @@ hap_char_t *hap_char_data_create(char *type_uuid, uint16_t perms, hap_data_val_t * @return Handle for the characteristic object created * @return NULL on error */ -hap_char_t *hap_char_tlv8_create(char *type_uuid, uint16_t perms, hap_tlv8_val_t *val); +hap_char_t *hap_char_tlv8_create(const char *type_uuid, uint16_t perms, hap_tlv8_val_t *val); /** * @brief Delete a characteristic object @@ -765,7 +765,7 @@ void hap_char_delete(hap_char_t *hc); * @return Handle for the service object created * @return NULL on error */ -hap_serv_t *hap_serv_create(char *type_uuid); +hap_serv_t *hap_serv_create(const char *type_uuid); /** * @brief Delete a service object @@ -884,7 +884,7 @@ uint32_t hap_serv_get_iid(hap_serv_t *hs); * * @return Type UUID for the service */ -char *hap_serv_get_type_uuid(hap_serv_t *hs); +const char *hap_serv_get_type_uuid(hap_serv_t *hs); /** * @brief Get parent Service for given Characteristic * diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.c b/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.c index de079b4dd..0b811e3c9 100755 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.c @@ -128,7 +128,7 @@ hap_char_t *hap_char_current_temperature_create(float curr_temp) } /* Char: Firmware Revision */ -hap_char_t *hap_char_firmware_revision_create(char *fw_rev) +hap_char_t *hap_char_firmware_revision_create(const char *fw_rev) { hap_char_t *hc = hap_char_string_create(HAP_CHAR_UUID_FIRMWARE_REVISION, HAP_CHAR_PERM_PR, fw_rev); @@ -139,7 +139,7 @@ hap_char_t *hap_char_firmware_revision_create(char *fw_rev) } /* Char: Hardware Revision */ -hap_char_t *hap_char_hardware_revision_create(char *hw_rev) +hap_char_t *hap_char_hardware_revision_create(const char *hw_rev) { hap_char_t *hc = hap_char_string_create(HAP_CHAR_UUID_HARDWARE_REVISION, HAP_CHAR_PERM_PR, hw_rev); @@ -218,7 +218,7 @@ hap_char_t *hap_char_lock_target_state_create(uint8_t lock_targ_state) } /* Char: Manufacturer */ -hap_char_t *hap_char_manufacturer_create(char *manufacturer) +hap_char_t *hap_char_manufacturer_create(const char *manufacturer) { hap_char_t *hc = hap_char_string_create(HAP_CHAR_UUID_MANUFACTURER, HAP_CHAR_PERM_PR, manufacturer); @@ -229,7 +229,7 @@ hap_char_t *hap_char_manufacturer_create(char *manufacturer) } /* Char: Model */ -hap_char_t *hap_char_model_create(char *model) +hap_char_t *hap_char_model_create(const char *model) { hap_char_t *hc = hap_char_string_create(HAP_CHAR_UUID_MODEL, HAP_CHAR_PERM_PR, model); @@ -252,7 +252,7 @@ hap_char_t *hap_char_motion_detected_create(bool motion_detected) } /* Char: Name */ -hap_char_t *hap_char_name_create(char *name) +hap_char_t *hap_char_name_create(const char *name) { hap_char_t *hc = hap_char_string_create(HAP_CHAR_UUID_NAME, HAP_CHAR_PERM_PR, name); @@ -341,7 +341,7 @@ hap_char_t *hap_char_saturation_create(float saturation) } /* Char: Serial Number */ -hap_char_t *hap_char_serial_number_create(char *serial_num) +hap_char_t *hap_char_serial_number_create(const char *serial_num) { hap_char_t *hc = hap_char_string_create(HAP_CHAR_UUID_SERIAL_NUMBER, HAP_CHAR_PERM_PR, serial_num); @@ -424,7 +424,7 @@ hap_char_t *hap_char_temperature_display_units_create(uint8_t temp_disp_units) } /* Char: Version */ -hap_char_t *hap_char_version_create(char *version) +hap_char_t *hap_char_version_create(const char *version) { hap_char_t *hc = hap_char_string_create(HAP_CHAR_UUID_VERSION, HAP_CHAR_PERM_PR, version); diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.h b/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.h index 90aa12e08..6fcc69697 100755 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.h +++ b/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.h @@ -227,7 +227,7 @@ hap_char_t *hap_char_current_temperature_create(float curr_temp); * @return Pointer to the characteristic object on success * @return NULL on failure */ -hap_char_t *hap_char_firmware_revision_create(char *fw_rev); +hap_char_t *hap_char_firmware_revision_create(const char *fw_rev); /** Create Hardware Revision Characteristic * @@ -239,7 +239,7 @@ hap_char_t *hap_char_firmware_revision_create(char *fw_rev); * @return Pointer to the characteristic object on success * @return NULL on failure */ -hap_char_t *hap_char_hardware_revision_create(char *hw_rev); +hap_char_t *hap_char_hardware_revision_create(const char *hw_rev); /** Heating Threshold Temperature Characteristic * @@ -309,7 +309,7 @@ hap_char_t *hap_char_lock_target_state_create(uint8_t lock_targ_state); * @return Pointer to the characteristic object on success * @return NULL on failure */ -hap_char_t *hap_char_manufacturer_create(char *manufacturer); +hap_char_t *hap_char_manufacturer_create(const char *manufacturer); /** Create Model Characteristic * @@ -321,7 +321,7 @@ hap_char_t *hap_char_manufacturer_create(char *manufacturer); * @return Pointer to the characteristic object on success * @return NULL on failure */ -hap_char_t *hap_char_model_create(char *model); +hap_char_t *hap_char_model_create(const char *model); /** Create Motion Detected Characteristic * @@ -345,7 +345,7 @@ hap_char_t *hap_char_motion_detected_create(bool motion_detected); * @return Pointer to the characteristic object on success * @return NULL on failure */ -hap_char_t *hap_char_name_create(char *name); +hap_char_t *hap_char_name_create(const char *name); /** Create Obstruction Detected Characteristic * @@ -429,7 +429,7 @@ hap_char_t *hap_char_saturation_create(float saturation); * @return Pointer to the characteristic object on success * @return NULL on failure */ -hap_char_t *hap_char_serial_number_create(char *serial_num); +hap_char_t *hap_char_serial_number_create(const char *serial_num); /** Create Target Door State Characteristic * @@ -501,7 +501,7 @@ hap_char_t *hap_char_temperature_display_units_create(uint8_t temp_disp_units); * @return Pointer to the characteristic object on success * @return NULL on failure */ -hap_char_t *hap_char_version_create(char *version); +hap_char_t *hap_char_version_create(const char *version); /** Create Security System Current State Characteristic * diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_httpd.c b/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_httpd.c index 9bd679da4..7d19b62e8 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_httpd.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_httpd.c @@ -82,7 +82,7 @@ esp_err_t hap_platform_httpd_set_sess_ctx(httpd_req_t *req, void *ctx, httpd_fre return ESP_FAIL; } -static char * hap_platform_httpd_rqtype_to_string(int method) +static const char * hap_platform_httpd_rqtype_to_string(int method) { switch (method) { case HTTP_GET: diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hexdump.c b/lib/libesp32_div/ESP32-HomeKit/src/hexdump.c index f6e7e0aef..dfa3a56fe 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/hexdump.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/hexdump.c @@ -16,7 +16,7 @@ //#define HEX_DBG_ENABLE #ifdef HEX_DBG_ENABLE -void hex_dbg_with_name(char *name, unsigned char *buf, int buf_len) +void hex_dbg_with_name(const char *name, unsigned char *buf, int buf_len) { int i; printf("%s: ", name); @@ -28,7 +28,7 @@ void hex_dbg_with_name(char *name, unsigned char *buf, int buf_len) printf("\r\n"); } #else -void hex_dbg_with_name(char *name, unsigned char *buf, int buf_len) +void hex_dbg_with_name(const char *name, unsigned char *buf, int buf_len) { } #endif /* HEX_DBG_ENABLED */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hexdump.h b/lib/libesp32_div/ESP32-HomeKit/src/hexdump.h index a64bc7c18..e6b0009e5 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/hexdump.h +++ b/lib/libesp32_div/ESP32-HomeKit/src/hexdump.h @@ -13,6 +13,6 @@ // limitations under the License. #ifndef _HEXDUMP_H_ #define _HEXDUMP_H_ -void hex_dbg_with_name(char *name, unsigned char *buf, int buf_len); +void hex_dbg_with_name(const char *name, unsigned char *buf, int buf_len); #endif /* _HEXDUMP_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/json_generator.c b/lib/libesp32_div/ESP32-HomeKit/src/json_generator.c index 947fb62b5..61102f92f 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/json_generator.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/json_generator.c @@ -34,13 +34,13 @@ static inline int json_gen_get_empty_len(json_gen_str_t *jstr) * flushed out will always be equal to the size of the buffer unless * this is the last chunk being flushed out on json_gen_end_str() */ -static int json_gen_add_to_str(json_gen_str_t *jstr, char *str) +static int json_gen_add_to_str(json_gen_str_t *jstr, const char *str) { if (!str) { return 0; } int len = strlen(str); - char *cur_ptr = str; + const char *cur_ptr = str; while (1) { int len_remaining = json_gen_get_empty_len(jstr); int copy_len = len_remaining > len ? len : len_remaining; @@ -91,7 +91,7 @@ static inline void json_gen_handle_comma(json_gen_str_t *jstr) } -static int json_gen_handle_name(json_gen_str_t *jstr, char *name) +static int json_gen_handle_name(json_gen_str_t *jstr, const char *name) { json_gen_add_to_str(jstr, "\""); json_gen_add_to_str(jstr, name); @@ -126,7 +126,7 @@ int json_gen_end_array(json_gen_str_t *jstr) return json_gen_add_to_str(jstr, "]"); } -int json_gen_push_object(json_gen_str_t *jstr, char *name) +int json_gen_push_object(json_gen_str_t *jstr, const char *name) { json_gen_handle_comma(jstr); json_gen_handle_name(jstr, name); @@ -140,7 +140,7 @@ int json_gen_pop_object(json_gen_str_t *jstr) return json_gen_add_to_str(jstr, "}"); } -int json_gen_push_object_str(json_gen_str_t *jstr, char *name, char *object_str) +int json_gen_push_object_str(json_gen_str_t *jstr, const char *name, char *object_str) { json_gen_handle_comma(jstr); json_gen_handle_name(jstr, name); @@ -148,7 +148,7 @@ int json_gen_push_object_str(json_gen_str_t *jstr, char *name, char *object_str) return json_gen_add_to_str(jstr, object_str); } -int json_gen_push_array(json_gen_str_t *jstr, char *name) +int json_gen_push_array(json_gen_str_t *jstr, const char *name) { json_gen_handle_comma(jstr); json_gen_handle_name(jstr, name); @@ -161,7 +161,7 @@ int json_gen_pop_array(json_gen_str_t *jstr) return json_gen_add_to_str(jstr, "]"); } -int json_gen_push_array_str(json_gen_str_t *jstr, char *name, char *array_str) +int json_gen_push_array_str(json_gen_str_t *jstr, const char *name, char *array_str) { json_gen_handle_comma(jstr); json_gen_handle_name(jstr, name); @@ -177,7 +177,7 @@ static int json_gen_set_bool(json_gen_str_t *jstr, bool val) else return json_gen_add_to_str(jstr, "false"); } -int json_gen_obj_set_bool(json_gen_str_t *jstr, char *name, bool val) +int json_gen_obj_set_bool(json_gen_str_t *jstr, const char *name, bool val) { json_gen_handle_comma(jstr); json_gen_handle_name(jstr, name); @@ -198,7 +198,7 @@ static int json_gen_set_int(json_gen_str_t *jstr, int val) return json_gen_add_to_str(jstr, str); } -int json_gen_obj_set_int(json_gen_str_t *jstr, char *name, int val) +int json_gen_obj_set_int(json_gen_str_t *jstr, const char *name, int val) { json_gen_handle_comma(jstr); json_gen_handle_name(jstr, name); @@ -219,7 +219,7 @@ static int json_gen_set_float(json_gen_str_t *jstr, float val) snprintf(str, MAX_FLOAT_IN_STR, "%.*f", JSON_FLOAT_PRECISION, val); return json_gen_add_to_str(jstr, str); } -int json_gen_obj_set_float(json_gen_str_t *jstr, char *name, float val) +int json_gen_obj_set_float(json_gen_str_t *jstr, const char *name, float val) { json_gen_handle_comma(jstr); json_gen_handle_name(jstr, name); @@ -231,7 +231,7 @@ int json_gen_arr_set_float(json_gen_str_t *jstr, float val) return json_gen_set_float(jstr, val); } -static int json_gen_set_string(json_gen_str_t *jstr, char *val) +static int json_gen_set_string(json_gen_str_t *jstr, const char *val) { jstr->comma_req = true; json_gen_add_to_str(jstr, "\""); @@ -239,40 +239,40 @@ static int json_gen_set_string(json_gen_str_t *jstr, char *val) return json_gen_add_to_str(jstr, "\""); } -int json_gen_obj_set_string(json_gen_str_t *jstr, char *name, char *val) +int json_gen_obj_set_string(json_gen_str_t *jstr, const char *name, const char *val) { json_gen_handle_comma(jstr); json_gen_handle_name(jstr, name); return json_gen_set_string(jstr, val); } -int json_gen_arr_set_string(json_gen_str_t *jstr, char *val) +int json_gen_arr_set_string(json_gen_str_t *jstr, const char *val) { json_gen_handle_comma(jstr); return json_gen_set_string(jstr, val); } -static int json_gen_set_long_string(json_gen_str_t *jstr, char *val) +static int json_gen_set_long_string(json_gen_str_t *jstr, const char *val) { jstr->comma_req = true; json_gen_add_to_str(jstr, "\""); return json_gen_add_to_str(jstr, val); } -int json_gen_obj_start_long_string(json_gen_str_t *jstr, char *name, char *val) +int json_gen_obj_start_long_string(json_gen_str_t *jstr, const char *name, const char *val) { json_gen_handle_comma(jstr); json_gen_handle_name(jstr, name); return json_gen_set_long_string(jstr, val); } -int json_gen_arr_start_long_string(json_gen_str_t *jstr, char *val) +int json_gen_arr_start_long_string(json_gen_str_t *jstr, const char *val) { json_gen_handle_comma(jstr); return json_gen_set_long_string(jstr, val); } -int json_gen_add_to_long_string(json_gen_str_t *jstr, char *val) +int json_gen_add_to_long_string(json_gen_str_t *jstr, const char *val) { return json_gen_add_to_str(jstr, val); } @@ -286,7 +286,7 @@ static int json_gen_set_null(json_gen_str_t *jstr) jstr->comma_req = true; return json_gen_add_to_str(jstr, "null"); } -int json_gen_obj_set_null(json_gen_str_t *jstr, char *name) +int json_gen_obj_set_null(json_gen_str_t *jstr, const char *name) { json_gen_handle_comma(jstr); json_gen_handle_name(jstr, name); diff --git a/lib/libesp32_div/ESP32-HomeKit/src/json_generator.h b/lib/libesp32_div/ESP32-HomeKit/src/json_generator.h index 540e12461..b4cf4be11 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/json_generator.h +++ b/lib/libesp32_div/ESP32-HomeKit/src/json_generator.h @@ -170,7 +170,7 @@ int json_gen_end_array(json_gen_str_t *jstr); * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data * added after that */ -int json_gen_push_object(json_gen_str_t *jstr, char *name); +int json_gen_push_object(json_gen_str_t *jstr, const char *name); /** Pop a named JSON object * @@ -204,7 +204,7 @@ int json_gen_pop_object(json_gen_str_t *jstr); * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data * added after that. */ -int json_gen_push_object_str(json_gen_str_t *jstr, char *name, char *object_str); +int json_gen_push_object_str(json_gen_str_t *jstr, const char *name, char *object_str); /** Push a named JSON array * @@ -219,7 +219,7 @@ int json_gen_push_object_str(json_gen_str_t *jstr, char *name, char *object_str) * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data * added after that */ -int json_gen_push_array(json_gen_str_t *jstr, char *name); +int json_gen_push_array(json_gen_str_t *jstr, const char *name); /** Pop a named JSON array * @@ -253,7 +253,7 @@ int json_gen_pop_array(json_gen_str_t *jstr); * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data * added after that. */ -int json_gen_push_array_str(json_gen_str_t *jstr, char *name, char *array_str); +int json_gen_push_array_str(json_gen_str_t *jstr, const char *name, char *array_str); /** Add a boolean element to an object * @@ -272,7 +272,7 @@ int json_gen_push_array_str(json_gen_str_t *jstr, char *name, char *array_str); * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data * added after that */ -int json_gen_obj_set_bool(json_gen_str_t *jstr, char *name, bool val); +int json_gen_obj_set_bool(json_gen_str_t *jstr, const char *name, bool val); /** Add an integer element to an object * @@ -291,7 +291,7 @@ int json_gen_obj_set_bool(json_gen_str_t *jstr, char *name, bool val); * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data * added after that */ -int json_gen_obj_set_int(json_gen_str_t *jstr, char *name, int val); +int json_gen_obj_set_int(json_gen_str_t *jstr, const char *name, int val); /** Add a float element to an object * @@ -310,7 +310,7 @@ int json_gen_obj_set_int(json_gen_str_t *jstr, char *name, int val); * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data * added after that */ -int json_gen_obj_set_float(json_gen_str_t *jstr, char *name, float val); +int json_gen_obj_set_float(json_gen_str_t *jstr, const char *name, float val); /** Add a string element to an object * @@ -329,7 +329,7 @@ int json_gen_obj_set_float(json_gen_str_t *jstr, char *name, float val); * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data * added after that */ -int json_gen_obj_set_string(json_gen_str_t *jstr, char *name, char *val); +int json_gen_obj_set_string(json_gen_str_t *jstr, const char *name, const char *val); /** Add a NULL element to an object * @@ -347,7 +347,7 @@ int json_gen_obj_set_string(json_gen_str_t *jstr, char *name, char *val); * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data * added after that */ -int json_gen_obj_set_null(json_gen_str_t *jstr, char *name); +int json_gen_obj_set_null(json_gen_str_t *jstr, const char *name); /** Add a boolean element to an array * @@ -411,7 +411,7 @@ int json_gen_arr_set_float(json_gen_str_t *jstr, float val); * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data * added after that */ -int json_gen_arr_set_string(json_gen_str_t *jstr, char *val); +int json_gen_arr_set_string(json_gen_str_t *jstr, const char *val); /** Add a NULL element to an array * @@ -448,7 +448,7 @@ int json_gen_arr_set_null(json_gen_str_t *jstr); * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data * added after that */ -int json_gen_obj_start_long_string(json_gen_str_t *jstr, char *name, char *val); +int json_gen_obj_start_long_string(json_gen_str_t *jstr, const char *name, const char *val); /** Start a Long string in an array * @@ -469,7 +469,7 @@ int json_gen_obj_start_long_string(json_gen_str_t *jstr, char *name, char *val); * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data * added after that */ -int json_gen_arr_start_long_string(json_gen_str_t *jstr, char *val); +int json_gen_arr_start_long_string(json_gen_str_t *jstr, const char *val); /** Add to a JSON Long string * @@ -485,7 +485,7 @@ int json_gen_arr_start_long_string(json_gen_str_t *jstr, char *val); * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data * added after that */ -int json_gen_add_to_long_string(json_gen_str_t *jstr, char *val); +int json_gen_add_to_long_string(json_gen_str_t *jstr, const char *val); /** End a JSON Long string * diff --git a/lib/libesp32_div/ESP32-HomeKit/src/json_parser.c b/lib/libesp32_div/ESP32-HomeKit/src/json_parser.c index 65a915591..e6c47fb68 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/json_parser.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/json_parser.c @@ -23,7 +23,7 @@ #include #include -static bool token_matches_str(jparse_ctx_t *ctx, json_tok_t *tok, char *str) +static bool token_matches_str(jparse_ctx_t *ctx, json_tok_t *tok, const char *str) { char *js = ctx->js; return ((strncmp(js + tok->start, str, strlen(str)) == 0) @@ -100,7 +100,7 @@ static int json_tok_to_string(jparse_ctx_t *jctx, json_tok_t *tok, char *val, in return OS_SUCCESS; } -static json_tok_t *json_obj_search(jparse_ctx_t *jctx, char *key) +static json_tok_t *json_obj_search(jparse_ctx_t *jctx, const char *key) { json_tok_t *tok = jctx->cur; int size = tok->size; @@ -118,7 +118,7 @@ static json_tok_t *json_obj_search(jparse_ctx_t *jctx, char *key) return NULL; } -static json_tok_t *json_obj_get_val_tok(jparse_ctx_t *jctx, char *name, jsmntype_t type) +static json_tok_t *json_obj_get_val_tok(jparse_ctx_t *jctx, const char *name, jsmntype_t type) { json_tok_t *tok = json_obj_search(jctx, name); if (!tok) @@ -129,7 +129,7 @@ static json_tok_t *json_obj_get_val_tok(jparse_ctx_t *jctx, char *name, jsmntype return tok; } -int json_obj_get_array(jparse_ctx_t *jctx, char *name, int *num_elem) +int json_obj_get_array(jparse_ctx_t *jctx, const char *name, int *num_elem) { json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_ARRAY); if (!tok) @@ -153,7 +153,7 @@ int json_obj_leave_array(jparse_ctx_t *jctx) return OS_SUCCESS; } -int json_obj_get_object(jparse_ctx_t *jctx, char *name) +int json_obj_get_object(jparse_ctx_t *jctx, const char *name) { json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_OBJECT); if (!tok) @@ -176,7 +176,7 @@ int json_obj_leave_object(jparse_ctx_t *jctx) return OS_SUCCESS; } -int json_obj_get_bool(jparse_ctx_t *jctx, char *name, bool *val) +int json_obj_get_bool(jparse_ctx_t *jctx, const char *name, bool *val) { json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_PRIMITIVE); if (!tok) @@ -184,7 +184,7 @@ int json_obj_get_bool(jparse_ctx_t *jctx, char *name, bool *val) return json_tok_to_bool(jctx, tok, val); } -int json_obj_get_int(jparse_ctx_t *jctx, char *name, int *val) +int json_obj_get_int(jparse_ctx_t *jctx, const char *name, int *val) { json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_PRIMITIVE); if (!tok) @@ -192,7 +192,7 @@ int json_obj_get_int(jparse_ctx_t *jctx, char *name, int *val) return json_tok_to_int(jctx, tok, val); } -int json_obj_get_int64(jparse_ctx_t *jctx, char *name, int64_t *val) +int json_obj_get_int64(jparse_ctx_t *jctx, const char *name, int64_t *val) { json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_PRIMITIVE); if (!tok) @@ -200,7 +200,7 @@ int json_obj_get_int64(jparse_ctx_t *jctx, char *name, int64_t *val) return json_tok_to_int64(jctx, tok, val); } -int json_obj_get_float(jparse_ctx_t *jctx, char *name, float *val) +int json_obj_get_float(jparse_ctx_t *jctx, const char *name, float *val) { json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_PRIMITIVE); if (!tok) @@ -208,7 +208,7 @@ int json_obj_get_float(jparse_ctx_t *jctx, char *name, float *val) return json_tok_to_float(jctx, tok, val); } -int json_obj_get_string(jparse_ctx_t *jctx, char *name, char *val, int size) +int json_obj_get_string(jparse_ctx_t *jctx, const char *name, char *val, int size) { json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_STRING); if (!tok) @@ -216,7 +216,7 @@ int json_obj_get_string(jparse_ctx_t *jctx, char *name, char *val, int size) return json_tok_to_string(jctx, tok, val, size); } -int json_obj_get_strlen(jparse_ctx_t *jctx, char *name, int *strlen) +int json_obj_get_strlen(jparse_ctx_t *jctx, const char *name, int *strlen) { json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_STRING); if (!tok) @@ -225,7 +225,7 @@ int json_obj_get_strlen(jparse_ctx_t *jctx, char *name, int *strlen) return OS_SUCCESS; } -int json_obj_get_object_str(jparse_ctx_t *jctx, char *name, char *val, int size) +int json_obj_get_object_str(jparse_ctx_t *jctx, const char *name, char *val, int size) { json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_OBJECT); if (!tok) @@ -233,7 +233,7 @@ int json_obj_get_object_str(jparse_ctx_t *jctx, char *name, char *val, int size) return json_tok_to_string(jctx, tok, val, size); } -int json_obj_get_object_strlen(jparse_ctx_t *jctx, char *name, int *strlen) +int json_obj_get_object_strlen(jparse_ctx_t *jctx, const char *name, int *strlen) { json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_OBJECT); if (!tok) @@ -241,7 +241,7 @@ int json_obj_get_object_strlen(jparse_ctx_t *jctx, char *name, int *strlen) *strlen = tok->end - tok->start; return OS_SUCCESS; } -int json_obj_get_array_str(jparse_ctx_t *jctx, char *name, char *val, int size) +int json_obj_get_array_str(jparse_ctx_t *jctx, const char *name, char *val, int size) { json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_ARRAY); if (!tok) @@ -249,7 +249,7 @@ int json_obj_get_array_str(jparse_ctx_t *jctx, char *name, char *val, int size) return json_tok_to_string(jctx, tok, val, size); } -int json_obj_get_array_strlen(jparse_ctx_t *jctx, char *name, int *strlen) +int json_obj_get_array_strlen(jparse_ctx_t *jctx, const char *name, int *strlen) { json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_ARRAY); if (!tok) diff --git a/lib/libesp32_div/ESP32-HomeKit/src/json_parser.h b/lib/libesp32_div/ESP32-HomeKit/src/json_parser.h index 3e982fe14..42163d7fc 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/json_parser.h +++ b/lib/libesp32_div/ESP32-HomeKit/src/json_parser.h @@ -43,20 +43,20 @@ typedef struct { int json_parse_start(jparse_ctx_t *jctx, char *js, int len); int json_parse_end(jparse_ctx_t *jctx); -int json_obj_get_array(jparse_ctx_t *jctx, char *name, int *num_elem); +int json_obj_get_array(jparse_ctx_t *jctx, const char *name, int *num_elem); int json_obj_leave_array(jparse_ctx_t *jctx); -int json_obj_get_object(jparse_ctx_t *jctx, char *name); +int json_obj_get_object(jparse_ctx_t *jctx, const char *name); int json_obj_leave_object(jparse_ctx_t *jctx); -int json_obj_get_bool(jparse_ctx_t *jctx, char *name, bool *val); -int json_obj_get_int(jparse_ctx_t *jctx, char *name, int *val); -int json_obj_get_int64(jparse_ctx_t *jctx, char *name, int64_t *val); -int json_obj_get_float(jparse_ctx_t *jctx, char *name, float *val); -int json_obj_get_string(jparse_ctx_t *jctx, char *name, char *val, int size); -int json_obj_get_strlen(jparse_ctx_t *jctx, char *name, int *strlen); -int json_obj_get_object_str(jparse_ctx_t *jctx, char *name, char *val, int size); -int json_obj_get_object_strlen(jparse_ctx_t *jctx, char *name, int *strlen); -int json_obj_get_array_str(jparse_ctx_t *jctx, char *name, char *val, int size); -int json_obj_get_array_strlen(jparse_ctx_t *jctx, char *name, int *strlen); +int json_obj_get_bool(jparse_ctx_t *jctx, const char *name, bool *val); +int json_obj_get_int(jparse_ctx_t *jctx, const char *name, int *val); +int json_obj_get_int64(jparse_ctx_t *jctx, const char *name, int64_t *val); +int json_obj_get_float(jparse_ctx_t *jctx, const char *name, float *val); +int json_obj_get_string(jparse_ctx_t *jctx, const char *name, char *val, int size); +int json_obj_get_strlen(jparse_ctx_t *jctx, const char *name, int *strlen); +int json_obj_get_object_str(jparse_ctx_t *jctx, const char *name, char *val, int size); +int json_obj_get_object_strlen(jparse_ctx_t *jctx, const char *name, int *strlen); +int json_obj_get_array_str(jparse_ctx_t *jctx, const char *name, char *val, int size); +int json_obj_get_array_strlen(jparse_ctx_t *jctx, const char *name, int *strlen); int json_arr_get_array(jparse_ctx_t *jctx, uint32_t index); int json_arr_leave_array(jparse_ctx_t *jctx); diff --git a/lib/libesp32_div/ESP32-HomeKit/src/mu_srp.c b/lib/libesp32_div/ESP32-HomeKit/src/mu_srp.c index 7a14b93e0..0b7ad0b98 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/mu_srp.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/mu_srp.c @@ -447,7 +447,7 @@ int mu_srp_get_session_key(mu_srp_handle_t *hd, char *bytes_A, int len_A, char * return -1; } -int mu_srp_exchange_proofs(mu_srp_handle_t *hd, char *username, char *bytes_user_proof, char *bytes_host_proof) +int mu_srp_exchange_proofs(mu_srp_handle_t *hd, const char *username, char *bytes_user_proof, char *bytes_host_proof) { /* First calculate M */ unsigned char hash_n[SHA512HashSize]; diff --git a/lib/libesp32_div/ESP32-HomeKit/src/mu_srp.h b/lib/libesp32_div/ESP32-HomeKit/src/mu_srp.h index 8463ea318..80883bc77 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/mu_srp.h +++ b/lib/libesp32_div/ESP32-HomeKit/src/mu_srp.h @@ -84,7 +84,7 @@ int mu_srp_get_session_key(mu_srp_handle_t *hd, char *bytes_A, int len_A, char * * bytes_user_proof is parameter in * bytes_host_proof is parameter out (should be SHA512_DIGEST_LENGTH) bytes in size */ -int mu_srp_exchange_proofs(mu_srp_handle_t *hd, char *username, char *bytes_user_proof, char *bytes_host_proof); +int mu_srp_exchange_proofs(mu_srp_handle_t *hd, const char *username, char *bytes_user_proof, char *bytes_host_proof); diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum.h b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum.h index 5ead8cc6f..b6d6f1c1f 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum.h +++ b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum.h @@ -13,68 +13,8 @@ // limitations under the License. #pragma once -#include_next "mbedtls/bignum.h" -#include "sdkconfig.h" - -/** - * This is a wrapper for the main mbedtls/bignum.h. This wrapper - * provides a few additional ESP32-only functions. - * - * This is because we don't set MBEDTLS_BIGNUM_ALT in the same way we - * do for AES, SHA, etc. Because we still use most of the bignum.h - * implementation and just replace a few hardware accelerated - * functions (see MBEDTLS_MPI_EXP_MOD_ALT & MBEDTLS_MPI_MUL_MPI_ALT in - * esp_config.h). - * - * @note Unlike the other hardware accelerator support functions in esp32/hwcrypto, there is no - * generic "hwcrypto/bignum.h" header for using these functions without mbedTLS. The reason for this - * is that all of the function implementations depend strongly upon the mbedTLS MPI implementation. - */ - -/** - * @brief Lock access to RSA Accelerator (MPI/bignum operations) - * - * RSA Accelerator hardware unit can only be used by one - * consumer at a time. - * - * @note This function is non-recursive (do not call it twice from the - * same task.) - * - * @note You do not need to call this if you are using the mbedTLS bignum.h - * API or esp_mpi_xxx functions. This function is only needed if you - * want to call ROM RSA functions or access the registers directly. - * - */ -void esp_mpi_acquire_hardware(void); - -/** - * @brief Unlock access to RSA Accelerator (MPI/bignum operations) - * - * Has to be called once for each call to esp_mpi_acquire_hardware(). - * - * @note You do not need to call this if you are using the mbedTLS bignum.h - * API or esp_mpi_xxx functions. This function is only needed if you - * want to call ROM RSA functions or access the registers directly. - */ -void esp_mpi_release_hardware(void); - -//#if CONFIG_MBEDTLS_HARDWARE_MPI - -/* @brief MPI modular mupltiplication function - * - * Calculates Z = (X * Y) mod M using MPI hardware acceleration. - * - * This is not part of the standard mbedTLS bignum API. - * - * @note All of X, Y & Z should be less than 4096 bit long or an error is returned. - * - * @param Z Result bignum, should be pre-initialised with mbedtls_mpi_init(). - * @param X First multiplication argument. - * @param Y Second multiplication argument. - * @param M Modulus value for result. - * - * @return 0 on success, mbedTLS MPI error codes on failure. - */ -int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M); - -//#endif // CONFIG_MBEDTLS_HARDWARE_MPI +#if CONFIG_IDF_TARGET_ESP32 +#include "bignum_ESP32.h" +#elif CONFIG_IDF_TARGET_ESP32C3 +#include "bignum_ESP32_C3.h" +#endif diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum.c b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.c similarity index 98% rename from lib/libesp32_div/ESP32-HomeKit/src/port/bignum.c rename to lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.c index 5fab344e5..52d9554b5 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.c @@ -21,10 +21,11 @@ * */ +#if CONFIG_IDF_TARGET_ESP32 #if __has_include("esp_idf_version.h") #include "esp_idf_version.h" #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) -#warning("IDF is 4 or later") +// #warning("IDF is 4 or later") #include "soc/hwcrypto_periph.h" #endif #endif @@ -35,6 +36,9 @@ #include "bignum_impl.h" #include #include +#if CONFIG_IDF_TARGET_ESP32C3 +#include "esp32c3/dport_access.h" +#endif static _lock_t mpi_lock; @@ -284,3 +288,4 @@ void esp_mpi_mult_mpi_failover_mod_mult_hw_op(const mbedtls_mpi *X, const mbedtl start_op(RSA_MULT_START_REG); } +#endif //CONFIG_IDF_TARGET_ESP32 diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.h b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.h new file mode 100644 index 000000000..fa91a961f --- /dev/null +++ b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.h @@ -0,0 +1,82 @@ +// Copyright 2015-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. +#if CONFIG_IDF_TARGET_ESP32 +#pragma once + +#include_next "mbedtls/bignum.h" +#include "sdkconfig.h" + +/** + * This is a wrapper for the main mbedtls/bignum.h. This wrapper + * provides a few additional ESP32-only functions. + * + * This is because we don't set MBEDTLS_BIGNUM_ALT in the same way we + * do for AES, SHA, etc. Because we still use most of the bignum.h + * implementation and just replace a few hardware accelerated + * functions (see MBEDTLS_MPI_EXP_MOD_ALT & MBEDTLS_MPI_MUL_MPI_ALT in + * esp_config.h). + * + * @note Unlike the other hardware accelerator support functions in esp32/hwcrypto, there is no + * generic "hwcrypto/bignum.h" header for using these functions without mbedTLS. The reason for this + * is that all of the function implementations depend strongly upon the mbedTLS MPI implementation. + */ + +/** + * @brief Lock access to RSA Accelerator (MPI/bignum operations) + * + * RSA Accelerator hardware unit can only be used by one + * consumer at a time. + * + * @note This function is non-recursive (do not call it twice from the + * same task.) + * + * @note You do not need to call this if you are using the mbedTLS bignum.h + * API or esp_mpi_xxx functions. This function is only needed if you + * want to call ROM RSA functions or access the registers directly. + * + */ +void esp_mpi_acquire_hardware(void); + +/** + * @brief Unlock access to RSA Accelerator (MPI/bignum operations) + * + * Has to be called once for each call to esp_mpi_acquire_hardware(). + * + * @note You do not need to call this if you are using the mbedTLS bignum.h + * API or esp_mpi_xxx functions. This function is only needed if you + * want to call ROM RSA functions or access the registers directly. + */ +void esp_mpi_release_hardware(void); + +//#if CONFIG_MBEDTLS_HARDWARE_MPI + +/* @brief MPI modular mupltiplication function + * + * Calculates Z = (X * Y) mod M using MPI hardware acceleration. + * + * This is not part of the standard mbedTLS bignum API. + * + * @note All of X, Y & Z should be less than 4096 bit long or an error is returned. + * + * @param Z Result bignum, should be pre-initialised with mbedtls_mpi_init(). + * @param X First multiplication argument. + * @param Y Second multiplication argument. + * @param M Modulus value for result. + * + * @return 0 on success, mbedTLS MPI error codes on failure. + */ +int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M); + +//#endif // CONFIG_MBEDTLS_HARDWARE_MPI +#endif //CONFIG_IDF_TARGET_ESP32 diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.c b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.c new file mode 100644 index 000000000..a96d514b9 --- /dev/null +++ b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.c @@ -0,0 +1,108 @@ +/** + * \brief Multi-precision integer library, ESP-IDF hardware accelerated parts + * + * based on mbedTLS implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * Additions Copyright (C) 2016-2020, Espressif Systems (Shanghai) PTE Ltd + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + */ + +#if CONFIG_IDF_TARGET_ESP32C3 +#if __has_include("esp_idf_version.h") +#include "esp_idf_version.h" +#endif + +#include +#include "soc/hwcrypto_periph.h" +#include "driver/periph_ctrl.h" +#include "mbedtls/bignum.h" +#include "bignum_impl.h" +#include "soc/system_reg.h" +#include "soc/periph_defs.h" +#include "esp_crypto_lock.h" + +/* Copy mbedTLS MPI bignum 'mpi' to hardware memory block at 'mem_base'. + + If hw_words is higher than the number of words in the bignum then + these additional words will be zeroed in the memory buffer. + +*/ +static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, size_t num_words) +{ + uint32_t *pbase = (uint32_t *)mem_base; + uint32_t copy_words = MIN(num_words, mpi->n); + + /* Copy MPI data to memory block registers */ + for (int i = 0; i < copy_words; i++) { + pbase[i] = mpi->p[i]; + } + + /* Zero any remaining memory block data */ + for (int i = copy_words; i < num_words; i++) { + pbase[i] = 0; + } +} + +/* Read mbedTLS MPI bignum back from hardware memory block. + + Reads num_words words from block. + + Bignum 'x' should already be grown to at least num_words by caller (can be done while + calculation is in progress, to save some cycles) +*/ +static inline void mem_block_to_mpi(mbedtls_mpi *x, uint32_t mem_base, int num_words) +{ + + /* Copy data from memory block registers */ + const size_t REG_WIDTH = sizeof(uint32_t); + for (size_t i = 0; i < num_words; i++) { + x->p[i] = REG_READ(mem_base + (i * REG_WIDTH)); + } + /* Zero any remaining limbs in the bignum, if the buffer is bigger + than num_words */ + for (size_t i = num_words; i < x->n; i++) { + x->p[i] = 0; + } + +} + +/* Begin an RSA operation. op_reg specifies which 'START' register + to write to. +*/ +static inline void start_op(uint32_t op_reg) +{ + /* Clear interrupt status */ + REG_WRITE(RSA_CLEAR_INTERRUPT_REG, 1); + + /* Note: above REG_WRITE includes a memw, so we know any writes + to the memory blocks are also complete. */ + + REG_WRITE(op_reg, 1); +} + +/* Wait for an RSA operation to complete. +*/ +static inline void wait_op_complete(void) +{ + while (REG_READ(RSA_QUERY_INTERRUPT_REG) != 1) + { } + + /* clear the interrupt */ + REG_WRITE(RSA_CLEAR_INTERRUPT_REG, 1); +} + +#endif //CONFIG_IDF_TARGET_ESP32C3 diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.h b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.h new file mode 100644 index 000000000..333615c3f --- /dev/null +++ b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.h @@ -0,0 +1,87 @@ +// Copyright 2015-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. +#if CONFIG_IDF_TARGET_ESP32C3 +#pragma once + +#include_next "mbedtls/bignum.h" +#include "sdkconfig.h" + +/** + * This is a wrapper for the main mbedtls/bignum.h. This wrapper + * provides a few additional ESP32-only functions. + * + * This is because we don't set MBEDTLS_BIGNUM_ALT in the same way we + * do for AES, SHA, etc. Because we still use most of the bignum.h + * implementation and just replace a few hardware accelerated + * functions (see MBEDTLS_MPI_EXP_MOD_ALT & MBEDTLS_MPI_MUL_MPI_ALT in + * esp_config.h). + * + * @note Unlike the other hardware accelerator support functions in esp32/hwcrypto, there is no + * generic "hwcrypto/bignum.h" header for using these functions without mbedTLS. The reason for this + * is that all of the function implementations depend strongly upon the mbedTLS MPI implementation. + */ + +/** + * @brief Lock access to RSA Accelerator (MPI/bignum operations) + * + * RSA Accelerator hardware unit can only be used by one + * consumer at a time. + * + * @note This function is non-recursive (do not call it twice from the + * same task.) + * + * @note You do not need to call this if you are using the mbedTLS bignum.h + * API or esp_mpi_xxx functions. This function is only needed if you + * want to call ROM RSA functions or access the registers directly. + * + */ +void esp_mpi_acquire_hardware(void); + +/** + * @brief Unlock access to RSA Accelerator (MPI/bignum operations) + * + * Has to be called once for each call to esp_mpi_acquire_hardware(). + * + * @note You do not need to call this if you are using the mbedTLS bignum.h + * API or esp_mpi_xxx functions. This function is only needed if you + * want to call ROM RSA functions or access the registers directly. + */ +void esp_mpi_release_hardware(void); + +//#if CONFIG_MBEDTLS_HARDWARE_MPI + +/* @brief MPI modular mupltiplication function + * + * Calculates Z = (X * Y) mod M using MPI hardware acceleration. + * + * This is not part of the standard mbedTLS bignum API. + * + * @note All of X, Y & Z should be less than 4096 bit long or an error is returned. + * + * @param Z Result bignum, should be pre-initialised with mbedtls_mpi_init(). + * @param X First multiplication argument. + * @param Y Second multiplication argument. + * @param M Modulus value for result. + * + * @return 0 on success, mbedTLS MPI error codes on failure. + */ +int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M); + +void esp_mpi_mul_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t num_words); +static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, size_t num_words); +void esp_mpi_mul_mpi_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words); + + +//#endif // CONFIG_MBEDTLS_HARDWARE_MPI +#endif //CONFIG_IDF_TARGET_ESP32C3 diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_impl.h b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_impl.h index 0c70fa339..20943499b 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_impl.h +++ b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_impl.h @@ -10,7 +10,7 @@ exponentiation instead. */ -#define CONFIG_IDF_TARGET_ESP32 1 +// #define CONFIG_IDF_TARGET_ESP32 1 #if CONFIG_IDF_TARGET_ESP32 #define ESP_MPI_USE_MONT_EXP @@ -19,7 +19,7 @@ //#define MBEDTLS_MPI_MUL_MPI_ALT #endif - +#if CONFIG_IDF_TARGET_ESP32 int esp_mpi_exp_mod( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, mbedtls_mpi *_Rinv ); /** @@ -86,7 +86,11 @@ int esp_mont_hw_op(mbedtls_mpi* Z, const mbedtls_mpi* X, const mbedtls_mpi* Y, c * */ void esp_mpi_exp_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t hw_words); - +#endif //CONFIG_IDF_TARGET_ESP32 #endif //ESP_MPI_USE_MONT_EXP +#if CONFIG_IDF_TARGET_ESP32C3 +void esp_mpi_exp_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t num_words); +#endif //CONFIG_IDF_TARGET_ESP32C3 + #endif diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/esp_bignum.c b/lib/libesp32_div/ESP32-HomeKit/src/port/esp_bignum.c index 44e0a798c..2c0fb07ce 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/port/esp_bignum.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/port/esp_bignum.c @@ -23,7 +23,7 @@ #if __has_include("esp_idf_version.h") #include "esp_idf_version.h" #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) -#warning("IDF is 4 or later") +// #warning("IDF is 4 or later") #include "soc/hwcrypto_periph.h" #endif #endif @@ -79,7 +79,7 @@ static inline size_t bits_to_words(size_t bits) /* Return the number of words actually used to represent an mpi number. */ -#if defined(MBEDTLS_MPI_EXP_MOD_ALT) +#if defined(MBEDTLS_MPI_EXP_MOD_ALT) || defined(CONFIG_IDF_TARGET_ESP32C3) static size_t mpi_words(const mbedtls_mpi *mpi) { for (size_t i = mpi->n; i > 0; i--) { @@ -369,6 +369,87 @@ cleanup: #endif /* MBEDTLS_MPI_EXP_MOD_ALT */ +#if CONFIG_IDF_TARGET_ESP32C3 +int esp_mpi_exp_mod( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, mbedtls_mpi *_Rinv ) +{ + int ret = 0; + size_t x_words = mpi_words(X); + size_t y_words = mpi_words(Y); + size_t m_words = mpi_words(M); + + + /* "all numbers must be the same length", so choose longest number + as cardinal length of operation... + */ + size_t num_words = esp_mpi_hardware_words(MAX(m_words, MAX(x_words, y_words))); + + mbedtls_mpi Rinv_new; /* used if _Rinv == NULL */ + mbedtls_mpi *Rinv; /* points to _Rinv (if not NULL) othwerwise &RR_new */ + mbedtls_mpi_uint Mprime; + + if (mbedtls_mpi_cmp_int(M, 0) <= 0 || (M->p[0] & 1) == 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (mbedtls_mpi_cmp_int(Y, 0) < 0) { + return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + } + + if (mbedtls_mpi_cmp_int(Y, 0) == 0) { + return mbedtls_mpi_lset(Z, 1); + } + + if (num_words * 32 > SOC_RSA_MAX_BIT_LEN) { + return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + } + + /* Determine RR pointer, either _RR for cached value + or local RR_new */ + if (_Rinv == NULL) { + mbedtls_mpi_init(&Rinv_new); + Rinv = &Rinv_new; + } else { + Rinv = _Rinv; + } + if (Rinv->p == NULL) { + MBEDTLS_MPI_CHK(calculate_rinv(Rinv, M, num_words)); + } + + Mprime = modular_inverse(M); + + // Montgomery exponentiation: Z = X ^ Y mod M (HAC 14.94) +#ifdef ESP_MPI_USE_MONT_EXP + ret = mpi_montgomery_exp_calc(Z, X, Y, M, Rinv, num_words, Mprime) ; + MBEDTLS_MPI_CHK(ret); +#else + esp_mpi_enable_hardware_hw_op(); + + esp_mpi_exp_mpi_mod_hw_op(X, Y, M, Rinv, Mprime, num_words); + ret = mbedtls_mpi_grow(Z, m_words); + if (ret != 0) { + esp_mpi_disable_hardware_hw_op(); + goto cleanup; + } + esp_mpi_read_result_hw_op(Z, m_words); + esp_mpi_disable_hardware_hw_op(); +#endif + + // Compensate for negative X + if (X->s == -1 && (Y->p[0] & 1) != 0) { + Z->s = -1; + MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(Z, M, Z)); + } else { + Z->s = 1; + } + +cleanup: + if (_Rinv == NULL) { + mbedtls_mpi_free(&Rinv_new); + } + return ret; +} +#endif //CONFIG_IDF_TARGET_ESP32C3 + #if defined(MBEDTLS_MPI_MUL_MPI_ALT) /* MBEDTLS_MPI_MUL_MPI_ALT */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/shatest.c b/lib/libesp32_div/ESP32-HomeKit/src/shatest.c index 3924a31d5..f2c9232b3 100644 --- a/lib/libesp32_div/ESP32-HomeKit/src/shatest.c +++ b/lib/libesp32_div/ESP32-HomeKit/src/shatest.c @@ -781,11 +781,11 @@ void printstr(const char *str, int len) */ void printxstr(const char *str, int len) { - char *sep = ""; + char sep[2] = {0}; for ( ; len-- > 0; str++) { printf("%s%c%c", sep, hexdigits[(*str >> 4) & 0xF], hexdigits[*str & 0xF]); - sep = " "; + sep[0] = ' '; } } @@ -866,7 +866,7 @@ void printResult(uint8_t *Message_Digest, int hashsize, putchar('\n'); } else if (printResults == PRINTBASE64) { unsigned char b; - char *sm = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + const char *sm = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789+/"; for (i = 0; i < hashsize; i += 3) { putchar(sm[Message_Digest[i] >> 2]); diff --git a/pio-tools/add_c_flags.py b/pio-tools/add_c_flags.py deleted file mode 100644 index c93059b36..000000000 --- a/pio-tools/add_c_flags.py +++ /dev/null @@ -1,4 +0,0 @@ -Import("env") - -# General options that are passed to the C compiler (C only; not C++). -env.Append(CFLAGS=["-Wno-discarded-qualifiers"]) diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 81f1dbded..5d3175b06 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -89,9 +89,9 @@ lib_extra_dirs = ${library.lib_extra_dirs} [env:tasmota32_base] -; *** Uncomment next lines ";" to enable Beta Tasmota Arduino version ESP32 IDF4.4 +; *** Uncomment next lines ";" to enable development Tasmota Arduino version ESP32 ;platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-idf-master -;platform_packages = framework-arduinoespressif32 @ https://github.com/tasmota/arduino-esp32/releases/download/2.0.1rc1/framework-arduinoespressif32-release_IDF4.4.tar.gz +;platform_packages = framework-arduinoespressif32 @ https://github.com/tasmota/arduino-esp32/releases/download/2.0.1/framework-arduinoespressif32-release_IDF4.4.tar.gz ; platformio/tool-esptoolpy @ https://github.com/tasmota/esptool/releases/download/v3.2/esptool-v3.2.zip ; platformio/tool-mklittlefs @ ~1.203.200522 build_unflags = ${esp32_defaults.build_unflags} diff --git a/platformio_tasmota32.ini b/platformio_tasmota32.ini index 64e78a073..f832417ea 100644 --- a/platformio_tasmota32.ini +++ b/platformio_tasmota32.ini @@ -2,9 +2,15 @@ [esp32_defaults] build_unflags = ${esp_defaults.build_unflags} + -Wswitch-unreachable + -Wstringop-overflow + -Wincompatible-pointer-types + -Wnonnull-compare -fexceptions -Wpointer-arith build_flags = ${esp_defaults.build_flags} + -Wno-switch-unreachable + -Wno-stringop-overflow -fno-exceptions -DBUFFER_LENGTH=128 -DHTTP_UPLOAD_BUFLEN=2048 @@ -26,9 +32,8 @@ build_flags = ${esp_defaults.build_flags} -Wl,--wrap=panicHandler -Wl,--wrap=xt_unhandled_exception [core32] -platform = espressif32 @ 3.3.1 -platform_packages = framework-arduinoespressif32 @ https://github.com/tasmota/arduino-esp32/releases/download/1.0.7.5/tasmota-arduinoespressif32-release_v3.3.5.tar.gz - platformio/toolchain-xtensa32 @ ~2.50200.0 +platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-idf-master +platform_packages = framework-arduinoespressif32 @ https://github.com/tasmota/arduino-esp32/releases/download/2.0.1.1/framework-arduinoespressif32-release_IDF4.4.tar.gz platformio/tool-esptoolpy @ https://github.com/tasmota/esptool/releases/download/v3.2/esptool-v3.2.zip platformio/tool-mklittlefs @ ~1.203.200522 build_unflags = ${esp32_defaults.build_unflags} @@ -36,10 +41,9 @@ build_flags = ${esp32_defaults.build_flags} [core32solo1] -platform = espressif32 @ 3.3.1 -platform_packages = framework-arduinoespressif32 @ https://github.com/tasmota/arduino-esp32/releases/download/1.0.7.5/tasmota-arduinoespressif32-solo1-release_v3.3.5.tar.gz - platformio/toolchain-xtensa32 @ ~2.50200.0 +platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-idf-master +platform_packages = framework-arduinoespressif32 @ https://github.com/tasmota/arduino-esp32/releases/download/2.0.1.1/framework-arduinoespressif32-solo1-release_IDF4.4.tar.gz platformio/tool-esptoolpy @ https://github.com/tasmota/esptool/releases/download/v3.2/esptool-v3.2.zip platformio/tool-mklittlefs @ ~1.203.200522 build_unflags = ${esp32_defaults.build_unflags} -build_flags = ${esp32_defaults.build_flags} \ No newline at end of file +build_flags = ${esp32_defaults.build_flags} diff --git a/platformio_tasmota_cenv_sample.ini b/platformio_tasmota_cenv_sample.ini index d3733589e..ea5114455 100644 --- a/platformio_tasmota_cenv_sample.ini +++ b/platformio_tasmota_cenv_sample.ini @@ -1,24 +1,14 @@ -; *** Tasmota32 development core version ESP32 IDF4.4 -[env:tasmota32-dev] -extends = env:tasmota32idf4 -platform_packages = framework-arduinoespressif32 @ https://github.com/Jason2866/esp32-arduino-lib-builder/releases/download/516/framework-arduinoespressif32-release_v4.4-432c3c78c.tar.gz - platformio/tool-esptoolpy @ https://github.com/tasmota/esptool/releases/download/v3.2/esptool-v3.2.zip - platformio/tool-mklittlefs @ ~1.203.200522 -build_flags = ${env:tasmota32idf4.build_flags} - -D FIRMWARE_TASMOTA32 - ;*** Beta Tasmota version for ESP32-S2 -;*** Example how to override the standard core with [tasmota32-dev] core [env:tasmota32s2] -extends = env:tasmota32-dev -platform_packages = ${env:tasmota32-dev.platform_packages} +extends = env:tasmota32_base board = esp32s2 -build_flags = ${env:tasmota32idf4.build_flags} - -D FIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -D FIRMWARE_TASMOTA32 lib_ignore = ESP8266Audio ESP8266SAM TTGO TWatch Library + NimBLE-Arduino + epdiy [env:tasmota-rangeextender] build_flags = ${env.build_flags} @@ -28,8 +18,8 @@ build_flags = ${env.build_flags} -D USE_WIFI_RANGE_EXTENDER_NAPT [env:tasmota32-rangeextender] -extends = env:tasmota32idf4 -build_flags = ${env:tasmota32idf4.build_flags} +extends = env:tasmota32_base +build_flags = ${env:tasmota32_base.build_flags} -D FIRMWARE_TASMOTA32 -D USE_WIFI_RANGE_EXTENDER -D USE_WIFI_RANGE_EXTENDER_NAPT diff --git a/platformio_tasmota_env32.ini b/platformio_tasmota_env32.ini index 00c00281a..380fac213 100644 --- a/platformio_tasmota_env32.ini +++ b/platformio_tasmota_env32.ini @@ -33,23 +33,6 @@ lib_ignore = ; Disable next if you want to use ArduinoOTA in Tasmota32 (default disabled) ArduinoOTA -[env:tasmota32idf4] -extends = env:tasmota32_base -platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-idf-master -platform_packages = framework-arduinoespressif32 @ https://github.com/tasmota/arduino-esp32/releases/download/2.0.1rc1/framework-arduinoespressif32-release_IDF4.4.tar.gz - platformio/tool-esptoolpy @ https://github.com/tasmota/esptool/releases/download/v3.2/esptool-v3.2.zip - platformio/tool-mklittlefs @ ~1.203.200522 -build_unflags = ${env:tasmota32_base.build_unflags} - -Wswitch-unreachable - -Wstringop-overflow - -Wincompatible-pointer-types - -Wnonnull-compare -build_flags = ${env:tasmota32_base.build_flags} - -Wno-switch-unreachable - -Wno-stringop-overflow -extra_scripts = ${env:tasmota32_base.extra_scripts} - pio-tools/add_c_flags.py - [env:tasmota32] extends = env:tasmota32_base build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_TASMOTA32 @@ -78,13 +61,12 @@ lib_extra_dirs = lib/libesp32 [env:tasmota32-odroidgo] extends = env:tasmota32_base board = esp32-odroid -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_ODROID_GO -lib_extra_dirs = lib/libesp32, lib/lib_basic, lib/lib_i2c, lib/lib_rf, lib/lib_div, lib/lib_ssl, lib/lib_display +build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_ODROID_GO -DUSE_UNIVERSAL_DISPLAY -DUSE_AUTOCONF [env:tasmota32-core2] extends = env:tasmota32_base board = esp32-m5core2 -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_M5STACK_CORE2 -DUSE_UNIVERSAL_DISPLAY +build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_M5STACK_CORE2 -DUSE_UNIVERSAL_DISPLAY -DUSE_AUTOCONF 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 [env:tasmota32-bluetooth] @@ -99,7 +81,7 @@ lib_extra_dirs = lib/libesp32, lib/lib_basic, lib/lib_display [env:tasmota32-lvgl] extends = env:tasmota32_base -build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_LVGL +build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_LVGL -DUSE_AUTOCONF board_build.f_cpu = 160000000L 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 @@ -109,24 +91,15 @@ build_flags = ${env:tasmota32_base.build_flags} -DUSE_IR_REMOTE_FULL lib_extra_dirs = lib/libesp32, lib/lib_basic [env:tasmota32c3] -extends = env:tasmota32idf4 +extends = env:tasmota32_base board = esp32c3 -platform = ${env:tasmota32idf4.platform} -platform_packages = ${env:tasmota32idf4.platform_packages} -build_unflags = ${env:tasmota32idf4.build_unflags} +build_unflags = ${env:tasmota32_base.build_unflags} -mtarget-align - -DNDEBUG -build_flags = ${env:tasmota32idf4.build_flags} -; *** Comment next two lines to disable BLE -; -DUSE_BLE_ESP32 -; -DUSE_MI_ESP32 - ;-DESP32_STAGE=true - -DFIRMWARE_TASMOTA32 +build_flags = ${env:tasmota32_base.build_flags} -DFIRMWARE_TASMOTA32 lib_ignore = ESP8266Audio ESP8266SAM TTGO TWatch Library - ESP32-HomeKit Micro-RTSP epdiy diff --git a/tasmota/berry/drivers/i2c_axp192_M5StickC.be b/tasmota/berry/drivers/i2c_axp192_M5StickC.be index 9d38bea3a..2d0c63d24 100644 --- a/tasmota/berry/drivers/i2c_axp192_M5StickC.be +++ b/tasmota/berry/drivers/i2c_axp192_M5StickC.be @@ -85,6 +85,19 @@ class AXP192_M5StickC : AXP192 def set_lcd_reset(state) self.set_ldo_enable(3, state) end + + # Dimmer in percentage + def set_displaydimmer(x) + var v = tasmota.scale_uint(x, 0, 100, 2500, 3300) + self.set_lcd_voltage(v) + end + + # respond to display events + def display(cmd, idx, payload, raw) + if cmd == "dim" || cmd == "power" + self.set_displaydimmer(idx) + end + end end axp = AXP192_M5StickC() diff --git a/tasmota/berry/leds/rainbow.be b/tasmota/berry/leds/rainbow.be new file mode 100644 index 000000000..bb7a4f105 --- /dev/null +++ b/tasmota/berry/leds/rainbow.be @@ -0,0 +1,183 @@ +# simple Rainbow animator + +#- +# Ex: if WS2812 configured to WS2812 - channel 2 + +var strip = neopixelbus(25, gpio.pin(gpio.WS2812, 1)) +rainbow = Rainbow(strip) +rainbow.start() + +-# + +import animate + +# https://stackoverflow.com/questions/34187171/fast-integer-square-root-approximation +def fast_sqrt_int(val) + var a, b + + if val < 2 return val end + + a = 1255 # starting point is relatively unimportant + + b = val / a; a = (a+b) /2; + b = val / a; a = (a+b) /2; + b = val / a; a = (a+b) /2; + b = val / a; a = (a+b) /2; + b = val / a; a = (a+b) /2; + b = val / a; a = (a+b) /2; + if (val < 20000) + b = val / a; a = (a+b) /2; + b = val / a; a = (a+b) /2; + end + + return a +end + +class Rainbow : Leds_animator + var cur_offset # current offset in the palette + static palette = [ 0xFF0000, #- red -# + 0xFFA500, #- orange -# + 0xFFFF00, #- yellow -# + 0x008800, #- green -# + 0x0000FF, #- blue -# + 0x4B0082, #- indigo -# + 0xEE82EE, #- violet -# + ] + + def init(strip, duration) + super(self).init(strip) + self.cur_offset = 0 + # add an animator to change `self.cur_offset` to each value of the palette + self.add_anim(animate.rotate(def(v) self.cur_offset = v end, 0, size(self.palette), int(duration * 1000))) + end + + def animate() + # move instance variables to registers to avoid GETMBR inside the loop + var cur_offset = self.cur_offset + var modulus = size(self.palette) + var palette = self.palette + var strip = self.strip + var bri = self.bri + var set_pixel_color = strip.set_pixel_color + + var i = 0 + while i < self.pixel_count # doing a loop rather than a `for` prevents from allocating a new object + var col = palette[(cur_offset + i) % modulus] + set_pixel_color(strip, i, col, bri) # simulate the method call without GETMET + i += 1 + end + strip.show() + end + +end + +#- + +var strip = Leds_matrix(5,5, gpio.pin(gpio.WS2812, 1)) +var r = Rainbow(strip, 1.0) +r.start() + +-# + +class Rainbow_stripes : Leds_animator + var cur_offset # current offset in the palette + static palette = [ 0xFF0000, #- red -# + 0xFFA500, #- orange -# + 0xFFFF00, #- yellow -# + 0x008800, #- green -# + 0x0000FF, #- blue -# + 0x4B0082, #- indigo -# + 0xEE82EE, #- violet -# + ] + + def init(strip, duration) + super(self).init(strip) + self.cur_offset = 0 + # add an animator to change `self.cur_offset` to each value of the palette + self.add_anim(animate.rotate(def(v) self.cur_offset = v end, 0, size(self.palette), int(duration * 1000))) + end + + def animate() + # move instance variables to registers to avoid GETMBR inside the loop + var cur_offset = self.cur_offset + var modulus = size(self.palette) + var palette = self.palette + var strip = self.strip + var bri = self.bri + var set_matrix_pixel_color = strip.set_matrix_pixel_color + var h = self.strip.h + var w = self.strip.w + + var y = 0 + while y < h + var x = 0 + var col = palette[(cur_offset + y) % modulus] + while x < w + set_matrix_pixel_color(strip, x, y, col, bri) # simulate the method call without GETMET + x += 1 + end + y += 1 + end + strip.show() + end + +end + +#- + +var strip = Leds_matrix(5,5, gpio.pin(gpio.WS2812, 1)) +var r = Rainbow_Matrix(strip, 0.5) +r.start() + +-# + +class Round : Leds_animator + var cur_val + var min_val, max_val + var incr_val + var h + + def init(strip, glow_duration, color_duration) + super(self).init(strip) + self.cur_val = 5 << 8 + self.h = 0 # start with hue = 0 (red) + # add animator for color over 30 colors + self.add_anim(animate.rotate(def(h) self.h = h end, 0, 359, int(color_duration * 1000))) + self.add_anim(animate.back_forth(def(v) self.cur_val = v end, 2 << 8, 6 << 8, int(glow_duration * 1000))) + end + + def animate() + # move instance variables to registers to avoid GETMBR inside the loop + var strip = self.strip + var bri = self.bri + var set_matrix_pixel_color = strip.set_matrix_pixel_color + var h = self.strip.h + var w = self.strip.w + var ch = h / 2 + var cw = w / 2 + var col_ref = tasmota.hs2rgb(self.h) + + var y = 0 + while y < h + var x = 0 + while x < w + var col = col_ref + var dist = fast_sqrt_int( ((y - ch)*(y - ch) + (x - cw)*(x - cw)) << 16) + var rel_bri = tasmota.scale_uint(dist, 0, self.cur_val, bri, 0) + set_matrix_pixel_color(strip, x, y, col, rel_bri) # simulate the method call without GETMET + x += 1 + end + y += 1 + end + strip.show() + end + +end + +#- + +var strip = Leds_matrix(5,5, gpio.pin(gpio.WS2812, 1)) +var r = Round(strip, 2, 30) +r.start() + +-# \ No newline at end of file diff --git a/tasmota/berry/modules/partition.bec b/tasmota/berry/modules/partition.bec index 48ce1d2ab..8a2f56cd3 100644 Binary files a/tasmota/berry/modules/partition.bec and b/tasmota/berry/modules/partition.bec differ diff --git a/tasmota/homekit.c b/tasmota/homekit.c index 92e19543c..55d71c239 100755 --- a/tasmota/homekit.c +++ b/tasmota/homekit.c @@ -38,7 +38,7 @@ #include #include #include - +#include #include @@ -703,9 +703,9 @@ nextline: #define HK_PASSCODE "111-11-111" int hap_loop_stop(void); +int32_t homekit_pars(uint32_t sel); - -void homekit_main(char *desc, uint32_t flag ) { +int32_t homekit_main(char *desc, uint32_t flag ) { if (desc) { char *cp = desc; cp += 2; @@ -724,7 +724,7 @@ void homekit_main(char *desc, uint32_t flag ) { } if (*cp != '\n') { printf("init error\n"); - return; + return -1; } cp++; hk_desc = cp; @@ -736,17 +736,44 @@ void homekit_main(char *desc, uint32_t flag ) { hap_loop_stop(); // is just the folder in wrapper hap_platfrom_keystore_erase_partition(hap_platform_keystore_get_nvs_partition_name()); + } else if (flag < 3) { + return homekit_pars(flag); } else { hap_loop_stop(); } - return; + + return 0; } - if (!hk_desc) return; + if (!hk_desc) return -2; /* Create the application thread */ xTaskCreate(smart_outlet_thread_entry, SMART_OUTLET_TASK_NAME, SMART_OUTLET_TASK_STACKSIZE, NULL, SMART_OUTLET_TASK_PRIORITY, NULL); + return 0; +} + +#include + +int32_t homekit_pars(uint32_t sel) { + + if (sel == 0) { + // return CONFIG_LWIP_MAX_SOCKETS; + return MEMP_NUM_NETCONN; + } else if (sel == 1) { + return LWIP_SOCKET_OFFSET; + } else { + struct sockaddr name; + socklen_t len = sizeof(name); + uint8_t open_socs = 0; + for (uint32_t cnt = 0; cnt < CONFIG_LWIP_MAX_SOCKETS; cnt++) { + //if (!getsockname(cnt, &name, &len)) { + if (!getpeername(LWIP_SOCKET_OFFSET + cnt, &name, &len)) { + open_socs++; + } + } + return open_socs; + } } #endif // ESP32 diff --git a/tasmota/i18n.h b/tasmota/i18n.h index 9c8aed881..2e31ff08d 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -477,6 +477,7 @@ #define D_CMND_FADE "Fade" #define D_CMND_PALETTE "Palette" #define D_CMND_PIXELS "Pixels" +#define D_CMND_STEPPIXELS "StepPixels" #define D_CMND_RGBWWTABLE "RGBWWTable" #define D_CMND_ROTATION "Rotation" #define D_CMND_SCHEME "Scheme" @@ -692,6 +693,9 @@ #define D_CMND_SHUTTER_INVERTWEBBUTTONS "InvertWebButtons" #define D_CMND_SHUTTER_PWMRANGE "PWMRange" #define D_CMND_SHUTTER_UNITTEST "UnitTest" +#define D_CMND_SHUTTER_TILTCONFIG "TiltConfig" +#define D_CMND_SHUTTER_SETTILT "Tilt" +#define D_CMND_SHUTTER_TILTINCDEC "TiltChange" // Commands xdrv_32_hotplug.ino #define D_CMND_HOTPLUG "HotPlug" diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index 4c8478ea0..d4015f984 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -249,7 +249,7 @@ #define D_REDIRECTED "Пренасочено към портала за настройка" #define D_WIFIMANAGER_SET_ACCESSPOINT_AND_STATION "Wifimanager set AccessPoint and keep Station" #define D_WIFIMANAGER_SET_ACCESSPOINT "Wifimanager set AccessPoint" -#define D_TRYING_TO_CONNECT "Извършва се опит за свързване на устройството към мрежата" +#define D_TRYING_TO_CONNECT "Oпит за свързване към избраната мрежа" #define D_RESTART_IN "Рестарт след" #define D_SECONDS "секунди" @@ -336,7 +336,7 @@ #define D_SINGLE_DEVICE "едно устройство" #define D_MULTI_DEVICE "много устройства" -#define D_CONFIGURE_TEMPLATE "Настройка на шаблона" +#define D_CONFIGURE_TEMPLATE "Настройки на шаблона" #define D_TEMPLATE_PARAMETERS "Параметри на шаблона" #define D_TEMPLATE_NAME "Име" #define D_BASE_TYPE "Основан на" @@ -364,7 +364,7 @@ #define D_ESP_CHIP_ID "ID на чипа на ESP" #define D_FLASH_CHIP_ID "ID на чипа на флаш-паметта" #define D_FLASH_CHIP_SIZE "Размер на флаш-паметта" -#define D_FREE_PROGRAM_SPACE "Свободно пространство за програми" +#define D_FREE_PROGRAM_SPACE "Свободно място за програми" #define D_UPGRADE_BY_WEBSERVER "Обновяване от сървър" #define D_OTA_URL "Адрес на сървър за OTA" @@ -376,7 +376,7 @@ #define D_UPLOAD_TRANSFER "Upload transfer" #define D_TRANSFER_STARTED "Transfer started" #define D_UPLOAD_ERR_1 "Не е избран файл" -#define D_UPLOAD_ERR_2 "Недостатъчно свободно пространство" +#define D_UPLOAD_ERR_2 "Недостатъчно свободно място" #define D_UPLOAD_ERR_3 "Недействителен подпис на файла" #define D_UPLOAD_ERR_4 "Размерът на програмата е по-голям от размера на флаш-паметта" #define D_UPLOAD_ERR_5 "Грешка при сравняване на буфери" @@ -413,11 +413,11 @@ #define D_WEMO_BASIC_EVENT "Основно събитие на WeMo" #define D_WEMO_EVENT_SERVICE "Услуга за събития на WeMo" #define D_WEMO_META_SERVICE "Мета-услуга на WeMo" -#define D_WEMO_SETUP "Настройка на WeMo" +#define D_WEMO_SETUP "Настройки на WeMo" #define D_RESPONSE_SENT "Отговорът е изпратен" #define D_HUE "Hue" -#define D_HUE_BRIDGE_SETUP "Настройка на Hue" +#define D_HUE_BRIDGE_SETUP "Настройки на Hue" #define D_HUE_API_NOT_IMPLEMENTED "ППИ на Hue не е реализиран" #define D_HUE_API "ППИ на Hue" #define D_HUE_POST_ARGS "Параметри на Hue по POST" @@ -442,18 +442,18 @@ #define D_DOMOTICZ_UPDATE_TIMER "Период на обновяване" // xdrv_09_timers.ino -#define D_CONFIGURE_TIMER "Настройка на графика" +#define D_CONFIGURE_TIMER "Настройки на график" #define D_TIMER_PARAMETERS "Параметри на графиците" #define D_TIMER_ENABLE "Използване на графици" #define D_TIMER_ARM "Включване" #define D_TIMER_TIME "Време" #define D_TIMER_DAYS "Дни" -#define D_TIMER_REPEAT "Периодичен" +#define D_TIMER_REPEAT "Повтаряне" #define D_TIMER_OUTPUT "Изход" #define D_TIMER_ACTION "Действие" // xdrv_10_knx.ino -#define D_CONFIGURE_KNX "Настройка на KNX" +#define D_CONFIGURE_KNX "Настройки на KNX" #define D_KNX_PARAMETERS "Параметри на KNX" #define D_KNX_GENERAL_CONFIG "Основни" #define D_KNX_PHYSICAL_ADDRESS "Физически адрес" @@ -513,7 +513,7 @@ #define D_DOMOTICZ_SHUTTER "Щора" // xdrv_28_pcf8574.ino -#define D_CONFIGURE_PCF8574 "Настройка на PCF8574" +#define D_CONFIGURE_PCF8574 "Настройки на PCF8574" #define D_PCF8574_PARAMETERS "Параметри на PCF8574" #define D_INVERT_PORTS "Размяна на портовете" #define D_DEVICE "Устройство" @@ -563,7 +563,7 @@ #define D_HX_CAL_DONE "Калибрирано" #define D_HX_CAL_FAIL "Грешка при калибриране" #define D_RESET_HX711 "Нулиране на везната" -#define D_CONFIGURE_HX711 "Настройка на везната" +#define D_CONFIGURE_HX711 "Настройки на везната" #define D_HX711_PARAMETERS "Параметри на везната" #define D_ITEM_WEIGHT "Тегло" #define D_REFERENCE_WEIGHT "Еталонна тежест" @@ -608,7 +608,7 @@ // tasmota_template.h - keep them as short as possible to be able to fit them in GUI drop down box #define D_SENSOR_NONE "Няма" -#define D_SENSOR_USER "Потребител" +#define D_SENSOR_USER "Потребителско" #define D_SENSOR_OPTION "Настройки" #define D_SENSOR_DHT11 "DHT11" #define D_SENSOR_AM2301 "AM2301" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 2640d3de5..bf887ff19 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -79,7 +79,7 @@ #define WIFI_CONFIG_TOOL WIFI_RETRY // [WifiConfig] Default tool if Wi-Fi fails to connect (default option: 4 - WIFI_RETRY) // (WIFI_RESTART, WIFI_MANAGER, WIFI_RETRY, WIFI_WAIT, WIFI_SERIAL, WIFI_MANAGER_RESET_ONLY) // The configuration can be changed after first setup using WifiConfig 0, 2, 4, 5, 6 and 7. -#define WIFI_ARP_INTERVAL 0 // [SetOption41] Send gratuitous ARP interval +#define WIFI_ARP_INTERVAL 60 // [SetOption41] Send gratuitous ARP interval #define WIFI_SCAN_AT_RESTART false // [SetOption56] Scan Wi-Fi network at restart for configured AP's #define WIFI_SCAN_REGULARLY true // [SetOption57] Scan Wi-Fi network every 44 minutes for configured AP's @@ -658,6 +658,7 @@ // #define USE_AM2320 // [I2cDriver60] Enable AM2320 temperature and humidity Sensor (I2C address 0x5C) (+1k code) // #define USE_T67XX // [I2cDriver61] Enable Telaire T67XX CO2 sensor (I2C address 0x15) (+1k3 code) // #define USE_HM330X // [I2cDriver63] Enable support for SeedStudio Grove Particule sensor (I2C address 0x40) (+1k5 code) +// #define USE_HDC2010 // [I2cDriver64] Enable HDC2010 temperature/humidity sensor (I2C address 0x40) (+1k5 code) // #define HM330X_DEFAULT_ADDRESS 0x40 // Option: change default I2C address for HM330X used in SeedSTudio Particucle Sensor // #define HM330X_WARMUP_DELAY 30 // Option: change warmup delay during which data are not read from sensor after a power up // #define HM330X_HIDE_OUT_OF_DATE false // Option: change to true to hide data from web GUI and SENSOR while sensor is asleep @@ -703,7 +704,6 @@ #define USE_DISPLAY_ILI9341 // [DisplayModel 4] Enable ILI9341 Tft 480x320 display (+19k code) // #define USE_DISPLAY_EPAPER_29 // [DisplayModel 5] Enable e-paper 2.9 inch display (+19k code) // #define USE_DISPLAY_EPAPER_42 // [DisplayModel 6] Enable e-paper 4.2 inch display -// #define USE_DISPLAY_ILI9488 // [DisplayModel 8] [I2cDriver38] (Touch) // #define USE_DISPLAY_SSD1351 // [DisplayModel 9] Enable SSD1351 module // #define USE_DISPLAY_RA8876 // [DisplayModel 10] [I2cDriver39] (Touch) // #define USE_DISPLAY_ST7789 // [DisplayModel 12] Enable ST7789 module @@ -989,6 +989,7 @@ //#define USE_IBEACON_ESP32 //#define USE_WEBCAM // Add support for webcam +// #define USE_AUTOCONF // Enable Esp32 autoconf feature, requires USE_BERRY and USE_WEBCLIENT_HTTPS (12KB Flash) #define USE_BERRY // Enable Berry scripting language #define USE_BERRY_PYTHON_COMPAT // Enable by default `import python_compat` #define USE_BERRY_TIMEOUT 4000 // Timeout in ms, will raise an exception if running time exceeds this timeout @@ -1090,6 +1091,19 @@ #error "Select either USE_RULES or USE_SCRIPT. They can't both be used at the same time" #endif +/*********************************************************************************************\ + * Post-process compile options for Autoconf +\*********************************************************************************************/ + +#if defined(USE_AUTOCONF) + #ifndef USE_BERRY + #define USE_BERRY + #endif + #ifndef USE_WEBCLIENT_HTTPS + #define USE_WEBCLIENT_HTTPS + #endif +#endif // USE_AUTOCONF + /*********************************************************************************************\ * Post-process compile options for TLS \*********************************************************************************************/ diff --git a/tasmota/settings.h b/tasmota/settings.h index d16568768..c75842aac 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -524,7 +524,7 @@ typedef struct { uint8_t ex_switchmode[8]; // 3A4 - Free since 9.2.0.6 - myio my_gp; // 3AC 2 x 18 bytes (ESP8266) / 2 x 40 bytes (ESP32) / 2 x 22 bytes (ESP32-C3) + myio my_gp; // 3AC 2x18 bytes (ESP8266) / 2x40 bytes (ESP32) / 2x22 bytes (ESP32-C3) / 2x47 bytes (ESP32-S2) #ifdef ESP8266 uint16_t gpio16_converted; // 3D0 uint8_t free_esp8266_3D2[42]; // 3D2 @@ -534,7 +534,7 @@ typedef struct { uint8_t free_esp32c3_3D8[36]; // 3D8 - Due to smaller myio #endif // CONFIG_IDF_TARGET_ESP32C3 #endif // ESP32 - mytmplt user_template; // 3FC 2 x 15 bytes (ESP8266) / 2 x 37 bytes (ESP32) / 2 x 23 bytes (ESP32-C3) + mytmplt user_template; // 3FC 2x15 bytes (ESP8266) / 2x37 bytes (ESP32) / 2x23 bytes (ESP32-C3) / 2x37 bytes (ESP32-S2) #ifdef ESP8266 uint8_t free_esp8266_41A[55]; // 41A #endif // ESP8266 @@ -546,6 +546,9 @@ typedef struct { uint8_t eth_clk_mode; // 447 uint8_t free_esp32_448[4]; // 448 +#ifdef CONFIG_IDF_TARGET_ESP32S2 + uint8_t free_esp32s2_456[2]; // 456 - fix 32-bit offset for WebCamCfg +#endif WebCamCfg webcam_config; // 44C uint8_t eth_address; // 450 @@ -563,9 +566,11 @@ typedef struct { myio8 ex_my_gp8; // 484 17 bytes (ESP8266) - Free since 9.0.0.1 #endif // ESP8266 #ifdef ESP32 - +#ifdef CONFIG_IDF_TARGET_ESP32S2 + uint8_t free_esp32s2_494[1]; // 494 - 2 bytes extra because of WebCamCfg 32-bit offset +#else uint8_t free_esp32_484[17]; // 484 - +#endif #endif // ESP32 uint8_t ex_my_adc0; // 495 Free since 9.0.0.1 @@ -591,7 +596,10 @@ typedef struct { uint16_t influxdb_port; // 4CE power_t interlock[MAX_INTERLOCKS_SET]; // 4D0 MAX_INTERLOCKS = MAX_RELAYS / 2 - uint8_t free_508[36]; // 508 + int8_t shutter_tilt_config[5][MAX_SHUTTERS]; //508 + int8_t shutter_tilt_pos[MAX_SHUTTERS]; //51C + uint16_t influxdb_period; // 520 + uint8_t free_522[10]; // 522 uint16_t mqtt_keepalive; // 52C uint16_t mqtt_socket_timeout; // 52E @@ -632,9 +640,7 @@ typedef struct { mytmplt8285 ex_user_template8; // 72F 14 bytes (ESP8266) - Free since 9.0.0.1 #endif // ESP8266 #ifdef ESP32 - uint8_t free_esp32_72f[14]; // 72F - #endif // ESP32 uint8_t novasds_startingoffset; // 73D @@ -734,8 +740,9 @@ typedef struct { uint16_t shd_warmup_brightness; // F5C uint8_t shd_warmup_time; // F5E uint8_t tcp_config; // F5F + uint8_t light_step_pixels; // F60 - uint8_t free_f60[60]; // F60 - Decrement if adding new Setting variables just above and below + uint8_t free_f59[59]; // F61 - Decrement if adding new Setting variables just above and below // Only 32 bit boundary variables below @@ -761,6 +768,8 @@ typedef struct { uint32_t cfg_crc32; // FFC } TSettings; +static_assert(sizeof(TSettings) == 4096, "TSettings Size is not correct"); + typedef struct { uint16_t valid; // 280 (RTC memory offset 100 - sizeof(RTCRBT)) uint8_t fast_reboot_count; // 282 diff --git a/tasmota/settings.ino b/tasmota/settings.ino index e64e0cec1..ec09129f4 100644 --- a/tasmota/settings.ino +++ b/tasmota/settings.ino @@ -1454,6 +1454,11 @@ void SettingsDelta(void) { memset(&Settings->energy_kWhtoday_ph, 0, 36); memset(&RtcSettings.energy_kWhtoday_ph, 0, 24); } + if (Settings->version < 0x0A000003) { + if (0 == Settings->param[P_ARP_GRATUITOUS]) { + Settings->param[P_ARP_GRATUITOUS] = WIFI_ARP_INTERVAL; + } + } Settings->version = VERSION; SettingsSave(1); diff --git a/tasmota/support.ino b/tasmota/support.ino index 20274005c..76ca608e9 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -1840,6 +1840,15 @@ int8_t ParseSerialConfig(const char *pstr) return serial_config; } +uint32_t ConvertSerialConfig(uint8_t serial_config) { +#ifdef ESP8266 + return (uint32_t)pgm_read_byte(kTasmotaSerialConfig + serial_config); +#elif defined(ESP32) + return (uint32_t)pgm_read_dword(kTasmotaSerialConfig + serial_config); +#else + #error "platform not supported" +#endif +} // workaround disabled 05.11.2021 solved with https://github.com/espressif/arduino-esp32/pull/5549 //#if defined(ESP32) && CONFIG_IDF_TARGET_ESP32C3 diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino index 3daea88a7..23cd04c0b 100644 --- a/tasmota/support_command.ino +++ b/tasmota/support_command.ino @@ -621,7 +621,7 @@ void CmndStatus(void) if ((0 == payload) || (8 == payload) || (10 == payload)) { Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS10_SENSOR "\":")); - MqttShowSensor(); + MqttShowSensor(true); ResponseJsonEnd(); CmndStatusResponse((8 == payload) ? 8 : 10); } diff --git a/tasmota/support_device_groups.ino b/tasmota/support_device_groups.ino index cd628522e..2f2089a12 100644 --- a/tasmota/support_device_groups.ino +++ b/tasmota/support_device_groups.ino @@ -24,9 +24,11 @@ #ifdef USE_DEVICE_GROUPS //#define DEVICE_GROUPS_DEBUG -#define DGR_MEMBER_TIMEOUT 45000 -#define DGR_ANNOUNCEMENT_INTERVAL 60000 -#define DEVICE_GROUP_MESSAGE "TASMOTA_DGR" +#define DGR_MULTICAST_REPEAT_COUNT 1 // Number of times to re-send each multicast +#define DGR_ACK_WAIT_TIME 150 // Initial ms to wait for ack's +#define DGR_MEMBER_TIMEOUT 45000 // ms to wait for ack's before removing a member +#define DGR_ANNOUNCEMENT_INTERVAL 60000 // ms between announcements +#define DEVICE_GROUP_MESSAGE "TASMOTA_DGR" const char kDeviceGroupMessage[] PROGMEM = DEVICE_GROUP_MESSAGE; @@ -49,6 +51,7 @@ struct device_group { uint16_t ack_check_interval; uint8_t message_header_length; uint8_t initial_status_requests_remaining; + uint8_t multicasts_remaining; char group_name[TOPSZ]; uint8_t message[128]; struct device_group_member * device_group_members; @@ -815,6 +818,7 @@ bool _SendDeviceGroupMessage(int32_t device, DevGroupMessageType message_type, . } // Multicast the packet. + device_group->multicasts_remaining = DGR_MULTICAST_REPEAT_COUNT; SendReceiveDeviceGroupMessage(device_group, nullptr, device_group->message, device_group->message_length, false); #ifdef USE_DEVICE_GROUPS_SEND @@ -832,14 +836,14 @@ bool _SendDeviceGroupMessage(int32_t device, DevGroupMessageType message_type, . device_group->next_ack_check_time = 0; } else { - device_group->ack_check_interval = 200; + device_group->ack_check_interval = DGR_ACK_WAIT_TIME; device_group->next_ack_check_time = now + device_group->ack_check_interval; - if (device_group->next_ack_check_time < next_check_time) next_check_time = device_group->next_ack_check_time; + if ((int32_t)(next_check_time - device_group->next_ack_check_time) > 0) next_check_time = device_group->next_ack_check_time; device_group->member_timeout_time = now + DGR_MEMBER_TIMEOUT; } device_group->next_announcement_time = now + DGR_ANNOUNCEMENT_INTERVAL; - if (device_group->next_announcement_time < next_check_time) next_check_time = device_group->next_announcement_time; + if ((int32_t)(next_check_time - device_group->next_announcement_time) > 0) next_check_time = device_group->next_announcement_time; return 0; } @@ -868,6 +872,8 @@ void ProcessDeviceGroupMessage(uint8_t * message, int message_length) return; } device_group_member->ip_address = remote_ip; + device_group_member->acked_sequence = device_group->outgoing_sequence; + device_group->member_timeout_time = millis() + DGR_MEMBER_TIMEOUT; *flink = device_group_member; AddLog(LOG_LEVEL_DEBUG, PSTR("DGR: Member %s added"), IPAddressToString(remote_ip)); break; @@ -914,7 +920,7 @@ void DeviceGroupsLoop(void) uint32_t now = millis(); // If it's time to check on things, iterate through the device groups. - if ((long)(now - next_check_time) >= 0) { + if ((int32_t)(now - next_check_time) >= 0) { #ifdef DEVICE_GROUPS_DEBUG AddLog(LOG_LEVEL_DEBUG, PSTR("DGR: Checking next_check_time=%u, now=%u"), next_check_time, now); #endif // DEVICE_GROUPS_DEBUG @@ -927,7 +933,7 @@ AddLog(LOG_LEVEL_DEBUG, PSTR("DGR: Checking next_check_time=%u, now=%u"), next_c if (device_group->next_ack_check_time) { // If it's time to check for acks, ... - if ((long)(now - device_group->next_ack_check_time) >= 0) { + if ((int32_t)(now - device_group->next_ack_check_time) >= 0) { // If we're still sending the initial status request message, send it. if (device_group->initial_status_requests_remaining) { @@ -951,7 +957,7 @@ AddLog(LOG_LEVEL_DEBUG, PSTR("DGR: Checking next_check_time=%u, now=%u"), next_c // If we're done initializing, iterate through the group memebers, ... else { #ifdef DEVICE_GROUPS_DEBUG - AddLog(LOG_LEVEL_DEBUG, PSTR("DGR: Checking for ack's")); + AddLog(LOG_LEVEL_DEBUG, PSTR("DGR: Checking for %s ack's"), device_group->group_name); #endif // DEVICE_GROUPS_DEBUG bool acked = true; struct device_group_member ** flink = &device_group->device_group_members; @@ -963,17 +969,23 @@ AddLog(LOG_LEVEL_DEBUG, PSTR("DGR: Checking next_check_time=%u, now=%u"), next_c // If we haven't receive an ack from this member in DGR_MEMBER_TIMEOUT ms, assume // they're offline and remove them from the group. - if ((long)(now - device_group->member_timeout_time) >= 0) { + if ((int32_t)(now - device_group->member_timeout_time) >= 0) { *flink = device_group_member->flink; free(device_group_member); AddLog(LOG_LEVEL_DEBUG, PSTR("DGR: Member %s removed"), IPAddressToString(device_group_member->ip_address)); continue; } - // Otherwise, unicast the last message directly to this member. + // If we have more multicasts to do, multicast the packet to all members again; + // otherwise, unicast the message directly to this member. + if (device_group->multicasts_remaining) device_group_member = nullptr; SendReceiveDeviceGroupMessage(device_group, device_group_member, device_group->message, device_group->message_length, false); - device_group_member->unicast_count++; acked = false; + if (device_group->multicasts_remaining) { + device_group->multicasts_remaining--; + break; + } + device_group_member->unicast_count++; } flink = &device_group_member->flink; } @@ -986,31 +998,34 @@ AddLog(LOG_LEVEL_DEBUG, PSTR("DGR: Checking next_check_time=%u, now=%u"), next_c } // If there are still members we haven't received an ack from, set the next ack check - // time. We start at 200ms and double the interval each pass with a maximum interval of - // 5 seconds. + // time. We start at DGR_ACK_WAIT_TIME ms and add 100ms each pass with a maximum + // interval of 2 seconds. else { - device_group->ack_check_interval *= 2; - if (device_group->ack_check_interval > 5000) device_group->ack_check_interval = 5000; + device_group->ack_check_interval += 100; + if (device_group->ack_check_interval > 2000) device_group->ack_check_interval = 2000; device_group->next_ack_check_time = now + device_group->ack_check_interval; } } } - if (device_group->next_ack_check_time < next_check_time) next_check_time = device_group->next_ack_check_time; + if (device_group->next_ack_check_time && (int32_t)(next_check_time - device_group->next_ack_check_time) > 0) next_check_time = device_group->next_ack_check_time; } - // If it's time to send a multicast announcement for this group, send it. This is to - // announce ourself to any members that have somehow not heard about us. We send it at the - // announcement interval plus a random number of milliseconds so that even if all the devices - // booted at the same time, they don't all multicast their announcements at the same time. + // If we're not still waiting for acks and it's time to send a multicast announcement for this + // group, send it. This is to announce ourself to any members that have somehow not heard + // about us. We send it at the announcement interval plus a random number of milliseconds so + // that even if all the devices booted at the same time, they don't all multicast their + // announcements at the same time. + else { #ifdef DEVICE_GROUPS_DEBUG - AddLog(LOG_LEVEL_DEBUG, PSTR("DGR: next_announcement_time=%u, now=%u"), device_group->next_announcement_time, now); + AddLog(LOG_LEVEL_DEBUG, PSTR("DGR: next_announcement_time=%u, now=%u"), device_group->next_announcement_time, now); #endif // DEVICE_GROUPS_DEBUG - if ((long)(now - device_group->next_announcement_time) >= 0) { - SendReceiveDeviceGroupMessage(device_group, nullptr, device_group->message, BeginDeviceGroupMessage(device_group, DGR_FLAG_ANNOUNCEMENT, true) - device_group->message, false); - device_group->next_announcement_time = now + DGR_ANNOUNCEMENT_INTERVAL + random(10000); + if ((int32_t)(now - device_group->next_announcement_time) >= 0) { + SendReceiveDeviceGroupMessage(device_group, nullptr, device_group->message, BeginDeviceGroupMessage(device_group, DGR_FLAG_ANNOUNCEMENT, true) - device_group->message, false); + device_group->next_announcement_time = now + DGR_ANNOUNCEMENT_INTERVAL + random(10000); + } + if ((int32_t)(next_check_time - device_group->next_announcement_time) > 0) next_check_time = device_group->next_announcement_time; } - if (device_group->next_announcement_time < next_check_time) next_check_time = device_group->next_announcement_time; } } } diff --git a/tasmota/support_esp.ino b/tasmota/support_esp.ino index 87db014c0..93abe9daa 100644 --- a/tasmota/support_esp.ino +++ b/tasmota/support_esp.ino @@ -103,6 +103,19 @@ String GetDeviceHardware(void) { #ifdef ESP32 +// ESP32_ARCH contains the name of the architecture (used by autoconf) +#if CONFIG_IDF_TARGET_ESP32 + #define ESP32_ARCH "esp32" +#elif CONFIG_IDF_TARGET_ESP32S2 + #define ESP32_ARCH "esp32s2" +#elif CONFIG_IDF_TARGET_ESP32S3 + #define ESP32_ARCH "esp32s3" +#elif CONFIG_IDF_TARGET_ESP32C3 + #define ESP32_ARCH "esp32c3" +#else + #define ESP32_ARCH "" +#endif + // Handle 20k of NVM #include diff --git a/tasmota/support_features.ino b/tasmota/support_features.ino index 6a2d73b37..9236a511b 100644 --- a/tasmota/support_features.ino +++ b/tasmota/support_features.ino @@ -673,9 +673,9 @@ void ResponseAppendFeatures(void) #if defined(USE_SPI) && defined(USE_DISPLAY) && defined(USE_DISPLAY_EPAPER_42) feature7 |= 0x00008000; // xdsp_06_epaper_42.ino #endif -#if defined(USE_SPI) && defined(USE_DISPLAY) && defined(USE_DISPLAY_ILI9488) - feature7 |= 0x00010000; // xdsp_08_ILI9488.ino -#endif +// #if defined(USE_SPI) && defined(USE_DISPLAY) && defined(USE_DISPLAY_ILI9488) +// feature7 |= 0x00010000; // xdsp_08_ILI9488.ino +// #endif #if defined(USE_SPI) && defined(USE_DISPLAY) && defined(USE_DISPLAY_SSD1351) feature7 |= 0x00020000; // xdsp_09_SSD1351.ino #endif @@ -772,10 +772,12 @@ void ResponseAppendFeatures(void) feature8 |= 0x00004000; // xsns_92_scd40.ino #endif #if defined(USE_I2C) && defined(USE_HM330X) - feature8 |= 0x00008000; + feature8 |= 0x00008000; // xsns_93_hm330x.ino #endif -// feature8 |= 0x00010000; +#if defined(USE_I2C) && defined(USE_HDC2010) + feature8 |= 0x00010000; // xsns_94_hdc2010.ino +#endif // feature8 |= 0x00020000; // feature8 |= 0x00040000; // feature8 |= 0x00080000; diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 97fba4b6c..13671b18f 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -565,7 +565,7 @@ bool SendKey(uint32_t key, uint32_t device, uint32_t state) result = XdrvRulesProcess(0); } #ifdef USE_PWM_DIMMER - if (PWM_DIMMER != TasmotaGlobal.module_type || !result) { + if (PWM_DIMMER != TasmotaGlobal.module_type || (!result && !Settings->flag3.mqtt_buttons)) { #endif // USE_PWM_DIMMER int32_t payload_save = XdrvMailbox.payload; XdrvMailbox.payload = device_save << 24 | key << 16 | state << 8 | device; @@ -756,6 +756,11 @@ void MqttShowState(void) ESP_getFreeHeap1024(), GetTextIndexed(stemp1, sizeof(stemp1), Settings->flag3.sleep_normal, kSleepMode), // SetOption60 - Enable normal sleep instead of dynamic sleep TasmotaGlobal.sleep, TasmotaGlobal.loop_load_avg, MqttConnectCount()); +#ifdef USE_BERRY + extern void BrShowState(void); + BrShowState(); +#endif // USE_BERRY + for (uint32_t i = 1; i <= TasmotaGlobal.devices_present; i++) { #ifdef USE_LIGHT if ((LightDevice()) && (i >= LightDevice())) { @@ -835,7 +840,7 @@ String GetSwitchText(uint32_t i) { return switch_text; } -bool MqttShowSensor(void) +bool MqttShowSensor(bool call_show_sensor) { ResponseAppendTime(); @@ -894,20 +899,20 @@ bool MqttShowSensor(void) } ResponseJsonEnd(); - if (json_data_available) { XdrvCall(FUNC_SHOW_SENSOR); } + if (call_show_sensor && json_data_available) { XdrvCall(FUNC_SHOW_SENSOR); } return json_data_available; } void MqttPublishSensor(void) { ResponseClear(); - if (MqttShowSensor()) { + if (MqttShowSensor(true)) { MqttPublishTeleSensor(); } } void MqttPublishTeleperiodSensor(void) { ResponseClear(); - if (MqttShowSensor()) { + if (MqttShowSensor(true)) { MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings->flag.mqtt_sensor_retain); // CMND_SENSORRETAIN XdrvRulesProcess(1); } @@ -994,8 +999,10 @@ void PerformEverySecond(void) } } +#ifdef ESP8266 // Wifi keep alive to send Gratuitous ARP wifiKeepAlive(); +#endif WifiPollNtp(); @@ -1206,8 +1213,18 @@ void Every250mSeconds(void) char version[50]; snprintf_P(version, sizeof(version), PSTR("%s%s"), TasmotaGlobal.version, TasmotaGlobal.image_name); AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPLOAD "%s %s"), full_ota_url, version); +#if defined(ESP32) && defined(USE_WEBCLIENT_HTTPS) + HTTPClientLight OTAclient; + if (!OTAclient.begin(full_ota_url)) { + AddLog(LOG_LEVEL_INFO, "OTA: unsupported protocol"); + ota_result = -999; + } else { + ota_result = (HTTP_UPDATE_FAILED != httpUpdateLight.update(OTAclient, version)); + } +#else // standard OTA over HTTP WiFiClient OTAclient; ota_result = (HTTP_UPDATE_FAILED != ESPhttpUpdate.update(OTAclient, full_ota_url, version)); +#endif if (!ota_result) { #ifndef FIRMWARE_MINIMAL int ota_error = ESPhttpUpdate.getLastError(); @@ -1651,6 +1668,22 @@ void ResetPwm(void) /********************************************************************************************/ +#ifdef ESP32 +// Since ESP-IDF 4.4, GPIO matrix or I/O is not reset during a restart +// and GPIO configuration can get stuck because of leftovers +// +// This patched version of pinMode forces a full GPIO reset before setting new mode +// +extern "C" void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode); + +extern "C" void ARDUINO_ISR_ATTR pinMode(uint8_t pin, uint8_t mode) { + gpio_reset_pin((gpio_num_t)pin); + __pinMode(pin, mode); +} +#endif + +/********************************************************************************************/ + void GpioInit(void) { if (!ValidModule(Settings->module)) { diff --git a/tasmota/support_wifi.ino b/tasmota/support_wifi.ino index bf80f579e..05072542a 100644 --- a/tasmota/support_wifi.ino +++ b/tasmota/support_wifi.ino @@ -668,6 +668,7 @@ void EspRestart(void) } } +#ifdef ESP8266 // // Gratuitous ARP, backported from https://github.com/esp8266/Arduino/pull/6889 // @@ -715,6 +716,7 @@ void wifiKeepAlive(void) { SetNextTimeInterval(wifi_timer, wifiTimerSec * 1000); } } +#endif // ESP8266 void WifiPollNtp() { static uint8_t ntp_sync_minute = 0; diff --git a/tasmota/tasmota.h b/tasmota/tasmota.h index 92803ca87..f6a2b113d 100644 --- a/tasmota/tasmota.h +++ b/tasmota/tasmota.h @@ -83,10 +83,22 @@ const uint16_t VL53L0X_MAX_SENSORS = 8; // Max number of VL53L0X sensors const uint8_t MAX_I2C = 2; // Max number of I2C controllers (ESP32 = 2) const uint8_t MAX_SPI = 2; // Max number of Hardware SPI controllers (ESP32 = 2) const uint8_t MAX_I2S = 2; // Max number of Hardware I2S controllers (ESP32 = 2) + +#if CONFIG_IDF_TARGET_ESP32 +const uint8_t MAX_RMT = 8; // Max number or RMT channels (ESP32 only) +#elif CONFIG_IDF_TARGET_ESP32S2 +const uint8_t MAX_RMT = 4; // Max number or RMT channels (ESP32S2 only) +#elif CONFIG_IDF_TARGET_ESP32C3 +const uint8_t MAX_RMT = 2; // Max number or RMT channels (ESP32C3 only) +#else +const uint8_t MAX_RMT = 0; // Max number or RMT channels (0 if unknown) +#endif + #else const uint8_t MAX_I2C = 0; // Max number of I2C controllers (ESP8266 = 0, no choice) const uint8_t MAX_SPI = 0; // Max number of Hardware SPI controllers (ESP8266 = 0, no choice) const uint8_t MAX_I2S = 0; // Max number of Hardware I2S controllers (ESP8266 = 0, no choice) +const uint8_t MAX_RMT = 0; // No RMT channel on ESP8266 #endif // Changes to the following MAX_ defines need to be in line with enum SettingsTextIndex diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index f4008b93d..3e1ed63c4 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -35,6 +35,9 @@ // Libraries #include // Ota #include // Ota +#ifdef ESP32 + #include "HTTPUpdateLight.h" // Ota over HTTPS for ESP32 +#endif #include // Webserver, Updater #include #include diff --git a/tasmota/tasmota_configurations.h b/tasmota/tasmota_configurations.h index 59810fccd..8dc302dad 100644 --- a/tasmota/tasmota_configurations.h +++ b/tasmota/tasmota_configurations.h @@ -148,6 +148,7 @@ //#define USE_BM8563 // [I2cDriver59] Enable BM8563 RTC - found in M5Stack - support both I2C buses on ESP32 (I2C address 0x51) (+2k5 code) //#define USE_AM2320 // [I2cDriver60] Enable AM2320 temperature and humidity Sensor (I2C address 0x5C) (+1k code) //#define USE_T67XX // [I2cDriver61] Enable Telaire T67XX CO2 sensor (I2C address 0x15) (+1k3 code) +//#define USE_HDC2010 // [I2cDriver64] Enable HDC2010 temperature/humidity sensor (I2C address 0x40) (+1k5 code) //#define USE_SPI // Hardware SPI using GPIO12(MISO), GPIO13(MOSI) and GPIO14(CLK) in addition to two user selectable GPIOs(CS and DC) //#define USE_RC522 // Add support for MFRC522 13.56Mhz Rfid reader (+6k code) @@ -329,7 +330,7 @@ #define USE_DISPLAY_ILI9341 // [DisplayModel 4] Enable ILI9341 Tft 480x320 display (+19k code) #define USE_DISPLAY_EPAPER_29 // [DisplayModel 5] Enable e-paper 2.9 inch display (+19k code) #define USE_DISPLAY_EPAPER_42 // [DisplayModel 6] Enable e-paper 4.2 inch display - #define USE_DISPLAY_ILI9488 // [DisplayModel 8] + // #define USE_DISPLAY_ILI9488 // [DisplayModel 8] #define USE_DISPLAY_SSD1351 // [DisplayModel 9] #define USE_DISPLAY_RA8876 // [DisplayModel 10] #define USE_DISPLAY_ST7789 // [DisplayModel 12] Enable ST7789 module diff --git a/tasmota/tasmota_configurations_ESP32.h b/tasmota/tasmota_configurations_ESP32.h index dc2ad62fa..74ed07d32 100644 --- a/tasmota/tasmota_configurations_ESP32.h +++ b/tasmota/tasmota_configurations_ESP32.h @@ -73,15 +73,22 @@ #define USE_ODROID_GO // Add support for Odroid Go #define USE_SDCARD +#define USE_WEBCLIENT_HTTPS + #undef USE_HOME_ASSISTANT -#define USE_ADC +#define USE_I2C #define USE_SPI - #define USE_DISPLAY // Add SPI Display Support (+2k code) + #define USE_DISPLAY #define SHOW_SPLASH - #ifndef USE_UNIVERSAL_DISPLAY - #define USE_DISPLAY_ILI9341 // [DisplayModel 4] Enable ILI9341 Tft 480x320 display (+19k code) - #endif +#ifdef USE_UNIVERSAL_DISPLAY + #define USE_LVGL + #define USE_LVGL_FREETYPE +// #define USE_DISPLAY_LVGL_ONLY +#else + #define USE_DISPLAY_ILI9341 // [DisplayModel 4] Enable ILI9341 Tft 480x320 display (+19k code) + #define USE_DISPLAY_MODES1TO5 +#endif //#define USE_BLE_ESP32 // Enable new BLE driver //#define USE_MI_ESP32 // (ESP32 only) Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash) #endif // FIRMWARE_ODROID_GO @@ -108,6 +115,8 @@ #define USE_I2S_WEBRADIO #define USE_SDCARD +#define USE_WEBCLIENT_HTTPS + #define USE_I2C #define USE_BMA423 #define USE_MPU_ACCEL @@ -171,7 +180,7 @@ #define USE_SDCARD #define USE_ADC -#undef USE_BERRY // Disable Berry scripting language +//#undef USE_BERRY // Disable Berry scripting language #define USE_BLE_ESP32 // Enable new BLE driver #define USE_EQ3_ESP32 #define USE_MI_ESP32 // (ESP32 only) Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash) @@ -195,6 +204,8 @@ #undef USE_DOMOTICZ #undef USE_HOME_ASSISTANT +#define USE_WEBCLIENT_HTTPS + #define USE_I2S #define USE_SPI #define USE_LVGL diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index 0de887e9c..bbbce4d01 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -569,7 +569,7 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_P9813_CLK), // P9813 CLOCK AGPIO(GPIO_P9813_DAT), // P9813 DATA #else - AGPIO(GPIO_WS2812), // WS2812 Led string + AGPIO(GPIO_WS2812) + MAX_RMT,// WS2812 Led string, using RMT on ESP32 #endif // NEO_HW_P9813 #endif #ifdef USE_ARILUX_RF @@ -1076,11 +1076,11 @@ const char PINS_WEMOS[] PROGMEM = "IOTXIORXIOIOFLFLFLFLFLFLIOIOIOIOIOIOIOIOIOIOI typedef struct MYIO { uint16_t io[MAX_GPIO_PIN]; -} myio; // ESP8266: 18 * 2 = 36 bytes / ESP32: 40 * 2 = 80 bytes / ESP32-C3: 22 * 2 = 44 bytes +} myio; // ESP8266: 18*2 = 36 bytes / ESP32: 40*2 = 80 bytes / ESP32-C3: 22*2 = 44 bytes / ESP32-S2: 47*2 = 94 bytes typedef struct MYCFGIO { uint16_t io[MAX_USER_PINS]; -} mycfgio; // ESP8266: 14 * 2 = 28 bytes / ESP32: 36 * 2 = 72 bytes / ESP32-C3: 22 * 2 = 44 bytes +} mycfgio; // ESP8266: 14*2 = 28 bytes / ESP32: 36*2 = 72 bytes / ESP32-C3: 22*2 = 44 bytes / ESP32-S2: 36*2 = 72 bytes #define GPIO_FLAG_USED 0 // Currently no flags used @@ -1107,9 +1107,9 @@ typedef union { } gpio_flag; // 2 bytes typedef struct MYTMPLT { - mycfgio gp; // 28 / 72 / 44 bytes + mycfgio gp; // 28 / 72 / 44 / 72 bytes gpio_flag flag; // 2 bytes -} mytmplt; // 30 / 74 / 46 bytes +} mytmplt; // 30 / 74 / 46 / 74 bytes //******************************************************************************************** diff --git a/tasmota/tasmota_version.h b/tasmota/tasmota_version.h index f131a366f..7e3e74d42 100644 --- a/tasmota/tasmota_version.h +++ b/tasmota/tasmota_version.h @@ -20,6 +20,6 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x0A000001; +const uint32_t VERSION = 0x0A000003; #endif // _TASMOTA_VERSION_H_ diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index cab94ba46..ec28f4f23 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -3117,8 +3117,12 @@ int WebQuery(char *buffer) // An unlimited number of headers can be sent per request, and a body can be sent for all command types // The body will be ignored if sending a GET command +#if defined(ESP32) && defined(USE_WEBCLIENT_HTTPS) + HTTPClientLight http; +#else // HTTP only WiFiClient http_client; HTTPClient http; +#endif int status = WEBCMND_WRONG_PARAMETERS; @@ -3127,7 +3131,11 @@ int WebQuery(char *buffer) char *method = strtok_r(temp, " ", &temp); if (url && method) { +#if defined(ESP32) && defined(USE_WEBCLIENT_HTTPS) + if (http.begin(UrlEncode(url))) { +#else // HTTP only if (http.begin(http_client, UrlEncode(url))) { +#endif char empty_body[1] = { 0 }; char *body = empty_body; if (temp) { // There is a body and/or header @@ -3204,9 +3212,15 @@ int WebGetConfig(char *buffer) DEBUG_CORE_LOG(PSTR("WEB: Config Uri '%s'"), url.c_str()); + +#if defined(ESP32) && defined(USE_WEBCLIENT_HTTPS) + HTTPClientLight http; + if (http.begin(UrlEncode(url))) { // UrlEncode(url) = |http://192.168.178.86/cm?cmnd=POWER1%20ON| +#else // HTTP only WiFiClient http_client; HTTPClient http; if (http.begin(http_client, UrlEncode(url))) { // UrlEncode(url) = |http://192.168.178.86/cm?cmnd=POWER1%20ON| +#endif int http_code = http.GET(); // Start connection and send HTTP header if (http_code > 0) { // http_code will be negative on error status = WEBCMND_DONE; diff --git a/tasmota/xdrv_02_9_mqtt.ino b/tasmota/xdrv_02_9_mqtt.ino index 181917fa1..f5302330f 100644 --- a/tasmota/xdrv_02_9_mqtt.ino +++ b/tasmota/xdrv_02_9_mqtt.ino @@ -216,6 +216,12 @@ void MqttInit(void) { tlsClient = new BearSSL::WiFiClientSecure_light(1024,1024); #endif +#ifdef USE_MQTT_AWS_IOT_LIGHT + if (443 == Settings->mqtt_port) { + static const char * alpn_mqtt = "mqtt"; // needs to be static + tlsClient->setALPN(&alpn_mqtt, 1); // need to set alpn to 'mqtt' for AWS IoT + } +#endif #ifdef USE_MQTT_AWS_IOT loadTlsDir(); // load key and certificate data from Flash if ((nullptr != AWS_IoT_Private_Key) && (nullptr != AWS_IoT_Client_Certificate)) { diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index d4b4d1134..d5a2c5bdb 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -205,11 +205,17 @@ void alt_eeprom_readBytes(uint32_t adr, uint32_t len, uint8_t *buf) { #endif // LITTLEFS_SCRIPT_SIZE +#include #ifdef TESLA_POWERWALL #include "powerwall.h" #endif +#ifdef USE_DISPLAY_DUMP +#include +extern Renderer *renderer; +#endif + // offsets epoch readings by 1.1.2019 00:00:00 to fit into float with second resolution #ifndef EPOCH_OFFSET #define EPOCH_OFFSET 1546300800 @@ -231,7 +237,7 @@ extern FS *ufsp; #endif // USE_UFILESYS -extern "C" void homekit_main(char *, uint32_t); +extern "C" int32_t homekit_main(char *, uint32_t); #ifdef SUPPORT_MQTT_EVENT #include // Import LinkedList library @@ -434,6 +440,9 @@ struct SCRIPT_MEM { bool homekit_running = false; #endif // USE_HOMEKIT uint32_t epoch_offset = EPOCH_OFFSET; +#ifdef USE_SCRIPT_SERIAL + TasmotaSerial *sp; +#endif } glob_script_mem; @@ -2586,6 +2595,23 @@ chknext: #endif break; case 'i': + if (!strncmp(vname, "ins(", 4)) { + char s1[SCRIPT_MAXSSIZE]; + lp = GetStringArgument(lp + 4, OPER_EQU, s1, 0); + SCRIPT_SKIP_SPACES + char s2[SCRIPT_MAXSSIZE]; + lp = GetStringArgument(lp, OPER_EQU, s2, 0); + SCRIPT_SKIP_SPACES + char *cp = strstr(s1, s2); + if (cp) { + fvar = ((uint32_t)cp - (uint32_t)s1); + } else { + fvar = -1; + } + lp++; + len = 0; + goto exit; + } if (!strncmp(vname, "int(", 4)) { lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv); fvar = floor(fvar); @@ -3176,6 +3202,168 @@ chknext: goto exit; } #endif //USE_SML_M + +#ifdef USE_SCRIPT_SERIAL + if (!strncmp(vname, "so(", 3)) { + float rxpin, txpin, br; + lp = GetNumericArgument(lp + 3, OPER_EQU, &rxpin, gv); + SCRIPT_SKIP_SPACES + lp = GetNumericArgument(lp, OPER_EQU, &txpin, gv); + SCRIPT_SKIP_SPACES + lp = GetNumericArgument(lp, OPER_EQU, &br, gv); + SCRIPT_SKIP_SPACES + uint32_t sconfig = TS_SERIAL_8N1; + if (*lp!=')') { + // serial options, must be 3 chars 8N1, 7E2 etc + uint8_t bits = *lp++ & 0xf; + uint8_t parity = 0; + if (*lp == 'E') parity = 1; + if (*lp == 'O') parity = 2; + lp++; + uint8_t stopb = (*lp++ & 0x3) - 1; + sconfig = (bits - 5) + (parity * 8) + stopb * 4; + } + SCRIPT_SKIP_SPACES + // check for rec buffer + float rxbsiz = 128; + if (*lp!=')') { + lp = GetNumericArgument(lp, OPER_EQU, &rxbsiz, gv); + } + fvar= -1; + if (glob_script_mem.sp) { + fvar == -1; + } else { + if (Is_gpio_used(rxpin) || Is_gpio_used(txpin)) { + AddLog(LOG_LEVEL_INFO, PSTR("warning: pins already used")); + } + + glob_script_mem.sp = new TasmotaSerial(rxpin, txpin, 1, 0, rxbsiz); + + if (glob_script_mem.sp) { + uint32_t config; +#ifdef ESP8266 + config = pgm_read_byte(kTasmotaSerialConfig + sconfig); +#endif // ESP8266 + +#ifdef ESP32 + config = pgm_read_dword(kTasmotaSerialConfig + sconfig); +#endif // ESP32 + fvar = glob_script_mem.sp->begin(br, config); + uint32_t savc = Settings->serial_config; + //setRxBufferSize(TMSBSIZ); + + Settings->serial_config = sconfig; + AddLog(LOG_LEVEL_INFO, PSTR("Serial port set to %s %d bit/s at rx=%d tx=%d rbu=%d"), GetSerialConfig().c_str(), (uint32_t)br, (uint32_t)rxpin, (uint32_t)txpin, (uint32_t)rxbsiz); + Settings->serial_config = savc; + if (rxpin == 3 and txpin == 1) ClaimSerial(); + + } else { + fvar = -2; + } + } + lp++; + len = 0; + goto exit; + } + if (!strncmp(vname, "sw(", 3)) { + char str[SCRIPT_MAXSSIZE]; + lp = GetStringArgument(lp + 3, OPER_EQU, str, 0); + fvar = -1; + if (glob_script_mem.sp) { + glob_script_mem.sp->write(str, strlen(str)); + fvar = 0; + } + lp++; + len = 0; + goto exit; + } + if (!strncmp(vname, "swb(", 4)) { + lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, 0); + fvar = -1; + if (glob_script_mem.sp) { + glob_script_mem.sp->write((uint8_t)fvar); + fvar = 0; + } + lp++; + len = 0; + goto exit; + } + if (!strncmp(vname, "sa(", 3)) { + fvar = -1; + if (glob_script_mem.sp) { + fvar = glob_script_mem.sp->available(); + } + lp++; + len = 0; + goto exit; + } + if (!strncmp(vname, "srb(", 3)) { + fvar = -1; + if (glob_script_mem.sp) { + fvar = glob_script_mem.sp->available(); + if (fvar > 0) { + fvar = glob_script_mem.sp->read(); + } + } + lp++; + len = 0; + goto exit; + } + if (!strncmp(vname, "sp(", 3)) { + fvar = -1; + if (glob_script_mem.sp) { + fvar = glob_script_mem.sp->available(); + if (fvar > 0) { + fvar = glob_script_mem.sp->peek(); + } + } + lp++; + len = 0; + goto exit; + } + if (!strncmp(vname, "sr(", 3)) { + uint16_t size = glob_script_mem.max_ssize; + char str[size]; + memset(str, 0, size); + lp += 3; + uint8_t runt = 0; + if (*lp != ')') { + // read until + lp = GetNumericArgument(lp, OPER_EQU, &fvar, 0); + runt = fvar; + } + fvar = -1; + uint8_t flg = 0; + if (glob_script_mem.sp) { + for (uint16_t index = 0; index < (size - 1); index++) { + if (!glob_script_mem.sp->available()) { + flg = 1; + break; + } + uint8_t iob = glob_script_mem.sp->read(); + if (iob == runt) { + flg = 2; + break; + } + str[index] = iob; + } + } + //AddLog(LOG_LEVEL_INFO, PSTR(">>: %d - %d - %d - %s"), runt, flg, index, str); + lp++; + len = 0; + if (sp) strlcpy(sp, str, size); + goto strexit;; + } + if (!strncmp(vname, "sc(", 3)) { + fvar = -1; + if (Script_Close_Serial()) { + fvar = 0; + } + lp+=4; + len = 0; + goto exit; + } +#endif //USE_SCRIPT_SERIAL break; case 't': if (!strncmp(vname, "time", 4)) { @@ -3280,6 +3468,21 @@ chknext: goto exit; } #endif + +#ifdef USE_TIMERS + if (!strncmp(vname, "ttget(", 6)) { + lp = GetNumericArgument(lp + 6, OPER_EQU, &fvar, gv); + SCRIPT_SKIP_SPACES + uint8_t index = fvar; + if (index < 1 || index > MAX_TIMERS) index = 1; + lp = GetNumericArgument(lp, OPER_EQU, &fvar, gv); + SCRIPT_SKIP_SPACES + fvar = get_tpars(index - 1, fvar); + lp++; + len = 0; + goto exit; + } +#endif break; case 'u': if (!strncmp(vname, "uptime", 6)) { @@ -3382,7 +3585,7 @@ chknext: goto exit; } #endif // USE_TTGO_WATCH -#if defined(USE_FT5206) || defined(USE_XPT2046) || defined(USE_LILYGO47) +#if defined(USE_FT5206) || defined(USE_XPT2046) || defined(USE_LILYGO47) || defined(USE_M5EPD47) if (!strncmp(vname, "wtch(", 5)) { lp = GetNumericArgument(lp + 5, OPER_EQU, &fvar, gv); fvar = Touch_Status(fvar); @@ -4498,6 +4701,9 @@ int16_t Run_script_sub(const char *type, int8_t tlen, struct GVARS *gv) { // set pin mode lp = GetNumericArgument(lp + 6, OPER_EQU, &fvar, 0); int8_t pinnr = fvar; + if (Is_gpio_used(pinnr)) { + AddLog(LOG_LEVEL_INFO, PSTR("warning: pins already used")); + } SCRIPT_SKIP_SPACES uint8_t mode = 0; if ((*lp=='I') || (*lp=='O') || (*lp=='P')) { @@ -5000,6 +5206,25 @@ int16_t Run_script_sub(const char *type, int8_t tlen, struct GVARS *gv) { return -1; } +#ifdef USE_SCRIPT_SERIAL +bool Script_Close_Serial() { + if (glob_script_mem.sp) { + glob_script_mem.sp->flush(); + delay(100); + delete(glob_script_mem.sp); + glob_script_mem.sp = 0; + return true; + } + return false; +} +#endif //USE_SCRIPT_SERIAL + +bool Is_gpio_used(uint8_t gpiopin) { + if ((gpiopin < nitems(TasmotaGlobal.gpio_pin)) && (TasmotaGlobal.gpio_pin[gpiopin] > 0)) { + return true; + } + return false; +} void ScripterEvery100ms(void) { static uint8_t xsns_index = 0; @@ -5440,6 +5665,8 @@ void ScriptSaveSettings(void) { SaveScript(); + } else { + AddLog(LOG_LEVEL_INFO, PSTR("script memory error")); } SaveScriptEnd(); @@ -5481,6 +5708,10 @@ void SaveScriptEnd(void) { return; } +#ifdef USE_SCRIPT_SERIAL + Script_Close_Serial(); +#endif + Run_Scripter(">B\n", 3, 0); Run_Scripter(">BS", 3, 0); @@ -6529,9 +6760,8 @@ char buff[512]; if (sflg) { #ifdef USE_DISPLAY_DUMP - -#include -extern Renderer *renderer; +//#include +//extern Renderer *renderer; // screen copy #define fileHeaderSize 14 @@ -6541,7 +6771,9 @@ extern Renderer *renderer; uint8_t *bp = renderer->framebuffer; uint8_t *lbuf = (uint8_t*)special_malloc(Settings->display_width * 3 + 2); if (!lbuf) return; - int8_t bpp = renderer->disp_bpp; + uint8_t dmflg = 0; + if (renderer->disp_bpp & 0x40) dmflg = 1; + int8_t bpp = renderer->disp_bpp & 0xbf;; uint8_t *lbp; uint8_t fileHeader[fileHeaderSize]; createBitmapFileHeader(Settings->display_height , Settings->display_width , fileHeader); @@ -6549,8 +6781,7 @@ extern Renderer *renderer; uint8_t infoHeader[infoHeaderSize]; createBitmapInfoHeader(Settings->display_height, Settings->display_width, infoHeader ); Webserver->client().write((uint8_t *)infoHeader, infoHeaderSize); - - if (bpp == -1) { + if (bpp < 0) { for (uint32_t lins = Settings->display_height - 1; lins >= 0 ; lins--) { lbp = lbuf; for (uint32_t cols = 0; cols < Settings->display_width; cols ++) { @@ -6570,16 +6801,30 @@ extern Renderer *renderer; if (bpp == 4) { for (uint32_t cols = 0; cols < Settings->display_width; cols += 2) { uint8_t pixel; - for (uint32_t cnt = 0; cnt <= 1; cnt++) { - if (cnt & 1) { - pixel = *bp >> 4; - } else { - pixel = *bp & 0xf; + if (!dmflg) { + for (uint32_t cnt = 0; cnt <= 1; cnt++) { + if (cnt & 1) { + pixel = *bp >> 4; + } else { + pixel = *bp & 0xf; + } } pixel *= 15; *--lbp = pixel; *--lbp = pixel; *--lbp = pixel; + } else { + for (uint32_t cnt = 0; cnt <= 1; cnt++) { + if (!(cnt & 1)) { + pixel = *bp >> 4; + } else { + pixel = *bp & 0xf; + } + pixel *= 15; + *--lbp = pixel; + *--lbp = pixel; + *--lbp = pixel; + } } bp++; } @@ -6601,8 +6846,8 @@ extern Renderer *renderer; bp++; } } + Webserver->client().write((const char*)lbuf, Settings->display_width * 3); } - Webserver->client().write((const char*)lbuf, Settings->display_width * 3); } if (lbuf) free(lbuf); Webserver->client().stop(); @@ -6796,6 +7041,13 @@ const char SCRIPT_MSG_SLIDER[] PROGMEM = const char SCRIPT_MSG_CHKBOX[] PROGMEM = "
"; +const char SCRIPT_MSG_PULLDOWNa[] PROGMEM = + "
"; + const char SCRIPT_MSG_TEXTINP[] PROGMEM = "
"; @@ -7098,7 +7350,43 @@ void ScriptWebShow(char mc) { uval = 1; } WSContentSend_PD(SCRIPT_MSG_CHKBOX, label, (char*)cp, uval, vname); + } else if (!strncmp(lin, "pd(", 3)) { + // pull down + char *lp = lin + 3; + char *slp = lp; + float val; + lp = GetNumericArgument(lp, OPER_EQU, &val, 0); + SCRIPT_SKIP_SPACES + char vname[16]; + ScriptGetVarname(vname, slp, sizeof(vname)); + + SCRIPT_SKIP_SPACES + char pulabel[SCRIPT_MAXSSIZE]; + lp = GetStringArgument(lp, OPER_EQU, pulabel, 0); + + WSContentSend_PD(SCRIPT_MSG_PULLDOWNa, vname, pulabel, 1, vname, vname); + + // get pu labels + uint8_t index = 1; + while (*lp) { + SCRIPT_SKIP_SPACES + lp = GetStringArgument(lp, OPER_EQU, pulabel, 0); + char *cp; + if (val == index) { + cp = (char*)"selected"; + } else { + cp = (char*)""; + } + WSContentSend_PD(SCRIPT_MSG_PULLDOWNb, cp, index, pulabel); + SCRIPT_SKIP_SPACES + if (*lp == ')') { + lp++; + break; + } + index++; + } + WSContentSend_PD(SCRIPT_MSG_PULLDOWNc); } else if (!strncmp(lin, "bu(", 3)) { char *lp = lin + 3; uint8_t bcnt = 0; @@ -8295,6 +8583,42 @@ void lvgl_setup(void) { #endif // USE_LVGL + +#ifdef USE_TIMERS +int32_t get_tpars(uint32_t index, uint32_t sel) { +int32_t retval = 0; + switch (sel) { + case 0: + retval = Settings->timer[index].time; + break; + case 1: + //retval = Settings->timer[index].window; + retval = timer_window[index]; + break; + case 2: + retval = Settings->timer[index].repeat; + break; + case 3: + retval = Settings->timer[index].days; + break; + case 4: + retval = Settings->timer[index].device; + break; + case 5: + retval = Settings->timer[index].power; + break; + case 6: + retval = Settings->timer[index].mode; + break; + case 7: + retval = Settings->timer[index].arm; + break; + } + return retval; +} + +#endif + /*********************************************************************************************\ * Interface \*********************************************************************************************/ diff --git a/tasmota/xdrv_12_discovery.ino b/tasmota/xdrv_12_discovery.ino index 3ade73dbb..da92495d5 100644 --- a/tasmota/xdrv_12_discovery.ino +++ b/tasmota/xdrv_12_discovery.ino @@ -215,7 +215,7 @@ void TasDiscovery(void) { if (!Settings->flag.hass_discovery) { // SetOption19 - Clear retained message Response_P(PSTR("{\"sn\":")); - MqttShowSensor(); + MqttShowSensor(true); ResponseAppend_P(PSTR(",\"ver\":1}")); } snprintf_P(stopic, sizeof(stopic), PSTR("tasmota/discovery/%s/sensors"), NetworkUniqueId().c_str()); diff --git a/tasmota/xdrv_12_home_assistant.ino b/tasmota/xdrv_12_home_assistant.ino index e57981677..2ece432c7 100644 --- a/tasmota/xdrv_12_home_assistant.ino +++ b/tasmota/xdrv_12_home_assistant.ino @@ -128,6 +128,24 @@ const char HASS_DISCOVER_SHUTTER_POS[] PROGMEM = "\"pos_open\":100," "\"set_pos_t\":\"%s%d\""; // cmnd/%topic%/ShutterPosition1 +const char HASS_DISCOVER_SHUTTER_TILT[] PROGMEM = + ",\"tilt_cmd_t\":\"%s%d\"," // cmnd/%topic%/ShutterTilt1 + "\"tilt_opnd_val\":%d," + "\"tilt_clsd_val\":%d"; + +/* +"tilt_clsd_val": "tilt_closed_value", +"tilt_cmd_t": "tilt_command_topic", +"tilt_cmd_tpl": "tilt_command_template", +"tilt_inv_stat": "tilt_invert_state", +"tilt_max": "tilt_max", +"tilt_min": "tilt_min", +"tilt_opnd_val": "tilt_opened_value", +"tilt_opt": "tilt_optimistic", +"tilt_status_t": "tilt_status_topic", +"tilt_status_tpl": "tilt_status_template", +*/ + const char HASS_DISCOVER_SENSOR_HASS_STATUS[] PROGMEM = ",\"json_attr_t\":\"%s\"," "\"unit_of_meas\":\"%%\"," @@ -364,7 +382,7 @@ void NewHAssDiscovery(void) { if (!Settings->flag.hass_discovery) { // SetOption19 - Clear retained message Response_P(PSTR("{\"sn\":")); - MqttShowSensor(); + MqttShowSensor(true); ResponseAppend_P(PSTR(",\"ver\":1}")); } snprintf_P(stopic, sizeof(stopic), PSTR("tasmota/discovery/%s/sensors"), NetworkUniqueId().c_str()); @@ -1020,7 +1038,10 @@ void HAssAnnounceShutters(void) GetTopic_P(stemp1, STAT, TasmotaGlobal.mqtt_topic, PSTR("SHUTTER")); GetTopic_P(stemp2, CMND, TasmotaGlobal.mqtt_topic, PSTR("ShutterPosition")); TryResponseAppend_P(HASS_DISCOVER_SHUTTER_POS, stemp1, i + 1, stemp2, i + 1); - + + GetTopic_P(stemp1, CMND, TasmotaGlobal.mqtt_topic, PSTR("ShutterTilt")); + TryResponseAppend_P(HASS_DISCOVER_SHUTTER_TILT, stemp1, i + 1, Settings->shutter_tilt_config[3][i], Settings->shutter_tilt_config[4][i]); + TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP_getChipId()); TryResponseAppend_P(PSTR("}")); } else { diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino index da4439f61..4b4a988cf 100755 --- a/tasmota/xdrv_13_display.ino +++ b/tasmota/xdrv_13_display.ino @@ -67,7 +67,7 @@ struct MULTI_DISP { uint8_t used; } displays[MAX_MULTI_DISPLAYS]; uint8_t cur_display; -Renderer *Init_uDisplay(const char *desc, int8_t cs); +Renderer *Init_uDisplay(const char *desc); void Set_display(uint8_t index) { displays[index].display = renderer; @@ -631,7 +631,7 @@ void DisplayText(void) srot = Settings->display_rotate; Settings->display_rotate = rot; } - renderer = Init_uDisplay(fdesc, -1); + renderer = Init_uDisplay(fdesc); if (rot >= 0) { Settings->display_rotate = srot; } @@ -701,6 +701,12 @@ void DisplayText(void) if (renderer) renderer->fillCircle(disp_xpos, disp_ypos, temp, fg_color); //else DisplayDrawFilledCircle(disp_xpos, disp_ypos, temp, fg_color); break; + case 'm': + // epaper draw mode currently only for 4,7 inch displays + var = atoiv(cp, &temp); + cp += var; + if (renderer) renderer->ep_update_mode(temp); + break; case 'r': // rectangle var = atoiv(cp, &temp); @@ -723,7 +729,27 @@ void DisplayText(void) break; case 'u': // rounded rectangle - { int16_t rad; + { int16_t rad, xp, yp, width, height; + if (*cp == 'p') { + // update epaper display + cp++; + var = atoiv(cp, &xp); + cp += var; + cp++; + var = atoiv(cp, &yp); + cp += var; + cp++; + var = atoiv(cp, &width); + cp += var; + cp++; + var = atoiv(cp, &height); + cp += var; + cp++; + var = atoiv(cp, &temp); + cp += var; + if (renderer) renderer->ep_update_area(xp, yp, width, height, temp); + break; + } var = atoiv(cp, &temp); cp += var; cp++; @@ -1100,7 +1126,7 @@ extern FS *ffsp; if (buttons[num]) { if (!sbt) { buttons[num]->vpower.slider = 0; - buttons[num]->initButtonUL(renderer, gxp, gyp, gxs, gys, GetColorFromIndex(outline),\ + buttons[num]->xinitButtonUL(renderer, gxp, gyp, gxs, gys, GetColorFromIndex(outline),\ GetColorFromIndex(fill), GetColorFromIndex(textcolor), bbuff, textsize); if (!bflags) { // power button @@ -1969,6 +1995,7 @@ void ApplyDisplayDimmer(void) { // still call Berry virtual display in case it is not managed entirely by renderer Xdsp18(FUNC_DISPLAY_DIM); #endif // USE_BERRY + } else { XdspCall(FUNC_DISPLAY_DIM); } @@ -2631,7 +2658,11 @@ void Restore_graph(uint8_t num, char *path) { if (count<=4) { if (count==0) gp->xcnt=atoi(vbuff); } else { - gp->values[count-5]=atoi(vbuff); + uint8_t yval = atoi(vbuff); + if (yval >= gp->ys) { + yval = gp->ys - 1; + } + gp->values[count-5] = yval; } } fp.close(); @@ -2735,9 +2766,9 @@ void AddValue(uint8_t num,float fval) { // decimation option if (gp->decimation<0) { if (gp->dcnt>=-gp->decimation) { - gp->dcnt=0; // calc average - val=gp->summ/-gp->decimation; + val=gp->summ/gp->dcnt; + gp->dcnt=0; gp->summ=0; // add to graph AddGraph(num,val); diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino index 494d26fb8..f2d3334eb 100644 --- a/tasmota/xdrv_23_zigbee_5_converters.ino +++ b/tasmota/xdrv_23_zigbee_5_converters.ino @@ -1311,8 +1311,9 @@ void ZCLFrame::computeSyntheticAttributes(Z_attribute_list& attr_list) { } break; case 0x00010021: // BatteryPercentage - if (modelId.startsWith(F("TRADFRI"))) { - attr.setUInt(attr.getUInt() * 2); // bug in TRADFRI battery, need to double the value + 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" diff --git a/tasmota/xdrv_27_shutter.ino b/tasmota/xdrv_27_shutter.ino index 9e57438a8..198fbb9c1 100644 --- a/tasmota/xdrv_27_shutter.ino +++ b/tasmota/xdrv_27_shutter.ino @@ -47,6 +47,7 @@ int32_t current_stop_way = 0; int32_t next_possible_stop_position = 0; int32_t current_real_position = 0; int32_t current_pwm_velocity = 0; +int8_t savedata_original = 0; const uint8_t MAX_MODES = 7; enum Shutterposition_mode {SHT_UNDEF, SHT_TIME, SHT_TIME_UP_DOWN, SHT_TIME_GARAGE, SHT_COUNTER, SHT_PWM_VALUE, SHT_PWM_TIME,}; @@ -59,7 +60,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_UNITTEST "|" D_CMND_SHUTTER_TILTCONFIG "|" D_CMND_SHUTTER_SETTILT "|" D_CMND_SHUTTER_TILTINCDEC "|"; void (* const ShutterCommand[])(void) PROGMEM = { &CmndShutterOpen, &CmndShutterClose, &CmndShutterToggle, &CmndShutterToggleDir, &CmndShutterStop, &CmndShutterPosition, @@ -67,9 +68,9 @@ void (* const ShutterCommand[])(void) PROGMEM = { &CmndShutterSetHalfway, &CmndShutterSetClose, &CmndShutterSetOpen, &CmndShutterInvert, &CmndShutterCalibration , &CmndShutterMotorDelay, &CmndShutterFrequency, &CmndShutterButton, &CmndShutterLock, &CmndShutterEnableEndStopTime, &CmndShutterInvertWebButtons, &CmndShutterStopOpen, &CmndShutterStopClose, &CmndShutterStopToggle, &CmndShutterStopToggleDir, &CmndShutterStopPosition, &CmndShutterIncDec, - &CmndShutterUnitTest}; + &CmndShutterUnitTest,&CmndShutterTiltConfig,&CmndShutterSetTilt,&CmndShutterTiltIncDec}; - const char JSON_SHUTTER_POS[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Position\":%d,\"Direction\":%d,\"Target\":%d}"; + const char JSON_SHUTTER_POS[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Position\":%d,\"Direction\":%d,\"Target\":%d,\"Tilt\":%d}"; const char JSON_SHUTTER_BUTTON[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Button%d\":%d}"; #include @@ -93,6 +94,16 @@ struct SHUTTER { uint16_t pwm_value; // dutyload of PWM 0..1023 on ESP8266 uint16_t close_velocity_max; // maximum of PWM change during closeing. Defines velocity on opening. Steppers and Servos only int32_t accelerator; // speed of ramp-up, ramp down of shutters with velocity control. Steppers and Servos only + int8_t tilt_config[5]; // tilt_min, tilt_max, duration, tilt_closed_value, tilt_opened_value + int8_t tilt_real_pos; // -90 to 90 + int8_t tilt_target_pos; // target positon for movements of the tilt + int8_t tilt_start_pos; // saved start position before shutter moves + uint8_t tilt_velocity; // degree rotation per step 0.05sec + int8_t tiltmoving; // 0 operating move, 1 = operating tilt + uint16_t venetian_delay = 0; // Delay in steps before venetian shutter start physical moving. Based on tilt position + uint16_t min_realPositionChange = 0; // minimum change of the position before the shutter operates. different for PWM and time based operations + uint16_t min_TiltChange = 0; // minimum change of the tilt before the shutter operates. different for PWM and time based operations + uint16_t last_reported_time =0; } Shutter[MAX_SHUTTERS]; struct SHUTTERGLOBAL { @@ -102,7 +113,7 @@ struct SHUTTERGLOBAL { uint8_t position_mode = 0; // how to calculate actual position: SHT_TIME, SHT_COUNTER, SHT_PWM_VALUE, SHT_PWM_TIME uint8_t skip_relay_change; // avoid overrun at endstops uint8_t start_reported = 0; // indicates of the shutter start was reported through MQTT JSON - uint16_t open_velocity_max = 1000; // maximum of PWM change during opening. Defines velocity on opening. Steppers and Servos only + uint16_t open_velocity_max = RESOLUTION; // maximum of PWM change during opening. Defines velocity on opening. Steppers and Servos only } ShutterGlobal; #define SHT_DIV_ROUND(__A, __B) (((__A) + (__B)/2) / (__B)) @@ -111,8 +122,9 @@ void ShutterLogPos(uint32_t i) { char stemp2[10]; dtostrfd((float)Shutter[i].time / STEPS_PER_SECOND, 2, stemp2); - AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d Real %d, Start %d, Stop %d, Dir %d, Delay %d, Rtc %s [s], Freq %d, PWM %d"), - i+1, Shutter[i].real_position, Shutter[i].start_position, Shutter[i].target_position, Shutter[i].direction, Shutter[i].motordelay, stemp2, Shutter[i].pwm_velocity, Shutter[i].pwm_value); + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d Real %d, Start %d, Stop %d, Dir %d, Delay %d, Rtc %s [s], Freq %d, PWM %d, Tilt %d"), + i+1, Shutter[i].real_position, Shutter[i].start_position, Shutter[i].target_position, Shutter[i].direction, Shutter[i].motordelay, stemp2, + Shutter[i].pwm_velocity, Shutter[i].pwm_value,Shutter[i].tilt_real_pos); } void ExecuteCommandPowerShutter(uint32_t device, uint32_t state, uint32_t source) @@ -312,20 +324,34 @@ void ShutterInit(void) Shutter[i].motordelay = Settings->shutter_motordelay[i]; Shutter[i].lastdirection = (50 < Settings->shutter_position[i]) ? 1 : -1; + // Venetian Blind + for (uint8_t k=0; k<5; k++) { + Shutter[i].tilt_config[k] = Settings->shutter_tilt_config[k][i]; + } + Shutter[i].tilt_target_pos = Shutter[i].tilt_real_pos = Settings->shutter_tilt_pos[i]; + + Shutter[i].tilt_velocity = Shutter[i].tilt_config[2] > 0 ? ((Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0])/Shutter[i].tilt_config[2])+1 : 1; + + Shutter[i].close_velocity_max = ShutterGlobal.open_velocity_max*Shutter[i].open_time / Shutter[i].close_time; + + Shutter[i].min_realPositionChange = 2 * tmax(ShutterGlobal.open_velocity_max, Shutter[i].close_velocity_max); + Shutter[i].min_TiltChange = 2 * Shutter[i].tilt_velocity; + switch (ShutterGlobal.position_mode) { case SHT_PWM_VALUE: ShutterGlobal.open_velocity_max = RESOLUTION; // Initiate pwm range with defaults if not already set. Settings->shutter_pwmrange[0][i] = Settings->shutter_pwmrange[0][i] > 0 ? Settings->shutter_pwmrange[0][i] : pwm_servo_min; Settings->shutter_pwmrange[1][i] = Settings->shutter_pwmrange[1][i] > 0 ? Settings->shutter_pwmrange[1][i] : pwm_servo_max; + Shutter[i].min_realPositionChange = 0; + Shutter[i].min_TiltChange = 0; break; } - Shutter[i].close_velocity_max = ShutterGlobal.open_velocity_max*Shutter[i].open_time / Shutter[i].close_time; - - //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Openvel %d, Closevel: %d"),i, ShutterGlobal.open_velocity_max, Shutter[i].close_velocity_max); - AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d Init. Pos %d, Inverted %d, Locked %d, End stop time enabled %d, webButtons inverted %d"), + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d min realpos_chg: %d, min tilt_chg %d"),i+1,Shutter[i].min_realPositionChange,Shutter[i].min_TiltChange); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Openvel %d, Closevel: %d"),i, ShutterGlobal.open_velocity_max, Shutter[i].close_velocity_max); + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr%d Init. Pos %d, Inv %d, Locked %d, Endstop enab %d, webButt inv %d, Motordel: %d"), i+1, Shutter[i].real_position, - (Settings->shutter_options[i]&1) ? 1 : 0, (Settings->shutter_options[i]&2) ? 1 : 0, (Settings->shutter_options[i]&4) ? 1 : 0, (Settings->shutter_options[i]&8) ? 1 : 0); + (Settings->shutter_options[i]&1) ? 1 : 0, (Settings->shutter_options[i]&2) ? 1 : 0, (Settings->shutter_options[i]&4) ? 1 : 0, (Settings->shutter_options[i]&8) ? 1 : 0, Shutter[i].motordelay); } else { // terminate loop at first INVALID Shutter[i]. @@ -339,9 +365,9 @@ void ShutterInit(void) void ShutterReportPosition(bool always, uint32_t index) { Response_P(PSTR("{")); - TasmotaGlobal.rules_flag.shutter_moving = 0; uint32_t i = 0; uint32_t n = TasmotaGlobal.shutters_present; + uint8_t shutter_running = 0; if( index != MAX_SHUTTERS) { i = index; n = index+1; @@ -350,21 +376,22 @@ void ShutterReportPosition(bool always, uint32_t index) //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) { - TasmotaGlobal.rules_flag.shutter_moving = 1; ShutterLogPos(i); + shutter_running++; } if (i && index == MAX_SHUTTERS) { ResponseAppend_P(PSTR(",")); } 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 ); + 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 ); } ResponseJsonEnd(); - if (always || (TasmotaGlobal.rules_flag.shutter_moving)) { + if (always || shutter_running) { MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_PRFX_SHUTTER)); // RulesProcess() now re-entry protected } //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: rules_flag.shutter_moving: %d, moved %d"), TasmotaGlobal.rules_flag.shutter_moving, TasmotaGlobal.rules_flag.shutter_moved); } -void ShutterLimitRealAndTargetPositions(uint32_t i) { +void ShutterLimitRealAndTargetPositions(uint32_t i) +{ if (Shutter[i].real_position<0) Shutter[i].real_position = 0; if (Shutter[i].real_position>Shutter[i].open_max) Shutter[i].real_position = Shutter[i].open_max; if (Shutter[i].target_position<0) Shutter[i].target_position = 0; @@ -431,11 +458,12 @@ void ShutterDecellerateForStop(uint8_t i) //prepare for stop PWM Shutter[i].accelerator = 0; Shutter[i].pwm_velocity = 0; + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Remain %d count %d -> target %d, dir %d"), missing_steps, RtcSettings.pulse_counter[i], (uint32_t)(Shutter[i].target_position-Shutter[i].start_position)*Shutter[i].direction*ShutterGlobal.open_velocity_max/RESOLUTION/STEPS_PER_SECOND, Shutter[i].direction); while (RtcSettings.pulse_counter[i] < (uint32_t)(Shutter[i].target_position-Shutter[i].start_position)*Shutter[i].direction*ShutterGlobal.open_velocity_max/RESOLUTION/STEPS_PER_SECOND && missing_steps > 0) { } analogWrite(Pin(GPIO_PWM1, i), 0); // removed with 8.3 because of reset caused by watchog Shutter[i].real_position = ShutterCalculatePosition(i); - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Remain steps %d"), missing_steps); + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Remain steps %d"), missing_steps); AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Real %d, Pulsecount %d, tobe %d, Start %d"), Shutter[i].real_position,RtcSettings.pulse_counter[i], (uint32_t)(Shutter[i].target_position-Shutter[i].start_position)*Shutter[i].direction*ShutterGlobal.open_velocity_max/RESOLUTION/STEPS_PER_SECOND, Shutter[i].start_position); } Shutter[i].direction = 0; @@ -444,16 +472,24 @@ void ShutterDecellerateForStop(uint8_t i) } } -void ShutterPowerOff(uint8_t i) { - AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Stop Shutter %d. Switchmode %d"), i+1,Shutter[i].switch_mode); // fix log to indicate correct shutter number +void ShutterPowerOff(uint8_t i) +{ + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Stop %d. Mode %d, time:%d"), i+1,Shutter[i].switch_mode, Shutter[i].time); // fix log to indicate correct shutter number ShutterDecellerateForStop(i); + if (Shutter[i].direction !=0) { + Shutter[i].direction = 0; + } + if (Shutter[i].real_position == Shutter[i].start_position) { + //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Update target tilt shutter %d from %d to %d"), i+1, Shutter[i].tilt_target_pos , Shutter[i].tilt_real_pos); + Shutter[i].tilt_target_pos = Shutter[i].tilt_real_pos; + } + TasmotaGlobal.rules_flag.shutter_moved = 1; switch (Shutter[i].switch_mode) { case SHT_SWITCH: - if ((1 << (Settings->shutter_startrelay[i]-1)) & TasmotaGlobal.power) { - ExecuteCommandPowerShutter(Settings->shutter_startrelay[i], 0, SRC_SHUTTER); - } - if ((1 << (Settings->shutter_startrelay[i])) & TasmotaGlobal.power) { - ExecuteCommandPowerShutter(Settings->shutter_startrelay[i]+1, 0, SRC_SHUTTER); + for (int8_t k=0;k<2;k++) { + if ((1 << (Settings->shutter_startrelay[i]+k-1)) & TasmotaGlobal.power) { + ExecuteCommandPowerShutter(Settings->shutter_startrelay[i]+k, 0, SRC_SHUTTER); + } } break; case SHT_PULSE: @@ -473,25 +509,23 @@ void ShutterPowerOff(uint8_t i) { // Store current PWM value to ensure proper position after reboot. switch (ShutterGlobal.position_mode) { case SHT_PWM_VALUE: - char scmnd[20]; -#ifdef SHUTTER_CLEAR_PWM_ONSTOP - // free the PWM servo lock on stop. - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_PWM "%d 0" ), i+1); -#else - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_PWM "%d %d" ), i+1,Shutter[i].pwm_value); -#endif - ExecuteCommand(scmnd, SRC_BUTTON); - break; - } - if (Shutter[i].direction !=0) { - Shutter[i].direction = 0; - delay(MOTOR_STOP_TIME); + Shutter[i].pwm_value = SHT_DIV_ROUND((Settings->shutter_pwmrange[1][i]-Settings->shutter_pwmrange[0][i]) * Shutter[i].target_position , Shutter[i].open_max)+Settings->shutter_pwmrange[0][i]; + analogWrite(Pin(GPIO_PWM1, i), Shutter[i].pwm_value); + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: PWM final %d"),Shutter[i].pwm_value); + char scmnd[20]; + #ifdef SHUTTER_CLEAR_PWM_ONSTOP + // free the PWM servo lock on stop. + analogWrite(Pin(GPIO_PWM1, i), 0); + #endif + break; } + Settings->save_data = savedata_original; + TasmotaGlobal.save_data_counter = Settings->save_data; + delay(MOTOR_STOP_TIME); } void ShutterUpdatePosition(void) { - char scommand[CMDSZ]; char stopic[TOPSZ]; for (uint32_t i = 0; i < TasmotaGlobal.shutters_present; i++) { @@ -501,11 +535,15 @@ void ShutterUpdatePosition(void) XdrvRulesProcess(0); ShutterGlobal.start_reported = 1; } - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Time %d, cStop %d, cVelo %d, mVelo %d, aVelo %d, mRun %d, aPos %d, nStop %d, Trgt %d, mVelo %d, Dir %d"), - Shutter[i].time, current_stop_way, current_pwm_velocity, velocity_max, Shutter[i].accelerator, min_runtime_ms, current_real_position, - next_possible_stop_position, Shutter[i].target_position, velocity_change_per_step_max, Shutter[i].direction); - - if ( Shutter[i].real_position * Shutter[i].direction >= Shutter[i].target_position * Shutter[i].direction || (ShutterGlobal.position_mode == SHT_COUNTER && Shutter[i].accelerator <0 && Shutter[i].pwm_velocity+Shutter[i].accelerator= Shutter[i].target_position * Shutter[i].direction && Shutter[i].tiltmoving==0) || + ((int16_t)Shutter[i].tilt_real_pos * Shutter[i].direction * Shutter[i].tilt_config[2] >= (int16_t)Shutter[i].tilt_target_pos * Shutter[i].direction * Shutter[i].tilt_config[2] && Shutter[i].tiltmoving==1)) + || (ShutterGlobal.position_mode == SHT_COUNTER && Shutter[i].accelerator <0 && Shutter[i].pwm_velocity+Shutter[i].acceleratorshutter_position[i] = ShutterRealToPercentPosition(Shutter[i].real_position, i); 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) { + 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; + XdrvMailbox.payload = -99; + XdrvMailbox.index = i+1; + Shutter[i].tiltmoving = 1; + CmndShutterPosition(); + return; + } else { + Settings->shutter_tilt_pos[i] = Shutter[i].tilt_real_pos; + } ShutterLogPos(i); // sending MQTT result to broker @@ -529,7 +581,8 @@ void ShutterUpdatePosition(void) } } -bool ShutterState(uint32_t device) { +bool ShutterState(uint32_t device) +{ if (device > 4) { return false; } device--; device &= 3; @@ -541,22 +594,22 @@ void ShutterAllowPreStartProcedure(uint8_t i) { #ifdef USE_RULES uint32_t uptime_Local=0; - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Delay Start. var%d <99>=<%s>, max10s?"),i+1, rules_vars[i]); - TasmotaGlobal.rules_flag.shutter_moving = 1; + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Delay Start? var%d <99>=<%s>, max10s?"),i+1, rules_vars[i]); XdrvRulesProcess(0); uptime_Local = TasmotaGlobal.uptime; while (uptime_Local+10 > TasmotaGlobal.uptime && (String)rules_vars[i] == "99") { loop(); } - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Delay Start. Done")); + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Delay Start. Done")); #endif // USE_RULES } void ShutterStartInit(uint32_t i, int32_t direction, int32_t target_pos) { - //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: dir %d, delta1 %d, delta2 %d, grant %d"),direction, (Shutter[i].open_max - Shutter[i].real_position) / Shutter[i].close_velocity, Shutter[i].real_position / Shutter[i].close_velocity, 2+Shutter[i].motordelay); - if ( ( (1 == direction) && ((Shutter[i].open_max - Shutter[i].real_position) / 100 <= 2) ) - || ( (-1 == direction) && (Shutter[i].real_position / Shutter[i].close_velocity <= 2)) ) { + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: dir %d, delta1 %d, delta2 %d"),direction, (Shutter[i].open_max - Shutter[i].real_position) / Shutter[i].close_velocity, Shutter[i].real_position / Shutter[i].close_velocity); + if ( ( ( (1 == direction) && ((Shutter[i].open_max - Shutter[i].real_position) <= Shutter[i].min_realPositionChange)) + || ( (-1 == direction) && (Shutter[i].real_position <= Shutter[i].min_realPositionChange)) ) + && abs(Shutter[i].tilt_real_pos-Shutter[i].tilt_target_pos) <= Shutter[i].min_TiltChange) { ShutterGlobal.skip_relay_change = 1; } else { Shutter[i].pwm_velocity = 0; @@ -569,19 +622,33 @@ void ShutterStartInit(uint32_t i, int32_t direction, int32_t target_pos) break; #endif } + Shutter[i].accelerator = ShutterGlobal.open_velocity_max / (Shutter[i].motordelay>0 ? Shutter[i].motordelay : 1); Shutter[i].target_position = target_pos; Shutter[i].start_position = Shutter[i].real_position; TasmotaGlobal.rules_flag.shutter_moving = 1; ShutterAllowPreStartProcedure(i); - Shutter[i].time = 0; - Shutter[i].direction = direction; + Shutter[i].time = Shutter[i].last_reported_time = 0; + + // avoid file system writes during move to minimize missing steps + savedata_original = Settings->save_data; + Settings->save_data = 0; // will be restored after movement + + TasmotaGlobal.save_data_counter = Settings->save_data; ShutterGlobal.skip_relay_change = 0; TasmotaGlobal.rules_flag.shutter_moved = 0; ShutterGlobal.start_reported = 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 , Shutter[i].direction ,ShutterGlobal.open_velocity_max ); + 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]); + //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); + } } - //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Start shtr%d from %d to %d in direction %d"), i, Shutter[i].start_position, Shutter[i].target_position, Shutter[i].direction); + //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Start shtr%d from %d to %d in dir: %d"), i, Shutter[i].start_position, Shutter[i].target_position, direction); + Shutter[i].direction = direction; // Last action. This causes RTC to start. } int32_t ShutterCalculatePosition(uint32_t i) @@ -595,7 +662,14 @@ int32_t ShutterCalculatePosition(uint32_t i) case SHT_TIME: case SHT_TIME_UP_DOWN: case SHT_TIME_GARAGE: - return Shutter[i].start_position + ( (Shutter[i].time - Shutter[i].motordelay) * (Shutter[i].direction > 0 ? RESOLUTION : -Shutter[i].close_velocity)); + if (Shutter[i].tilt_config[2] > 0) { + if (Shutter[i].time <= Shutter[i].venetian_delay) { + Shutter[i].tilt_real_pos = (Shutter[i].tilt_start_pos + ((Shutter[i].direction * (int16_t)Shutter[i].time * (Shutter[i].tilt_config[1]-Shutter[i].tilt_config[0])) / Shutter[i].tilt_config[2])); + } else { + Shutter[i].tilt_real_pos = Shutter[i].direction == 1 ? Shutter[i].tilt_config[1] : Shutter[i].tilt_config[0]; + } + } + return Shutter[i].start_position + ( (Shutter[i].time - tmin(Shutter[i].venetian_delay+Shutter[i].motordelay, Shutter[i].time)) * (Shutter[i].direction > 0 ? RESOLUTION : -Shutter[i].close_velocity)); break; case SHT_PWM_TIME: break; @@ -624,8 +698,8 @@ void ShutterRelayChanged(void) // SRC_IGNORE added because INTERLOCK function bite causes this as last source for changing the relay. //uint8 manual_relays_changed = ((ShutterGlobal.RelayCurrentMask >> (Settings->shutter_startrelay[i] -1)) & 3) && SRC_IGNORE != TasmotaGlobal.last_source && SRC_SHUTTER != TasmotaGlobal.last_source && SRC_PULSETIMER != TasmotaGlobal.last_source ; uint8 manual_relays_changed = ((ShutterGlobal.RelayCurrentMask >> (Settings->shutter_startrelay[i] -1)) & 3) && SRC_SHUTTER != TasmotaGlobal.last_source && SRC_PULSETIMER != TasmotaGlobal.last_source ; - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d, Source %s, Powerstate %ld, RelayMask %d, ManualChange %d"), - i+1, GetTextIndexed(stemp1, sizeof(stemp1), TasmotaGlobal.last_source, kCommandSource), powerstate_local,ShutterGlobal.RelayCurrentMask,manual_relays_changed); + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d, Source %s, Powerstate %ld, RelayMask %d, ManualChange %d"), + // i+1, GetTextIndexed(stemp1, sizeof(stemp1), TasmotaGlobal.last_source, kCommandSource), powerstate_local,ShutterGlobal.RelayCurrentMask,manual_relays_changed); if (manual_relays_changed) { //ShutterGlobal.skip_relay_change = true; ShutterLimitRealAndTargetPositions(i); @@ -642,12 +716,16 @@ void ShutterRelayChanged(void) TasmotaGlobal.last_source = SRC_SHUTTER; // avoid switch off in the next loop if (Shutter[i].direction != 0 ) Shutter[i].target_position = Shutter[i].real_position; } + if (powerstate_local > 0) { + Shutter[i].tiltmoving = 0; + } switch (ShutterGlobal.position_mode) { // enum Shutterposition_mode {SHT_TIME, SHT_TIME_UP_DOWN, SHT_TIME_GARAGE, SHT_COUNTER, SHT_PWM_VALUE, SHT_PWM_TIME,}; case SHT_TIME_UP_DOWN: case SHT_COUNTER: case SHT_PWM_VALUE: case SHT_PWM_TIME: + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: power off manual change")); ShutterPowerOff(i); switch (powerstate_local) { case 1: @@ -686,12 +764,13 @@ void ShutterRelayChanged(void) } // switch (ShutterGlobal.position_mode) - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d, Target %ld, Powerstatelocal %d"), i+1, Shutter[i].target_position, powerstate_local); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d, Target %ld, Power: %d, tiltmv: %d"), i+1, Shutter[i].target_position, powerstate_local,Shutter[i].tiltmoving); } // if (manual_relays_changed) } // for (uint32_t i = 0; i < TasmotaGlobal.shutters_present; i++) } -bool ShutterButtonIsSimultaneousHold(uint32_t button_index, uint32_t shutter_index) { +bool ShutterButtonIsSimultaneousHold(uint32_t button_index, uint32_t shutter_index) +{ // check for simultaneous shutter button hold uint32 min_shutterbutton_hold_timer = -1; // -1 == max(uint32) for (uint32_t i = 0; i < MAX_SHUTTER_KEYS; i++) { @@ -892,7 +971,7 @@ void ShutterSetPosition(uint32_t device, uint32_t position) void ShutterToggle(bool dir) { - AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Payload toggle: %d, i %d, dir %d, lastdir %d"), XdrvMailbox.payload, XdrvMailbox.index, dir, Shutter[XdrvMailbox.index-1].lastdirection); + AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Toggle: %d, i %d, dir %d, lastdir %d"), XdrvMailbox.payload, XdrvMailbox.index, dir, Shutter[XdrvMailbox.index-1].lastdirection); if ((1 == XdrvMailbox.index) && (XdrvMailbox.payload != -99)) { XdrvMailbox.index = XdrvMailbox.payload; } @@ -1031,7 +1110,6 @@ void CmndShutterIncDec(void) } } - void CmndShutterPosition(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { @@ -1075,15 +1153,26 @@ void CmndShutterPosition(void) Shutter[index].target_position = ShutterPercentToRealPosition(target_pos_percent, index); //Shutter[i].accelerator[index] = ShutterGlobal.open_velocity_max / ((Shutter[i].motordelay[index] > 0) ? Shutter[i].motordelay[index] : 1); //Shutter[i].target_position[index] = XdrvMailbox.payload < 5 ? Settings->shuttercoeff[2][index] * XdrvMailbox.payload : Settings->shuttercoeff[1][index] * XdrvMailbox.payload + Settings->shuttercoeff[0,index]; - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: lastsource %d:, real %d, target %d, payload %d"), TasmotaGlobal.last_source, Shutter[index].real_position ,Shutter[index].target_position,target_pos_percent); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: lastsource %d:, real %d, target %d, tiltreal: %d, tilttarget: %d, payload %d"), TasmotaGlobal.last_source, Shutter[index].real_position ,Shutter[index].target_position,Shutter[index].tilt_real_pos, Shutter[index].tilt_target_pos,target_pos_percent); } - if ( (target_pos_percent >= 0) && (target_pos_percent <= 100) && abs(Shutter[index].target_position - Shutter[index].real_position ) / Shutter[index].close_velocity > 2) { + if ( (target_pos_percent >= 0) && (target_pos_percent <= 100) && + (abs(Shutter[index].target_position - Shutter[index].real_position ) > Shutter[index].min_realPositionChange || + abs(Shutter[index].tilt_target_pos - Shutter[index].tilt_real_pos ) > Shutter[index].min_TiltChange) ) { if (Settings->shutter_options[index] & 4) { if (0 == target_pos_percent) Shutter[index].target_position -= 1 * RESOLUTION * STEPS_PER_SECOND; if (100 == target_pos_percent) Shutter[index].target_position += 1 * RESOLUTION * STEPS_PER_SECOND; } - int8_t new_shutterdirection = Shutter[index].real_position < Shutter[index].target_position ? 1 : -1; + int8_t new_shutterdirection; + if (abs(Shutter[index].target_position - Shutter[index].real_position ) > Shutter[index].min_realPositionChange) { + new_shutterdirection = Shutter[index].real_position < Shutter[index].target_position ? 1 : -1; + Shutter[index].tiltmoving = 0; + } else { + new_shutterdirection = Shutter[index].tilt_real_pos < Shutter[index].tilt_target_pos ? 1 : -1; + Shutter[index].tiltmoving = 1; + } + if (Shutter[index].direction == -new_shutterdirection) { + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Stop shutter to reverse direction")); ShutterPowerOff(index); } if (Shutter[index].direction != new_shutterdirection) { @@ -1155,6 +1244,7 @@ void CmndShutterStopPosition(void) } } } + void CmndShutterOpenTime(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { @@ -1187,6 +1277,7 @@ void CmndShutterMotorDelay(void) if (XdrvMailbox.data_len > 0) { Settings->shutter_motordelay[XdrvMailbox.index -1] = (uint8_t)(STEPS_PER_SECOND * CharToFloat(XdrvMailbox.data)); ShutterInit(); + //AddLog(LOG_LEVEL_DEBUG, PSTR("SHT: Shtr Init1. realdelay %d"),Shutter[XdrvMailbox.index -1].motordelay); } char time_chr[10]; dtostrfd((float)(Shutter[XdrvMailbox.index -1].motordelay) / STEPS_PER_SECOND, 2, time_chr); @@ -1387,6 +1478,7 @@ void CmndShutterSetClose(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { Shutter[XdrvMailbox.index -1].real_position = 0; + Shutter[XdrvMailbox.index -1].tilt_real_pos = Shutter[XdrvMailbox.index -1].tilt_config[0]; ShutterStartInit(XdrvMailbox.index -1, 0, 0); Settings->shutter_position[XdrvMailbox.index -1] = 0; ResponseCmndIdxChar(D_CONFIGURATION_RESET); @@ -1397,6 +1489,7 @@ void CmndShutterSetOpen(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { Shutter[XdrvMailbox.index -1].real_position = Shutter[XdrvMailbox.index -1].open_max; + Shutter[XdrvMailbox.index -1].tilt_real_pos = Shutter[XdrvMailbox.index -1].tilt_config[1]; ShutterStartInit(XdrvMailbox.index -1, 0, Shutter[XdrvMailbox.index -1].open_max); Settings->shutter_position[XdrvMailbox.index -1] = 100; ResponseCmndIdxChar(D_CONFIGURATION_RESET); @@ -1467,7 +1560,8 @@ void CmndShutterCalibration(void) } } -void ShutterOptionsSetHelper(uint16_t option){ +void ShutterOptionsSetHelper(uint16_t option) +{ if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { if (XdrvMailbox.payload == 0) { Settings->shutter_options[XdrvMailbox.index -1] &= ~(option); @@ -1478,22 +1572,85 @@ void ShutterOptionsSetHelper(uint16_t option){ } } -void CmndShutterInvert(void) { +void CmndShutterInvert(void) +{ ShutterOptionsSetHelper(1); } -void CmndShutterLock(void) { +void CmndShutterLock(void) +{ ShutterOptionsSetHelper(2); } -void CmndShutterEnableEndStopTime(void) { +void CmndShutterEnableEndStopTime(void) +{ ShutterOptionsSetHelper(4); } -void CmndShutterInvertWebButtons(void) { +void CmndShutterInvertWebButtons(void) +{ ShutterOptionsSetHelper(8); } +void CmndShutterSetTilt(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + if (XdrvMailbox.payload != -99 ) { + Shutter[XdrvMailbox.index -1].tilt_target_pos = tmin(tmax(XdrvMailbox.payload, Shutter[XdrvMailbox.index -1].tilt_config[0]), Shutter[XdrvMailbox.index -1].tilt_config[1]); + XdrvMailbox.payload = -99; + } + if ((XdrvMailbox.data_len > 1) && (XdrvMailbox.payload <= 0)) { + if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_OPEN) ) { + Shutter[XdrvMailbox.index -1].tilt_target_pos = Shutter[XdrvMailbox.index -1].tilt_config[3]; // open position + XdrvMailbox.payload = -99; + } + if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_CLOSE) ) { + Shutter[XdrvMailbox.index -1].tilt_target_pos = Shutter[XdrvMailbox.index -1].tilt_config[4]; // close position + XdrvMailbox.payload = -99; + } + } + } + XdrvMailbox.data[0] = '\0'; + ResponseCmndNumber(Shutter[XdrvMailbox.index -1].tilt_target_pos); + Shutter[XdrvMailbox.index -1].tiltmoving = 1; + CmndShutterPosition(); +} + +void CmndShutterTiltConfig(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + if (XdrvMailbox.data_len > 0) { + uint8_t i = 0; + char *str_ptr; + char data_copy[strlen(XdrvMailbox.data) +1]; + strncpy(data_copy, XdrvMailbox.data, sizeof(data_copy)); // Duplicate data as strtok_r will modify it. + // Loop through the data string, splitting on ' ' seperators. + for (char *str = strtok_r(data_copy, " ", &str_ptr); str && i < 6; str = strtok_r(nullptr, " ", &str_ptr), i++) { + Shutter[XdrvMailbox.index -1].tilt_config[i] = Settings->shutter_tilt_config[i][XdrvMailbox.index -1] = atoi(str); + } + ShutterInit(); + ResponseCmndIdxChar(XdrvMailbox.data); + } else { + char setting_chr[30] = "0"; + snprintf_P(setting_chr, sizeof(setting_chr), PSTR("SHT:%d %d %d %d %d %d"), XdrvMailbox.index -1,Shutter[XdrvMailbox.index -1].tilt_config[0], Shutter[XdrvMailbox.index -1].tilt_config[1],Shutter[XdrvMailbox.index -1].tilt_config[2],Shutter[XdrvMailbox.index -1].tilt_config[3],Shutter[XdrvMailbox.index -1].tilt_config[4]); + ResponseCmndIdxChar(setting_chr); + } + AddLog(LOG_LEVEL_INFO, PSTR("SHT: TiltConfig %d, min: %d, max %d, runtime %d, close_pos: %d, open_pos: %d"), XdrvMailbox.index ,Shutter[XdrvMailbox.index -1].tilt_config[0], Shutter[XdrvMailbox.index -1].tilt_config[1],Shutter[XdrvMailbox.index -1].tilt_config[2],Shutter[XdrvMailbox.index -1].tilt_config[3],Shutter[XdrvMailbox.index -1].tilt_config[4]); + } +} + +void CmndShutterTiltIncDec(void) +{ + //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Change in: payload %s (%d), payload %d, idx %d, src %d"), XdrvMailbox.data , XdrvMailbox.data_len, XdrvMailbox.payload , XdrvMailbox.index, TasmotaGlobal.last_source ); + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= TasmotaGlobal.shutters_present)) { + if (XdrvMailbox.data_len > 0) { + XdrvMailbox.payload = Shutter[XdrvMailbox.index -1].tilt_target_pos+XdrvMailbox.payload; + CmndShutterSetTilt(); + } + } + ResponseCmndNumber(Shutter[XdrvMailbox.index -1].tilt_target_pos); +} + /*********************************************************************************************\ * Interface \*********************************************************************************************/ @@ -1524,7 +1681,7 @@ bool Xdrv27(uint8_t function) uint8_t target = (Settings->shutter_options[i] & 1) ? 100 - ShutterRealToPercentPosition(Shutter[i].target_position, i) : ShutterRealToPercentPosition(Shutter[i].target_position, i); ResponseAppend_P(","); - ResponseAppend_P(JSON_SHUTTER_POS, i+1, position, Shutter[i].direction,target); + ResponseAppend_P(JSON_SHUTTER_POS, i+1, position, Shutter[i].direction,target, Shutter[i].tilt_real_pos); #ifdef USE_DOMOTICZ if ((0 == TasmotaGlobal.tele_period) && (0 == i)) { DomoticzSensor(DZ_SHUTTER, position); diff --git a/tasmota/xdrv_35_pwm_dimmer.ino b/tasmota/xdrv_35_pwm_dimmer.ino index 261caa0c7..4b5101818 100644 --- a/tasmota/xdrv_35_pwm_dimmer.ino +++ b/tasmota/xdrv_35_pwm_dimmer.ino @@ -758,7 +758,7 @@ bool Xdrv35(uint8_t function) case FUNC_BUTTON_PRESSED: // If the button is pressed or was just released, ... - if (!XdrvMailbox.payload || button_pressed[XdrvMailbox.index]) { + if (!Settings->flag3.mqtt_buttons && (!XdrvMailbox.payload || button_pressed[XdrvMailbox.index])) { uint32_t button_index = XdrvMailbox.index; uint32_t now = millis(); diff --git a/tasmota/xdrv_39_thermostat.ino b/tasmota/xdrv_39_thermostat.ino index d016c3edc..60a8c7b10 100644 --- a/tasmota/xdrv_39_thermostat.ino +++ b/tasmota/xdrv_39_thermostat.ino @@ -778,7 +778,7 @@ void ThermostatCalculatePI(uint8_t ctr_output) // Minimum action limiter // If result is less than the minimum action time, adjust to minimum value - if ((Thermostat[ctr_output].time_total_pi <= abs(((uint32_t)Thermostat[ctr_output].time_min_action * 60))) + if ((Thermostat[ctr_output].time_total_pi <= abs(((int32_t)Thermostat[ctr_output].time_min_action * 60))) && (Thermostat[ctr_output].time_total_pi != 0)) { Thermostat[ctr_output].time_total_pi = ((int32_t)Thermostat[ctr_output].time_min_action * 60); } @@ -1253,6 +1253,7 @@ void ThermostatTimerDisarm(uint8_t ctr_output) } #ifdef DEBUG_THERMOSTAT + void ThermostatVirtualSwitch(uint8_t ctr_output) { char domoticz_in_topic[] = DOMOTICZ_IN_TOPIC; @@ -1327,6 +1328,27 @@ void ThermostatDebug(uint8_t ctr_output) } #endif // DEBUG_THERMOSTAT +uint8_t ThermostatGetDutyCycle(uint8_t ctr_output) +{ + uint8_t value = 0; + if ( (Thermostat[ctr_output].status.controller_mode == CTR_PI) + || ((Thermostat[ctr_output].status.controller_mode == CTR_HYBRID) + &&(Thermostat[ctr_output].status.phase_hybrid_ctr == CTR_HYBRID_PI))) { + value = Thermostat[ctr_output].time_total_pi / Thermostat[ctr_output].time_pi_cycle; + } + else if ( (Thermostat[ctr_output].status.controller_mode == CTR_RAMP_UP) + || ((Thermostat[ctr_output].status.controller_mode == CTR_HYBRID) + &&(Thermostat[ctr_output].status.phase_hybrid_ctr == CTR_HYBRID_RAMP_UP))) { + if (Thermostat[ctr_output].status.status_output == IFACE_ON) { + value = 100; + } + else { + value = 0; + } + } + return value; +} + void ThermostatGetLocalSensor(uint8_t ctr_output) { String buf = ResponseData(); // copy the string into a new buffer that will be modified JsonParser parser((char*)buf.c_str()); @@ -1950,23 +1972,8 @@ void CmndCtrDutyCycleRead(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= THERMOSTAT_CONTROLLER_OUTPUTS)) { uint8_t ctr_output = XdrvMailbox.index - 1; - uint8_t value = 0; - if ( (Thermostat[ctr_output].status.controller_mode == CTR_PI) - || ((Thermostat[ctr_output].status.controller_mode == CTR_HYBRID) - &&(Thermostat[ctr_output].status.phase_hybrid_ctr == CTR_HYBRID_PI))) { - value = Thermostat[ctr_output].time_total_pi / Thermostat[ctr_output].time_pi_cycle; - } - else if ( (Thermostat[ctr_output].status.controller_mode == CTR_RAMP_UP) - || ((Thermostat[ctr_output].status.controller_mode == CTR_HYBRID) - &&(Thermostat[ctr_output].status.phase_hybrid_ctr == CTR_HYBRID_RAMP_UP))) { - if (Thermostat[ctr_output].status.status_output == IFACE_ON) { - value = 100; - } - else { - value = 0; - } - } - ResponseCmndIdxNumber((int)value); + + ResponseCmndIdxNumber((int)ThermostatGetDutyCycle(ctr_output) ); } } @@ -1984,6 +1991,80 @@ void CmndEnableOutputSet(void) } } + + +/*********************************************************************************************\ + * Web UI +\*********************************************************************************************/ + + +// To be done, add all of this defines in according languages file when all will be finished +// Avoid multiple changes on all language files during developement +// -------------------------------------------------- +// xdrv_39_thermostat.ino +#define D_THERMOSTAT "Thermostat" +#define D_THERMOSTAT_SET_POINT "Set Point" +#define D_THERMOSTAT_SENSOR "Current" +#define D_THERMOSTAT_GRADIENT "Gradient" +#define D_THERMOSTAT_DUTY_CYCLE "Duty cycle" +#define D_THERMOSTAT_CYCLE_TIME "Cycle time" +#define D_THERMOSTAT_PI_AUTOTUNE "PI Auto tuning" +// -------------------------------------------------- + + +#ifdef USE_WEBSERVER +const char HTTP_THERMOSTAT_INFO[] PROGMEM = "{s}" D_THERMOSTAT "{m}%s{e}"; +const char HTTP_THERMOSTAT_TEMPERATURE[] PROGMEM = "{s}%s " D_TEMPERATURE "{m}%*_f " D_UNIT_DEGREE "%c{e}"; +const char HTTP_THERMOSTAT_DUTY_CYCLE[] PROGMEM = "{s}" D_THERMOSTAT_DUTY_CYCLE "{m}%d " D_UNIT_PERCENT "{e}"; +const char HTTP_THERMOSTAT_CYCLE_TIME[] PROGMEM = "{s}" D_THERMOSTAT_CYCLE_TIME "{m}%d " D_UNIT_MINUTE "{e}"; +const char HTTP_THERMOSTAT_PI_AUTOTUNE[] PROGMEM = "{s}" D_THERMOSTAT_PI_AUTOTUNE "{m}%s{e}"; +const char HTTP_THERMOSTAT_HL[] PROGMEM = "{s}
{m}
{e}"; + +#endif // USE_WEBSERVER + +void ThermostatShow(uint8_t ctr_output) +{ +#ifdef USE_WEBSERVER + + WSContentSend_P(HTTP_THERMOSTAT_HL); + + if (Thermostat[ctr_output].status.thermostat_mode == THERMOSTAT_OFF) { + WSContentSend_P(HTTP_THERMOSTAT_INFO, D_DISABLED ); + + } else { + char c_unit = Thermostat[ctr_output].status.temp_format==TEMP_CELSIUS ? D_UNIT_CELSIUS[0] : D_UNIT_FAHRENHEIT[0]; + float f_temperature ; + + WSContentSend_P(HTTP_THERMOSTAT_INFO, D_ENABLED ); + + f_temperature = Thermostat[ctr_output].temp_target_level / 10.0f ; + WSContentSend_PD(HTTP_THERMOSTAT_TEMPERATURE, D_THERMOSTAT_SET_POINT, Settings->flag2.temperature_resolution, &f_temperature, c_unit); + + f_temperature = Thermostat[ctr_output].temp_measured / 10.0f; + WSContentSend_PD(HTTP_THERMOSTAT_TEMPERATURE, D_THERMOSTAT_SENSOR, Settings->flag2.temperature_resolution, &f_temperature, c_unit); + + int16_t value = Thermostat[ctr_output].temp_measured_gradient; + if (Thermostat[ctr_output].status.temp_format == TEMP_FAHRENHEIT) { + value = ThermostatCelsiusToFahrenheit((int32_t)Thermostat[ctr_output].temp_measured_gradient, TEMP_CONV_RELATIVE); + } + f_temperature = value / 1000.0f; + WSContentSend_PD(HTTP_THERMOSTAT_TEMPERATURE, D_THERMOSTAT_GRADIENT, Settings->flag2.temperature_resolution, &f_temperature, c_unit); + WSContentSend_P(HTTP_THERMOSTAT_DUTY_CYCLE, ThermostatGetDutyCycle(ctr_output) ); + WSContentSend_P(HTTP_THERMOSTAT_CYCLE_TIME, Thermostat[ctr_output].time_pi_cycle ); + + #ifdef USE_PI_AUTOTUNING + WSContentSend_P(HTTP_THERMOSTAT_PI_AUTOTUNE, D_ENABLED ); + #else + WSContentSend_P(HTTP_THERMOSTAT_PI_AUTOTUNE, D_DISABLED ); + #endif + + } + +#endif // USE_WEBSERVER +} + + + /*********************************************************************************************\ * Interface \*********************************************************************************************/ @@ -2029,6 +2110,15 @@ bool Xdrv39(uint8_t function) } } break; + +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + for (ctr_output = 0; ctr_output < THERMOSTAT_CONTROLLER_OUTPUTS; ctr_output++) { + ThermostatShow(ctr_output); + } + break; +#endif // USE_WEBSERVER + case FUNC_COMMAND: result = DecodeCommand(kThermostatCommands, ThermostatCommand); break; diff --git a/tasmota/xdrv_41_tcp_bridge.ino b/tasmota/xdrv_41_tcp_bridge.ino index d9b6f280d..c24fae5ec 100644 --- a/tasmota/xdrv_41_tcp_bridge.ino +++ b/tasmota/xdrv_41_tcp_bridge.ino @@ -134,6 +134,7 @@ void TCPLoop(void) } /********************************************************************************************/ + void TCPInit(void) { if (PinUsed(GPIO_TCP_RX) && PinUsed(GPIO_TCP_TX)) { if (0 == (0x80 & Settings->tcp_config)) // !0x80 means unitialized @@ -143,7 +144,7 @@ void TCPInit(void) { if (!Settings->tcp_baudrate) { Settings->tcp_baudrate = 115200 / 1200; } TCPSerial = new TasmotaSerial(Pin(GPIO_TCP_RX), Pin(GPIO_TCP_TX), TasmotaGlobal.seriallog_level ? 1 : 2, 0, TCP_BRIDGE_BUF_SIZE); // set a receive buffer of 256 bytes - TCPSerial->begin(Settings->tcp_baudrate * 1200, 0x7F & Settings->tcp_config); + TCPSerial->begin(Settings->tcp_baudrate * 1200, ConvertSerialConfig(0x7F & Settings->tcp_config)); if (TCPSerial->hardwareSerial()) { ClaimSerial(); } @@ -199,7 +200,7 @@ void CmndTCPBaudrate(void) { if ((XdrvMailbox.payload >= 1200) && (XdrvMailbox.payload <= 115200)) { XdrvMailbox.payload /= 1200; // Make it a valid baudrate Settings->tcp_baudrate = XdrvMailbox.payload; - TCPSerial->begin(Settings->tcp_baudrate * 1200, 0x7F & Settings->tcp_config); // Reinitialize serial port with new baud rate + TCPSerial->begin(Settings->tcp_baudrate * 1200, ConvertSerialConfig(0x7F & Settings->tcp_config)); // Reinitialize serial port with new baud rate } ResponseCmndNumber(Settings->tcp_baudrate * 1200); } @@ -209,7 +210,7 @@ void CmndTCPConfig(void) { uint8_t serial_config = ParseSerialConfig(XdrvMailbox.data); if (serial_config >= 0) { Settings->tcp_config = 0x80 | serial_config; // default 0x00 should be 8N1 - TCPSerial->begin(Settings->tcp_baudrate * 1200, 0x7F & Settings->tcp_config); // Reinitialize serial port with new config + TCPSerial->begin(Settings->tcp_baudrate * 1200, ConvertSerialConfig(0x7F & Settings->tcp_config)); // Reinitialize serial port with new config } } ResponseCmndChar_P(GetSerialConfig(0x7F & Settings->tcp_config).c_str()); diff --git a/tasmota/xdrv_50_filesystem.ino b/tasmota/xdrv_50_filesystem.ino index ebd5b681c..8a0ed1d16 100644 --- a/tasmota/xdrv_50_filesystem.ino +++ b/tasmota/xdrv_50_filesystem.ino @@ -102,7 +102,7 @@ void UfsInitOnce(void) { #ifdef ESP8266 ffsp = &LittleFS; if (!LittleFS.begin()) { - ffsp = 0; + ffsp = nullptr; return; } #endif // ESP8266 @@ -114,6 +114,7 @@ void UfsInitOnce(void) { // ffat is second ffsp = &FFat; if (!FFat.begin(true)) { + ffsp = nullptr; return; } ffs_type = UFS_TFAT; diff --git a/tasmota/xdrv_52_0_berry_struct.ino b/tasmota/xdrv_52_0_berry_struct.ino index 74ae1eee7..61ff080c5 100644 --- a/tasmota/xdrv_52_0_berry_struct.ino +++ b/tasmota/xdrv_52_0_berry_struct.ino @@ -21,6 +21,9 @@ #ifdef USE_BERRY #include +#include + +#include "re1.5.h" #define BERRY_CONSOLE_CMD_DELIMITER "\x01" diff --git a/tasmota/xdrv_52_3_berry_display.ino b/tasmota/xdrv_52_3_berry_display.ino new file mode 100644 index 000000000..ed930301d --- /dev/null +++ b/tasmota/xdrv_52_3_berry_display.ino @@ -0,0 +1,63 @@ +/* + xdrv_52_3_berry_display.ino - Berry scripting language, native fucnctions + + Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#ifdef USE_BERRY +#ifdef USE_DISPLAY + +#include + +#ifdef USE_UNIVERSAL_DISPLAY +Renderer *Init_uDisplay(const char *desc); +#endif // USE_UNIVERSAL_DISPLAY + +/*********************************************************************************************\ + * Native functions mapped to Berry functions + * + * import display + * display.start(string) -> comptr or nil if failed + * +\*********************************************************************************************/ +extern "C" { + + int be_disp_start(bvm *vm); + int be_disp_start(bvm *vm) { +#ifdef USE_UNIVERSAL_DISPLAY + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 1 && be_isstring(vm, 1)) { + const char * desc = be_tostring(vm, 1); + // remove all objects on stack to avoid warnings in subsequent calls to Berry + be_pop(vm, argc); + Renderer * renderer = Init_uDisplay(desc); + if (renderer) { + be_pushcomptr(vm, renderer); + } else { + be_pushnil(vm); + } + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); +#else // USE_UNIVERSAL_DISPLAY + be_raise(vm, "internal_error", "universal display driver not present"); +#endif // USE_UNIVERSAL_DISPLAY + } +} + +#endif // USE_DISPLAY +#endif // USE_BERRY diff --git a/tasmota/xdrv_52_3_berry_gpio.ino b/tasmota/xdrv_52_3_berry_gpio.ino index 8d2119040..f694b6444 100644 --- a/tasmota/xdrv_52_3_berry_gpio.ino +++ b/tasmota/xdrv_52_3_berry_gpio.ino @@ -173,7 +173,12 @@ extern "C" { if (argc == 2 && be_isint(vm, 2)) { index = be_toint(vm, 2); } - bool ret = PinUsed(pin, index); + bool ret; + if (pin == GPIO_OPTION_A) { + ret = bitRead(TasmotaGlobal.gpio_optiona.data, index); + } else { + ret = PinUsed(pin, index); + } be_pushbool(vm, ret); be_return(vm); } diff --git a/tasmota/xdrv_52_3_berry_leds.ino b/tasmota/xdrv_52_3_berry_leds.ino new file mode 100644 index 000000000..5e7d95b77 --- /dev/null +++ b/tasmota/xdrv_52_3_berry_leds.ino @@ -0,0 +1,299 @@ +/* + xdrv_52_3_berry_leds.ino - Berry scripting language, native fucnctions + + Copyright (C) 2021 Stephan Hadinger, Berry language by Guan Wenliang https://github.com/Skiars/berry + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#ifdef USE_BERRY + +#include + +#ifdef USE_WS2812 + +#include + +enum { + ws2812_grb = 1, + ws2812_grbw = 2, + sk6812_grb = 3, + sk6812_grbw = 4, + + neopixel_type_end +}; + +typedef NeoPixelBus neopixel_ws2812_grb_t; +typedef NeoPixelBus neopixel_ws2812_grbw_t; +typedef NeoPixelBus neopixel_sk6812_grb_t; +typedef NeoPixelBus neopixel_sk6812_grbw_t; + + +/*********************************************************************************************\ + * Native functions mapped to Berry functions + * + * import unishox + * + * +\*********************************************************************************************/ +extern "C" { + + // # Native commands + // # 00 : ctor + // # 01 : begin void -> void + // # 02 : show void -> void + // # 03 : CanShow void -> bool + // # 04 : IsDirty void -> bool + // # 05 : Dirty void -> void + // # 06 : Pixels void -> bytes() (mapped to the buffer) + // # 07 : PixelSize void -> int + // # 08 : PixelCount void -> int + // # 09 : ClearTo (color:??) -> void + // # 10 : SetPixelColor (idx:int, color:??) -> void + // # 11 : GetPixelColor (idx:int) -> color:?? + // # 20 : RotateLeft (rot:int [, first:int, last:int]) -> void + // # 21 : RotateRight (rot:int [, first:int, last:int]) -> void + // # 22 : ShiftLeft (rot:int [, first:int, last:int]) -> void + // # 23 : ShiftRight (rot:int [, first:int, last:int]) -> void + + void * be_get_neopixelbus(bvm *vm) { + be_getmember(vm, 1, "_p"); + void * strip = (void*) be_tocomptr(vm, -1); + be_pop(vm, 1); + if (strip == nullptr) { + be_raise(vm, "internal_error", "neopixelbus object not initialized"); + } + return strip; + } + int32_t be_get_leds_type(bvm *vm) { + be_getmember(vm, 1, "_t"); + int32_t type = be_toint(vm, -1); + be_pop(vm, 1); + if (type <= 0 || type >= neopixel_type_end) { + be_raise(vm, "internal_error", "invalid leds type"); + } + return type; + } + + int be_neopixelbus_call_native(bvm *vm); + int be_neopixelbus_call_native(bvm *vm) { + int32_t argc = be_top(vm); // Get the number of arguments + if (argc >= 2 && be_isint(vm, 2)) { + int32_t cmd = be_toint(vm, 2); + + if (0 == cmd) { // 00 : ctor (leds:int, gpio:int) -> void + if (!(argc >= 4 && be_isint(vm, 3) && be_isint(vm, 4))) { + be_raise(vm, "value_error", "bad arguments for neopixelbus:ctor"); + } + int32_t leds = be_toint(vm, 3); + int32_t gpio = be_toint(vm, 4); + int32_t rmt = 0; + int32_t neopixel_type = ws2812_grb; + if (argc >= 5 && !(be_isnil(vm, 5))) { + neopixel_type = be_toint(vm, 5); + } + if (neopixel_type < 1) { neopixel_type = 1; } + if (neopixel_type >= neopixel_type_end) { neopixel_type = neopixel_type_end - 1; } + + // store type in attribute `_t` + be_pushint(vm, neopixel_type); + be_setmember(vm, 1, "_t"); + be_pop(vm, 1); + + if (PinUsed(GPIO_WS2812)) { + rmt = 1; // if WS2812 is already configured by Tasmota UI, we switch to RMT1 + } + if (argc >= 6 && !(be_isnil(vm, 6))) { + rmt = be_toint(vm, 6); // if arg5, then RMT channel is specified + } + if (rmt < 0) { rmt = 0; } + if (rmt >= MAX_RMT) { rmt = MAX_RMT - 1; } + void * strip = nullptr; + switch (neopixel_type) { + case ws2812_grb: strip = new neopixel_ws2812_grb_t(leds, gpio, (NeoBusChannel) rmt); + break; + case ws2812_grbw: strip = new neopixel_ws2812_grbw_t(leds, gpio, (NeoBusChannel) rmt); + break; + case sk6812_grb: strip = new neopixel_sk6812_grb_t(leds, gpio, (NeoBusChannel) rmt); + break; + case sk6812_grbw: strip = new neopixel_sk6812_grbw_t(leds, gpio, (NeoBusChannel) rmt); + break; + } + be_pushcomptr(vm, (void*) strip); + be_setmember(vm, 1, "_p"); + be_pop(vm, 1); + be_pushnil(vm); + } else { + // all other commands need a valid neopixelbus pointer + int32_t leds_type = be_get_leds_type(vm); + const void * s = be_get_neopixelbus(vm); // raises an exception if pointer is invalid + // initialize all possible variants + neopixel_ws2812_grb_t * s_ws2812_grb = (leds_type == ws2812_grb) ? (neopixel_ws2812_grb_t*) s : nullptr; + neopixel_ws2812_grbw_t * s_ws2812_grbw = (leds_type == ws2812_grbw) ? (neopixel_ws2812_grbw_t*) s : nullptr; + neopixel_sk6812_grb_t * s_sk6812_grb = (leds_type == sk6812_grb) ? (neopixel_sk6812_grb_t*) s : nullptr; + neopixel_sk6812_grbw_t * s_sk6812_grbw = (leds_type == sk6812_grbw) ? (neopixel_sk6812_grbw_t*) s : nullptr; + + be_pushnil(vm); // push a default `nil` return value + + switch (cmd) { + case 1: // # 01 : begin void -> void + if (s_ws2812_grb) s_ws2812_grb->Begin(); + if (s_ws2812_grbw) s_ws2812_grbw->Begin(); + if (s_sk6812_grb) s_sk6812_grb->Begin(); + if (s_sk6812_grbw) s_sk6812_grbw->Begin(); + break; + case 2: // # 02 : show void -> void + if (s_ws2812_grb) s_ws2812_grb->Show(); + if (s_ws2812_grbw) s_ws2812_grbw->Show(); + if (s_sk6812_grb) s_sk6812_grb->Show(); + if (s_sk6812_grbw) s_sk6812_grbw->Show(); + break; + case 3: // # 03 : CanShow void -> bool + if (s_ws2812_grb) be_pushbool(vm, s_ws2812_grb->CanShow()); + if (s_ws2812_grbw) be_pushbool(vm, s_ws2812_grbw->CanShow()); + if (s_sk6812_grb) be_pushbool(vm, s_sk6812_grb->CanShow()); + if (s_sk6812_grbw) be_pushbool(vm, s_sk6812_grbw->CanShow()); + break; + case 4: // # 04 : IsDirty void -> bool + if (s_ws2812_grb) be_pushbool(vm, s_ws2812_grb->IsDirty()); + if (s_ws2812_grbw) be_pushbool(vm, s_ws2812_grbw->IsDirty()); + if (s_sk6812_grb) be_pushbool(vm, s_sk6812_grb->IsDirty()); + if (s_sk6812_grbw) be_pushbool(vm, s_sk6812_grbw->IsDirty()); + break; + case 5: // # 05 : Dirty void -> void + if (s_ws2812_grb) s_ws2812_grb->Dirty(); + if (s_ws2812_grbw) s_ws2812_grbw->Dirty(); + if (s_sk6812_grb) s_sk6812_grb->Dirty(); + if (s_sk6812_grbw) s_sk6812_grbw->Dirty(); + 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_ws2812_grbw) pixels_bytes = s_ws2812_grbw->PixelsSize(); + if (s_sk6812_grb) pixels_bytes = s_sk6812_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_ws2812_grbw) pixels = s_ws2812_grbw->Pixels(); + if (s_sk6812_grb) pixels = s_sk6812_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 + if (s_ws2812_grb) be_pushint(vm, s_ws2812_grb->PixelSize()); + if (s_ws2812_grbw) be_pushint(vm, s_ws2812_grbw->PixelSize()); + if (s_sk6812_grb) be_pushint(vm, s_sk6812_grb->PixelSize()); + if (s_sk6812_grbw) be_pushint(vm, s_sk6812_grbw->PixelSize()); + break; + case 8: // # 08 : PixelCount void -> int + if (s_ws2812_grb) be_pushint(vm, s_ws2812_grb->PixelCount()); + if (s_ws2812_grbw) be_pushint(vm, s_ws2812_grbw->PixelCount()); + if (s_sk6812_grb) be_pushint(vm, s_sk6812_grb->PixelCount()); + if (s_sk6812_grbw) be_pushint(vm, s_sk6812_grbw->PixelCount()); + break; + case 9: // # 09 : ClearTo (color:??) -> void + { + uint32_t rgbw = be_toint(vm, 3); + uint8_t w = (rgbw & 0xFF000000) >> 24; + uint8_t r = (rgbw & 0xFF0000) >> 16; + uint8_t g = (rgbw & 0xFF00) >> 8; + uint8_t b = (rgbw & 0xFF); + if (s_ws2812_grb) s_ws2812_grb->ClearTo(RgbColor(r, g, b)); + if (s_ws2812_grbw) s_ws2812_grbw->ClearTo(RgbwColor(r, g, b, 0)); + if (s_sk6812_grb) s_sk6812_grb->ClearTo(RgbColor(r, g, b)); + if (s_sk6812_grbw) s_sk6812_grbw->ClearTo(RgbwColor(r, g, b, 0)); + } + break; + case 10: // # 10 : SetPixelColor (idx:int, color:??) -> void + { + int32_t idx = be_toint(vm, 3); + uint32_t rgbw = be_toint(vm, 4); + uint8_t w = (rgbw & 0xFF000000) >> 24; + uint8_t r = (rgbw & 0xFF0000) >> 16; + uint8_t g = (rgbw & 0xFF00) >> 8; + uint8_t b = (rgbw & 0xFF); + if (s_ws2812_grb) s_ws2812_grb->SetPixelColor(idx, RgbColor(r, g, b)); + if (s_ws2812_grbw) s_ws2812_grbw->SetPixelColor(idx, RgbwColor(r, g, b, 0)); + if (s_sk6812_grb) s_sk6812_grb->SetPixelColor(idx, RgbColor(r, g, b)); + if (s_sk6812_grbw) s_sk6812_grbw->SetPixelColor(idx, RgbwColor(r, g, b, 0)); + } + break; + case 11: // # 11 : GetPixelColor (idx:int) -> color:?? + { + int32_t idx = be_toint(vm, 3); + RgbColor rgb; + + if (s_ws2812_grb) { + RgbColor rgb = s_ws2812_grb->GetPixelColor(idx); + be_pushint(vm, (rgb.R << 16) | (rgb.G << 8) | rgb.B); + } + if (s_ws2812_grbw) { + RgbwColor rgbw = s_ws2812_grbw->GetPixelColor(idx); + be_pushint(vm, (rgbw.W << 24) | (rgb.R << 16) | (rgb.G << 8) | rgb.B); + } + if (s_sk6812_grb) { + RgbColor rgb = s_sk6812_grb->GetPixelColor(idx); + be_pushint(vm, (rgb.R << 16) | (rgb.G << 8) | rgb.B); + } + if (s_sk6812_grbw) { + RgbwColor rgbw = s_sk6812_grbw->GetPixelColor(idx); + be_pushint(vm, (rgbw.W << 24) | (rgb.R << 16) | (rgb.G << 8) | rgb.B); + } + } + break; + // case 20: // # 20 : RotateLeft (rot:int [, first:int, last:int]) -> void + // case 21: // # 21 : RotateRight (rot:int [, first:int, last:int]) -> void + // case 22: // # 22 : ShiftLeft (rot:int [, first:int, last:int]) -> void + // case 23: // # 23 : ShiftRight (rot:int [, first:int, last:int]) -> void + // { + // int32_t rot = be_toint(vm, 3); + // int32_t first = -1; + // int32_t last = -1; + // if (argc >= 5) { + // first = be_toint(vm, 4); + // last = be_toint(vm, 5); + // } + // if (20 == cmd) { + // if (first >= 0) { strip->RotateLeft(rot, first, last); } else { strip->RotateLeft(rot); }; + // } else if (21 == cmd) { + // if (first >= 0) { strip->RotateRight(rot, first, last); } else { strip->RotateRight(rot); }; + // } else if (22 == cmd) { + // if (first >= 0) { strip->ShiftLeft(rot, first, last); } else { strip->ShiftLeft(rot); }; + // } else if (23 == cmd) { + // if (first >= 0) { strip->ShiftRight(rot, first, last); } else { strip->ShiftRight(rot); }; + // } + // } + // break; + default: + break; + } + } + be_return(vm); + } + be_raise(vm, kTypeError, nullptr); + } + +} + +#endif // USE_WS2812 +#endif // USE_BERRY diff --git a/tasmota/xdrv_52_3_berry_tasmota.ino b/tasmota/xdrv_52_3_berry_tasmota.ino index f98a5820a..667a8f7b2 100644 --- a/tasmota/xdrv_52_3_berry_tasmota.ino +++ b/tasmota/xdrv_52_3_berry_tasmota.ino @@ -519,6 +519,14 @@ extern "C" { be_return(vm); } + // Berry: `arvh() -> string` + // ESP object + int32_t l_arch(bvm *vm); + int32_t l_arch(bvm *vm) { + be_pushstring(vm, ESP32_ARCH); + be_return(vm); + } + // Berry: `save(file:string, f:closure) -> bool` int32_t l_save(struct bvm *vm); int32_t l_save(struct bvm *vm) { @@ -533,6 +541,36 @@ extern "C" { } } +/*********************************************************************************************\ + * Native functions mapped to Berry functions + * + * read_sensors(show_sensor:bool) -> string + * +\*********************************************************************************************/ +extern "C" { + int32_t l_read_sensors(struct bvm *vm); + int32_t l_read_sensors(struct bvm *vm) { + int32_t top = be_top(vm); // Get the number of arguments + bool sensor_display = false; // don't trigger a display by default + if (top >= 2) { + sensor_display = be_tobool(vm, 2); + } + be_pop(vm, top); // clear stack to avoid `Error be_top is non zero=1` errors + ResponseClear(); + if (MqttShowSensor(sensor_display)) { + // return string + be_pushstring(vm, ResponseData()); + be_return(vm); + } else { + be_return_nil(vm); + } + } +} + +/*********************************************************************************************\ + * Logging functions + * +\*********************************************************************************************/ // called as a replacement to Berry `print()` void berry_log(const char * berry_buf); void berry_log(const char * berry_buf) { diff --git a/tasmota/xdrv_52_3_berry_webclient.ino b/tasmota/xdrv_52_3_berry_webclient.ino index e95dcf9d9..b7b56a39e 100644 --- a/tasmota/xdrv_52_3_berry_webclient.ino +++ b/tasmota/xdrv_52_3_berry_webclient.ino @@ -24,6 +24,10 @@ #include #include "HttpClientLight.h" +#include "be_sys.h" + +// Tasmota extension +extern File * be_get_arduino_file(void *hfile); String wc_UrlEncode(const String& text) { const char hex[] = "0123456789ABCDEF"; @@ -298,6 +302,26 @@ extern "C" { be_return(vm); /* return code */ } + int32_t wc_writefile(struct bvm *vm); + int32_t wc_writefile(struct bvm *vm) { + int32_t argc = be_top(vm); + if (argc >= 2 && be_isstring(vm, 2)) { + HTTPClientLight * cl = wc_getclient(vm); + const char * fname = be_tostring(vm, 2); + + void * f = be_fopen(fname, "w"); + int ret = -1; + if (f) { + File * fptr = be_get_arduino_file(f); + ret = cl->writeToStream(fptr); + } + be_fclose(f); + be_pushint(vm, ret); + be_return(vm); /* return code */ + } + be_raise(vm, kTypeError, nullptr); + } + int32_t wc_getsize(struct bvm *vm); int32_t wc_getsize(struct bvm *vm) { HTTPClientLight * cl = wc_getclient(vm); diff --git a/tasmota/xdrv_52_7_berry_embedded.ino b/tasmota/xdrv_52_7_berry_embedded.ino index 5450de6a9..a51409406 100644 --- a/tasmota/xdrv_52_7_berry_embedded.ino +++ b/tasmota/xdrv_52_7_berry_embedded.ino @@ -43,6 +43,13 @@ const char berry_prog[] = "def log(m,l) tasmota.log(m,l) end " "def load(f) return tasmota.load(f) end " +#ifdef USE_AUTOCONF + // autoconf + "import autoconf " +#endif // USE_AUTOCONF + + "import tapp " + #ifdef USE_LVGL "import lv " // create the '_lvgl' global singleton diff --git a/tasmota/xdrv_52_9_berry.ino b/tasmota/xdrv_52_9_berry.ino index e8577b7aa..e938c5bb4 100644 --- a/tasmota/xdrv_52_9_berry.ino +++ b/tasmota/xdrv_52_9_berry.ino @@ -24,6 +24,7 @@ #include #include "be_vm.h" +#include "ZipReadFS.h" extern "C" { extern void be_load_custom_libs(bvm *vm); @@ -261,7 +262,10 @@ void BerryObservability(bvm *vm, int event...) { { int32_t vm_usage2 = va_arg(param, int32_t); uint32_t gc_elapsed = millis() - gc_time; - AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_BERRY "GC from %i to %i bytes (in %d ms)"), vm_usage, vm_usage2, gc_elapsed); + uint32_t vm_scanned = va_arg(param, uint32_t); + uint32_t vm_freed = va_arg(param, uint32_t); + AddLog(LOG_LEVEL_DEBUG, D_LOG_BERRY "GC from %i to %i bytes, objects freed %i/%i (in %d ms)", + vm_usage, vm_usage2, vm_freed, vm_scanned, gc_elapsed); // 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 @@ -291,6 +295,17 @@ void BerryObservability(bvm *vm, int event...) { va_end(param); } +/*********************************************************************************************\ + * Adde Berry metrics to teleperiod +\*********************************************************************************************/ +void BrShowState(void); +void BrShowState(void) { + // trigger a gc first + be_gc_collect(berry.vm); + ResponseAppend_P(PSTR(",\"Berry\":{\"HeapUsed\":%u,\"Objects\":%u}"), + berry.vm->gc.usage / 1024, berry.vm->counter_gc_kept); +} + /*********************************************************************************************\ * VM Init \*********************************************************************************************/ @@ -335,6 +350,9 @@ void BerryInit(void) { AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_BERRY "Berry initialized, RAM used=%u"), callBerryGC()); berry_init_ok = true; + // we generate a synthetic event `autoexec` + callBerryEventDispatcher(PSTR("preinit"), nullptr, 0, nullptr); + // Run pre-init BrLoad("preinit.be"); // run 'preinit.be' if present } while (0); @@ -758,6 +776,9 @@ bool Xdrv52(uint8_t function) // break; case FUNC_LOOP: if (!berry.autoexec_done) { + // we generate a synthetic event `autoexec` + callBerryEventDispatcher(PSTR("autoexec"), nullptr, 0, nullptr); + BrLoad("autoexec.be"); // run autoexec.be at first tick, so we know all modules are initialized berry.autoexec_done = true; } @@ -773,9 +794,6 @@ bool Xdrv52(uint8_t function) case FUNC_MQTT_DATA: result = callBerryEventDispatcher(PSTR("mqtt_data"), XdrvMailbox.topic, 0, XdrvMailbox.data, XdrvMailbox.data_len); break; - case FUNC_EVERY_50_MSECOND: - callBerryEventDispatcher(PSTR("every_50ms"), nullptr, 0, nullptr); - break; case FUNC_COMMAND: result = DecodeCommand(kBrCommands, BerryCommand); if (!result) { @@ -784,6 +802,9 @@ bool Xdrv52(uint8_t function) break; // Module specific events + case FUNC_EVERY_50_MSECOND: + callBerryEventDispatcher(PSTR("every_50ms"), nullptr, 0, nullptr); + break; case FUNC_EVERY_100_MSECOND: callBerryEventDispatcher(PSTR("every_100ms"), nullptr, 0, nullptr); break; diff --git a/tasmota/xdrv_54_lvgl.ino b/tasmota/xdrv_54_lvgl.ino index 9d5855099..d36a8f098 100644 --- a/tasmota/xdrv_54_lvgl.ino +++ b/tasmota/xdrv_54_lvgl.ino @@ -121,6 +121,12 @@ void lv_flush_callback(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *c ************************************************************/ #ifdef USE_UFILESYS + +#include +#include "ZipReadFS.h" +extern FS *ffsp; +FS lv_zip_ufsp(ZipReadFSImplPtr(new ZipReadFSImpl(&ffsp))); + extern "C" { typedef void lvbe_FILE; @@ -132,7 +138,7 @@ extern "C" { String file_path = "/"; file_path += filename; - File f = dfsp->open(file_path, mode); + File f = lv_zip_ufsp.open(file_path, mode); // AddLog(LOG_LEVEL_INFO, "LVG: lvbe_fopen(%s) -> %i", file_path.c_str(), (int32_t)f); // AddLog(LOG_LEVEL_INFO, "LVG: F=%*_H", sizeof(f), &f); if (f) { @@ -202,15 +208,9 @@ static void * lvbe_fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mo // AddLog(LOG_LEVEL_INFO, "LVG: lvbe_fs_open(%p, %p, %s, %i) %i", drv, file_p, path, mode, sizeof(File)); const char * modes = nullptr; switch (mode) { - case LV_FS_MODE_WR: - modes = "w"; - break; - case LV_FS_MODE_RD: - modes = "r"; - break; - case LV_FS_MODE_WR | LV_FS_MODE_RD: - modes = "rw"; - break; + case LV_FS_MODE_WR: modes = "w"; break; + case LV_FS_MODE_RD: modes = "r"; break; + case LV_FS_MODE_WR | LV_FS_MODE_RD: modes = "rw"; break; } if (modes == nullptr) { @@ -218,28 +218,12 @@ static void * lvbe_fs_open(lv_fs_drv_t * drv, const char * path, lv_fs_mode_t mo return nullptr; } - // Add "/" prefix - String file_path = "/"; - file_path += path; - - File f = dfsp->open(file_path.c_str(), modes); - // AddLog(LOG_LEVEL_INFO, "LVG: lvbe_fs_open(%s) -> %i", file_path.c_str(), (int32_t)f); - // AddLog(LOG_LEVEL_INFO, "LVG: F=%*_H", sizeof(f), &f); - if (f) { - File * f_ptr = new File(f); // copy to dynamic object - return f_ptr; - } else { - return nullptr; - } + return (void*) lvbe_fopen(path, modes); } static lv_fs_res_t lvbe_fs_close(lv_fs_drv_t * drv, void * file_p); static lv_fs_res_t lvbe_fs_close(lv_fs_drv_t * drv, void * file_p) { - // AddLog(LOG_LEVEL_INFO, "LVG: lvbe_fs_close(%p, %p)", drv, file_p); - File * f_ptr = (File*) file_p; - f_ptr->close(); - delete f_ptr; - return LV_FS_RES_OK; + return lvbe_fclose((void*)file_p); } static lv_fs_res_t lvbe_fs_read(lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br); @@ -363,8 +347,7 @@ extern "C" { * We use Adafruit_LvGL_Glue to leverage the Adafruit * display ecosystem. ************************************************************/ - -Renderer *Init_uDisplay(const char *desc, int8_t cs); +extern Renderer *Init_uDisplay(const char *desc); void start_lvgl(const char * uconfig); @@ -377,7 +360,7 @@ void start_lvgl(const char * uconfig) { if (!renderer || uconfig) { #ifdef USE_UNIVERSAL_DISPLAY // TODO - we will probably support only UNIV_DISPLAY - renderer = Init_uDisplay((char*)uconfig, -1); + renderer = Init_uDisplay((char*)uconfig); if (!renderer) return; #else return; diff --git a/tasmota/xdrv_55_touch.ino b/tasmota/xdrv_55_touch.ino index 4abb9683e..269f775af 100644 --- a/tasmota/xdrv_55_touch.ino +++ b/tasmota/xdrv_55_touch.ino @@ -21,9 +21,9 @@ #if defined(USE_FT5206) || defined(USE_XPT2046) || defined(USE_LILYGO47) || defined(USE_TOUCH_BUTTONS) -// #ifdef USE_DISPLAY_LVGL_ONLY -// #undef USE_TOUCH_BUTTONS -// #endif +#ifdef USE_DISPLAY_LVGL_ONLY +#undef USE_TOUCH_BUTTONS +#endif #include @@ -317,5 +317,9 @@ bool Xdrv55(uint8_t function) { } return result; } - -#endif // USE_TOUCH +#else +// dummy for LVGL without a touch controller +uint32_t Touch_Status(uint32_t sel) { +return 0; +} +#endif // #if defined(USE_FT5206) || defined(USE_XPT2046) || defined(USE_LILYGO47) || defined(USE_TOUCH_BUTTONS) diff --git a/tasmota/xdrv_59_influxdb.ino b/tasmota/xdrv_59_influxdb.ino index ecafe8003..435a3ed2f 100644 --- a/tasmota/xdrv_59_influxdb.ino +++ b/tasmota/xdrv_59_influxdb.ino @@ -37,6 +37,7 @@ * IfxBucket - Set Influxdb v2 and bucket name * IfxOrg - Set Influxdb v2 and organization * IfxToken - Set Influxdb v2 and token + * IfxPeriod - Set Influxdb period. If not set (or 0), use Teleperiod * * Set influxdb update interval with command teleperiod * @@ -364,8 +365,9 @@ void InfluxDbPublishPowerState(uint32_t device) { void InfluxDbLoop(void) { if (!TasmotaGlobal.global_state.network_down) { IFDB.interval--; - if (IFDB.interval <= 0 || IFDB.interval > Settings->tele_period) { - IFDB.interval = Settings->tele_period; + uint16_t period = Settings->influxdb_period ? Settings->influxdb_period : Settings->tele_period; + if (IFDB.interval <= 0 || IFDB.interval > period) { + IFDB.interval = period; if (!IFDB.init) { if (InfluxDbParameterInit()) { IFDB.init = InfluxDbValidateConnection(); @@ -385,7 +387,7 @@ void InfluxDbLoop(void) { // {"Time":"2021-08-14T17:19:33","Switch1":"ON","Switch2":"OFF","ANALOG":{"Temperature":184.72},"DS18B20":{"Id":"01144A0CB2AA","Temperature":27.50},"HTU21":{"Temperature":28.23,"Humidity":39.7,"DewPoint":13.20},"Global":{"Temperature":27.50,"Humidity":39.7,"DewPoint":12.55},"TempUnit":"C"} ResponseClear(); - if (MqttShowSensor()) { // Pull sensor data + if (MqttShowSensor(true)) { // Pull sensor data InfluxDbProcessJson(); }; @@ -408,20 +410,23 @@ void InfluxDbLoop(void) { #define D_CMND_INFLUXDBTOKEN "Token" #define D_CMND_INFLUXDBDATABASE "Database" #define D_CMND_INFLUXDBBUCKET "Bucket" +#define D_CMND_INFLUXDBPERIOD "Period" const char kInfluxDbCommands[] PROGMEM = D_PRFX_INFLUXDB "|" // Prefix "|" D_CMND_INFLUXDBLOG "|" D_CMND_INFLUXDBHOST "|" D_CMND_INFLUXDBPORT "|" D_CMND_INFLUXDBUSER "|" D_CMND_INFLUXDBORG "|" D_CMND_INFLUXDBPASSWORD "|" D_CMND_INFLUXDBTOKEN "|" - D_CMND_INFLUXDBDATABASE "|" D_CMND_INFLUXDBBUCKET; + D_CMND_INFLUXDBDATABASE "|" D_CMND_INFLUXDBBUCKET "|" + D_CMND_INFLUXDBPERIOD; void (* const InfluxCommand[])(void) PROGMEM = { &CmndInfluxDbState, &CmndInfluxDbLog, &CmndInfluxDbHost, &CmndInfluxDbPort, &CmndInfluxDbUser, &CmndInfluxDbUser, &CmndInfluxDbPassword, &CmndInfluxDbPassword, - &CmndInfluxDbDatabase, &CmndInfluxDbDatabase }; + &CmndInfluxDbDatabase, &CmndInfluxDbDatabase, + &CmndInfluxDbPeriod }; void InfluxDbReinit(void) { IFDB.init = false; @@ -504,6 +509,16 @@ void CmndInfluxDbDatabase(void) { ResponseCmndChar(SettingsText(SET_INFLUXDB_BUCKET)); } +void CmndInfluxDbPeriod(void) { + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) { + Settings->influxdb_period = XdrvMailbox.payload; + if(Settings->influxdb_period > 0 && Settings->influxdb_period < 10) { + Settings->influxdb_period = 10; + } + } + ResponseCmndNumber(Settings->influxdb_period); +} + /*********************************************************************************************\ * Interface \*********************************************************************************************/ diff --git a/tasmota/xdrv_79_esp32_ble.ino b/tasmota/xdrv_79_esp32_ble.ino index 94589f4c4..2dd4b9d40 100644 --- a/tasmota/xdrv_79_esp32_ble.ino +++ b/tasmota/xdrv_79_esp32_ble.ino @@ -1150,7 +1150,7 @@ void setDetails(ble_advertisment_t *ad){ *(p++) = '{'; maxlen--; - strcpy(p, "\"details\":{"); + strcpy(p, "\"DetailsBLE\":{"); int len = strlen(p); p += len; maxlen -= len; diff --git a/tasmota/xdrv_82_esp32_ethernet.ino b/tasmota/xdrv_82_esp32_ethernet.ino index d276ad7fd..1deb646b5 100644 --- a/tasmota/xdrv_82_esp32_ethernet.ino +++ b/tasmota/xdrv_82_esp32_ethernet.ino @@ -86,15 +86,15 @@ char eth_hostname[sizeof(TasmotaGlobal.hostname)]; void EthernetEvent(WiFiEvent_t event) { switch (event) { - case SYSTEM_EVENT_ETH_START: + case ARDUINO_EVENT_ETH_START: AddLog(LOG_LEVEL_DEBUG, PSTR("ETH: " D_ATTEMPTING_CONNECTION)); ETH.setHostname(eth_hostname); break; - case SYSTEM_EVENT_ETH_CONNECTED: + case ARDUINO_EVENT_ETH_CONNECTED: AddLog(LOG_LEVEL_INFO, PSTR("ETH: " D_CONNECTED " at %dMbps%s"), ETH.linkSpeed(), (ETH.fullDuplex()) ? " Full Duplex" : ""); break; - case SYSTEM_EVENT_ETH_GOT_IP: + 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); Settings->ipv4_address[1] = (uint32_t)ETH.gatewayIP(); @@ -103,11 +103,11 @@ void EthernetEvent(WiFiEvent_t event) { Settings->ipv4_address[4] = (uint32_t)ETH.dnsIP(1); TasmotaGlobal.global_state.eth_down = 0; break; - case SYSTEM_EVENT_ETH_DISCONNECTED: + case ARDUINO_EVENT_ETH_DISCONNECTED: AddLog(LOG_LEVEL_INFO, PSTR("ETH: Disconnected")); TasmotaGlobal.global_state.eth_down = 1; break; - case SYSTEM_EVENT_ETH_STOP: + case ARDUINO_EVENT_ETH_STOP: AddLog(LOG_LEVEL_DEBUG, PSTR("ETH: Stopped")); TasmotaGlobal.global_state.eth_down = 1; break; @@ -129,9 +129,9 @@ void EthernetInit(void) { Settings->eth_clk_mode = ETH_CLOCK_GPIO0_IN; // EthClockMode } -// snprintf_P(Eth.hostname, sizeof(Eth.hostname), PSTR("%s_eth"), TasmotaGlobal.hostname); - strlcpy(eth_hostname, TasmotaGlobal.hostname, sizeof(eth_hostname) -5); // Make sure there is room for "_eth" - strcat(eth_hostname, "_eth"); +// snprintf_P(Eth.hostname, sizeof(Eth.hostname), PSTR("%s-eth"), TasmotaGlobal.hostname); + strlcpy(eth_hostname, TasmotaGlobal.hostname, sizeof(eth_hostname) -5); // Make sure there is room for "-eth" + strcat(eth_hostname, "-eth"); WiFi.onEvent(EthernetEvent); diff --git a/tasmota/xdrv_84_esp32_core2.ino b/tasmota/xdrv_84_esp32_core2.ino index b88814219..b2cfe5720 100644 --- a/tasmota/xdrv_84_esp32_core2.ino +++ b/tasmota/xdrv_84_esp32_core2.ino @@ -265,7 +265,7 @@ void Core2EverySecond(void) { if (core2_globs.ready) { Core2GetADC(); - if (Rtc.utc_time > START_VALID_TIME && core2_globs.tset==false && abs(Rtc.utc_time - Core2GetUtc()) > 3) { + if (Rtc.utc_time > START_VALID_TIME && core2_globs.tset==false && abs((int32_t)Rtc.utc_time - (int32_t)Core2GetUtc()) > 3) { Core2SetUtc(Rtc.utc_time); AddLog(LOG_LEVEL_INFO, PSTR("CR2: Write Time TO BM8563 from NTP (" D_UTC_TIME ") %s, (" D_DST_TIME ") %s, (" D_STD_TIME ") %s"), GetDateAndTime(DT_UTC).c_str(), GetDateAndTime(DT_DST).c_str(), GetDateAndTime(DT_STD).c_str()); diff --git a/tasmota/xdrv_86_esp32_sonoff_spm.ino b/tasmota/xdrv_86_esp32_sonoff_spm.ino new file mode 100644 index 000000000..808ada4c8 --- /dev/null +++ b/tasmota/xdrv_86_esp32_sonoff_spm.ino @@ -0,0 +1,1266 @@ +/* + xdrv_86_esp32_sonoff_spm.ino - Sonoff SPM support for Tasmota + + Copyright (C) 2021 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +//#define USE_SONOFF_SPM + +#ifdef ESP32 +#ifdef USE_SONOFF_SPM +/*********************************************************************************************\ + * Sonoff Stackable Power Manager (Current state: PROOF OF CONCEPT) + * + * Initial POC template: + * {"NAME":"Sonoff SPM (POC1)","GPIO":[1,1,1,1,3200,1,1,1,1,1,1,1,3232,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,544,1,1,32,1,0,0,1],"FLAG":0,"BASE":1} + * Add ethernet support: + * {"NAME":"Sonoff SPM (POC2)","GPIO":[1,0,1,0,3200,5536,0,0,1,1,1,0,3232,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,544,1,1,32,1,0,0,1],"FLAG":0,"BASE":1} + * + * Things to know: + * Bulk of the action is handled by ARM processors present in every unit communicating over modbus RS-485. + * Each SPM-4Relay has 4 bistable relays with their own CSE7761 energy monitoring device handled by an ARM processor. + * Green led is controlled by ARM processor indicating SD-Card access. + * ESP32 is used as interface between eWelink and ARM processor in SPM-Main unit communicating over proprietary serial protocol. + * Power on sequence for two SPM-4Relay modules is 00-00-15-10-(0F)-(13)-(13)-(19)-0C-09-04-09-04-0B-0B + * + * Tasmota POC1: + * Up to 7 SPM-4Relay units supporting up to 28 relays. + * Gui rotating energy display for 4 relays at a time. + * Button on SPM-Main initiates re-scan of SPM-4Relay units. + * Blue led equals Tasmota WiFi status. + * + * Tasmota POC2: + * Ethernet support. + * Gui optimized for energy display. + * + * Todo: + * Gui for Overload Protection entry (is handled by ARM processor). + * Gui for Scheduling entry (is handled by ARM processor). + * Yellow led functionality. + * Interpretation of reset sequence on GPIO's 12-14. + * + * Nice to have: + * Support for all 32 SPM4Relay units equals 128 relays + * + * GPIO's used: + * GPIO00 - Bootmode / serial flash + * GPIO01 - Serial console TX (921600bps8N1 originally) + * GPIO03 - Serial console RX + * GPIO04 - ARM processor TX (115200bps8N1) + * GPIO05 - ETH POWER + * GPIO12 - SPI MISO ARM pulsetrain code (input?) + * GPIO13 - SPI CLK + * GPIO14 - SPI CS ARM pulsetrain eoc (input?) + * GPIO15 - ARM reset (output) - 18ms low active 125ms after restart esp32 + * GPIO16 - ARM processor RX + * GPIO17 - EMAC_CLK_OUT_180 + * GPIO18 - ETH MDIO + * GPIO19 - EMAC_TXD0(RMII) + * GPIO21 - EMAC_TX_EN(RMII) + * GPIO22 - EMAC_TXD1(RMII) + * GPIO23 - ETH MDC + * GPIO25 - EMAC_RXD0(RMII) + * GPIO26 - EMAC_RXD1(RMII) + * GPIO27 - EMAC_RX_CRS_DV + * GPIO32 - Blue status led2 + * GPIO33 - Yellow error led3 + * GPIO35 - Button + * #define ETH_TYPE ETH_PHY_LAN8720 + * #define ETH_CLKMODE ETH_CLOCK_GPIO17_OUT + * #define ETH_ADDRESS 0 + * + * Variables used: + * module = 0 to 31 SPM-4Relays + * channel = 0 to 3 or 01, 02, 04, 08 Bitmask of four relays in module + * relay = 0 to 127 Relays +\*********************************************************************************************/ + +#define SSPM_JSON_ENERGY_TODAY // Show JSON energy today +#define SSPM_JSON_ENERGY_YESTERDAY // Show JSON energy yesterday + +/*********************************************************************************************\ + * Fixed defines - Do not change +\*********************************************************************************************/ + +#define XDRV_86 86 + +#define SSPM_MAX_MODULES 7 // Currently supports up to 7 SPM-4RELAY units for a total of 28 relays restricted by power_t size +#define SSPM_SERIAL_BUFFER_SIZE 512 // Needs to accomodate Energy total history for six months (408 bytes) + +// Send +#define SSPM_FUNC_FIND 0 // 0x00 +#define SSPM_FUNC_SET_OPS 3 // 0x03 - Overload Protection +#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 +#define SSPM_FUNC_SET_SCHEME 10 // 0x0A +#define SSPM_FUNC_GET_SCHEME 11 // 0x0B +#define SSPM_FUNC_SET_TIME 12 // 0x0C +#define SSPM_FUNC_IAMHERE 13 // 0x0D +#define SSPM_FUNC_INIT_SCAN 16 // 0x10 +#define SSPM_FUNC_UNITS 21 // 0x15 +#define SSPM_FUNC_GET_ENERGY_TOTAL 22 // 0x16 +#define SSPM_FUNC_GET_ENERGY 24 // 0x18 +#define SSPM_FUNC_GET_LOG 26 // 0x1A +#define SSPM_FUNC_ENERGY_PERIOD 27 // 0x1B + +// Receive +#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_DONE 25 // 0x19 + +#define SSPM_GPIO_ARM_RESET 15 + +#define SSPM_MODULE_NAME_SIZE 12 + +/*********************************************************************************************/ + +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 + SPM_POLL_ARM_2, // 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_GET_ENERGY_TOTALS, // Init available Energy totals registers + SPM_UPDATE_CHANNELS // Update Energy for powered on channels + }; + +#include +TasmotaSerial *SspmSerial; + +typedef struct { + float voltage[SSPM_MAX_MODULES][4]; // 123.12 V + float current[SSPM_MAX_MODULES][4]; // 123.12 A + float active_power[SSPM_MAX_MODULES][4]; // 123.12 W + float apparent_power[SSPM_MAX_MODULES][4]; // 123.12 VA + float reactive_power[SSPM_MAX_MODULES][4]; // 123.12 VAr + float power_factor[SSPM_MAX_MODULES][4]; // 0.12 + float energy_today[SSPM_MAX_MODULES][4]; // 12345 kWh + float energy_yesterday[SSPM_MAX_MODULES][4]; // 12345 kWh + float energy_total[SSPM_MAX_MODULES][4]; // 12345 kWh total energy since last 6 month!!! + + uint32_t timeout; + power_t old_power; + uint16_t last_totals; + uint16_t serial_in_byte_counter; + uint16_t expected_bytes; + uint8_t module[SSPM_MAX_MODULES][SSPM_MODULE_NAME_SIZE]; + + uint8_t allow_updates; + uint8_t get_energy_relay; + uint8_t get_totals; + uint8_t rotate; + uint8_t module_max; + uint8_t module_selected; + uint8_t no_send_key; + uint8_t counter; + uint8_t command_sequence; + uint8_t mstate; + uint8_t last_button; + bool discovery_triggered; +} TSspm; + +uint8_t *SspmBuffer = nullptr; +TSspm *Sspm = nullptr; + +/*********************************************************************************************/ + +void SSPMSetLock(uint32_t seconds) { + Sspm->timeout = seconds * 10; // Decremented every 100mSec + Sspm->allow_updates = 0; // Disable requests from 100mSec loop +} + +uint16_t SSPMCalculateCRC(uint8_t *frame, uint32_t num) { + // CRC-16/ARC (polynomial 0x8005 reflected as 0xA001) + uint16_t crc = 0; + for (uint32_t i = 2; i < num; i++) { + crc ^= frame[i]; + for (uint32_t i = 0; i < 8; i++) { + crc = (crc & 1) ? (crc >> 1) ^ 0xA001 : crc >> 1; + } + } + return crc ^ 0; +} + +void SSPMSend(uint32_t size) { + uint16_t crc = SSPMCalculateCRC(SspmBuffer, size -2); + SspmBuffer[size -2] = (uint8_t)(crc >> 8); + SspmBuffer[size -1] = (uint8_t)crc; + + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SPM: ESP %*_H"), size, SspmBuffer); + + SspmSerial->write(SspmBuffer, size); +} + +void SSPMSendAck(uint32_t command_sequence) { + /* + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 80 0f 00 01 00 01 3d e6 + Marker |Module id |Ac|Cm|Size |Pl|Ix|Chksm| + */ + SspmBuffer[15] = 0x80; + SspmBuffer[17] = 0x00; + SspmBuffer[18] = 0x01; + SspmBuffer[19] = 0x00; + SspmBuffer[20] = command_sequence; + + SSPMSend(23); +} + +void SSPMInitSend(void) { + /* + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + Marker |Module id |Ac|Cm|Size | + */ + memset(SspmBuffer, 0, 19); + SspmBuffer[0] = 0xAA; + SspmBuffer[1] = 0x55; + SspmBuffer[2] = 0x01; +} + +void SSPMSendCmnd(uint32_t command) { + /* + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FC 51 + Marker |Module id |Ac|Cm|Size |Ix|Chksm| + */ + SSPMInitSend(); + SspmBuffer[16] = command; + if (0 == command) { + Sspm->command_sequence = 0; + } else { + Sspm->command_sequence++; + } + SspmBuffer[19] = Sspm->command_sequence; + + SSPMSend(22); +} + +/*********************************************************************************************/ + +void SSPMSendOPS(uint32_t relay_num) { + /* + Overload Protection + 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 + AA 55 01 6b 7e 32 37 39 37 34 13 4b 35 36 37 00 03 00 12 04 00 11 30 00 00 00 0a 00 f0 00 00 00 0a 00 14 00 00 fb a6 f8 = Default settings + Marker |Module id |Ac|Cm|Size |Ch|Ra|Max P |Min P |Max U |Min U |Max I |De|Ix|Chksm| + | | | 4400W| 0.1W| 240V| 0.1V| 20A| | + Ch - Bitmask channel 01 = 1, 02 = 2, 04 = 3, 08 = 4 + Ra - Bitmask enabled features xxxxxxx1 Enable Max current + Ra - Bitmask enabled features xxxxxx1x Enable Min voltage + Ra - Bitmask enabled features xxxxx1xx Enable Max voltage + Ra - Bitmask enabled features xxxx1xxx Enable Min power + Ra - Bitmask enabled features xxx1xxxx Enable Max power + De - 0 to 255 seconds Overload detection delay + Values are XX XX - number + XX - decimals + + Acknowledge: + AA 55 01 6b 7e 32 37 39 37 34 13 4b 35 36 37 80 03 00 01 00 14 08 bc + |Ac|Cm|Size |Rt|Ix|Chksm| + Ac - Acknowledge or error number + Rt - Return code + */ + + SspmBuffer[16] = SSPM_FUNC_SET_OPS; // 0x03 + +} + +void SSPMSendGetOps(uint32_t module) { + /* + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + aa 55 01 6b 7e 32 37 39 37 34 13 4b 35 36 37 00 04 00 00 08 c0 0a + Marker |Module id |Ac|Cm|Size |Ix|Chksm| + */ + SSPMInitSend(); + memcpy(SspmBuffer +3, Sspm->module[module], SSPM_MODULE_NAME_SIZE); + SspmBuffer[16] = SSPM_FUNC_GET_OPS; // 0x04 + Sspm->command_sequence++; + SspmBuffer[19] = Sspm->command_sequence; + + SSPMSend(22); +} + +void SSPMSendSetRelay(uint32_t relay, uint32_t state) { + /* + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + AA 55 01 6b 7e 32 37 39 37 34 13 4b 35 36 37 00 08 00 01 44 08 c0 34 + Marker |Module id |Ac|Cm|Size |Pl|Ix|Chksm| + */ + uint8_t channel = 1 << (relay & 0x03); // Channel relays are bit masked + if (state) { + channel |= (channel << 4); + } + uint8_t module = relay >> 2; + SSPMInitSend(); + memcpy(SspmBuffer +3, Sspm->module[module], SSPM_MODULE_NAME_SIZE); + SspmBuffer[16] = SSPM_FUNC_SET_RELAY; // 0x08 + SspmBuffer[18] = 0x01; + SspmBuffer[19] = channel; + Sspm->command_sequence++; + SspmBuffer[20] = Sspm->command_sequence; + + SSPMSend(23); +} + +void SSPMSendGetModuleState(uint32_t module) { + /* + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 00 09 00 01 0f 05 b5 de + Marker |Module id |Ac|Cm|Size |Pl|Ix|Chksm| + */ + SSPMInitSend(); + memcpy(SspmBuffer +3, Sspm->module[module], SSPM_MODULE_NAME_SIZE); + SspmBuffer[16] = SSPM_FUNC_GET_MODULE_STATE; // 0x09 + SspmBuffer[18] = 0x01; + SspmBuffer[19] = 0x0F; // State of all four relays + Sspm->command_sequence++; + SspmBuffer[20] = Sspm->command_sequence; + + SSPMSend(23); +} + +void SSPMSendScheme(uint32_t relay) { + /* + Time scheme + 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 + One time + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 00 0a 00 1e 01 01 01 07 e5 0b 0e 0b 38 08 00 6b 01 00 ea 60 20 23 1b 04 fd 7a 83 05 63 ee dd a9 b9 3a 7e 14 95 + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 00 0a 00 1e 01 01 01 07 e5 0b 0e 0c 04 35 00 55 01 02 46 76 0e 0c 20 e1 22 7c 67 ab 9c 66 73 6d bd e8 7f 50 d4 + Marker |Module id |Ac|Cm|Size |No| |Mo| YYYY|MM|DD|HH|MM |St|Re|Scheme id | + No - Number of schemes defined + Mo - Scheme type (1 = temporarly, 2 = scheduled) + Re - Relay 0 to 3 + St - State (0 = off, 1 = On) + + Scheduled On + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 00 0a 00 18 01 01 02 15 0c 0c 01 03 99 65 93 dc f8 d0 b0 29 a8 66 ba 8f 41 66 29 24 80 5b 48 + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 00 0a 00 18 01 01 02 15 0c 0c 01 03 99 65 93 dc f8 d0 b0 29 a8 66 ba 8f 41 66 29 24 82 9a c9 + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 00 0a 00 18 01 01 02 53 0c 0c 01 03 99 65 93 dc f8 d0 b0 29 a8 66 ba 8f 41 66 29 24 83 44 aa + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 00 0a 00 18 01 01 02 53 0d 0b 00 02 99 65 93 dc f8 d0 b0 29 a8 66 ba 8f 41 66 29 24 84 e0 22 + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 00 0a 00 18 01 01 02 0e 0d 3b 01 03 84 fb ea 35 ca 16 51 b5 b8 10 a1 1c d0 1a 3f 7a 86 e3 fa + + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 00 0a 00 2f 02 01 02 0e 0d 3b 01 03 84 fb ea 35 ca 16 51 b5 b8 10 a1 1c d0 1a 3f 7a + 01 02 53 0d 0b 00 02 99 65 93 dc f8 d0 b0 29 a8 66 ba 8f 41 66 29 24 87 e8 02 + + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 00 0a 00 2f 02 01 02 53 0d 0b 00 02 99 65 93 dc f8 d0 b0 29 a8 66 ba 8f 41 66 29 24 + 01 02 0e 0d 3b 01 03 84 fb ea 35 ca 16 51 b5 b8 10 a1 1c d0 1a 3f 7a 89 6e e6 + + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 00 0a 00 4c 03 01 01 07 e5 0b 0e 0e 0e 26 00 e7 01 00 e6 b2 48 8e ef be ce 78 3e 5d a8 3a c0 c5 6f 5e = One time + 01 02 53 0d 0b 00 02 99 65 93 dc f8 d0 b0 29 a8 66 ba 8f 41 66 29 24 = 14:11 OFF CH3 SuMoThSa + 01 02 0e 0d 3b 01 03 84 fb ea 35 ca 16 51 b5 b8 10 a1 1c d0 1a 3f 7a 8a 2f f8 = 14:59 ON CH4 MoTuWe + + Marker |Module id |Ac|Cm|Size |No| |Mo|Dy|HH|MM|St|Re|Scheme id | + Dy - Bitmask days xxxxxxx1 sunday + xxxxxx1x monday + xxxxx1xx tuesday + xxxx1xxx wednesday + xxx1xxxx thursday + xx1xxxxx friday + x1xxxxxx saturday + + Scheduled Off + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 00 0a 00 01 00 81 26 9f + Schedule 2 off + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 00 0a 00 18 01 01 02 53 0d 0b 00 02 99 65 93 dc f8 d0 b0 29 a8 66 ba 8f 41 66 29 24 88 e5 22 + Marker |Module id |Ac|Cm|Size | + */ + + SspmBuffer[16] = SSPM_FUNC_SET_SCHEME; // 0x0A + +} + +void SSPMSendGetScheme(uint32_t module) { + /* + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + AA 55 01 6b 7e 32 37 39 37 34 13 4b 35 36 37 00 0b 00 00 09 14 c8 + Marker |Module id |Ac|Cm|Size |Ix|Chksm| + */ + SSPMInitSend(); + memcpy(SspmBuffer +3, Sspm->module[module], SSPM_MODULE_NAME_SIZE); + SspmBuffer[16] = SSPM_FUNC_GET_SCHEME; // 0x0B + Sspm->command_sequence++; + SspmBuffer[19] = Sspm->command_sequence; + + SSPMSend(22); +} + +void SSPMSendSetTime(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 24 25 26 27 28 29 30 31 32 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 0c 00 0b 07 e5 0b 06 0c 39 01 00 00 02 00 04 8a 37 + Marker |Module id |Ac|Cm|Size |YY YY MM DD HH MM SS|Ln|St|Tzone|Ix|Chksm| + UTC time + Tzone = Time zone, [-12,+14], can be a decimal, such as 7.5 + */ + SSPMInitSend(); + SspmBuffer[16] = SSPM_FUNC_SET_TIME; // 0x0C + SspmBuffer[18] = 0x0B; + TIME_T time; + BreakTime(Rtc.utc_time, time); + uint16_t year = time.year + 1970; + SspmBuffer[19] = year >> 8; + SspmBuffer[20] = year; + SspmBuffer[21] = time.month; + SspmBuffer[22] = time.day_of_month; + SspmBuffer[23] = time.hour; + SspmBuffer[24] = time.minute; + SspmBuffer[25] = time.second; + SspmBuffer[26] = 0; + SspmBuffer[27] = 0; + SspmBuffer[28] = 1 + (Rtc.time_timezone / 60); // Not sure why the "1" is needed but it is in my case + SspmBuffer[29] = abs(Rtc.time_timezone % 60); + Sspm->command_sequence++; + SspmBuffer[30] = Sspm->command_sequence; + + SSPMSend(33); +} + +void SSPMSendIAmHere(uint32_t relay) { + /* + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 00 0d 00 00 17 35 b6 + Marker |Module id |Ac|Cm|Size |Ix|Chksm| + + Response is blink green COMM led on SPM-4Relay + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 80 0d 00 01 00 17 48 b5 + Marker |Module id |Ac|Cm|Size |Rs|Ix|Chksm| + Rs = Return state + */ + uint8_t module = relay >> 2; + SSPMInitSend(); + memcpy(SspmBuffer +3, Sspm->module[module], SSPM_MODULE_NAME_SIZE); + SspmBuffer[16] = SSPM_FUNC_IAMHERE; // 0x0D + Sspm->command_sequence++; + SspmBuffer[19] = Sspm->command_sequence; + + SSPMSend(22); +} + +void SSPMSendInitScan(void) { + /* + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + AA 55 01 ff ff ff ff ff ff ff ff ff ff ff ff 00 10 00 00 02 cd f0 + Marker |Module id |Ac|Cm|Size |Ix|Chksm| + + Acknowledge: + AA 55 01 ff ff ff ff ff ff ff ff ff ff ff ff 80 10 00 01 00 02 e5 03 + |Ac|Cm|Size |Rt|Ix|Chksm| + */ + SSPMSetLock(30); // Disable requests from 100mSec loop + + memset(SspmBuffer, 0xFF, 15); + SspmBuffer[0] = 0xAA; + SspmBuffer[1] = 0x55; + SspmBuffer[2] = 0x01; + + SspmBuffer[15] = 0; + SspmBuffer[16] = SSPM_FUNC_INIT_SCAN; // 0x10 + SspmBuffer[17] = 0; + SspmBuffer[18] = 0; + Sspm->command_sequence++; + SspmBuffer[19] = Sspm->command_sequence; + + SSPMSend(22); + + AddLog(LOG_LEVEL_DEBUG, PSTR("SPM: Start relay scan...")); +} + +void SSPMSendGetEnergyTotal(uint32_t relay) { + /* + 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 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 16 00 0d 6b 7e 32 37 39 37 34 13 4b 35 36 37 01 14 e6 93 + Marker | | |Cm|Size |Module id |Ch|Ix|Chksm| + */ + uint8_t module = relay >> 2; + uint8_t channel = relay & 0x03; // Channel relays are NOT bit masked this time + SSPMInitSend(); + SspmBuffer[16] = SSPM_FUNC_GET_ENERGY_TOTAL; // 0x16 + SspmBuffer[18] = 0x0D; + memcpy(SspmBuffer +19, Sspm->module[module], SSPM_MODULE_NAME_SIZE); + SspmBuffer[31] = channel; + Sspm->command_sequence++; + SspmBuffer[32] = Sspm->command_sequence; + + SSPMSend(35); +} + +void SSPMSendGetEnergy(uint32_t relay) { + /* + relay_num = 1..8 + 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 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 18 00 10 6b 7e 32 37 39 37 34 13 4b 35 36 37 01 01 00 3c 2a db d1 + Marker | | |Cm|Size |Module id | |Ch| |Ix|Chksm| + */ + uint8_t module = relay >> 2; + uint8_t channel = 1 << (relay & 0x03); // Channel relays are bit masked + SSPMInitSend(); + SspmBuffer[16] = SSPM_FUNC_GET_ENERGY; // 0x18 + SspmBuffer[18] = 0x10; + memcpy(SspmBuffer +19, Sspm->module[module], SSPM_MODULE_NAME_SIZE); + SspmBuffer[31] = 0x01; + SspmBuffer[32] = channel; + SspmBuffer[33] = 0; + SspmBuffer[34] = 0x3C; + Sspm->command_sequence++; + SspmBuffer[35] = Sspm->command_sequence; + + SSPMSend(38); +} + +void SSPMSendGetLog(uint32_t relay, uint32_t entries) { + /* + 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 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 1a 00 10 6b 7e 32 37 39 37 34 13 4b 35 36 37 00 00 00 1d 09 8c cd + Marker | | |Cm|Size |Module id |Start|End |Ix|Chksm| + Start = newest log start number (Latest is 0) + End = older log end number (End - Start >= 29 (0x1d)) + */ + uint8_t module = relay >> 2; + uint32_t startlog = (entries >= 29) ? entries -29 : 0; + SSPMInitSend(); + SspmBuffer[16] = SSPM_FUNC_GET_LOG; // 0x1A + SspmBuffer[18] = 0x10; + memcpy(SspmBuffer +19, Sspm->module[module], SSPM_MODULE_NAME_SIZE); + SspmBuffer[31] = startlog >> 8; // MSB start log + SspmBuffer[32] = startlog; // LSB start log + SspmBuffer[33] = entries >> 8; // MSB end log + SspmBuffer[34] = entries; // LSB end log - Number of logs + Sspm->command_sequence++; + SspmBuffer[35] = Sspm->command_sequence; + + SSPMSend(38); +} + +/*********************************************************************************************/ + +void SSPMHandleReceivedData(void) { + uint8_t command = SspmBuffer[16]; + bool ack = (0x80 == SspmBuffer[15]); + uint8_t command_sequence = SspmBuffer[19 + Sspm->expected_bytes]; + +// AddLog(LOG_LEVEL_DEBUG, PSTR("SPM: Rcvd ack %d, cmnd %d, seq %d, size %d"), +// ack, command, command_sequence, Sspm->expected_bytes); + + if (ack) { + // Responses from ARM (Acked) + switch(command) { + case SSPM_FUNC_FIND: + /* 0x00 + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 01 00 00 fc 73 + |Er| |St| + */ + if ((1 == Sspm->expected_bytes) && (0 == SspmBuffer[19])) { + Sspm->mstate++; // Cycle to + } + break; + case SSPM_FUNC_GET_OPS: + /* 0x04 - Overload Protection + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 80 04 00 02 00 00 06 98 06 + Marker |Module id |Ac|Cm|Size | |Ix|Chksm| + + AA 55 01 6B 7E 32 37 39 37 34 13 4B 35 36 37 80 04 00 35 00 07 00 11 30 00 00 00 0A 00 F0 00 00 00 0A 00 14 00 00 + 00 11 30 00 00 00 0A 00 F0 00 00 00 0A 00 14 00 00 + 00 11 30 00 00 00 0A 00 F0 00 00 00 0A 00 14 00 00 07 8A 86 + Marker |Module id |Ac|Cm|Size | |Ch|Ra|Max P |Min P |Max U |Min U |Max I |De|Ix|Chksm| + | | | 4400W| 0.1W| 240V| 0.1V| 20A| | + */ + if (0x02 == Sspm->expected_bytes) { + + } + + Sspm->module_selected--; + if (Sspm->module_selected > 0) { + SSPMSendGetModuleState(Sspm->module_selected -1); + } else { + SSPMSendGetScheme(Sspm->module_selected); + } + break; + case SSPM_FUNC_GET_MODULE_STATE: + /* 0x09 + 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 + AA 55 01 8b 34 32 37 39 37 34 13 4b 35 36 37 80 09 00 06 00 0f 01 01 01 01 05 fe 35 + |OS|4RelayMasks| + */ + if (0x06 == Sspm->expected_bytes) { + // SspmBuffer[20] & 0x0F // Relays operational + power_t current_state = SspmBuffer[20] >> 4; // Relays state + power_t mask = 0x0000000F; + for (uint32_t i = 0; i < Sspm->module_max; i++) { + if ((SspmBuffer[3] == Sspm->module[i][0]) && (SspmBuffer[4] == Sspm->module[i][1])) { + current_state <<= (i * 4); + mask <<= (i * 4); + TasmotaGlobal.power &= (POWER_MASK ^ mask); + TasmotaGlobal.power |= current_state; + break; + } + } + Sspm->old_power = TasmotaGlobal.power; + TasmotaGlobal.devices_present += 4; + } + SSPMSendGetOps(Sspm->module_selected -1); + break; + case SSPM_FUNC_GET_SCHEME: + /* 0x0B + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 + AA 55 01 6b 7e 32 37 39 37 34 13 4b 35 36 37 80 0b 00 02 00 00 09 bb c7 + |?? ??| + */ + if (0x02 == Sspm->expected_bytes) { + + } + Sspm->module_selected++; + if (Sspm->module_selected < Sspm->module_max) { + SSPMSendGetScheme(Sspm->module_selected); + } else { + AddLog(LOG_LEVEL_DEBUG, PSTR("SPM: Relay scan done")); + + Sspm->mstate = SPM_SCAN_COMPLETE; + } + break; + case SSPM_FUNC_SET_TIME: + /* 0x0C + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 80 0c 00 01 00 04 3e 62 + */ + TasmotaGlobal.devices_present = 0; + SSPMSendGetModuleState(Sspm->module_selected -1); + break; + case SSPM_FUNC_INIT_SCAN: + /* 0x10 + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + 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: + /* 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 + |?? ?? ?? ??| + */ + Sspm->mstate = SPM_START_SCAN; + break; + case SSPM_FUNC_GET_ENERGY_TOTAL: + /* 0x16 + 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 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 80 16 01 7e 00 8b 34 32 37 39 37 34 13 4b 35 36 37 + 03 <- L4 + 07 e5 0b 0d <- End date (Today) 2021 nov 13 + 07 e5 05 11 <- Start date 2021 may 17 + 00 05 <- 5kWh (13/11 Today) + 00 00 <- 0 (12/11 Yesterday) + 00 04 <- 4kWh (11/11 etc) + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 42 67 46 + */ + { + uint32_t energy_today = 0; + uint32_t energy_yesterday = 0; + uint32_t energy_total = 0; + uint32_t entries = (Sspm->expected_bytes - 22) / 2; + + for (uint32_t i = 0; i < entries; i++) { + uint32_t today_energy = (SspmBuffer[41 + (i*2)] << 8) + SspmBuffer[42 + (i*2)]; + if (28702 == today_energy) { today_energy = 0; } // Unknown why sometimes 0x701E (=28702kWh) pops up + if (0 == i) { energy_today = today_energy; } + if (1 == i) { energy_yesterday = today_energy; } + energy_total += today_energy; + } + uint32_t channel = SspmBuffer[32]; + for (uint32_t module = 0; module < Sspm->module_max; module++) { + if ((SspmBuffer[20] == Sspm->module[module][0]) && (SspmBuffer[21] == Sspm->module[module][1])) { + Sspm->energy_today[module][channel] = energy_today; + Sspm->energy_yesterday[module][channel] = energy_yesterday; + Sspm->energy_total[module][channel] = energy_total; // xkWh + break; + } + } + Sspm->allow_updates = 1; + } + break; + case SSPM_FUNC_GET_LOG: + /* 0x1A + 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 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 80 1a 01 3a 00 6b 7e 32 37 39 37 34 13 4b 35 36 37 + 1e Number of log entries (1e = 30) + 07 e5 0b 06 0f 25 19 02 01 00 10 byte log entry + |-- trigger 00 = App, 01 = Device, 02 = Overload, 03 = Overtemp + |----- state 00 = Off, 01 = On + |-------- Channel 00 to 03 + |----------- Second = 25 + |-------------- Minute = 37 + |----------------- Hour = 15 + |-------------------- Day = 6 + |----------------------- Month = 11 = November + ----------------------------- Year 07 e5 = 2021 + 07 e5 0b 06 0f 1f 08 00 00 01 + 07 e5 0b 06 0f 1f 04 02 00 01 + 07 e5 0b 06 0f 1e 32 01 00 01 + 07 e5 0b 06 0f 1e 1e 01 01 01 + 07 e5 0b 06 0f 18 38 02 01 01 + 07 e5 0b 06 0f 12 38 00 01 01 + 07 e5 0b 06 0e 37 36 03 00 00 + 07 e5 0b 06 0e 37 36 01 00 00 + 07 e5 0b 06 0e 37 1e 03 01 00 + 07 e5 0b 06 0e 36 37 01 01 00 + ... + 07 e5 0b 06 0d 30 2d 03 00 01 09 89 fe + */ + + break; + case SSPM_FUNC_ENERGY_PERIOD: + /* 0x1B + Response after start energy period + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 80 1b 00 0e [00] 8b 34 32 37 39 37 34 13 4b 35 36 37 [03] f7 b1 bc L4 + Response after refresh or stop energy period + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 80 1b 00 11 [00] 8b 34 32 37 39 37 34 13 4b 35 36 37 [03] [00 00 00] f8 94 15 L4, kWh start period (0) + */ + + break; + } + } else { + // Initiated by ARM + switch(command) { + case SSPM_FUNC_ENERGY_RESULT: + /* 0x06 + 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 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00 1c 6b 7e 32 37 39 37 34 13 4b 35 36 37 01 00 00 00 e3 5b 00 00 00 00 00 00 00 00 00 6b 1f 95 1e + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00 1C 8B 34 32 37 39 37 34 13 4B 35 36 37 01 00 0B 00 E4 37 00 19 0E 00 00 02 00 19 09 4B 28 1D 71 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00 1C 8B 34 32 37 39 37 34 13 4B 35 36 37 08 00 0A 00 E3 61 00 18 2E 00 00 00 00 18 33 4B 27 D3 0D + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00 1C 8B 34 32 37 39 37 34 13 4B 35 36 37 08 02 04 00 DC 14 01 C1 3D 00 10 19 01 C2 29 4B 37 6B 26 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00 1c 8b 34 32 37 39 37 34 13 4b 35 36 37 08 00 44 00 e1 35 00 9a 3e 00 01 45 00 9a 38 00 08 8b ae + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 06 00 1c 8b 34 32 37 39 37 34 13 4b 35 36 37 08 00 4a 00 e1 22 00 61 4d 00 2c 38 00 a8 28 20 26 21 70 + |Ch|Curre|Voltage |ActivePo|Reactive|Apparent|5m| + Values are XX XX - number + XX - decimals + 5m - 5 minutes Power Consumption (Ws) + */ + { + uint32_t channel = 0; + for (channel = 0; channel < 4; channel++) { + if (SspmBuffer[31] & 1) { break; } + SspmBuffer[31] >>= 1; + } + for (uint32_t module = 0; module < Sspm->module_max; module++) { + if ((SspmBuffer[19] == Sspm->module[module][0]) && (SspmBuffer[20] == Sspm->module[module][1])) { + Sspm->current[module][channel] = SspmBuffer[32] + (float)SspmBuffer[33] / 100; // x.xxA + Sspm->voltage[module][channel] = (SspmBuffer[34] << 8) + SspmBuffer[35] + (float)SspmBuffer[36] / 100; // x.xxV + Sspm->active_power[module][channel] = (SspmBuffer[37] << 8) + SspmBuffer[38] + (float)SspmBuffer[39] / 100; // x.xxW + Sspm->reactive_power[module][channel] = (SspmBuffer[40] << 8) + SspmBuffer[41] + (float)SspmBuffer[42] / 100; // x.xxVAr + Sspm->apparent_power[module][channel] = (SspmBuffer[43] << 8) + SspmBuffer[44] + (float)SspmBuffer[45] / 100; // x.xxVA + float power_factor = (Sspm->active_power[module][channel] && Sspm->apparent_power[module][channel]) ? Sspm->active_power[module][channel] / Sspm->apparent_power[module][channel] : 0; + if (power_factor > 1) { power_factor = 1; } + Sspm->power_factor[module][channel] = power_factor; + break; + } + } + SSPMSendAck(command_sequence); + Sspm->allow_updates = 1; + } + break; + case SSPM_FUNC_KEY_PRESS: + /* 0x07 + 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 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 07 00 0d 6b 7e 32 37 39 37 34 13 4b 35 36 37 11 04 bf c3 + |AS| + */ + if (!Sspm->no_send_key) { + power_t relay = SspmBuffer[31] & 0x0F; // Relays active + power_t relay_state = SspmBuffer[31] >> 4; // Relays state + for (uint32_t i = 0; i < Sspm->module_max; i++) { + if ((SspmBuffer[19] == Sspm->module[i][0]) && (SspmBuffer[20] == Sspm->module[i][1])) { + relay <<= (i * 4); + relay_state <<= (i * 4); + break; + } + } + for (uint32_t i = 1; i <= TasmotaGlobal.devices_present; i++) { + if (relay &1) { + ExecuteCommandPower(i, relay_state &1, SRC_BUTTON); + } + relay >>= 1; + relay_state >>= 1; + } + Sspm->old_power = TasmotaGlobal.power; + } + SSPMSendAck(command_sequence); + break; + case SSPM_FUNC_SCAN_START: + /* 0x0F + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 0f 00 01 02 01 9d f8 + */ + SSPMSendAck(command_sequence); + break; + 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| + |130| 1.0.0| 20A| 0.1A| 240V| 0.1V| 4400W| 0.1W| + Ty = Type of sub-device. 130: Four-channel sub-device + */ + if ((0x24 == Sspm->expected_bytes) && (Sspm->module_max < SSPM_MAX_MODULES)) { + memcpy(Sspm->module[1], Sspm->module[0], (SSPM_MAX_MODULES -1) * SSPM_MODULE_NAME_SIZE); + memcpy(Sspm->module[0], SspmBuffer + 19, SSPM_MODULE_NAME_SIZE); + Sspm->module_max++; + } + SSPMSendAck(command_sequence); + break; + case SSPM_FUNC_SCAN_DONE: + /* 0x19 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 19 00 00 03 a1 16 + */ + SSPMSendAck(command_sequence); + Sspm->module_selected = Sspm->module_max; + SSPMSendSetTime(); + break; + } + } +} + +void SSPMSerialInput(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 24 25 26 27 + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 00 19 00 00 03 a1 16 + Marker |Module id |Ac|Cm|Size |Ix|Chksm| + AA 55 01 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 01 00 00 fc 73 + Marker |Module id |Ac|Cm|Size |Pl|Ix|Chksm| + AA 55 01 6b 7e 32 37 39 37 34 13 4b 35 36 37 80 09 00 06 00 0f 01 01 01 01 05 f9 9d + Marker |Module id |Ac|Cm|Size |Payload |Ix|Chksm| + 00 Request + 80 Response (Ack) + */ + while (SspmSerial->available()) { + yield(); + uint8_t serial_in_byte = SspmSerial->read(); + + if ((0x55 == serial_in_byte) && (0xAA == SspmBuffer[Sspm->serial_in_byte_counter -1])) { + Sspm->expected_bytes = 0; + SspmBuffer[0] = 0xAA; + Sspm->serial_in_byte_counter = 1; + } + if (Sspm->serial_in_byte_counter < SSPM_SERIAL_BUFFER_SIZE -1) { + SspmBuffer[Sspm->serial_in_byte_counter++] = serial_in_byte; + if (19 == Sspm->serial_in_byte_counter) { + Sspm->expected_bytes = (SspmBuffer[Sspm->serial_in_byte_counter -2] << 8) + SspmBuffer[Sspm->serial_in_byte_counter -1]; + } + if (Sspm->serial_in_byte_counter == (22 + Sspm->expected_bytes)) { + + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SPM: ARM %*_H"), Sspm->serial_in_byte_counter, SspmBuffer); + + uint16_t crc_rcvd = (SspmBuffer[Sspm->serial_in_byte_counter -2] << 8) + SspmBuffer[Sspm->serial_in_byte_counter -1]; + uint16_t crc_calc = SSPMCalculateCRC(SspmBuffer, Sspm->serial_in_byte_counter -2); + if (crc_rcvd == crc_calc) { + SSPMHandleReceivedData(); + } else { + AddLog(LOG_LEVEL_DEBUG, PSTR("SPM: CRC error")); + } + Sspm->serial_in_byte_counter = 0; + Sspm->expected_bytes = 0; + } + } else { + AddLog(LOG_LEVEL_DEBUG, PSTR("SPM: Serial input buffer overflow")); + Sspm->serial_in_byte_counter = 0; + Sspm->expected_bytes = 0; + } + } +} + +/*********************************************************************************************/ + +void SSPMInit(void) { + if (!ValidTemplate(PSTR("Sonoff SPM (POC1)")) && + !ValidTemplate(PSTR("Sonoff SPM (POC2)"))) { return; } + if (!PinUsed(GPIO_RXD) || !PinUsed(GPIO_TXD)) { return; } + + Sspm = (TSspm*)calloc(sizeof(TSspm), 1); + if (!Sspm) { return; } + SspmBuffer = (uint8_t*)malloc(SSPM_SERIAL_BUFFER_SIZE); + if (!SspmBuffer) { + free(Sspm); + return; + } + SspmSerial = new TasmotaSerial(Pin(GPIO_RXD), Pin(GPIO_TXD), 1, 0, SSPM_SERIAL_BUFFER_SIZE); + if (!SspmSerial->begin(115200)) { + free(SspmBuffer); + free(Sspm); + return; + } + + pinMode(SSPM_GPIO_ARM_RESET, OUTPUT); + digitalWrite(SSPM_GPIO_ARM_RESET, 1); + + if (0 == Settings->flag2.voltage_resolution) { + Settings->flag2.voltage_resolution = 1; // SPM has 2 decimals but this keeps the gui clean + Settings->flag2.current_resolution = 2; // SPM has 2 decimals + Settings->flag2.wattage_resolution = 1; // SPM has 2 decimals but this keeps the gui clean + Settings->flag2.energy_resolution = 0; // SPM has no decimals on total energy + } + +#if CONFIG_IDF_TARGET_ESP32 +#ifdef USE_ETHERNET + Settings->eth_address = 0; // EthAddress + Settings->eth_type = ETH_PHY_LAN8720; // EthType + Settings->eth_clk_mode = ETH_CLOCK_GPIO17_OUT; // EthClockMode +#endif +#endif + + Sspm->old_power = TasmotaGlobal.power; + Sspm->mstate = SPM_WAIT; // Start init sequence +} + +/*********************************************************************************************/ + +void SSPMEvery100ms(void) { + Sspm->last_totals++; + + if (Sspm->no_send_key) { Sspm->no_send_key--; } + + if (Sspm->timeout) { + Sspm->timeout--; + if (!Sspm->timeout) { + Sspm->allow_updates = 1; + } + } + + // Fix race condition if the ARM doesn't respond + if ((Sspm->mstate > SPM_NONE) && (Sspm->mstate < SPM_SEND_FUNC_UNITS)) { + Sspm->counter++; + if (Sspm->counter > 20) { + Sspm->mstate = SPM_NONE; + } + } + switch (Sspm->mstate) { + case SPM_NONE: + return; + case SPM_WAIT: + // 100ms wait + Sspm->mstate = SPM_RESET; + break; + case SPM_RESET: + // Reset ARM + digitalWrite(SSPM_GPIO_ARM_RESET, 0); + delay(18); + digitalWrite(SSPM_GPIO_ARM_RESET, 1); + delay(18); + Sspm->mstate = SPM_POLL_ARM; + case SPM_POLL_ARM: + // Wait for first acknowledge from ARM after reset + SSPMSendCmnd(SSPM_FUNC_FIND); + break; + case SPM_POLL_ARM_2: + // Wait for second acknowledge from ARM after reset + SSPMSendCmnd(SSPM_FUNC_FIND); + break; + case SPM_SEND_FUNC_UNITS: + // Get number of units + SSPMSendCmnd(SSPM_FUNC_UNITS); + break; + case SPM_START_SCAN: + // Start scan module sequence + Sspm->module_max = 0; + SSPMSendInitScan(); + Sspm->mstate = SPM_WAIT_FOR_SCAN; + break; + case SPM_WAIT_FOR_SCAN: + // Wait for scan sequence to complete + break; + case SPM_SCAN_COMPLETE: + // Scan sequence finished + TasmotaGlobal.discovery_counter = 1; // Force TasDiscovery() + Sspm->get_energy_relay = 0; + Sspm->allow_updates = 1; // Enable requests from 100mSec loop + Sspm->mstate = SPM_GET_ENERGY_TOTALS; + break; + case SPM_GET_ENERGY_TOTALS: + // Retrieve Energy total status from up to 128 relays + if (Sspm->allow_updates) { + SSPMSetLock(4); + SSPMSendGetEnergyTotal(Sspm->get_energy_relay); + Sspm->get_energy_relay++; + if (Sspm->get_energy_relay >= TasmotaGlobal.devices_present) { + Sspm->get_energy_relay = TasmotaGlobal.devices_present; + Sspm->mstate = SPM_UPDATE_CHANNELS; + } + } + break; + case SPM_UPDATE_CHANNELS: + // Retrieve Energy status from up to 128 powered on relays (takes 128 * 2s!!) + if (Sspm->allow_updates) { + Sspm->get_energy_relay++; + if (Sspm->get_energy_relay >= TasmotaGlobal.devices_present) { + Sspm->get_energy_relay = 0; + if (Sspm->last_totals > 1200) { // Get totals every 2 minutes (takes 128 * 0.2s) + Sspm->last_totals = 0; + Sspm->get_totals = 1; + } else { + Sspm->get_totals = 0; + } + } + power_t powered_on = TasmotaGlobal.power >> Sspm->get_energy_relay; + if (powered_on &1) { + SSPMSetLock(4); + if (Sspm->get_totals) { + SSPMSendGetEnergyTotal(Sspm->get_energy_relay); + } else { + SSPMSendGetEnergy(Sspm->get_energy_relay); + } + } else { + uint32_t module = Sspm->get_energy_relay >> 2; + uint32_t channel = Sspm->get_energy_relay &3; + if (Sspm->voltage[module][channel]) { + Sspm->voltage[module][channel] = 0; + Sspm->current[module][channel] = 0; + Sspm->active_power[module][channel] = 0; + Sspm->apparent_power[module][channel] = 0; + Sspm->reactive_power[module][channel] = 0; + Sspm->power_factor[module][channel] = 0; + } + } + } + break; + + } +} + +/*********************************************************************************************/ + +bool SSPMSetDevicePower(void) { + power_t new_power = XdrvMailbox.index; + if (new_power != Sspm->old_power) { + for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { + uint8_t new_state = (new_power >> i) &1; + if (new_state != ((Sspm->old_power >> i) &1)) { + SSPMSendSetRelay(i, new_state); + Sspm->no_send_key = 10; // Disable buttons for 10 * 0.1 second + } + } + Sspm->old_power = new_power; + } + return true; +} + +/*********************************************************************************************/ + +bool SSPMButton(void) { + bool result = false; + uint32_t button = XdrvMailbox.payload; + if ((PRESSED == button) && (NOT_PRESSED == Sspm->last_button)) { // Button pressed + Sspm->mstate = SPM_START_SCAN; + result = true; // Disable further button processing + } + Sspm->last_button = button; + return result; +} + +/*********************************************************************************************/ + +const uint16_t SSPM_SIZE = 128; +const char kSSPMEnergyPhases[] PROGMEM = "%*_f
%*_f%*_f%*_f|[%*_f,%*_f,%*_f,%*_f]"; + +char* SSPMEnergyFormat(char* result, float* input, uint32_t resolution, bool json) { + char layout[100]; + GetTextIndexed(layout, sizeof(layout), json, kSSPMEnergyPhases); + ext_snprintf_P(result, SSPM_SIZE, layout, resolution, &input[0], resolution, &input[1], resolution, &input[2], resolution, &input[3]); + return result; +} + +const char HTTP_SSPM_VOLTAGE[] PROGMEM = + "{s}" D_VOLTAGE "%s" D_UNIT_VOLT "{e}"; // {s} =
, {m} = , {e} =
%s" D_UNIT_AMPERE "{e}"; +const char HTTP_SSPM_POWER[] PROGMEM = + "{s}" D_POWERUSAGE_ACTIVE "%s" D_UNIT_WATT "{e}"; +const char HTTP_SSPM_POWER2[] PROGMEM = + "{s}" D_POWERUSAGE_APPARENT "%s" D_UNIT_VA "{e}" + "{s}" D_POWERUSAGE_REACTIVE "%s" D_UNIT_VAR "{e}" + "{s}" D_POWER_FACTOR "%s{e}"; +const char HTTP_SSPM_ENERGY[] PROGMEM = + "{s}" D_ENERGY_TODAY "%s" D_UNIT_KILOWATTHOUR "{e}" + "{s}" D_ENERGY_YESTERDAY "%s" D_UNIT_KILOWATTHOUR "{e}" + "{s}" D_ENERGY_TOTAL "%s" D_UNIT_KILOWATTHOUR "{e}"; + +void SSPMEnergyShow(bool json) { + if (!TasmotaGlobal.devices_present) { return; } // Not ready yet + + if (json) { + ResponseAppend_P(PSTR(",\"SPM\":{\"" D_JSON_ENERGY "\":[")); + for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { + ResponseAppend_P(PSTR("%s%*_f"), (i>0)?",":"", -1, &Sspm->energy_total[i >>2][i &3]); + } +#ifdef SSPM_JSON_ENERGY_YESTERDAY + ResponseAppend_P(PSTR("],\"" D_JSON_YESTERDAY "\":[")); + for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { + ResponseAppend_P(PSTR("%s%*_f"), (i>0)?",":"", -1, &Sspm->energy_today[i >>2][i &3]); + } +#endif +#ifdef SSPM_JSON_ENERGY_TODAY + ResponseAppend_P(PSTR("],\"" D_JSON_TODAY "\":[")); + for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { + ResponseAppend_P(PSTR("%s%*_f"), (i>0)?",":"", -1, &Sspm->energy_yesterday[i >>2][i &3]); + } +#endif + ResponseAppend_P(PSTR("],\"" D_JSON_ACTIVE_POWERUSAGE "\":[")); + for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { + ResponseAppend_P(PSTR("%s%*_f"), (i>0)?",":"", Settings->flag2.wattage_resolution, &Sspm->active_power[i >>2][i &3]); + } + ResponseAppend_P(PSTR("],\"" D_JSON_APPARENT_POWERUSAGE "\":[")); + for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { + ResponseAppend_P(PSTR("%s%*_f"), (i>0)?",":"", Settings->flag2.wattage_resolution, &Sspm->apparent_power[i >>2][i &3]); + } + ResponseAppend_P(PSTR("],\"" D_JSON_REACTIVE_POWERUSAGE "\":[")); + for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { + ResponseAppend_P(PSTR("%s%*_f"), (i>0)?",":"", Settings->flag2.wattage_resolution, &Sspm->reactive_power[i >>2][i &3]); + } + ResponseAppend_P(PSTR("],\"" D_JSON_POWERFACTOR "\":[")); + for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { + ResponseAppend_P(PSTR("%s%*_f"), (i>0)?",":"", 2, &Sspm->power_factor[i >>2][i &3]); + } + ResponseAppend_P(PSTR("],\"" D_JSON_VOLTAGE "\":[")); + for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { + ResponseAppend_P(PSTR("%s%*_f"), (i>0)?",":"", Settings->flag2.voltage_resolution, &Sspm->voltage[i >>2][i &3]); + } + ResponseAppend_P(PSTR("],\"" D_JSON_CURRENT "\":[")); + for (uint32_t i = 0; i < TasmotaGlobal.devices_present; i++) { + ResponseAppend_P(PSTR("%s%*_f"), (i>0)?",":"", Settings->flag2.current_resolution, &Sspm->current[i >>2][i &3]); + } + ResponseAppend_P(PSTR("]}")); + } else { + Sspm->rotate++; + if (Sspm->rotate >= TasmotaGlobal.devices_present) { + Sspm->rotate = 0; + } + uint32_t module = Sspm->rotate >> 2; + uint32_t relay_base = module * 4; + WSContentSend_P(PSTR("
{t}{s}")); // First column is empty ({t} = , {s} = ) + char value_chr[SSPM_SIZE]; + WSContentSend_PD(HTTP_SSPM_VOLTAGE, SSPMEnergyFormat(value_chr, Sspm->voltage[module], Settings->flag2.voltage_resolution, json)); + WSContentSend_PD(HTTP_SSPM_CURRENT, SSPMEnergyFormat(value_chr, Sspm->current[module], Settings->flag2.current_resolution, json)); + WSContentSend_PD(HTTP_SSPM_POWER, SSPMEnergyFormat(value_chr, Sspm->active_power[module], Settings->flag2.wattage_resolution, json)); + char valu2_chr[SSPM_SIZE]; + char valu3_chr[SSPM_SIZE]; + WSContentSend_PD(HTTP_SSPM_POWER2, SSPMEnergyFormat(value_chr, Sspm->apparent_power[module], Settings->flag2.wattage_resolution, json), + SSPMEnergyFormat(valu2_chr, Sspm->reactive_power[module], Settings->flag2.wattage_resolution, json), + SSPMEnergyFormat(valu3_chr, Sspm->power_factor[module], 2, json)); + WSContentSend_PD(HTTP_SSPM_ENERGY, SSPMEnergyFormat(value_chr, Sspm->energy_today[module], Settings->flag2.energy_resolution, json), + SSPMEnergyFormat(valu2_chr, Sspm->energy_yesterday[module], Settings->flag2.energy_resolution, json), + SSPMEnergyFormat(valu3_chr, Sspm->energy_total[module], Settings->flag2.energy_resolution, json)); + WSContentSend_P(PSTR("
) + for (uint32_t i = 1; i < 5; i++) { + WSContentSend_P(PSTR("L%d"), relay_base +i); + } + WSContentSend_P(PSTR("{e}")); // Last column is units ({e} =
{t}")); // {t} = - Define for next FUNC_WEB_SENSOR + } +} + +/*********************************************************************************************\ + * Commands +\*********************************************************************************************/ + +const char kSSPMCommands[] PROGMEM = "SSPM|" // Prefix + "Log|Energy|History|Scan|IamHere" ; + +void (* const SSPMCommand[])(void) PROGMEM = { + &CmndSSPMLog, &CmndSSPMEnergy, &CmndSSPMEnergyHistory, &CmndSSPMScan, &CmndSSPMIamHere }; + +void CmndSSPMLog(void) { + // Report 29 log entries + if ((XdrvMailbox.index < 1) || (XdrvMailbox.index > TasmotaGlobal.devices_present)) { XdrvMailbox.index = 1; } + XdrvMailbox.payload &= 0xFFFF; // Max 65000 entries + SSPMSendGetLog(XdrvMailbox.index -1, XdrvMailbox.payload +1); + ResponseCmndDone(); +} + +void CmndSSPMEnergy(void) { + if ((XdrvMailbox.index < 1) || (XdrvMailbox.index > TasmotaGlobal.devices_present)) { XdrvMailbox.index = 1; } + SSPMSendGetEnergy(XdrvMailbox.index -1); + ResponseCmndDone(); +} + +void CmndSSPMEnergyHistory(void) { + if ((XdrvMailbox.index < 1) || (XdrvMailbox.index > TasmotaGlobal.devices_present)) { XdrvMailbox.index = 1; } + SSPMSendGetEnergyTotal(XdrvMailbox.index -1); + ResponseCmndDone(); +} + +void CmndSSPMScan(void) { + // Start relay module scan taking up to 20 seconds + Sspm->mstate = SPM_START_SCAN; + ResponseCmndChar(PSTR(D_JSON_STARTED)); +} + +void CmndSSPMIamHere(void) { + // Blink module COMM led containing relay + if ((XdrvMailbox.payload < 1) || (XdrvMailbox.payload > TasmotaGlobal.devices_present)) { XdrvMailbox.payload = 1; } + SSPMSendIAmHere(XdrvMailbox.payload -1); + ResponseCmndDone(); +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv86(uint8_t function) { + bool result = false; + + if (FUNC_INIT == function) { + SSPMInit(); + } + else if (Sspm) { + switch (function) { + case FUNC_LOOP: + if (SspmSerial) { SSPMSerialInput(); } + break; + case FUNC_EVERY_100_MSECOND: + SSPMEvery100ms(); + break; + case FUNC_SET_DEVICE_POWER: + result = SSPMSetDevicePower(); + break; + case FUNC_JSON_APPEND: + SSPMEnergyShow(true); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + SSPMEnergyShow(false); + break; +#endif // USE_WEBSERVER + case FUNC_COMMAND: + result = DecodeCommand(kSSPMCommands, SSPMCommand); + break; + case FUNC_BUTTON_PRESSED: + result = SSPMButton(); + break; + } + } + return result; +} + +#endif // USE_SONOFF_SPM +#endif // ESP32 diff --git a/tasmota/xdsp_08_ILI9488.ino b/tasmota/xdsp_08_ILI9488.ino deleted file mode 100644 index 5c3cd2f5d..000000000 --- a/tasmota/xdsp_08_ILI9488.ino +++ /dev/null @@ -1,167 +0,0 @@ -/* - xdsp_08_ILI9488.ino - Display ILI9488 support for Tasmota - - Copyright (C) 2021 Theo Arends, 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 - 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_SPI -#ifdef USE_DISPLAY -#ifdef USE_DISPLAY_ILI9488 - -#define XDSP_08 8 -#define XI2C_38 38 // See I2CDEVICES.md - -#define COLORED 1 -#define UNCOLORED 0 - -// using font 8 is opional (num=3) -// very badly readable, but may be useful for graphs -#define USE_TINY_FONT - - -#include -uint8_t ili9488_ctouch_counter = 0; -bool ili9488_init_done = false; - -// currently fixed -#define BACKPLANE_PIN 2 - -extern uint8_t color_type; -ILI9488 *ili9488; -extern const uint16_t picture[]; - -/*********************************************************************************************/ - -void ILI9488_InitDriver(void) { - if (PinUsed(GPIO_ILI9488_CS) && (TasmotaGlobal.spi_enabled & SPI_MOSI)) { - - Settings->display_model = XDSP_08; - - if (Settings->display_width != ILI9488_TFTWIDTH) { - Settings->display_width = ILI9488_TFTWIDTH; - } - if (Settings->display_height != ILI9488_TFTHEIGHT) { - Settings->display_height = ILI9488_TFTHEIGHT; - } - - // default colors - fg_color = ILI9488_WHITE; - bg_color = ILI9488_BLACK; - - int8_t bppin = BACKPLANE_PIN; - if (PinUsed(GPIO_BACKLIGHT)) { - bppin = Pin(GPIO_BACKLIGHT); - } - - // init renderer, must use hardware spi - ili9488 = new ILI9488(Pin(GPIO_ILI9488_CS), Pin(GPIO_SPI_MOSI), Pin(GPIO_SPI_CLK), bppin); - - ili9488->begin(); - renderer = ili9488; - renderer->DisplayInit(DISPLAY_INIT_MODE,Settings->display_size,Settings->display_rotate,Settings->display_font); - renderer->dim(GetDisplayDimmer16()); - -#ifdef SHOW_SPLASH - // Welcome text - renderer->setTextFont(2); - renderer->setTextColor(ILI9488_WHITE,ILI9488_BLACK); - renderer->DrawStringAt(50, 50, "ILI9488 TFT Display!", ILI9488_WHITE,0); - delay(1000); - - //renderer->drawRGBBitmap(100,100, picture,51,34); -#endif - - color_type = COLOR_COLOR; - // start digitizer -#ifdef USE_FT5206 - FT5206_Touch_Init(Wire); -#endif - - ili9488_init_done = true; - AddLog(LOG_LEVEL_INFO, PSTR("DSP: ILI9488")); - } -} - -#ifdef USE_FT5206 -#ifdef USE_TOUCH_BUTTONS - -void ILI9488_RotConvert(int16_t *x, int16_t *y) { -int16_t temp; - if (renderer) { - uint8_t rot=renderer->getRotation(); - switch (rot) { - case 0: - temp=*y; - *y=renderer->height()-*x; - *x=temp; - break; - case 1: - break; - case 2: - break; - case 3: - temp=*y; - *y=*x; - *x=renderer->width()-temp; - break; - } - } -} - -// check digitizer hit -void ILI9488_CheckTouch(void) { - ili9488_ctouch_counter++; - if (2 == ili9488_ctouch_counter) { - // every 100 ms should be enough - ili9488_ctouch_counter = 0; - Touch_Check(ILI9488_RotConvert); - } -} -#endif // USE_TOUCH_BUTTONS -#endif // USE_FT5206 - - -/*********************************************************************************************/ -/*********************************************************************************************\ - * Interface -\*********************************************************************************************/ -bool Xdsp08(uint8_t function) -{ - bool result = false; - - if (FUNC_DISPLAY_INIT_DRIVER == function) { - ILI9488_InitDriver(); - } - else if (ili9488_init_done && (XDSP_08 == Settings->display_model)) { - switch (function) { - case FUNC_DISPLAY_MODEL: - result = true; - break; - case FUNC_DISPLAY_EVERY_50_MSECOND: -#ifdef USE_TOUCH_BUTTONS - if (FT5206_found) { - ILI9488_CheckTouch(); - } -#endif - break; - } - } - return result; -} - -#endif // USE_DISPLAY_ILI9488 -#endif // USE_DISPLAY -#endif // USE_SPI diff --git a/tasmota/xdsp_08_ILI9488_UD.ino b/tasmota/xdsp_08_ILI9488_UD.ino deleted file mode 100644 index 8717397d5..000000000 --- a/tasmota/xdsp_08_ILI9488_UD.ino +++ /dev/null @@ -1,111 +0,0 @@ -/* - xdsp_08_ILI9488.ino - Display ILI9488 support for Tasmota - - Copyright (C) 2021 Theo Arends, 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 - 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_SPI -#ifdef USE_DISPLAY -#ifdef USE_DISPLAY_ILI9488_UD -#ifdef USE_UNIVERSAL_DISPLAY - -#define XDSP_08 8 - -bool ili9488_init_done = false; - -Renderer *Init_uDisplay(const char *desc, int8_t cs); -void udisp_CheckTouch(void); - -/*********************************************************************************************/ - -const char ILI9488_DESC[] PROGMEM = -":H,ILI9488,480,320,16,SPI,1,*,*,*,*,*,*,*,10\n" -":S,2,1,1,0,40,20\n" -":I\n" -"E0,0F,00,03,09,08,16,0A,3F,78,4C,09,0A,08,16,1A,0F\n" -"E1,0F,00,16,19,03,0F,05,32,45,46,04,0E,0D,35,37,0F\n" -"C0,2,17,15\n" -"C1,1,41\n" -"C5,3,00,12,80\n" -"36,1,48\n" -"3A,1,66\n" -"B0,1,80\n" -"B1,1,A0\n" -"B4,1,02\n" -"B6,2,02,02\n" -"E9,1,00\n" -"F7,4,A9,51,2C,82\n" -"11,80\n" -"29,0\n" -":o,28\n" -":O,29\n" -":A,2A,2B,2C,16\n" -":R,36\n" -";:0,48,00,00,00\n" -":0,28,00,00,01\n" -":1,28,00,00,00\n" -":2,E8,00,00,03\n" -":3,88,00,00,02\n" -":P,18\n" -":i,20,21\n" -":TI1,38,*,*\n" -"#\n"; - -void ILI9488_InitDriver(void) { - if (PinUsed(GPIO_ILI9488_CS) && (TasmotaGlobal.spi_enabled & SPI_MOSI)) { - - renderer = Init_uDisplay(ILI9488_DESC, Pin(GPIO_ILI9488_CS)); - - if (!renderer) return; - - Settings->display_model = XDSP_08; - - ili9488_init_done = true; - } -} - -/*********************************************************************************************/ -/*********************************************************************************************\ - * Interface -\*********************************************************************************************/ -bool Xdsp08(uint8_t function) -{ - bool result = false; - - if (FUNC_DISPLAY_INIT_DRIVER == function) { - ILI9488_InitDriver(); - } - else if (ili9488_init_done && (XDSP_08 == Settings->display_model)) { - switch (function) { - case FUNC_DISPLAY_MODEL: - result = true; - break; - case FUNC_DISPLAY_EVERY_50_MSECOND: -#ifdef USE_FT5206 - if (FT5206_found) { - udisp_CheckTouch(); - } -#endif - break; - } - } - return result; -} - -#endif // USE_UNIVERSAL_DISPLAY -#endif // USE_DISPLAY_ILI9488 -#endif // USE_DISPLAY -#endif // USE_SPI diff --git a/tasmota/xdsp_17_universal.ino b/tasmota/xdsp_17_universal.ino index d8be8b94b..b80205029 100644 --- a/tasmota/xdsp_17_universal.ino +++ b/tasmota/xdsp_17_universal.ino @@ -62,10 +62,11 @@ void Core2DisplayDim(uint8_t dim); const char DSP_SAMPLE_DESC[] PROGMEM = DSP_ROM_DESC #endif // DSP_ROM_DESC /*********************************************************************************************/ -Renderer *Init_uDisplay(const char *desc, int8_t cs) { +Renderer *Init_uDisplay(const char *desc) { char *ddesc = 0; char *fbuff; uDisplay *udisp; +int8_t cs; if (TasmotaGlobal.gpio_optiona.udisplay_driver || desc) { @@ -185,18 +186,16 @@ uDisplay *udisp; cp += 4; //; 7 params nr,cs,sclk,mosi,dc,bl,reset,miso //SPI,*,*,*,*,*,*,* - if (cs < 0) { - switch (*cp) { - case '1': - cs = Pin(GPIO_SPI_CS); - break; - case '2': - cs = Pin(GPIO_SPI_CS, 1); - break; - default: - cs = Pin(GPIO_SSPI_CS); - break; - } + switch (*cp) { + case '1': + cs = Pin(GPIO_SPI_CS); + break; + case '2': + cs = Pin(GPIO_SPI_CS, 1); + break; + default: + cs = Pin(GPIO_SSPI_CS); + break; } if (*cp == '1') { cp+=2; @@ -433,7 +432,7 @@ bool Xdsp17(uint8_t function) { bool result = false; if (FUNC_DISPLAY_INIT_DRIVER == function) { - Init_uDisplay(0, -1); + Init_uDisplay(nullptr); } else if (udisp_init_done && (XDSP_17 == Settings->display_model)) { switch (function) { diff --git a/tasmota/xlgt_01_ws2812.ino b/tasmota/xlgt_01_ws2812.ino index 465aba427..f2c8b0610 100644 --- a/tasmota/xlgt_01_ws2812.ino +++ b/tasmota/xlgt_01_ws2812.ino @@ -29,15 +29,15 @@ * * light_scheme WS2812 3+ Colors 1+2 Colors Effect * ------------ ------ --------- ---------- ----------------- - * 0 yes no no Clock - * 1 yes no no Incandescent - * 2 yes no no RGB - * 3 yes no no Christmas - * 4 yes no no Hanukkah - * 5 yes no no Kwanzaa - * 6 yes no no Rainbow - * 7 yes no no Fire - * + * 0 (5) yes no no Clock + * 1 (6) yes no no Incandescent + * 2 (7) yes no no RGB + * 3 (8) yes no no Christmas + * 4 (9) yes no no Hanukkah + * 5 (10) yes no no Kwanzaa + * 6 (11) yes no no Rainbow + * 7 (12) yes no no Fire + * 8 (13) yes no no Stairs \*********************************************************************************************/ #define XLGT_01 1 @@ -45,10 +45,10 @@ const uint8_t WS2812_SCHEMES = 10; // Number of WS2812 schemes const char kWs2812Commands[] PROGMEM = "|" // No prefix - D_CMND_LED "|" D_CMND_PIXELS "|" D_CMND_ROTATION "|" D_CMND_WIDTH ; + D_CMND_LED "|" D_CMND_PIXELS "|" D_CMND_ROTATION "|" D_CMND_WIDTH "|" D_CMND_STEPPIXELS ; void (* const Ws2812Command[])(void) PROGMEM = { - &CmndLed, &CmndPixels, &CmndRotation, &CmndWidth }; + &CmndLed, &CmndPixels, &CmndRotation, &CmndWidth, &CmndStepPixels }; #include @@ -171,6 +171,7 @@ WsColor kHanukkah[2] = { 0,0,255, 255,255,255 }; WsColor kwanzaa[3] = { 255,0,0, 0,0,0, 0,255,0 }; WsColor kRainbow[7] = { 255,0,0, 255,128,0, 255,255,0, 0,255,0, 0,0,255, 128,0,255, 255,0,255 }; WsColor kFire[3] = { 255,0,0, 255,102,0, 255,192,0 }; +WsColor kStairs[2] = { 0,0,0, 255,255,255 }; ColorScheme kSchemes[WS2812_SCHEMES -1] = { // Skip clock scheme kIncandescent, 2, kRgb, 3, @@ -178,7 +179,8 @@ ColorScheme kSchemes[WS2812_SCHEMES -1] = { // Skip clock scheme kHanukkah, 2, kwanzaa, 3, kRainbow, 7, - kFire, 3 }; + kFire, 3, + kStairs, 2 }; uint8_t kWidth[5] = { 1, // Small @@ -491,6 +493,97 @@ void Ws2812Bars(uint32_t schemenr) Ws2812StripShow(); } +void Ws2812Steps(uint32_t schemenr) { +#if (USE_WS2812_CTYPE > NEO_3LED) + RgbwColor c; + c.W = 0; +#else + RgbColor c; +#endif + + ColorScheme scheme = kSchemes[schemenr]; + // apply main color if current sheme == kStairs + if (scheme.colors == kStairs) { + scheme.colors[1].red = Settings->light_color[0]; + scheme.colors[1].green = Settings->light_color[1]; + scheme.colors[1].blue = Settings->light_color[2]; + } + + uint8_t scheme_count = scheme.count; + if (Settings->light_fade) { + scheme_count = Settings->ws_width[WS_HOUR]; // Width4 + } + if (scheme_count < 2) { + scheme_count = 2; + } + + WsColor mcolor[scheme_count]; + + uint8_t color_start = 0; + uint8_t color_end = 1; + if (Settings->light_rotation & 0x01) { + color_start = 1; + color_end = 0; + } + + if (Settings->light_fade) { + // generate gradient (width = Width4) + for (uint32_t i = 1; i < scheme_count - 1; i++) { + mcolor[i].red = (uint8_t) wsmap(i, 0, scheme_count, scheme.colors[color_start].red, scheme.colors[color_end].red); + mcolor[i].green = (uint8_t) wsmap(i, 0, scheme_count, scheme.colors[color_start].green, scheme.colors[color_end].green); + mcolor[i].blue = (uint8_t) wsmap(i, 0, scheme_count, scheme.colors[color_start].blue, scheme.colors[color_end].blue); + } + } else { + memcpy(mcolor, scheme.colors, sizeof(mcolor)); + } + // Repair first & last color in gradient; apply scheme rotation if fade==0 + mcolor[0].red = scheme.colors[color_start].red; + mcolor[0].green = scheme.colors[color_start].green; + mcolor[0].blue = scheme.colors[color_start].blue; + mcolor[scheme_count-1].red = scheme.colors[color_end].red; + mcolor[scheme_count-1].green = scheme.colors[color_end].green; + mcolor[scheme_count-1].blue = scheme.colors[color_end].blue; + + // Adjust to dimmer value + float dimmer = 100 / (float)Settings->light_dimmer; + for (uint32_t i = 0; i < scheme_count; i++) { + float fmyRed = (float)mcolor[i].red / dimmer; + float fmyGrn = (float)mcolor[i].green / dimmer; + float fmyBlu = (float)mcolor[i].blue / dimmer; + mcolor[i].red = (uint8_t)fmyRed; + mcolor[i].green = (uint8_t)fmyGrn; + mcolor[i].blue = (uint8_t)fmyBlu; + } + + uint32_t speed = Settings->light_speed; + int32_t current_position = Light.strip_timer_counter / speed; + + //all pixels are shown already | rotation change will not change current state + if (current_position > Settings->light_pixels / Settings->light_step_pixels + scheme_count ) { + return; + } + + int32_t colorIndex; + int32_t step_nr; + + for (uint32_t i = 0; i < Settings->light_pixels; i++) { + step_nr = i / Settings->light_step_pixels; + colorIndex = current_position - step_nr; + if (colorIndex < 0) { colorIndex = 0; } + if (colorIndex > scheme_count - 1) { colorIndex = scheme_count - 1; } + c.R = mcolor[colorIndex].red; + c.G = mcolor[colorIndex].green; + c.B = mcolor[colorIndex].blue; + // Adjust the scheme rotation + if (Settings->light_rotation & 0x02) { + strip->SetPixelColor(Settings->light_pixels - i - 1, c); + } else { + strip->SetPixelColor(i, c); + } + } + Ws2812StripShow(); +} + void Ws2812Clear(void) { strip->ClearTo(0); @@ -593,10 +686,14 @@ void Ws2812ShowScheme(void) Ws2812.show_next = 1; break; default: - if (1 == Settings->light_fade) { - Ws2812Gradient(scheme -1); - } else { - Ws2812Bars(scheme -1); + if(Settings->light_step_pixels > 0){ + Ws2812Steps(scheme -1); + } else { + if (1 == Settings->light_fade) { + Ws2812Gradient(scheme -1); + } else { + Ws2812Bars(scheme -1); + } } Ws2812.show_next = 1; break; @@ -665,6 +762,17 @@ void CmndPixels(void) ResponseCmndNumber(Settings->light_pixels); } +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(); + Light.update = true; + } + ResponseCmndNumber(Settings->light_step_pixels); +} + + void CmndRotation(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < Settings->light_pixels)) { diff --git a/tasmota/xnrg_15_teleinfo.ino b/tasmota/xnrg_15_teleinfo.ino index dc940d502..37b16084f 100755 --- a/tasmota/xnrg_15_teleinfo.ino +++ b/tasmota/xnrg_15_teleinfo.ino @@ -357,6 +357,7 @@ void DataCallback(struct _ValueList * me, uint8_t flags) Energy.import_active[0] = total/1000.0f; EnergyUpdateTotal(); + AddLog (LOG_LEVEL_INFO, PSTR ("TIC: Total counter updated to %u Wh"), total); } // Wh total index (standard) @@ -568,6 +569,9 @@ void TInfoDrvInit(void) { TasmotaGlobal.energy_driver = XNRG_15; Energy.voltage_available = false; Energy.phase_count = 1; + // init hardware energy counters + Settings->flag3.hardware_energy_total = true; + Settings->energy_kWhtotal = 0; } } diff --git a/tasmota/xnrg_19_cse7761.ino b/tasmota/xnrg_19_cse7761.ino index c61322d30..ec6647a76 100644 --- a/tasmota/xnrg_19_cse7761.ino +++ b/tasmota/xnrg_19_cse7761.ino @@ -137,7 +137,7 @@ bool Cse7761ReadOnce(uint32_t log_level, uint32_t reg, uint32_t size, uint32_t* uint8_t buffer[8] = { 0 }; uint32_t rcvd = 0; - uint32_t timeout = millis() + 3; + uint32_t timeout = millis() + 6; while (!TimeReached(timeout) && (rcvd <= size)) { // while (!TimeReached(timeout)) { diff --git a/tasmota/xsns_02_analog.ino b/tasmota/xsns_02_analog.ino index 1e69da349..c6fce4051 100644 --- a/tasmota/xsns_02_analog.ino +++ b/tasmota/xsns_02_analog.ino @@ -43,7 +43,7 @@ // Parameters for equation #define ANALOG_V33 3.3 // ESP8266 / ESP32 Analog voltage -#define ANALOG_T0 TO_KELVIN(25.0) // 25 degrees Celcius in Kelvin (= 298.15) +#define ANALOG_T0 TO_KELVIN(25.0) // 25 degrees Celsius in Kelvin (= 298.15) // Shelly 2.5 NTC Thermistor // 3V3 --- ANALOG_NTC_BRIDGE_RESISTANCE ---v--- NTC --- Gnd @@ -409,8 +409,15 @@ void AdcEverySecond(void) { for (uint32_t idx = 0; idx < Adcs.present; idx++) { if (ADC_TEMP == Adc[idx].type) { int adc = AdcRead(Adc[idx].pin, 2); - // Steinhart-Hart equation for thermistor as temperature sensor + // Steinhart-Hart equation for thermistor as temperature sensor: + // double Rt = (adc * Adc[idx].param1 * MAX_ADC_V) / (ANALOG_RANGE * ANALOG_V33 - (double)adc * MAX_ADC_V); + // MAX_ADC_V in ESP8266 is 1 + // MAX_ADC_V in ESP32 is 3.3 +#ifdef ESP8266 double Rt = (adc * Adc[idx].param1) / (ANALOG_RANGE * ANALOG_V33 - (double)adc); // Shelly param1 = 32000 (ANALOG_NTC_BRIDGE_RESISTANCE) +#else + double Rt = (adc * Adc[idx].param1) / (ANALOG_RANGE - (double)adc); +#endif double BC = (double)Adc[idx].param3 / 10000; // Shelly param3 = 3350 (ANALOG_NTC_B_COEFFICIENT) double T = BC / (BC / ANALOG_T0 + TaylorLog(Rt / (double)Adc[idx].param2)); // Shelly param2 = 10000 (ANALOG_NTC_RESISTANCE) Adc[idx].temperature = ConvertTemp(TO_CELSIUS(T)); diff --git a/tasmota/xsns_21_sgp30.ino b/tasmota/xsns_21_sgp30.ino index ff5445455..e012813cb 100644 --- a/tasmota/xsns_21_sgp30.ino +++ b/tasmota/xsns_21_sgp30.ino @@ -114,14 +114,14 @@ void Sgp30Show(bool json) { if (sgp30_ready) { char abs_hum[33]; - - if (TasmotaGlobal.global_update && (TasmotaGlobal.humidity > 0) && !isnan(TasmotaGlobal.temperature_celsius)) { + bool ahum_available = TasmotaGlobal.global_update && (TasmotaGlobal.humidity > 0) && !isnan(TasmotaGlobal.temperature_celsius); + if (ahum_available) { // has humidity + temperature dtostrfd(sgp30_abshum,4,abs_hum); } if (json) { ResponseAppend_P(PSTR(",\"SGP30\":{\"" D_JSON_ECO2 "\":%d,\"" D_JSON_TVOC "\":%d"), sgp.eCO2, sgp.TVOC); - if (TasmotaGlobal.global_update && TasmotaGlobal.humidity>0 && !isnan(TasmotaGlobal.temperature_celsius)) { + if (ahum_available) { ResponseAppend_P(PSTR(",\"" D_JSON_AHUM "\":%s"),abs_hum); } ResponseJsonEnd(); @@ -131,7 +131,7 @@ void Sgp30Show(bool json) #ifdef USE_WEBSERVER } else { WSContentSend_PD(HTTP_SNS_SGP30, sgp.eCO2, sgp.TVOC); - if (TasmotaGlobal.global_update) { + if (ahum_available) { WSContentSend_PD(HTTP_SNS_AHUM, abs_hum); } #endif diff --git a/tasmota/xsns_62_esp32_mi_ble.ino b/tasmota/xsns_62_esp32_mi_ble.ino index 973c1e604..92fdf4de0 100644 --- a/tasmota/xsns_62_esp32_mi_ble.ino +++ b/tasmota/xsns_62_esp32_mi_ble.ino @@ -1586,6 +1586,10 @@ void MI32ParseATCPacket(const uint8_t * _buf, uint32_t length, const uint8_t *ad MIBLEsensors[_slot].bat = ppv_packet->battery_level; MIBLEsensors[_slot].eventType.bat = 1; + MIBLEsensors[_slot].Btn = (ppv_packet->flags) & 0x1; // First bit is reed switch status + MIBLEsensors[_slot].eventType.Btn = 1; + MIBLEsensors[_slot].feature.Btn = 1; + if(MI32.option.directBridgeMode) { MIBLEsensors[_slot].shallSendMQTT = 1; MI32.mode.shallTriggerTele = 1; @@ -3271,4 +3275,4 @@ bool Xsns62(uint8_t function) #endif // CONFIG_IDF_TARGET_ESP32 or CONFIG_IDF_TARGET_ESP32C3 #endif // ESP32 -#endif \ No newline at end of file +#endif diff --git a/tasmota/xsns_75_prometheus.ino b/tasmota/xsns_75_prometheus.ino index caa2330fa..df9d41881 100644 --- a/tasmota/xsns_75_prometheus.ino +++ b/tasmota/xsns_75_prometheus.ino @@ -282,7 +282,7 @@ void HandleMetrics(void) { } ResponseClear(); - MqttShowSensor(); //Pull sensor data + MqttShowSensor(true); //Pull sensor data String jsonStr = ResponseData(); JsonParser parser((char *)jsonStr.c_str()); JsonParserObject root = parser.getRootObject(); diff --git a/tasmota/xsns_83_neopool.ino b/tasmota/xsns_83_neopool.ino index 18d7a7ee7..5f0e96292 100644 --- a/tasmota/xsns_83_neopool.ino +++ b/tasmota/xsns_83_neopool.ino @@ -598,7 +598,7 @@ struct { const uint16_t type; union { NeoPoolRegBlock block; - NeoPoolRegList list[]; + NeoPoolRegList *list; }; } NeoPoolReg[] = { // 6 entries so using 250ms poll interval we are through in 1,5 for all register diff --git a/tasmota/xsns_94_hdc2010.ino b/tasmota/xsns_94_hdc2010.ino new file mode 100755 index 000000000..edacc2adf --- /dev/null +++ b/tasmota/xsns_94_hdc2010.ino @@ -0,0 +1,215 @@ +/* + xsns_94_hdc2010.ino - Texas Instruments HDC1080 temperature and humidity sensor support for Tasmota + + Copyright (C) 2021 Luc Boudreau + + 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_HDC2010 + +/*********************************************************************************************\ + * HDC2010 - Temperature and Humidity sensor + * + * Source: Luc Boudreau + * Other sources: Luis Teixeira from the HDC1080 code (GPL3+) + * sSense arduino library (Public Domain) + * + * I2C Address: 0x40 +\*********************************************************************************************/ + +#define XSNS_94 94 +#define XI2C_64 64 // See I2CDEVICES.md + +#define HDC2010_ADDR 0x40 + +// Registers: + +#define HDC2010_REG_TEMP_LSB 0x00 // Temperature register LSB +#define HDC2010_REG_TEMP_MSB 0x01 // Temperature register MSB +#define HDC2010_REG_RH_LSB 0x02 // Humidity register LSB +#define HDC2010_REG_RH_MSB 0x03 // Humidity register MSB +#define HDC2010_REG_INTR_DRDY 0x04 // Interrupt / Data Ready register +#define HDC2010_REG_CONFIG 0x0F // Configuration register +#define HDC2010_REG_RESET 0x0E // Reset register +#define HDC2010_REG_MAN_LSB 0xFC // Manufacturer LSB +#define HDC2010_REG_MAN_MSB 0xFD // Manufacturer MSB +#define HDC2010_REG_DEV_LSB 0xFE // Device ID LSB +#define HDC2010_REG_DEV_MSB 0xFF // Device ID MSB + +// Note: These are bit flipped. Actual IDs need to shift byte 0 and 1 +#define HDC2010_MAN_ID 0x4954 // Manufacturer ID (Texas Instruments) +#define HDC2010_DEV_ID 0xD007 // Device ID (valid for the HDC2010) + +#define HDC2010_CONV_TIME 50 + +struct HDC2010 { + const char* hdc_type_name = "HDC2010"; + uint16_t hdc_manufacturer_id = 0; + uint16_t hdc_device_id = 0; + float hdc_temperature = 0.0; + float hdc_humidity = 0.0; + uint8_t hdc_valid = 0; +} HDC2010; + +/** + * Reads the device ID register. + */ +uint16_t Hdc2010ReadDeviceId(void) { + return I2cRead16(HDC2010_ADDR, HDC2010_REG_DEV_LSB); +} + +/** + * Reads the manufacturer ID register. + */ +uint16_t Hdc2010ReadManufacturerId(void) { + return I2cRead16(HDC2010_ADDR, HDC2010_REG_MAN_LSB); +} + +/** + * The various initialization steps for this sensor. + */ +void Hdc2010Init(void) { + Hdc2010Reset(); + Hdc2010SetMeasurementConfig(); + HDC2010.hdc_valid = 1; +} + +/** + * Performs a temp and humidity read + */ +void Hdc2010Read(void) { + uint8_t byte[2]; + uint16_t temp; + uint16_t humidity; + byte[0] = I2cRead8(HDC2010_ADDR, HDC2010_REG_TEMP_LSB); + byte[1] = I2cRead8(HDC2010_ADDR, HDC2010_REG_TEMP_MSB); + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcRead: temperature raw data: 0x%02x 0x%02x"), byte[0], byte[1]); + temp = (unsigned int)(byte[1]) << 8 | (unsigned int) byte[0]; + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcRead: temperature shifted data: %d"), temp); + HDC2010.hdc_temperature = (float)(temp) * 165 / 65536 - 40; + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcRead: temperature : %f"), hdc_temperature); + + byte[0] = I2cRead8(HDC2010_ADDR, HDC2010_REG_RH_LSB); + byte[1] = I2cRead8(HDC2010_ADDR, HDC2010_REG_RH_MSB); + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcRead: humidity raw data: 0x%02x 0x%02x"), byte[0], byte[1]); + humidity = (unsigned int)byte[1] << 8 | byte[0]; + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcRead: humidity shifted data: %d"), humidity); + HDC2010.hdc_humidity = (float)(humidity)/( 65536 )* 100; + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcRead: humidity : %f"), hdc_humidity); +} + +/** + * Performs a reset of the sensor (slow oper) + */ +void Hdc2010Reset(void) { + uint8_t current = I2cRead8(HDC2010_ADDR, HDC2010_REG_RESET); + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcReset: current reset registry value = %d"), current); + current |= 0x80; + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcReset: new reset registry value = %d"), current); + I2cWrite8(HDC2010_ADDR, HDC2010_REG_RESET, current); + delay(HDC2010_CONV_TIME); +} + +/** + * Detects the sensor + */ +bool Hdc2010Detect(void) { + if (!I2cSetDevice(HDC2010_ADDR)) { return false; } + + HDC2010.hdc_manufacturer_id = Hdc2010ReadManufacturerId(); + HDC2010.hdc_device_id = Hdc2010ReadDeviceId(); + + AddLog(LOG_LEVEL_DEBUG, PSTR("HdcDetect: detected device with manufacturerId = 0x%04X and deviceId = 0x%04X"), HDC2010.hdc_manufacturer_id, HDC2010.hdc_device_id); + + if (HDC2010.hdc_device_id == HDC2010_DEV_ID && HDC2010.hdc_manufacturer_id == HDC2010_MAN_ID) { + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcDetect: adding device HDC2010")); + Hdc2010Init(); + I2cSetActiveFound(HDC2010_ADDR, HDC2010.hdc_type_name); + return true; + } + return false; +} + +/** + * Shows the sensor in the ui + */ +void Hdc2010Show(bool json) { + if (HDC2010.hdc_valid) { + TempHumDewShow(json, (0 == TasmotaGlobal.tele_period), HDC2010.hdc_type_name, HDC2010.hdc_temperature, HDC2010.hdc_humidity); + } +} + +/** + * Configures measurement settings + */ +void Hdc2010SetMeasurementConfig() { + uint8_t resetContents = I2cRead8(HDC2010_ADDR, HDC2010_REG_RESET); + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcSetMeasureRate: current reset registry value = %d"), resetContents); + // Measure twice per second + resetContents |= 0x60; + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcSetMeasureRate: new reset registry value = %d"), resetContents); + I2cWrite8(HDC2010_ADDR, HDC2010_REG_RESET, resetContents); + + uint8_t configContents = I2cRead8(HDC2010_ADDR, HDC2010_REG_CONFIG); + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcSetMeasureRate: current config registry value = %d"), configContents); + // Measure both temp and humidity + configContents |= 0x01; + //AddLog(LOG_LEVEL_DEBUG, PSTR("HdcSetMeasureRate: new config registry value = %d"), configContents); + I2cWrite8(HDC2010_ADDR, HDC2010_REG_CONFIG, configContents); +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns94(uint8_t function) +{ + if (!I2cEnabled(XI2C_64)) { + return false; + } + + bool result = false; + + if (FUNC_INIT == function) { + result = Hdc2010Detect(); + } + else if (HDC2010.hdc_device_id) { + switch (function) { + case FUNC_EVERY_SECOND: + if (HDC2010.hdc_valid) { + Hdc2010Read(); + result = true; + } + break; + case FUNC_JSON_APPEND: + if (HDC2010.hdc_valid) { + Hdc2010Show(1); + } + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + Hdc2010Show(0); + result = true; + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_HDC2010 +#endif // USE_I2C + diff --git a/tools/decode-status.py b/tools/decode-status.py index 0fef90db9..f6d8a9b36 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -259,7 +259,7 @@ a_features = [[ "USE_BM8563","USE_ENERGY_DUMMY","USE_AM2320","USE_T67XX", "USE_MCP2515","USE_TASMESH","USE_WIFI_RANGE_EXTENDER","USE_INFLUXDB", "USE_HRG15","USE_VINDRIKTNING","USE_SCD40","USE_HM330X", - "","","","", + "USE_HDC2010","","","", "","","","", "","","","", "","","","" @@ -290,7 +290,7 @@ else: obj = json.load(fp) def StartDecode(): - print ("\n*** decode-status.py v20211008 by Theo Arends and Jacek Ziolkowski ***") + print ("\n*** decode-status.py v20211111 by Theo Arends and Jacek Ziolkowski ***") # print("Decoding\n{}".format(obj))