diff --git a/.github/workflows/validate_esphome.yml b/.github/workflows/validate_esphome.yml index ebb17bc..ede792d 100644 --- a/.github/workflows/validate_esphome.yml +++ b/.github/workflows/validate_esphome.yml @@ -1,5 +1,5 @@ --- -name: Validate ESPHome +name: Validate and Build ESPHome # yamllint disable-line rule:truthy on: @@ -28,173 +28,301 @@ on: workflow_dispatch: concurrency: - # yamllint disable-line rule:line-length group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: + setup_dependencies: + name: Setup & Cache Dependencies + runs-on: ubuntu-latest + outputs: + cache-hit-idf-v4: ${{ steps.cache-idf-v4.outputs.cache-hit }} + cache-hit-idf-v5: ${{ steps.cache-idf-v5.outputs.cache-hit }} + cache-hit-arduino: ${{ steps.cache-arduino.outputs.cache-hit }} + + steps: + - name: Checkout repository + uses: actions/checkout@main + + - name: Cache ESP-IDF v4 Dependencies + id: cache-idf-v4 + uses: actions/cache@main + with: + path: | + ~/.esphome/cache + ~/.platformio/packages + ~/.platformio/platforms + key: ${{ runner.os }}-esp-idf-v4-${{ hashFiles('**/esphome_idf_basic.yaml') }} + restore-keys: | + ${{ runner.os }}-esp-idf-v4- + + - name: Cache ESP-IDF v5 Dependencies + id: cache-idf-v5 + uses: actions/cache@main + with: + path: | + ~/.esphome/cache + ~/.platformio/packages + ~/.platformio/platforms + key: ${{ runner.os }}-esp-idf-v5-${{ hashFiles('**/esphome_idf5_basic.yaml') }} + restore-keys: | + ${{ runner.os }}-esp-idf-v5- + + - name: Cache Arduino Dependencies + id: cache-arduino + uses: actions/cache@main + with: + path: | + ~/.esphome/cache + ~/.platformio/packages + ~/.platformio/platforms + key: ${{ runner.os }}-arduino-${{ hashFiles('**/esphome_ard_basic.yaml') }} + restore-keys: | + ${{ runner.os }}-arduino- + code_scan: name: Code scan (YAML) runs-on: "ubuntu-latest" + needs: setup_dependencies steps: - - uses: actions/checkout@main - with: - fetch-depth: '0' - - name: Validate nspanel_esphome.yaml - run: yamllint -c "./.rules/yamllint.yml" nspanel_esphome.yaml - - name: Validate nspanel_esphome_core.yaml - run: yamllint -c "./.rules/yamllint.yml" esphome/nspanel_esphome_core.yaml - - name: Validate nspanel_esphome_addon_climate_cool.yaml - run: yamllint -c "./.rules/yamllint.yml" nspanel_esphome_addon_climate_cool.yaml - - name: Validate nspanel_esphome_addon_climate_heat.yaml - run: yamllint -c "./.rules/yamllint.yml" nspanel_esphome_addon_climate_heat.yaml - - name: Validate nspanel_esphome_addon_climate_dual.yaml - run: yamllint -c "./.rules/yamllint.yml" nspanel_esphome_addon_climate_dual.yaml - - name: Validate nspanel_esphome_addon_upload_tft.yaml - run: yamllint -c "./.rules/yamllint.yml" esphome/nspanel_esphome_addon_upload_tft.yaml - - name: Validate nspanel_esphome_advanced.yaml - run: yamllint -c "./.rules/yamllint.yml" esphome/nspanel_esphome_advanced.yaml - - name: Validate nspanel_esphome_addon_climate_base.yaml - run: yamllint -c "./.rules/yamllint.yml" esphome/nspanel_esphome_addon_climate_base.yaml - - name: Validate nspanel_esphome_addon_climate_cool.yaml - run: yamllint -c "./.rules/yamllint.yml" esphome/nspanel_esphome_addon_climate_cool.yaml - - name: Validate nspanel_esphome_addon_climate_heat.yaml - run: yamllint -c "./.rules/yamllint.yml" esphome/nspanel_esphome_addon_climate_heat.yaml - - name: Validate nspanel_esphome_addon_climate_dual.yaml - run: yamllint -c "./.rules/yamllint.yml" esphome/nspanel_esphome_addon_climate_dual.yaml - - name: Validate nspanel_esphome_prebuilt.yaml - run: yamllint -c "./.rules/yamllint.yml" prebuilt/nspanel_esphome_prebuilt.yaml - - name: Validate wall_display.yaml - run: yamllint -c "./.rules/yamllint.yml" prebuilt/wall_display.yaml + - name: Checkout Code + uses: actions/checkout@main - build_core: - name: Core - runs-on: "ubuntu-latest" - needs: - - code_scan - steps: - - uses: actions/checkout@main + - name: Setup Python + uses: actions/setup-python@main with: - fetch-depth: '0' - - name: Build core + python-version: '3.8' + + - name: Install Yamllint + run: pip install yamllint + + - name: Validate YAML files + run: find . -name "*.yaml" -exec yamllint -c ./.rules/yamllint.yml {} + + + build_cores: + name: Core + needs: [code_scan, setup_dependencies] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - id: idf_v4 + yaml_file: ".test/esphome_idf_basic.yaml" + cache-hit: ${{ needs.setup_dependencies.outputs.cache-hit-idf-v4 }} + - id: idf_v5 + yaml_file: ".test/esphome_idf5_basic.yaml" + cache-hit: ${{ needs.setup_dependencies.outputs.cache-hit-idf-v5 }} + - id: ard + yaml_file: ".test/esphome_ard_basic.yaml" + cache-hit: ${{ needs.setup_dependencies.outputs.cache-hit-arduino }} + + steps: + - name: Checkout repository + uses: actions/checkout@main + + - name: Firmware + if: steps.matrix.outputs.cache-hit != 'true' uses: barndawgie/build-action@v1.9.0 with: - yaml_file: "./.test/esphome_basic.yaml" + yaml_file: ${{ matrix.yaml_file }} build_advanced: name: Advanced - runs-on: "ubuntu-latest" - needs: - - build_core - steps: - - uses: actions/checkout@main - with: - fetch-depth: '0' - - name: Build core+advanced - uses: barndawgie/build-action@v1.9.0 - with: - yaml_file: "./.test/esphome_advanced.yaml" + needs: build_cores + runs-on: ubuntu-latest + strategy: + matrix: + include: + - id: idf_v4 + base: idf_v4 + yaml_file: ".test/esphome_idf_advanced.yaml" + - id: idf_v5 + base: idf_v5 + yaml_file: ".test/esphome_idf5_advanced.yaml" + - id: ard + base: ard + yaml_file: ".test/esphome_ard_advanced.yaml" - build_climate_heat: - name: Climate (heat) - runs-on: "ubuntu-latest" - needs: - - build_core steps: - - uses: actions/checkout@main - with: - fetch-depth: '0' - - name: Build core+climate_heat + - name: Checkout repository + uses: actions/checkout@main + + - name: Build Advanced Firmware uses: barndawgie/build-action@v1.9.0 with: - yaml_file: "./.test/esphome_climate_heat.yaml" + yaml_file: ${{ matrix.yaml_file }} + + build_ble_tracker: + name: BLE Tracker + needs: build_cores + runs-on: ubuntu-latest + strategy: + matrix: + include: + - id: idf_v4 + base: idf_v4 + yaml_file: ".test/esphome_idf_ble_tracker.yaml" + - id: idf_v5 + base: idf_v5 + yaml_file: ".test/esphome_idf5_ble_tracker.yaml" + + steps: + - name: Checkout repository + uses: actions/checkout@main + + - name: Build BLE Tracker Firmware + uses: barndawgie/build-action@v1.9.0 + with: + yaml_file: ${{ matrix.yaml_file }} + + build_bluetooth_proxy: + name: Bluetooth Proxy + needs: build_cores + runs-on: ubuntu-latest + strategy: + matrix: + include: + - id: idf_v4 + base: idf_v4 + yaml_file: ".test/esphome_idf_bluetooth_proxy.yaml" + - id: idf_v5 + base: idf_v5 + yaml_file: ".test/esphome_idf5_bluetooth_proxy.yaml" + + steps: + - name: Checkout repository + uses: actions/checkout@main + + - name: Build Bluetooth Proxy Firmware + uses: barndawgie/build-action@v1.9.0 + with: + yaml_file: ${{ matrix.yaml_file }} build_climate_cool: - name: Climate (cool) - runs-on: "ubuntu-latest" - needs: - - build_core + name: Climate Cool + needs: build_cores + runs-on: ubuntu-latest + strategy: + matrix: + include: + - id: idf_v4 + base: idf_v4 + yaml_file: ".test/esphome_idf_climate_cool.yaml" + - id: idf_v5 + base: idf_v5 + yaml_file: ".test/esphome_idf5_climate_cool.yaml" + - id: ard + base: ard + yaml_file: ".test/esphome_ard_climate_cool.yaml" + steps: - - uses: actions/checkout@main - with: - fetch-depth: '0' - - name: Build core+climate_cool + - name: Checkout repository + uses: actions/checkout@main + + - name: Build Climate Cool Firmware uses: barndawgie/build-action@v1.9.0 with: - yaml_file: "./.test/esphome_climate_cool.yaml" + yaml_file: ${{ matrix.yaml_file }} + + build_climate_heat: + name: Climate Heat + needs: build_cores + runs-on: ubuntu-latest + strategy: + matrix: + include: + - id: idf_v4 + base: idf_v4 + yaml_file: ".test/esphome_idf_climate_heat.yaml" + - id: idf_v5 + base: idf_v5 + yaml_file: ".test/esphome_idf5_climate_heat.yaml" + - id: ard + base: ard + yaml_file: ".test/esphome_ard_climate_heat.yaml" + + steps: + - name: Checkout repository + uses: actions/checkout@main + + - name: Build Climate Heat Firmware + uses: barndawgie/build-action@v1.9.0 + with: + yaml_file: ${{ matrix.yaml_file }} build_climate_dual: - name: Climate (dual) - runs-on: "ubuntu-latest" - needs: - - build_core + name: Climate Dual + needs: build_cores + runs-on: ubuntu-latest + strategy: + matrix: + include: + - id: idf_v4 + base: idf_v4 + yaml_file: ".test/esphome_idf_climate_dual.yaml" + - id: idf_v5 + base: idf_v5 + yaml_file: ".test/esphome_idf5_climate_dual.yaml" + - id: ard + base: ard + yaml_file: ".test/esphome_ard_climate_dual.yaml" + steps: - - uses: actions/checkout@main - with: - fetch-depth: '0' - - name: Build core+climate_dual + - name: Checkout repository + uses: actions/checkout@main + + - name: Build Climate Dial Firmware uses: barndawgie/build-action@v1.9.0 with: - yaml_file: "./.test/esphome_climate_dual.yaml" + yaml_file: ${{ matrix.yaml_file }} - build_climate_heat_advanced: - name: Advanced+climate (heat) - runs-on: "ubuntu-latest" + build_customizations: + name: Customizations needs: - - build_climate_heat - build_advanced + - build_climate_heat + runs-on: ubuntu-latest + strategy: + matrix: + include: + - id: idf_v4 + base: idf_v4 + yaml_file: ".test/esphome_idf_advanced_climate_heat_customizations.yaml" + - id: ard + base: ard + yaml_file: ".test/esphome_ard_advanced_climate_heat_customizations.yaml" + steps: - - uses: actions/checkout@main - with: - fetch-depth: '0' - - name: Build core+advanced+climate_heat + - name: Checkout repository + uses: actions/checkout@main + + - name: Build Customizations Firmware uses: barndawgie/build-action@v1.9.0 with: - yaml_file: "./.test/esphome_advanced_climate_heat.yaml" + yaml_file: ${{ matrix.yaml_file }} - build_climate_cool_advanced_arduino: - name: Arduino - runs-on: "ubuntu-latest" + build_climate_ble_proxy: + name: Climate Cool + Bluetooth Proxy needs: - build_climate_cool - - build_advanced - steps: - - uses: actions/checkout@main - with: - fetch-depth: '0' - - name: Build core+advanced+climate_cool+arduino - uses: barndawgie/build-action@v1.9.0 - with: - yaml_file: "./.test/esphome_advanced_climate_cool_arduino.yaml" + - build_bluetooth_proxy + runs-on: ubuntu-latest + strategy: + matrix: + include: + - id: idf_v4 + base: idf_v4 + yaml_file: ".test/esphome_idf_climate_cool_bluetooth_proxy.yaml" - build_climate_dual_esp_idf5: - name: esp-idf v5 & Climate Dual & Bluetooth proxy - runs-on: "ubuntu-latest" - needs: - - build_advanced - - build_climate_dual steps: - - uses: actions/checkout@main - with: - fetch-depth: '0' - - name: Build core+climate_dual+bt_proxy+esp_idf5 - uses: barndawgie/build-action@v1.9.0 - with: - yaml_file: "./.test/esphome_advanced_climate_dual_esp_idf5.yaml" + - name: Checkout repository + uses: actions/checkout@main - build_climate_heat_advanced_customization: - name: Customizations - runs-on: "ubuntu-latest" - needs: - - code_scan - steps: - - uses: actions/checkout@main - with: - fetch-depth: '0' - - name: Build core+advanced+climate_heat+customizations + - name: Build Customizations Firmware uses: barndawgie/build-action@v1.9.0 with: - yaml_file: "./.test/esphome_advanced_climate_heat_customizations.yaml" + yaml_file: ${{ matrix.yaml_file }} build_prebuilt_firmware: name: Prebuilt Firmware @@ -203,8 +331,6 @@ jobs: if: github.ref == 'refs/heads/dev' || github.base_ref == 'dev' steps: - uses: actions/checkout@main - with: - fetch-depth: '0' - name: Build ESPHome Prebuilt Firmware uses: barndawgie/build-action@v1.9.0 @@ -228,68 +354,20 @@ jobs: cp prebuilt/.esphome/build/nspanel/.pioenvs/nspanel/firmware.bin prebuilt/wall_display.bin || true cp prebuilt/.esphome/build/nspanel/.pioenvs/nspanel/firmware-factory.bin prebuilt/wall_display-factory.bin || true - - name: Generate checksum nspanel_esphome_prebuilt - uses: jmgilman/actions-generate-checksum@v1 - with: - method: md5 - patterns: prebuilt/nspanel_esphome_prebuilt.bin - output: prebuilt/nspanel_esphome_prebuilt.bin.md5 - - - name: Generate checksum nspanel_esphome_prebuilt-factory - uses: jmgilman/actions-generate-checksum@v1 - with: - method: md5 - patterns: prebuilt/nspanel_esphome_prebuilt-factory.bin - output: prebuilt/nspanel_esphome_prebuilt-factory.bin.md5 - - - name: Generate checksum wall_display - uses: jmgilman/actions-generate-checksum@v1 - with: - method: md5 - patterns: prebuilt/wall_display.bin - output: prebuilt/wall_display.bin.md5 - - - name: Generate checksum wall_display-factory - uses: jmgilman/actions-generate-checksum@v1 - with: - method: md5 - patterns: prebuilt/wall_display-factory.bin - output: prebuilt/wall_display-factory.bin.md5 - - - name: Set Commit Message - id: set_commit_message + - name: Generate checksum for Firmware Files run: | - if [[ "${{ github.event_name }}" == "pull_request" ]]; then - echo "COMMIT_MESSAGE=Pre-built firmware for NSPanel - ${{ github.event.pull_request.title }}" >> $GITHUB_ENV - elif [[ "${{ github.event_name }}" == "push" ]]; then - commit_message=$(git log -1 --pretty=format:'%s') - echo "COMMIT_MESSAGE=Pre-built firmware for NSPanel - $commit_message" >> $GITHUB_ENV - else - echo "COMMIT_MESSAGE=Pre-built firmware for NSPanel" >> $GITHUB_ENV - fi + md5sum prebuilt/nspanel_esphome_prebuilt.bin > prebuilt/nspanel_esphome_prebuilt.bin.md5 + md5sum prebuilt/nspanel_esphome_prebuilt-factory.bin > prebuilt/nspanel_esphome_prebuilt-factory.bin.md5 + md5sum prebuilt/wall_display.bin > prebuilt/wall_display.bin.md5 + md5sum prebuilt/wall_display-factory.bin > prebuilt/wall_display-factory.bin.md5 - name: Commit and Push Firmware Files run: | git config --global user.name 'GitHub Actions' git config --global user.email 'actions@github.com' - git add prebuilt/*.bin - git add prebuilt/*.md5 - git commit -m "${{ env.COMMIT_MESSAGE }}" + git add prebuilt/*.bin prebuilt/*.md5 + git commit -m "Pre-built firmware update: ${{ github.run_id }}" git push env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - build_climate_cool_bluetooth_proxy: - name: Climate cool & BLE proxy - runs-on: "ubuntu-latest" - needs: - - build_climate_cool - steps: - - uses: actions/checkout@main - with: - fetch-depth: '0' - - name: Build core+climate_cool+bluetooth_proxy - uses: barndawgie/build-action@v1.9.0 - with: - yaml_file: "./.test/esphome_climate_cool_bluetooth_proxy.yaml" ... diff --git a/.test/esphome_advanced.yaml b/.test/esphome_ard_advanced.yaml similarity index 57% rename from .test/esphome_advanced.yaml rename to .test/esphome_ard_advanced.yaml index 829bb40..3c1acde 100644 --- a/.test/esphome_advanced.yaml +++ b/.test/esphome_ard_advanced.yaml @@ -8,7 +8,8 @@ substitutions: packages: basic_package: !include ../nspanel_esphome.yaml # Core package advanced_package: !include ../esphome/nspanel_esphome_advanced.yaml - # addon_climate_heat: !include ../esphome/nspanel_esphome_addon_climate_heat.yaml - # addon_climate_cool: !include ../esphome/nspanel_esphome_addon_climate_cool.yaml - # addon_climate_dual: !include ../esphome/nspanel_esphome_addon_climate_dual.yaml + +esp32: + framework: + type: arduino ... diff --git a/.test/esphome_ard_advanced_climate_heat_customizations.yaml b/.test/esphome_ard_advanced_climate_heat_customizations.yaml new file mode 100644 index 0000000..2ac8f0d --- /dev/null +++ b/.test/esphome_ard_advanced_climate_heat_customizations.yaml @@ -0,0 +1,240 @@ +--- +substitutions: + device_name: nspanel + wifi_ssid: "nspanel" + wifi_password: "NSPanel_HA_Blueprint" + nextion_blank_url: "http://homeassistant.local:8123/local/nspanel_blank.tft" + +packages: + basic_package: !include ../nspanel_esphome.yaml # Core package + advanced_package: !include ../esphome/nspanel_esphome_advanced.yaml + addon_climate_heat: !include ../esphome/nspanel_esphome_addon_climate_heat.yaml + +esp32: + framework: + type: arduino + +##### Customizations from Wiki ##### +api: + # Encrypt the communication between ESPHome and Home Assistant + encryption: + key: !secret api_encryption_key + # Reboot if HA is not connected for 15 minutes + reboot_timeout: 15min + +binary_sensor: + # Is display awake? + - name: ${device_name} Display state + id: display_state + platform: template + lambda: |- + return (current_page->state != "screensaver"); + +button: + # Adds a button to put the panel to sleep + - name: ${device_name} Sleep + id: force_sleep + platform: template + icon: mdi:sleep + on_press: + then: + - logger.log: Button Sleep pressed + - lambda: |- + goto_page->execute("screensaver"); + + # Adds a button to wake-up the panel (similar to the existing service) + - name: ${device_name} Wake-up + id: force_wake_up + platform: template + icon: mdi:alarm + on_press: + then: + - logger.log: Button Wake-up pressed + - lambda: |- + if (current_page->state == "screensaver") id(disp1).goto_page(id(wakeup_page_name).state.c_str()); + // timer_page->execute(); // enable this if you want page timeout to be reset + timer_sleep->execute(); + timer_dim->execute(); + +# Add custom presets to your climate (heat in this example) +climate: + - id: !extend thermostat_embedded + heat_deadband: 0.3 + heat_overrun: 0.0 + default_preset: "Home" + preset: + - name: "Off" + default_target_temperature_low: ${temp_min} ${temp_units} + mode: "off" + - name: Home + default_target_temperature_low: 21 ${temp_units} + mode: "heat" + - name: Away + default_target_temperature_low: 16.5 ${temp_units} + mode: "heat" + - name: Sleep + default_target_temperature_low: 17.5 ${temp_units} + mode: "heat" + +esphome: + # change OTA password, remove after flashing + on_boot: + - priority: 601.0 + then: + - lambda: |- + id(my_ota).set_auth_password("New password"); + # Limit the amount of resources used for compiling + compile_process_limit: 1 + +light: + # Add the display as a light in Home Assistant + - name: ${device_name} Display + id: display_light + icon: mdi:tablet-dashboard + platform: monochromatic + output: display_output + default_transition_length: 0s + on_turn_on: + then: + - lambda: |- + ESP_LOGD("light.display_light", "Turn-on"); + if (current_page->state == "screensaver") disp1->goto_page(wakeup_page_name->state.c_str()); + timer_reset_all->execute(); + on_turn_off: + then: + - lambda: |- + ESP_LOGD("light.display_light", "Turn-off"); + goto_page->execute("screensaver"); + +logger: + # Enable hardware UART serial logging + baud_rate: 115200 + +ota: + # change OTA password, remove after flashing + password: !secret wifi_password + id: my_ota + +output: + # Output required by `display_light` to send the commands to Nextion + - id: display_output + platform: template + type: float + write_action: + - lambda: |- + ESP_LOGV("output.display_output", "state: %f", state); + uint8_t current_brightness = int(round(display_light->current_values.is_on() ? (display_light->current_values.get_brightness() * 100.0f) : 0.0)); + ESP_LOGV("output.display_output", "current_brightness: %i%%", current_brightness); + set_brightness->execute(current_brightness); + +script: + # Updates the existing `page_changed` script to update the `display_light` status when a page changes + - id: !extend page_changed + then: + - lambda: |- + ESP_LOGD("script.page_changed(custom)", "page: %s", current_page->state.c_str()); + ESP_LOGV("script.page_changed(custom)", "is_on(): %s", display_light->current_values.is_on() ? "True" : "False"); + if (current_page->state == "screensaver" and display_light->current_values.is_on()) { + auto call = display_light->turn_off(); + call.perform(); + } else if (current_page->state != "screensaver" and (not display_light->current_values.is_on())) { + auto call = display_light->turn_on(); + call.perform(); + } + + # Updates the existing `set_brightness` script to update the `display_light` status when a new brightness level is set + - id: !extend set_brightness + then: + - lambda: |- + ESP_LOGD("script.set_brightness(custom)", "brightness: %.0f%%", brightness); + uint8_t current_light_brightness = int(round(display_light->current_values.is_on() ? (display_light->current_values.get_brightness() * 100.0f) : 0.0)); + ESP_LOGV("script.set_brightness(custom)", "current_light_brightness: %i%%", current_light_brightness); + if (brightness != current_light_brightness) { + if (current_page->state != "screensaver" and brightness > 0) { + auto call = display_light->turn_on(); + call.set_brightness(current_brightness->state / 100.0f); + call.perform(); + } else if (display_light->current_values.is_on()) { + auto call = display_light->turn_off(); + call.set_brightness(0); + call.perform(); + } + } + +time: + - id: !extend time_provider + timezone: "America/Cancun" + # Use my own local network time server + platform: sntp + servers: + - !secret mysntpserver + - europe.pool.ntp.org + - 0.pool.ntp.org + # Scheduled relay + on_time: + - hours: 7 + minutes: 30 + seconds: 0 + then: + - switch.turn_on: relay_1 + - hours: 12 + minutes: 15 + seconds: 0 + then: + - switch.turn_off: relay_1 + - hours: 19 + minutes: 30 + seconds: 0 + then: + - switch.turn_on: relay_1 + - hours: 23 + minutes: 30 + seconds: 0 + then: + - switch.turn_off: relay_1 + # Scheduled climate + - hours: 7 + minutes: 0 + seconds: 0 + then: + - climate.control: + id: thermostat_embedded + mode: auto + target_temperature: 22°C + - hours: 19 + minutes: 0 + seconds: 0 + then: + - climate.control: + id: thermostat_embedded + mode: auto + target_temperature: 20°C + - hours: 23 + minutes: 0 + seconds: 0 + then: + - climate.control: + id: thermostat_embedded + mode: auto + target_temperature: 18°C + +web_server: + # Custom web server credentials + auth: + username: !secret web_server_username + password: !secret web_server_password + +wifi: + networks: + - id: !extend wifi_default + # Set IP address manually + manual_ip: + static_ip: 192.168.0.123 + gateway: 192.168.0.1 + subnet: 255.255.255.0 + # Set dual network + priority: 10 + - ssid: !secret wifi_ssid_backup + password: !secret wifi_password_backup + priority: 0 +... diff --git a/.test/esphome_ard_basic.yaml b/.test/esphome_ard_basic.yaml new file mode 100644 index 0000000..4b1e883 --- /dev/null +++ b/.test/esphome_ard_basic.yaml @@ -0,0 +1,14 @@ +--- +substitutions: + device_name: nspanel + wifi_ssid: "nspanel" + wifi_password: "NSPanel_HA_Blueprint" + nextion_update_url: "https://github.com/Blackymas/NSPanel_HA_Blueprint/dummy" + +packages: + basic_package: !include ../nspanel_esphome.yaml # Basic package + +esp32: + framework: + type: arduino +... diff --git a/.test/esphome_advanced_climate_cool_arduino.yaml b/.test/esphome_ard_climate_cool.yaml similarity index 61% rename from .test/esphome_advanced_climate_cool_arduino.yaml rename to .test/esphome_ard_climate_cool.yaml index a440d88..a11a441 100644 --- a/.test/esphome_advanced_climate_cool_arduino.yaml +++ b/.test/esphome_ard_climate_cool.yaml @@ -7,10 +7,7 @@ substitutions: packages: basic_package: !include ../nspanel_esphome.yaml # Core package - advanced_package: !include ../esphome/nspanel_esphome_advanced.yaml - # addon_climate_heat: !include ../esphome/nspanel_esphome_addon_climate_heat.yaml addon_climate_cool: !include ../esphome/nspanel_esphome_addon_climate_cool.yaml - # addon_climate_dual: !include ../esphome/nspanel_esphome_addon_climate_dual.yaml esp32: framework: diff --git a/.test/esphome_climate_dual.yaml b/.test/esphome_ard_climate_dual.yaml similarity index 59% rename from .test/esphome_climate_dual.yaml rename to .test/esphome_ard_climate_dual.yaml index 4dfff72..e68b280 100644 --- a/.test/esphome_climate_dual.yaml +++ b/.test/esphome_ard_climate_dual.yaml @@ -7,8 +7,9 @@ substitutions: packages: basic_package: !include ../nspanel_esphome.yaml # Core package - # advanced_package: !include ../esphome/nspanel_esphome_advanced.yaml - # addon_climate_heat: !include ../esphome/nspanel_esphome_addon_climate_heat.yaml - # addon_climate_cool: !include ../esphome/nspanel_esphome_addon_climate_cool.yaml addon_climate_dual: !include ../esphome/nspanel_esphome_addon_climate_dual.yaml + +esp32: + framework: + type: arduino ... diff --git a/.test/esphome_climate_heat.yaml b/.test/esphome_ard_climate_heat.yaml similarity index 59% rename from .test/esphome_climate_heat.yaml rename to .test/esphome_ard_climate_heat.yaml index 8767891..bd118c4 100644 --- a/.test/esphome_climate_heat.yaml +++ b/.test/esphome_ard_climate_heat.yaml @@ -7,8 +7,9 @@ substitutions: packages: basic_package: !include ../nspanel_esphome.yaml # Core package - # advanced_package: !include ../esphome/nspanel_esphome_advanced.yaml addon_climate_heat: !include ../esphome/nspanel_esphome_addon_climate_heat.yaml - # addon_climate_cool: !include ../esphome/nspanel_esphome_addon_climate_cool.yaml - # addon_climate_dual: !include ../esphome/nspanel_esphome_addon_climate_dual.yaml + +esp32: + framework: + type: arduino ... diff --git a/.test/esphome_basic.yaml b/.test/esphome_basic.yaml deleted file mode 100644 index 85cbb1a..0000000 --- a/.test/esphome_basic.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -substitutions: - device_name: nspanel - wifi_ssid: "nspanel" - wifi_password: "NSPanel_HA_Blueprint" - nextion_update_url: "https://github.com/Blackymas/NSPanel_HA_Blueprint/dummy" - -packages: - basic_package: !include ../nspanel_esphome.yaml # Basic package - # advanced_package: !include ../esphome/nspanel_esphome_advanced.yaml - # addon_climate_heat: !include ../esphome/nspanel_esphome_addon_climate_heat.yaml - # addon_climate_cool: !include ../esphome/nspanel_esphome_addon_climate_cool.yaml - # addon_climate_dual: !include ../esphome/nspanel_esphome_addon_climate_dual.yaml -... diff --git a/.test/esphome_idf5_advanced.yaml b/.test/esphome_idf5_advanced.yaml new file mode 100644 index 0000000..68e8150 --- /dev/null +++ b/.test/esphome_idf5_advanced.yaml @@ -0,0 +1,17 @@ +--- +substitutions: + device_name: nspanel + wifi_ssid: "nspanel" + wifi_password: "NSPanel_HA_Blueprint" + nextion_update_url: "https://github.com/Blackymas/NSPanel_HA_Blueprint/dummy" + +packages: + basic_package: !include ../nspanel_esphome.yaml # Core package + advanced_package: !include ../esphome/nspanel_esphome_advanced.yaml + +esp32: + framework: + type: esp-idf + version: 5.0.2 + platform_version: 6.3.2 +... diff --git a/.test/esphome_idf5_basic.yaml b/.test/esphome_idf5_basic.yaml new file mode 100644 index 0000000..ada9acc --- /dev/null +++ b/.test/esphome_idf5_basic.yaml @@ -0,0 +1,16 @@ +--- +substitutions: + device_name: nspanel + wifi_ssid: "nspanel" + wifi_password: "NSPanel_HA_Blueprint" + nextion_update_url: "https://github.com/Blackymas/NSPanel_HA_Blueprint/dummy" + +packages: + basic_package: !include ../nspanel_esphome.yaml # Basic package + +esp32: + framework: + type: esp-idf + version: 5.0.2 + platform_version: 6.3.2 +... diff --git a/.test/esphome_idf5_ble_tracker.yaml b/.test/esphome_idf5_ble_tracker.yaml new file mode 100644 index 0000000..5da0690 --- /dev/null +++ b/.test/esphome_idf5_ble_tracker.yaml @@ -0,0 +1,17 @@ +--- +substitutions: + device_name: nspanel + wifi_ssid: "nspanel" + wifi_password: "NSPanel_HA_Blueprint" + nextion_update_url: "https://github.com/Blackymas/NSPanel_HA_Blueprint/dummy" + +packages: + basic_package: !include ../nspanel_esphome.yaml # Core package + addon_ble_tracker: !include ../esphome/nspanel_esphome_addon_ble_tracker.yaml + +esp32: + framework: + type: esp-idf + version: 5.0.2 + platform_version: 6.3.2 +... diff --git a/.test/esphome_idf5_bluetooth_proxy.yaml b/.test/esphome_idf5_bluetooth_proxy.yaml new file mode 100644 index 0000000..545df9f --- /dev/null +++ b/.test/esphome_idf5_bluetooth_proxy.yaml @@ -0,0 +1,17 @@ +--- +substitutions: + device_name: nspanel + wifi_ssid: "nspanel" + wifi_password: "NSPanel_HA_Blueprint" + nextion_update_url: "https://github.com/Blackymas/NSPanel_HA_Blueprint/dummy" + +packages: + basic_package: !include ../nspanel_esphome.yaml # Core package + addon_bluetooth_proxy: !include ../esphome/nspanel_esphome_addon_bluetooth_proxy.yaml + +esp32: + framework: + type: esp-idf + version: 5.0.2 + platform_version: 6.3.2 +... diff --git a/.test/esphome_climate_cool.yaml b/.test/esphome_idf5_climate_cool.yaml similarity index 59% rename from .test/esphome_climate_cool.yaml rename to .test/esphome_idf5_climate_cool.yaml index da2b486..440379d 100644 --- a/.test/esphome_climate_cool.yaml +++ b/.test/esphome_idf5_climate_cool.yaml @@ -7,8 +7,11 @@ substitutions: packages: basic_package: !include ../nspanel_esphome.yaml # Core package - # advanced_package: !include ../esphome/nspanel_esphome_advanced.yaml - # addon_climate_heat: !include ../esphome/nspanel_esphome_addon_climate_heat.yaml addon_climate_cool: !include ../esphome/nspanel_esphome_addon_climate_cool.yaml - # addon_climate_dual: !include ../esphome/nspanel_esphome_addon_climate_dual.yaml + +esp32: + framework: + type: esp-idf + version: 5.0.2 + platform_version: 6.3.2 ... diff --git a/.test/esphome_advanced_climate_dual_esp_idf5.yaml b/.test/esphome_idf5_climate_dual.yaml similarity index 54% rename from .test/esphome_advanced_climate_dual_esp_idf5.yaml rename to .test/esphome_idf5_climate_dual.yaml index 3502aa0..6dd7dfd 100644 --- a/.test/esphome_advanced_climate_dual_esp_idf5.yaml +++ b/.test/esphome_idf5_climate_dual.yaml @@ -7,9 +7,6 @@ substitutions: packages: basic_package: !include ../nspanel_esphome.yaml # Core package - # advanced_package: !include ../esphome/nspanel_esphome_advanced.yaml - # addon_climate_heat: !include ../esphome/nspanel_esphome_addon_climate_heat.yaml - # addon_climate_cool: !include ../esphome/nspanel_esphome_addon_climate_cool.yaml addon_climate_dual: !include ../esphome/nspanel_esphome_addon_climate_dual.yaml esp32: @@ -17,10 +14,4 @@ esp32: type: esp-idf version: 5.0.2 platform_version: 6.3.2 - -bluetooth_proxy: - -# Set Wi-Fi power save mode to "LIGHT" as required for Bluetooth on ESP32 -wifi: - power_save_mode: LIGHT ... diff --git a/.test/esphome_idf5_climate_heat.yaml b/.test/esphome_idf5_climate_heat.yaml new file mode 100644 index 0000000..1d3e3a0 --- /dev/null +++ b/.test/esphome_idf5_climate_heat.yaml @@ -0,0 +1,17 @@ +--- +substitutions: + device_name: nspanel + wifi_ssid: "nspanel" + wifi_password: "NSPanel_HA_Blueprint" + nextion_update_url: "https://github.com/Blackymas/NSPanel_HA_Blueprint/dummy" + +packages: + basic_package: !include ../nspanel_esphome.yaml # Core package + addon_climate_heat: !include ../esphome/nspanel_esphome_addon_climate_heat.yaml + +esp32: + framework: + type: esp-idf + version: 5.0.2 + platform_version: 6.3.2 +... diff --git a/.test/esphome_idf_advanced.yaml b/.test/esphome_idf_advanced.yaml new file mode 100644 index 0000000..b702954 --- /dev/null +++ b/.test/esphome_idf_advanced.yaml @@ -0,0 +1,11 @@ +--- +substitutions: + device_name: nspanel + wifi_ssid: "nspanel" + wifi_password: "NSPanel_HA_Blueprint" + nextion_update_url: "https://github.com/Blackymas/NSPanel_HA_Blueprint/dummy" + +packages: + basic_package: !include ../nspanel_esphome.yaml # Core package + advanced_package: !include ../esphome/nspanel_esphome_advanced.yaml +... diff --git a/.test/esphome_advanced_climate_heat.yaml b/.test/esphome_idf_advanced_climate_heat.yaml similarity index 100% rename from .test/esphome_advanced_climate_heat.yaml rename to .test/esphome_idf_advanced_climate_heat.yaml diff --git a/.test/esphome_advanced_climate_heat_customizations.yaml b/.test/esphome_idf_advanced_climate_heat_customizations.yaml similarity index 100% rename from .test/esphome_advanced_climate_heat_customizations.yaml rename to .test/esphome_idf_advanced_climate_heat_customizations.yaml index 2588ac8..02499e2 100644 --- a/.test/esphome_advanced_climate_heat_customizations.yaml +++ b/.test/esphome_idf_advanced_climate_heat_customizations.yaml @@ -168,8 +168,8 @@ time: - !secret mysntpserver - europe.pool.ntp.org - 0.pool.ntp.org - on_time: # Scheduled relay + on_time: - hours: 7 minutes: 30 seconds: 0 diff --git a/.test/esphome_idf_basic.yaml b/.test/esphome_idf_basic.yaml new file mode 100644 index 0000000..47a57c5 --- /dev/null +++ b/.test/esphome_idf_basic.yaml @@ -0,0 +1,10 @@ +--- +substitutions: + device_name: nspanel + wifi_ssid: "nspanel" + wifi_password: "NSPanel_HA_Blueprint" + nextion_update_url: "https://github.com/Blackymas/NSPanel_HA_Blueprint/dummy" + +packages: + basic_package: !include ../nspanel_esphome.yaml # Basic package +... diff --git a/.test/esphome_idf_ble_tracker.yaml b/.test/esphome_idf_ble_tracker.yaml new file mode 100644 index 0000000..63130fb --- /dev/null +++ b/.test/esphome_idf_ble_tracker.yaml @@ -0,0 +1,11 @@ +--- +substitutions: + device_name: nspanel + wifi_ssid: "nspanel" + wifi_password: "NSPanel_HA_Blueprint" + nextion_update_url: "https://github.com/Blackymas/NSPanel_HA_Blueprint/dummy" + +packages: + basic_package: !include ../nspanel_esphome.yaml # Core package + addon_ble_tracker: !include ../esphome/nspanel_esphome_addon_ble_tracker.yaml +... diff --git a/.test/esphome_idf_bluetooth_proxy.yaml b/.test/esphome_idf_bluetooth_proxy.yaml new file mode 100644 index 0000000..8367b63 --- /dev/null +++ b/.test/esphome_idf_bluetooth_proxy.yaml @@ -0,0 +1,11 @@ +--- +substitutions: + device_name: nspanel + wifi_ssid: "nspanel" + wifi_password: "NSPanel_HA_Blueprint" + nextion_update_url: "https://github.com/Blackymas/NSPanel_HA_Blueprint/dummy" + +packages: + basic_package: !include ../nspanel_esphome.yaml # Core package + addon_bluetooth_proxy: !include ../esphome/nspanel_esphome_addon_bluetooth_proxy.yaml +... diff --git a/.test/esphome_climate_cool_bluetooth_proxy.yaml b/.test/esphome_idf_climate_cool.yaml similarity index 57% rename from .test/esphome_climate_cool_bluetooth_proxy.yaml rename to .test/esphome_idf_climate_cool.yaml index 69510b1..6c89a8d 100644 --- a/.test/esphome_climate_cool_bluetooth_proxy.yaml +++ b/.test/esphome_idf_climate_cool.yaml @@ -7,10 +7,5 @@ substitutions: packages: basic_package: !include ../nspanel_esphome.yaml # Core package - # advanced_package: !include ../esphome/nspanel_esphome_advanced.yaml - # addon_climate_heat: !include ../esphome/nspanel_esphome_addon_climate_heat.yaml addon_climate_cool: !include ../esphome/nspanel_esphome_addon_climate_cool.yaml - # addon_climate_dual: !include ../esphome/nspanel_esphome_addon_climate_dual. - -bluetooth_proxy: ... diff --git a/.test/esphome_idf_climate_cool_bluetooth_proxy.yaml b/.test/esphome_idf_climate_cool_bluetooth_proxy.yaml new file mode 100644 index 0000000..6143491 --- /dev/null +++ b/.test/esphome_idf_climate_cool_bluetooth_proxy.yaml @@ -0,0 +1,12 @@ +--- +substitutions: + device_name: nspanel + wifi_ssid: "nspanel" + wifi_password: "NSPanel_HA_Blueprint" + nextion_update_url: "https://github.com/Blackymas/NSPanel_HA_Blueprint/dummy" + +packages: + basic_package: !include ../nspanel_esphome.yaml # Core package + addon_climate_cool: !include ../esphome/nspanel_esphome_addon_climate_cool.yaml + addon_bluetooth_proxy: !include ../esphome/nspanel_esphome_addon_bluetooth_proxy.yaml +... diff --git a/.test/esphome_idf_climate_dual.yaml b/.test/esphome_idf_climate_dual.yaml new file mode 100644 index 0000000..efde304 --- /dev/null +++ b/.test/esphome_idf_climate_dual.yaml @@ -0,0 +1,11 @@ +--- +substitutions: + device_name: nspanel + wifi_ssid: "nspanel" + wifi_password: "NSPanel_HA_Blueprint" + nextion_update_url: "https://github.com/Blackymas/NSPanel_HA_Blueprint/dummy" + +packages: + basic_package: !include ../nspanel_esphome.yaml # Core package + addon_climate_dual: !include ../esphome/nspanel_esphome_addon_climate_dual.yaml +... diff --git a/.test/esphome_idf_climate_heat.yaml b/.test/esphome_idf_climate_heat.yaml new file mode 100644 index 0000000..29c25b2 --- /dev/null +++ b/.test/esphome_idf_climate_heat.yaml @@ -0,0 +1,11 @@ +--- +substitutions: + device_name: nspanel + wifi_ssid: "nspanel" + wifi_password: "NSPanel_HA_Blueprint" + nextion_update_url: "https://github.com/Blackymas/NSPanel_HA_Blueprint/dummy" + +packages: + basic_package: !include ../nspanel_esphome.yaml # Core package + addon_climate_heat: !include ../esphome/nspanel_esphome_addon_climate_heat.yaml +... diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 01e8b41..d47460f 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -680,6 +680,67 @@ Users can now interact with the temperature display as intended, facilitating se This update is essential for ensuring that the NSPanel functions correctly, maintaining the quality and reliability expected by our users. We apologize for any inconvenience caused and thank you for your continued support. +## v4.3.5 - Experimenting with Bluetooth Capabilities +This patch release v4.3.5 introduces experimental Bluetooth features alongside critical fixes and enhancements. +The new Bluetooth capabilities leverage the previously untapped potential of the NSPanel's Bluetooth modem, enabled by the increased memory availability in the ESP-IDF framework. + +### New Bluetooth Features (Experimental) +- **BLE Tracker Add-on** + - **Description:** This add-on enables the NSPanel to act as a Bluetooth Low Energy (BLE) tracker, allowing it to detect and report the presence of BLE devices in its vicinity. + This feature is instrumental for presence detection and smart home automation scenarios. + +- **Bluetooth Proxy Add-on** + - **Description:** The Bluetooth Proxy add-on allows the NSPanel to act as a bridge or proxy for other Bluetooth devices, facilitating communication between BLE devices and Home Assistant. + This can significantly extend the functionality of Home Assistant in managing Bluetooth devices without direct connectivity. + +### Temperature Display and Control Fixes +- **Temperature Increment Error in Climate Card Resolved (#2076)** + - **Criticality:** Medium + - **Affected Components:** ESPHome + - **Description:** Corrected a rounding error in the climate card, which caused temperature set points to adjust in increments of 0.9 degrees. + This fix ensures temperature adjustments are now rounded to the nearest whole number, aligning with expected control behavior. + +- **Consistent Temperature Unit Display Across Panels (#2056)** + - **Criticality:** Medium + - **Affected Components:** ESPHome + - **Description:** Resolved an issue where the internal temperature sensor did not convert temperatures from Celsius to Fahrenheit for display on the home screen, + despite displaying correctly on the climate page. Temperatures are now consistently shown in the user-defined units across all NSPanel displays. + +### Control and Interface Enhancements +- **Improved Custom Button Response for Dimmable Color Lights (#2072)** + - **Criticality:** Minor + - **Affected Components:** Blueprint + - **Description:** Fixed a bug where custom buttons for dimmable color lights only toggled the lights on/off. + The buttons now correctly adjust brightness and color settings, enhancing user control. + +- **Homepage Weather and Climate Control Delay Minimized (#2056)** + - **Criticality:** Minor + - **Affected Components:** ESPHome and TFT + - **Description:** Introduced a minor delay optimization for weather updates and climate control interactions on the home page, improving the responsiveness and user experience. + +- **Consistent Icon Color Display on Home Page (#2043)** + - **Criticality:** Minor + - **Affected Components:** Blueprint + - **Description:** Addressed an issue where icons on the home page always displayed in white, regardless of the set color. + Icons now correctly reflect the specified colors, enhancing visual consistency and user interface aesthetics. + +### System Stability and Functionality +- **Restoration of Webserver Functionality Post-Upgrade (#2054, #2050)** + - **Criticality:** Critical + - **Affected Components:** ESPHome + - **Description:** Fixed issues that caused the webserver component to stop functioning following recent upgrades. + This repair restores full webserver functionality, essential for user access and system configuration via a web interface. + +- **Reliability Improvements for TFT Uploads with Bluetooth Components (#1946, #1815)** + - **Criticality:** Medium + - **Affected Components:** ESPHome + - **Description:** Enhanced the reliability of TFT file uploads when the Bluetooth proxy or the BLE Tracker are enabled. + This fix addresses disruptions previously experienced during TFT updates, ensuring smoother and more reliable firmware installations. + +This update, v4.3.5, is a significant step towards harnessing the full potential of the NSPanel's hardware capabilities, especially its Bluetooth functionality, +while continuing to refine the user experience and system stability. +We appreciate the community's active involvement in identifying these issues and thank everyone for their contributions to improving the firmware. + ## Support For support or more information about this update, visit our [GitHub repository](https://github.com/Blackymas/NSPanel_HA_Blueprint) @@ -696,6 +757,7 @@ Your efforts have significantly improved its functionality and reliability (#183 Your contributions have made our guides more informative and accessible, enriching the user experience for everyone (#1865). ## Previous releases +- [v4.3.4 - Urgent Fix for Home Screen Interaction](https://github.com/Blackymas/NSPanel_HA_Blueprint/releases/tag/v4.3.4) - [v4.3.3 - Enhancing Flexibility and User Experience](https://github.com/Blackymas/NSPanel_HA_Blueprint/releases/tag/v4.3.3) - [v4.3.2 - Enhancements and Critical Fixes for a Seamless Experience](https://github.com/Blackymas/NSPanel_HA_Blueprint/releases/tag/v4.3.2) - [v4.3.1 - Ensuring Compatibility with ESPHome v2024.3.0 and Enhancing Stability](https://github.com/Blackymas/NSPanel_HA_Blueprint/releases/tag/v4.3.1) diff --git a/components/nspanel_ha_blueprint/__init__.py b/components/nspanel_ha_blueprint/__init__.py index 89670f1..893e8bb 100644 --- a/components/nspanel_ha_blueprint/__init__.py +++ b/components/nspanel_ha_blueprint/__init__.py @@ -1,18 +1,20 @@ # __init__.py + import esphome.codegen as cg import esphome.config_validation as cv from esphome.components.esp32 import add_idf_sdkconfig_option from esphome.core import CORE, coroutine_with_priority +# from esphome.cpp_tools import CppFile CODEOWNERS = ["@edwardtfn"] nspanel_ha_blueprint_ns = cg.esphome_ns.namespace('nspanel_ha_blueprint') +# MdiIcons = nspanel_ha_blueprint_ns.class_('MdiIcons', cg.Component) CONFIG_SCHEMA = cv.All( cv.Schema({}), ) - @coroutine_with_priority(1.0) async def to_code(config): if CORE.using_arduino: @@ -25,15 +27,18 @@ async def to_code(config): add_idf_sdkconfig_option("CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST", True) add_idf_sdkconfig_option("CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY", True) add_idf_sdkconfig_option("CONFIG_ESP32_REV_MIN_3", True) - add_idf_sdkconfig_option("CONFIG_LWIP_MAX_SOCKETS", 5) # Is this adding any advantage here? + # add_idf_sdkconfig_option("CONFIG_LWIP_MAX_SOCKETS", 5) # This breakes web_server add_idf_sdkconfig_option("CONFIG_MBEDTLS_DYNAMIC_BUFFER", True) add_idf_sdkconfig_option("CONFIG_MBEDTLS_DYNAMIC_FREE_CA_CERT", True) add_idf_sdkconfig_option("CONFIG_MBEDTLS_DYNAMIC_FREE_CONFIG_DATA", True) add_idf_sdkconfig_option("CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC", True) - add_idf_sdkconfig_option("CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY", True) # This makes a significant improvement on RAM - add_idf_sdkconfig_option("CONFIG_SPIRAM_IGNORE_NOTFOUND", True) + add_idf_sdkconfig_option("CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY", True) add_idf_sdkconfig_option("CONFIG_SPIRAM_RODATA", True) add_idf_sdkconfig_option("CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP", True) cg.add_define("USE_NSPANEL_HA_BLUEPRINT") cg.add_global(nspanel_ha_blueprint_ns.using) + + # Setup the MdiIcons class instance + # mdi_icons = cg.new_Pvariable('mdi_icons') + # yield cg.register_component(mdi_icons, config) diff --git a/components/nspanel_ha_blueprint/icons.cpp b/components/nspanel_ha_blueprint/icons.cpp new file mode 100644 index 0000000..1d04058 --- /dev/null +++ b/components/nspanel_ha_blueprint/icons.cpp @@ -0,0 +1,61 @@ +// icons.cpp +#include "icons.h" +#include +#ifdef USE_PSRAM + #ifdef USE_ARDUINO + #include + #else // ESP-IDF + #include // Required for heap capabilities functions + #endif // ARDUINO vs ESP-IDF +#endif // USE_PSRAM + +namespace nspanel_ha_blueprint { + + std::vector icons; // This declaration may not be necessary; see below + + bool initializeIconsVector() { + Icon* allocatedMemory = nullptr; + + // Try to allocate the vector in PSRAM + #ifdef USE_PSRAM + #if defined(USE_ARDUINO) + if (psramFound()) + allocatedMemory = static_cast(ps_malloc(10 * sizeof(Icon))); + #else // ESP-IDF + allocatedMemory = static_cast(heap_caps_malloc(10 * sizeof(Icon), MALLOC_CAP_SPIRAM)); + #endif + + if (allocatedMemory != nullptr) { + new (&icons) std::vector(allocatedMemory, allocatedMemory + 10); // Placement new to initialize vector + return true; // Successfully allocated in PSRAM + } + #endif + + // Fallback to DRAM if PSRAM allocation fails or if PSRAM is not used + allocatedMemory = static_cast(malloc(10 * sizeof(Icon))); + if (allocatedMemory != nullptr) { + new (&icons) std::vector(allocatedMemory, allocatedMemory + 10); // Placement new to initialize vector + return true; // Successfully allocated in DRAM + } + + return false; // Allocation failed + } + + void Icon::updateIcon(const char* code, uint16_t color, bool vis) { + if (strcmp(last_icon_code, code) != 0 || last_icon_color != color || visible != vis) { + strncpy(last_icon_code, code, 4); + last_icon_code[4] = '\0'; + last_icon_color = color; + visible = vis; + } + } + + Icon* findIcon(uint8_t page_id, const char* comp) { + for (auto& icon : icons) { + if (icon.page_id == page_id && strcmp(icon.component, comp) == 0) { + return &icon; + } + } + return nullptr; + } +} diff --git a/components/nspanel_ha_blueprint/icons.h b/components/nspanel_ha_blueprint/icons.h new file mode 100644 index 0000000..18578f2 --- /dev/null +++ b/components/nspanel_ha_blueprint/icons.h @@ -0,0 +1,32 @@ +// icons.h +#pragma once + +#include +#include // For strncpy and strcmp +#include + +namespace nspanel_ha_blueprint { + + struct Icon { + uint8_t page_id; // Page ID, placed logically before the component + char component[15]; // Component name (max 14 chars + null terminator) + char last_icon_code[5]; // UTF-8 code (4 bytes + null terminator) + uint16_t last_icon_color; // Color value + bool visible; // Visibility of the icon + + // Constructor with default values + Icon(uint8_t pid, const char* comp, const char* code = "\xEF\xBF\xBF", uint16_t color = UINT16_MAX, bool vis = true) + : page_id(pid), last_icon_color(color), visible(vis) { + strncpy(const_cast(component), comp, 14); // Use const_cast to bypass const for initialization + const_cast(component)[14] = '\0'; // Ensure null termination safely + strncpy(last_icon_code, code, 4); + last_icon_code[4] = '\0'; + } + + void updateIcon(const char* code, uint16_t color, bool vis); + }; + + extern std::vector icons; // Global list of icons + + Icon* findIcon(uint8_t page_id, const char* component); +} diff --git a/components/nspanel_ha_blueprint/mdiicons.cpp b/components/nspanel_ha_blueprint/mdiicons.cpp new file mode 100644 index 0000000..2fbe5b8 --- /dev/null +++ b/components/nspanel_ha_blueprint/mdiicons.cpp @@ -0,0 +1,64 @@ +// mdiicons.cpp + +#include "mdiicons.h" +#include "esphome/core/log.h" + +using namespace esphome; + +MdiIcons::MdiIcons() : iconPool(nullptr), iconPoolSize(0), iconPoolCapacity(100) {} + +void MdiIcons::setup() { + iconPool = new MdiIcon[iconPoolCapacity]; + if (!iconPool) { + ESP_LOGE("MdiIcons", "Failed to allocate memory for icons in PSRAM"); + return; + } + memset(iconPool, 0, iconPoolCapacity * sizeof(MdiIcon)); + ESP_LOGI("MdiIcons", "Icon pool initialized with capacity %u", iconPoolCapacity); +} + +void MdiIcons::dump_config() { + ESP_LOGCONFIG("MdiIcons", "MDI Icons: Initialized with pool capacity %u", iconPoolCapacity); +} + +const MdiIcon* MdiIcons::find_icon(const char* name) const { + for (size_t i = 0; i < iconPoolSize; ++i) { + if (strcmp(iconPool[i].name, name) == 0) { + return &iconPool[i]; + } + } + return nullptr; +} + +bool MdiIcons::add_icon(const char* name, const char* code) { + if (find_icon(name) != nullptr) { + ESP_LOGW("MdiIcons", "Icon '%s' is already in the pool. Not adding again.", name); + return false; + } + + if (iconPoolSize >= iconPoolCapacity) { + resize_pool(); + } + + strncpy(iconPool[iconPoolSize].name, name, sizeof(MdiIcon::name) - 1); + strncpy(iconPool[iconPoolSize].code, code, sizeof(MdiIcon::code) - 1); + iconPool[iconPoolSize].name[sizeof(MdiIcon::name) - 1] = '\0'; + iconPool[iconPoolSize].code[sizeof(MdiIcon::code) - 1] = '\0'; + iconPoolSize++; + ESP_LOGI("MdiIcons", "New icon '%s' added to the pool.", name); + return true; +} + +void MdiIcons::resize_pool() { + size_t newCapacity = iconPoolCapacity * 2; + MdiIcon* newPool = new MdiIcon[newCapacity]; + if (!newPool) { + ESP_LOGE("MdiIcons", "Failed to resize the icon pool"); + return; + } + memcpy(newPool, iconPool, iconPoolSize * sizeof(MdiIcon)); + delete[] iconPool; + iconPool = newPool; + iconPoolCapacity = newCapacity; + ESP_LOGI("MdiIcons", "Icon pool resized to %u.", iconPoolCapacity); +} diff --git a/components/nspanel_ha_blueprint/mdiicons.h b/components/nspanel_ha_blueprint/mdiicons.h new file mode 100644 index 0000000..89e48cf --- /dev/null +++ b/components/nspanel_ha_blueprint/mdiicons.h @@ -0,0 +1,33 @@ +// mdiicons.h + +#ifndef MDI_ICONS_H +#define MDI_ICONS_H + +#include "esphome/core/component.h" +#include "esphome/core/log.h" +#include + +struct MdiIcon { + char name[32]; // Icon name, assuming max length of 31 characters + null terminator + char code[5]; // Icon code, 4 bytes + null terminator (UTF-8 characters) +}; + +class MdiIcons : public esphome::Component { + public: + MdiIcons(); // Constructor declaration + + void setup() override; // Setup method declaration + void dump_config() override; // Dump config method declaration + + const MdiIcon* find_icon(const char* name) const; // Method to find an icon by name + bool add_icon(const char* name, const char* code); // Method to add an icon + + private: + MdiIcon* iconPool; // Dynamic array of MdiIcons + size_t iconPoolSize; // Number of icons currently in the pool + size_t iconPoolCapacity; // Current capacity of the pool + + void resize_pool(); // Method to resize the icon pool +}; + +#endif // MDI_ICONS_H diff --git a/docs/README.md b/docs/README.md index e27d1d6..15aba08 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,7 +12,8 @@ ## Advanced settings - [Customization](customization.md) -- [Add-on climate](addon_climate.md) +- [Add-on Bluetooth Proxy](addon_bluetooth_proxy.md) +- [Add-on Climate](addon_climate.md) - [Alarm Control Panel](alarm.md) - [API](api.md) - [Using Different Versions of This Project](different_version.md) diff --git a/docs/addon_ble_tracker.md b/docs/addon_ble_tracker.md new file mode 100644 index 0000000..1dd8175 --- /dev/null +++ b/docs/addon_ble_tracker.md @@ -0,0 +1,64 @@ +# Add-on: BLE Tracker + +## Description +This add-on enables your NSPanel to use its internal Bluetooth module to track nearby Bluetooth Low Energy (BLE) devices +using the [ESPHome BLE Tracker component](https://esphome.io/components/esp32_ble_tracker.html). + +> [!IMPORTANT] +> Configuring the BLE Tracker on your NSPanel is crucial for enabling device discovery and presence detection functionalities efficiently. +This component should be managed with careful consideration of ESP32's memory capabilities, especially when other Bluetooth components are used concurrently. + +## Prerequisites +- The `esp-idf` framework is recommended for the [ESP32 Platform](customization.md#framework-esp-idf) to ensure optimal operation and compatibility when using BLE features. +The `arduino` framework is not advised as it may increase memory usage and impact the performance negatively. + +> [!WARNING] +> Using the `arduino` framework can lead to high memory consumption which might interfere with the stability of BLE operations on the NSPanel. +It is crucial to use the `esp-idf` framework to avoid such issues. + +## Configuration Steps +1. **Edit Your ESPHome YAML File**: Incorporate the BLE Tracker component into your NSPanel's configuration by adding the necessary entries under the `esp32_ble_tracker:` section as shown below: + ```yaml + substitutions: + device_name: "YOUR_NSPANEL_NAME" # Set your NSPanel's device name + friendly_name: "Your Friendly Name" # Set a friendly display name + wifi_ssid: !secret wifi_ssid # Your Wi-Fi SSID + wifi_password: !secret wifi_password # Your Wi-Fi password + + # Optional configurations (uncomment if needed) + ## Add-on for specific tracked devices or automation triggers + # sensor: + # - platform: ble_rssi + # mac_address: MAC_ADDRESS_OF_DEVICE + # name: "BLE Device RSSI" + + ## If you wanna set non-standard parameters to your BLE tracker, just add like this: + # esp32_ble_tracker: + # scan_parameters: + # interval: 1100ms + # window: 1100ms + # active: true + + # Package Configuration + packages: + remote_package: + url: https://github.com/Blackymas/NSPanel_HA_Blueprint + ref: main + refresh: 300s + files: + - nspanel_esphome.yaml # Basic NSPanel package + # Optional packages for advanced features and other add-ons + - esphome/nspanel_esphome_addon_ble_tracker.yaml # BLE Tracker add-on package + # - esphome/nspanel_esphome_addon_bluetooth_proxy.yaml + # - esphome/nspanel_esphome_addon_climate_cool.yaml + # - esphome/nspanel_esphome_addon_climate_heat.yaml + # - esphome/nspanel_esphome_addon_climate_dual.yaml + ``` +2. **Update Substitutions**: Customize `"YOUR_NSPANEL_NAME"` and `"Your Friendly Name"` to appropriate identifiers for your device and its Bluetooth functionality. +3. **Save and Upload**: After making the necessary changes, save your configuration file and upload it to your NSPanel via the ESPHome dashboard. + +> [!NOTE] +> The first time this component is enabled for an ESP32, the code partition needs to be resized. +> Please flash the ESP32 via USB when adding this to your configuration. After that, you can use OTA updates again. + +This configuration allows your NSPanel to efficiently manage Bluetooth connections, acting as a proxy for various BLE operations. diff --git a/docs/addon_bluetooth_proxy.md b/docs/addon_bluetooth_proxy.md new file mode 100644 index 0000000..f665bf6 --- /dev/null +++ b/docs/addon_bluetooth_proxy.md @@ -0,0 +1,65 @@ +# Add-on: Bluetooth Proxy + +## Description +This add-on enables your NSPanel to function as a Bluetooth Low Energy (BLE) proxy utilizing its internal Bluetooth module +along with the [ESPHome Bluetooth Proxy component](https://esphome.io/components/bluetooth_proxy.html). + +> [!IMPORTANT] +> It is crucial to configure the Bluetooth Proxy using this add-on for optimal memory management, which involves releasing the Bluetooth stack prior to any TFT updates. + +### Prerequisites +- Ensure the `esp-idf` framework is utilized for the [ESP32 Platform](customization.md#framework-esp-idf) when enabling Bluetooth features. +Avoid switching to the `arduino` framework as it significantly increases memory usage, potentially causing installation failures on your panel. + +> [!WARNING] +> The `arduino` framework, while compatible, should not be used for Bluetooth-intensive applications on the NSPanel due to its higher memory consumption. + +### Configuration Steps +1. **Edit Your ESPHome YAML File**: Add the Bluetooth Proxy add-on to your configuration by including the `remote_package` entry under the `packages` section as illustrated below: + ```yaml + substitutions: + device_name: "YOUR_NSPANEL_NAME" # Set your NSPanel's device name + friendly_name: "Your Friendly Name" # Set a friendly display name + wifi_ssid: !secret wifi_ssid # Your Wi-Fi SSID + wifi_password: !secret wifi_password # Your Wi-Fi password + + # Optional configurations (uncomment if needed) + ## Add-on for climate control + # heater_relay: "1" # Options: "1" or "2" + + # Begin Customization Section + ##### Customization - Start ##### + ## If you wanna set non-standard parameters to your Bluetooth proxy just add like this: + # esp32_ble_tracker: + # scan_parameters: + # interval: 1100ms + # window: 1100ms + # active: true + # + # bluetooth_proxy: + # active: true + ##### Customization - End ##### + + # Package Configuration + packages: + remote_package: + url: https://github.com/Blackymas/NSPanel_HA_Blueprint + ref: main + refresh: 300s + files: + - nspanel_esphome.yaml # Basic NSPanel package + # Optional packages for advanced features and other add-ons + # - esphome/nspanel_esphome_addon_ble_tracker.yaml + - esphome/nspanel_esphome_addon_bluetooth_proxy.yaml # Bluetooth Proxy add-on package + # - esphome/nspanel_esphome_addon_climate_cool.yaml + # - esphome/nspanel_esphome_addon_climate_heat.yaml + # - esphome/nspanel_esphome_addon_climate_dual.yaml + ``` +2. **Update Substitutions**: Customize `"YOUR_NSPANEL_NAME"` and `"Your Friendly Name"` to appropriate identifiers for your device and its Bluetooth functionality. +3. **Save and Upload**: After making the necessary changes, save your configuration file and upload it to your NSPanel via the ESPHome dashboard. + +> [!NOTE] +> The first time this component is enabled for an ESP32, the code partition needs to be resized. +> Please flash the ESP32 via USB when adding this to your configuration. After that, you can use OTA updates again. + +This configuration allows your NSPanel to efficiently manage Bluetooth connections, acting as a proxy for various BLE operations. diff --git a/docs/addon_climate.md b/docs/addon_climate.md index b78d133..a53e0bc 100644 --- a/docs/addon_climate.md +++ b/docs/addon_climate.md @@ -46,14 +46,16 @@ packages: remote_package: url: https://github.com/Blackymas/NSPanel_HA_Blueprint ref: main + refresh: 300s files: - nspanel_esphome.yaml # Basic package # Optional advanced and add-on configurations # - esphome/nspanel_esphome_advanced.yaml - # - nspanel_esphome_addon_climate_cool.yaml - - nspanel_esphome_addon_climate_heat.yaml - # - nspanel_esphome_addon_climate_dual.yaml - refresh: 300s + # - esphome/nspanel_esphome_addon_ble_tracker.yaml + # - esphome/nspanel_esphome_addon_bluetooth_proxy.yaml + # - esphome/nspanel_esphome_addon_climate_cool.yaml + - esphome/nspanel_esphome_addon_climate_heat.yaml + # - esphome/nspanel_esphome_addon_climate_dual.yaml ``` ## Configuration @@ -116,14 +118,16 @@ packages: remote_package: url: https://github.com/Blackymas/NSPanel_HA_Blueprint ref: main + refresh: 300s files: - nspanel_esphome.yaml # Basic package # Optional advanced and add-on configurations # - esphome/nspanel_esphome_advanced.yaml - - nspanel_esphome_addon_climate_cool.yaml - # - nspanel_esphome_addon_climate_heat.yaml - # - nspanel_esphome_addon_climate_dual.yaml - refresh: 300s + # - esphome/nspanel_esphome_addon_ble_tracker.yaml + # - esphome/nspanel_esphome_addon_bluetooth_proxy.yaml + - esphome/nspanel_esphome_addon_climate_cool.yaml + # - esphome/nspanel_esphome_addon_climate_heat.yaml + # - esphome/nspanel_esphome_addon_climate_dual.yaml ``` ### Heater @@ -155,16 +159,19 @@ packages: remote_package: url: https://github.com/Blackymas/NSPanel_HA_Blueprint ref: main + refresh: 300s files: - nspanel_esphome.yaml # Basic package # Optional advanced and add-on configurations # - esphome/nspanel_esphome_advanced.yaml - # - nspanel_esphome_addon_climate_cool.yaml - - nspanel_esphome_addon_climate_heat.yaml - # - nspanel_esphome_addon_climate_dual.yaml - refresh: 300s + # - esphome/nspanel_esphome_addon_ble_tracker.yaml + # - esphome/nspanel_esphome_addon_bluetooth_proxy.yaml + # - esphome/nspanel_esphome_addon_climate_cool.yaml + - esphome/nspanel_esphome_addon_climate_heat.yaml + # - esphome/nspanel_esphome_addon_climate_dual.yaml ``` + ### Dual ```yaml @@ -197,14 +204,16 @@ packages: remote_package: url: https://github.com/Blackymas/NSPanel_HA_Blueprint ref: main + refresh: 300s files: - nspanel_esphome.yaml # Basic package # Optional advanced and add-on configurations # - esphome/nspanel_esphome_advanced.yaml - # - nspanel_esphome_addon_climate_cool.yaml - # - nspanel_esphome_addon_climate_heat.yaml - - nspanel_esphome_addon_climate_dual.yaml - refresh: 300s + # - esphome/nspanel_esphome_addon_ble_tracker.yaml + # - esphome/nspanel_esphome_addon_bluetooth_proxy.yaml + # - esphome/nspanel_esphome_addon_climate_cool.yaml + # - esphome/nspanel_esphome_addon_climate_heat.yaml + - esphome/nspanel_esphome_addon_climate_dual.yaml ``` ### Real Use Case Example: Water Underfloor Heating with NSPanel diff --git a/docs/customization.md b/docs/customization.md index e663f7c..7cc6819 100644 --- a/docs/customization.md +++ b/docs/customization.md @@ -90,14 +90,16 @@ packages: remote_package: url: https://github.com/Blackymas/NSPanel_HA_Blueprint ref: main + refresh: 300s files: - nspanel_esphome.yaml # Basic package # Optional advanced and add-on configurations # - esphome/nspanel_esphome_advanced.yaml - # - nspanel_esphome_addon_climate_cool.yaml - - nspanel_esphome_addon_climate_heat.yaml - # - nspanel_esphome_addon_climate_dual.yaml - refresh: 300s + # - esphome/nspanel_esphome_addon_ble_tracker.yaml + # - esphome/nspanel_esphome_addon_bluetooth_proxy.yaml + # - esphome/nspanel_esphome_addon_climate_cool.yaml + # - esphome/nspanel_esphome_addon_climate_heat.yaml + # - esphome/nspanel_esphome_addon_climate_dual.yaml ``` ## Memory Management @@ -572,93 +574,11 @@ esp32: type: esp-idf ``` -### Bluetooth proxy - -> [!IMPORTANT] -> The [ESP32 Platform](#framework-esp-idf) component should be configured to use the `esp-idf` framework, -> as the `arduino` framework uses significantly more memory and performs poorly with the Bluetooth stack enabled. - -> [!IMPORTANT] -> The Bluetooth stack significantly reduces device RAM. -> Enabling this with additional customizations/components may lead to crashes due to low memory. -> HTTPS connections might be erratic, and local TFT flashing could fail due to insufficient RAM. -> -> Solutions include: -> 1. Flash the device (remove Bluetooth components) while updating TFT. -> 2. Flash from a local (HTTP) source at a low baud rate (9600 or lower) to avoid memory crashes. This method is slower. - -```yaml -# Enable Bluetooth proxy -bluetooth_proxy: - id: ble_proxy - -# Give an id for the BLE Tracker (which is part of BT proxy) -esp32_ble_tracker: - id: ble_tracker - -# Modify upload tft engine to stop BLE scan while uploading -script: - - id: !extend upload_tft - then: - - lambda: |- - static const char *const TAG = "CUSTOM.script.upload_tft"; - ble_tracker->dump_config(); - ESP_LOGD(TAG, "Stopping BLE Tracker scan..."); - ble_tracker->stop_scan(); - ESP_LOGD(TAG, "Disabling BLE Tracker scan..."); - ble_tracker->set_scan_active(false); - ESP_LOGD(TAG, "State: %s", id(ble_proxy)->has_active() ? "Active" : "Passive"); - while (ble_proxy->get_bluetooth_connections_limit() != ble_proxy->get_bluetooth_connections_free()) { - ESP_LOGD(TAG, "Connections: %i of %i", int(ble_proxy->get_bluetooth_connections_limit() - ble_proxy->get_bluetooth_connections_free()), int(ble_proxy->get_bluetooth_connections_limit())); - if (id(ble_proxy)->has_active()) { - ESP_LOGD(TAG, "Setting passive mode..."); - ble_proxy->set_active(false); - } - vTaskDelay(pdMS_TO_TICKS(1000)); - App.feed_wdt(); - } - -# Set Wi-Fi power save mode to "LIGHT" as required for Bluetooth on ESP32 -wifi: - power_save_mode: LIGHT -``` +### Bluetooth Proxy +Please refer to the "[Add-on: Bluetooth Proxy](addon_bluetooth_proxy.md)" guide. ### BLE Tracker - -> [!IMPORTANT] -> The [ESP32 Platform](#framework-esp-idf) component should be configured to use the `esp-idf` framework, -> as the `arduino` framework uses significantly more memory and performs poorly with the Bluetooth stack enabled. - -> [!IMPORTANT] -> The Bluetooth stack significantly reduces device RAM. -> Enabling this with additional customizations/components may lead to crashes due to low memory. -> HTTPS connections might be erratic, and local TFT flashing could fail due to insufficient RAM. -> -> Solutions include: -> 1. Flash the device (remove Bluetooth components) while updating TFT. -> 2. Flash from a local (HTTP) source at a low baud rate (9600 or lower) to avoid memory crashes. This method is slower. - -```yaml -# Enable Bluetooth tracker -esp32_ble_tracker: - id: ble_tracker - -# Modify upload tft engine to stop BLE tracker while uploading -script: - - id: !extend upload_tft - then: - - lambda: |- - static const char *const TAG = "CUSTOM.script.upload_tft"; - ble_tracker->dump_config(); - ESP_LOGI(TAG, "Stopping BLE Tracker scan..."); - ble_tracker->stop_scan(); - ESP_LOGI(TAG, "Disabling BLE Tracker scan..."); - ble_tracker->set_scan_active(false); - -# Set Wi-Fi power save mode to "LIGHT" as required for Bluetooth on ESP32 -wifi: - power_save_mode: LIGHT -``` +Please refer to the "[Add-on: BLE Tracker Proxy](addon_ble_tracker.md)" guide. ### Logger via UART diff --git a/docs/install.md b/docs/install.md index f0d4bcc..195fc30 100644 --- a/docs/install.md +++ b/docs/install.md @@ -129,9 +129,11 @@ Follow these steps to add a new device in the ESPHome Dashboard: - nspanel_esphome.yaml # Basic package # Optional advanced and add-on configurations # - esphome/nspanel_esphome_advanced.yaml - # - nspanel_esphome_addon_climate_cool.yaml - # - nspanel_esphome_addon_climate_heat.yaml - # - nspanel_esphome_addon_climate_dual.yaml + # - esphome/nspanel_esphome_addon_ble_tracker.yaml + # - esphome/nspanel_esphome_addon_bluetooth_proxy.yaml + # - esphome/nspanel_esphome_addon_climate_cool.yaml + - esphome/nspanel_esphome_addon_climate_heat.yaml + # - esphome/nspanel_esphome_addon_climate_dual.yaml ``` ![YAML Code](pics/ha_esphome_dashboard_new_device_06.png) diff --git a/esphome/nspanel_esphome_addon_ble_tracker.yaml b/esphome/nspanel_esphome_addon_ble_tracker.yaml new file mode 100644 index 0000000..e984fab --- /dev/null +++ b/esphome/nspanel_esphome_addon_ble_tracker.yaml @@ -0,0 +1,36 @@ +##################################################################################################### +##### NSPANEL ESPHOME created by Blackymas - https://github.com/Blackymas/NSPanel_HA_Blueprint ##### +##### ESPHome Add-on for BLE Tracker ##### +##### PLEASE only make changes if it is necessary and also the required knowledge is available. ##### +##### For normal use with the Blueprint, no changes are necessary. ##### +##################################################################################################### +##### ATTENTION: This will add climate elements to the core system and requires the core part. ##### +##################################################################################################### +--- + +# Enable Bluetooth tracker +esp32_ble_tracker: + id: ble_tracker + +esphome: + platformio_options: + build_flags: + - -D NSPANEL_HA_BLUEPRINT_ADDON_BLE_TRACKER + +script: + - id: !extend dump_config + then: + - lambda: |- + // Check if this is installed with Arduino + #ifdef USE_ARDUINO + #error "Invalid settings for add-on BLE Tracker. Arduino framework is not supported when using Bluetooth in this project." + #endif + if (!id(is_uploading_tft)) { + static const char *const TAG = "nspanel_ha_blueprint"; + ESP_LOGCONFIG(TAG, "Add-on BLE Tracker"); + } + +# Set Wi-Fi power save mode to "LIGHT" as required for Bluetooth on ESP32 +wifi: + power_save_mode: LIGHT +... diff --git a/esphome/nspanel_esphome_addon_bluetooth_proxy.yaml b/esphome/nspanel_esphome_addon_bluetooth_proxy.yaml new file mode 100644 index 0000000..51f65e2 --- /dev/null +++ b/esphome/nspanel_esphome_addon_bluetooth_proxy.yaml @@ -0,0 +1,43 @@ +##################################################################################################### +##### NSPANEL ESPHOME created by Blackymas - https://github.com/Blackymas/NSPanel_HA_Blueprint ##### +##### ESPHome Add-on for Bluetooth proxy ##### +##### PLEASE only make changes if it is necessary and also the required knowledge is available. ##### +##### For normal use with the Blueprint, no changes are necessary. ##### +##################################################################################################### +##### ATTENTION: This will add climate elements to the core system and requires the core part. ##### +##################################################################################################### +--- + +bluetooth_proxy: + id: ble_proxy + +# Enable Bluetooth tracker +esp32_ble_tracker: + id: ble_tracker + +esphome: + platformio_options: + build_flags: + - -D NSPANEL_HA_BLUEPRINT_ADDON_BLUETOOTH_PROXY + +script: + - id: !extend dump_config + then: + - lambda: |- + // Check if this is installed with Arduino + #ifdef USE_ARDUINO + #error "Invalid settings for add-on Bluetooth Proxy. Arduino framework is not supported when using Bluetooth in this project." + #endif + if (!id(is_uploading_tft)) { + static const char *const TAG = "nspanel_ha_blueprint"; + ESP_LOGCONFIG(TAG, "Add-on Bluetooth Proxy:"); + ESP_LOGCONFIG(TAG, " Mode: %s", ble_proxy->has_active() ? "Active" : "Passive"); + ESP_LOGCONFIG(TAG, " Connections: %i", int(ble_proxy->get_bluetooth_connections_limit() - + ble_proxy->get_bluetooth_connections_free())); + ESP_LOGCONFIG(TAG, " Limit: %i", int(ble_proxy->get_bluetooth_connections_limit())); + } + +# Set Wi-Fi power save mode to "LIGHT" as required for Bluetooth on ESP32 +wifi: + power_save_mode: LIGHT +... diff --git a/esphome/nspanel_esphome_addon_climate_base.yaml b/esphome/nspanel_esphome_addon_climate_base.yaml index 18aae4d..c1c6034 100644 --- a/esphome/nspanel_esphome_addon_climate_base.yaml +++ b/esphome/nspanel_esphome_addon_climate_base.yaml @@ -113,6 +113,53 @@ script: call.perform(); } + - id: !extend dump_config + then: + - lambda: |- + // Check if more than one or none of the climate options are defined + #if defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_COOL) && defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_HEAT) + #error "Invalid settings for add-on Climate. More than one option selected: Cool + Heat." + #elif defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_COOL) && defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_DUAL) + #error "Invalid settings for add-on Climate. More than one option selected: Cool + Dual." + #elif defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_HEAT) && defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_DUAL) + #error "Invalid settings for add-on Climate. More than one option selected: Heat + Dual." + #elif !defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_COOL) && !defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_HEAT) && !defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_DUAL) + #error "Invalid settings for add-on Climate. No option selected between Cool, Heat or Dual." + #endif + if (!id(is_uploading_tft)) { + static const char *const TAG = "nspanel_ha_blueprint"; + uint cooler_relay = ${cooler_relay}; + uint heater_relay = ${heater_relay}; + ESP_LOGCONFIG(TAG, "Add-on climate:"); + #ifdef NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_COOL + ESP_LOGCONFIG(TAG, " Cool: Enabled"); + if (cooler_relay == 1 or cooler_relay == 2) + ESP_LOGCONFIG(TAG, " Relay: %u", cooler_relay); + else + ESP_LOGE(TAG, " Relay: %u", cooler_relay); + #endif + #ifdef NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_HEAT + ESP_LOGCONFIG(TAG, " Heat: Enabled"); + if (heater_relay == 1 or heater_relay == 2) + ESP_LOGCONFIG(TAG, " Relay: %u", heater_relay); + else + ESP_LOGE(TAG, " Relay: %u", heater_relay); + #endif + #ifdef NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_DUAL + ESP_LOGCONFIG(TAG, " Dual: Enabled"); + if (cooler_relay == 1 or cooler_relay == 2) + ESP_LOGCONFIG(TAG, " Relay (cooler): %u", cooler_relay); + else + ESP_LOGE(TAG, " Relay (cooler): %u", cooler_relay); + if (heater_relay == 1 or heater_relay == 2) + ESP_LOGCONFIG(TAG, " Relay (heater): %u", heater_relay); + else + ESP_LOGE(TAG, " Relay (heater): %u", heater_relay); + if (cooler_relay == heater_relay) + ESP_LOGE(TAG, " Double relay assignment"); + #endif + } + - id: !extend init_hardware_climate then: - lambda: |- @@ -126,8 +173,8 @@ script: auto CelsiusToFahrenheit = [](float celsius) -> float { return (celsius * 9 / 5) + 32; }; - std::string temp_units = "${temp_units}"; - bool temp_unit_fahrenheit = (temp_units == "°F" || temp_units == "F" || temp_units == "°f" || temp_units == "f"); + const std::string temp_units = "${temp_units}"; + const bool temp_unit_fahrenheit = (temp_units == "°F" || temp_units == "F" || temp_units == "°f" || temp_units == "f"); ClimateTraits traits = thermostat_embedded->get_traits(); disp1->set_component_text("page_label", id(addon_climate_friendly_name).c_str()); @@ -140,7 +187,7 @@ script: float temp_current = thermostat_embedded->current_temperature; if (temp_unit_fahrenheit) { //temp_step = CelsiusToFahrenheit(temp_step); - temp_step = temp_step * 1.8; + temp_step = std::ceil(temp_step * 1.8); temp_offset = CelsiusToFahrenheit(temp_offset); temp_max = CelsiusToFahrenheit(temp_max); temp_target = CelsiusToFahrenheit(temp_target); @@ -197,51 +244,4 @@ script: - lambda: |- if (current_page->state == "climate" and !id(is_uploading_tft)) id(is_addon_climate_visible) = embedded_climate; - - - id: !extend watchdog - then: - - lambda: |- - // Check if more than one or none of the climate options are defined - #if defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_COOL) && defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_HEAT) - #error "Invalid settings for add-on Climate. More than one option selected: Cool + Heat." - #elif defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_COOL) && defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_DUAL) - #error "Invalid settings for add-on Climate. More than one option selected: Cool + Dual." - #elif defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_HEAT) && defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_DUAL) - #error "Invalid settings for add-on Climate. More than one option selected: Heat + Dual." - #elif !defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_COOL) && !defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_HEAT) && !defined(NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_DUAL) - #error "Invalid settings for add-on Climate. No option selected between Cool, Heat or Dual." - #endif - if (!id(is_uploading_tft)) { - static const char *const TAG = "addon_climate_base.script.watchdog"; - uint cooler_relay = ${cooler_relay}; - uint heater_relay = ${heater_relay}; - ESP_LOGI(TAG, "Add-on climate:"); - #ifdef NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_COOL - ESP_LOGI(TAG, " Cool: Enabled"); - if (cooler_relay == 1 or cooler_relay == 2) - ESP_LOGI(TAG, " Relay: %u", cooler_relay); - else - ESP_LOGE(TAG, " Relay: %u", cooler_relay); - #endif - #ifdef NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_HEAT - ESP_LOGI(TAG, " Heat: Enabled"); - if (heater_relay == 1 or heater_relay == 2) - ESP_LOGI(TAG, " Relay: %u", heater_relay); - else - ESP_LOGE(TAG, " Relay: %u", heater_relay); - #endif - #ifdef NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_DUAL - ESP_LOGI(TAG, " Dual: Enabled"); - if (cooler_relay == 1 or cooler_relay == 2) - ESP_LOGI(TAG, " Relay (cooler): %u", cooler_relay); - else - ESP_LOGE(TAG, " Relay (cooler): %u", cooler_relay); - if (heater_relay == 1 or heater_relay == 2) - ESP_LOGI(TAG, " Relay (heater): %u", heater_relay); - else - ESP_LOGE(TAG, " Relay (heater): %u", heater_relay); - if (cooler_relay == heater_relay) - ESP_LOGE(TAG, " Double relay assignment"); - #endif - } ... diff --git a/esphome/nspanel_esphome_addon_upload_tft.yaml b/esphome/nspanel_esphome_addon_upload_tft.yaml index 39db087..67bf26d 100644 --- a/esphome/nspanel_esphome_addon_upload_tft.yaml +++ b/esphome/nspanel_esphome_addon_upload_tft.yaml @@ -89,6 +89,16 @@ globals: initial_value: 'esphome::nextion::Nextion::TFTUploadResult::UNKNOWN' script: + - id: !extend dump_config + then: + - lambda: |- + if (!id(is_uploading_tft)) { + static const char *const TAG = "nspanel_ha_blueprint"; + ESP_LOGCONFIG(TAG, "Add-on Upload TFT:"); + ESP_LOGCONFIG(TAG, " File model: %s", tft_file_model->state.c_str()); + ESP_LOGCONFIG(TAG, " Valid TFT: %s", YESNO(id(tft_is_valid))); + } + - id: nextion_status mode: restart then: @@ -179,6 +189,25 @@ script: then: - switch.turn_on: screen_power - delay: 5s + - lambda: if (id(tft_is_valid)) disp1->goto_page("home"); + - delay: 2s + - script.execute: open_upload_dialog + - script.wait: open_upload_dialog + - wait_until: + condition: + - lambda: return (current_page->state == "confirm"); + timeout: 2s + - script.execute: + id: report_upload_progress + message: "Set Nextion unavailable for blueprint calls" + - script.wait: report_upload_progress + - binary_sensor.template.publish: + id: nextion_init + state: false + - script.execute: + id: report_upload_progress + message: "Preparing for upload..." + - script.wait: report_upload_progress # Then start the upload - lambda: |- static const char *const TAG = "addon_upload_tft.script.upload_tft"; @@ -195,7 +224,50 @@ script: ESP_LOGD(TAG, " Upload URL: %s", url.c_str()); disp1->set_tft_url(url.c_str()); - - lambda: if (id(tft_is_valid)) disp1->goto_page("home"); + #ifdef USE_IMPROV + ESP_LOGD(TAG, "Stop Improv BLE"); + ble_improv->dump_config(); + ble_improv->stop(); + ble_improv->dump_config(); + #endif + #ifdef USE_CAPTIVE_PORTAL + ESP_LOGD(TAG, "Stop Captive Portal"); + ap_captive_portal->dump_config(); + ap_captive_portal->end(); + ap_captive_portal->dump_config(); + #endif + #ifdef USE_ESP32_BLE_CLIENT + ble_tracker->dump_config(); + ESP_LOGD(TAG, "Disable BLE"); + #ifdef USE_BLUETOOTH_PROXY + ESP_LOGD(TAG, " Bluetooth proxy: %s", ble_proxy->has_active() ? "Active" : "Passive"); + while (ble_proxy->has_active() and + ble_proxy->get_bluetooth_connections_limit() != ble_proxy->get_bluetooth_connections_free()) { + ESP_LOGD(TAG, " BT proxy connections: %i of %i", + int(ble_proxy->get_bluetooth_connections_limit() - ble_proxy->get_bluetooth_connections_free()), + int(ble_proxy->get_bluetooth_connections_limit())); + if (ble_proxy->has_active()) { + ESP_LOGD(TAG, " BT proxy set passive mode..."); + ble_proxy->set_active(false); + } + #ifdef ARDUINO + delay(1000); + #elif defined(USE_ESP_IDF) + vTaskDelay(pdMS_TO_TICKS(1000)); + #endif + App.feed_wdt(); + } + #endif // USE_BLUETOOTH_PROXY + ESP_LOGD(TAG, " Stopping BLE Tracker scan..."); + ble_tracker->stop_scan(); + ESP_LOGD(TAG, " Disabling BLE Tracker scan..."); + ble_tracker->set_scan_active(false); + ESP_LOGD(TAG, " Disabling BLE..."); + ble_tracker->get_parent()->disable(); + ble_tracker->dump_config(); + #endif // USE_ESP32_BLE_CLIENT + + - lambda: if (id(tft_is_valid) and current_page->state != "confirm") disp1->goto_page("home"); - delay: 2s - script.execute: open_upload_dialog - script.wait: open_upload_dialog @@ -203,13 +275,6 @@ script: condition: - lambda: return (current_page->state == "confirm"); timeout: 2s - - script.execute: - id: report_upload_progress - message: "Set Nextion unavailable for blueprint calls" - - script.wait: report_upload_progress - - binary_sensor.template.publish: - id: nextion_init - state: false - script.execute: id: report_upload_progress message: "Stopping other scripts" @@ -362,16 +427,6 @@ script: ESP_LOGI("addon_upload_tft.script.upload_tft_attempt", "Restarting ESPHome"); App.safe_reboot(); - - id: !extend watchdog - then: - - lambda: |- - if (!id(is_uploading_tft)) { - static const char *const TAG = "addon_upload_tft.script.watchdog"; - ESP_LOGI(TAG, "Add-on Upload TFT:"); - ESP_LOGI(TAG, " File model: %s", tft_file_model->state.c_str()); - ESP_LOGI(TAG, " Valid TFT: %s", YESNO(id(tft_is_valid))); - } - select: - id: tft_file_model name: Update TFT display - Model diff --git a/esphome/nspanel_esphome_advanced.yaml b/esphome/nspanel_esphome_advanced.yaml index 5b2124e..f44b00c 100644 --- a/esphome/nspanel_esphome_advanced.yaml +++ b/esphome/nspanel_esphome_advanced.yaml @@ -33,6 +33,7 @@ button: - script.execute: exit_reparse captive_portal: + id: ap_captive_portal script: - id: exit_reparse @@ -76,9 +77,9 @@ sensor: text_sensor: ##### ESPhome version used to compile the app ##### - - name: ESPhome Version + - name: ESPhome Compiler platform: version - disabled_by_default: false + disabled_by_default: true internal: false icon: mdi:tag-text-outline diff --git a/esphome/nspanel_esphome_core.yaml b/esphome/nspanel_esphome_core.yaml index e3466cd..4491a56 100644 --- a/esphome/nspanel_esphome_core.yaml +++ b/esphome/nspanel_esphome_core.yaml @@ -17,7 +17,7 @@ substitutions: invalid_cooldown: "100ms" bytes_per_char: "1" ##### DON'T CHANGE THIS ###### - version: "4.3.4" + version: "4.3.5" ############################## ##### External components ##### @@ -27,16 +27,24 @@ external_components: # path: packages/Blackymas/components type: git url: https://github.com/Blackymas/NSPanel_HA_Blueprint - ref: v4.3.4 + ref: v4.3.5 components: - nspanel_ha_blueprint refresh: 300s - source: type: git url: https://github.com/edwardtfn/esphome - ref: nextion-v432 + ref: nextion-v435 components: - - nextion # Change this when that PR#6192 gets released (2024.4?) + - nextion # Change this when that PR#6192 gets released (2024.5?) + - psram # Change this when that PR#6526 gets released (2024.5?) + refresh: 300s + - source: + type: git + url: https://github.com/edwardtfn/esphome + ref: esp32ble-01 + components: + - esp32_ble_tracker # Change this when that PR#6585 gets released (2024.5?) refresh: 300s - source: type: git @@ -62,6 +70,7 @@ esphome: - lambda: |- set_timezone->execute(id(mui_timezone).c_str()); if (isnan(blueprint_status->raw_state)) blueprint_status->publish_state(0); + version_esphome->publish_state("${version}"); device_name->publish_state("${name}"); notification_label->publish_state(""); notification_text->publish_state(""); @@ -115,10 +124,10 @@ wifi: password: ${wifi_password} on_connect: then: - - script.execute: watchdog + - script.execute: refresh_wifi_icon on_disconnect: then: - - script.execute: watchdog + - script.execute: refresh_wifi_icon ##### OTA PASSWORD ##### ota: @@ -168,9 +177,31 @@ time: refresh_relays->execute(3); refresh_hardware_buttons_bars->execute(3); refresh_wifi_icon->execute(); - - seconds: 30 + - seconds: 30 # Watchdog then: - - script.execute: watchdog + - lambda: |- + if (not wifi_component->is_connected()) { + ESP_LOGW("watchdog", "Retrying Wi-Fi connection"); + wifi_component->retry_connect(); + } + if (not api_server->is_connected() and + current_page->state != "blank" and + current_page->state != "boot" and + current_page->state != "confirm" and + current_page->state != "home" and + current_page->state != "qrcode" and + current_page->state != "screensaver" and + current_page->state != "settings") { + ESP_LOGW("watchdog", "API disconnected. Falling back to Home page."); + goto_page->execute("home"); + blueprint_status->publish_state(0); + } + refresh_wifi_icon->execute(); + + - minutes: /10 + seconds: 5 + then: + - script.execute: dump_config on_time_sync: then: @@ -187,10 +218,11 @@ api: reboot_timeout: 60min on_client_connected: then: - - script.execute: watchdog + - script.execute: refresh_wifi_icon + - script.execute: dump_config on_client_disconnected: then: - - script.execute: watchdog + - script.execute: refresh_wifi_icon services: # Dynamically configures button properties on a specified page, enhancing UI interactivity by allowing updates to button appearance and behavior based on given parameters. - service: button # yamllint disable-line rule:indentation @@ -231,7 +263,7 @@ api: then: - lambda: |- if (!id(is_uploading_tft)) - disp1->send_command_printf("%s", cmd.c_str()); + disp1->send_command(cmd.c_str()); # Changes the foreground color of a specified component on the display. - service: component_color @@ -342,7 +374,6 @@ api: screensaver_time_font: int # Specifies the font id for the screensaver time display. screensaver_time_color: int[] # RGB color for the screensaver time display, e.g., [165, 42, 42] for reddish-brown. decimal_separator: string # The char to be used as decimal separator. - # bytes_per_char: init then: - if: condition: @@ -358,7 +389,6 @@ api: screensaver_time_font: !lambda return screensaver_time_font; screensaver_time_color: !lambda return screensaver_time_color; decimal_separator: !lambda return decimal_separator; - # bytes_per_char: !lambda return bytes_per_char; - script.wait: global_settings - lambda: blueprint_status->publish_state(int(blueprint_status->raw_state) | (1 << 5)); @@ -769,7 +799,7 @@ api: set_component_visibility->execute("time_total", true); set_component_visibility->execute("time_progress", true); } else { - disp1->send_command_printf("prg_timer.en=0"); + disp1->send_command("prg_timer.en=0"); set_component_visibility->execute("time_current", false); set_component_visibility->execute("time_total", false); set_component_visibility->execute("time_progress", false); @@ -807,6 +837,14 @@ api: - lambda: |- if (component == "is_climate") id(is_climate) = val; + - service: set_int + variables: + component: string + val: int + then: + - lambda: |- + if (component == "bytes_per_char") id(mui_bytes_per_char) = val; + - service: set_string variables: component: string @@ -950,18 +988,6 @@ display: break; } break; - case 1: // Home - switch (component_id) { - case 4: // indr_temp - case 27: // indr_temp_icon - if (id(is_climate) and !touch_event) { // Release - detailed_entity->publish_state((id(is_embedded_thermostat)) ? "embedded_climate" : ""); - disp1->set_component_value("climate.embedded", id(is_embedded_thermostat) ? 1 : 0); - goto_page->execute("climate"); - } - break; - } - break; case 8: // Settings switch (component_id) { case 9: // Reboot button @@ -973,7 +999,7 @@ display: break; case 10: // light switch (component_id) { - case 34: // power_button + case 32: // power_button if (!touch_event) { // Release ha_call_service->execute("light.toggle", "", "", detailed_entity->state.c_str()); } @@ -1001,7 +1027,7 @@ display: break; case 22: // fan switch (component_id) { - case 17: // bt_oscillate + case 15: // bt_oscillate if (!touch_event) { // Release ha_call_service->execute("fan.oscillate", "oscillating", "toggle", detailed_entity->state.c_str()); } @@ -1287,7 +1313,7 @@ binary_sensor: entity_category: diagnostic icon: mdi:tablet-dashboard lambda: |- - return disp1->is_setup(); + return (!id(is_uploading_tft) and disp1->is_setup()); ##### START - BUTTON CONFIGURATION ##### button: @@ -1659,6 +1685,7 @@ switch: esphome::api::CustomAPIDevice ha_event; ha_event.fire_homeassistant_event("esphome.nspanel_ha_blueprint", { {"device_name", device_name->state.c_str()}, + {"esphome_version", "${version}"}, {"type", "notification_changed"}, {"component", "notification_unread"}, {"action", "turn_on"} @@ -1668,6 +1695,7 @@ switch: esphome::api::CustomAPIDevice ha_event; ha_event.fire_homeassistant_event("esphome.nspanel_ha_blueprint", { {"device_name", device_name->state.c_str()}, + {"esphome_version", "${version}"}, {"type", "notification_changed"}, {"component", "notification_unread"}, {"action", "turn_off"} @@ -1818,6 +1846,7 @@ text_sensor: esphome::api::CustomAPIDevice ha_event; ha_event.fire_homeassistant_event("esphome.nspanel_ha_blueprint", { {"device_name", device_name->state.c_str()}, + {"esphome_version", "${version}"}, {"type", "notification_changed"}, {"component", "notification_label"}, {"action", "new_value"} @@ -1831,6 +1860,7 @@ text_sensor: esphome::api::CustomAPIDevice ha_event; ha_event.fire_homeassistant_event("esphome.nspanel_ha_blueprint", { {"device_name", device_name->state.c_str()}, + {"esphome_version", "${version}"}, {"type", "notification_changed"}, {"component", "notification_text"}, {"action", "new_value"} @@ -1861,10 +1891,19 @@ text_sensor: esphome::api::CustomAPIDevice ha_event; // Send event to Home Assistant if (event == "short_click" or event == "long_click") { - ha_button->execute(page.c_str(), component.c_str(), event.c_str()); + if (api_server->is_connected() and page == "home" and component == "weather") { + goto_page->execute("weather01"); + } else if (id(is_climate) and page == "home" and (component == "indr_temp" or component == "indr_temp_icon")) { + detailed_entity->publish_state((id(is_embedded_thermostat)) ? "embedded_climate" : ""); + disp1->set_component_value("climate.embedded", id(is_embedded_thermostat) ? 1 : 0); + goto_page->execute("climate"); + } else { + ha_button->execute(page.c_str(), component.c_str(), event.c_str()); + } } else if (page == "light" or page == "climate") { // Generic event ha_event.fire_homeassistant_event("esphome.nspanel_ha_blueprint", { {"device_name", device_name->state.c_str()}, + {"esphome_version", "${version}"}, {"type", "generic"}, {"page", page.c_str()}, {"component", component.c_str()}, @@ -1914,6 +1953,7 @@ text_sensor: ha_event.fire_homeassistant_event("esphome.nspanel_ha_blueprint", { {"device_name", device_name->state.c_str()}, + {"esphome_version", "${version}"}, {"type", "service_call"}, {"service", "light.turn_on"}, {"key", "rgb_color"}, @@ -1948,6 +1988,16 @@ text_sensor: - lambda: |- check_versions->execute(); + - id: version_esphome + name: Version ESPHome + platform: template + entity_category: diagnostic + icon: mdi:tag-text-outline + internal: false + update_interval: never + lambda: |- + return {"${version}"}; + - id: version_tft name: Version TFT platform: nextion @@ -1973,6 +2023,7 @@ script: ha_event.fire_homeassistant_event("esphome.nspanel_ha_blueprint", { {"device_name", device_name->state.c_str()}, + {"esphome_version", "${version}"}, {"type", "boot"}, {"step", "start"} }); @@ -1988,6 +2039,7 @@ script: ha_event.fire_homeassistant_event("esphome.nspanel_ha_blueprint", { {"device_name", device_name->state.c_str()}, + {"esphome_version", "${version}"}, {"type", "boot"}, {"step", "timeout"} }); @@ -2009,7 +2061,7 @@ script: disp1->set_component_value("boot.progress", step); } if (current_page->state == "boot" and !isnan(display_charset->state) and !isnan(display_mode->state) and !version_tft->state.empty()) - disp1->send_command_printf("tm_esphome.en=0"); + disp1->send_command("tm_esphome.en=0"); - id: change_climate_state mode: restart @@ -2051,6 +2103,7 @@ script: ha_event.fire_homeassistant_event("esphome.nspanel_ha_blueprint", { {"device_name", device_name->state.c_str()}, + {"esphome_version", "${version}"}, {"type", "version"}, {"tft", version_tft->state.c_str()}, {"esphome", "${version}"}, @@ -2063,13 +2116,13 @@ script: then: - lambda: |- if (id(embedded_indoor_temp) or !wifi_component->is_connected() or !api_server->is_connected()) { - float unit_based_temperature = id(temp_nspanel).state; + const std::string temp_units = "${temp_units}"; + const bool temp_unit_fahrenheit = (temp_units == "°F" || temp_units == "F" || temp_units == "°f" || temp_units == "f"); char buffer[15]; // Buffer for formatted temperature string - if ("${temp_units}"[0] == 'F' || "${temp_units}"[0] == 'f' || "${temp_units}"[1] == 'F' || "${temp_units}"[1] == 'f') { - unit_based_temperature = (unit_based_temperature * 9.0 / 5.0) + 32; // Convert to Fahrenheit if necessary - snprintf(buffer, sizeof(buffer), "%.0f${temp_units}", unit_based_temperature); // Fahrenheit with no decimal + if (temp_unit_fahrenheit) { + snprintf(buffer, sizeof(buffer), "%.0f${temp_units}", (id(temp_nspanel).state * 9.0 / 5.0) + 32); // Fahrenheit with no decimal } else { - snprintf(buffer, sizeof(buffer), "%.1f${temp_units}", unit_based_temperature); // Celsius with one decimal + snprintf(buffer, sizeof(buffer), "%.1f${temp_units}", id(temp_nspanel).state); // Celsius with one decimal } id(disp1)->set_component_text("home.indr_temp", adjustDecimalSeparator(buffer, id(mui_decimal_separator)).c_str()); } @@ -2110,6 +2163,167 @@ script: } disp1->set_component_text(component.c_str(), wrappedText.c_str()); + - id: dump_config + mode: restart + then: + - delay: 10s + - lambda: |- + #include + static const char *const TAG = "nspanel_ha_blueprint"; + if (id(is_uploading_tft)) { + ESP_LOGW(TAG, "TFT upload in progress"); + } else { + // report Wi-Fi status + bool wifi_connected = wifi_component->is_connected(); + if (wifi_connected) { + float rssi = wifi_rssi->state; + const char *rssi_status = "Unknown"; // Use const char* to avoid dynamic memory allocation + if (rssi > -50) rssi_status = "Excellent"; + else if (rssi > -60) rssi_status = "Good"; + else if (rssi > -70) rssi_status = "Fair"; + else if (rssi > -80) rssi_status = "Weak"; + else rssi_status = "Poor"; + if (rssi > -70) ESP_LOGCONFIG(TAG, "Wi-Fi: %s (%.0f dBm)", rssi_status, rssi); + else if (rssi > -80) ESP_LOGW(TAG, "Wi-Fi: %s (%.0f dBm)", rssi_status, rssi); + else ESP_LOGE(TAG, "Wi-Fi: %s (%.0f dBm)", rssi_status, rssi); + } + else { + ESP_LOGW(TAG, "Wi-Fi: DISCONNECTED"); + } + + // report API status + bool api_connected = api_server->is_connected(); + if (api_connected) { + ESP_LOGCONFIG(TAG, "API: Connected"); + } else { + ESP_LOGW(TAG, "API: DISCONNECTED"); + } + + if (!wifi_connected or !api_connected) blueprint_status->publish_state(0); + + // Report blueprint version + ESP_LOGCONFIG(TAG, "Blueprint:"); + if (blueprint_status->state > 99) { + ESP_LOGCONFIG(TAG, " Version: %s", version_blueprint->state.c_str()); + ESP_LOGCONFIG(TAG, " Init steps: %i (%0.1f%%)", int(blueprint_status->raw_state), blueprint_status->state); + } else { + ESP_LOGW(TAG, " Init steps: %i (%0.1f%%)", int(blueprint_status->raw_state), blueprint_status->state); + ESP_LOGW(TAG, " State: %s", (wifi_connected and api_connected) ? "Pending" : "DISCONNECTED"); + ESP_LOGCONFIG(TAG, "Requesting blueprint settings"); + boot_event->execute(false); + } + + // Report ESPHome + ESP_LOGCONFIG(TAG, "ESPHome:"); + ESP_LOGCONFIG(TAG, " Version: ${version}"); + ESP_LOGCONFIG(TAG, " Compiler: %s", ESPHOME_VERSION); + // Report framework + #ifdef ARDUINO + ESP_LOGCONFIG(TAG, " Framework: Arduino"); + #elif defined(USE_ESP_IDF) + ESP_LOGCONFIG(TAG, " Framework: ESP-IDF"); + #endif + // Report memory + const size_t internal_heap_size = heap_caps_get_total_size(MALLOC_CAP_INTERNAL); + const size_t internal_heap_size_free = heap_caps_get_free_size(MALLOC_CAP_INTERNAL); + ESP_LOGCONFIG(TAG, " Free heap:"); + + if (internal_heap_size != 0) { + ESP_LOGCONFIG(TAG, " Internal: %7d bytes (%0.1f%%)", internal_heap_size_free, + ((float)internal_heap_size_free / internal_heap_size) * 100.0f); + } else { + ESP_LOGCONFIG(TAG, " Internal: %7d bytes", internal_heap_size_free); + } + + #ifdef USE_PSRAM + const size_t psram_heap_size = heap_caps_get_total_size(MALLOC_CAP_SPIRAM); + const size_t psram_heap_size_free = heap_caps_get_free_size(MALLOC_CAP_SPIRAM); + if (psram_heap_size != 0) { + ESP_LOGCONFIG(TAG, " PSRAM: %7d bytes (%0.1f%%)", psram_heap_size_free, + ((float)psram_heap_size_free / psram_heap_size) * 100.0f); + } else { + ESP_LOGCONFIG(TAG, " PSRAM: %7d bytes", psram_heap_size_free); + } + #endif + + // Report UART + ESP_LOGCONFIG(TAG, "UART:"); + ESP_LOGCONFIG(TAG, " Baud rate: %" PRIu32 " bps", tf_uart->get_baud_rate()); + ESP_LOGCONFIG(TAG, " Queue size: %d", tf_uart->available()); + + // Report Nextion status + nextion_init->publish_state(!id(is_uploading_tft) and nextion_init->state and disp1->is_setup()); + ESP_LOGCONFIG(TAG, "Nextion:"); + ESP_LOGCONFIG(TAG, " Queue size: %d", disp1->queue_size()); + if (disp1->is_setup()) + ESP_LOGCONFIG(TAG, " Is setup: True"); + else { + ESP_LOGW(TAG, " Is setup: False"); + ESP_LOGW(TAG, " Is detected: %s", YESNO(disp1->is_detected())); + //exit_reparse->execute(); + } + if (nextion_init->state) { + ESP_LOGCONFIG(TAG, " Init: True"); + } else + ESP_LOGW(TAG, " Init: False"); + if (version_tft->state.empty()) + ESP_LOGW(TAG, " TFT: UNKNOWN"); + else + ESP_LOGCONFIG(TAG, " TFT: %s", version_tft->state.c_str()); + ESP_LOGCONFIG(TAG, "Packages:"); + #ifdef NSPANEL_HA_BLUEPRINT_CORE + ESP_LOGCONFIG(TAG, " - Core"); + #endif + #ifdef NSPANEL_HA_BLUEPRINT_ADVANCED + ESP_LOGCONFIG(TAG, " - Advanced"); + #endif + #ifdef NSPANEL_HA_BLUEPRINT_ADDON_BLUETOOTH_PROXY + ESP_LOGCONFIG(TAG, " - Bluetooth Proxy"); + #endif + #ifdef NSPANEL_HA_BLUEPRINT_ADDON_UPLOAD_TFT + ESP_LOGCONFIG(TAG, " - Upload TFT"); + #endif + #ifdef NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_BASE + ESP_LOGCONFIG(TAG, " - Climate - Base"); + #endif + #ifdef NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_COOL + ESP_LOGCONFIG(TAG, " - Climate - Cool"); + #endif + #ifdef NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_DUAL + ESP_LOGCONFIG(TAG, " - Climate - Dual"); + #endif + #ifdef NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_HEAT + ESP_LOGCONFIG(TAG, " - Climate - Heat"); + #endif + #ifdef NSPANEL_HA_BLUEPRINT_PREBUILT + ESP_LOGCONFIG(TAG, " - Pre-built"); + #endif + #ifdef NSPANEL_HA_BLUEPRINT_PREBUILT_WALL_DISPLAY + ESP_LOGCONFIG(TAG, " - Pre-built (Wall Display)"); + #endif + #if defined(USE_BLUETOOTH_PROXY) || defined(USE_WEBSERVER) || defined(USE_CAPTIVE_PORTAL) + ESP_LOGCONFIG(TAG, "Components:"); + #ifdef USE_ESP32_BLE_SERVER + ESP_LOGCONFIG(TAG, " - BLE server"); + #endif + #ifdef USE_ESP32_BLE_CLIENT + ESP_LOGCONFIG(TAG, " - BLE tracker"); + #endif + #ifdef USE_BLUETOOTH_PROXY + ESP_LOGCONFIG(TAG, " - Bluetooth proxy"); + #endif + #ifdef USE_CAPTIVE_PORTAL + ESP_LOGCONFIG(TAG, " - Captive portal"); + #endif + #ifdef USE_IMPROV + ESP_LOGCONFIG(TAG, " - Improv (BLE)"); + #endif + #ifdef USE_WEBSERVER + ESP_LOGCONFIG(TAG, " - Web server"); + #endif + #endif + } + - id: global_settings mode: restart parameters: @@ -2121,7 +2335,6 @@ script: screensaver_time_font: int screensaver_time_color: int32_t[] decimal_separator: string - # bytes_per_char: int then: - lambda: |- if (!id(is_uploading_tft)) { @@ -2133,7 +2346,6 @@ script: // MUI strings id(mui_please_confirm_global) = mui_please_confirm; id(mui_unavailable_global) = mui_unavailable; - // id(mui_bytes_per_char) = bytes_per_char; // Screen saver page (sleep) id(screensaver_display_time) = screensaver_time; @@ -2158,10 +2370,7 @@ script: parameters: page: string then: - - lambda: |- - if (current_page->state != page) { - disp1->goto_page(page.c_str()); - } + - lambda: if (current_page->state != page) disp1->goto_page(page.c_str()); - id: ha_button mode: parallel @@ -2177,6 +2386,7 @@ script: ha_event.fire_homeassistant_event("esphome.nspanel_ha_blueprint", { {"device_name", device_name->state.c_str()}, + {"esphome_version", "${version}"}, {"type", "button_click"}, {"page", page}, {"component", component}, @@ -2197,6 +2407,7 @@ script: ha_event.fire_homeassistant_event("esphome.nspanel_ha_blueprint", { {"device_name", device_name->state.c_str()}, + {"esphome_version", "${version}"}, {"type", "service_call"}, {"service", service}, {"key", key}, @@ -2235,7 +2446,7 @@ script: #elif defined(USE_ESP_IDF) disp1->set_component_text("framework", "ESP-IDF"); #endif - disp1->send_command_printf("tm_esphome.en=0"); + disp1->send_command("tm_esphome.en=0"); - id: page_boot mode: single @@ -2305,6 +2516,7 @@ script: ha_event.fire_homeassistant_event("esphome.nspanel_ha_blueprint", { {"device_name", device_name->state.c_str()}, + {"esphome_version", "${version}"}, {"type", "boot"}, {"step", "nextion_init"} }); @@ -2324,6 +2536,9 @@ script: disp1->set_component_font("home.wifi_icon", id(home_chip_font_id)); disp1->set_component_font_color("home.chip_relay1", id(home_relay1_icon_color)); disp1->set_component_font_color("home.chip_relay2", id(home_relay2_icon_color)); + #if defined(USE_ESP32_BLE_SERVER) || defined(USE_ESP32_BLE_CLIENT) || defined(USE_BLUETOOTH_PROXY) || defined(USE_IMPROV) + disp1->set_component_text("home.bt_icon", "\uE0AE"); + #endif boot_progress->execute(8); - wait_until: condition: @@ -2390,7 +2605,7 @@ script: current_page->state != "confirm" && current_page->state != "keyb_num") { detailed_entity->publish_state(""); - disp1->send_command_printf("back_page_id=1"); + disp1->send_command("back_page_id=1"); } if (current_page->state != "media_player") { id(last_volume_level) = 0; @@ -2412,6 +2627,7 @@ script: ha_event.fire_homeassistant_event("esphome.nspanel_ha_blueprint", { {"device_name", device_name->state.c_str()}, + {"esphome_version", "${version}"}, {"type", "page_changed"}, {"page", current_page->state.c_str()}, {"entity", detailed_entity->state.c_str()} @@ -2640,7 +2856,7 @@ script: #if ESPHOME_LOG_LEVEL > ESPHOME_LOG_LEVEL_DEBUG ESP_LOGV("script.refresh_hardware_buttons_bars", "Page: %s", current_page->state.c_str()); ESP_LOGV("script.refresh_hardware_buttons_bars", "Page id: %i", get_page_id(current_page->state.c_str())); - ESP_LOGV("script.refresh_hardware_buttons_bars", "buttons_bars_pages: %i", id(buttons_bars_pages)); + ESP_LOGV("script.refresh_hardware_buttons_bars", "buttons_bars_pages: %" PRIu32, id(buttons_bars_pages)); ESP_LOGV("script.refresh_hardware_buttons_bars", "relay_settings: %i", id(relay_settings)); ESP_LOGV("script.refresh_hardware_buttons_bars", "button_mask: %i", button_mask); #endif @@ -2776,20 +2992,11 @@ script: parameters: brightness: float then: - - if: - condition: - - lambda: return (!id(is_uploading_tft)); - then: - - lambda: |- - if (!id(is_uploading_tft)) { - if (brightness == display_brightness->state and current_page->state != "boot" and current_page->state != "screensaver") - disp1->send_command_printf("wakeup_timer.en=1"); - else - disp1->set_backlight_brightness(brightness / 100.0f); - current_brightness->update(); - } - - delay: 5s - - lambda: if (!id(is_uploading_tft)) current_brightness->update(); + - lambda: |- + if (!id(is_uploading_tft)) { + disp1->set_backlight_brightness(brightness / 100.0f); + current_brightness->update(); + } - id: set_climate mode: restart @@ -2908,6 +3115,7 @@ script: check_versions->stop(); display_embedded_temp->stop(); display_wrapped_text->stop(); + dump_config->stop(); global_settings->stop(); ha_button->stop(); ha_call_service->stop(); @@ -2959,7 +3167,6 @@ script: update_alarm_icon->stop(); update_climate_icon->stop(); update_tft_info->stop(); - watchdog->stop(); ###### Timers ###### - id: timer_reset_all # Global timer reset - Triggered with a touch on the screen @@ -3174,162 +3381,4 @@ script: condition: - lambda: return (!isnan(display_charset->state) and !isnan(display_mode->state) and !(version_tft->state.empty())); timeout: 10s - - - id: watchdog - mode: restart - then: - - lambda: |- - #include - static const char *const TAG = "script.watchdog"; - if (id(is_uploading_tft)) { - ESP_LOGW(TAG, "TFT upload in progress"); - } else { - // report Wi-Fi status - bool wifi_connected = wifi_component->is_connected(); - if (wifi_connected) { - float rssi = wifi_rssi->state; - const char *rssi_status = "Unknown"; // Use const char* to avoid dynamic memory allocation - if (rssi > -50) rssi_status = "Excellent"; - else if (rssi > -60) rssi_status = "Good"; - else if (rssi > -70) rssi_status = "Fair"; - else if (rssi > -80) rssi_status = "Weak"; - else rssi_status = "Poor"; - if (rssi > -70) ESP_LOGI(TAG, "Wi-Fi: %s (%.0f dBm)", rssi_status, rssi); - else if (rssi > -80) ESP_LOGW(TAG, "Wi-Fi: %s (%.0f dBm)", rssi_status, rssi); - else ESP_LOGE(TAG, "Wi-Fi: %s (%.0f dBm)", rssi_status, rssi); - } - else { - ESP_LOGW(TAG, "Wi-Fi: DISCONNECTED"); - ESP_LOGI(TAG, "Retrying Wi-Fi connection"); - wifi_component->retry_connect(); - } - - // report API status - bool api_connected = api_server->is_connected(); - if (api_connected) { - ESP_LOGI(TAG, "API: Connected"); - } else { - ESP_LOGW(TAG, "API: DISCONNECTED"); - blueprint_status->publish_state(0); - if (current_page->state != "blank" and - current_page->state != "boot" and - current_page->state != "home" and - current_page->state != "screensaver" and - current_page->state != "settings" and - current_page->state != "qrcode") { - ESP_LOGI(TAG, "Fallback to page Home"); - disp1->goto_page("home"); - } - } - - if (!wifi_connected or !api_connected) blueprint_status->publish_state(0); - - // Report blueprint version - ESP_LOGI(TAG, "Blueprint:"); - if (blueprint_status->state > 99) { - ESP_LOGI(TAG, " Version: %s", version_blueprint->state.c_str()); - ESP_LOGI(TAG, " Init steps: %i (%0.1f%%)", int(blueprint_status->raw_state), blueprint_status->state); - } else { - ESP_LOGW(TAG, " Init steps: %i (%0.1f%%)", int(blueprint_status->raw_state), blueprint_status->state); - ESP_LOGW(TAG, " State: %s", (wifi_connected and api_connected) ? "Pending" : "DISCONNECTED"); - ESP_LOGI(TAG, "Requesting blueprint settings"); - boot_event->execute(false); - } - - // Report ESPHome - ESP_LOGI(TAG, "ESPHome:"); - ESP_LOGI(TAG, " Version: ${version}"); - ESP_LOGI(TAG, " Compiler: %s", ESPHOME_VERSION); - // Report framework - #ifdef ARDUINO - ESP_LOGI(TAG, " Framework: Arduino"); - #elif defined(USE_ESP_IDF) - ESP_LOGI(TAG, " Framework: ESP-IDF"); - #endif - // Report memory - const size_t internal_heap_size = heap_caps_get_total_size(MALLOC_CAP_INTERNAL); - const size_t internal_heap_size_free = heap_caps_get_free_size(MALLOC_CAP_INTERNAL); - const size_t psram_heap_size = heap_caps_get_total_size(MALLOC_CAP_SPIRAM); - const size_t psram_heap_size_free = heap_caps_get_free_size(MALLOC_CAP_SPIRAM); - ESP_LOGI(TAG, " Free heap:"); - - if (internal_heap_size != 0) { - ESP_LOGI(TAG, " Internal: %7d bytes (%0.1f%%)", internal_heap_size_free, - ((float)internal_heap_size_free / internal_heap_size) * 100.0f); - } else { - ESP_LOGI(TAG, " Internal: %7d bytes", internal_heap_size_free); - } - - if (psram_heap_size != 0) { - ESP_LOGI(TAG, " PSRAM: %7d bytes (%0.1f%%)", psram_heap_size_free, - ((float)psram_heap_size_free / psram_heap_size) * 100.0f); - } else { - ESP_LOGI(TAG, " PSRAM: %7d bytes", psram_heap_size_free); - } - // Report UART - ESP_LOGI(TAG, "UART:"); - ESP_LOGI(TAG, " Baud rate: %" PRIu32 " bps", tf_uart->get_baud_rate()); - ESP_LOGI(TAG, " Queue size: %d", tf_uart->available()); - - // Report Nextion status - nextion_init->publish_state(nextion_init->state and disp1->is_setup()); - ESP_LOGI(TAG, "Nextion:"); - ESP_LOGI(TAG, " Queue size: %d", disp1->queue_size()); - if (disp1->is_setup()) - ESP_LOGI(TAG, " Is setup: True"); - else { - ESP_LOGW(TAG, " Is setup: False"); - ESP_LOGW(TAG, " Is detected: %s", YESNO(disp1->is_detected())); - //exit_reparse->execute(); - } - if (nextion_init->state) { - ESP_LOGI(TAG, " Init: True"); - } else - ESP_LOGW(TAG, " Init: False"); - if (version_tft->state.empty()) - ESP_LOGW(TAG, " TFT: UNKNOWN"); - else - ESP_LOGI(TAG, " TFT: %s", version_tft->state.c_str()); - ESP_LOGI(TAG, "Packages:"); - #ifdef NSPANEL_HA_BLUEPRINT_CORE - ESP_LOGI(TAG, " - Core"); - #endif - #ifdef NSPANEL_HA_BLUEPRINT_ADVANCED - ESP_LOGI(TAG, " - Advanced"); - #endif - #ifdef NSPANEL_HA_BLUEPRINT_ADDON_UPLOAD_TFT - ESP_LOGI(TAG, " - Upload TFT"); - #endif - #ifdef NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_BASE - ESP_LOGI(TAG, " - Climate - Base"); - #endif - #ifdef NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_COOL - ESP_LOGI(TAG, " - Climate - Cool"); - #endif - #ifdef NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_DUAL - ESP_LOGI(TAG, " - Climate - Dual"); - #endif - #ifdef NSPANEL_HA_BLUEPRINT_ADDON_CLIMATE_HEAT - ESP_LOGI(TAG, " - Climate - Heat"); - #endif - #ifdef NSPANEL_HA_BLUEPRINT_PREBUILT - ESP_LOGI(TAG, " - Pre-built"); - #endif - #ifdef NSPANEL_HA_BLUEPRINT_PREBUILT_WALL_DISPLAY - ESP_LOGI(TAG, " - Pre-built (Wall Display)"); - #endif - #if defined(USE_BLUETOOTH_PROXY) || defined(USE_WEBSERVER) || defined(USE_CAPTIVE_PORTAL) - ESP_LOGI(TAG, "Non-standard components:"); - #ifdef USE_CAPTIVE_PORTAL - ESP_LOGI(TAG, " - Captive portal"); - #endif - #ifdef USE_BLUETOOTH_PROXY - ESP_LOGI(TAG, " - Bluetooth proxy"); - #endif - #ifdef USE_WEBSERVER - ESP_LOGI(TAG, " - Web server"); - #endif - #endif - refresh_wifi_icon->execute(); - } ... diff --git a/hmi/dev/nspanel_CJK_eu_code/alarm.txt b/hmi/dev/nspanel_CJK_eu_code/alarm.txt index f7bdd14..1f1f2c8 100644 --- a/hmi/dev/nspanel_CJK_eu_code/alarm.txt +++ b/hmi/dev/nspanel_CJK_eu_code/alarm.txt @@ -12,6 +12,7 @@ Page alarm Events Preinitialize Event + dim=brightness if(api==0) { page home @@ -23,7 +24,6 @@ Page alarm vis bt_vacat,0 vis bt_bypass,0 } - vis unavailable,0 printh 92 prints "current_page",0 printh 00 @@ -192,16 +192,6 @@ Text bt_disarm_icon Text :  Max. Text Size : 3 -Text unavailable - Attributes - ID : 32 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Picture bt_home_pic Attributes ID : 4 @@ -402,26 +392,3 @@ Hotspot bt_disarm printh 00 printh FF FF FF -Timer wakeup_timer - Attributes - ID : 31 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 29 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 29 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 29 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 29 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim1) { @@ -304,16 +304,6 @@ Text page_index Text : Max. Text Size : 12 -Text unavailable - Attributes - ID : 31 - Scope : local - Dragging : 0 - Send Component ID : disabled - Associated Keyboard: none - Text : - Max. Text Size : 1 - Button button_back Attributes ID : 28 @@ -340,29 +330,6 @@ Timer swipestore swipex=tch0 swipey=tch1 -Timer wakeup_timer - Attributes - ID : 30 - Scope : local - Period (ms): 100 - Enabled : yes - - Events - Timer Event - if(dim # NSPanel Configuration via Blueprint: Complete UI-Based Setup - **Version**: v4.3.4 + **Version**: v4.3.5 This project enables comprehensive configuration of your NSPanel through a Blueprint featuring a user interface. @@ -3650,11 +3650,11 @@ blueprint: description: > Adjusts the delay between sequential commands to the Nextion display, preventing overload and synchronization issues. While increasing delay enhances stability, it may slow down page rendering. - default: 1 + default: 10 selector: number: min: 0 - max: 100 + max: 250 step: 1 unit_of_measurement: milliseconds mode: box @@ -3801,13 +3801,6 @@ trigger_variables: if nspanel_entities | selectattr(None, "search", "sensor.*_current_page") | list | count > 0 else ("sensor." ~ device_name ~ "_current_page") }} - detailed_entity: > - {{ - nspanel_entities | selectattr(None, "search", "sensor.*_detailed_entity") | list | last - if nspanel_entities | selectattr(None, "search", "sensor.*_detailed_entity") | list | count > 0 - else ("sensor." ~ device_name ~ "_detailed_entity") - }} - nspaneltemp: > {{ nspanel_entities | selectattr(None, "search", "sensor.*_temperature") | list | last @@ -3833,7 +3826,7 @@ trigger_variables: group06: !input utilities_page01_group06_line_reference variables: - blueprint_version: '4.3.4' + blueprint_version: '4.3.5' pages: current: '{{ states(currentpage) }}' home: "home" @@ -3879,6 +3872,20 @@ variables: }} embedded_indoor_temperature: '{{ indoor_temperature_sensor == nspaneltemp }}' + nextion_display_sensor: > + {{ + nspanel_entities | selectattr(None, "search", "sensor.*_nextion_display") | list | last + if nspanel_entities | selectattr(None, "search", "sensor.*_nextion_display") | list | count > 0 + else ("sensor." ~ device_name ~ "_nextion_display") + }} + + detailed_entity: > + {{ + nspanel_entities | selectattr(None, "search", "sensor.*_detailed_entity") | list | last + if nspanel_entities | selectattr(None, "search", "sensor.*_detailed_entity") | list | count > 0 + else ("sensor." ~ device_name ~ "_detailed_entity") + }} + # yamllint disable rule:indentation rule:comments-indentation trigger: ##### Trigger - General ################################################################################################################# @@ -4657,7 +4664,11 @@ trigger: # yamllint disable rule:line-length condition: - - '{{ trigger.id in ["automation_reloaded", "ha_started", "nspanel_event"] or has_value(device_name_sensor) }}' + - > # Trigger is coming from panel's event or Nextion display must be connected + {{ + trigger.id in ["automation_reloaded", "ha_started", "nspanel_event"] or + (states(nextion_display_sensor) | default(false) and has_value(device_name_sensor)) + }} - > # Update page Home only when visible or home_page_background_update is enabled {{ trigger.id not in ["home_values_state", "trigger_chip_state"] or @@ -4721,6 +4732,29 @@ action: else device_name ) }} + + esphome_version: > + {% + set esphome_version_sensor = + nspanel_entities | selectattr(None, "search", "sensor.*_esphome_version") | list | last + if nspanel_entities | selectattr(None, "search", "sensor.*_esphome_version") | list | count > 0 + else ("sensor." ~ device_name ~ "_esphome_version") + %} + {{ + version(trigger.event.data.esphome_version) + if + trigger is defined and + trigger.event is defined and + trigger.event.data is defined and + trigger.event.data.esphome_version is defined and + trigger.event.data.esphome_version is string and trigger.event.data.esphome_version | length > 0 + else + ( + version(states(esphome_version_sensor)) + if has_value(esphome_version_sensor) + else version("0.0.0") + ) + }} date_format_temp: !input 'date_format' # Avoid breaking change for existing users with legacy type format date_format: '{{ date_format_temp if date_format_temp not in ["%d.%m", "%d/%m", "%-d/%-m", "%-m/%-d"] else "%A, " ~ date_format_temp }}' @@ -7974,7 +8008,6 @@ action: "off": ["locked"] # yamllint enable rule:truthy rule:line-length rule:comments-indentation - - if: '{{ false }}' #### Global anchor repository #### then: - variables: @@ -8227,7 +8260,7 @@ action: timezone: !input timezone ##### Timezone ##### - - if: '{{ timezone is string and timezone | length > 1 }}' + - if: '{{ timezone is string and timezone | length > 1 and esphome_version >= "4.3.4" }}' then: - variables: timezone_code: > @@ -8419,7 +8452,7 @@ action: climate_friendly_name: '{{ state_attr(climate, "friendly_name") if climate_entity_id_valid else "" }}' hw_buttons_bars_pages: !input hw_buttons_bars_pages - - if: '{{ not climate_entity_id_valid }}' + - if: '{{ esphome_version >= "4.3.4" }}' then: - *delay_default - service: 'esphome.{{ nspanel_name }}_set_bool' @@ -8958,7 +8991,7 @@ action: id: '{{ repeat.item.page }}.{{ repeat.item.component }}_icon' txt: '{{ entity.icon }}' continue_on_error: true - - if: '{{ overlap.icon_color is not sequence }}' # Do not color icon if it has overlap + - if: '{{ entity.icon_color != [200, 204, 200] }}' then: - *delay_default - service: 'esphome.{{ nspanel_name }}_component_color' @@ -9114,25 +9147,48 @@ action: conditions: '{{ nspanel_event.page == pages.light }}' sequence: &refresh_page_light - variables: - light_entity: > + entity_id: > {{ nspanel_event.entity if nspanel_event is defined and nspanel_event.entity is defined else (trigger.entity_id if trigger.entity_id is defined else trigger.event.data.entity_id) }} - supported_color_modes: '{{ state_attr(light_entity, "supported_color_modes") | default("unknown") }}' + - &variables_light_modes + variables: + supported_features: '{{ state_attr(entity_id, "supported_features") | int(0) }}' + supported_color_modes: '{{ state_attr(entity_id, "supported_color_modes") | default("unknown") }}' + color_mode_brightness: > + {{ + supported_features | bitwise_and(1) > 0 or + enum.ColorMode.BRIGHTNESS in supported_color_modes or + "brightness" in supported_color_modes or + state_attr(entity_id, "brightness") | int(-1) >= 0 + }} color_mode_color: > {{ - "hs" in supported_color_modes - or "xy" in supported_color_modes - or "rgb" in supported_color_modes - or "rgbw" in supported_color_modes - or "rgbww" in supported_color_modes + supported_features | bitwise_and(16) > 0 or + enum.ColorMode.HS in supported_color_modes or + enum.ColorMode.XY in supported_color_modes or + enum.ColorMode.RGB in supported_color_modes or + enum.ColorMode.RGBW in supported_color_modes or + enum.ColorMode.RGBWW in supported_color_modes or + "hs" in supported_color_modes or + "xy" in supported_color_modes or + "rgb" in supported_color_modes or + "rgbw" in supported_color_modes or + "rgbww" in supported_color_modes or + state_attr(entity_id, "rgb_color") is sequence + }} + color_mode_color_temp: > + {{ + supported_features | bitwise_and(2) > 0 or + enum.ColorMode.COLOR_TEMP in supported_color_modes or + "color_temp" in supported_color_modes or + state_attr(entity_id, "color_temp") | int(-1) >= 0 }} - color_mode_color_temp: '{{ "color_temp" in supported_color_modes }}' ##### LIGHT State ##### - variables: - curr_brightness: '{{ (state_attr(light_entity, "brightness") | int(0) * 100 / 255) | round(0) }}' + curr_brightness: '{{ (state_attr(entity_id, "brightness") | int(0) * 100 / 255) | round(0) }}' - *delay_default - service: 'esphome.{{ nspanel_name }}_component_val' data: @@ -9156,9 +9212,9 @@ action: - if: '{{ color_mode_color_temp }}' then: - variables: - curr_color_temp: '{{ state_attr(light_entity, "color_temp") | int(-1) }}' - min_mireds: '{{ state_attr(light_entity, "min_mireds") | int(153) }}' - max_mireds: '{{ state_attr(light_entity, "max_mireds") | int(500) }}' + curr_color_temp: '{{ state_attr(entity_id, "color_temp") | int(-1) }}' + min_mireds: '{{ state_attr(entity_id, "min_mireds") | int(153) }}' + max_mireds: '{{ state_attr(entity_id, "max_mireds") | int(500) }}' - variables: curr_color_temp: > {{ @@ -10337,6 +10393,7 @@ action: - variables: utilities_constructor_init: true page_icon: '{{ pages_utilities.title.icon.split("mdi:")[1] if pages_utilities.title.icon is string and pages_utilities.title.icon.split("mdi:") | count == 2 }}' + - *delay_default - service: 'esphome.{{ nspanel_name }}_value' data: id: utilities.title @@ -10373,6 +10430,7 @@ action: then: - variables: icon_code: '{{ repeat.item.icon.split("mdi:")[1] }}' + - *delay_default - service: 'esphome.{{ nspanel_name }}_icon' data: id: '{{ repeat.item.name }}_icon' @@ -10383,16 +10441,19 @@ action: - alias: Utilities - Label if: '{{ label_enabled }}' then: + - *delay_default - service: 'esphome.{{ nspanel_name }}_component_text' data: id: '{{ repeat.item.name }}_label' txt: '{{ repeat.item.label }}' continue_on_error: true + - *delay_default - service: 'esphome.{{ nspanel_name }}_component_color' data: id: '{{ repeat.item.name }}_label' color: '{{ repeat.item.color }}' continue_on_error: true + - *delay_default - service: 'esphome.{{ nspanel_name }}_components_visibility' data: ids: '{{ [repeat.item.name ~ "_label"] }}' @@ -10415,6 +10476,7 @@ action: entity_id: '{{ repeat.item.value1 }}' unit_of_measurement: '{{ state_attr(entity_id, "unit_of_measurement") | default("") }}' - *variable_entity + - *delay_default - service: 'esphome.{{ nspanel_name }}_utilities_group_refresh' data: group_id: '{{ repeat.item.name }}' @@ -10424,11 +10486,13 @@ action: continue_on_error: true - if: '{{ utilities_constructor }}' then: + - *delay_default - service: 'esphome.{{ nspanel_name }}_component_color' data: id: '{{ repeat.item.name }}' color: '{{ repeat.item.color }}' continue_on_error: true + - *delay_default - service: 'esphome.{{ nspanel_name }}_components_visibility' data: ids: '{{ [repeat.item.name] }}' @@ -10441,6 +10505,7 @@ action: entity_id: '{{ repeat.item.value2 }}' unit_of_measurement: '{{ state_attr(entity_id, "unit_of_measurement") | default("") }}' - *variable_entity + - *delay_default - service: 'esphome.{{ nspanel_name }}_utilities_group_refresh' data: group_id: '{{ repeat.item.name }}' @@ -10450,11 +10515,13 @@ action: continue_on_error: true - if: '{{ utilities_constructor }}' then: + - *delay_default - service: 'esphome.{{ nspanel_name }}_component_color' data: id: '{{ repeat.item.name }}b' color: '{{ repeat.item.color }}' continue_on_error: true + - *delay_default - service: 'esphome.{{ nspanel_name }}_components_visibility' data: ids: '{{ [repeat.item.name ~ "b"] }}' @@ -10468,20 +10535,24 @@ action: then: - variables: rgb565: '{{ int(((repeat.item.color[0] //(2**3)) *(2**11))+((repeat.item.color[1] //(2**2)) *(2**5))+(repeat.item.color[2] //(2**3))) }}' + - *delay_default - service: 'esphome.{{ nspanel_name }}_command' data: cmd: '{{ repeat.item.name }}_line.bco={{ rgb565 }}' continue_on_error: true + - *delay_default - service: 'esphome.{{ nspanel_name }}_command' data: cmd: '{{ repeat.item.name }}_line.bco1={{ rgb565 }}' continue_on_error: true - if: '{{ pages_utilities.cursor.width != 255 }}' then: + - *delay_default - service: 'esphome.{{ nspanel_name }}_command' data: cmd: '{{ repeat.item.name }}_line.wid={{ pages_utilities.cursor.width }}' continue_on_error: true + - *delay_default - service: 'esphome.{{ nspanel_name }}_components_visibility' data: ids: '{{ [repeat.item.name ~ "_line"] }}' @@ -10519,6 +10590,7 @@ action: - &entity_details_show if: '{{ true }}' then: + - *delay_default - service: 'esphome.{{ nspanel_name }}_entity_details_show' data: entity: '{{ "embedded_climate" if entity_id == thermostat_embedded else entity_id }}' @@ -10682,25 +10754,13 @@ action: name: '{{ last_click_button.name if last_click_button.name is defined else None }}' - *variable_entity - condition: '{{ entity_id_valid }}' - - variables: - supported_features: '{{ state_attr(entity_id, "supported_features") | int(0) }}' - supported_color_modes: '{{ state_attr(entity_id, "supported_color_modes") | default([]) }}' + - *variables_light_modes - if: > {{ entity_domain in ["alarm_control_panel", "climate", "media_player"] or (entity_domain == "cover" and supported_features | bitwise_and(4) > 0) or (entity_domain == "fan" and (supported_features | bitwise_and(1) > 0 or supported_features | bitwise_and(2) > 0)) or - ( - entity_domain == "light" and - ( - supported_features | bitwise_and(1) > 0 or - supported_features | bitwise_and(2) > 0 or - supported_features | bitwise_and(16) > 0 or - enum.ColorMode.BRIGHTNESS in supported_color_modes or - enum.ColorMode.COLOR_TEMP in supported_color_modes or - enum.ColorMode.RGB in supported_color_modes - ) - ) + (entity_domain == "light" and (color_mode_brightness or color_mode_color or color_mode_temp)) }} then: - variables: @@ -11229,6 +11289,7 @@ action: ) ) in enum.states.on }} + - *delay_default - service: 'esphome.{{ nspanel_name }}_hw_button_state' data: button_mask: '{{ 1 if trigger.id in ["left_button_state", "left_button_alt_state"] else 2 }}' @@ -11240,6 +11301,7 @@ action: button_state_new: *button_state_var - if: '{{ button_state_new != button_state }}' then: + - *delay_default - service: 'esphome.{{ nspanel_name }}_hw_button_state' data: button_mask: '{{ 1 if trigger.id in ["left_button_state", "left_button_alt_state"] else 2 }}' @@ -11297,6 +11359,7 @@ action: - condition: trigger id: wake_up_sensors sequence: + - *delay_default - service: 'esphome.{{ nspanel_name }}_wake_up' data: reset_timer: true diff --git a/prebuilt/nspanel_esphome_prebuilt-factory.bin b/prebuilt/nspanel_esphome_prebuilt-factory.bin index 0bded10..3e69a20 100644 Binary files a/prebuilt/nspanel_esphome_prebuilt-factory.bin and b/prebuilt/nspanel_esphome_prebuilt-factory.bin differ diff --git a/prebuilt/nspanel_esphome_prebuilt-factory.bin.md5 b/prebuilt/nspanel_esphome_prebuilt-factory.bin.md5 index 35b4900..a777384 100644 --- a/prebuilt/nspanel_esphome_prebuilt-factory.bin.md5 +++ b/prebuilt/nspanel_esphome_prebuilt-factory.bin.md5 @@ -1 +1 @@ -f5ff2ee0594cf8ea5c5569b84a3865ed prebuilt/nspanel_esphome_prebuilt-factory.bin +c8016077cb28df7cb82b0383f484b328 prebuilt/nspanel_esphome_prebuilt-factory.bin diff --git a/prebuilt/nspanel_esphome_prebuilt.bin b/prebuilt/nspanel_esphome_prebuilt.bin index cc8c2a2..4dd185e 100644 Binary files a/prebuilt/nspanel_esphome_prebuilt.bin and b/prebuilt/nspanel_esphome_prebuilt.bin differ diff --git a/prebuilt/nspanel_esphome_prebuilt.bin.md5 b/prebuilt/nspanel_esphome_prebuilt.bin.md5 index f40e03b..ad66efc 100644 --- a/prebuilt/nspanel_esphome_prebuilt.bin.md5 +++ b/prebuilt/nspanel_esphome_prebuilt.bin.md5 @@ -1 +1 @@ -29b180e01121a636e080a90efb1690b8 prebuilt/nspanel_esphome_prebuilt.bin +53d04b61095a8e53fbf141933f81f040 prebuilt/nspanel_esphome_prebuilt.bin diff --git a/prebuilt/nspanel_esphome_prebuilt.yaml b/prebuilt/nspanel_esphome_prebuilt.yaml index 91bca8b..23fbfea 100644 --- a/prebuilt/nspanel_esphome_prebuilt.yaml +++ b/prebuilt/nspanel_esphome_prebuilt.yaml @@ -57,14 +57,22 @@ button: ESP_LOGE(TAG, "Firmware update failed!"); captive_portal: + id: ap_captive_portal dashboard_import: package_import_url: github://Blackymas/NSPanel_HA_Blueprint/prebuilt/nspanel_esphome_prebuilt.yaml@main import_full_config: false +esp32_ble: + id: ble + esp32_improv: + id: ble_improv authorizer: none +esp32_ble_server: + id: ble_server + esphome: name_add_mac_suffix: true project: @@ -75,6 +83,7 @@ esphome: - -D NSPANEL_HA_BLUEPRINT_PREBUILT improv_serial: + id: serial_improv logger: baud_rate: 115200 @@ -115,7 +124,6 @@ text: - lambda: |- ESP_LOGD("text.fw_url", "New Firmware URL set: %s", x.c_str()); - wifi: networks: !remove ap: {} diff --git a/prebuilt/wall_display-factory.bin b/prebuilt/wall_display-factory.bin index 609c406..2f9507e 100644 Binary files a/prebuilt/wall_display-factory.bin and b/prebuilt/wall_display-factory.bin differ diff --git a/prebuilt/wall_display-factory.bin.md5 b/prebuilt/wall_display-factory.bin.md5 index d4e7487..3dc34e3 100644 --- a/prebuilt/wall_display-factory.bin.md5 +++ b/prebuilt/wall_display-factory.bin.md5 @@ -1 +1 @@ -045b898a2d5f533cdfab5d304283b9d3 prebuilt/wall_display-factory.bin +c3d6bfb1bf1eb452fe62fffb7e1e174d prebuilt/wall_display-factory.bin diff --git a/prebuilt/wall_display.bin b/prebuilt/wall_display.bin index e1b300e..83ec5a4 100644 Binary files a/prebuilt/wall_display.bin and b/prebuilt/wall_display.bin differ diff --git a/prebuilt/wall_display.bin.md5 b/prebuilt/wall_display.bin.md5 index 990d8a2..b638c35 100644 --- a/prebuilt/wall_display.bin.md5 +++ b/prebuilt/wall_display.bin.md5 @@ -1 +1 @@ -ed38877819c1d00ea3957c1c9045f2ab prebuilt/wall_display.bin +eff812d46f305262611476b13fb8326c prebuilt/wall_display.bin