mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-04 09:01:49 +00:00 
			
		
		
		
	Merge branch 'dev' into jesserockz-2023-304
This commit is contained in:
		
							
								
								
									
										4
									
								
								.github/actions/restore-python/action.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/actions/restore-python/action.yml
									
									
									
									
										vendored
									
									
								
							@@ -17,12 +17,12 @@ runs:
 | 
			
		||||
  steps:
 | 
			
		||||
    - name: Set up Python ${{ inputs.python-version }}
 | 
			
		||||
      id: python
 | 
			
		||||
      uses: actions/setup-python@v4.6.0
 | 
			
		||||
      uses: actions/setup-python@v4.7.0
 | 
			
		||||
      with:
 | 
			
		||||
        python-version: ${{ inputs.python-version }}
 | 
			
		||||
    - name: Restore Python virtual environment
 | 
			
		||||
      id: cache-venv
 | 
			
		||||
      uses: actions/cache/restore@v3.3.1
 | 
			
		||||
      uses: actions/cache/restore@v3.3.2
 | 
			
		||||
      with:
 | 
			
		||||
        path: venv
 | 
			
		||||
        # yamllint disable-line rule:line-length
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								.github/workflows/ci-docker.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/ci-docker.yml
									
									
									
									
										vendored
									
									
								
							@@ -40,15 +40,15 @@ jobs:
 | 
			
		||||
        arch: [amd64, armv7, aarch64]
 | 
			
		||||
        build_type: ["ha-addon", "docker", "lint"]
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@v4
 | 
			
		||||
      - uses: actions/checkout@v4.0.0
 | 
			
		||||
      - name: Set up Python
 | 
			
		||||
        uses: actions/setup-python@v4
 | 
			
		||||
        uses: actions/setup-python@v4.7.0
 | 
			
		||||
        with:
 | 
			
		||||
          python-version: "3.9"
 | 
			
		||||
      - name: Set up Docker Buildx
 | 
			
		||||
        uses: docker/setup-buildx-action@v2
 | 
			
		||||
        uses: docker/setup-buildx-action@v3.0.0
 | 
			
		||||
      - name: Set up QEMU
 | 
			
		||||
        uses: docker/setup-qemu-action@v2
 | 
			
		||||
        uses: docker/setup-qemu-action@v3.0.0
 | 
			
		||||
 | 
			
		||||
      - name: Set TAG
 | 
			
		||||
        run: |
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										56
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										56
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							@@ -7,6 +7,10 @@ on:
 | 
			
		||||
    branches: [dev, beta, release]
 | 
			
		||||
 | 
			
		||||
  pull_request:
 | 
			
		||||
    paths:
 | 
			
		||||
      - "**"
 | 
			
		||||
      - "!.github/workflows/*.yml"
 | 
			
		||||
      - ".github/workflows/ci.yml"
 | 
			
		||||
  merge_group:
 | 
			
		||||
 | 
			
		||||
permissions:
 | 
			
		||||
@@ -30,13 +34,13 @@ jobs:
 | 
			
		||||
      cache-key: ${{ steps.cache-key.outputs.key }}
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code from GitHub
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v4.0.0
 | 
			
		||||
      - name: Generate cache-key
 | 
			
		||||
        id: cache-key
 | 
			
		||||
        run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT
 | 
			
		||||
      - name: Set up Python ${{ env.DEFAULT_PYTHON }}
 | 
			
		||||
        id: python
 | 
			
		||||
        uses: actions/setup-python@v4.6.0
 | 
			
		||||
        uses: actions/setup-python@v4.7.0
 | 
			
		||||
        with:
 | 
			
		||||
          python-version: ${{ env.DEFAULT_PYTHON }}
 | 
			
		||||
      - name: Restore Python virtual environment
 | 
			
		||||
@@ -55,15 +59,6 @@ jobs:
 | 
			
		||||
          pip install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt
 | 
			
		||||
          pip install -e .
 | 
			
		||||
 | 
			
		||||
  yamllint:
 | 
			
		||||
    name: yamllint
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code from GitHub
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
      - name: Run yamllint
 | 
			
		||||
        uses: frenck/action-yamllint@v1.4.1
 | 
			
		||||
 | 
			
		||||
  black:
 | 
			
		||||
    name: Check black
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
@@ -71,7 +66,7 @@ jobs:
 | 
			
		||||
      - common
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code from GitHub
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v4.0.0
 | 
			
		||||
      - name: Restore Python
 | 
			
		||||
        uses: ./.github/actions/restore-python
 | 
			
		||||
        with:
 | 
			
		||||
@@ -92,7 +87,7 @@ jobs:
 | 
			
		||||
      - common
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code from GitHub
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v4.0.0
 | 
			
		||||
      - name: Restore Python
 | 
			
		||||
        uses: ./.github/actions/restore-python
 | 
			
		||||
        with:
 | 
			
		||||
@@ -113,7 +108,7 @@ jobs:
 | 
			
		||||
      - common
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code from GitHub
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v4.0.0
 | 
			
		||||
      - name: Restore Python
 | 
			
		||||
        uses: ./.github/actions/restore-python
 | 
			
		||||
        with:
 | 
			
		||||
@@ -134,7 +129,7 @@ jobs:
 | 
			
		||||
      - common
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code from GitHub
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v4.0.0
 | 
			
		||||
      - name: Restore Python
 | 
			
		||||
        uses: ./.github/actions/restore-python
 | 
			
		||||
        with:
 | 
			
		||||
@@ -155,7 +150,7 @@ jobs:
 | 
			
		||||
      - common
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code from GitHub
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v4.0.0
 | 
			
		||||
      - name: Restore Python
 | 
			
		||||
        uses: ./.github/actions/restore-python
 | 
			
		||||
        with:
 | 
			
		||||
@@ -176,7 +171,7 @@ jobs:
 | 
			
		||||
      - common
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code from GitHub
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v4.0.0
 | 
			
		||||
      - name: Restore Python
 | 
			
		||||
        uses: ./.github/actions/restore-python
 | 
			
		||||
        with:
 | 
			
		||||
@@ -196,7 +191,7 @@ jobs:
 | 
			
		||||
      - common
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code from GitHub
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v4.0.0
 | 
			
		||||
      - name: Restore Python
 | 
			
		||||
        uses: ./.github/actions/restore-python
 | 
			
		||||
        with:
 | 
			
		||||
@@ -215,6 +210,17 @@ jobs:
 | 
			
		||||
        run: script/ci-suggest-changes
 | 
			
		||||
        if: always()
 | 
			
		||||
 | 
			
		||||
  compile-tests-list:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    outputs:
 | 
			
		||||
      matrix: ${{ steps.set-matrix.outputs.matrix }}
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code from GitHub
 | 
			
		||||
        uses: actions/checkout@v4.0.0
 | 
			
		||||
      - name: Find all YAML test files
 | 
			
		||||
        id: set-matrix
 | 
			
		||||
        run: echo "matrix=$(ls tests/test*.yaml | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT
 | 
			
		||||
 | 
			
		||||
  compile-tests:
 | 
			
		||||
    name: Run YAML test ${{ matrix.file }}
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
@@ -227,24 +233,24 @@ jobs:
 | 
			
		||||
      - pylint
 | 
			
		||||
      - pytest
 | 
			
		||||
      - pyupgrade
 | 
			
		||||
      - yamllint
 | 
			
		||||
      - compile-tests-list
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      max-parallel: 2
 | 
			
		||||
      matrix:
 | 
			
		||||
        file: [1, 2, 3, 3.1, 4, 5, 6, 7, 8, 9, 9.1, 10]
 | 
			
		||||
        file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }}
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code from GitHub
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v4.0.0
 | 
			
		||||
      - name: Restore Python
 | 
			
		||||
        uses: ./.github/actions/restore-python
 | 
			
		||||
        with:
 | 
			
		||||
          python-version: ${{ env.DEFAULT_PYTHON }}
 | 
			
		||||
          cache-key: ${{ needs.common.outputs.cache-key }}
 | 
			
		||||
      - name: Run esphome compile tests/test${{ matrix.file }}.yaml
 | 
			
		||||
      - name: Run esphome compile ${{ matrix.file }}
 | 
			
		||||
        run: |
 | 
			
		||||
          . venv/bin/activate
 | 
			
		||||
          esphome compile tests/test${{ matrix.file }}.yaml
 | 
			
		||||
          esphome compile ${{ matrix.file }}
 | 
			
		||||
 | 
			
		||||
  clang-tidy:
 | 
			
		||||
    name: ${{ matrix.name }}
 | 
			
		||||
@@ -258,7 +264,6 @@ jobs:
 | 
			
		||||
      - pylint
 | 
			
		||||
      - pytest
 | 
			
		||||
      - pyupgrade
 | 
			
		||||
      - yamllint
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      max-parallel: 2
 | 
			
		||||
@@ -295,7 +300,7 @@ jobs:
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code from GitHub
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v4.0.0
 | 
			
		||||
      - name: Restore Python
 | 
			
		||||
        uses: ./.github/actions/restore-python
 | 
			
		||||
        with:
 | 
			
		||||
@@ -341,7 +346,6 @@ jobs:
 | 
			
		||||
      - pylint
 | 
			
		||||
      - pytest
 | 
			
		||||
      - pyupgrade
 | 
			
		||||
      - yamllint
 | 
			
		||||
      - compile-tests
 | 
			
		||||
      - clang-tidy
 | 
			
		||||
    if: always()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/workflows/lock.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/lock.yml
									
									
									
									
										vendored
									
									
								
							@@ -18,7 +18,7 @@ jobs:
 | 
			
		||||
  lock:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: dessant/lock-threads@v4
 | 
			
		||||
      - uses: dessant/lock-threads@v4.0.1
 | 
			
		||||
        with:
 | 
			
		||||
          pr-inactive-days: "1"
 | 
			
		||||
          pr-lock-reason: ""
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@@ -19,7 +19,7 @@ jobs:
 | 
			
		||||
    outputs:
 | 
			
		||||
      tag: ${{ steps.tag.outputs.tag }}
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@v4
 | 
			
		||||
      - uses: actions/checkout@v4.0.0
 | 
			
		||||
      - name: Get tag
 | 
			
		||||
        id: tag
 | 
			
		||||
        # yamllint disable rule:line-length
 | 
			
		||||
@@ -43,9 +43,9 @@ jobs:
 | 
			
		||||
    if: github.repository == 'esphome/esphome' && github.event_name == 'release'
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@v4
 | 
			
		||||
      - uses: actions/checkout@v4.0.0
 | 
			
		||||
      - name: Set up Python
 | 
			
		||||
        uses: actions/setup-python@v4
 | 
			
		||||
        uses: actions/setup-python@v4.7.0
 | 
			
		||||
        with:
 | 
			
		||||
          python-version: "3.x"
 | 
			
		||||
      - name: Set up python environment
 | 
			
		||||
@@ -88,24 +88,24 @@ jobs:
 | 
			
		||||
            target: "lint"
 | 
			
		||||
            baseimg: "docker"
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@v4
 | 
			
		||||
      - uses: actions/checkout@v4.0.0
 | 
			
		||||
      - name: Set up Python
 | 
			
		||||
        uses: actions/setup-python@v4
 | 
			
		||||
        uses: actions/setup-python@v4.7.0
 | 
			
		||||
        with:
 | 
			
		||||
          python-version: "3.9"
 | 
			
		||||
 | 
			
		||||
      - name: Set up Docker Buildx
 | 
			
		||||
        uses: docker/setup-buildx-action@v2
 | 
			
		||||
        uses: docker/setup-buildx-action@v3.0.0
 | 
			
		||||
      - name: Set up QEMU
 | 
			
		||||
        uses: docker/setup-qemu-action@v2
 | 
			
		||||
        uses: docker/setup-qemu-action@v3.0.0
 | 
			
		||||
 | 
			
		||||
      - name: Log in to docker hub
 | 
			
		||||
        uses: docker/login-action@v2
 | 
			
		||||
        uses: docker/login-action@v3.0.0
 | 
			
		||||
        with:
 | 
			
		||||
          username: ${{ secrets.DOCKER_USER }}
 | 
			
		||||
          password: ${{ secrets.DOCKER_PASSWORD }}
 | 
			
		||||
      - name: Log in to the GitHub container registry
 | 
			
		||||
        uses: docker/login-action@v2
 | 
			
		||||
        uses: docker/login-action@v3.0.0
 | 
			
		||||
        with:
 | 
			
		||||
          registry: ghcr.io
 | 
			
		||||
          username: ${{ github.actor }}
 | 
			
		||||
@@ -119,7 +119,7 @@ jobs:
 | 
			
		||||
            --suffix "${{ matrix.image.suffix }}"
 | 
			
		||||
 | 
			
		||||
      - name: Build and push
 | 
			
		||||
        uses: docker/build-push-action@v4
 | 
			
		||||
        uses: docker/build-push-action@v5.0.0
 | 
			
		||||
        with:
 | 
			
		||||
          context: .
 | 
			
		||||
          file: ./docker/Dockerfile
 | 
			
		||||
@@ -141,7 +141,7 @@ jobs:
 | 
			
		||||
    needs: [deploy-docker]
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Trigger Workflow
 | 
			
		||||
        uses: actions/github-script@v6
 | 
			
		||||
        uses: actions/github-script@v6.4.1
 | 
			
		||||
        with:
 | 
			
		||||
          github-token: ${{ secrets.DEPLOY_HA_ADDON_REPO_TOKEN }}
 | 
			
		||||
          script: |
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
								
							@@ -18,7 +18,7 @@ jobs:
 | 
			
		||||
  stale:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/stale@v8
 | 
			
		||||
      - uses: actions/stale@v8.0.0
 | 
			
		||||
        with:
 | 
			
		||||
          days-before-pr-stale: 90
 | 
			
		||||
          days-before-pr-close: 7
 | 
			
		||||
@@ -38,7 +38,7 @@ jobs:
 | 
			
		||||
  close-issues:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/stale@v8
 | 
			
		||||
      - uses: actions/stale@v8.0.0
 | 
			
		||||
        with:
 | 
			
		||||
          days-before-pr-stale: -1
 | 
			
		||||
          days-before-pr-close: -1
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								.github/workflows/sync-device-classes.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								.github/workflows/sync-device-classes.yml
									
									
									
									
										vendored
									
									
								
							@@ -4,8 +4,7 @@ name: Synchronise Device Classes from Home Assistant
 | 
			
		||||
on:
 | 
			
		||||
  workflow_dispatch:
 | 
			
		||||
  schedule:
 | 
			
		||||
    - cron: '45 6 * * *'
 | 
			
		||||
 | 
			
		||||
    - cron: "45 6 * * *"
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  sync:
 | 
			
		||||
@@ -14,16 +13,16 @@ jobs:
 | 
			
		||||
    if: github.repository == 'esphome/esphome'
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v4.0.0
 | 
			
		||||
 | 
			
		||||
      - name: Checkout Home Assistant
 | 
			
		||||
        uses: actions/checkout@v4
 | 
			
		||||
        uses: actions/checkout@v4.0.0
 | 
			
		||||
        with:
 | 
			
		||||
          repository: home-assistant/core
 | 
			
		||||
          path: lib/home-assistant
 | 
			
		||||
 | 
			
		||||
      - name: Setup Python
 | 
			
		||||
        uses: actions/setup-python@v4
 | 
			
		||||
        uses: actions/setup-python@v4.7.0
 | 
			
		||||
        with:
 | 
			
		||||
          python-version: 3.11
 | 
			
		||||
 | 
			
		||||
@@ -37,7 +36,7 @@ jobs:
 | 
			
		||||
          python ./script/sync-device_class.py
 | 
			
		||||
 | 
			
		||||
      - name: Commit changes
 | 
			
		||||
        uses: peter-evans/create-pull-request@v5
 | 
			
		||||
        uses: peter-evans/create-pull-request@v5.0.2
 | 
			
		||||
        with:
 | 
			
		||||
          commit-message: "Synchronise Device Classes from Home Assistant"
 | 
			
		||||
          committer: esphomebot <esphome@nabucasa.com>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								.github/workflows/yaml-lint.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								.github/workflows/yaml-lint.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
name: YAML lint
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
    branches: [dev, beta, release]
 | 
			
		||||
    paths:
 | 
			
		||||
      - "**.yaml"
 | 
			
		||||
      - "**.yml"
 | 
			
		||||
  pull_request:
 | 
			
		||||
    paths:
 | 
			
		||||
      - "**.yaml"
 | 
			
		||||
      - "**.yml"
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  yamllint:
 | 
			
		||||
    name: yamllint
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Check out code from GitHub
 | 
			
		||||
        uses: actions/checkout@v4.0.0
 | 
			
		||||
      - name: Run yamllint
 | 
			
		||||
        uses: frenck/action-yamllint@v1.4.1
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
# See https://pre-commit.com/hooks.html for more hooks
 | 
			
		||||
repos:
 | 
			
		||||
  - repo: https://github.com/psf/black-pre-commit-mirror
 | 
			
		||||
    rev: 23.7.0
 | 
			
		||||
    rev: 23.9.1
 | 
			
		||||
    hooks:
 | 
			
		||||
      - id: black
 | 
			
		||||
        args:
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,8 @@ RUN \
 | 
			
		||||
        curl=7.74.0-1.3+deb11u7 \
 | 
			
		||||
        openssh-client=1:8.4p1-5+deb11u1 \
 | 
			
		||||
        python3-cffi=1.14.5-1 \
 | 
			
		||||
        libcairo2=1.16.0-5; \
 | 
			
		||||
        libcairo2=1.16.0-5 \
 | 
			
		||||
        patch=2.7.6-7; \
 | 
			
		||||
    if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
 | 
			
		||||
        apt-get install -y --no-install-recommends \
 | 
			
		||||
          build-essential=12.9 \
 | 
			
		||||
 
 | 
			
		||||
@@ -5,10 +5,7 @@ from esphome.const import CONF_ANALOG, CONF_INPUT
 | 
			
		||||
 | 
			
		||||
from esphome.core import CORE
 | 
			
		||||
from esphome.components.esp32 import get_esp32_variant
 | 
			
		||||
from esphome.const import (
 | 
			
		||||
    PLATFORM_ESP8266,
 | 
			
		||||
    PLATFORM_RP2040,
 | 
			
		||||
)
 | 
			
		||||
from esphome.const import PLATFORM_ESP8266
 | 
			
		||||
from esphome.components.esp32.const import (
 | 
			
		||||
    VARIANT_ESP32,
 | 
			
		||||
    VARIANT_ESP32C2,
 | 
			
		||||
@@ -147,7 +144,9 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
 | 
			
		||||
 | 
			
		||||
def validate_adc_pin(value):
 | 
			
		||||
    if str(value).upper() == "VCC":
 | 
			
		||||
        return cv.only_on([PLATFORM_ESP8266, PLATFORM_RP2040])("VCC")
 | 
			
		||||
        if CORE.is_rp2040:
 | 
			
		||||
            return pins.internal_gpio_input_pin_schema(29)
 | 
			
		||||
        return cv.only_on([PLATFORM_ESP8266])("VCC")
 | 
			
		||||
 | 
			
		||||
    if str(value).upper() == "TEMPERATURE":
 | 
			
		||||
        return cv.only_on_rp2040("TEMPERATURE")
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
#include "adc_sensor.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
#include "esphome/core/helpers.h"
 | 
			
		||||
#include "esphome/core/log.h"
 | 
			
		||||
 | 
			
		||||
#ifdef USE_ESP8266
 | 
			
		||||
#ifdef USE_ADC_SENSOR_VCC
 | 
			
		||||
@@ -246,45 +246,42 @@ float ADCSensor::sample() {
 | 
			
		||||
    adc_set_temp_sensor_enabled(true);
 | 
			
		||||
    delay(1);
 | 
			
		||||
    adc_select_input(4);
 | 
			
		||||
 | 
			
		||||
    int32_t raw = adc_read();
 | 
			
		||||
    adc_set_temp_sensor_enabled(false);
 | 
			
		||||
    if (this->output_raw_) {
 | 
			
		||||
      return raw;
 | 
			
		||||
    }
 | 
			
		||||
    return raw * 3.3f / 4096.0f;
 | 
			
		||||
  } else {
 | 
			
		||||
    uint8_t pin;
 | 
			
		||||
#ifdef USE_ADC_SENSOR_VCC
 | 
			
		||||
    uint8_t pin = this->pin_->get_pin();
 | 
			
		||||
#ifdef CYW43_USES_VSYS_PIN
 | 
			
		||||
    // Measuring VSYS on Raspberry Pico W needs to be wrapped with
 | 
			
		||||
    // `cyw43_thread_enter()`/`cyw43_thread_exit()` as discussed in
 | 
			
		||||
    // https://github.com/raspberrypi/pico-sdk/issues/1222, since Wifi chip and
 | 
			
		||||
    // VSYS ADC both share GPIO29
 | 
			
		||||
    cyw43_thread_enter();
 | 
			
		||||
    if (pin == PICO_VSYS_PIN) {
 | 
			
		||||
      // Measuring VSYS on Raspberry Pico W needs to be wrapped with
 | 
			
		||||
      // `cyw43_thread_enter()`/`cyw43_thread_exit()` as discussed in
 | 
			
		||||
      // https://github.com/raspberrypi/pico-sdk/issues/1222, since Wifi chip and
 | 
			
		||||
      // VSYS ADC both share GPIO29
 | 
			
		||||
      cyw43_thread_enter();
 | 
			
		||||
    }
 | 
			
		||||
#endif  // CYW43_USES_VSYS_PIN
 | 
			
		||||
    pin = PICO_VSYS_PIN;
 | 
			
		||||
#else
 | 
			
		||||
    pin = this->pin_->get_pin();
 | 
			
		||||
#endif  // USE_ADC_SENSOR_VCC
 | 
			
		||||
 | 
			
		||||
    adc_gpio_init(pin);
 | 
			
		||||
    adc_select_input(pin - 26);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  int32_t raw = adc_read();
 | 
			
		||||
  if (this->is_temperature_) {
 | 
			
		||||
    adc_set_temp_sensor_enabled(false);
 | 
			
		||||
  } else {
 | 
			
		||||
#ifdef USE_ADC_SENSOR_VCC
 | 
			
		||||
    int32_t raw = adc_read();
 | 
			
		||||
 | 
			
		||||
#ifdef CYW43_USES_VSYS_PIN
 | 
			
		||||
    cyw43_thread_exit();
 | 
			
		||||
    if (pin == PICO_VSYS_PIN) {
 | 
			
		||||
      cyw43_thread_exit();
 | 
			
		||||
    }
 | 
			
		||||
#endif  // CYW43_USES_VSYS_PIN
 | 
			
		||||
#endif  // USE_ADC_SENSOR_VCC
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (output_raw_) {
 | 
			
		||||
    return raw;
 | 
			
		||||
    if (output_raw_) {
 | 
			
		||||
      return raw;
 | 
			
		||||
    }
 | 
			
		||||
    float coeff = pin == PICO_VSYS_PIN ? 3.0 : 1.0;
 | 
			
		||||
    return raw * 3.3f / 4096.0f * coeff;
 | 
			
		||||
  }
 | 
			
		||||
  float coeff = 1.0;
 | 
			
		||||
#ifdef USE_ADC_SENSOR_VCC
 | 
			
		||||
  // As per Raspberry Pico (W) datasheet (section 2.1) the VSYS/3 is measured
 | 
			
		||||
  coeff = 3.0;
 | 
			
		||||
#endif  // USE_ADC_SENSOR_VCC
 | 
			
		||||
  return raw * 3.3f / 4096.0f * coeff;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -62,8 +62,12 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
 | 
			
		||||
  adc1_channel_t channel1_{ADC1_CHANNEL_MAX};
 | 
			
		||||
  adc2_channel_t channel2_{ADC2_CHANNEL_MAX};
 | 
			
		||||
  bool autorange_{false};
 | 
			
		||||
#if ESP_IDF_VERSION_MAJOR >= 5
 | 
			
		||||
  esp_adc_cal_characteristics_t cal_characteristics_[SOC_ADC_ATTEN_NUM] = {};
 | 
			
		||||
#else
 | 
			
		||||
  esp_adc_cal_characteristics_t cal_characteristics_[ADC_ATTEN_MAX] = {};
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace adc
 | 
			
		||||
 
 | 
			
		||||
@@ -19,4 +19,4 @@ async def to_code(config):
 | 
			
		||||
        cg.add_library("esphome/AsyncTCP-esphome", "2.0.1")
 | 
			
		||||
    elif CORE.is_esp8266:
 | 
			
		||||
        # https://github.com/esphome/ESPAsyncTCP
 | 
			
		||||
        cg.add_library("esphome/ESPAsyncTCP-esphome", "1.2.3")
 | 
			
		||||
        cg.add_library("esphome/ESPAsyncTCP-esphome", "2.0.0")
 | 
			
		||||
 
 | 
			
		||||
@@ -80,8 +80,6 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
 | 
			
		||||
  TEMPLATABLE_VALUE(std::string, url)
 | 
			
		||||
  TEMPLATABLE_VALUE(const char *, method)
 | 
			
		||||
  TEMPLATABLE_VALUE(std::string, body)
 | 
			
		||||
  TEMPLATABLE_VALUE(const char *, useragent)
 | 
			
		||||
  TEMPLATABLE_VALUE(uint16_t, timeout)
 | 
			
		||||
 | 
			
		||||
  void add_header(const char *key, TemplatableValue<const char *, Ts...> value) { this->headers_.insert({key, value}); }
 | 
			
		||||
 | 
			
		||||
@@ -105,25 +103,18 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
 | 
			
		||||
      auto f = std::bind(&HttpRequestSendAction<Ts...>::encode_json_func_, this, x..., std::placeholders::_1);
 | 
			
		||||
      this->parent_->set_body(json::build_json(f));
 | 
			
		||||
    }
 | 
			
		||||
    if (this->useragent_.has_value()) {
 | 
			
		||||
      this->parent_->set_useragent(this->useragent_.value(x...));
 | 
			
		||||
    }
 | 
			
		||||
    if (this->timeout_.has_value()) {
 | 
			
		||||
      this->parent_->set_timeout(this->timeout_.value(x...));
 | 
			
		||||
    }
 | 
			
		||||
    if (!this->headers_.empty()) {
 | 
			
		||||
      std::list<Header> headers;
 | 
			
		||||
      for (const auto &item : this->headers_) {
 | 
			
		||||
        auto val = item.second;
 | 
			
		||||
        Header header;
 | 
			
		||||
        header.name = item.first;
 | 
			
		||||
        header.value = val.value(x...);
 | 
			
		||||
        headers.push_back(header);
 | 
			
		||||
      }
 | 
			
		||||
      this->parent_->set_headers(headers);
 | 
			
		||||
    std::list<Header> headers;
 | 
			
		||||
    for (const auto &item : this->headers_) {
 | 
			
		||||
      auto val = item.second;
 | 
			
		||||
      Header header;
 | 
			
		||||
      header.name = item.first;
 | 
			
		||||
      header.value = val.value(x...);
 | 
			
		||||
      headers.push_back(header);
 | 
			
		||||
    }
 | 
			
		||||
    this->parent_->set_headers(headers);
 | 
			
		||||
    this->parent_->send(this->response_triggers_);
 | 
			
		||||
    this->parent_->close();
 | 
			
		||||
    this->parent_->set_body("");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
 
 | 
			
		||||
@@ -13,8 +13,7 @@ namespace mdns {
 | 
			
		||||
void MDNSComponent::setup() {
 | 
			
		||||
  this->compile_records_();
 | 
			
		||||
 | 
			
		||||
  network::IPAddress addr = network::get_ip_address();
 | 
			
		||||
  MDNS.begin(this->hostname_.c_str(), (uint32_t) addr);
 | 
			
		||||
  MDNS.begin(this->hostname_.c_str());
 | 
			
		||||
 | 
			
		||||
  for (const auto &service : this->services_) {
 | 
			
		||||
    // Strip the leading underscore from the proto and service_type. While it is
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ from esphome.components.climate import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
CODEOWNERS = ["@dudanov"]
 | 
			
		||||
DEPENDENCIES = ["climate", "uart", "wifi"]
 | 
			
		||||
DEPENDENCIES = ["climate", "uart"]
 | 
			
		||||
AUTO_LOAD = ["sensor"]
 | 
			
		||||
CONF_OUTDOOR_TEMPERATURE = "outdoor_temperature"
 | 
			
		||||
CONF_POWER_USAGE = "power_usage"
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ from .const import (
 | 
			
		||||
    CONF_BITMASK,
 | 
			
		||||
    CONF_BYTE_OFFSET,
 | 
			
		||||
    CONF_COMMAND_THROTTLE,
 | 
			
		||||
    CONF_OFFLINE_SKIP_UPDATES,
 | 
			
		||||
    CONF_CUSTOM_COMMAND,
 | 
			
		||||
    CONF_FORCE_NEW_RANGE,
 | 
			
		||||
    CONF_MODBUS_CONTROLLER_ID,
 | 
			
		||||
@@ -104,6 +105,7 @@ CONFIG_SCHEMA = cv.All(
 | 
			
		||||
            cv.Optional(
 | 
			
		||||
                CONF_COMMAND_THROTTLE, default="0ms"
 | 
			
		||||
            ): cv.positive_time_period_milliseconds,
 | 
			
		||||
            cv.Optional(CONF_OFFLINE_SKIP_UPDATES, default=0): cv.positive_int,
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
    .extend(cv.polling_component_schema("60s"))
 | 
			
		||||
@@ -206,8 +208,9 @@ async def add_modbus_base_properties(
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
    var = cg.new_Pvariable(config[CONF_ID], config[CONF_COMMAND_THROTTLE])
 | 
			
		||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
			
		||||
    cg.add(var.set_command_throttle(config[CONF_COMMAND_THROTTLE]))
 | 
			
		||||
    cg.add(var.set_offline_skip_updates(config[CONF_OFFLINE_SKIP_UPDATES]))
 | 
			
		||||
    await register_modbus_device(var, config)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
CONF_BITMASK = "bitmask"
 | 
			
		||||
CONF_BYTE_OFFSET = "byte_offset"
 | 
			
		||||
CONF_COMMAND_THROTTLE = "command_throttle"
 | 
			
		||||
CONF_OFFLINE_SKIP_UPDATES = "offline_skip_updates"
 | 
			
		||||
CONF_CUSTOM_COMMAND = "custom_command"
 | 
			
		||||
CONF_FORCE_NEW_RANGE = "force_new_range"
 | 
			
		||||
CONF_MODBUS_CONTROLLER_ID = "modbus_controller_id"
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,17 @@ bool ModbusController::send_next_command_() {
 | 
			
		||||
 | 
			
		||||
    // remove from queue if command was sent too often
 | 
			
		||||
    if (command->send_countdown < 1) {
 | 
			
		||||
      if (!this->module_offline_) {
 | 
			
		||||
        ESP_LOGW(TAG, "Modbus device=%d set offline", this->address_);
 | 
			
		||||
 | 
			
		||||
        if (this->offline_skip_updates_ > 0) {
 | 
			
		||||
          // Update skip_updates_counter to stop flooding channel with timeouts
 | 
			
		||||
          for (auto &r : this->register_ranges_) {
 | 
			
		||||
            r.skip_updates_counter = this->offline_skip_updates_;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      this->module_offline_ = true;
 | 
			
		||||
      ESP_LOGD(
 | 
			
		||||
          TAG,
 | 
			
		||||
          "Modbus command to device=%d register=0x%02X countdown=%d no response received - removed from send queue",
 | 
			
		||||
@@ -49,6 +60,18 @@ bool ModbusController::send_next_command_() {
 | 
			
		||||
void ModbusController::on_modbus_data(const std::vector<uint8_t> &data) {
 | 
			
		||||
  auto ¤t_command = this->command_queue_.front();
 | 
			
		||||
  if (current_command != nullptr) {
 | 
			
		||||
    if (this->module_offline_) {
 | 
			
		||||
      ESP_LOGW(TAG, "Modbus device=%d back online", this->address_);
 | 
			
		||||
 | 
			
		||||
      if (this->offline_skip_updates_ > 0) {
 | 
			
		||||
        // Restore skip_updates_counter to restore commands updates
 | 
			
		||||
        for (auto &r : this->register_ranges_) {
 | 
			
		||||
          r.skip_updates_counter = 0;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    this->module_offline_ = false;
 | 
			
		||||
 | 
			
		||||
    // Move the commandItem to the response queue
 | 
			
		||||
    current_command->payload = data;
 | 
			
		||||
    this->incoming_queue_.push(std::move(current_command));
 | 
			
		||||
 
 | 
			
		||||
@@ -409,7 +409,6 @@ class ModbusCommandItem {
 | 
			
		||||
 | 
			
		||||
class ModbusController : public PollingComponent, public modbus::ModbusDevice {
 | 
			
		||||
 public:
 | 
			
		||||
  ModbusController(uint16_t throttle = 0) : command_throttle_(throttle){};
 | 
			
		||||
  void dump_config() override;
 | 
			
		||||
  void loop() override;
 | 
			
		||||
  void setup() override;
 | 
			
		||||
@@ -431,6 +430,12 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice {
 | 
			
		||||
                                  const std::vector<uint8_t> &data);
 | 
			
		||||
  /// called by esphome generated code to set the command_throttle period
 | 
			
		||||
  void set_command_throttle(uint16_t command_throttle) { this->command_throttle_ = command_throttle; }
 | 
			
		||||
  /// called by esphome generated code to set the offline_skip_updates
 | 
			
		||||
  void set_offline_skip_updates(uint16_t offline_skip_updates) { this->offline_skip_updates_ = offline_skip_updates; }
 | 
			
		||||
  /// get the number of queued modbus commands (should be mostly empty)
 | 
			
		||||
  size_t get_command_queue_length() { return command_queue_.size(); }
 | 
			
		||||
  /// get if the module is offline, didn't respond the last command
 | 
			
		||||
  bool get_module_offline() { return module_offline_; }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  /// parse sensormap_ and create range of sequential addresses
 | 
			
		||||
@@ -443,8 +448,6 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice {
 | 
			
		||||
  void process_modbus_data_(const ModbusCommandItem *response);
 | 
			
		||||
  /// send the next modbus command from the send queue
 | 
			
		||||
  bool send_next_command_();
 | 
			
		||||
  /// get the number of queued modbus commands (should be mostly empty)
 | 
			
		||||
  size_t get_command_queue_length_() { return command_queue_.size(); }
 | 
			
		||||
  /// dump the parsed sensormap for diagnostics
 | 
			
		||||
  void dump_sensors_();
 | 
			
		||||
  /// Collection of all sensors for this component
 | 
			
		||||
@@ -459,6 +462,10 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice {
 | 
			
		||||
  uint32_t last_command_timestamp_;
 | 
			
		||||
  /// min time in ms between sending modbus commands
 | 
			
		||||
  uint16_t command_throttle_;
 | 
			
		||||
  /// if module didn't respond the last command
 | 
			
		||||
  bool module_offline_;
 | 
			
		||||
  /// how many updates to skip if module is offline
 | 
			
		||||
  uint16_t offline_skip_updates_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** Convert vector<uint8_t> response payload to float.
 | 
			
		||||
 
 | 
			
		||||
@@ -71,7 +71,8 @@ bool MopekaStdCheck::parse_device(const esp32_ble_tracker::ESPBTDevice &device)
 | 
			
		||||
  const auto *mopeka_data = (const mopeka_std_package *) manu_data.data.data();
 | 
			
		||||
 | 
			
		||||
  const u_int8_t hardware_id = mopeka_data->data_1 & 0xCF;
 | 
			
		||||
  if (static_cast<SensorType>(hardware_id) != STANDARD && static_cast<SensorType>(hardware_id) != XL) {
 | 
			
		||||
  if (static_cast<SensorType>(hardware_id) != STANDARD && static_cast<SensorType>(hardware_id) != XL &&
 | 
			
		||||
      static_cast<SensorType>(hardware_id) != ETRAILER) {
 | 
			
		||||
    ESP_LOGE(TAG, "[%s] Unsupported Sensor Type (0x%X)", device.address_str().c_str(), hardware_id);
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@ namespace mopeka_std_check {
 | 
			
		||||
enum SensorType {
 | 
			
		||||
  STANDARD = 0x02,
 | 
			
		||||
  XL = 0x03,
 | 
			
		||||
  ETRAILER = 0x46,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 4 values in one struct so it aligns to 8 byte. One `mopeka_std_values` is 40 bit long.
 | 
			
		||||
 
 | 
			
		||||
@@ -273,8 +273,8 @@ async def to_code(config):
 | 
			
		||||
    await cg.register_component(var, config)
 | 
			
		||||
    # Add required libraries for ESP8266
 | 
			
		||||
    if CORE.is_esp8266:
 | 
			
		||||
        # https://github.com/OttoWinter/async-mqtt-client/blob/master/library.json
 | 
			
		||||
        cg.add_library("ottowinter/AsyncMqttClient-esphome", "0.8.6")
 | 
			
		||||
        # https://github.com/heman/async-mqtt-client/blob/master/library.json
 | 
			
		||||
        cg.add_library("heman/AsyncMqttClient-esphome", "1.0.0")
 | 
			
		||||
 | 
			
		||||
    cg.add_define("USE_MQTT")
 | 
			
		||||
    cg.add_global(mqtt_ns.using)
 | 
			
		||||
 
 | 
			
		||||
@@ -168,15 +168,10 @@ void MQTTClientComponent::start_dnslookup_() {
 | 
			
		||||
    case ERR_OK: {
 | 
			
		||||
      // Got IP immediately
 | 
			
		||||
      this->dns_resolved_ = true;
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
#if LWIP_IPV6
 | 
			
		||||
      this->ip_ = addr.u_addr.ip4.addr;
 | 
			
		||||
#else
 | 
			
		||||
      this->ip_ = addr.addr;
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef USE_ESP8266
 | 
			
		||||
      this->ip_ = addr.addr;
 | 
			
		||||
#endif
 | 
			
		||||
      this->start_connect_();
 | 
			
		||||
      return;
 | 
			
		||||
@@ -228,15 +223,10 @@ void MQTTClientComponent::dns_found_callback(const char *name, const ip_addr_t *
 | 
			
		||||
  if (ipaddr == nullptr) {
 | 
			
		||||
    a_this->dns_resolve_error_ = true;
 | 
			
		||||
  } else {
 | 
			
		||||
#ifdef USE_ESP32
 | 
			
		||||
#if LWIP_IPV6
 | 
			
		||||
    a_this->ip_ = ipaddr->u_addr.ip4.addr;
 | 
			
		||||
#else
 | 
			
		||||
    a_this->ip_ = ipaddr->addr;
 | 
			
		||||
#endif
 | 
			
		||||
#endif  // USE_ESP32
 | 
			
		||||
#ifdef USE_ESP8266
 | 
			
		||||
    a_this->ip_ = ipaddr->addr;
 | 
			
		||||
#endif
 | 
			
		||||
    a_this->dns_resolved_ = true;
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -15,22 +15,23 @@ IPAddress = network_ns.class_("IPAddress")
 | 
			
		||||
 | 
			
		||||
CONFIG_SCHEMA = cv.Schema(
 | 
			
		||||
    {
 | 
			
		||||
        cv.SplitDefault(CONF_ENABLE_IPV6, esp32=False): cv.All(
 | 
			
		||||
            cv.only_on_esp32, cv.boolean
 | 
			
		||||
        ),
 | 
			
		||||
        cv.Optional(CONF_ENABLE_IPV6, default=False): cv.boolean,
 | 
			
		||||
    }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def to_code(config):
 | 
			
		||||
    if CONF_ENABLE_IPV6 in config:
 | 
			
		||||
        cg.add_define("ENABLE_IPV6", config[CONF_ENABLE_IPV6])
 | 
			
		||||
        if CORE.using_esp_idf:
 | 
			
		||||
            add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", config[CONF_ENABLE_IPV6])
 | 
			
		||||
            add_idf_sdkconfig_option(
 | 
			
		||||
                "CONFIG_LWIP_IPV6_AUTOCONFIG", config[CONF_ENABLE_IPV6]
 | 
			
		||||
            )
 | 
			
		||||
        else:
 | 
			
		||||
            if config[CONF_ENABLE_IPV6]:
 | 
			
		||||
                cg.add_build_flag("-DCONFIG_LWIP_IPV6")
 | 
			
		||||
                cg.add_build_flag("-DCONFIG_LWIP_IPV6_AUTOCONFIG")
 | 
			
		||||
    cg.add_define("ENABLE_IPV6", config[CONF_ENABLE_IPV6])
 | 
			
		||||
    if CORE.using_esp_idf:
 | 
			
		||||
        add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", config[CONF_ENABLE_IPV6])
 | 
			
		||||
        add_idf_sdkconfig_option(
 | 
			
		||||
            "CONFIG_LWIP_IPV6_AUTOCONFIG", config[CONF_ENABLE_IPV6]
 | 
			
		||||
        )
 | 
			
		||||
    else:
 | 
			
		||||
        if config[CONF_ENABLE_IPV6]:
 | 
			
		||||
            cg.add_build_flag("-DCONFIG_LWIP_IPV6")
 | 
			
		||||
            cg.add_build_flag("-DCONFIG_LWIP_IPV6_AUTOCONFIG")
 | 
			
		||||
            if CORE.is_rp2040:
 | 
			
		||||
                cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_ENABLE_IPV6")
 | 
			
		||||
            if CORE.is_esp8266:
 | 
			
		||||
                cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_LOW_MEMORY")
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,9 @@ void PulseMeterSensor::setup() {
 | 
			
		||||
  this->pin_->setup();
 | 
			
		||||
  this->isr_pin_ = pin_->to_isr();
 | 
			
		||||
 | 
			
		||||
  // Set the last processed edge to now for the first timeout
 | 
			
		||||
  this->last_processed_edge_us_ = micros();
 | 
			
		||||
 | 
			
		||||
  if (this->filter_mode_ == FILTER_EDGE) {
 | 
			
		||||
    this->pin_->attach_interrupt(PulseMeterSensor::edge_intr, this, gpio::INTERRUPT_RISING_EDGE);
 | 
			
		||||
  } else if (this->filter_mode_ == FILTER_PULSE) {
 | 
			
		||||
@@ -38,12 +41,16 @@ void PulseMeterSensor::loop() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // We need to detect at least two edges to have a valid pulse width
 | 
			
		||||
    if (!this->initialized_) {
 | 
			
		||||
      this->initialized_ = true;
 | 
			
		||||
    } else {
 | 
			
		||||
      uint32_t delta_us = this->get_->last_detected_edge_us_ - this->last_processed_edge_us_;
 | 
			
		||||
      float pulse_width_us = delta_us / float(this->get_->count_);
 | 
			
		||||
      this->publish_state((60.0f * 1000000.0f) / pulse_width_us);
 | 
			
		||||
    switch (this->meter_state_) {
 | 
			
		||||
      case MeterState::INITIAL:
 | 
			
		||||
      case MeterState::TIMED_OUT: {
 | 
			
		||||
        this->meter_state_ = MeterState::RUNNING;
 | 
			
		||||
      } break;
 | 
			
		||||
      case MeterState::RUNNING: {
 | 
			
		||||
        uint32_t delta_us = this->get_->last_detected_edge_us_ - this->last_processed_edge_us_;
 | 
			
		||||
        float pulse_width_us = delta_us / float(this->get_->count_);
 | 
			
		||||
        this->publish_state((60.0f * 1000000.0f) / pulse_width_us);
 | 
			
		||||
      } break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this->last_processed_edge_us_ = this->get_->last_detected_edge_us_;
 | 
			
		||||
@@ -53,10 +60,18 @@ void PulseMeterSensor::loop() {
 | 
			
		||||
    const uint32_t now = micros();
 | 
			
		||||
    const uint32_t time_since_valid_edge_us = now - this->last_processed_edge_us_;
 | 
			
		||||
 | 
			
		||||
    if (this->initialized_ && time_since_valid_edge_us > this->timeout_us_) {
 | 
			
		||||
      ESP_LOGD(TAG, "No pulse detected for %us, assuming 0 pulses/min", time_since_valid_edge_us / 1000000);
 | 
			
		||||
      this->initialized_ = false;
 | 
			
		||||
      this->publish_state(0.0f);
 | 
			
		||||
    switch (this->meter_state_) {
 | 
			
		||||
        // Running and initial states can timeout
 | 
			
		||||
      case MeterState::INITIAL:
 | 
			
		||||
      case MeterState::RUNNING: {
 | 
			
		||||
        if (time_since_valid_edge_us > this->timeout_us_) {
 | 
			
		||||
          this->meter_state_ = MeterState::TIMED_OUT;
 | 
			
		||||
          ESP_LOGD(TAG, "No pulse detected for %us, assuming 0 pulses/min", time_since_valid_edge_us / 1000000);
 | 
			
		||||
          this->publish_state(0.0f);
 | 
			
		||||
        }
 | 
			
		||||
      } break;
 | 
			
		||||
      default:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,8 @@ class PulseMeterSensor : public sensor::Sensor, public Component {
 | 
			
		||||
  InternalFilterMode filter_mode_{FILTER_EDGE};
 | 
			
		||||
 | 
			
		||||
  // Variables used in the loop
 | 
			
		||||
  bool initialized_ = false;
 | 
			
		||||
  enum class MeterState { INITIAL, RUNNING, TIMED_OUT };
 | 
			
		||||
  MeterState meter_state_ = MeterState::INITIAL;
 | 
			
		||||
  uint32_t total_pulses_ = 0;
 | 
			
		||||
  uint32_t last_processed_edge_us_ = 0;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ static const char *const TAG = "radon_eye_ble";
 | 
			
		||||
 | 
			
		||||
bool RadonEyeListener::parse_device(const esp32_ble_tracker::ESPBTDevice &device) {
 | 
			
		||||
  if (not device.get_name().empty()) {
 | 
			
		||||
    if (device.get_name().rfind("FR:R20:SN", 0) == 0) {
 | 
			
		||||
    if (device.get_name().rfind("FR:R", 0) == 0) {
 | 
			
		||||
      // This is an RD200, I think
 | 
			
		||||
      ESP_LOGD(TAG, "Found Radon Eye RD200 device Name: %s (MAC: %s)", device.get_name().c_str(),
 | 
			
		||||
               device.address_str().c_str());
 | 
			
		||||
 
 | 
			
		||||
@@ -57,6 +57,10 @@ KNOWN_FIRMWARE = {
 | 
			
		||||
        "https://github.com/jamesturton/shelly-dimmer-stm32/releases/download/v51.6/shelly-dimmer-stm32_v51.6.bin",
 | 
			
		||||
        "eda483e111c914723a33f5088f1397d5c0b19333db4a88dc965636b976c16c36",
 | 
			
		||||
    ),
 | 
			
		||||
    "51.7": (
 | 
			
		||||
        "https://github.com/jamesturton/shelly-dimmer-stm32/releases/download/v51.7/shelly-dimmer-stm32_v51.7.bin",
 | 
			
		||||
        "7a20f1c967c469917368a79bc56498009045237080408cef7190743e08031889",
 | 
			
		||||
    ),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,8 @@ from esphome.const import (
 | 
			
		||||
    UNIT_PERCENT,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
CONF_HEATER_ENABLED = "heater_enabled"
 | 
			
		||||
 | 
			
		||||
DEPENDENCIES = ["i2c"]
 | 
			
		||||
AUTO_LOAD = ["sensirion_common"]
 | 
			
		||||
 | 
			
		||||
@@ -36,7 +38,8 @@ CONFIG_SCHEMA = (
 | 
			
		||||
                device_class=DEVICE_CLASS_HUMIDITY,
 | 
			
		||||
                state_class=STATE_CLASS_MEASUREMENT,
 | 
			
		||||
            ),
 | 
			
		||||
        }
 | 
			
		||||
            cv.Optional(CONF_HEATER_ENABLED, default=True): cv.boolean,
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
    .extend(cv.polling_component_schema("60s"))
 | 
			
		||||
    .extend(i2c.i2c_device_schema(0x44))
 | 
			
		||||
@@ -48,6 +51,8 @@ async def to_code(config):
 | 
			
		||||
    await cg.register_component(var, config)
 | 
			
		||||
    await i2c.register_i2c_device(var, config)
 | 
			
		||||
 | 
			
		||||
    cg.add(var.set_heater_enabled(config[CONF_HEATER_ENABLED]))
 | 
			
		||||
 | 
			
		||||
    if CONF_TEMPERATURE in config:
 | 
			
		||||
        sens = await sensor.new_sensor(config[CONF_TEMPERATURE])
 | 
			
		||||
        cg.add(var.set_temperature_sensor(sens))
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,10 @@ void SHT3XDComponent::setup() {
 | 
			
		||||
    this->mark_failed();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if (!this->write_command(heater_enabled_ ? SHT3XD_COMMAND_HEATER_ENABLE : SHT3XD_COMMAND_HEATER_DISABLE)) {
 | 
			
		||||
    this->mark_failed();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  uint32_t serial_number = (uint32_t(raw_serial_number[0]) << 16) | uint32_t(raw_serial_number[1]);
 | 
			
		||||
  ESP_LOGV(TAG, "    Serial Number: 0x%08X", serial_number);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,10 +17,12 @@ class SHT3XDComponent : public PollingComponent, public sensirion_common::Sensir
 | 
			
		||||
  void dump_config() override;
 | 
			
		||||
  float get_setup_priority() const override;
 | 
			
		||||
  void update() override;
 | 
			
		||||
  void set_heater_enabled(bool heater_enabled) { heater_enabled_ = heater_enabled; }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
  sensor::Sensor *temperature_sensor_{nullptr};
 | 
			
		||||
  sensor::Sensor *humidity_sensor_{nullptr};
 | 
			
		||||
  bool heater_enabled_{true};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace sht3xd
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,7 @@ socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t po
 | 
			
		||||
  memset(server, 0, sizeof(sockaddr_in6));
 | 
			
		||||
  server->sin6_family = AF_INET6;
 | 
			
		||||
  server->sin6_port = htons(port);
 | 
			
		||||
  server->sin6_addr = in6addr_any;
 | 
			
		||||
  server->sin6_addr = IN6ADDR_ANY_INIT;
 | 
			
		||||
  return sizeof(sockaddr_in6);
 | 
			
		||||
#else
 | 
			
		||||
  if (addrlen < sizeof(sockaddr_in)) {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,8 +14,8 @@ SX1509BinarySensor = sx1509_ns.class_("SX1509BinarySensor", binary_sensor.Binary
 | 
			
		||||
CONFIG_SCHEMA = binary_sensor.binary_sensor_schema(SX1509BinarySensor).extend(
 | 
			
		||||
    {
 | 
			
		||||
        cv.GenerateID(CONF_SX1509_ID): cv.use_id(SX1509Component),
 | 
			
		||||
        cv.Required(CONF_ROW): cv.int_range(min=0, max=4),
 | 
			
		||||
        cv.Required(CONF_COL): cv.int_range(min=0, max=4),
 | 
			
		||||
        cv.Required(CONF_ROW): cv.int_range(min=0, max=7),
 | 
			
		||||
        cv.Required(CONF_COL): cv.int_range(min=0, max=7),
 | 
			
		||||
    }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -986,6 +986,7 @@ void ThermostatClimate::change_preset_(climate::ClimatePreset preset) {
 | 
			
		||||
      // Fire any preset changed trigger if defined
 | 
			
		||||
      Trigger<> *trig = this->preset_change_trigger_;
 | 
			
		||||
      assert(trig != nullptr);
 | 
			
		||||
      this->preset = preset;
 | 
			
		||||
      trig->trigger();
 | 
			
		||||
 | 
			
		||||
      this->refresh();
 | 
			
		||||
@@ -1010,6 +1011,7 @@ void ThermostatClimate::change_custom_preset_(const std::string &custom_preset)
 | 
			
		||||
      // Fire any preset changed trigger if defined
 | 
			
		||||
      Trigger<> *trig = this->preset_change_trigger_;
 | 
			
		||||
      assert(trig != nullptr);
 | 
			
		||||
      this->custom_preset = custom_preset;
 | 
			
		||||
      trig->trigger();
 | 
			
		||||
 | 
			
		||||
      this->refresh();
 | 
			
		||||
 
 | 
			
		||||
@@ -1561,6 +1561,23 @@ void WaveshareEPaper7P5In::dump_config() {
 | 
			
		||||
  LOG_PIN("  Busy Pin: ", this->busy_pin_);
 | 
			
		||||
  LOG_UPDATE_INTERVAL(this);
 | 
			
		||||
}
 | 
			
		||||
bool WaveshareEPaper7P5InV2::wait_until_idle_() {
 | 
			
		||||
  if (this->busy_pin_ == nullptr) {
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const uint32_t start = millis();
 | 
			
		||||
  while (this->busy_pin_->digital_read()) {
 | 
			
		||||
    this->command(0x71);
 | 
			
		||||
    if (millis() - start > this->idle_timeout_()) {
 | 
			
		||||
      ESP_LOGE(TAG, "Timeout while displaying image!");
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    App.feed_wdt();
 | 
			
		||||
    delay(10);
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
void WaveshareEPaper7P5InV2::initialize() {
 | 
			
		||||
  // COMMAND POWER SETTING
 | 
			
		||||
  this->command(0x01);
 | 
			
		||||
@@ -1568,10 +1585,21 @@ void WaveshareEPaper7P5InV2::initialize() {
 | 
			
		||||
  this->data(0x07);
 | 
			
		||||
  this->data(0x3f);
 | 
			
		||||
  this->data(0x3f);
 | 
			
		||||
  this->command(0x04);
 | 
			
		||||
 | 
			
		||||
  // We don't want the display to be powered at this point
 | 
			
		||||
 | 
			
		||||
  delay(100);  // NOLINT
 | 
			
		||||
  this->wait_until_idle_();
 | 
			
		||||
 | 
			
		||||
  // COMMAND VCOM AND DATA INTERVAL SETTING
 | 
			
		||||
  this->command(0x50);
 | 
			
		||||
  this->data(0x10);
 | 
			
		||||
  this->data(0x07);
 | 
			
		||||
 | 
			
		||||
  // COMMAND TCON SETTING
 | 
			
		||||
  this->command(0x60);
 | 
			
		||||
  this->data(0x22);
 | 
			
		||||
 | 
			
		||||
  // COMMAND PANEL SETTING
 | 
			
		||||
  this->command(0x00);
 | 
			
		||||
  this->data(0x1F);
 | 
			
		||||
@@ -1582,19 +1610,30 @@ void WaveshareEPaper7P5InV2::initialize() {
 | 
			
		||||
  this->data(0x20);
 | 
			
		||||
  this->data(0x01);
 | 
			
		||||
  this->data(0xE0);
 | 
			
		||||
  // COMMAND ...?
 | 
			
		||||
 | 
			
		||||
  // COMMAND DUAL SPI MM_EN, DUSPI_EN
 | 
			
		||||
  this->command(0x15);
 | 
			
		||||
  this->data(0x00);
 | 
			
		||||
  // COMMAND VCOM AND DATA INTERVAL SETTING
 | 
			
		||||
  this->command(0x50);
 | 
			
		||||
  this->data(0x10);
 | 
			
		||||
  this->data(0x07);
 | 
			
		||||
  // COMMAND TCON SETTING
 | 
			
		||||
  this->command(0x60);
 | 
			
		||||
  this->data(0x22);
 | 
			
		||||
 | 
			
		||||
  // COMMAND POWER DRIVER HAT DOWN
 | 
			
		||||
  // This command will turn off booster, controller, source driver, gate driver, VCOM, and
 | 
			
		||||
  // temperature sensor, but register data will be kept until VDD turned OFF or Deep Sleep Mode.
 | 
			
		||||
  // Source/Gate/Border/VCOM will be released to floating.
 | 
			
		||||
  this->command(0x02);
 | 
			
		||||
}
 | 
			
		||||
void HOT WaveshareEPaper7P5InV2::display() {
 | 
			
		||||
  uint32_t buf_len = this->get_buffer_length_();
 | 
			
		||||
 | 
			
		||||
  // COMMAND POWER ON
 | 
			
		||||
  ESP_LOGI(TAG, "Power on the display and hat");
 | 
			
		||||
 | 
			
		||||
  // This command will turn on booster, controller, regulators, and temperature sensor will be
 | 
			
		||||
  // activated for one-time sensing before enabling booster. When all voltages are ready, the
 | 
			
		||||
  // BUSY_N signal will return to high.
 | 
			
		||||
  this->command(0x04);
 | 
			
		||||
  delay(200);  // NOLINT
 | 
			
		||||
  this->wait_until_idle_();
 | 
			
		||||
 | 
			
		||||
  // COMMAND DATA START TRANSMISSION NEW DATA
 | 
			
		||||
  this->command(0x13);
 | 
			
		||||
  delay(2);
 | 
			
		||||
@@ -1602,14 +1641,23 @@ void HOT WaveshareEPaper7P5InV2::display() {
 | 
			
		||||
    this->data(~(this->buffer_[i]));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  delay(100);  // NOLINT
 | 
			
		||||
  this->wait_until_idle_();
 | 
			
		||||
 | 
			
		||||
  // COMMAND DISPLAY REFRESH
 | 
			
		||||
  this->command(0x12);
 | 
			
		||||
  delay(100);  // NOLINT
 | 
			
		||||
  this->wait_until_idle_();
 | 
			
		||||
 | 
			
		||||
  ESP_LOGV(TAG, "Before command(0x02) (>> power off)");
 | 
			
		||||
  this->command(0x02);
 | 
			
		||||
  this->wait_until_idle_();
 | 
			
		||||
  ESP_LOGV(TAG, "After command(0x02) (>> power off)");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WaveshareEPaper7P5InV2::get_width_internal() { return 800; }
 | 
			
		||||
int WaveshareEPaper7P5InV2::get_height_internal() { return 480; }
 | 
			
		||||
uint32_t WaveshareEPaper7P5InV2::idle_timeout_() { return 10000; }
 | 
			
		||||
void WaveshareEPaper7P5InV2::dump_config() {
 | 
			
		||||
  LOG_DISPLAY("", "Waveshare E-Paper", this);
 | 
			
		||||
  ESP_LOGCONFIG(TAG, "  Model: 7.5inV2rev2");
 | 
			
		||||
 
 | 
			
		||||
@@ -472,6 +472,8 @@ class WaveshareEPaper7P5InBC : public WaveshareEPaper {
 | 
			
		||||
 | 
			
		||||
class WaveshareEPaper7P5InV2 : public WaveshareEPaper {
 | 
			
		||||
 public:
 | 
			
		||||
  bool wait_until_idle_();
 | 
			
		||||
 | 
			
		||||
  void initialize() override;
 | 
			
		||||
 | 
			
		||||
  void display() override;
 | 
			
		||||
@@ -491,6 +493,8 @@ class WaveshareEPaper7P5InV2 : public WaveshareEPaper {
 | 
			
		||||
  int get_width_internal() override;
 | 
			
		||||
 | 
			
		||||
  int get_height_internal() override;
 | 
			
		||||
 | 
			
		||||
  uint32_t idle_timeout_() override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class WaveshareEPaper7P5InV2alt : public WaveshareEPaper7P5InV2 {
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,7 @@ CONFIG_SCHEMA = cv.All(
 | 
			
		||||
        {
 | 
			
		||||
            cv.GenerateID(): cv.declare_id(WebServer),
 | 
			
		||||
            cv.Optional(CONF_PORT, default=80): cv.port,
 | 
			
		||||
            cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2),
 | 
			
		||||
            cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2, int=True),
 | 
			
		||||
            cv.Optional(CONF_CSS_URL): cv.string,
 | 
			
		||||
            cv.Optional(CONF_CSS_INCLUDE): cv.file_,
 | 
			
		||||
            cv.Optional(CONF_JS_URL): cv.string,
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ extern "C" {
 | 
			
		||||
#include "lwip/apps/sntp.h"
 | 
			
		||||
#if LWIP_IPV6
 | 
			
		||||
#include "lwip/netif.h"  // struct netif
 | 
			
		||||
#include <AddrList.h>
 | 
			
		||||
#endif
 | 
			
		||||
#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(3, 0, 0)
 | 
			
		||||
#include "LwipDhcpServer.h"
 | 
			
		||||
@@ -97,6 +98,7 @@ bool WiFiComponent::wifi_apply_power_save_() {
 | 
			
		||||
      power_save = NONE_SLEEP_T;
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  wifi_fpm_auto_sleep_set_in_null_mode(1);
 | 
			
		||||
  return wifi_set_sleep_type(power_save);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -164,11 +166,11 @@ bool WiFiComponent::wifi_sta_ip_config_(optional<ManualIP> manual_ip) {
 | 
			
		||||
 | 
			
		||||
  ip_addr_t dns;
 | 
			
		||||
  if (uint32_t(manual_ip->dns1) != 0) {
 | 
			
		||||
    dns.addr = static_cast<uint32_t>(manual_ip->dns1);
 | 
			
		||||
    ip_addr_set_ip4_u32_val(dns, static_cast<uint32_t>(manual_ip->dns1));
 | 
			
		||||
    dns_setserver(0, &dns);
 | 
			
		||||
  }
 | 
			
		||||
  if (uint32_t(manual_ip->dns2) != 0) {
 | 
			
		||||
    dns.addr = static_cast<uint32_t>(manual_ip->dns2);
 | 
			
		||||
    ip_addr_set_ip4_u32_val(dns, static_cast<uint32_t>(manual_ip->dns2));
 | 
			
		||||
    dns_setserver(1, &dns);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -325,6 +327,18 @@ bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#if ENABLE_IPV6
 | 
			
		||||
  for (bool configured = false; !configured;) {
 | 
			
		||||
    for (auto addr : addrList) {
 | 
			
		||||
      ESP_LOGV(TAG, "Address %s", addr.toString().c_str());
 | 
			
		||||
      if ((configured = !addr.isLocal() && addr.isV6())) {
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    delay(500);  // NOLINT
 | 
			
		||||
  }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  if (ap.get_channel().has_value()) {
 | 
			
		||||
    ret = wifi_set_channel(*ap.get_channel());
 | 
			
		||||
    if (!ret) {
 | 
			
		||||
 
 | 
			
		||||
@@ -175,7 +175,11 @@ network::IPAddress WiFiComponent::wifi_subnet_mask_() { return {WiFi.subnetMask(
 | 
			
		||||
network::IPAddress WiFiComponent::wifi_gateway_ip_() { return {WiFi.gatewayIP()}; }
 | 
			
		||||
network::IPAddress WiFiComponent::wifi_dns_ip_(int num) {
 | 
			
		||||
  const ip_addr_t *dns_ip = dns_getserver(num);
 | 
			
		||||
#ifdef PIO_FRAMEWORK_ARDUINO_ENABLE_IPV6
 | 
			
		||||
  return {dns_ip->u_addr.ip4.addr};
 | 
			
		||||
#else
 | 
			
		||||
  return {dns_ip->addr};
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiComponent::wifi_loop_() {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
"""Constants used by esphome."""
 | 
			
		||||
 | 
			
		||||
__version__ = "2023.9.0-dev"
 | 
			
		||||
__version__ = "2023.10.0-dev"
 | 
			
		||||
 | 
			
		||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
 | 
			
		||||
VALID_SUBSTITUTIONS_CHARACTERS = (
 | 
			
		||||
 
 | 
			
		||||
@@ -57,7 +57,7 @@ class SimpleRegistry(dict):
 | 
			
		||||
        return decorator
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def safe_print(message=""):
 | 
			
		||||
def safe_print(message="", end="\n"):
 | 
			
		||||
    from esphome.core import CORE
 | 
			
		||||
 | 
			
		||||
    if CORE.dashboard:
 | 
			
		||||
@@ -67,20 +67,26 @@ def safe_print(message=""):
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        print(message)
 | 
			
		||||
        print(message, end=end)
 | 
			
		||||
        return
 | 
			
		||||
    except UnicodeEncodeError:
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        print(message.encode("utf-8", "backslashreplace"))
 | 
			
		||||
        print(message.encode("utf-8", "backslashreplace"), end=end)
 | 
			
		||||
    except UnicodeEncodeError:
 | 
			
		||||
        try:
 | 
			
		||||
            print(message.encode("ascii", "backslashreplace"))
 | 
			
		||||
            print(message.encode("ascii", "backslashreplace"), end=end)
 | 
			
		||||
        except UnicodeEncodeError:
 | 
			
		||||
            print("Cannot print line because of invalid locale!")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def safe_input(prompt=""):
 | 
			
		||||
    if prompt:
 | 
			
		||||
        safe_print(prompt, end="")
 | 
			
		||||
    return input()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def shlex_quote(s):
 | 
			
		||||
    if not s:
 | 
			
		||||
        return "''"
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ from esphome.core import CORE
 | 
			
		||||
from esphome.helpers import get_bool_env, write_file
 | 
			
		||||
from esphome.log import Fore, color
 | 
			
		||||
from esphome.storage_json import StorageJSON, ext_storage_path
 | 
			
		||||
from esphome.util import safe_print
 | 
			
		||||
from esphome.util import safe_input, safe_print
 | 
			
		||||
 | 
			
		||||
CORE_BIG = r"""    _____ ____  _____  ______
 | 
			
		||||
   / ____/ __ \|  __ \|  ____|
 | 
			
		||||
@@ -252,7 +252,7 @@ def safe_print_step(step, big):
 | 
			
		||||
def default_input(text, default):
 | 
			
		||||
    safe_print()
 | 
			
		||||
    safe_print(f"Press ENTER for default ({default})")
 | 
			
		||||
    return input(text.format(default)) or default
 | 
			
		||||
    return safe_input(text.format(default)) or default
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# From https://stackoverflow.com/a/518232/8924614
 | 
			
		||||
@@ -306,7 +306,7 @@ def wizard(path):
 | 
			
		||||
    )
 | 
			
		||||
    safe_print()
 | 
			
		||||
    sleep(1)
 | 
			
		||||
    name = input(color(Fore.BOLD_WHITE, "(name): "))
 | 
			
		||||
    name = safe_input(color(Fore.BOLD_WHITE, "(name): "))
 | 
			
		||||
 | 
			
		||||
    while True:
 | 
			
		||||
        try:
 | 
			
		||||
@@ -343,7 +343,9 @@ def wizard(path):
 | 
			
		||||
    while True:
 | 
			
		||||
        sleep(0.5)
 | 
			
		||||
        safe_print()
 | 
			
		||||
        platform = input(color(Fore.BOLD_WHITE, f"({'/'.join(wizard_platforms)}): "))
 | 
			
		||||
        platform = safe_input(
 | 
			
		||||
            color(Fore.BOLD_WHITE, f"({'/'.join(wizard_platforms)}): ")
 | 
			
		||||
        )
 | 
			
		||||
        try:
 | 
			
		||||
            platform = vol.All(vol.Upper, vol.Any(*wizard_platforms))(platform.upper())
 | 
			
		||||
            break
 | 
			
		||||
@@ -397,7 +399,7 @@ def wizard(path):
 | 
			
		||||
        boards.append(board_id)
 | 
			
		||||
 | 
			
		||||
    while True:
 | 
			
		||||
        board = input(color(Fore.BOLD_WHITE, "(board): "))
 | 
			
		||||
        board = safe_input(color(Fore.BOLD_WHITE, "(board): "))
 | 
			
		||||
        try:
 | 
			
		||||
            board = vol.All(vol.Lower, vol.Any(*boards))(board)
 | 
			
		||||
            break
 | 
			
		||||
@@ -423,7 +425,7 @@ def wizard(path):
 | 
			
		||||
    sleep(1.5)
 | 
			
		||||
    safe_print(f"For example \"{color(Fore.BOLD_WHITE, 'Abraham Linksys')}\".")
 | 
			
		||||
    while True:
 | 
			
		||||
        ssid = input(color(Fore.BOLD_WHITE, "(ssid): "))
 | 
			
		||||
        ssid = safe_input(color(Fore.BOLD_WHITE, "(ssid): "))
 | 
			
		||||
        try:
 | 
			
		||||
            ssid = cv.ssid(ssid)
 | 
			
		||||
            break
 | 
			
		||||
@@ -449,7 +451,7 @@ def wizard(path):
 | 
			
		||||
    safe_print()
 | 
			
		||||
    safe_print(f"For example \"{color(Fore.BOLD_WHITE, 'PASSWORD42')}\"")
 | 
			
		||||
    sleep(0.5)
 | 
			
		||||
    psk = input(color(Fore.BOLD_WHITE, "(PSK): "))
 | 
			
		||||
    psk = safe_input(color(Fore.BOLD_WHITE, "(PSK): "))
 | 
			
		||||
    safe_print(
 | 
			
		||||
        "Perfect! WiFi is now set up (you can create static IPs and so on later)."
 | 
			
		||||
    )
 | 
			
		||||
@@ -466,7 +468,7 @@ def wizard(path):
 | 
			
		||||
    safe_print()
 | 
			
		||||
    sleep(0.25)
 | 
			
		||||
    safe_print("Press ENTER for no password")
 | 
			
		||||
    password = input(color(Fore.BOLD_WHITE, "(password): "))
 | 
			
		||||
    password = safe_input(color(Fore.BOLD_WHITE, "(password): "))
 | 
			
		||||
 | 
			
		||||
    if not wizard_write(
 | 
			
		||||
        path=path,
 | 
			
		||||
 
 | 
			
		||||
@@ -57,6 +57,7 @@ lib_deps =
 | 
			
		||||
    ${common.lib_deps}
 | 
			
		||||
    SPI                                                   ; spi (Arduino built-in)
 | 
			
		||||
    Wire                                                  ; i2c (Arduino built-int)
 | 
			
		||||
    heman/AsyncMqttClient-esphome@1.0.0                   ; mqtt
 | 
			
		||||
    esphome/ESPAsyncWebServer-esphome@2.1.0               ; web_server_base
 | 
			
		||||
    fastled/FastLED@3.3.2                                 ; fastled_base
 | 
			
		||||
    mikalhart/TinyGPSPlus@1.0.2                           ; gps
 | 
			
		||||
@@ -88,8 +89,7 @@ lib_deps =
 | 
			
		||||
    ${common:arduino.lib_deps}
 | 
			
		||||
    ESP8266WiFi                           ; wifi (Arduino built-in)
 | 
			
		||||
    Update                                ; ota (Arduino built-in)
 | 
			
		||||
    ottowinter/AsyncMqttClient-esphome@0.8.6              ; mqtt
 | 
			
		||||
    esphome/ESPAsyncTCP-esphome@1.2.3  ; async_tcp
 | 
			
		||||
    esphome/ESPAsyncTCP-esphome@2.0.0     ; async_tcp
 | 
			
		||||
    ESP8266HTTPClient                     ; http_request (Arduino built-in)
 | 
			
		||||
    ESP8266mDNS                           ; mdns (Arduino built-in)
 | 
			
		||||
    DNSServer                             ; captive_portal (Arduino built-in)
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ esptool==4.6.2
 | 
			
		||||
click==8.1.7
 | 
			
		||||
esphome-dashboard==20230904.0
 | 
			
		||||
aioesphomeapi==15.0.0
 | 
			
		||||
zeroconf==0.102.0
 | 
			
		||||
zeroconf==0.108.0
 | 
			
		||||
 | 
			
		||||
# esp-idf requires this, but doesn't bundle it by default
 | 
			
		||||
# https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
pylint==2.17.5
 | 
			
		||||
flake8==6.1.0  # also change in .pre-commit-config.yaml when updating
 | 
			
		||||
black==23.7.0  # also change in .pre-commit-config.yaml when updating
 | 
			
		||||
black==23.9.1  # also change in .pre-commit-config.yaml when updating
 | 
			
		||||
pyupgrade==3.10.1  # also change in .pre-commit-config.yaml when updating
 | 
			
		||||
pre-commit
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										697
									
								
								tests/test11.5.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										697
									
								
								tests/test11.5.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,697 @@
 | 
			
		||||
---
 | 
			
		||||
# copy of test5.yaml configured to build on IDF 5
 | 
			
		||||
esphome:
 | 
			
		||||
  name: test11-5
 | 
			
		||||
  build_path: build/test11.5
 | 
			
		||||
  project:
 | 
			
		||||
    name: esphome.test11_5_project
 | 
			
		||||
    version: "1.0.0"
 | 
			
		||||
 | 
			
		||||
esp32:
 | 
			
		||||
  board: nodemcu-32s
 | 
			
		||||
  framework:
 | 
			
		||||
    type: esp-idf
 | 
			
		||||
    version: 5.0.2
 | 
			
		||||
    platform_version: 6.3.2
 | 
			
		||||
    advanced:
 | 
			
		||||
      ignore_efuse_mac_crc: true
 | 
			
		||||
 | 
			
		||||
wifi:
 | 
			
		||||
  networks:
 | 
			
		||||
    - ssid: "MySSID"
 | 
			
		||||
      password: "password1"
 | 
			
		||||
      manual_ip:
 | 
			
		||||
        static_ip: 192.168.1.23
 | 
			
		||||
        gateway: 192.168.1.1
 | 
			
		||||
        subnet: 255.255.255.0
 | 
			
		||||
 | 
			
		||||
api:
 | 
			
		||||
 | 
			
		||||
ota:
 | 
			
		||||
 | 
			
		||||
logger:
 | 
			
		||||
 | 
			
		||||
debug:
 | 
			
		||||
 | 
			
		||||
psram:
 | 
			
		||||
 | 
			
		||||
uart:
 | 
			
		||||
  - id: uart_1
 | 
			
		||||
    tx_pin: 1
 | 
			
		||||
    rx_pin: 3
 | 
			
		||||
    baud_rate: 9600
 | 
			
		||||
  - id: uart_2
 | 
			
		||||
    tx_pin: 17
 | 
			
		||||
    rx_pin: 16
 | 
			
		||||
    baud_rate: 19200
 | 
			
		||||
 | 
			
		||||
i2c:
 | 
			
		||||
  frequency: 100khz
 | 
			
		||||
 | 
			
		||||
modbus:
 | 
			
		||||
  uart_id: uart_1
 | 
			
		||||
  flow_control_pin: 5
 | 
			
		||||
  id: mod_bus1
 | 
			
		||||
 | 
			
		||||
modbus_controller:
 | 
			
		||||
  - id: modbus_controller_test
 | 
			
		||||
    address: 0x2
 | 
			
		||||
    modbus_id: mod_bus1
 | 
			
		||||
 | 
			
		||||
mqtt:
 | 
			
		||||
  broker: test.mosquitto.org
 | 
			
		||||
  port: 1883
 | 
			
		||||
  discovery: true
 | 
			
		||||
  discovery_prefix: homeassistant
 | 
			
		||||
  idf_send_async: false
 | 
			
		||||
  on_message:
 | 
			
		||||
    topic: testing/sensor/testing_sensor/state
 | 
			
		||||
    qos: 0
 | 
			
		||||
    then:
 | 
			
		||||
      # yamllint disable rule:line-length
 | 
			
		||||
      - lambda: |-
 | 
			
		||||
          ESP_LOGD("Mqtt Test", "testing/sensor/testing_sensor/state=[%s]", x.c_str());
 | 
			
		||||
      # yamllint enable rule:line-length
 | 
			
		||||
 | 
			
		||||
vbus:
 | 
			
		||||
  - uart_id: uart_2
 | 
			
		||||
 | 
			
		||||
binary_sensor:
 | 
			
		||||
  - platform: gpio
 | 
			
		||||
    pin: GPIO0
 | 
			
		||||
    id: io0_button
 | 
			
		||||
    icon: mdi:gesture-tap-button
 | 
			
		||||
 | 
			
		||||
  - platform: modbus_controller
 | 
			
		||||
    modbus_controller_id: modbus_controller_test
 | 
			
		||||
    id: modbus_binsensortest
 | 
			
		||||
    register_type: read
 | 
			
		||||
    address: 0x3200
 | 
			
		||||
    bitmask: 0x80 # (bit 8)
 | 
			
		||||
    lambda: "return x;"
 | 
			
		||||
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: Button0
 | 
			
		||||
    key: 0
 | 
			
		||||
    filters:
 | 
			
		||||
      - delayed_on: 10ms
 | 
			
		||||
    on_press:
 | 
			
		||||
      then:
 | 
			
		||||
        - switch.turn_on: Led0
 | 
			
		||||
    on_release:
 | 
			
		||||
      then:
 | 
			
		||||
        - switch.turn_off: Led0
 | 
			
		||||
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: Button1
 | 
			
		||||
    key: 1
 | 
			
		||||
    on_press:
 | 
			
		||||
      then:
 | 
			
		||||
        - switch.turn_on: Led1
 | 
			
		||||
    on_release:
 | 
			
		||||
      then:
 | 
			
		||||
        - switch.turn_off: Led1
 | 
			
		||||
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: Button2
 | 
			
		||||
    key: 2
 | 
			
		||||
    on_press:
 | 
			
		||||
      then:
 | 
			
		||||
        - switch.turn_on: Led2
 | 
			
		||||
    on_release:
 | 
			
		||||
      then:
 | 
			
		||||
        - switch.turn_off: Led2
 | 
			
		||||
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: Button3
 | 
			
		||||
    key: 3
 | 
			
		||||
    on_press:
 | 
			
		||||
      then:
 | 
			
		||||
        - switch.turn_on: Led3
 | 
			
		||||
    on_release:
 | 
			
		||||
      then:
 | 
			
		||||
        - switch.turn_off: Led3
 | 
			
		||||
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: Button4
 | 
			
		||||
    key: 4
 | 
			
		||||
    on_press:
 | 
			
		||||
      then:
 | 
			
		||||
        - output.turn_on: Led4
 | 
			
		||||
    on_release:
 | 
			
		||||
      then:
 | 
			
		||||
        - output.turn_off: Led4
 | 
			
		||||
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: Button5
 | 
			
		||||
    key: 5
 | 
			
		||||
    on_press:
 | 
			
		||||
      then:
 | 
			
		||||
        - output.turn_on: Led5
 | 
			
		||||
    on_release:
 | 
			
		||||
      then:
 | 
			
		||||
        - output.turn_off: Led5
 | 
			
		||||
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: Button6
 | 
			
		||||
    key: 6
 | 
			
		||||
    on_press:
 | 
			
		||||
      then:
 | 
			
		||||
        - output.turn_on: Led6
 | 
			
		||||
    on_release:
 | 
			
		||||
      then:
 | 
			
		||||
        - output.turn_off: Led6
 | 
			
		||||
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: Button7
 | 
			
		||||
    key: 7
 | 
			
		||||
    on_press:
 | 
			
		||||
      then:
 | 
			
		||||
        - output.turn_on: Led7
 | 
			
		||||
    on_release:
 | 
			
		||||
      then:
 | 
			
		||||
        - output.turn_off: Led7
 | 
			
		||||
 | 
			
		||||
  - platform: gpio
 | 
			
		||||
    id: sn74hc165_pin_0
 | 
			
		||||
    pin:
 | 
			
		||||
      sn74hc165: sn74hc165_hub
 | 
			
		||||
      number: 0
 | 
			
		||||
 | 
			
		||||
  - platform: ezo_pmp
 | 
			
		||||
    pump_state:
 | 
			
		||||
      name: "Pump State"
 | 
			
		||||
    is_paused:
 | 
			
		||||
      name: "Is Paused"
 | 
			
		||||
 | 
			
		||||
  - platform: matrix_keypad
 | 
			
		||||
    keypad_id: keypad
 | 
			
		||||
    id: key4
 | 
			
		||||
    row: 1
 | 
			
		||||
    col: 1
 | 
			
		||||
  - platform: matrix_keypad
 | 
			
		||||
    id: key1
 | 
			
		||||
    key: 1
 | 
			
		||||
 | 
			
		||||
  - platform: vbus
 | 
			
		||||
    model: deltasol_bs_plus
 | 
			
		||||
    relay2:
 | 
			
		||||
      name: Relay 2 On
 | 
			
		||||
    sensor1_error:
 | 
			
		||||
      name: Sensor 1 Error
 | 
			
		||||
 | 
			
		||||
  - platform: vbus
 | 
			
		||||
    model: custom
 | 
			
		||||
    command: 0x100
 | 
			
		||||
    source: 0x1234
 | 
			
		||||
    dest: 0x10
 | 
			
		||||
    binary_sensors:
 | 
			
		||||
      - id: vcustom_b
 | 
			
		||||
        name: VBus Custom Binary Sensor
 | 
			
		||||
        lambda: return x[0] & 1;
 | 
			
		||||
 | 
			
		||||
tlc5947:
 | 
			
		||||
  data_pin: GPIO12
 | 
			
		||||
  clock_pin: GPIO14
 | 
			
		||||
  lat_pin: GPIO15
 | 
			
		||||
 | 
			
		||||
gp8403:
 | 
			
		||||
  - id: gp8403_5v
 | 
			
		||||
    voltage: 5V
 | 
			
		||||
  - id: gp8403_10v
 | 
			
		||||
    voltage: 10V
 | 
			
		||||
 | 
			
		||||
output:
 | 
			
		||||
  - platform: gpio
 | 
			
		||||
    pin: GPIO2
 | 
			
		||||
    id: built_in_led
 | 
			
		||||
 | 
			
		||||
  - platform: tlc5947
 | 
			
		||||
    id: output_red
 | 
			
		||||
    channel: 0
 | 
			
		||||
    max_power: 0.8
 | 
			
		||||
 | 
			
		||||
  - platform: mcp47a1
 | 
			
		||||
    id: output_mcp47a1
 | 
			
		||||
 | 
			
		||||
  - platform: modbus_controller
 | 
			
		||||
    modbus_controller_id: modbus_controller_test
 | 
			
		||||
    id: modbus_output_test
 | 
			
		||||
    lambda: |-
 | 
			
		||||
      return x * 1.0 ;
 | 
			
		||||
    address: 0x9001
 | 
			
		||||
    value_type: U_WORD
 | 
			
		||||
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: Led4
 | 
			
		||||
    led: 4
 | 
			
		||||
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: Led5
 | 
			
		||||
    led: 5
 | 
			
		||||
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: Led6
 | 
			
		||||
    led: 6
 | 
			
		||||
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: Led7
 | 
			
		||||
    led: 7
 | 
			
		||||
 | 
			
		||||
  - platform: gp8403
 | 
			
		||||
    id: gp8403_output_0
 | 
			
		||||
    gp8403_id: gp8403_5v
 | 
			
		||||
    channel: 0
 | 
			
		||||
  - platform: gp8403
 | 
			
		||||
    gp8403_id: gp8403_10v
 | 
			
		||||
    id: gp8403_output_1
 | 
			
		||||
    channel: 1
 | 
			
		||||
 | 
			
		||||
demo:
 | 
			
		||||
 | 
			
		||||
esp32_ble:
 | 
			
		||||
 | 
			
		||||
esp32_ble_server:
 | 
			
		||||
  manufacturer: ESPHome
 | 
			
		||||
  model: Test11
 | 
			
		||||
 | 
			
		||||
esp32_improv:
 | 
			
		||||
  authorizer: io0_button
 | 
			
		||||
  authorized_duration: 1min
 | 
			
		||||
  status_indicator: built_in_led
 | 
			
		||||
 | 
			
		||||
ezo_pmp:
 | 
			
		||||
  id: hcl_pump
 | 
			
		||||
  update_interval: 1s
 | 
			
		||||
 | 
			
		||||
number:
 | 
			
		||||
  - platform: template
 | 
			
		||||
    name: My template number
 | 
			
		||||
    id: template_number_id
 | 
			
		||||
    optimistic: true
 | 
			
		||||
    max_value: 100
 | 
			
		||||
    min_value: 0
 | 
			
		||||
    step: 5
 | 
			
		||||
    unit_of_measurement: "%"
 | 
			
		||||
    mode: slider
 | 
			
		||||
    device_class: humidity
 | 
			
		||||
    on_value:
 | 
			
		||||
      - logger.log:
 | 
			
		||||
          format: Number changed to %f
 | 
			
		||||
          args: [x]
 | 
			
		||||
    set_action:
 | 
			
		||||
      - logger.log:
 | 
			
		||||
          format: Template Number set to %f
 | 
			
		||||
          args: [x]
 | 
			
		||||
      - number.set:
 | 
			
		||||
          id: template_number_id
 | 
			
		||||
          value: 50
 | 
			
		||||
      - number.to_min: template_number_id
 | 
			
		||||
      - number.to_min:
 | 
			
		||||
          id: template_number_id
 | 
			
		||||
      - number.to_max: template_number_id
 | 
			
		||||
      - number.to_max:
 | 
			
		||||
          id: template_number_id
 | 
			
		||||
      - number.increment: template_number_id
 | 
			
		||||
      - number.increment:
 | 
			
		||||
          id: template_number_id
 | 
			
		||||
          cycle: false
 | 
			
		||||
      - number.decrement: template_number_id
 | 
			
		||||
      - number.decrement:
 | 
			
		||||
          id: template_number_id
 | 
			
		||||
          cycle: false
 | 
			
		||||
      - number.operation:
 | 
			
		||||
          id: template_number_id
 | 
			
		||||
          operation: Increment
 | 
			
		||||
          cycle: false
 | 
			
		||||
      - number.operation:
 | 
			
		||||
          id: template_number_id
 | 
			
		||||
          operation: !lambda "return NUMBER_OP_INCREMENT;"
 | 
			
		||||
          cycle: !lambda "return false;"
 | 
			
		||||
 | 
			
		||||
  - id: modbus_numbertest
 | 
			
		||||
    platform: modbus_controller
 | 
			
		||||
    modbus_controller_id: modbus_controller_test
 | 
			
		||||
    name: ModbusNumber
 | 
			
		||||
    address: 0x9002
 | 
			
		||||
    value_type: U_WORD
 | 
			
		||||
    lambda: "return  x * 1.0;"
 | 
			
		||||
    write_lambda: |-
 | 
			
		||||
      return x * 1.0 ;
 | 
			
		||||
    multiply: 1.0
 | 
			
		||||
 | 
			
		||||
select:
 | 
			
		||||
  - platform: template
 | 
			
		||||
    name: My template select
 | 
			
		||||
    id: template_select_id
 | 
			
		||||
    optimistic: true
 | 
			
		||||
    initial_option: two
 | 
			
		||||
    restore_value: true
 | 
			
		||||
    on_value:
 | 
			
		||||
      - logger.log:
 | 
			
		||||
          format: Select changed to %s (index %d)"
 | 
			
		||||
          args: ["x.c_str()", "i"]
 | 
			
		||||
    set_action:
 | 
			
		||||
      - logger.log:
 | 
			
		||||
          format: Template Select set to %s
 | 
			
		||||
          args: ["x.c_str()"]
 | 
			
		||||
      - select.set:
 | 
			
		||||
          id: template_select_id
 | 
			
		||||
          option: two
 | 
			
		||||
      - select.first: template_select_id
 | 
			
		||||
      - select.last:
 | 
			
		||||
          id: template_select_id
 | 
			
		||||
      - select.previous: template_select_id
 | 
			
		||||
      - select.next:
 | 
			
		||||
          id: template_select_id
 | 
			
		||||
          cycle: false
 | 
			
		||||
      - select.operation:
 | 
			
		||||
          id: template_select_id
 | 
			
		||||
          operation: Previous
 | 
			
		||||
          cycle: false
 | 
			
		||||
      - select.operation:
 | 
			
		||||
          id: template_select_id
 | 
			
		||||
          operation: !lambda "return SELECT_OP_PREVIOUS;"
 | 
			
		||||
          cycle: !lambda "return true;"
 | 
			
		||||
      - select.set_index:
 | 
			
		||||
          id: template_select_id
 | 
			
		||||
          index: 1
 | 
			
		||||
      - select.set_index:
 | 
			
		||||
          id: template_select_id
 | 
			
		||||
          index: !lambda "return 1 + 1;"
 | 
			
		||||
    options:
 | 
			
		||||
      - one
 | 
			
		||||
      - two
 | 
			
		||||
      - three
 | 
			
		||||
 | 
			
		||||
  - platform: modbus_controller
 | 
			
		||||
    name: Modbus Select Register 1000
 | 
			
		||||
    address: 1000
 | 
			
		||||
    value_type: U_WORD
 | 
			
		||||
    optionsmap:
 | 
			
		||||
      "Zero": 0
 | 
			
		||||
      "One": 1
 | 
			
		||||
      "Two": 2
 | 
			
		||||
      "Three": 3
 | 
			
		||||
 | 
			
		||||
sensor:
 | 
			
		||||
  - platform: adc
 | 
			
		||||
    id: adc_sensor_p32
 | 
			
		||||
    name: ADC pin 32
 | 
			
		||||
    pin: 32
 | 
			
		||||
    attenuation: 11db
 | 
			
		||||
    update_interval: 1s
 | 
			
		||||
  - platform: internal_temperature
 | 
			
		||||
    name: Internal Temperature
 | 
			
		||||
  - platform: selec_meter
 | 
			
		||||
    total_active_energy:
 | 
			
		||||
      name: SelecEM2M Total Active Energy
 | 
			
		||||
    import_active_energy:
 | 
			
		||||
      name: SelecEM2M Import Active Energy
 | 
			
		||||
    export_active_energy:
 | 
			
		||||
      name: SelecEM2M Export Active Energy
 | 
			
		||||
    total_reactive_energy:
 | 
			
		||||
      name: SelecEM2M Total Reactive Energy
 | 
			
		||||
    import_reactive_energy:
 | 
			
		||||
      name: SelecEM2M Import Reactive Energy
 | 
			
		||||
    export_reactive_energy:
 | 
			
		||||
      name: SelecEM2M Export Reactive Energy
 | 
			
		||||
    apparent_energy:
 | 
			
		||||
      name: SelecEM2M Apparent Energy
 | 
			
		||||
    active_power:
 | 
			
		||||
      name: SelecEM2M Active Power
 | 
			
		||||
    reactive_power:
 | 
			
		||||
      name: SelecEM2M Reactive Power
 | 
			
		||||
    apparent_power:
 | 
			
		||||
      name: SelecEM2M Apparent Power
 | 
			
		||||
    voltage:
 | 
			
		||||
      name: SelecEM2M Voltage
 | 
			
		||||
    current:
 | 
			
		||||
      name: SelecEM2M Current
 | 
			
		||||
    power_factor:
 | 
			
		||||
      name: SelecEM2M Power Factor
 | 
			
		||||
    frequency:
 | 
			
		||||
      name: SelecEM2M Frequency
 | 
			
		||||
    maximum_demand_active_power:
 | 
			
		||||
      name: SelecEM2M Maximum Demand Active Power
 | 
			
		||||
      disabled_by_default: true
 | 
			
		||||
    maximum_demand_reactive_power:
 | 
			
		||||
      name: SelecEM2M Maximum Demand Reactive Power
 | 
			
		||||
      disabled_by_default: true
 | 
			
		||||
    maximum_demand_apparent_power:
 | 
			
		||||
      name: SelecEM2M Maximum Demand Apparent Power
 | 
			
		||||
      disabled_by_default: true
 | 
			
		||||
 | 
			
		||||
  - id: modbus_sensortest
 | 
			
		||||
    platform: modbus_controller
 | 
			
		||||
    modbus_controller_id: modbus_controller_test
 | 
			
		||||
    address: 0x331A
 | 
			
		||||
    register_type: read
 | 
			
		||||
    value_type: U_WORD
 | 
			
		||||
 | 
			
		||||
  - platform: t6615
 | 
			
		||||
    uart_id: uart_2
 | 
			
		||||
    co2:
 | 
			
		||||
      name: CO2 Sensor
 | 
			
		||||
 | 
			
		||||
  - platform: bmp3xx
 | 
			
		||||
    temperature:
 | 
			
		||||
      name: BMP Temperature
 | 
			
		||||
      oversampling: 16x
 | 
			
		||||
    pressure:
 | 
			
		||||
      name: BMP Pressure
 | 
			
		||||
    address: 0x77
 | 
			
		||||
    iir_filter: 2X
 | 
			
		||||
 | 
			
		||||
  - platform: sen5x
 | 
			
		||||
    id: sen54
 | 
			
		||||
    temperature:
 | 
			
		||||
      name: Temperature
 | 
			
		||||
      accuracy_decimals: 1
 | 
			
		||||
    humidity:
 | 
			
		||||
      name: Humidity
 | 
			
		||||
      accuracy_decimals: 0
 | 
			
		||||
    pm_1_0:
 | 
			
		||||
      name: PM <1µm Weight concentration
 | 
			
		||||
      id: pm_1_0
 | 
			
		||||
      accuracy_decimals: 1
 | 
			
		||||
    pm_2_5:
 | 
			
		||||
      name: PM <2.5µm Weight concentration
 | 
			
		||||
      id: pm_2_5
 | 
			
		||||
      accuracy_decimals: 1
 | 
			
		||||
    pm_4_0:
 | 
			
		||||
      name: PM <4µm Weight concentration
 | 
			
		||||
      id: pm_4_0
 | 
			
		||||
      accuracy_decimals: 1
 | 
			
		||||
    pm_10_0:
 | 
			
		||||
      name: PM <10µm Weight concentration
 | 
			
		||||
      id: pm_10_0
 | 
			
		||||
      accuracy_decimals: 1
 | 
			
		||||
    nox:
 | 
			
		||||
      name: NOx
 | 
			
		||||
    voc:
 | 
			
		||||
      name: VOC
 | 
			
		||||
      algorithm_tuning:
 | 
			
		||||
        index_offset: 100
 | 
			
		||||
        learning_time_offset_hours: 12
 | 
			
		||||
        learning_time_gain_hours: 12
 | 
			
		||||
        gating_max_duration_minutes: 180
 | 
			
		||||
        std_initial: 50
 | 
			
		||||
        gain_factor: 230
 | 
			
		||||
    temperature_compensation:
 | 
			
		||||
      offset: 0
 | 
			
		||||
      normalized_offset_slope: 0
 | 
			
		||||
      time_constant: 0
 | 
			
		||||
    auto_cleaning_interval: 604800s
 | 
			
		||||
    acceleration_mode: low
 | 
			
		||||
    store_baseline: true
 | 
			
		||||
    address: 0x69
 | 
			
		||||
  - platform: mcp9600
 | 
			
		||||
    thermocouple_type: K
 | 
			
		||||
    hot_junction:
 | 
			
		||||
      name: Thermocouple Temperature
 | 
			
		||||
    cold_junction:
 | 
			
		||||
      name: Ambient Temperature
 | 
			
		||||
 | 
			
		||||
  - platform: ezo_pmp
 | 
			
		||||
    current_volume_dosed:
 | 
			
		||||
      name: Current Volume Dosed
 | 
			
		||||
    total_volume_dosed:
 | 
			
		||||
      name: Total Volume Dosed
 | 
			
		||||
    absolute_total_volume_dosed:
 | 
			
		||||
      name: Absolute Total Volume Dosed
 | 
			
		||||
    pump_voltage:
 | 
			
		||||
      name: Pump Voltage
 | 
			
		||||
    last_volume_requested:
 | 
			
		||||
      name: Last Volume Requested
 | 
			
		||||
    max_flow_rate:
 | 
			
		||||
      name: Max Flow Rate
 | 
			
		||||
 | 
			
		||||
  - platform: vbus
 | 
			
		||||
    model: deltasol c
 | 
			
		||||
    temperature_3:
 | 
			
		||||
      name: Temperature 3
 | 
			
		||||
    operating_hours_1:
 | 
			
		||||
      name: Operating Hours 1
 | 
			
		||||
    heat_quantity:
 | 
			
		||||
      name: Heat Quantity
 | 
			
		||||
    time:
 | 
			
		||||
      name: System Time
 | 
			
		||||
 | 
			
		||||
  - platform: debug
 | 
			
		||||
    free:
 | 
			
		||||
      name: "Heap Free"
 | 
			
		||||
    block:
 | 
			
		||||
      name: "Heap Max Block"
 | 
			
		||||
    loop_time:
 | 
			
		||||
      name: "Loop Time"
 | 
			
		||||
    psram:
 | 
			
		||||
      name: "PSRAM Free"
 | 
			
		||||
 | 
			
		||||
  - platform: vbus
 | 
			
		||||
    model: custom
 | 
			
		||||
    command: 0x100
 | 
			
		||||
    source: 0x1234
 | 
			
		||||
    dest: 0x10
 | 
			
		||||
    sensors:
 | 
			
		||||
      - id: vcustom
 | 
			
		||||
        name: VBus Custom Sensor
 | 
			
		||||
        lambda: return x[0] / 10.0;
 | 
			
		||||
 | 
			
		||||
  - platform: kuntze
 | 
			
		||||
    ph:
 | 
			
		||||
      name: Kuntze pH
 | 
			
		||||
    temperature:
 | 
			
		||||
      name: Kuntze temperature
 | 
			
		||||
 | 
			
		||||
script:
 | 
			
		||||
  - id: automation_test
 | 
			
		||||
    then:
 | 
			
		||||
      - repeat:
 | 
			
		||||
          count: 5
 | 
			
		||||
          then:
 | 
			
		||||
            - logger.log: looping!
 | 
			
		||||
 | 
			
		||||
  - id: zero_repeat_test
 | 
			
		||||
    then:
 | 
			
		||||
      - repeat:
 | 
			
		||||
          count: !lambda "return 0;"
 | 
			
		||||
          then:
 | 
			
		||||
            - logger.log: shouldn't see mee!
 | 
			
		||||
 | 
			
		||||
switch:
 | 
			
		||||
  - platform: modbus_controller
 | 
			
		||||
    modbus_controller_id: modbus_controller_test
 | 
			
		||||
    id: modbus_switch_test
 | 
			
		||||
    register_type: coil
 | 
			
		||||
    address: 2
 | 
			
		||||
    bitmask: 1
 | 
			
		||||
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: Led0
 | 
			
		||||
    led: 0
 | 
			
		||||
    name: TM1638Led0
 | 
			
		||||
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: Led1
 | 
			
		||||
    led: 1
 | 
			
		||||
    name: TM1638Led1
 | 
			
		||||
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: Led2
 | 
			
		||||
    led: 2
 | 
			
		||||
    name: TM1638Led2
 | 
			
		||||
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: Led3
 | 
			
		||||
    led: 3
 | 
			
		||||
    name: TM1638Led3
 | 
			
		||||
 | 
			
		||||
display:
 | 
			
		||||
  - platform: tm1638
 | 
			
		||||
    id: primarydisplay
 | 
			
		||||
    stb_pin: 5 #TM1638 STB
 | 
			
		||||
    clk_pin: 18 #TM1638 CLK
 | 
			
		||||
    dio_pin: 23 #TM1638 DIO
 | 
			
		||||
    update_interval: 5s
 | 
			
		||||
    intensity: 5
 | 
			
		||||
    lambda: |-
 | 
			
		||||
      it.print("81818181");
 | 
			
		||||
 | 
			
		||||
time:
 | 
			
		||||
  - platform: pcf85063
 | 
			
		||||
  - platform: pcf8563
 | 
			
		||||
 | 
			
		||||
text_sensor:
 | 
			
		||||
  - platform: ezo_pmp
 | 
			
		||||
    dosing_mode:
 | 
			
		||||
      name: Dosing Mode
 | 
			
		||||
    calibration_status:
 | 
			
		||||
      name: Calibration Status
 | 
			
		||||
      on_value:
 | 
			
		||||
        - ezo_pmp.dose_volume:
 | 
			
		||||
            id: hcl_pump
 | 
			
		||||
            volume: 10
 | 
			
		||||
        - ezo_pmp.dose_volume_over_time:
 | 
			
		||||
            id: hcl_pump
 | 
			
		||||
            volume: 10
 | 
			
		||||
            duration: 2
 | 
			
		||||
        - ezo_pmp.dose_with_constant_flow_rate:
 | 
			
		||||
            id: hcl_pump
 | 
			
		||||
            volume_per_minute: 10
 | 
			
		||||
            duration: 2
 | 
			
		||||
        - ezo_pmp.set_calibration_volume:
 | 
			
		||||
            id: hcl_pump
 | 
			
		||||
            volume: 10
 | 
			
		||||
        - ezo_pmp.find: hcl_pump
 | 
			
		||||
        - ezo_pmp.dose_continuously: hcl_pump
 | 
			
		||||
        - ezo_pmp.clear_total_volume_dosed: hcl_pump
 | 
			
		||||
        - ezo_pmp.clear_calibration: hcl_pump
 | 
			
		||||
        - ezo_pmp.pause_dosing: hcl_pump
 | 
			
		||||
        - ezo_pmp.stop_dosing: hcl_pump
 | 
			
		||||
        - ezo_pmp.arbitrary_command:
 | 
			
		||||
            id: hcl_pump
 | 
			
		||||
            command: D,?
 | 
			
		||||
 | 
			
		||||
sn74hc165:
 | 
			
		||||
  id: sn74hc165_hub
 | 
			
		||||
  data_pin: GPIO12
 | 
			
		||||
  clock_pin: GPIO14
 | 
			
		||||
  load_pin: GPIO27
 | 
			
		||||
  clock_inhibit_pin: GPIO26
 | 
			
		||||
  sr_count: 4
 | 
			
		||||
 | 
			
		||||
matrix_keypad:
 | 
			
		||||
  id: keypad
 | 
			
		||||
  rows:
 | 
			
		||||
    - pin: 21
 | 
			
		||||
    - pin: 19
 | 
			
		||||
  columns:
 | 
			
		||||
    - pin: 17
 | 
			
		||||
    - pin: 16
 | 
			
		||||
  keys: "1234"
 | 
			
		||||
 | 
			
		||||
key_collector:
 | 
			
		||||
  - id: reader
 | 
			
		||||
    source_id: keypad
 | 
			
		||||
    min_length: 4
 | 
			
		||||
    max_length: 4
 | 
			
		||||
 | 
			
		||||
light:
 | 
			
		||||
  - platform: esp32_rmt_led_strip
 | 
			
		||||
    id: led_strip
 | 
			
		||||
    pin: 13
 | 
			
		||||
    num_leds: 60
 | 
			
		||||
    rmt_channel: 6
 | 
			
		||||
    rgb_order: GRB
 | 
			
		||||
    chipset: ws2812
 | 
			
		||||
  - platform: esp32_rmt_led_strip
 | 
			
		||||
    id: led_strip2
 | 
			
		||||
    pin: 15
 | 
			
		||||
    num_leds: 60
 | 
			
		||||
    rmt_channel: 2
 | 
			
		||||
    rgb_order: RGB
 | 
			
		||||
    bit0_high: 100us
 | 
			
		||||
    bit0_low: 100us
 | 
			
		||||
    bit1_high: 100us
 | 
			
		||||
    bit1_low: 100us
 | 
			
		||||
@@ -392,6 +392,12 @@ select:
 | 
			
		||||
      "Three": 3
 | 
			
		||||
 | 
			
		||||
sensor:
 | 
			
		||||
  - platform: adc
 | 
			
		||||
    id: adc_sensor_p32
 | 
			
		||||
    name: ADC pin 32
 | 
			
		||||
    pin: 32
 | 
			
		||||
    attenuation: 11db
 | 
			
		||||
    update_interval: 1s
 | 
			
		||||
  - platform: internal_temperature
 | 
			
		||||
    name: Internal Temperature
 | 
			
		||||
  - platform: selec_meter
 | 
			
		||||
 
 | 
			
		||||
@@ -319,7 +319,7 @@ def test_wizard_accepts_default_answers_esp8266(tmpdir, monkeypatch, wizard_answ
 | 
			
		||||
    config_file = tmpdir.join("test.yaml")
 | 
			
		||||
    input_mock = MagicMock(side_effect=wizard_answers)
 | 
			
		||||
    monkeypatch.setattr("builtins.input", input_mock)
 | 
			
		||||
    monkeypatch.setattr(wz, "safe_print", lambda t=None: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "sleep", lambda _: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "wizard_write", MagicMock())
 | 
			
		||||
 | 
			
		||||
@@ -341,7 +341,7 @@ def test_wizard_accepts_default_answers_esp32(tmpdir, monkeypatch, wizard_answer
 | 
			
		||||
    config_file = tmpdir.join("test.yaml")
 | 
			
		||||
    input_mock = MagicMock(side_effect=wizard_answers)
 | 
			
		||||
    monkeypatch.setattr("builtins.input", input_mock)
 | 
			
		||||
    monkeypatch.setattr(wz, "safe_print", lambda t=None: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "sleep", lambda _: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "wizard_write", MagicMock())
 | 
			
		||||
 | 
			
		||||
@@ -371,7 +371,7 @@ def test_wizard_offers_better_node_name(tmpdir, monkeypatch, wizard_answers):
 | 
			
		||||
    config_file = tmpdir.join("test.yaml")
 | 
			
		||||
    input_mock = MagicMock(side_effect=wizard_answers)
 | 
			
		||||
    monkeypatch.setattr("builtins.input", input_mock)
 | 
			
		||||
    monkeypatch.setattr(wz, "safe_print", lambda t=None: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "sleep", lambda _: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "wizard_write", MagicMock())
 | 
			
		||||
 | 
			
		||||
@@ -394,7 +394,7 @@ def test_wizard_requires_correct_platform(tmpdir, monkeypatch, wizard_answers):
 | 
			
		||||
    config_file = tmpdir.join("test.yaml")
 | 
			
		||||
    input_mock = MagicMock(side_effect=wizard_answers)
 | 
			
		||||
    monkeypatch.setattr("builtins.input", input_mock)
 | 
			
		||||
    monkeypatch.setattr(wz, "safe_print", lambda t=None: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "sleep", lambda _: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "wizard_write", MagicMock())
 | 
			
		||||
 | 
			
		||||
@@ -416,7 +416,7 @@ def test_wizard_requires_correct_board(tmpdir, monkeypatch, wizard_answers):
 | 
			
		||||
    config_file = tmpdir.join("test.yaml")
 | 
			
		||||
    input_mock = MagicMock(side_effect=wizard_answers)
 | 
			
		||||
    monkeypatch.setattr("builtins.input", input_mock)
 | 
			
		||||
    monkeypatch.setattr(wz, "safe_print", lambda t=None: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "sleep", lambda _: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "wizard_write", MagicMock())
 | 
			
		||||
 | 
			
		||||
@@ -438,7 +438,7 @@ def test_wizard_requires_valid_ssid(tmpdir, monkeypatch, wizard_answers):
 | 
			
		||||
    config_file = tmpdir.join("test.yaml")
 | 
			
		||||
    input_mock = MagicMock(side_effect=wizard_answers)
 | 
			
		||||
    monkeypatch.setattr("builtins.input", input_mock)
 | 
			
		||||
    monkeypatch.setattr(wz, "safe_print", lambda t=None: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "safe_print", lambda t=None, end=None: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "sleep", lambda _: 0)
 | 
			
		||||
    monkeypatch.setattr(wz, "wizard_write", MagicMock())
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user