mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-03 16:41:50 +00:00 
			
		
		
		
	Compare commits
	
		
			170 Commits
		
	
	
		
			2024.5.0b4
			...
			jesserockz
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					385d5c018b | ||
| 
						 | 
					460ce5991c | ||
| 
						 | 
					03b2d3f9d3 | ||
| 
						 | 
					8ef4aaa70e | ||
| 
						 | 
					7143e9cd9e | ||
| 
						 | 
					cc217d8a83 | ||
| 
						 | 
					c52d5c0279 | ||
| 
						 | 
					f36a96c8e2 | ||
| 
						 | 
					594856899a | ||
| 
						 | 
					f7742cdf19 | ||
| 
						 | 
					5b062a222c | ||
| 
						 | 
					664ee56dc5 | ||
| 
						 | 
					388b2c2de0 | ||
| 
						 | 
					ce4a3d9950 | ||
| 
						 | 
					ac9f57600d | ||
| 
						 | 
					69d38f6137 | ||
| 
						 | 
					eb75778f84 | ||
| 
						 | 
					2d56d8d84f | ||
| 
						 | 
					cdf83c5d8c | ||
| 
						 | 
					78b48209aa | ||
| 
						 | 
					05491e756b | ||
| 
						 | 
					b8d2a6f574 | ||
| 
						 | 
					2353b2b5e1 | ||
| 
						 | 
					2beb1f0336 | ||
| 
						 | 
					41e13fa6f4 | ||
| 
						 | 
					1f301df51d | ||
| 
						 | 
					2894a138e7 | ||
| 
						 | 
					8dfe1d5220 | ||
| 
						 | 
					dd27881336 | ||
| 
						 | 
					8aba890e69 | ||
| 
						 | 
					63fc8ab10a | ||
| 
						 | 
					9de8eaff24 | ||
| 
						 | 
					c130ddbe9c | ||
| 
						 | 
					a7fc1a6298 | ||
| 
						 | 
					854d3f2e4a | ||
| 
						 | 
					5ae32e81c3 | ||
| 
						 | 
					439fd94718 | ||
| 
						 | 
					6d5d382f3d | ||
| 
						 | 
					60433c5e64 | ||
| 
						 | 
					bff24e2977 | ||
| 
						 | 
					ec3164f800 | ||
| 
						 | 
					2b691ad5ad | ||
| 
						 | 
					06996def72 | ||
| 
						 | 
					db6f6f0cb7 | ||
| 
						 | 
					497cf8742f | ||
| 
						 | 
					d2b35adcc8 | ||
| 
						 | 
					3fe2fc9b56 | ||
| 
						 | 
					4cd4b168b4 | ||
| 
						 | 
					f07479419c | ||
| 
						 | 
					54b51269ab | ||
| 
						 | 
					6e4fd428e7 | ||
| 
						 | 
					e285196709 | ||
| 
						 | 
					17c6bf57cd | ||
| 
						 | 
					4125b48b86 | ||
| 
						 | 
					6d341ce4e7 | ||
| 
						 | 
					964410bd64 | ||
| 
						 | 
					d72ab25d46 | ||
| 
						 | 
					af755380b7 | ||
| 
						 | 
					04db724295 | ||
| 
						 | 
					863bee28d9 | ||
| 
						 | 
					9d03f47233 | ||
| 
						 | 
					c2d67659f3 | ||
| 
						 | 
					aed0593793 | ||
| 
						 | 
					4ab7a5d964 | ||
| 
						 | 
					7f9383c83b | ||
| 
						 | 
					9a6fde21ee | ||
| 
						 | 
					1ca7c2d7dd | ||
| 
						 | 
					76abf2200c | ||
| 
						 | 
					83d3584173 | ||
| 
						 | 
					0ee4348777 | ||
| 
						 | 
					fcdf36e991 | ||
| 
						 | 
					5eb8efd8b3 | ||
| 
						 | 
					cd0f557940 | ||
| 
						 | 
					efde677ca9 | ||
| 
						 | 
					2eebee1de7 | ||
| 
						 | 
					525c4891d5 | ||
| 
						 | 
					ce6dc040da | ||
| 
						 | 
					9de67feccd | ||
| 
						 | 
					bad400e1cd | ||
| 
						 | 
					59b1e9c1b0 | ||
| 
						 | 
					25ee24299a | ||
| 
						 | 
					81ef67cfbb | ||
| 
						 | 
					f235dcc096 | ||
| 
						 | 
					d2d3db4b8c | ||
| 
						 | 
					ec6d86c8f5 | ||
| 
						 | 
					7452879fb1 | ||
| 
						 | 
					4fc2f2284a | ||
| 
						 | 
					840f69ffe6 | ||
| 
						 | 
					b9bb3cd4be | ||
| 
						 | 
					91e7a44c31 | ||
| 
						 | 
					080f8bc86e | ||
| 
						 | 
					a85d37a1cf | ||
| 
						 | 
					ba73187c1b | ||
| 
						 | 
					4469ba4024 | ||
| 
						 | 
					70e0925f9a | ||
| 
						 | 
					1164cb8610 | ||
| 
						 | 
					94b63d7bc2 | ||
| 
						 | 
					df838b5788 | ||
| 
						 | 
					d410cc4f7b | ||
| 
						 | 
					b06e0746f5 | ||
| 
						 | 
					034c196ad8 | ||
| 
						 | 
					996f71c03c | ||
| 
						 | 
					98cb6555df | ||
| 
						 | 
					0bb2773c64 | ||
| 
						 | 
					7c243dafb3 | ||
| 
						 | 
					247b2eee30 | ||
| 
						 | 
					f46c499c4e | ||
| 
						 | 
					f91c31f093 | ||
| 
						 | 
					a27c05483c | ||
| 
						 | 
					bf48ccaf22 | ||
| 
						 | 
					f2ef06d8b5 | ||
| 
						 | 
					f0ec900e48 | ||
| 
						 | 
					7d804bf90f | ||
| 
						 | 
					2921831b55 | ||
| 
						 | 
					08509f7755 | ||
| 
						 | 
					ebfccc64c7 | ||
| 
						 | 
					8952719045 | ||
| 
						 | 
					073fb4c124 | ||
| 
						 | 
					46eee4a4f0 | ||
| 
						 | 
					773951d85e | ||
| 
						 | 
					1f29023c92 | ||
| 
						 | 
					caa8c820de | ||
| 
						 | 
					9f1ba00b7c | ||
| 
						 | 
					891f56b421 | ||
| 
						 | 
					0d3adc8f0c | ||
| 
						 | 
					d7cb953994 | ||
| 
						 | 
					ad0a1c5c35 | ||
| 
						 | 
					5d2e3a7d8d | ||
| 
						 | 
					ebc3f0fe17 | ||
| 
						 | 
					9a6e90af54 | ||
| 
						 | 
					55e4532a88 | ||
| 
						 | 
					bd8afa51cd | ||
| 
						 | 
					db4aa0b679 | ||
| 
						 | 
					28a09cc0d0 | ||
| 
						 | 
					128fad57b3 | ||
| 
						 | 
					6f53607e5a | ||
| 
						 | 
					d5eeab81d6 | ||
| 
						 | 
					636037cec1 | ||
| 
						 | 
					7d791cbdfb | ||
| 
						 | 
					036a666e36 | ||
| 
						 | 
					921e56f2c6 | ||
| 
						 | 
					c94f638c0b | ||
| 
						 | 
					2ac0821cab | ||
| 
						 | 
					47b40505c2 | ||
| 
						 | 
					eae97dbaa0 | ||
| 
						 | 
					91007952e2 | ||
| 
						 | 
					5ee4bf3802 | ||
| 
						 | 
					a23d1631e1 | ||
| 
						 | 
					dd81c83686 | ||
| 
						 | 
					13e3920c13 | ||
| 
						 | 
					67ca60e2af | ||
| 
						 | 
					61b65e2726 | ||
| 
						 | 
					1a45858904 | ||
| 
						 | 
					47a1710b1e | ||
| 
						 | 
					ca5050d4a5 | ||
| 
						 | 
					8280772b91 | ||
| 
						 | 
					026c3a69b8 | ||
| 
						 | 
					78d1a50853 | ||
| 
						 | 
					ca031287a1 | ||
| 
						 | 
					5956bebcb7 | ||
| 
						 | 
					afe81184a8 | ||
| 
						 | 
					d0120cefd2 | ||
| 
						 | 
					3ec4a66c9e | ||
| 
						 | 
					819be76013 | ||
| 
						 | 
					72481006e4 | ||
| 
						 | 
					487e171443 | ||
| 
						 | 
					e48d02495b | ||
| 
						 | 
					7764ab2411 | ||
| 
						 | 
					225beb305d | ||
| 
						 | 
					b7c6125a0b | 
@@ -1,19 +1,3 @@
 | 
				
			|||||||
[metadata]
 | 
					 | 
				
			||||||
license      = MIT
 | 
					 | 
				
			||||||
license_file = LICENSE
 | 
					 | 
				
			||||||
platforms = any
 | 
					 | 
				
			||||||
description  = Make creating custom firmwares for ESP32/ESP8266 super easy.
 | 
					 | 
				
			||||||
long_description = file: README.md
 | 
					 | 
				
			||||||
keywords     = home, automation
 | 
					 | 
				
			||||||
classifier =
 | 
					 | 
				
			||||||
    Environment :: Console
 | 
					 | 
				
			||||||
    Intended Audience :: Developers
 | 
					 | 
				
			||||||
    Intended Audience :: End Users/Desktop
 | 
					 | 
				
			||||||
    License :: OSI Approved :: MIT License
 | 
					 | 
				
			||||||
    Programming Language :: C++
 | 
					 | 
				
			||||||
    Programming Language :: Python :: 3
 | 
					 | 
				
			||||||
    Topic :: Home Automation
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[flake8]
 | 
					[flake8]
 | 
				
			||||||
max-line-length = 120
 | 
					max-line-length = 120
 | 
				
			||||||
# Following 4 for black compatibility
 | 
					# Following 4 for black compatibility
 | 
				
			||||||
@@ -37,25 +21,22 @@ max-line-length = 120
 | 
				
			|||||||
# D401 First line should be in imperative mood
 | 
					# D401 First line should be in imperative mood
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ignore =
 | 
					ignore =
 | 
				
			||||||
    E501,
 | 
					  E501,
 | 
				
			||||||
    W503,
 | 
					  W503,
 | 
				
			||||||
    E203,
 | 
					  E203,
 | 
				
			||||||
    D202,
 | 
					  D202,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    D100,
 | 
					  D100,
 | 
				
			||||||
    D101,
 | 
					  D101,
 | 
				
			||||||
    D102,
 | 
					  D102,
 | 
				
			||||||
    D103,
 | 
					  D103,
 | 
				
			||||||
    D104,
 | 
					  D104,
 | 
				
			||||||
    D105,
 | 
					  D105,
 | 
				
			||||||
    D107,
 | 
					  D107,
 | 
				
			||||||
    D200,
 | 
					  D200,
 | 
				
			||||||
    D205,
 | 
					  D205,
 | 
				
			||||||
    D209,
 | 
					  D209,
 | 
				
			||||||
    D400,
 | 
					  D400,
 | 
				
			||||||
    D401,
 | 
					  D401,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exclude = api_pb2.py
 | 
					exclude = api_pb2.py
 | 
				
			||||||
 | 
					 | 
				
			||||||
[bdist_wheel]
 | 
					 | 
				
			||||||
universal = 1
 | 
					 | 
				
			||||||
							
								
								
									
										14
									
								
								.github/actions/build-image/action.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/actions/build-image/action.yaml
									
									
									
									
										vendored
									
									
								
							@@ -34,6 +34,16 @@ runs:
 | 
				
			|||||||
          echo $l >> $GITHUB_OUTPUT
 | 
					          echo $l >> $GITHUB_OUTPUT
 | 
				
			||||||
        done
 | 
					        done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # set cache-to only if dev branch
 | 
				
			||||||
 | 
					    - id: cache-to
 | 
				
			||||||
 | 
					      shell: bash
 | 
				
			||||||
 | 
					      run: |-
 | 
				
			||||||
 | 
					        if [[ "${{ github.ref }}" == "refs/heads/dev" ]]; then
 | 
				
			||||||
 | 
					          echo "value=type=gha,mode=max" >> $GITHUB_OUTPUT
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					          echo "value=" >> $GITHUB_OUTPUT
 | 
				
			||||||
 | 
					        fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: Build and push to ghcr by digest
 | 
					    - name: Build and push to ghcr by digest
 | 
				
			||||||
      id: build-ghcr
 | 
					      id: build-ghcr
 | 
				
			||||||
      uses: docker/build-push-action@v5.3.0
 | 
					      uses: docker/build-push-action@v5.3.0
 | 
				
			||||||
@@ -43,7 +53,7 @@ runs:
 | 
				
			|||||||
        platforms: ${{ inputs.platform }}
 | 
					        platforms: ${{ inputs.platform }}
 | 
				
			||||||
        target: ${{ inputs.target }}
 | 
					        target: ${{ inputs.target }}
 | 
				
			||||||
        cache-from: type=gha
 | 
					        cache-from: type=gha
 | 
				
			||||||
        cache-to: type=gha,mode=max
 | 
					        cache-to: ${{ steps.cache-to.outputs.value }}
 | 
				
			||||||
        build-args: |
 | 
					        build-args: |
 | 
				
			||||||
          BASEIMGTYPE=${{ inputs.baseimg }}
 | 
					          BASEIMGTYPE=${{ inputs.baseimg }}
 | 
				
			||||||
          BUILD_VERSION=${{ inputs.version }}
 | 
					          BUILD_VERSION=${{ inputs.version }}
 | 
				
			||||||
@@ -66,7 +76,7 @@ runs:
 | 
				
			|||||||
        platforms: ${{ inputs.platform }}
 | 
					        platforms: ${{ inputs.platform }}
 | 
				
			||||||
        target: ${{ inputs.target }}
 | 
					        target: ${{ inputs.target }}
 | 
				
			||||||
        cache-from: type=gha
 | 
					        cache-from: type=gha
 | 
				
			||||||
        cache-to: type=gha,mode=max
 | 
					        cache-to: ${{ steps.cache-to.outputs.value }}
 | 
				
			||||||
        build-args: |
 | 
					        build-args: |
 | 
				
			||||||
          BASEIMGTYPE=${{ inputs.baseimg }}
 | 
					          BASEIMGTYPE=${{ inputs.baseimg }}
 | 
				
			||||||
          BUILD_VERSION=${{ inputs.version }}
 | 
					          BUILD_VERSION=${{ inputs.version }}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/ci-api-proto.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/ci-api-proto.yml
									
									
									
									
										vendored
									
									
								
							@@ -21,7 +21,7 @@ jobs:
 | 
				
			|||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Checkout
 | 
					      - name: Checkout
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Set up Python
 | 
					      - name: Set up Python
 | 
				
			||||||
        uses: actions/setup-python@v5.1.0
 | 
					        uses: actions/setup-python@v5.1.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/ci-docker.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/ci-docker.yml
									
									
									
									
										vendored
									
									
								
							@@ -40,7 +40,7 @@ jobs:
 | 
				
			|||||||
        arch: [amd64, armv7, aarch64]
 | 
					        arch: [amd64, armv7, aarch64]
 | 
				
			||||||
        build_type: ["ha-addon", "docker", "lint"]
 | 
					        build_type: ["ha-addon", "docker", "lint"]
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v4.1.5
 | 
					      - uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Set up Python
 | 
					      - name: Set up Python
 | 
				
			||||||
        uses: actions/setup-python@v5.1.0
 | 
					        uses: actions/setup-python@v5.1.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										44
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										44
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							@@ -34,7 +34,7 @@ jobs:
 | 
				
			|||||||
      cache-key: ${{ steps.cache-key.outputs.key }}
 | 
					      cache-key: ${{ steps.cache-key.outputs.key }}
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Generate cache-key
 | 
					      - name: Generate cache-key
 | 
				
			||||||
        id: cache-key
 | 
					        id: cache-key
 | 
				
			||||||
        run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT
 | 
					        run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT
 | 
				
			||||||
@@ -66,7 +66,7 @@ jobs:
 | 
				
			|||||||
      - common
 | 
					      - common
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -87,7 +87,7 @@ jobs:
 | 
				
			|||||||
      - common
 | 
					      - common
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -108,7 +108,7 @@ jobs:
 | 
				
			|||||||
      - common
 | 
					      - common
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -129,7 +129,7 @@ jobs:
 | 
				
			|||||||
      - common
 | 
					      - common
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -150,7 +150,7 @@ jobs:
 | 
				
			|||||||
      - common
 | 
					      - common
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -199,7 +199,7 @@ jobs:
 | 
				
			|||||||
      - common
 | 
					      - common
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -229,7 +229,7 @@ jobs:
 | 
				
			|||||||
      - common
 | 
					      - common
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -254,7 +254,7 @@ jobs:
 | 
				
			|||||||
      matrix: ${{ steps.set-matrix.outputs.matrix }}
 | 
					      matrix: ${{ steps.set-matrix.outputs.matrix }}
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Find all YAML test files
 | 
					      - name: Find all YAML test files
 | 
				
			||||||
        id: set-matrix
 | 
					        id: set-matrix
 | 
				
			||||||
        run: echo "matrix=$(ls tests/test*.yaml | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT
 | 
					        run: echo "matrix=$(ls tests/test*.yaml | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT
 | 
				
			||||||
@@ -271,7 +271,7 @@ jobs:
 | 
				
			|||||||
        file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }}
 | 
					        file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }}
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -303,7 +303,7 @@ jobs:
 | 
				
			|||||||
        file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }}
 | 
					        file: ${{ fromJson(needs.compile-tests-list.outputs.matrix) }}
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -358,18 +358,26 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          python-version: ${{ env.DEFAULT_PYTHON }}
 | 
					          python-version: ${{ env.DEFAULT_PYTHON }}
 | 
				
			||||||
          cache-key: ${{ needs.common.outputs.cache-key }}
 | 
					          cache-key: ${{ needs.common.outputs.cache-key }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Cache platformio
 | 
					      - name: Cache platformio
 | 
				
			||||||
 | 
					        if: github.ref == 'refs/heads/dev'
 | 
				
			||||||
        uses: actions/cache@v4.0.2
 | 
					        uses: actions/cache@v4.0.2
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          path: ~/.platformio
 | 
					          path: ~/.platformio
 | 
				
			||||||
          # yamllint disable-line rule:line-length
 | 
					          key: platformio-${{ matrix.pio_cache_key }}
 | 
				
			||||||
          key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
 | 
					
 | 
				
			||||||
 | 
					      - name: Cache platformio
 | 
				
			||||||
 | 
					        if: github.ref != 'refs/heads/dev'
 | 
				
			||||||
 | 
					        uses: actions/cache/restore@v4.0.2
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          path: ~/.platformio
 | 
				
			||||||
 | 
					          key: platformio-${{ matrix.pio_cache_key }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Install clang-tidy
 | 
					      - name: Install clang-tidy
 | 
				
			||||||
        run: sudo apt-get install clang-tidy-14
 | 
					        run: sudo apt-get install clang-tidy-14
 | 
				
			||||||
@@ -402,7 +410,7 @@ jobs:
 | 
				
			|||||||
      count: ${{ steps.list-components.outputs.count }}
 | 
					      count: ${{ steps.list-components.outputs.count }}
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          # Fetch enough history so `git merge-base refs/remotes/origin/dev HEAD` works.
 | 
					          # Fetch enough history so `git merge-base refs/remotes/origin/dev HEAD` works.
 | 
				
			||||||
          fetch-depth: 500
 | 
					          fetch-depth: 500
 | 
				
			||||||
@@ -450,7 +458,7 @@ jobs:
 | 
				
			|||||||
        run: sudo apt-get install libsodium-dev
 | 
					        run: sudo apt-get install libsodium-dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -476,7 +484,7 @@ jobs:
 | 
				
			|||||||
      matrix: ${{ steps.split.outputs.components }}
 | 
					      matrix: ${{ steps.split.outputs.components }}
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Split components into 20 groups
 | 
					      - name: Split components into 20 groups
 | 
				
			||||||
        id: split
 | 
					        id: split
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
@@ -504,7 +512,7 @@ jobs:
 | 
				
			|||||||
        run: sudo apt-get install libsodium-dev
 | 
					        run: sudo apt-get install libsodium-dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@@ -19,7 +19,7 @@ jobs:
 | 
				
			|||||||
      tag: ${{ steps.tag.outputs.tag }}
 | 
					      tag: ${{ steps.tag.outputs.tag }}
 | 
				
			||||||
      branch_build: ${{ steps.tag.outputs.branch_build }}
 | 
					      branch_build: ${{ steps.tag.outputs.branch_build }}
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v4.1.5
 | 
					      - uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Get tag
 | 
					      - name: Get tag
 | 
				
			||||||
        id: tag
 | 
					        id: tag
 | 
				
			||||||
        # yamllint disable rule:line-length
 | 
					        # yamllint disable rule:line-length
 | 
				
			||||||
@@ -51,7 +51,7 @@ jobs:
 | 
				
			|||||||
      contents: read
 | 
					      contents: read
 | 
				
			||||||
      id-token: write
 | 
					      id-token: write
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v4.1.5
 | 
					      - uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Set up Python
 | 
					      - name: Set up Python
 | 
				
			||||||
        uses: actions/setup-python@v5.1.0
 | 
					        uses: actions/setup-python@v5.1.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -61,7 +61,9 @@ jobs:
 | 
				
			|||||||
          ESPHOME_NO_VENV: 1
 | 
					          ESPHOME_NO_VENV: 1
 | 
				
			||||||
        run: script/setup
 | 
					        run: script/setup
 | 
				
			||||||
      - name: Build
 | 
					      - name: Build
 | 
				
			||||||
        run: python setup.py sdist bdist_wheel
 | 
					        run: |-
 | 
				
			||||||
 | 
					          pip3 install build
 | 
				
			||||||
 | 
					          python3 -m build
 | 
				
			||||||
      - name: Publish
 | 
					      - name: Publish
 | 
				
			||||||
        uses: pypa/gh-action-pypi-publish@v1.8.14
 | 
					        uses: pypa/gh-action-pypi-publish@v1.8.14
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -81,7 +83,7 @@ jobs:
 | 
				
			|||||||
          - linux/arm/v7
 | 
					          - linux/arm/v7
 | 
				
			||||||
          - linux/arm64
 | 
					          - linux/arm64
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v4.1.5
 | 
					      - uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Set up Python
 | 
					      - name: Set up Python
 | 
				
			||||||
        uses: actions/setup-python@v5.1.0
 | 
					        uses: actions/setup-python@v5.1.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -94,12 +96,12 @@ jobs:
 | 
				
			|||||||
        uses: docker/setup-qemu-action@v3.0.0
 | 
					        uses: docker/setup-qemu-action@v3.0.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Log in to docker hub
 | 
					      - name: Log in to docker hub
 | 
				
			||||||
        uses: docker/login-action@v3.1.0
 | 
					        uses: docker/login-action@v3.2.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          username: ${{ secrets.DOCKER_USER }}
 | 
					          username: ${{ secrets.DOCKER_USER }}
 | 
				
			||||||
          password: ${{ secrets.DOCKER_PASSWORD }}
 | 
					          password: ${{ secrets.DOCKER_PASSWORD }}
 | 
				
			||||||
      - name: Log in to the GitHub container registry
 | 
					      - name: Log in to the GitHub container registry
 | 
				
			||||||
        uses: docker/login-action@v3.1.0
 | 
					        uses: docker/login-action@v3.2.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          registry: ghcr.io
 | 
					          registry: ghcr.io
 | 
				
			||||||
          username: ${{ github.actor }}
 | 
					          username: ${{ github.actor }}
 | 
				
			||||||
@@ -172,7 +174,7 @@ jobs:
 | 
				
			|||||||
          - ghcr
 | 
					          - ghcr
 | 
				
			||||||
          - dockerhub
 | 
					          - dockerhub
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v4.1.5
 | 
					      - uses: actions/checkout@v4.1.6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Download digests
 | 
					      - name: Download digests
 | 
				
			||||||
        uses: actions/download-artifact@v4.1.7
 | 
					        uses: actions/download-artifact@v4.1.7
 | 
				
			||||||
@@ -186,13 +188,13 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      - name: Log in to docker hub
 | 
					      - name: Log in to docker hub
 | 
				
			||||||
        if: matrix.registry == 'dockerhub'
 | 
					        if: matrix.registry == 'dockerhub'
 | 
				
			||||||
        uses: docker/login-action@v3.1.0
 | 
					        uses: docker/login-action@v3.2.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          username: ${{ secrets.DOCKER_USER }}
 | 
					          username: ${{ secrets.DOCKER_USER }}
 | 
				
			||||||
          password: ${{ secrets.DOCKER_PASSWORD }}
 | 
					          password: ${{ secrets.DOCKER_PASSWORD }}
 | 
				
			||||||
      - name: Log in to the GitHub container registry
 | 
					      - name: Log in to the GitHub container registry
 | 
				
			||||||
        if: matrix.registry == 'ghcr'
 | 
					        if: matrix.registry == 'ghcr'
 | 
				
			||||||
        uses: docker/login-action@v3.1.0
 | 
					        uses: docker/login-action@v3.2.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          registry: ghcr.io
 | 
					          registry: ghcr.io
 | 
				
			||||||
          username: ${{ github.actor }}
 | 
					          username: ${{ github.actor }}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								.github/workflows/sync-device-classes.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/sync-device-classes.yml
									
									
									
									
										vendored
									
									
								
							@@ -13,10 +13,10 @@ jobs:
 | 
				
			|||||||
    if: github.repository == 'esphome/esphome'
 | 
					    if: github.repository == 'esphome/esphome'
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Checkout
 | 
					      - name: Checkout
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Checkout Home Assistant
 | 
					      - name: Checkout Home Assistant
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          repository: home-assistant/core
 | 
					          repository: home-assistant/core
 | 
				
			||||||
          path: lib/home-assistant
 | 
					          path: lib/home-assistant
 | 
				
			||||||
@@ -36,7 +36,7 @@ jobs:
 | 
				
			|||||||
          python ./script/sync-device_class.py
 | 
					          python ./script/sync-device_class.py
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Commit changes
 | 
					      - name: Commit changes
 | 
				
			||||||
        uses: peter-evans/create-pull-request@v6.0.4
 | 
					        uses: peter-evans/create-pull-request@v6.0.5
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          commit-message: "Synchronise Device Classes from Home Assistant"
 | 
					          commit-message: "Synchronise Device Classes from Home Assistant"
 | 
				
			||||||
          committer: esphomebot <esphome@nabucasa.com>
 | 
					          committer: esphomebot <esphome@nabucasa.com>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/yaml-lint.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/yaml-lint.yml
									
									
									
									
										vendored
									
									
								
							@@ -18,7 +18,7 @@ jobs:
 | 
				
			|||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.5
 | 
					        uses: actions/checkout@v4.1.6
 | 
				
			||||||
      - name: Run yamllint
 | 
					      - name: Run yamllint
 | 
				
			||||||
        uses: frenck/action-yamllint@v1.5.0
 | 
					        uses: frenck/action-yamllint@v1.5.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@
 | 
				
			|||||||
# See https://pre-commit.com/hooks.html for more hooks
 | 
					# See https://pre-commit.com/hooks.html for more hooks
 | 
				
			||||||
repos:
 | 
					repos:
 | 
				
			||||||
  - repo: https://github.com/psf/black-pre-commit-mirror
 | 
					  - repo: https://github.com/psf/black-pre-commit-mirror
 | 
				
			||||||
    rev: 24.2.0
 | 
					    rev: 24.4.2
 | 
				
			||||||
    hooks:
 | 
					    hooks:
 | 
				
			||||||
      - id: black
 | 
					      - id: black
 | 
				
			||||||
        args:
 | 
					        args:
 | 
				
			||||||
@@ -40,3 +40,10 @@ repos:
 | 
				
			|||||||
    hooks:
 | 
					    hooks:
 | 
				
			||||||
      - id: clang-format
 | 
					      - id: clang-format
 | 
				
			||||||
        types_or: [c, c++]
 | 
					        types_or: [c, c++]
 | 
				
			||||||
 | 
					  - repo: local
 | 
				
			||||||
 | 
					    hooks:
 | 
				
			||||||
 | 
					      - id: pylint
 | 
				
			||||||
 | 
					        name: pylint
 | 
				
			||||||
 | 
					        entry: script/run-in-env.sh pylint
 | 
				
			||||||
 | 
					        language: script
 | 
				
			||||||
 | 
					        types: [python]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										26
									
								
								CODEOWNERS
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								CODEOWNERS
									
									
									
									
									
								
							@@ -6,7 +6,7 @@
 | 
				
			|||||||
# the integration's code owner is automatically notified.
 | 
					# the integration's code owner is automatically notified.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Core Code
 | 
					# Core Code
 | 
				
			||||||
setup.py @esphome/core
 | 
					pyproject.toml @esphome/core
 | 
				
			||||||
esphome/*.py @esphome/core
 | 
					esphome/*.py @esphome/core
 | 
				
			||||||
esphome/core/* @esphome/core
 | 
					esphome/core/* @esphome/core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -51,6 +51,8 @@ esphome/components/bang_bang/* @OttoWinter
 | 
				
			|||||||
esphome/components/bedjet/* @jhansche
 | 
					esphome/components/bedjet/* @jhansche
 | 
				
			||||||
esphome/components/bedjet/climate/* @jhansche
 | 
					esphome/components/bedjet/climate/* @jhansche
 | 
				
			||||||
esphome/components/bedjet/fan/* @jhansche
 | 
					esphome/components/bedjet/fan/* @jhansche
 | 
				
			||||||
 | 
					esphome/components/bedjet/sensor/* @javawizard @jhansche
 | 
				
			||||||
 | 
					esphome/components/beken_spi_led_strip/* @Mat931
 | 
				
			||||||
esphome/components/bh1750/* @OttoWinter
 | 
					esphome/components/bh1750/* @OttoWinter
 | 
				
			||||||
esphome/components/binary_sensor/* @esphome/core
 | 
					esphome/components/binary_sensor/* @esphome/core
 | 
				
			||||||
esphome/components/bk72xx/* @kuba2k2
 | 
					esphome/components/bk72xx/* @kuba2k2
 | 
				
			||||||
@@ -109,7 +111,10 @@ esphome/components/ee895/* @Stock-M
 | 
				
			|||||||
esphome/components/ektf2232/touchscreen/* @jesserockz
 | 
					esphome/components/ektf2232/touchscreen/* @jesserockz
 | 
				
			||||||
esphome/components/emc2101/* @ellull
 | 
					esphome/components/emc2101/* @ellull
 | 
				
			||||||
esphome/components/emmeti/* @E440QF
 | 
					esphome/components/emmeti/* @E440QF
 | 
				
			||||||
esphome/components/ens160/* @vincentscode
 | 
					esphome/components/ens160/* @latonita
 | 
				
			||||||
 | 
					esphome/components/ens160_base/* @latonita @vincentscode
 | 
				
			||||||
 | 
					esphome/components/ens160_i2c/* @latonita
 | 
				
			||||||
 | 
					esphome/components/ens160_spi/* @latonita
 | 
				
			||||||
esphome/components/ens210/* @itn3rd77
 | 
					esphome/components/ens210/* @itn3rd77
 | 
				
			||||||
esphome/components/esp32/* @esphome/core
 | 
					esphome/components/esp32/* @esphome/core
 | 
				
			||||||
esphome/components/esp32_ble/* @Rapsssito @jesserockz
 | 
					esphome/components/esp32_ble/* @Rapsssito @jesserockz
 | 
				
			||||||
@@ -135,6 +140,7 @@ esphome/components/fs3000/* @kahrendt
 | 
				
			|||||||
esphome/components/ft5x06/* @clydebarrow
 | 
					esphome/components/ft5x06/* @clydebarrow
 | 
				
			||||||
esphome/components/ft63x6/* @gpambrozio
 | 
					esphome/components/ft63x6/* @gpambrozio
 | 
				
			||||||
esphome/components/gcja5/* @gcormier
 | 
					esphome/components/gcja5/* @gcormier
 | 
				
			||||||
 | 
					esphome/components/gdk101/* @Szewcson
 | 
				
			||||||
esphome/components/globals/* @esphome/core
 | 
					esphome/components/globals/* @esphome/core
 | 
				
			||||||
esphome/components/gp8403/* @jesserockz
 | 
					esphome/components/gp8403/* @jesserockz
 | 
				
			||||||
esphome/components/gpio/* @esphome/core
 | 
					esphome/components/gpio/* @esphome/core
 | 
				
			||||||
@@ -146,6 +152,10 @@ esphome/components/grove_tb6612fng/* @max246
 | 
				
			|||||||
esphome/components/growatt_solar/* @leeuwte
 | 
					esphome/components/growatt_solar/* @leeuwte
 | 
				
			||||||
esphome/components/gt911/* @clydebarrow @jesserockz
 | 
					esphome/components/gt911/* @clydebarrow @jesserockz
 | 
				
			||||||
esphome/components/haier/* @paveldn
 | 
					esphome/components/haier/* @paveldn
 | 
				
			||||||
 | 
					esphome/components/haier/binary_sensor/* @paveldn
 | 
				
			||||||
 | 
					esphome/components/haier/button/* @paveldn
 | 
				
			||||||
 | 
					esphome/components/haier/sensor/* @paveldn
 | 
				
			||||||
 | 
					esphome/components/haier/text_sensor/* @paveldn
 | 
				
			||||||
esphome/components/havells_solar/* @sourabhjaiswal
 | 
					esphome/components/havells_solar/* @sourabhjaiswal
 | 
				
			||||||
esphome/components/hbridge/fan/* @WeekendWarrior
 | 
					esphome/components/hbridge/fan/* @WeekendWarrior
 | 
				
			||||||
esphome/components/hbridge/light/* @DotNetDann
 | 
					esphome/components/hbridge/light/* @DotNetDann
 | 
				
			||||||
@@ -157,9 +167,11 @@ esphome/components/homeassistant/* @OttoWinter
 | 
				
			|||||||
esphome/components/honeywell_hih_i2c/* @Benichou34
 | 
					esphome/components/honeywell_hih_i2c/* @Benichou34
 | 
				
			||||||
esphome/components/honeywellabp/* @RubyBailey
 | 
					esphome/components/honeywellabp/* @RubyBailey
 | 
				
			||||||
esphome/components/honeywellabp2_i2c/* @jpfaff
 | 
					esphome/components/honeywellabp2_i2c/* @jpfaff
 | 
				
			||||||
esphome/components/host/* @esphome/core
 | 
					esphome/components/host/* @clydebarrow @esphome/core
 | 
				
			||||||
 | 
					esphome/components/host/time/* @clydebarrow
 | 
				
			||||||
esphome/components/hrxl_maxsonar_wr/* @netmikey
 | 
					esphome/components/hrxl_maxsonar_wr/* @netmikey
 | 
				
			||||||
esphome/components/hte501/* @Stock-M
 | 
					esphome/components/hte501/* @Stock-M
 | 
				
			||||||
 | 
					esphome/components/http_request/ota/* @oarcher
 | 
				
			||||||
esphome/components/htu31d/* @betterengineering
 | 
					esphome/components/htu31d/* @betterengineering
 | 
				
			||||||
esphome/components/hydreon_rgxx/* @functionpointer
 | 
					esphome/components/hydreon_rgxx/* @functionpointer
 | 
				
			||||||
esphome/components/hyt271/* @Philippe12
 | 
					esphome/components/hyt271/* @Philippe12
 | 
				
			||||||
@@ -174,6 +186,9 @@ esphome/components/improv_base/* @esphome/core
 | 
				
			|||||||
esphome/components/improv_serial/* @esphome/core
 | 
					esphome/components/improv_serial/* @esphome/core
 | 
				
			||||||
esphome/components/ina226/* @Sergio303 @latonita
 | 
					esphome/components/ina226/* @Sergio303 @latonita
 | 
				
			||||||
esphome/components/ina260/* @mreditor97
 | 
					esphome/components/ina260/* @mreditor97
 | 
				
			||||||
 | 
					esphome/components/ina2xx_base/* @latonita
 | 
				
			||||||
 | 
					esphome/components/ina2xx_i2c/* @latonita
 | 
				
			||||||
 | 
					esphome/components/ina2xx_spi/* @latonita
 | 
				
			||||||
esphome/components/inkbird_ibsth1_mini/* @fkirill
 | 
					esphome/components/inkbird_ibsth1_mini/* @fkirill
 | 
				
			||||||
esphome/components/inkplate6/* @jesserockz
 | 
					esphome/components/inkplate6/* @jesserockz
 | 
				
			||||||
esphome/components/integration/* @OttoWinter
 | 
					esphome/components/integration/* @OttoWinter
 | 
				
			||||||
@@ -197,6 +212,7 @@ esphome/components/lilygo_t5_47/touchscreen/* @jesserockz
 | 
				
			|||||||
esphome/components/lock/* @esphome/core
 | 
					esphome/components/lock/* @esphome/core
 | 
				
			||||||
esphome/components/logger/* @esphome/core
 | 
					esphome/components/logger/* @esphome/core
 | 
				
			||||||
esphome/components/ltr390/* @sjtrny
 | 
					esphome/components/ltr390/* @sjtrny
 | 
				
			||||||
 | 
					esphome/components/ltr_als_ps/* @latonita
 | 
				
			||||||
esphome/components/matrix_keypad/* @ssieb
 | 
					esphome/components/matrix_keypad/* @ssieb
 | 
				
			||||||
esphome/components/max31865/* @DAVe3283
 | 
					esphome/components/max31865/* @DAVe3283
 | 
				
			||||||
esphome/components/max44009/* @berfenger
 | 
					esphome/components/max44009/* @berfenger
 | 
				
			||||||
@@ -297,7 +313,7 @@ esphome/components/rp2040_pwm/* @jesserockz
 | 
				
			|||||||
esphome/components/rpi_dpi_rgb/* @clydebarrow
 | 
					esphome/components/rpi_dpi_rgb/* @clydebarrow
 | 
				
			||||||
esphome/components/rtl87xx/* @kuba2k2
 | 
					esphome/components/rtl87xx/* @kuba2k2
 | 
				
			||||||
esphome/components/rtttl/* @glmnet
 | 
					esphome/components/rtttl/* @glmnet
 | 
				
			||||||
esphome/components/safe_mode/* @jsuanet @paulmonigatti
 | 
					esphome/components/safe_mode/* @jsuanet @kbx81 @paulmonigatti
 | 
				
			||||||
esphome/components/scd4x/* @martgras @sjtrny
 | 
					esphome/components/scd4x/* @martgras @sjtrny
 | 
				
			||||||
esphome/components/script/* @esphome/core
 | 
					esphome/components/script/* @esphome/core
 | 
				
			||||||
esphome/components/sdm_meter/* @jesserockz @polyfaces
 | 
					esphome/components/sdm_meter/* @jesserockz @polyfaces
 | 
				
			||||||
@@ -401,7 +417,7 @@ esphome/components/veml3235/* @kbx81
 | 
				
			|||||||
esphome/components/veml7700/* @latonita
 | 
					esphome/components/veml7700/* @latonita
 | 
				
			||||||
esphome/components/version/* @esphome/core
 | 
					esphome/components/version/* @esphome/core
 | 
				
			||||||
esphome/components/voice_assistant/* @jesserockz
 | 
					esphome/components/voice_assistant/* @jesserockz
 | 
				
			||||||
esphome/components/wake_on_lan/* @willwill2will54
 | 
					esphome/components/wake_on_lan/* @clydebarrow @willwill2will54
 | 
				
			||||||
esphome/components/waveshare_epaper/* @clydebarrow
 | 
					esphome/components/waveshare_epaper/* @clydebarrow
 | 
				
			||||||
esphome/components/web_server_base/* @OttoWinter
 | 
					esphome/components/web_server_base/* @OttoWinter
 | 
				
			||||||
esphome/components/web_server_idf/* @dentra
 | 
					esphome/components/web_server_idf/* @dentra
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -100,6 +100,9 @@ RUN --mount=type=tmpfs,target=/root/.cargo if [ "$TARGETARCH$TARGETVARIANT" = "a
 | 
				
			|||||||
    --break-system-packages --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
 | 
					    --break-system-packages --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
 | 
				
			||||||
    && /platformio_install_deps.py /platformio.ini --libraries
 | 
					    && /platformio_install_deps.py /platformio.ini --libraries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Avoid unsafe git error when container user and file config volume permissions don't match
 | 
				
			||||||
 | 
					RUN git config --system --add safe.directory '/config/*'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ======================= docker-type image =======================
 | 
					# ======================= docker-type image =======================
 | 
				
			||||||
FROM base AS docker
 | 
					FROM base AS docker
 | 
				
			||||||
@@ -110,7 +113,7 @@ RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
 | 
				
			|||||||
        export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
 | 
					        export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
 | 
				
			||||||
  fi; \
 | 
					  fi; \
 | 
				
			||||||
  pip3 install \
 | 
					  pip3 install \
 | 
				
			||||||
  --break-system-packages --no-cache-dir --no-use-pep517 -e /esphome
 | 
					  --break-system-packages --no-cache-dir -e /esphome
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Settings for dashboard
 | 
					# Settings for dashboard
 | 
				
			||||||
ENV USERNAME="" PASSWORD=""
 | 
					ENV USERNAME="" PASSWORD=""
 | 
				
			||||||
@@ -160,7 +163,7 @@ RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
 | 
				
			|||||||
        export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
 | 
					        export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
 | 
				
			||||||
  fi; \
 | 
					  fi; \
 | 
				
			||||||
  pip3 install \
 | 
					  pip3 install \
 | 
				
			||||||
  --break-system-packages --no-cache-dir --no-use-pep517 -e /esphome
 | 
					  --break-system-packages --no-cache-dir -e /esphome
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Labels
 | 
					# Labels
 | 
				
			||||||
LABEL \
 | 
					LABEL \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,22 +18,23 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_BAUD_RATE,
 | 
					    CONF_BAUD_RATE,
 | 
				
			||||||
    CONF_BROKER,
 | 
					    CONF_BROKER,
 | 
				
			||||||
    CONF_DEASSERT_RTS_DTR,
 | 
					    CONF_DEASSERT_RTS_DTR,
 | 
				
			||||||
 | 
					    CONF_DISABLED,
 | 
				
			||||||
 | 
					    CONF_ESPHOME,
 | 
				
			||||||
    CONF_LOGGER,
 | 
					    CONF_LOGGER,
 | 
				
			||||||
 | 
					    CONF_MDNS,
 | 
				
			||||||
 | 
					    CONF_MQTT,
 | 
				
			||||||
    CONF_NAME,
 | 
					    CONF_NAME,
 | 
				
			||||||
    CONF_OTA,
 | 
					    CONF_OTA,
 | 
				
			||||||
    CONF_MQTT,
 | 
					 | 
				
			||||||
    CONF_MDNS,
 | 
					 | 
				
			||||||
    CONF_DISABLED,
 | 
					 | 
				
			||||||
    CONF_PASSWORD,
 | 
					    CONF_PASSWORD,
 | 
				
			||||||
    CONF_PORT,
 | 
					    CONF_PLATFORM,
 | 
				
			||||||
    CONF_ESPHOME,
 | 
					 | 
				
			||||||
    CONF_PLATFORMIO_OPTIONS,
 | 
					    CONF_PLATFORMIO_OPTIONS,
 | 
				
			||||||
 | 
					    CONF_PORT,
 | 
				
			||||||
    CONF_SUBSTITUTIONS,
 | 
					    CONF_SUBSTITUTIONS,
 | 
				
			||||||
    PLATFORM_BK72XX,
 | 
					    PLATFORM_BK72XX,
 | 
				
			||||||
    PLATFORM_RTL87XX,
 | 
					 | 
				
			||||||
    PLATFORM_ESP32,
 | 
					    PLATFORM_ESP32,
 | 
				
			||||||
    PLATFORM_ESP8266,
 | 
					    PLATFORM_ESP8266,
 | 
				
			||||||
    PLATFORM_RP2040,
 | 
					    PLATFORM_RP2040,
 | 
				
			||||||
 | 
					    PLATFORM_RTL87XX,
 | 
				
			||||||
    SECRETS_FILES,
 | 
					    SECRETS_FILES,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from esphome.core import CORE, EsphomeError, coroutine
 | 
					from esphome.core import CORE, EsphomeError, coroutine
 | 
				
			||||||
@@ -65,7 +66,7 @@ def choose_prompt(options, purpose: str = None):
 | 
				
			|||||||
        f'Found multiple options{f" for {purpose}" if purpose else ""}, please choose one:'
 | 
					        f'Found multiple options{f" for {purpose}" if purpose else ""}, please choose one:'
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    for i, (desc, _) in enumerate(options):
 | 
					    for i, (desc, _) in enumerate(options):
 | 
				
			||||||
        safe_print(f"  [{i+1}] {desc}")
 | 
					        safe_print(f"  [{i + 1}] {desc}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while True:
 | 
					    while True:
 | 
				
			||||||
        opt = input("(number): ")
 | 
					        opt = input("(number): ")
 | 
				
			||||||
@@ -330,15 +331,19 @@ def upload_program(config, args, host):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return 1  # Unknown target platform
 | 
					        return 1  # Unknown target platform
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if CONF_OTA not in config:
 | 
					    ota_conf = {}
 | 
				
			||||||
 | 
					    for ota_item in config.get(CONF_OTA, []):
 | 
				
			||||||
 | 
					        if ota_item[CONF_PLATFORM] == CONF_ESPHOME:
 | 
				
			||||||
 | 
					            ota_conf = ota_item
 | 
				
			||||||
 | 
					            break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if not ota_conf:
 | 
				
			||||||
        raise EsphomeError(
 | 
					        raise EsphomeError(
 | 
				
			||||||
            "Cannot upload Over the Air as the config does not include the ota: "
 | 
					            f"Cannot upload Over the Air as the {CONF_OTA} configuration is not present or does not include {CONF_PLATFORM}: {CONF_ESPHOME}"
 | 
				
			||||||
            "component"
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from esphome import espota2
 | 
					    from esphome import espota2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ota_conf = config[CONF_OTA]
 | 
					 | 
				
			||||||
    remote_port = ota_conf[CONF_PORT]
 | 
					    remote_port = ota_conf[CONF_PORT]
 | 
				
			||||||
    password = ota_conf.get(CONF_PASSWORD, "")
 | 
					    password = ota_conf.get(CONF_PASSWORD, "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -346,7 +351,7 @@ def upload_program(config, args, host):
 | 
				
			|||||||
        not is_ip_address(CORE.address)  # pylint: disable=too-many-boolean-expressions
 | 
					        not is_ip_address(CORE.address)  # pylint: disable=too-many-boolean-expressions
 | 
				
			||||||
        and (get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED])
 | 
					        and (get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED])
 | 
				
			||||||
        and CONF_MQTT in config
 | 
					        and CONF_MQTT in config
 | 
				
			||||||
        and (not args.device or args.device == "MQTT")
 | 
					        and (not args.device or args.device in ("MQTT", "OTA"))
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
        from esphome import mqtt
 | 
					        from esphome import mqtt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,11 +4,11 @@ from esphome.const import (
 | 
				
			|||||||
    STATE_CLASS_MEASUREMENT,
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    ICON_ARROW_EXPAND_VERTICAL,
 | 
					    ICON_ARROW_EXPAND_VERTICAL,
 | 
				
			||||||
    DEVICE_CLASS_DISTANCE,
 | 
					    DEVICE_CLASS_DISTANCE,
 | 
				
			||||||
 | 
					    UNIT_MILLIMETER,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CODEOWNERS = ["@TH-Braemer"]
 | 
					CODEOWNERS = ["@TH-Braemer"]
 | 
				
			||||||
DEPENDENCIES = ["uart"]
 | 
					DEPENDENCIES = ["uart"]
 | 
				
			||||||
UNIT_MILLIMETERS = "mm"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
a02yyuw_ns = cg.esphome_ns.namespace("a02yyuw")
 | 
					a02yyuw_ns = cg.esphome_ns.namespace("a02yyuw")
 | 
				
			||||||
A02yyuwComponent = a02yyuw_ns.class_(
 | 
					A02yyuwComponent = a02yyuw_ns.class_(
 | 
				
			||||||
@@ -17,7 +17,7 @@ A02yyuwComponent = a02yyuw_ns.class_(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
CONFIG_SCHEMA = sensor.sensor_schema(
 | 
					CONFIG_SCHEMA = sensor.sensor_schema(
 | 
				
			||||||
    A02yyuwComponent,
 | 
					    A02yyuwComponent,
 | 
				
			||||||
    unit_of_measurement=UNIT_MILLIMETERS,
 | 
					    unit_of_measurement=UNIT_MILLIMETER,
 | 
				
			||||||
    icon=ICON_ARROW_EXPAND_VERTICAL,
 | 
					    icon=ICON_ARROW_EXPAND_VERTICAL,
 | 
				
			||||||
    accuracy_decimals=0,
 | 
					    accuracy_decimals=0,
 | 
				
			||||||
    state_class=STATE_CLASS_MEASUREMENT,
 | 
					    state_class=STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,11 +18,23 @@ from esphome.components.esp32.const import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
CODEOWNERS = ["@esphome/core"]
 | 
					CODEOWNERS = ["@esphome/core"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					adc_ns = cg.esphome_ns.namespace("adc")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					From the below patch versions (and 5.2+) ADC_ATTEN_DB_11 is deprecated and replaced with ADC_ATTEN_DB_12.
 | 
				
			||||||
 | 
					4.4.7
 | 
				
			||||||
 | 
					5.0.5
 | 
				
			||||||
 | 
					5.1.3
 | 
				
			||||||
 | 
					5.2+
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ATTENUATION_MODES = {
 | 
					ATTENUATION_MODES = {
 | 
				
			||||||
    "0db": cg.global_ns.ADC_ATTEN_DB_0,
 | 
					    "0db": cg.global_ns.ADC_ATTEN_DB_0,
 | 
				
			||||||
    "2.5db": cg.global_ns.ADC_ATTEN_DB_2_5,
 | 
					    "2.5db": cg.global_ns.ADC_ATTEN_DB_2_5,
 | 
				
			||||||
    "6db": cg.global_ns.ADC_ATTEN_DB_6,
 | 
					    "6db": cg.global_ns.ADC_ATTEN_DB_6,
 | 
				
			||||||
    "11db": cg.global_ns.ADC_ATTEN_DB_11,
 | 
					    "11db": adc_ns.ADC_ATTEN_DB_12_COMPAT,
 | 
				
			||||||
 | 
					    "12db": adc_ns.ADC_ATTEN_DB_12_COMPAT,
 | 
				
			||||||
    "auto": "auto",
 | 
					    "auto": "auto",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,27 +46,27 @@ extern "C"
 | 
				
			|||||||
    ADCSensor::setup() {
 | 
					    ADCSensor::setup() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
 | 
					  ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
 | 
				
			||||||
#if !defined(USE_ADC_SENSOR_VCC) && !defined(USE_RP2040)
 | 
					#if !defined(USE_ADC_SENSOR_VCC) && !defined(USE_RP2040)
 | 
				
			||||||
  pin_->setup();
 | 
					  this->pin_->setup();
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
  if (channel1_ != ADC1_CHANNEL_MAX) {
 | 
					  if (this->channel1_ != ADC1_CHANNEL_MAX) {
 | 
				
			||||||
    adc1_config_width(ADC_WIDTH_MAX_SOC_BITS);
 | 
					    adc1_config_width(ADC_WIDTH_MAX_SOC_BITS);
 | 
				
			||||||
    if (!autorange_) {
 | 
					    if (!this->autorange_) {
 | 
				
			||||||
      adc1_config_channel_atten(channel1_, attenuation_);
 | 
					      adc1_config_channel_atten(this->channel1_, this->attenuation_);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  } else if (channel2_ != ADC2_CHANNEL_MAX) {
 | 
					  } else if (this->channel2_ != ADC2_CHANNEL_MAX) {
 | 
				
			||||||
    if (!autorange_) {
 | 
					    if (!this->autorange_) {
 | 
				
			||||||
      adc2_config_channel_atten(channel2_, attenuation_);
 | 
					      adc2_config_channel_atten(this->channel2_, this->attenuation_);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // load characteristics for each attenuation
 | 
					  // load characteristics for each attenuation
 | 
				
			||||||
  for (int32_t i = 0; i <= ADC_ATTEN_DB_11; i++) {
 | 
					  for (int32_t i = 0; i <= ADC_ATTEN_DB_12_COMPAT; i++) {
 | 
				
			||||||
    auto adc_unit = channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2;
 | 
					    auto adc_unit = this->channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2;
 | 
				
			||||||
    auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS,
 | 
					    auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS,
 | 
				
			||||||
                                              1100,  // default vref
 | 
					                                              1100,  // default vref
 | 
				
			||||||
                                              &cal_characteristics_[i]);
 | 
					                                              &this->cal_characteristics_[i]);
 | 
				
			||||||
    switch (cal_value) {
 | 
					    switch (cal_value) {
 | 
				
			||||||
      case ESP_ADC_CAL_VAL_EFUSE_VREF:
 | 
					      case ESP_ADC_CAL_VAL_EFUSE_VREF:
 | 
				
			||||||
        ESP_LOGV(TAG, "Using eFuse Vref for calibration");
 | 
					        ESP_LOGV(TAG, "Using eFuse Vref for calibration");
 | 
				
			||||||
@@ -99,27 +99,27 @@ void ADCSensor::dump_config() {
 | 
				
			|||||||
#ifdef USE_ADC_SENSOR_VCC
 | 
					#ifdef USE_ADC_SENSOR_VCC
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  Pin: VCC");
 | 
					  ESP_LOGCONFIG(TAG, "  Pin: VCC");
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  LOG_PIN("  Pin: ", pin_);
 | 
					  LOG_PIN("  Pin: ", this->pin_);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#endif  // USE_ESP8266 || USE_LIBRETINY
 | 
					#endif  // USE_ESP8266 || USE_LIBRETINY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
  LOG_PIN("  Pin: ", pin_);
 | 
					  LOG_PIN("  Pin: ", this->pin_);
 | 
				
			||||||
  if (autorange_) {
 | 
					  if (this->autorange_) {
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, " Attenuation: auto");
 | 
					    ESP_LOGCONFIG(TAG, "  Attenuation: auto");
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    switch (this->attenuation_) {
 | 
					    switch (this->attenuation_) {
 | 
				
			||||||
      case ADC_ATTEN_DB_0:
 | 
					      case ADC_ATTEN_DB_0:
 | 
				
			||||||
        ESP_LOGCONFIG(TAG, " Attenuation: 0db");
 | 
					        ESP_LOGCONFIG(TAG, "  Attenuation: 0db");
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      case ADC_ATTEN_DB_2_5:
 | 
					      case ADC_ATTEN_DB_2_5:
 | 
				
			||||||
        ESP_LOGCONFIG(TAG, " Attenuation: 2.5db");
 | 
					        ESP_LOGCONFIG(TAG, "  Attenuation: 2.5db");
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      case ADC_ATTEN_DB_6:
 | 
					      case ADC_ATTEN_DB_6:
 | 
				
			||||||
        ESP_LOGCONFIG(TAG, " Attenuation: 6db");
 | 
					        ESP_LOGCONFIG(TAG, "  Attenuation: 6db");
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      case ADC_ATTEN_DB_11:
 | 
					      case ADC_ATTEN_DB_12_COMPAT:
 | 
				
			||||||
        ESP_LOGCONFIG(TAG, " Attenuation: 11db");
 | 
					        ESP_LOGCONFIG(TAG, "  Attenuation: 12db");
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      default:  // This is to satisfy the unused ADC_ATTEN_MAX
 | 
					      default:  // This is to satisfy the unused ADC_ATTEN_MAX
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
@@ -134,11 +134,11 @@ void ADCSensor::dump_config() {
 | 
				
			|||||||
#ifdef USE_ADC_SENSOR_VCC
 | 
					#ifdef USE_ADC_SENSOR_VCC
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "  Pin: VCC");
 | 
					    ESP_LOGCONFIG(TAG, "  Pin: VCC");
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
    LOG_PIN("  Pin: ", pin_);
 | 
					    LOG_PIN("  Pin: ", this->pin_);
 | 
				
			||||||
#endif  // USE_ADC_SENSOR_VCC
 | 
					#endif  // USE_ADC_SENSOR_VCC
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif  // USE_RP2040
 | 
					#endif  // USE_RP2040
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "  Samples: %i", this->sample_count_);
 | 
				
			||||||
  LOG_UPDATE_INTERVAL(this);
 | 
					  LOG_UPDATE_INTERVAL(this);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -149,14 +149,24 @@ void ADCSensor::update() {
 | 
				
			|||||||
  this->publish_state(value_v);
 | 
					  this->publish_state(value_v);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ADCSensor::set_sample_count(uint8_t sample_count) {
 | 
				
			||||||
 | 
					  if (sample_count != 0) {
 | 
				
			||||||
 | 
					    this->sample_count_ = sample_count;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP8266
 | 
					#ifdef USE_ESP8266
 | 
				
			||||||
float ADCSensor::sample() {
 | 
					float ADCSensor::sample() {
 | 
				
			||||||
 | 
					  uint32_t raw = 0;
 | 
				
			||||||
 | 
					  for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
				
			||||||
#ifdef USE_ADC_SENSOR_VCC
 | 
					#ifdef USE_ADC_SENSOR_VCC
 | 
				
			||||||
  int32_t raw = ESP.getVcc();  // NOLINT(readability-static-accessed-through-instance)
 | 
					    raw += ESP.getVcc();  // NOLINT(readability-static-accessed-through-instance)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  int32_t raw = analogRead(this->pin_->get_pin());  // NOLINT
 | 
					    raw += analogRead(this->pin_->get_pin());  // NOLINT
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  if (output_raw_) {
 | 
					  }
 | 
				
			||||||
 | 
					  raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
				
			||||||
 | 
					  if (this->output_raw_) {
 | 
				
			||||||
    return raw;
 | 
					    return raw;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return raw / 1024.0f;
 | 
					  return raw / 1024.0f;
 | 
				
			||||||
@@ -165,77 +175,81 @@ float ADCSensor::sample() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
float ADCSensor::sample() {
 | 
					float ADCSensor::sample() {
 | 
				
			||||||
  if (!autorange_) {
 | 
					  if (!this->autorange_) {
 | 
				
			||||||
    int raw = -1;
 | 
					    uint32_t sum = 0;
 | 
				
			||||||
    if (channel1_ != ADC1_CHANNEL_MAX) {
 | 
					    for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
				
			||||||
      raw = adc1_get_raw(channel1_);
 | 
					      int raw = -1;
 | 
				
			||||||
    } else if (channel2_ != ADC2_CHANNEL_MAX) {
 | 
					      if (this->channel1_ != ADC1_CHANNEL_MAX) {
 | 
				
			||||||
      adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw);
 | 
					        raw = adc1_get_raw(this->channel1_);
 | 
				
			||||||
 | 
					      } else if (this->channel2_ != ADC2_CHANNEL_MAX) {
 | 
				
			||||||
 | 
					        adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (raw == -1) {
 | 
				
			||||||
 | 
					        return NAN;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      sum += raw;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    sum = (sum + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
				
			||||||
    if (raw == -1) {
 | 
					    if (this->output_raw_) {
 | 
				
			||||||
      return NAN;
 | 
					      return sum;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (output_raw_) {
 | 
					    uint32_t mv = esp_adc_cal_raw_to_voltage(sum, &this->cal_characteristics_[(int32_t) this->attenuation_]);
 | 
				
			||||||
      return raw;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    uint32_t mv = esp_adc_cal_raw_to_voltage(raw, &cal_characteristics_[(int32_t) attenuation_]);
 | 
					 | 
				
			||||||
    return mv / 1000.0f;
 | 
					    return mv / 1000.0f;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int raw11 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX;
 | 
					  int raw12 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (channel1_ != ADC1_CHANNEL_MAX) {
 | 
					  if (this->channel1_ != ADC1_CHANNEL_MAX) {
 | 
				
			||||||
    adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_11);
 | 
					    adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_12_COMPAT);
 | 
				
			||||||
    raw11 = adc1_get_raw(channel1_);
 | 
					    raw12 = adc1_get_raw(this->channel1_);
 | 
				
			||||||
    if (raw11 < ADC_MAX) {
 | 
					    if (raw12 < ADC_MAX) {
 | 
				
			||||||
      adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_6);
 | 
					      adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_6);
 | 
				
			||||||
      raw6 = adc1_get_raw(channel1_);
 | 
					      raw6 = adc1_get_raw(this->channel1_);
 | 
				
			||||||
      if (raw6 < ADC_MAX) {
 | 
					      if (raw6 < ADC_MAX) {
 | 
				
			||||||
        adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_2_5);
 | 
					        adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_2_5);
 | 
				
			||||||
        raw2 = adc1_get_raw(channel1_);
 | 
					        raw2 = adc1_get_raw(this->channel1_);
 | 
				
			||||||
        if (raw2 < ADC_MAX) {
 | 
					        if (raw2 < ADC_MAX) {
 | 
				
			||||||
          adc1_config_channel_atten(channel1_, ADC_ATTEN_DB_0);
 | 
					          adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_0);
 | 
				
			||||||
          raw0 = adc1_get_raw(channel1_);
 | 
					          raw0 = adc1_get_raw(this->channel1_);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  } else if (channel2_ != ADC2_CHANNEL_MAX) {
 | 
					  } else if (this->channel2_ != ADC2_CHANNEL_MAX) {
 | 
				
			||||||
    adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_11);
 | 
					    adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_12_COMPAT);
 | 
				
			||||||
    adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw11);
 | 
					    adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw12);
 | 
				
			||||||
    if (raw11 < ADC_MAX) {
 | 
					    if (raw12 < ADC_MAX) {
 | 
				
			||||||
      adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_6);
 | 
					      adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_6);
 | 
				
			||||||
      adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6);
 | 
					      adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6);
 | 
				
			||||||
      if (raw6 < ADC_MAX) {
 | 
					      if (raw6 < ADC_MAX) {
 | 
				
			||||||
        adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_2_5);
 | 
					        adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_2_5);
 | 
				
			||||||
        adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw2);
 | 
					        adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw2);
 | 
				
			||||||
        if (raw2 < ADC_MAX) {
 | 
					        if (raw2 < ADC_MAX) {
 | 
				
			||||||
          adc2_config_channel_atten(channel2_, ADC_ATTEN_DB_0);
 | 
					          adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_0);
 | 
				
			||||||
          adc2_get_raw(channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw0);
 | 
					          adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw0);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (raw0 == -1 || raw2 == -1 || raw6 == -1 || raw11 == -1) {
 | 
					  if (raw0 == -1 || raw2 == -1 || raw6 == -1 || raw12 == -1) {
 | 
				
			||||||
    return NAN;
 | 
					    return NAN;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  uint32_t mv11 = esp_adc_cal_raw_to_voltage(raw11, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_11]);
 | 
					  uint32_t mv12 = esp_adc_cal_raw_to_voltage(raw12, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_12_COMPAT]);
 | 
				
			||||||
  uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_6]);
 | 
					  uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_6]);
 | 
				
			||||||
  uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]);
 | 
					  uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]);
 | 
				
			||||||
  uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]);
 | 
					  uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Contribution of each value, in range 0-2048 (12 bit ADC) or 0-4096 (13 bit ADC)
 | 
					  // Contribution of each value, in range 0-2048 (12 bit ADC) or 0-4096 (13 bit ADC)
 | 
				
			||||||
  uint32_t c11 = std::min(raw11, ADC_HALF);
 | 
					  uint32_t c12 = std::min(raw12, ADC_HALF);
 | 
				
			||||||
  uint32_t c6 = ADC_HALF - std::abs(raw6 - ADC_HALF);
 | 
					  uint32_t c6 = ADC_HALF - std::abs(raw6 - ADC_HALF);
 | 
				
			||||||
  uint32_t c2 = ADC_HALF - std::abs(raw2 - ADC_HALF);
 | 
					  uint32_t c2 = ADC_HALF - std::abs(raw2 - ADC_HALF);
 | 
				
			||||||
  uint32_t c0 = std::min(ADC_MAX - raw0, ADC_HALF);
 | 
					  uint32_t c0 = std::min(ADC_MAX - raw0, ADC_HALF);
 | 
				
			||||||
  // max theoretical csum value is 4096*4 = 16384
 | 
					  // max theoretical csum value is 4096*4 = 16384
 | 
				
			||||||
  uint32_t csum = c11 + c6 + c2 + c0;
 | 
					  uint32_t csum = c12 + c6 + c2 + c0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // each mv is max 3900; so max value is 3900*4096*4, fits in unsigned32
 | 
					  // each mv is max 3900; so max value is 3900*4096*4, fits in unsigned32
 | 
				
			||||||
  uint32_t mv_scaled = (mv11 * c11) + (mv6 * c6) + (mv2 * c2) + (mv0 * c0);
 | 
					  uint32_t mv_scaled = (mv12 * c12) + (mv6 * c6) + (mv2 * c2) + (mv0 * c0);
 | 
				
			||||||
  return mv_scaled / (float) (csum * 1000U);
 | 
					  return mv_scaled / (float) (csum * 1000U);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif  // USE_ESP32
 | 
					#endif  // USE_ESP32
 | 
				
			||||||
@@ -246,8 +260,11 @@ float ADCSensor::sample() {
 | 
				
			|||||||
    adc_set_temp_sensor_enabled(true);
 | 
					    adc_set_temp_sensor_enabled(true);
 | 
				
			||||||
    delay(1);
 | 
					    delay(1);
 | 
				
			||||||
    adc_select_input(4);
 | 
					    adc_select_input(4);
 | 
				
			||||||
 | 
					    uint32_t raw = 0;
 | 
				
			||||||
    int32_t raw = adc_read();
 | 
					    for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
				
			||||||
 | 
					      raw += adc_read();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
				
			||||||
    adc_set_temp_sensor_enabled(false);
 | 
					    adc_set_temp_sensor_enabled(false);
 | 
				
			||||||
    if (this->output_raw_) {
 | 
					    if (this->output_raw_) {
 | 
				
			||||||
      return raw;
 | 
					      return raw;
 | 
				
			||||||
@@ -268,7 +285,11 @@ float ADCSensor::sample() {
 | 
				
			|||||||
    adc_gpio_init(pin);
 | 
					    adc_gpio_init(pin);
 | 
				
			||||||
    adc_select_input(pin - 26);
 | 
					    adc_select_input(pin - 26);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int32_t raw = adc_read();
 | 
					    uint32_t raw = 0;
 | 
				
			||||||
 | 
					    for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
				
			||||||
 | 
					      raw += adc_read();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CYW43_USES_VSYS_PIN
 | 
					#ifdef CYW43_USES_VSYS_PIN
 | 
				
			||||||
    if (pin == PICO_VSYS_PIN) {
 | 
					    if (pin == PICO_VSYS_PIN) {
 | 
				
			||||||
@@ -276,7 +297,7 @@ float ADCSensor::sample() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
#endif  // CYW43_USES_VSYS_PIN
 | 
					#endif  // CYW43_USES_VSYS_PIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (output_raw_) {
 | 
					    if (this->output_raw_) {
 | 
				
			||||||
      return raw;
 | 
					      return raw;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    float coeff = pin == PICO_VSYS_PIN ? 3.0 : 1.0;
 | 
					    float coeff = pin == PICO_VSYS_PIN ? 3.0 : 1.0;
 | 
				
			||||||
@@ -287,10 +308,19 @@ float ADCSensor::sample() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#ifdef USE_LIBRETINY
 | 
					#ifdef USE_LIBRETINY
 | 
				
			||||||
float ADCSensor::sample() {
 | 
					float ADCSensor::sample() {
 | 
				
			||||||
  if (output_raw_) {
 | 
					  uint32_t raw = 0;
 | 
				
			||||||
    return analogRead(this->pin_->get_pin());  // NOLINT
 | 
					  if (this->output_raw_) {
 | 
				
			||||||
 | 
					    for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
				
			||||||
 | 
					      raw += analogRead(this->pin_->get_pin());  // NOLINT
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
				
			||||||
 | 
					    return raw;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return analogReadVoltage(this->pin_->get_pin()) / 1000.0f;  // NOLINT
 | 
					  for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
				
			||||||
 | 
					    raw += analogReadVoltage(this->pin_->get_pin());  // NOLINT
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
				
			||||||
 | 
					  return raw / 1000.0f;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif  // USE_LIBRETINY
 | 
					#endif  // USE_LIBRETINY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,33 +1,48 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "esphome/core/component.h"
 | 
					 | 
				
			||||||
#include "esphome/core/hal.h"
 | 
					 | 
				
			||||||
#include "esphome/core/defines.h"
 | 
					 | 
				
			||||||
#include "esphome/components/sensor/sensor.h"
 | 
					#include "esphome/components/sensor/sensor.h"
 | 
				
			||||||
#include "esphome/components/voltage_sampler/voltage_sampler.h"
 | 
					#include "esphome/components/voltage_sampler/voltage_sampler.h"
 | 
				
			||||||
 | 
					#include "esphome/core/component.h"
 | 
				
			||||||
 | 
					#include "esphome/core/defines.h"
 | 
				
			||||||
 | 
					#include "esphome/core/hal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
#include "driver/adc.h"
 | 
					 | 
				
			||||||
#include <esp_adc_cal.h>
 | 
					#include <esp_adc_cal.h>
 | 
				
			||||||
 | 
					#include "driver/adc.h"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace adc {
 | 
					namespace adc {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
 | 
					// clang-format off
 | 
				
			||||||
 | 
					#if (ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 7)) || \
 | 
				
			||||||
 | 
					    (ESP_IDF_VERSION_MAJOR == 5 && \
 | 
				
			||||||
 | 
					     ((ESP_IDF_VERSION_MINOR == 0 && ESP_IDF_VERSION_PATCH >= 5) || \
 | 
				
			||||||
 | 
					      (ESP_IDF_VERSION_MINOR == 1 && ESP_IDF_VERSION_PATCH >= 3) || \
 | 
				
			||||||
 | 
					      (ESP_IDF_VERSION_MINOR >= 2)) \
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					// clang-format on
 | 
				
			||||||
 | 
					static const adc_atten_t ADC_ATTEN_DB_12_COMPAT = ADC_ATTEN_DB_12;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static const adc_atten_t ADC_ATTEN_DB_12_COMPAT = ADC_ATTEN_DB_11;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif  // USE_ESP32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler {
 | 
					class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
  /// Set the attenuation for this pin. Only available on the ESP32.
 | 
					  /// Set the attenuation for this pin. Only available on the ESP32.
 | 
				
			||||||
  void set_attenuation(adc_atten_t attenuation) { attenuation_ = attenuation; }
 | 
					  void set_attenuation(adc_atten_t attenuation) { this->attenuation_ = attenuation; }
 | 
				
			||||||
  void set_channel1(adc1_channel_t channel) {
 | 
					  void set_channel1(adc1_channel_t channel) {
 | 
				
			||||||
    channel1_ = channel;
 | 
					    this->channel1_ = channel;
 | 
				
			||||||
    channel2_ = ADC2_CHANNEL_MAX;
 | 
					    this->channel2_ = ADC2_CHANNEL_MAX;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  void set_channel2(adc2_channel_t channel) {
 | 
					  void set_channel2(adc2_channel_t channel) {
 | 
				
			||||||
    channel2_ = channel;
 | 
					    this->channel2_ = channel;
 | 
				
			||||||
    channel1_ = ADC1_CHANNEL_MAX;
 | 
					    this->channel1_ = ADC1_CHANNEL_MAX;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  void set_autorange(bool autorange) { autorange_ = autorange; }
 | 
					  void set_autorange(bool autorange) { this->autorange_ = autorange; }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Update ADC values
 | 
					  /// Update ADC values
 | 
				
			||||||
@@ -38,7 +53,8 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
 | 
				
			|||||||
  /// `HARDWARE_LATE` setup priority
 | 
					  /// `HARDWARE_LATE` setup priority
 | 
				
			||||||
  float get_setup_priority() const override;
 | 
					  float get_setup_priority() const override;
 | 
				
			||||||
  void set_pin(InternalGPIOPin *pin) { this->pin_ = pin; }
 | 
					  void set_pin(InternalGPIOPin *pin) { this->pin_ = pin; }
 | 
				
			||||||
  void set_output_raw(bool output_raw) { output_raw_ = output_raw; }
 | 
					  void set_output_raw(bool output_raw) { this->output_raw_ = output_raw; }
 | 
				
			||||||
 | 
					  void set_sample_count(uint8_t sample_count);
 | 
				
			||||||
  float sample() override;
 | 
					  float sample() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP8266
 | 
					#ifdef USE_ESP8266
 | 
				
			||||||
@@ -46,12 +62,13 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_RP2040
 | 
					#ifdef USE_RP2040
 | 
				
			||||||
  void set_is_temperature() { is_temperature_ = true; }
 | 
					  void set_is_temperature() { this->is_temperature_ = true; }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
  InternalGPIOPin *pin_;
 | 
					  InternalGPIOPin *pin_;
 | 
				
			||||||
  bool output_raw_{false};
 | 
					  bool output_raw_{false};
 | 
				
			||||||
 | 
					  uint8_t sample_count_{1};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_RP2040
 | 
					#ifdef USE_RP2040
 | 
				
			||||||
  bool is_temperature_{false};
 | 
					  bool is_temperature_{false};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
import esphome.final_validate as fv
 | 
					import esphome.final_validate as fv
 | 
				
			||||||
@@ -19,16 +21,35 @@ from . import (
 | 
				
			|||||||
    ATTENUATION_MODES,
 | 
					    ATTENUATION_MODES,
 | 
				
			||||||
    ESP32_VARIANT_ADC1_PIN_TO_CHANNEL,
 | 
					    ESP32_VARIANT_ADC1_PIN_TO_CHANNEL,
 | 
				
			||||||
    ESP32_VARIANT_ADC2_PIN_TO_CHANNEL,
 | 
					    ESP32_VARIANT_ADC2_PIN_TO_CHANNEL,
 | 
				
			||||||
 | 
					    adc_ns,
 | 
				
			||||||
    validate_adc_pin,
 | 
					    validate_adc_pin,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_LOGGER = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AUTO_LOAD = ["voltage_sampler"]
 | 
					AUTO_LOAD = ["voltage_sampler"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONF_SAMPLES = "samples"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_attenuation = cv.enum(ATTENUATION_MODES, lower=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def validate_config(config):
 | 
					def validate_config(config):
 | 
				
			||||||
    if config[CONF_RAW] and config.get(CONF_ATTENUATION, None) == "auto":
 | 
					    if config[CONF_RAW] and config.get(CONF_ATTENUATION, None) == "auto":
 | 
				
			||||||
        raise cv.Invalid("Automatic attenuation cannot be used when raw output is set")
 | 
					        raise cv.Invalid("Automatic attenuation cannot be used when raw output is set")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if config.get(CONF_ATTENUATION, None) == "auto" and config.get(CONF_SAMPLES, 1) > 1:
 | 
				
			||||||
 | 
					        raise cv.Invalid(
 | 
				
			||||||
 | 
					            "Automatic attenuation cannot be used when multisampling is set"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    if config.get(CONF_ATTENUATION) == "11db":
 | 
				
			||||||
 | 
					        _LOGGER.warning(
 | 
				
			||||||
 | 
					            "`attenuation: 11db` is deprecated, use `attenuation: 12db` instead"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        # Alter value here so `config` command prints the recommended change
 | 
				
			||||||
 | 
					        config[CONF_ATTENUATION] = _attenuation("12db")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return config
 | 
					    return config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -47,7 +68,6 @@ def final_validate_config(config):
 | 
				
			|||||||
    return config
 | 
					    return config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
adc_ns = cg.esphome_ns.namespace("adc")
 | 
					 | 
				
			||||||
ADCSensor = adc_ns.class_(
 | 
					ADCSensor = adc_ns.class_(
 | 
				
			||||||
    "ADCSensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler
 | 
					    "ADCSensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -65,8 +85,9 @@ CONFIG_SCHEMA = cv.All(
 | 
				
			|||||||
            cv.Required(CONF_PIN): validate_adc_pin,
 | 
					            cv.Required(CONF_PIN): validate_adc_pin,
 | 
				
			||||||
            cv.Optional(CONF_RAW, default=False): cv.boolean,
 | 
					            cv.Optional(CONF_RAW, default=False): cv.boolean,
 | 
				
			||||||
            cv.SplitDefault(CONF_ATTENUATION, esp32="0db"): cv.All(
 | 
					            cv.SplitDefault(CONF_ATTENUATION, esp32="0db"): cv.All(
 | 
				
			||||||
                cv.only_on_esp32, cv.enum(ATTENUATION_MODES, lower=True)
 | 
					                cv.only_on_esp32, _attenuation
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_SAMPLES, default=1): cv.int_range(min=1, max=255),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    .extend(cv.polling_component_schema("60s")),
 | 
					    .extend(cv.polling_component_schema("60s")),
 | 
				
			||||||
@@ -90,6 +111,7 @@ async def to_code(config):
 | 
				
			|||||||
        cg.add(var.set_pin(pin))
 | 
					        cg.add(var.set_pin(pin))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cg.add(var.set_output_raw(config[CONF_RAW]))
 | 
					    cg.add(var.set_output_raw(config[CONF_RAW]))
 | 
				
			||||||
 | 
					    cg.add(var.set_sample_count(config[CONF_SAMPLES]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if attenuation := config.get(CONF_ATTENUATION):
 | 
					    if attenuation := config.get(CONF_ATTENUATION):
 | 
				
			||||||
        if attenuation == "auto":
 | 
					        if attenuation == "auto":
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,8 @@
 | 
				
			|||||||
#include "ade7880_registers.h"
 | 
					#include "ade7880_registers.h"
 | 
				
			||||||
#include "esphome/core/log.h"
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cinttypes>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace ade7880 {
 | 
					namespace ade7880 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -156,7 +158,7 @@ void ADE7880::update() {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ESP_LOGD(TAG, "update took %u ms", millis() - start);
 | 
					  ESP_LOGD(TAG, "update took %" PRIu32 " ms", millis() - start);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ADE7880::dump_config() {
 | 
					void ADE7880::dump_config() {
 | 
				
			||||||
@@ -176,9 +178,9 @@ void ADE7880::dump_config() {
 | 
				
			|||||||
    LOG_SENSOR("    ", "Forward Active Energy", this->channel_a_->forward_active_energy);
 | 
					    LOG_SENSOR("    ", "Forward Active Energy", this->channel_a_->forward_active_energy);
 | 
				
			||||||
    LOG_SENSOR("    ", "Reverse Active Energy", this->channel_a_->reverse_active_energy);
 | 
					    LOG_SENSOR("    ", "Reverse Active Energy", this->channel_a_->reverse_active_energy);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "    Calibration:");
 | 
					    ESP_LOGCONFIG(TAG, "    Calibration:");
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Current: %u", this->channel_a_->current_gain_calibration);
 | 
					    ESP_LOGCONFIG(TAG, "     Current: %" PRId32, this->channel_a_->current_gain_calibration);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Voltage: %d", this->channel_a_->voltage_gain_calibration);
 | 
					    ESP_LOGCONFIG(TAG, "     Voltage: %" PRId32, this->channel_a_->voltage_gain_calibration);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Power: %d", this->channel_a_->power_gain_calibration);
 | 
					    ESP_LOGCONFIG(TAG, "     Power: %" PRId32, this->channel_a_->power_gain_calibration);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Phase Angle: %u", this->channel_a_->phase_angle_calibration);
 | 
					    ESP_LOGCONFIG(TAG, "     Phase Angle: %u", this->channel_a_->phase_angle_calibration);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -192,9 +194,9 @@ void ADE7880::dump_config() {
 | 
				
			|||||||
    LOG_SENSOR("    ", "Forward Active Energy", this->channel_b_->forward_active_energy);
 | 
					    LOG_SENSOR("    ", "Forward Active Energy", this->channel_b_->forward_active_energy);
 | 
				
			||||||
    LOG_SENSOR("    ", "Reverse Active Energy", this->channel_b_->reverse_active_energy);
 | 
					    LOG_SENSOR("    ", "Reverse Active Energy", this->channel_b_->reverse_active_energy);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "    Calibration:");
 | 
					    ESP_LOGCONFIG(TAG, "    Calibration:");
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Current: %u", this->channel_b_->current_gain_calibration);
 | 
					    ESP_LOGCONFIG(TAG, "     Current: %" PRId32, this->channel_b_->current_gain_calibration);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Voltage: %d", this->channel_b_->voltage_gain_calibration);
 | 
					    ESP_LOGCONFIG(TAG, "     Voltage: %" PRId32, this->channel_b_->voltage_gain_calibration);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Power: %d", this->channel_b_->power_gain_calibration);
 | 
					    ESP_LOGCONFIG(TAG, "     Power: %" PRId32, this->channel_b_->power_gain_calibration);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Phase Angle: %u", this->channel_b_->phase_angle_calibration);
 | 
					    ESP_LOGCONFIG(TAG, "     Phase Angle: %u", this->channel_b_->phase_angle_calibration);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -208,9 +210,9 @@ void ADE7880::dump_config() {
 | 
				
			|||||||
    LOG_SENSOR("    ", "Forward Active Energy", this->channel_c_->forward_active_energy);
 | 
					    LOG_SENSOR("    ", "Forward Active Energy", this->channel_c_->forward_active_energy);
 | 
				
			||||||
    LOG_SENSOR("    ", "Reverse Active Energy", this->channel_c_->reverse_active_energy);
 | 
					    LOG_SENSOR("    ", "Reverse Active Energy", this->channel_c_->reverse_active_energy);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "    Calibration:");
 | 
					    ESP_LOGCONFIG(TAG, "    Calibration:");
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Current: %u", this->channel_c_->current_gain_calibration);
 | 
					    ESP_LOGCONFIG(TAG, "     Current: %" PRId32, this->channel_c_->current_gain_calibration);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Voltage: %d", this->channel_c_->voltage_gain_calibration);
 | 
					    ESP_LOGCONFIG(TAG, "     Voltage: %" PRId32, this->channel_c_->voltage_gain_calibration);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Power: %d", this->channel_c_->power_gain_calibration);
 | 
					    ESP_LOGCONFIG(TAG, "     Power: %" PRId32, this->channel_c_->power_gain_calibration);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Phase Angle: %u", this->channel_c_->phase_angle_calibration);
 | 
					    ESP_LOGCONFIG(TAG, "     Phase Angle: %u", this->channel_c_->phase_angle_calibration);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -218,7 +220,7 @@ void ADE7880::dump_config() {
 | 
				
			|||||||
    ESP_LOGCONFIG(TAG, "  Neutral:");
 | 
					    ESP_LOGCONFIG(TAG, "  Neutral:");
 | 
				
			||||||
    LOG_SENSOR("    ", "Current", this->channel_n_->current);
 | 
					    LOG_SENSOR("    ", "Current", this->channel_n_->current);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "    Calibration:");
 | 
					    ESP_LOGCONFIG(TAG, "    Calibration:");
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Current: %u", this->channel_n_->current_gain_calibration);
 | 
					    ESP_LOGCONFIG(TAG, "     Current: %" PRId32, this->channel_n_->current_gain_calibration);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  LOG_I2C_DEVICE(this);
 | 
					  LOG_I2C_DEVICE(this);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,8 @@
 | 
				
			|||||||
#include "ade7953_base.h"
 | 
					#include "ade7953_base.h"
 | 
				
			||||||
#include "esphome/core/log.h"
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cinttypes>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace ade7953_base {
 | 
					namespace ade7953_base {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -105,7 +107,7 @@ void ADE7953::update() {
 | 
				
			|||||||
    this->last_update_ = now;
 | 
					    this->last_update_ = now;
 | 
				
			||||||
    // prevent DIV/0
 | 
					    // prevent DIV/0
 | 
				
			||||||
    pf = ADE_WATTSEC_POWER_FACTOR * (diff < 10 ? 10 : diff) / 1000;
 | 
					    pf = ADE_WATTSEC_POWER_FACTOR * (diff < 10 ? 10 : diff) / 1000;
 | 
				
			||||||
    ESP_LOGVV(TAG, "ADE7953::update() diff=%d pf=%f", diff, pf);
 | 
					    ESP_LOGVV(TAG, "ADE7953::update() diff=%" PRIu32 " pf=%f", diff, pf);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Apparent power
 | 
					  // Apparent power
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
#include "ags10.h"
 | 
					#include "ags10.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cinttypes>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace ags10 {
 | 
					namespace ags10 {
 | 
				
			||||||
static const char *const TAG = "ags10";
 | 
					static const char *const TAG = "ags10";
 | 
				
			||||||
@@ -35,7 +37,7 @@ void AGS10Component::setup() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  auto resistance = this->read_resistance_();
 | 
					  auto resistance = this->read_resistance_();
 | 
				
			||||||
  if (resistance) {
 | 
					  if (resistance) {
 | 
				
			||||||
    ESP_LOGD(TAG, "AGS10 Sensor Resistance: 0x%08X", *resistance);
 | 
					    ESP_LOGD(TAG, "AGS10 Sensor Resistance: 0x%08" PRIX32, *resistance);
 | 
				
			||||||
    if (this->resistance_ != nullptr) {
 | 
					    if (this->resistance_ != nullptr) {
 | 
				
			||||||
      this->resistance_->publish_state(*resistance);
 | 
					      this->resistance_->publish_state(*resistance);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome.components import web_server
 | 
				
			||||||
from esphome import automation
 | 
					from esphome import automation
 | 
				
			||||||
from esphome.automation import maybe_simple_id
 | 
					from esphome.automation import maybe_simple_id
 | 
				
			||||||
from esphome.core import CORE, coroutine_with_priority
 | 
					from esphome.core import CORE, coroutine_with_priority
 | 
				
			||||||
@@ -8,6 +9,7 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_ON_STATE,
 | 
					    CONF_ON_STATE,
 | 
				
			||||||
    CONF_TRIGGER_ID,
 | 
					    CONF_TRIGGER_ID,
 | 
				
			||||||
    CONF_CODE,
 | 
					    CONF_CODE,
 | 
				
			||||||
 | 
					    CONF_WEB_SERVER_ID,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from esphome.cpp_helpers import setup_entity
 | 
					from esphome.cpp_helpers import setup_entity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -76,6 +78,8 @@ AlarmControlPanelCondition = alarm_control_panel_ns.class_(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ALARM_CONTROL_PANEL_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
 | 
					ALARM_CONTROL_PANEL_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
 | 
				
			||||||
 | 
					    web_server.WEBSERVER_SORTING_SCHEMA
 | 
				
			||||||
 | 
					).extend(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        cv.GenerateID(): cv.declare_id(AlarmControlPanel),
 | 
					        cv.GenerateID(): cv.declare_id(AlarmControlPanel),
 | 
				
			||||||
        cv.Optional(CONF_ON_STATE): automation.validate_automation(
 | 
					        cv.Optional(CONF_ON_STATE): automation.validate_automation(
 | 
				
			||||||
@@ -185,6 +189,9 @@ async def setup_alarm_control_panel_core_(var, config):
 | 
				
			|||||||
    for conf in config.get(CONF_ON_READY, []):
 | 
					    for conf in config.get(CONF_ON_READY, []):
 | 
				
			||||||
        trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
 | 
					        trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
 | 
				
			||||||
        await automation.build_automation(trigger, [], conf)
 | 
					        await automation.build_automation(trigger, [], conf)
 | 
				
			||||||
 | 
					    if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
 | 
				
			||||||
 | 
					        web_server_ = await cg.get_variable(webserver_id)
 | 
				
			||||||
 | 
					        web_server.add_entity_to_sorting_list(web_server_, var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def register_alarm_control_panel(var, config):
 | 
					async def register_alarm_control_panel(var, config):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -157,7 +157,7 @@ async def to_code(config):
 | 
				
			|||||||
            pixels = list(frame.getdata())
 | 
					            pixels = list(frame.getdata())
 | 
				
			||||||
            if len(pixels) != height * width:
 | 
					            if len(pixels) != height * width:
 | 
				
			||||||
                raise core.EsphomeError(
 | 
					                raise core.EsphomeError(
 | 
				
			||||||
                    f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})"
 | 
					                    f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})"
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            for pix, a in pixels:
 | 
					            for pix, a in pixels:
 | 
				
			||||||
                if transparent:
 | 
					                if transparent:
 | 
				
			||||||
@@ -180,7 +180,7 @@ async def to_code(config):
 | 
				
			|||||||
            pixels = list(frame.getdata())
 | 
					            pixels = list(frame.getdata())
 | 
				
			||||||
            if len(pixels) != height * width:
 | 
					            if len(pixels) != height * width:
 | 
				
			||||||
                raise core.EsphomeError(
 | 
					                raise core.EsphomeError(
 | 
				
			||||||
                    f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})"
 | 
					                    f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})"
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            for pix in pixels:
 | 
					            for pix in pixels:
 | 
				
			||||||
                data[pos] = pix[0]
 | 
					                data[pos] = pix[0]
 | 
				
			||||||
@@ -203,7 +203,7 @@ async def to_code(config):
 | 
				
			|||||||
            pixels = list(frame.getdata())
 | 
					            pixels = list(frame.getdata())
 | 
				
			||||||
            if len(pixels) != height * width:
 | 
					            if len(pixels) != height * width:
 | 
				
			||||||
                raise core.EsphomeError(
 | 
					                raise core.EsphomeError(
 | 
				
			||||||
                    f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})"
 | 
					                    f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})"
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            for r, g, b, a in pixels:
 | 
					            for r, g, b, a in pixels:
 | 
				
			||||||
                if transparent:
 | 
					                if transparent:
 | 
				
			||||||
@@ -232,7 +232,7 @@ async def to_code(config):
 | 
				
			|||||||
            pixels = list(frame.getdata())
 | 
					            pixels = list(frame.getdata())
 | 
				
			||||||
            if len(pixels) != height * width:
 | 
					            if len(pixels) != height * width:
 | 
				
			||||||
                raise core.EsphomeError(
 | 
					                raise core.EsphomeError(
 | 
				
			||||||
                    f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height*width})"
 | 
					                    f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})"
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            for r, g, b, a in pixels:
 | 
					            for r, g, b, a in pixels:
 | 
				
			||||||
                R = r >> 3
 | 
					                R = r >> 3
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1147,6 +1147,9 @@ message MediaPlayerCommandRequest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  bool has_media_url = 6;
 | 
					  bool has_media_url = 6;
 | 
				
			||||||
  string media_url = 7;
 | 
					  string media_url = 7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool has_announcement = 8;
 | 
				
			||||||
 | 
					  bool announcement = 9;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ==================== BLUETOOTH ====================
 | 
					// ==================== BLUETOOTH ====================
 | 
				
			||||||
@@ -1514,6 +1517,25 @@ message VoiceAssistantAudio {
 | 
				
			|||||||
  bool end = 2;
 | 
					  bool end = 2;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum VoiceAssistantTimerEvent {
 | 
				
			||||||
 | 
					  VOICE_ASSISTANT_TIMER_STARTED = 0;
 | 
				
			||||||
 | 
					  VOICE_ASSISTANT_TIMER_UPDATED = 1;
 | 
				
			||||||
 | 
					  VOICE_ASSISTANT_TIMER_CANCELLED = 2;
 | 
				
			||||||
 | 
					  VOICE_ASSISTANT_TIMER_FINISHED = 3;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					message VoiceAssistantTimerEventResponse {
 | 
				
			||||||
 | 
					  option (id) = 115;
 | 
				
			||||||
 | 
					  option (source) = SOURCE_CLIENT;
 | 
				
			||||||
 | 
					  option (ifdef) = "USE_VOICE_ASSISTANT";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  VoiceAssistantTimerEvent event_type = 1;
 | 
				
			||||||
 | 
					  string timer_id = 2;
 | 
				
			||||||
 | 
					  string name = 3;
 | 
				
			||||||
 | 
					  uint32 total_seconds = 4;
 | 
				
			||||||
 | 
					  uint32 seconds_left = 5;
 | 
				
			||||||
 | 
					  bool is_active = 6;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ==================== ALARM CONTROL PANEL ====================
 | 
					// ==================== ALARM CONTROL PANEL ====================
 | 
				
			||||||
enum AlarmControlPanelState {
 | 
					enum AlarmControlPanelState {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1002,7 +1002,11 @@ bool APIConnection::send_media_player_state(media_player::MediaPlayer *media_pla
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  MediaPlayerStateResponse resp{};
 | 
					  MediaPlayerStateResponse resp{};
 | 
				
			||||||
  resp.key = media_player->get_object_id_hash();
 | 
					  resp.key = media_player->get_object_id_hash();
 | 
				
			||||||
  resp.state = static_cast<enums::MediaPlayerState>(media_player->state);
 | 
					
 | 
				
			||||||
 | 
					  media_player::MediaPlayerState report_state = media_player->state == media_player::MEDIA_PLAYER_STATE_ANNOUNCING
 | 
				
			||||||
 | 
					                                                    ? media_player::MEDIA_PLAYER_STATE_PLAYING
 | 
				
			||||||
 | 
					                                                    : media_player->state;
 | 
				
			||||||
 | 
					  resp.state = static_cast<enums::MediaPlayerState>(report_state);
 | 
				
			||||||
  resp.volume = media_player->volume;
 | 
					  resp.volume = media_player->volume;
 | 
				
			||||||
  resp.muted = media_player->is_muted();
 | 
					  resp.muted = media_player->is_muted();
 | 
				
			||||||
  return this->send_media_player_state_response(resp);
 | 
					  return this->send_media_player_state_response(resp);
 | 
				
			||||||
@@ -1038,6 +1042,9 @@ void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) {
 | 
				
			|||||||
  if (msg.has_media_url) {
 | 
					  if (msg.has_media_url) {
 | 
				
			||||||
    call.set_media_url(msg.media_url);
 | 
					    call.set_media_url(msg.media_url);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  if (msg.has_announcement) {
 | 
				
			||||||
 | 
					    call.set_announcement(msg.announcement);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  call.perform();
 | 
					  call.perform();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -1186,6 +1193,15 @@ void APIConnection::on_voice_assistant_audio(const VoiceAssistantAudio &msg) {
 | 
				
			|||||||
    voice_assistant::global_voice_assistant->on_audio(msg);
 | 
					    voice_assistant::global_voice_assistant->on_audio(msg);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					void APIConnection::on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &msg) {
 | 
				
			||||||
 | 
					  if (voice_assistant::global_voice_assistant != nullptr) {
 | 
				
			||||||
 | 
					    if (voice_assistant::global_voice_assistant->get_api_connection() != this) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    voice_assistant::global_voice_assistant->on_timer_event(msg);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -150,6 +150,7 @@ class APIConnection : public APIServerConnection {
 | 
				
			|||||||
  void on_voice_assistant_response(const VoiceAssistantResponse &msg) override;
 | 
					  void on_voice_assistant_response(const VoiceAssistantResponse &msg) override;
 | 
				
			||||||
  void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override;
 | 
					  void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override;
 | 
				
			||||||
  void on_voice_assistant_audio(const VoiceAssistantAudio &msg) override;
 | 
					  void on_voice_assistant_audio(const VoiceAssistantAudio &msg) override;
 | 
				
			||||||
 | 
					  void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &msg) override;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ALARM_CONTROL_PANEL
 | 
					#ifdef USE_ALARM_CONTROL_PANEL
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -475,6 +475,22 @@ template<> const char *proto_enum_to_string<enums::VoiceAssistantEvent>(enums::V
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
 | 
					template<> const char *proto_enum_to_string<enums::VoiceAssistantTimerEvent>(enums::VoiceAssistantTimerEvent value) {
 | 
				
			||||||
 | 
					  switch (value) {
 | 
				
			||||||
 | 
					    case enums::VOICE_ASSISTANT_TIMER_STARTED:
 | 
				
			||||||
 | 
					      return "VOICE_ASSISTANT_TIMER_STARTED";
 | 
				
			||||||
 | 
					    case enums::VOICE_ASSISTANT_TIMER_UPDATED:
 | 
				
			||||||
 | 
					      return "VOICE_ASSISTANT_TIMER_UPDATED";
 | 
				
			||||||
 | 
					    case enums::VOICE_ASSISTANT_TIMER_CANCELLED:
 | 
				
			||||||
 | 
					      return "VOICE_ASSISTANT_TIMER_CANCELLED";
 | 
				
			||||||
 | 
					    case enums::VOICE_ASSISTANT_TIMER_FINISHED:
 | 
				
			||||||
 | 
					      return "VOICE_ASSISTANT_TIMER_FINISHED";
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      return "UNKNOWN";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::AlarmControlPanelState>(enums::AlarmControlPanelState value) {
 | 
					template<> const char *proto_enum_to_string<enums::AlarmControlPanelState>(enums::AlarmControlPanelState value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::ALARM_STATE_DISARMED:
 | 
					    case enums::ALARM_STATE_DISARMED:
 | 
				
			||||||
@@ -5253,6 +5269,14 @@ bool MediaPlayerCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt val
 | 
				
			|||||||
      this->has_media_url = value.as_bool();
 | 
					      this->has_media_url = value.as_bool();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case 8: {
 | 
				
			||||||
 | 
					      this->has_announcement = value.as_bool();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 9: {
 | 
				
			||||||
 | 
					      this->announcement = value.as_bool();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -5289,6 +5313,8 @@ void MediaPlayerCommandRequest::encode(ProtoWriteBuffer buffer) const {
 | 
				
			|||||||
  buffer.encode_float(5, this->volume);
 | 
					  buffer.encode_float(5, this->volume);
 | 
				
			||||||
  buffer.encode_bool(6, this->has_media_url);
 | 
					  buffer.encode_bool(6, this->has_media_url);
 | 
				
			||||||
  buffer.encode_string(7, this->media_url);
 | 
					  buffer.encode_string(7, this->media_url);
 | 
				
			||||||
 | 
					  buffer.encode_bool(8, this->has_announcement);
 | 
				
			||||||
 | 
					  buffer.encode_bool(9, this->announcement);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
void MediaPlayerCommandRequest::dump_to(std::string &out) const {
 | 
					void MediaPlayerCommandRequest::dump_to(std::string &out) const {
 | 
				
			||||||
@@ -5323,6 +5349,14 @@ void MediaPlayerCommandRequest::dump_to(std::string &out) const {
 | 
				
			|||||||
  out.append("  media_url: ");
 | 
					  out.append("  media_url: ");
 | 
				
			||||||
  out.append("'").append(this->media_url).append("'");
 | 
					  out.append("'").append(this->media_url).append("'");
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  has_announcement: ");
 | 
				
			||||||
 | 
					  out.append(YESNO(this->has_announcement));
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  announcement: ");
 | 
				
			||||||
 | 
					  out.append(YESNO(this->announcement));
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
  out.append("}");
 | 
					  out.append("}");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -6839,6 +6873,82 @@ void VoiceAssistantAudio::dump_to(std::string &out) const {
 | 
				
			|||||||
  out.append("}");
 | 
					  out.append("}");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					bool VoiceAssistantTimerEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
 | 
				
			||||||
 | 
					  switch (field_id) {
 | 
				
			||||||
 | 
					    case 1: {
 | 
				
			||||||
 | 
					      this->event_type = value.as_enum<enums::VoiceAssistantTimerEvent>();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 4: {
 | 
				
			||||||
 | 
					      this->total_seconds = value.as_uint32();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 5: {
 | 
				
			||||||
 | 
					      this->seconds_left = value.as_uint32();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 6: {
 | 
				
			||||||
 | 
					      this->is_active = value.as_bool();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bool VoiceAssistantTimerEventResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
 | 
				
			||||||
 | 
					  switch (field_id) {
 | 
				
			||||||
 | 
					    case 2: {
 | 
				
			||||||
 | 
					      this->timer_id = value.as_string();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 3: {
 | 
				
			||||||
 | 
					      this->name = value.as_string();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void VoiceAssistantTimerEventResponse::encode(ProtoWriteBuffer buffer) const {
 | 
				
			||||||
 | 
					  buffer.encode_enum<enums::VoiceAssistantTimerEvent>(1, this->event_type);
 | 
				
			||||||
 | 
					  buffer.encode_string(2, this->timer_id);
 | 
				
			||||||
 | 
					  buffer.encode_string(3, this->name);
 | 
				
			||||||
 | 
					  buffer.encode_uint32(4, this->total_seconds);
 | 
				
			||||||
 | 
					  buffer.encode_uint32(5, this->seconds_left);
 | 
				
			||||||
 | 
					  buffer.encode_bool(6, this->is_active);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
 | 
					void VoiceAssistantTimerEventResponse::dump_to(std::string &out) const {
 | 
				
			||||||
 | 
					  __attribute__((unused)) char buffer[64];
 | 
				
			||||||
 | 
					  out.append("VoiceAssistantTimerEventResponse {\n");
 | 
				
			||||||
 | 
					  out.append("  event_type: ");
 | 
				
			||||||
 | 
					  out.append(proto_enum_to_string<enums::VoiceAssistantTimerEvent>(this->event_type));
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  timer_id: ");
 | 
				
			||||||
 | 
					  out.append("'").append(this->timer_id).append("'");
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  name: ");
 | 
				
			||||||
 | 
					  out.append("'").append(this->name).append("'");
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  total_seconds: ");
 | 
				
			||||||
 | 
					  sprintf(buffer, "%" PRIu32, this->total_seconds);
 | 
				
			||||||
 | 
					  out.append(buffer);
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  seconds_left: ");
 | 
				
			||||||
 | 
					  sprintf(buffer, "%" PRIu32, this->seconds_left);
 | 
				
			||||||
 | 
					  out.append(buffer);
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  is_active: ");
 | 
				
			||||||
 | 
					  out.append(YESNO(this->is_active));
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					  out.append("}");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
bool ListEntitiesAlarmControlPanelResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
 | 
					bool ListEntitiesAlarmControlPanelResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
 | 
				
			||||||
  switch (field_id) {
 | 
					  switch (field_id) {
 | 
				
			||||||
    case 6: {
 | 
					    case 6: {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -191,6 +191,12 @@ enum VoiceAssistantEvent : uint32_t {
 | 
				
			|||||||
  VOICE_ASSISTANT_TTS_STREAM_START = 98,
 | 
					  VOICE_ASSISTANT_TTS_STREAM_START = 98,
 | 
				
			||||||
  VOICE_ASSISTANT_TTS_STREAM_END = 99,
 | 
					  VOICE_ASSISTANT_TTS_STREAM_END = 99,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					enum VoiceAssistantTimerEvent : uint32_t {
 | 
				
			||||||
 | 
					  VOICE_ASSISTANT_TIMER_STARTED = 0,
 | 
				
			||||||
 | 
					  VOICE_ASSISTANT_TIMER_UPDATED = 1,
 | 
				
			||||||
 | 
					  VOICE_ASSISTANT_TIMER_CANCELLED = 2,
 | 
				
			||||||
 | 
					  VOICE_ASSISTANT_TIMER_FINISHED = 3,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
enum AlarmControlPanelState : uint32_t {
 | 
					enum AlarmControlPanelState : uint32_t {
 | 
				
			||||||
  ALARM_STATE_DISARMED = 0,
 | 
					  ALARM_STATE_DISARMED = 0,
 | 
				
			||||||
  ALARM_STATE_ARMED_HOME = 1,
 | 
					  ALARM_STATE_ARMED_HOME = 1,
 | 
				
			||||||
@@ -1298,6 +1304,8 @@ class MediaPlayerCommandRequest : public ProtoMessage {
 | 
				
			|||||||
  float volume{0.0f};
 | 
					  float volume{0.0f};
 | 
				
			||||||
  bool has_media_url{false};
 | 
					  bool has_media_url{false};
 | 
				
			||||||
  std::string media_url{};
 | 
					  std::string media_url{};
 | 
				
			||||||
 | 
					  bool has_announcement{false};
 | 
				
			||||||
 | 
					  bool announcement{false};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
@@ -1773,6 +1781,23 @@ class VoiceAssistantAudio : public ProtoMessage {
 | 
				
			|||||||
  bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
 | 
					  bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
 | 
				
			||||||
  bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
 | 
					  bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					class VoiceAssistantTimerEventResponse : public ProtoMessage {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  enums::VoiceAssistantTimerEvent event_type{};
 | 
				
			||||||
 | 
					  std::string timer_id{};
 | 
				
			||||||
 | 
					  std::string name{};
 | 
				
			||||||
 | 
					  uint32_t total_seconds{0};
 | 
				
			||||||
 | 
					  uint32_t seconds_left{0};
 | 
				
			||||||
 | 
					  bool is_active{false};
 | 
				
			||||||
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 protected:
 | 
				
			||||||
 | 
					  bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
 | 
				
			||||||
 | 
					  bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
class ListEntitiesAlarmControlPanelResponse : public ProtoMessage {
 | 
					class ListEntitiesAlarmControlPanelResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string object_id{};
 | 
					  std::string object_id{};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -484,6 +484,8 @@ bool APIServerConnectionBase::send_voice_assistant_audio(const VoiceAssistantAud
 | 
				
			|||||||
  return this->send_message_<VoiceAssistantAudio>(msg, 106);
 | 
					  return this->send_message_<VoiceAssistantAudio>(msg, 106);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_VOICE_ASSISTANT
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#ifdef USE_ALARM_CONTROL_PANEL
 | 
					#ifdef USE_ALARM_CONTROL_PANEL
 | 
				
			||||||
bool APIServerConnectionBase::send_list_entities_alarm_control_panel_response(
 | 
					bool APIServerConnectionBase::send_list_entities_alarm_control_panel_response(
 | 
				
			||||||
    const ListEntitiesAlarmControlPanelResponse &msg) {
 | 
					    const ListEntitiesAlarmControlPanelResponse &msg) {
 | 
				
			||||||
@@ -1093,6 +1095,17 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
 | 
				
			|||||||
      ESP_LOGVV(TAG, "on_date_time_command_request: %s", msg.dump().c_str());
 | 
					      ESP_LOGVV(TAG, "on_date_time_command_request: %s", msg.dump().c_str());
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
      this->on_date_time_command_request(msg);
 | 
					      this->on_date_time_command_request(msg);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 115: {
 | 
				
			||||||
 | 
					#ifdef USE_VOICE_ASSISTANT
 | 
				
			||||||
 | 
					      VoiceAssistantTimerEventResponse msg;
 | 
				
			||||||
 | 
					      msg.decode(msg_data, msg_size);
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
 | 
					      ESP_LOGVV(TAG, "on_voice_assistant_timer_event_response: %s", msg.dump().c_str());
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					      this->on_voice_assistant_timer_event_response(msg);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -244,6 +244,9 @@ class APIServerConnectionBase : public ProtoService {
 | 
				
			|||||||
  bool send_voice_assistant_audio(const VoiceAssistantAudio &msg);
 | 
					  bool send_voice_assistant_audio(const VoiceAssistantAudio &msg);
 | 
				
			||||||
  virtual void on_voice_assistant_audio(const VoiceAssistantAudio &value){};
 | 
					  virtual void on_voice_assistant_audio(const VoiceAssistantAudio &value){};
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_VOICE_ASSISTANT
 | 
				
			||||||
 | 
					  virtual void on_voice_assistant_timer_event_response(const VoiceAssistantTimerEventResponse &value){};
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#ifdef USE_ALARM_CONTROL_PANEL
 | 
					#ifdef USE_ALARM_CONTROL_PANEL
 | 
				
			||||||
  bool send_list_entities_alarm_control_panel_response(const ListEntitiesAlarmControlPanelResponse &msg);
 | 
					  bool send_list_entities_alarm_control_panel_response(const ListEntitiesAlarmControlPanelResponse &msg);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -105,7 +105,7 @@ class CustomAPIDevice {
 | 
				
			|||||||
  /** Subscribe to the state (or attribute state) of an entity from Home Assistant.
 | 
					  /** Subscribe to the state (or attribute state) of an entity from Home Assistant.
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
   * Usage:
 | 
					   * Usage:
 | 
				
			||||||
   *å
 | 
					   *
 | 
				
			||||||
   * ```cpp
 | 
					   * ```cpp
 | 
				
			||||||
   * void setup() override {
 | 
					   * void setup() override {
 | 
				
			||||||
   *   subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "sensor.weather_forecast");
 | 
					   *   subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "sensor.weather_forecast");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,7 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
BEDJET_CLIENT_SCHEMA = cv.Schema(
 | 
					BEDJET_CLIENT_SCHEMA = cv.Schema(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        cv.Required(CONF_BEDJET_ID): cv.use_id(BedJetHub),
 | 
					        cv.GenerateID(CONF_BEDJET_ID): cv.use_id(BedJetHub),
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -157,5 +157,11 @@ bool BedjetCodec::compare(const uint8_t *data, uint16_t length) {
 | 
				
			|||||||
  return explicit_fields_changed;
 | 
					  return explicit_fields_changed;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Converts a BedJet temp step into degrees Celsius.
 | 
				
			||||||
 | 
					float bedjet_temp_to_c(uint8_t temp) {
 | 
				
			||||||
 | 
					  // BedJet temp is "C*2"; to get C, divide by 2.
 | 
				
			||||||
 | 
					  return temp / 2.0f;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace bedjet
 | 
					}  // namespace bedjet
 | 
				
			||||||
}  // namespace esphome
 | 
					}  // namespace esphome
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -187,5 +187,8 @@ class BedjetCodec {
 | 
				
			|||||||
  BedjetStatusPacket buf_;
 | 
					  BedjetStatusPacket buf_;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Converts a BedJet temp step into degrees Celsius.
 | 
				
			||||||
 | 
					float bedjet_temp_to_c(uint8_t temp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace bedjet
 | 
					}  // namespace bedjet
 | 
				
			||||||
}  // namespace esphome
 | 
					}  // namespace esphome
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,6 +40,14 @@ enum BedjetHeatMode {
 | 
				
			|||||||
  HEAT_MODE_EXTENDED,
 | 
					  HEAT_MODE_EXTENDED,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Which temperature to use as the climate entity's current temperature reading
 | 
				
			||||||
 | 
					enum BedjetTemperatureSource {
 | 
				
			||||||
 | 
					  // Use the temperature of the air the BedJet is putting out
 | 
				
			||||||
 | 
					  TEMPERATURE_SOURCE_OUTLET,
 | 
				
			||||||
 | 
					  // Use the ambient temperature of the room the BedJet is in
 | 
				
			||||||
 | 
					  TEMPERATURE_SOURCE_AMBIENT
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum BedjetButton : uint8_t {
 | 
					enum BedjetButton : uint8_t {
 | 
				
			||||||
  /// Turn BedJet off
 | 
					  /// Turn BedJet off
 | 
				
			||||||
  BTN_OFF = 0x1,
 | 
					  BTN_OFF = 0x1,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_HEAT_MODE,
 | 
					    CONF_HEAT_MODE,
 | 
				
			||||||
    CONF_ID,
 | 
					    CONF_ID,
 | 
				
			||||||
    CONF_RECEIVE_TIMEOUT,
 | 
					    CONF_RECEIVE_TIMEOUT,
 | 
				
			||||||
 | 
					    CONF_TEMPERATURE_SOURCE,
 | 
				
			||||||
    CONF_TIME_ID,
 | 
					    CONF_TIME_ID,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from .. import (
 | 
					from .. import (
 | 
				
			||||||
@@ -21,10 +22,15 @@ DEPENDENCIES = ["bedjet"]
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
BedJetClimate = bedjet_ns.class_("BedJetClimate", climate.Climate, cg.PollingComponent)
 | 
					BedJetClimate = bedjet_ns.class_("BedJetClimate", climate.Climate, cg.PollingComponent)
 | 
				
			||||||
BedjetHeatMode = bedjet_ns.enum("BedjetHeatMode")
 | 
					BedjetHeatMode = bedjet_ns.enum("BedjetHeatMode")
 | 
				
			||||||
 | 
					BedjetTemperatureSource = bedjet_ns.enum("BedjetTemperatureSource")
 | 
				
			||||||
BEDJET_HEAT_MODES = {
 | 
					BEDJET_HEAT_MODES = {
 | 
				
			||||||
    "heat": BedjetHeatMode.HEAT_MODE_HEAT,
 | 
					    "heat": BedjetHeatMode.HEAT_MODE_HEAT,
 | 
				
			||||||
    "extended": BedjetHeatMode.HEAT_MODE_EXTENDED,
 | 
					    "extended": BedjetHeatMode.HEAT_MODE_EXTENDED,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					BEDJET_TEMPERATURE_SOURCES = {
 | 
				
			||||||
 | 
					    "outlet": BedjetTemperatureSource.TEMPERATURE_SOURCE_OUTLET,
 | 
				
			||||||
 | 
					    "ambient": BedjetTemperatureSource.TEMPERATURE_SOURCE_AMBIENT,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONFIG_SCHEMA = (
 | 
					CONFIG_SCHEMA = (
 | 
				
			||||||
    climate.CLIMATE_SCHEMA.extend(
 | 
					    climate.CLIMATE_SCHEMA.extend(
 | 
				
			||||||
@@ -33,6 +39,9 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
            cv.Optional(CONF_HEAT_MODE, default="heat"): cv.enum(
 | 
					            cv.Optional(CONF_HEAT_MODE, default="heat"): cv.enum(
 | 
				
			||||||
                BEDJET_HEAT_MODES, lower=True
 | 
					                BEDJET_HEAT_MODES, lower=True
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_TEMPERATURE_SOURCE, default="ambient"): cv.enum(
 | 
				
			||||||
 | 
					                BEDJET_TEMPERATURE_SOURCES, lower=True
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    .extend(cv.polling_component_schema("60s"))
 | 
					    .extend(cv.polling_component_schema("60s"))
 | 
				
			||||||
@@ -63,3 +72,4 @@ async def to_code(config):
 | 
				
			|||||||
    await register_bedjet_child(var, config)
 | 
					    await register_bedjet_child(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cg.add(var.set_heating_mode(config[CONF_HEAT_MODE]))
 | 
					    cg.add(var.set_heating_mode(config[CONF_HEAT_MODE]))
 | 
				
			||||||
 | 
					    cg.add(var.set_temperature_source(config[CONF_TEMPERATURE_SOURCE]))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,12 +8,6 @@ namespace bedjet {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
using namespace esphome::climate;
 | 
					using namespace esphome::climate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Converts a BedJet temp step into degrees Celsius.
 | 
					 | 
				
			||||||
float bedjet_temp_to_c(const uint8_t temp) {
 | 
					 | 
				
			||||||
  // BedJet temp is "C*2"; to get C, divide by 2.
 | 
					 | 
				
			||||||
  return temp / 2.0f;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const std::string *bedjet_fan_step_to_fan_mode(const uint8_t fan_step) {
 | 
					static const std::string *bedjet_fan_step_to_fan_mode(const uint8_t fan_step) {
 | 
				
			||||||
  if (fan_step < BEDJET_FAN_SPEED_COUNT)
 | 
					  if (fan_step < BEDJET_FAN_SPEED_COUNT)
 | 
				
			||||||
    return &BEDJET_FAN_STEP_NAME_STRINGS[fan_step];
 | 
					    return &BEDJET_FAN_STEP_NAME_STRINGS[fan_step];
 | 
				
			||||||
@@ -236,9 +230,14 @@ void BedJetClimate::on_status(const BedjetStatusPacket *data) {
 | 
				
			|||||||
  if (converted_temp > 0)
 | 
					  if (converted_temp > 0)
 | 
				
			||||||
    this->target_temperature = converted_temp;
 | 
					    this->target_temperature = converted_temp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  converted_temp = bedjet_temp_to_c(data->ambient_temp_step);
 | 
					  if (this->temperature_source_ == TEMPERATURE_SOURCE_OUTLET) {
 | 
				
			||||||
  if (converted_temp > 0)
 | 
					    converted_temp = bedjet_temp_to_c(data->actual_temp_step);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    converted_temp = bedjet_temp_to_c(data->ambient_temp_step);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (converted_temp > 0) {
 | 
				
			||||||
    this->current_temperature = converted_temp;
 | 
					    this->current_temperature = converted_temp;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const auto *fan_mode_name = bedjet_fan_step_to_fan_mode(data->fan_step);
 | 
					  const auto *fan_mode_name = bedjet_fan_step_to_fan_mode(data->fan_step);
 | 
				
			||||||
  if (fan_mode_name != nullptr) {
 | 
					  if (fan_mode_name != nullptr) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,8 @@ class BedJetClimate : public climate::Climate, public BedJetClient, public Polli
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /** Sets the default strategy to use for climate::CLIMATE_MODE_HEAT. */
 | 
					  /** Sets the default strategy to use for climate::CLIMATE_MODE_HEAT. */
 | 
				
			||||||
  void set_heating_mode(BedjetHeatMode mode) { this->heating_mode_ = mode; }
 | 
					  void set_heating_mode(BedjetHeatMode mode) { this->heating_mode_ = mode; }
 | 
				
			||||||
 | 
					  /** Sets the temperature source to use for the climate entity's current temperature */
 | 
				
			||||||
 | 
					  void set_temperature_source(BedjetTemperatureSource source) { this->temperature_source_ = source; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  climate::ClimateTraits traits() override {
 | 
					  climate::ClimateTraits traits() override {
 | 
				
			||||||
    auto traits = climate::ClimateTraits();
 | 
					    auto traits = climate::ClimateTraits();
 | 
				
			||||||
@@ -74,6 +76,7 @@ class BedJetClimate : public climate::Climate, public BedJetClient, public Polli
 | 
				
			|||||||
  void control(const climate::ClimateCall &call) override;
 | 
					  void control(const climate::ClimateCall &call) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  BedjetHeatMode heating_mode_ = HEAT_MODE_HEAT;
 | 
					  BedjetHeatMode heating_mode_ = HEAT_MODE_HEAT;
 | 
				
			||||||
 | 
					  BedjetTemperatureSource temperature_source_ = TEMPERATURE_SOURCE_AMBIENT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void reset_state_();
 | 
					  void reset_state_();
 | 
				
			||||||
  bool update_status_();
 | 
					  bool update_status_();
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										55
									
								
								esphome/components/bedjet/sensor/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								esphome/components/bedjet/sensor/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome.components import sensor
 | 
				
			||||||
 | 
					from esphome.const import (
 | 
				
			||||||
 | 
					    CONF_ID,
 | 
				
			||||||
 | 
					    DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					    UNIT_CELSIUS,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					from .. import (
 | 
				
			||||||
 | 
					    BEDJET_CLIENT_SCHEMA,
 | 
				
			||||||
 | 
					    bedjet_ns,
 | 
				
			||||||
 | 
					    register_bedjet_child,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_LOGGER = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					CODEOWNERS = ["@jhansche", "@javawizard"]
 | 
				
			||||||
 | 
					DEPENDENCIES = ["bedjet"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONF_OUTLET_TEMPERATURE = "outlet_temperature"
 | 
				
			||||||
 | 
					CONF_AMBIENT_TEMPERATURE = "ambient_temperature"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BedjetSensor = bedjet_ns.class_("BedjetSensor", cg.Component)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONFIG_SCHEMA = cv.Schema(
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cv.GenerateID(): cv.declare_id(BedjetSensor),
 | 
				
			||||||
 | 
					        cv.Optional(CONF_OUTLET_TEMPERATURE): sensor.sensor_schema(
 | 
				
			||||||
 | 
					            unit_of_measurement=UNIT_CELSIUS,
 | 
				
			||||||
 | 
					            device_class=DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
 | 
					            state_class=STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        cv.Optional(CONF_AMBIENT_TEMPERATURE): sensor.sensor_schema(
 | 
				
			||||||
 | 
					            unit_of_measurement=UNIT_CELSIUS,
 | 
				
			||||||
 | 
					            device_class=DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
 | 
					            state_class=STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					).extend(BEDJET_CLIENT_SCHEMA)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def to_code(config):
 | 
				
			||||||
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
 | 
					    await register_bedjet_child(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if outlet_temperature_sensor := config.get(CONF_OUTLET_TEMPERATURE):
 | 
				
			||||||
 | 
					        sensor_var = await sensor.new_sensor(outlet_temperature_sensor)
 | 
				
			||||||
 | 
					        cg.add(var.set_outlet_temperature_sensor(sensor_var))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ambient_temperature_sensor := config.get(CONF_AMBIENT_TEMPERATURE):
 | 
				
			||||||
 | 
					        sensor_var = await sensor.new_sensor(ambient_temperature_sensor)
 | 
				
			||||||
 | 
					        cg.add(var.set_ambient_temperature_sensor(sensor_var))
 | 
				
			||||||
							
								
								
									
										34
									
								
								esphome/components/bedjet/sensor/bedjet_sensor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								esphome/components/bedjet/sensor/bedjet_sensor.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					#include "bedjet_sensor.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace bedjet {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string BedjetSensor::describe() { return "BedJet Sensor"; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BedjetSensor::dump_config() {
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "BedJet Sensor:");
 | 
				
			||||||
 | 
					  LOG_SENSOR("  ", "Outlet Temperature", this->outlet_temperature_sensor_);
 | 
				
			||||||
 | 
					  LOG_SENSOR("  ", "Ambient Temperature", this->ambient_temperature_sensor_);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BedjetSensor::on_bedjet_state(bool is_ready) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BedjetSensor::on_status(const BedjetStatusPacket *data) {
 | 
				
			||||||
 | 
					  if (this->outlet_temperature_sensor_ != nullptr) {
 | 
				
			||||||
 | 
					    float converted_temp = bedjet_temp_to_c(data->actual_temp_step);
 | 
				
			||||||
 | 
					    if (converted_temp > 0) {
 | 
				
			||||||
 | 
					      this->outlet_temperature_sensor_->publish_state(converted_temp);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (this->ambient_temperature_sensor_ != nullptr) {
 | 
				
			||||||
 | 
					    float converted_temp = bedjet_temp_to_c(data->ambient_temp_step);
 | 
				
			||||||
 | 
					    if (converted_temp > 0) {
 | 
				
			||||||
 | 
					      this->ambient_temperature_sensor_->publish_state(converted_temp);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace bedjet
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										32
									
								
								esphome/components/bedjet/sensor/bedjet_sensor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								esphome/components/bedjet/sensor/bedjet_sensor.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "esphome/core/component.h"
 | 
				
			||||||
 | 
					#include "esphome/components/sensor/sensor.h"
 | 
				
			||||||
 | 
					#include "esphome/components/bedjet/bedjet_child.h"
 | 
				
			||||||
 | 
					#include "esphome/components/bedjet/bedjet_codec.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace bedjet {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BedjetSensor : public BedJetClient, public Component {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  void dump_config() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void on_status(const BedjetStatusPacket *data) override;
 | 
				
			||||||
 | 
					  void on_bedjet_state(bool is_ready) override;
 | 
				
			||||||
 | 
					  std::string describe() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void set_outlet_temperature_sensor(sensor::Sensor *outlet_temperature_sensor) {
 | 
				
			||||||
 | 
					    this->outlet_temperature_sensor_ = outlet_temperature_sensor;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  void set_ambient_temperature_sensor(sensor::Sensor *ambient_temperature_sensor) {
 | 
				
			||||||
 | 
					    this->ambient_temperature_sensor_ = ambient_temperature_sensor;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 protected:
 | 
				
			||||||
 | 
					  sensor::Sensor *outlet_temperature_sensor_{nullptr};
 | 
				
			||||||
 | 
					  sensor::Sensor *ambient_temperature_sensor_{nullptr};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace bedjet
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										0
									
								
								esphome/components/beken_spi_led_strip/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								esphome/components/beken_spi_led_strip/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										384
									
								
								esphome/components/beken_spi_led_strip/led_strip.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										384
									
								
								esphome/components/beken_spi_led_strip/led_strip.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,384 @@
 | 
				
			|||||||
 | 
					#include "led_strip.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_BK72XX
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "esphome/core/helpers.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#include "rtos_pub.h"
 | 
				
			||||||
 | 
					#include "spi.h"
 | 
				
			||||||
 | 
					#include "arm_arch.h"
 | 
				
			||||||
 | 
					#include "general_dma_pub.h"
 | 
				
			||||||
 | 
					#include "gpio_pub.h"
 | 
				
			||||||
 | 
					#include "icu_pub.h"
 | 
				
			||||||
 | 
					#undef SPI_DAT
 | 
				
			||||||
 | 
					#undef SPI_BASE
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const uint32_t SPI_TX_DMA_CHANNEL = GDMA_CHANNEL_3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO: Check if SPI_PERI_CLK_DCO depends on the chip variant
 | 
				
			||||||
 | 
					static const uint32_t SPI_PERI_CLK_26M = 26000000;
 | 
				
			||||||
 | 
					static const uint32_t SPI_PERI_CLK_DCO = 120000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const uint32_t SPI_BASE = 0x00802700;
 | 
				
			||||||
 | 
					static const uint32_t SPI_DAT = SPI_BASE + 3 * 4;
 | 
				
			||||||
 | 
					static const uint32_t SPI_CONFIG = SPI_BASE + 1 * 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const uint32_t SPI_TX_EN = 1 << 0;
 | 
				
			||||||
 | 
					static const uint32_t CTRL_NSSMD_3 = 1 << 17;
 | 
				
			||||||
 | 
					static const uint32_t SPI_TX_FINISH_EN = 1 << 2;
 | 
				
			||||||
 | 
					static const uint32_t SPI_RX_FINISH_EN = 1 << 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace beken_spi_led_strip {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "beken_spi_led_strip";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct spi_data_t {
 | 
				
			||||||
 | 
					  SemaphoreHandle_t dma_tx_semaphore;
 | 
				
			||||||
 | 
					  volatile bool tx_in_progress;
 | 
				
			||||||
 | 
					  bool first_run;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static spi_data_t *spi_data = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void set_spi_ctrl_register(unsigned long bit, bool val) {
 | 
				
			||||||
 | 
					  uint32_t value = REG_READ(SPI_CTRL);
 | 
				
			||||||
 | 
					  if (val == 0) {
 | 
				
			||||||
 | 
					    value &= ~bit;
 | 
				
			||||||
 | 
					  } else if (val == 1) {
 | 
				
			||||||
 | 
					    value |= bit;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  REG_WRITE(SPI_CTRL, value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void set_spi_config_register(unsigned long bit, bool val) {
 | 
				
			||||||
 | 
					  uint32_t value = REG_READ(SPI_CONFIG);
 | 
				
			||||||
 | 
					  if (val == 0) {
 | 
				
			||||||
 | 
					    value &= ~bit;
 | 
				
			||||||
 | 
					  } else if (val == 1) {
 | 
				
			||||||
 | 
					    value |= bit;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  REG_WRITE(SPI_CONFIG, value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void spi_dma_tx_enable(bool enable) {
 | 
				
			||||||
 | 
					  GDMA_CFG_ST en_cfg;
 | 
				
			||||||
 | 
					  set_spi_config_register(SPI_TX_EN, enable ? 1 : 0);
 | 
				
			||||||
 | 
					  en_cfg.channel = SPI_TX_DMA_CHANNEL;
 | 
				
			||||||
 | 
					  en_cfg.param = enable ? 1 : 0;
 | 
				
			||||||
 | 
					  sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_DMA_ENABLE, &en_cfg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void spi_set_clock(uint32_t max_hz) {
 | 
				
			||||||
 | 
					  int source_clk = 0;
 | 
				
			||||||
 | 
					  int spi_clk = 0;
 | 
				
			||||||
 | 
					  int div = 0;
 | 
				
			||||||
 | 
					  uint32_t param;
 | 
				
			||||||
 | 
					  if (max_hz > 4333000) {
 | 
				
			||||||
 | 
					    if (max_hz > 30000000) {
 | 
				
			||||||
 | 
					      spi_clk = 30000000;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      spi_clk = max_hz;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    sddev_control(ICU_DEV_NAME, CMD_CLK_PWR_DOWN, ¶m);
 | 
				
			||||||
 | 
					    source_clk = SPI_PERI_CLK_DCO;
 | 
				
			||||||
 | 
					    param = PCLK_POSI_SPI;
 | 
				
			||||||
 | 
					    sddev_control(ICU_DEV_NAME, CMD_CONF_PCLK_DCO, ¶m);
 | 
				
			||||||
 | 
					    param = PWD_SPI_CLK_BIT;
 | 
				
			||||||
 | 
					    sddev_control(ICU_DEV_NAME, CMD_CLK_PWR_UP, ¶m);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    spi_clk = max_hz;
 | 
				
			||||||
 | 
					#if CFG_XTAL_FREQUENCE
 | 
				
			||||||
 | 
					    source_clk = CFG_XTAL_FREQUENCE;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    source_clk = SPI_PERI_CLK_26M;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    param = PCLK_POSI_SPI;
 | 
				
			||||||
 | 
					    sddev_control(ICU_DEV_NAME, CMD_CONF_PCLK_26M, ¶m);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  div = ((source_clk >> 1) / spi_clk);
 | 
				
			||||||
 | 
					  if (div < 2) {
 | 
				
			||||||
 | 
					    div = 2;
 | 
				
			||||||
 | 
					  } else if (div >= 255) {
 | 
				
			||||||
 | 
					    div = 255;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  param = REG_READ(SPI_CTRL);
 | 
				
			||||||
 | 
					  param &= ~(SPI_CKR_MASK << SPI_CKR_POSI);
 | 
				
			||||||
 | 
					  param |= (div << SPI_CKR_POSI);
 | 
				
			||||||
 | 
					  REG_WRITE(SPI_CTRL, param);
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "target frequency: %d, actual frequency: %d", max_hz, source_clk / 2 / div);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void spi_dma_tx_finish_callback(unsigned int param) {
 | 
				
			||||||
 | 
					  spi_data->tx_in_progress = false;
 | 
				
			||||||
 | 
					  xSemaphoreGive(spi_data->dma_tx_semaphore);
 | 
				
			||||||
 | 
					  spi_dma_tx_enable(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BekenSPILEDStripLightOutput::setup() {
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "Setting up Beken SPI LED Strip...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  size_t buffer_size = this->get_buffer_size_();
 | 
				
			||||||
 | 
					  size_t dma_buffer_size = (buffer_size * 8) + (2 * 64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
 | 
				
			||||||
 | 
					  this->buf_ = allocator.allocate(buffer_size);
 | 
				
			||||||
 | 
					  if (this->buf_ == nullptr) {
 | 
				
			||||||
 | 
					    ESP_LOGE(TAG, "Cannot allocate LED buffer!");
 | 
				
			||||||
 | 
					    this->mark_failed();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  this->effect_data_ = allocator.allocate(this->num_leds_);
 | 
				
			||||||
 | 
					  if (this->effect_data_ == nullptr) {
 | 
				
			||||||
 | 
					    ESP_LOGE(TAG, "Cannot allocate effect data!");
 | 
				
			||||||
 | 
					    this->mark_failed();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  this->dma_buf_ = allocator.allocate(dma_buffer_size);
 | 
				
			||||||
 | 
					  if (this->dma_buf_ == nullptr) {
 | 
				
			||||||
 | 
					    ESP_LOGE(TAG, "Cannot allocate DMA buffer!");
 | 
				
			||||||
 | 
					    this->mark_failed();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  memset(this->buf_, 0, buffer_size);
 | 
				
			||||||
 | 
					  memset(this->effect_data_, 0, this->num_leds_);
 | 
				
			||||||
 | 
					  memset(this->dma_buf_, 0, dma_buffer_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint32_t value = PCLK_POSI_SPI;
 | 
				
			||||||
 | 
					  sddev_control(ICU_DEV_NAME, CMD_CONF_PCLK_26M, &value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  value = PWD_SPI_CLK_BIT;
 | 
				
			||||||
 | 
					  sddev_control(ICU_DEV_NAME, CMD_CLK_PWR_UP, &value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (spi_data != nullptr) {
 | 
				
			||||||
 | 
					    ESP_LOGE(TAG, "SPI device already initialized!");
 | 
				
			||||||
 | 
					    this->mark_failed();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  spi_data = (spi_data_t *) calloc(1, sizeof(spi_data_t));
 | 
				
			||||||
 | 
					  if (spi_data == nullptr) {
 | 
				
			||||||
 | 
					    ESP_LOGE(TAG, "Cannot allocate spi_data!");
 | 
				
			||||||
 | 
					    this->mark_failed();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  spi_data->dma_tx_semaphore = xSemaphoreCreateBinary();
 | 
				
			||||||
 | 
					  if (spi_data->dma_tx_semaphore == nullptr) {
 | 
				
			||||||
 | 
					    ESP_LOGE(TAG, "TX Semaphore init faild!");
 | 
				
			||||||
 | 
					    this->mark_failed();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  spi_data->first_run = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  set_spi_ctrl_register(MSTEN, 0);
 | 
				
			||||||
 | 
					  set_spi_ctrl_register(BIT_WDTH, 0);
 | 
				
			||||||
 | 
					  spi_set_clock(this->spi_frequency_);
 | 
				
			||||||
 | 
					  set_spi_ctrl_register(CKPOL, 0);
 | 
				
			||||||
 | 
					  set_spi_ctrl_register(CKPHA, 0);
 | 
				
			||||||
 | 
					  set_spi_ctrl_register(MSTEN, 1);
 | 
				
			||||||
 | 
					  set_spi_ctrl_register(SPIEN, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  set_spi_ctrl_register(TXINT_EN, 0);
 | 
				
			||||||
 | 
					  set_spi_ctrl_register(RXINT_EN, 0);
 | 
				
			||||||
 | 
					  set_spi_config_register(SPI_TX_FINISH_EN, 1);
 | 
				
			||||||
 | 
					  set_spi_config_register(SPI_RX_FINISH_EN, 1);
 | 
				
			||||||
 | 
					  set_spi_ctrl_register(RXOVR_EN, 0);
 | 
				
			||||||
 | 
					  set_spi_ctrl_register(TXOVR_EN, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  value = REG_READ(SPI_CTRL);
 | 
				
			||||||
 | 
					  value &= ~CTRL_NSSMD_3;
 | 
				
			||||||
 | 
					  value |= (1 << 17);
 | 
				
			||||||
 | 
					  REG_WRITE(SPI_CTRL, value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  value = GFUNC_MODE_SPI_DMA;
 | 
				
			||||||
 | 
					  sddev_control(GPIO_DEV_NAME, CMD_GPIO_ENABLE_SECOND, &value);
 | 
				
			||||||
 | 
					  set_spi_ctrl_register(SPI_S_CS_UP_INT_EN, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  GDMA_CFG_ST en_cfg;
 | 
				
			||||||
 | 
					  GDMACFG_TPYES_ST init_cfg;
 | 
				
			||||||
 | 
					  memset(&init_cfg, 0, sizeof(GDMACFG_TPYES_ST));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  init_cfg.dstdat_width = 8;
 | 
				
			||||||
 | 
					  init_cfg.srcdat_width = 32;
 | 
				
			||||||
 | 
					  init_cfg.dstptr_incr = 0;
 | 
				
			||||||
 | 
					  init_cfg.srcptr_incr = 1;
 | 
				
			||||||
 | 
					  init_cfg.src_start_addr = this->dma_buf_;
 | 
				
			||||||
 | 
					  init_cfg.dst_start_addr = (void *) SPI_DAT;  // SPI_DMA_REG4_TXFIFO
 | 
				
			||||||
 | 
					  init_cfg.channel = SPI_TX_DMA_CHANNEL;
 | 
				
			||||||
 | 
					  init_cfg.prio = 0;  // 10
 | 
				
			||||||
 | 
					  init_cfg.u.type4.src_loop_start_addr = this->dma_buf_;
 | 
				
			||||||
 | 
					  init_cfg.u.type4.src_loop_end_addr = this->dma_buf_ + dma_buffer_size;
 | 
				
			||||||
 | 
					  init_cfg.half_fin_handler = nullptr;
 | 
				
			||||||
 | 
					  init_cfg.fin_handler = spi_dma_tx_finish_callback;
 | 
				
			||||||
 | 
					  init_cfg.src_module = GDMA_X_SRC_DTCM_RD_REQ;
 | 
				
			||||||
 | 
					  init_cfg.dst_module = GDMA_X_DST_GSPI_TX_REQ;  // GDMA_X_DST_HSSPI_TX_REQ
 | 
				
			||||||
 | 
					  sddev_control(GDMA_DEV_NAME, CMD_GDMA_CFG_TYPE4, (void *) &init_cfg);
 | 
				
			||||||
 | 
					  en_cfg.channel = SPI_TX_DMA_CHANNEL;
 | 
				
			||||||
 | 
					  en_cfg.param = dma_buffer_size;
 | 
				
			||||||
 | 
					  sddev_control(GDMA_DEV_NAME, CMD_GDMA_SET_TRANS_LENGTH, (void *) &en_cfg);
 | 
				
			||||||
 | 
					  en_cfg.channel = SPI_TX_DMA_CHANNEL;
 | 
				
			||||||
 | 
					  en_cfg.param = 0;
 | 
				
			||||||
 | 
					  sddev_control(GDMA_DEV_NAME, CMD_GDMA_CFG_WORK_MODE, (void *) &en_cfg);
 | 
				
			||||||
 | 
					  en_cfg.channel = SPI_TX_DMA_CHANNEL;
 | 
				
			||||||
 | 
					  en_cfg.param = 0;
 | 
				
			||||||
 | 
					  sddev_control(GDMA_DEV_NAME, CMD_GDMA_CFG_SRCADDR_LOOP, &en_cfg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  spi_dma_tx_enable(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  value = REG_READ(SPI_CONFIG);
 | 
				
			||||||
 | 
					  value &= ~(0xFFF << 8);
 | 
				
			||||||
 | 
					  value |= ((dma_buffer_size & 0xFFF) << 8);
 | 
				
			||||||
 | 
					  REG_WRITE(SPI_CONFIG, value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BekenSPILEDStripLightOutput::set_led_params(uint8_t bit0, uint8_t bit1, uint32_t spi_frequency) {
 | 
				
			||||||
 | 
					  this->bit0_ = bit0;
 | 
				
			||||||
 | 
					  this->bit1_ = bit1;
 | 
				
			||||||
 | 
					  this->spi_frequency_ = spi_frequency;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BekenSPILEDStripLightOutput::write_state(light::LightState *state) {
 | 
				
			||||||
 | 
					  // protect from refreshing too often
 | 
				
			||||||
 | 
					  uint32_t now = micros();
 | 
				
			||||||
 | 
					  if (*this->max_refresh_rate_ != 0 && (now - this->last_refresh_) < *this->max_refresh_rate_) {
 | 
				
			||||||
 | 
					    // try again next loop iteration, so that this change won't get lost
 | 
				
			||||||
 | 
					    this->schedule_show();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  this->last_refresh_ = now;
 | 
				
			||||||
 | 
					  this->mark_shown_();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ESP_LOGVV(TAG, "Writing RGB values to bus...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (spi_data == nullptr) {
 | 
				
			||||||
 | 
					    ESP_LOGE(TAG, "SPI not initialized");
 | 
				
			||||||
 | 
					    this->status_set_warning();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!spi_data->first_run && !xSemaphoreTake(spi_data->dma_tx_semaphore, 10 / portTICK_PERIOD_MS)) {
 | 
				
			||||||
 | 
					    ESP_LOGE(TAG, "Timed out waiting for semaphore");
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (spi_data->tx_in_progress) {
 | 
				
			||||||
 | 
					    ESP_LOGE(TAG, "tx_in_progress is set");
 | 
				
			||||||
 | 
					    this->status_set_warning();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  spi_data->tx_in_progress = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  size_t buffer_size = this->get_buffer_size_();
 | 
				
			||||||
 | 
					  size_t size = 0;
 | 
				
			||||||
 | 
					  uint8_t *psrc = this->buf_;
 | 
				
			||||||
 | 
					  uint8_t *pdest = this->dma_buf_ + 64;
 | 
				
			||||||
 | 
					  // The 64 byte padding is a workaround for a SPI DMA bug where the
 | 
				
			||||||
 | 
					  // output doesn't exactly start at the beginning of dma_buf_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while (size < buffer_size) {
 | 
				
			||||||
 | 
					    uint8_t b = *psrc;
 | 
				
			||||||
 | 
					    for (int i = 0; i < 8; i++) {
 | 
				
			||||||
 | 
					      *pdest++ = b & (1 << (7 - i)) ? this->bit1_ : this->bit0_;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    size++;
 | 
				
			||||||
 | 
					    psrc++;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  spi_data->first_run = false;
 | 
				
			||||||
 | 
					  spi_dma_tx_enable(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  this->status_clear_warning();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					light::ESPColorView BekenSPILEDStripLightOutput::get_view_internal(int32_t index) const {
 | 
				
			||||||
 | 
					  int32_t r = 0, g = 0, b = 0;
 | 
				
			||||||
 | 
					  switch (this->rgb_order_) {
 | 
				
			||||||
 | 
					    case ORDER_RGB:
 | 
				
			||||||
 | 
					      r = 0;
 | 
				
			||||||
 | 
					      g = 1;
 | 
				
			||||||
 | 
					      b = 2;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case ORDER_RBG:
 | 
				
			||||||
 | 
					      r = 0;
 | 
				
			||||||
 | 
					      g = 2;
 | 
				
			||||||
 | 
					      b = 1;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case ORDER_GRB:
 | 
				
			||||||
 | 
					      r = 1;
 | 
				
			||||||
 | 
					      g = 0;
 | 
				
			||||||
 | 
					      b = 2;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case ORDER_GBR:
 | 
				
			||||||
 | 
					      r = 2;
 | 
				
			||||||
 | 
					      g = 0;
 | 
				
			||||||
 | 
					      b = 1;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case ORDER_BGR:
 | 
				
			||||||
 | 
					      r = 2;
 | 
				
			||||||
 | 
					      g = 1;
 | 
				
			||||||
 | 
					      b = 0;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case ORDER_BRG:
 | 
				
			||||||
 | 
					      r = 1;
 | 
				
			||||||
 | 
					      g = 2;
 | 
				
			||||||
 | 
					      b = 0;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  uint8_t multiplier = this->is_rgbw_ || this->is_wrgb_ ? 4 : 3;
 | 
				
			||||||
 | 
					  uint8_t white = this->is_wrgb_ ? 0 : 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return {this->buf_ + (index * multiplier) + r + this->is_wrgb_,
 | 
				
			||||||
 | 
					          this->buf_ + (index * multiplier) + g + this->is_wrgb_,
 | 
				
			||||||
 | 
					          this->buf_ + (index * multiplier) + b + this->is_wrgb_,
 | 
				
			||||||
 | 
					          this->is_rgbw_ || this->is_wrgb_ ? this->buf_ + (index * multiplier) + white : nullptr,
 | 
				
			||||||
 | 
					          &this->effect_data_[index],
 | 
				
			||||||
 | 
					          &this->correction_};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BekenSPILEDStripLightOutput::dump_config() {
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "Beken SPI LED Strip:");
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "  Pin: %u", this->pin_);
 | 
				
			||||||
 | 
					  const char *rgb_order;
 | 
				
			||||||
 | 
					  switch (this->rgb_order_) {
 | 
				
			||||||
 | 
					    case ORDER_RGB:
 | 
				
			||||||
 | 
					      rgb_order = "RGB";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case ORDER_RBG:
 | 
				
			||||||
 | 
					      rgb_order = "RBG";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case ORDER_GRB:
 | 
				
			||||||
 | 
					      rgb_order = "GRB";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case ORDER_GBR:
 | 
				
			||||||
 | 
					      rgb_order = "GBR";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case ORDER_BGR:
 | 
				
			||||||
 | 
					      rgb_order = "BGR";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case ORDER_BRG:
 | 
				
			||||||
 | 
					      rgb_order = "BRG";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      rgb_order = "UNKNOWN";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "  RGB Order: %s", rgb_order);
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "  Max refresh rate: %" PRIu32, *this->max_refresh_rate_);
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "  Number of LEDs: %u", this->num_leds_);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float BekenSPILEDStripLightOutput::get_setup_priority() const { return setup_priority::HARDWARE; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace beken_spi_led_strip
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  // USE_BK72XX
 | 
				
			||||||
							
								
								
									
										85
									
								
								esphome/components/beken_spi_led_strip/led_strip.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								esphome/components/beken_spi_led_strip/led_strip.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_BK72XX
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "esphome/components/light/addressable_light.h"
 | 
				
			||||||
 | 
					#include "esphome/components/light/light_output.h"
 | 
				
			||||||
 | 
					#include "esphome/core/color.h"
 | 
				
			||||||
 | 
					#include "esphome/core/component.h"
 | 
				
			||||||
 | 
					#include "esphome/core/helpers.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace beken_spi_led_strip {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum RGBOrder : uint8_t {
 | 
				
			||||||
 | 
					  ORDER_RGB,
 | 
				
			||||||
 | 
					  ORDER_RBG,
 | 
				
			||||||
 | 
					  ORDER_GRB,
 | 
				
			||||||
 | 
					  ORDER_GBR,
 | 
				
			||||||
 | 
					  ORDER_BGR,
 | 
				
			||||||
 | 
					  ORDER_BRG,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BekenSPILEDStripLightOutput : public light::AddressableLight {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  void setup() override;
 | 
				
			||||||
 | 
					  void write_state(light::LightState *state) override;
 | 
				
			||||||
 | 
					  float get_setup_priority() const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int32_t size() const override { return this->num_leds_; }
 | 
				
			||||||
 | 
					  light::LightTraits get_traits() override {
 | 
				
			||||||
 | 
					    auto traits = light::LightTraits();
 | 
				
			||||||
 | 
					    if (this->is_rgbw_ || this->is_wrgb_) {
 | 
				
			||||||
 | 
					      traits.set_supported_color_modes({light::ColorMode::RGB_WHITE, light::ColorMode::WHITE});
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      traits.set_supported_color_modes({light::ColorMode::RGB});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return traits;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void set_pin(uint8_t pin) { this->pin_ = pin; }
 | 
				
			||||||
 | 
					  void set_num_leds(uint16_t num_leds) { this->num_leds_ = num_leds; }
 | 
				
			||||||
 | 
					  void set_is_rgbw(bool is_rgbw) { this->is_rgbw_ = is_rgbw; }
 | 
				
			||||||
 | 
					  void set_is_wrgb(bool is_wrgb) { this->is_wrgb_ = is_wrgb; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Set a maximum refresh rate in µs as some lights do not like being updated too often.
 | 
				
			||||||
 | 
					  void set_max_refresh_rate(uint32_t interval_us) { this->max_refresh_rate_ = interval_us; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void set_led_params(uint8_t bit0, uint8_t bit1, uint32_t spi_frequency);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void set_rgb_order(RGBOrder rgb_order) { this->rgb_order_ = rgb_order; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void clear_effect_data() override {
 | 
				
			||||||
 | 
					    for (int i = 0; i < this->size(); i++)
 | 
				
			||||||
 | 
					      this->effect_data_[i] = 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void dump_config() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 protected:
 | 
				
			||||||
 | 
					  light::ESPColorView get_view_internal(int32_t index) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  size_t get_buffer_size_() const { return this->num_leds_ * (this->is_rgbw_ || this->is_wrgb_ ? 4 : 3); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint8_t *buf_{nullptr};
 | 
				
			||||||
 | 
					  uint8_t *effect_data_{nullptr};
 | 
				
			||||||
 | 
					  uint8_t *dma_buf_{nullptr};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint8_t pin_;
 | 
				
			||||||
 | 
					  uint16_t num_leds_;
 | 
				
			||||||
 | 
					  bool is_rgbw_;
 | 
				
			||||||
 | 
					  bool is_wrgb_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint32_t spi_frequency_{6666666};
 | 
				
			||||||
 | 
					  uint8_t bit0_{0xE0};
 | 
				
			||||||
 | 
					  uint8_t bit1_{0xFC};
 | 
				
			||||||
 | 
					  RGBOrder rgb_order_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint32_t last_refresh_{0};
 | 
				
			||||||
 | 
					  optional<uint32_t> max_refresh_rate_{};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace beken_spi_led_strip
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  // USE_BK72XX
 | 
				
			||||||
							
								
								
									
										134
									
								
								esphome/components/beken_spi_led_strip/light.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								esphome/components/beken_spi_led_strip/light.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,134 @@
 | 
				
			|||||||
 | 
					from dataclasses import dataclass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome import pins
 | 
				
			||||||
 | 
					from esphome.components import libretiny, light
 | 
				
			||||||
 | 
					from esphome.const import (
 | 
				
			||||||
 | 
					    CONF_CHIPSET,
 | 
				
			||||||
 | 
					    CONF_IS_RGBW,
 | 
				
			||||||
 | 
					    CONF_MAX_REFRESH_RATE,
 | 
				
			||||||
 | 
					    CONF_NUM_LEDS,
 | 
				
			||||||
 | 
					    CONF_OUTPUT_ID,
 | 
				
			||||||
 | 
					    CONF_PIN,
 | 
				
			||||||
 | 
					    CONF_RGB_ORDER,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CODEOWNERS = ["@Mat931"]
 | 
				
			||||||
 | 
					DEPENDENCIES = ["libretiny"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					beken_spi_led_strip_ns = cg.esphome_ns.namespace("beken_spi_led_strip")
 | 
				
			||||||
 | 
					BekenSPILEDStripLightOutput = beken_spi_led_strip_ns.class_(
 | 
				
			||||||
 | 
					    "BekenSPILEDStripLightOutput", light.AddressableLight
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RGBOrder = beken_spi_led_strip_ns.enum("RGBOrder")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RGB_ORDERS = {
 | 
				
			||||||
 | 
					    "RGB": RGBOrder.ORDER_RGB,
 | 
				
			||||||
 | 
					    "RBG": RGBOrder.ORDER_RBG,
 | 
				
			||||||
 | 
					    "GRB": RGBOrder.ORDER_GRB,
 | 
				
			||||||
 | 
					    "GBR": RGBOrder.ORDER_GBR,
 | 
				
			||||||
 | 
					    "BGR": RGBOrder.ORDER_BGR,
 | 
				
			||||||
 | 
					    "BRG": RGBOrder.ORDER_BRG,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@dataclass
 | 
				
			||||||
 | 
					class LEDStripTimings:
 | 
				
			||||||
 | 
					    bit0: int
 | 
				
			||||||
 | 
					    bit1: int
 | 
				
			||||||
 | 
					    spi_frequency: int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CHIPSETS = {
 | 
				
			||||||
 | 
					    "WS2812": LEDStripTimings(
 | 
				
			||||||
 | 
					        0b11100000, 0b11111100, 6666666
 | 
				
			||||||
 | 
					    ),  # Clock divider: 9, Bit time: 1350ns
 | 
				
			||||||
 | 
					    "SK6812": LEDStripTimings(
 | 
				
			||||||
 | 
					        0b11000000, 0b11111000, 7500000
 | 
				
			||||||
 | 
					    ),  # Clock divider: 8, Bit time: 1200ns
 | 
				
			||||||
 | 
					    "APA106": LEDStripTimings(
 | 
				
			||||||
 | 
					        0b11000000, 0b11111110, 5454545
 | 
				
			||||||
 | 
					    ),  # Clock divider: 11, Bit time: 1650ns
 | 
				
			||||||
 | 
					    "SM16703": LEDStripTimings(
 | 
				
			||||||
 | 
					        0b11000000, 0b11111110, 7500000
 | 
				
			||||||
 | 
					    ),  # Clock divider: 8, Bit time: 1200ns
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONF_IS_WRGB = "is_wrgb"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SUPPORTED_PINS = {
 | 
				
			||||||
 | 
					    libretiny.const.FAMILY_BK7231N: [16],
 | 
				
			||||||
 | 
					    libretiny.const.FAMILY_BK7231T: [16],
 | 
				
			||||||
 | 
					    libretiny.const.FAMILY_BK7251: [16],
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _validate_pin(value):
 | 
				
			||||||
 | 
					    family = libretiny.get_libretiny_family()
 | 
				
			||||||
 | 
					    if family not in SUPPORTED_PINS:
 | 
				
			||||||
 | 
					        raise cv.Invalid(f"Chip family {family} is not supported.")
 | 
				
			||||||
 | 
					    if value not in SUPPORTED_PINS[family]:
 | 
				
			||||||
 | 
					        supported_pin_info = ", ".join(f"{x}" for x in SUPPORTED_PINS[family])
 | 
				
			||||||
 | 
					        raise cv.Invalid(
 | 
				
			||||||
 | 
					            f"Pin {value} is not supported on the {family}. Supported pins: {supported_pin_info}"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _validate_num_leds(value):
 | 
				
			||||||
 | 
					    max_num_leds = 165  # 170
 | 
				
			||||||
 | 
					    if value[CONF_IS_RGBW] or value[CONF_IS_WRGB]:
 | 
				
			||||||
 | 
					        max_num_leds = 123  # 127
 | 
				
			||||||
 | 
					    if value[CONF_NUM_LEDS] > max_num_leds:
 | 
				
			||||||
 | 
					        raise cv.Invalid(
 | 
				
			||||||
 | 
					            f"The maximum number of LEDs for this configuration is {max_num_leds}.",
 | 
				
			||||||
 | 
					            path=CONF_NUM_LEDS,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONFIG_SCHEMA = cv.All(
 | 
				
			||||||
 | 
					    light.ADDRESSABLE_LIGHT_SCHEMA.extend(
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(BekenSPILEDStripLightOutput),
 | 
				
			||||||
 | 
					            cv.Required(CONF_PIN): cv.All(
 | 
				
			||||||
 | 
					                pins.internal_gpio_output_pin_number, _validate_pin
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Required(CONF_NUM_LEDS): cv.positive_not_null_int,
 | 
				
			||||||
 | 
					            cv.Required(CONF_RGB_ORDER): cv.enum(RGB_ORDERS, upper=True),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds,
 | 
				
			||||||
 | 
					            cv.Required(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_IS_RGBW, default=False): cv.boolean,
 | 
				
			||||||
 | 
					            cv.Optional(CONF_IS_WRGB, default=False): cv.boolean,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    _validate_num_leds,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def to_code(config):
 | 
				
			||||||
 | 
					    var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
 | 
				
			||||||
 | 
					    await light.register_light(var, config)
 | 
				
			||||||
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cg.add(var.set_num_leds(config[CONF_NUM_LEDS]))
 | 
				
			||||||
 | 
					    cg.add(var.set_pin(config[CONF_PIN]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if CONF_MAX_REFRESH_RATE in config:
 | 
				
			||||||
 | 
					        cg.add(var.set_max_refresh_rate(config[CONF_MAX_REFRESH_RATE]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    chipset = CHIPSETS[config[CONF_CHIPSET]]
 | 
				
			||||||
 | 
					    cg.add(
 | 
				
			||||||
 | 
					        var.set_led_params(
 | 
				
			||||||
 | 
					            chipset.bit0,
 | 
				
			||||||
 | 
					            chipset.bit1,
 | 
				
			||||||
 | 
					            chipset.spi_frequency,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cg.add(var.set_rgb_order(config[CONF_RGB_ORDER]))
 | 
				
			||||||
 | 
					    cg.add(var.set_is_rgbw(config[CONF_IS_RGBW]))
 | 
				
			||||||
 | 
					    cg.add(var.set_is_wrgb(config[CONF_IS_WRGB]))
 | 
				
			||||||
@@ -4,7 +4,7 @@ from esphome.cpp_generator import MockObjClass
 | 
				
			|||||||
from esphome.cpp_helpers import setup_entity
 | 
					from esphome.cpp_helpers import setup_entity
 | 
				
			||||||
from esphome import automation, core
 | 
					from esphome import automation, core
 | 
				
			||||||
from esphome.automation import Condition, maybe_simple_id
 | 
					from esphome.automation import Condition, maybe_simple_id
 | 
				
			||||||
from esphome.components import mqtt
 | 
					from esphome.components import mqtt, web_server
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_DELAY,
 | 
					    CONF_DELAY,
 | 
				
			||||||
    CONF_DEVICE_CLASS,
 | 
					    CONF_DEVICE_CLASS,
 | 
				
			||||||
@@ -27,6 +27,7 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_TIMING,
 | 
					    CONF_TIMING,
 | 
				
			||||||
    CONF_TRIGGER_ID,
 | 
					    CONF_TRIGGER_ID,
 | 
				
			||||||
    CONF_MQTT_ID,
 | 
					    CONF_MQTT_ID,
 | 
				
			||||||
 | 
					    CONF_WEB_SERVER_ID,
 | 
				
			||||||
    DEVICE_CLASS_BATTERY,
 | 
					    DEVICE_CLASS_BATTERY,
 | 
				
			||||||
    DEVICE_CLASS_BATTERY_CHARGING,
 | 
					    DEVICE_CLASS_BATTERY_CHARGING,
 | 
				
			||||||
    DEVICE_CLASS_CARBON_MONOXIDE,
 | 
					    DEVICE_CLASS_CARBON_MONOXIDE,
 | 
				
			||||||
@@ -385,70 +386,76 @@ def validate_click_timing(value):
 | 
				
			|||||||
    return value
 | 
					    return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BINARY_SENSOR_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMPONENT_SCHEMA).extend(
 | 
					BINARY_SENSOR_SCHEMA = (
 | 
				
			||||||
    {
 | 
					    cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
 | 
				
			||||||
        cv.GenerateID(): cv.declare_id(BinarySensor),
 | 
					    .extend(cv.MQTT_COMPONENT_SCHEMA)
 | 
				
			||||||
        cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(
 | 
					    .extend(
 | 
				
			||||||
            mqtt.MQTTBinarySensorComponent
 | 
					        {
 | 
				
			||||||
        ),
 | 
					            cv.GenerateID(): cv.declare_id(BinarySensor),
 | 
				
			||||||
        cv.Optional(CONF_PUBLISH_INITIAL_STATE): cv.boolean,
 | 
					            cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(
 | 
				
			||||||
        cv.Optional(CONF_DEVICE_CLASS): validate_device_class,
 | 
					                mqtt.MQTTBinarySensorComponent
 | 
				
			||||||
        cv.Optional(CONF_FILTERS): validate_filters,
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_ON_PRESS): automation.validate_automation(
 | 
					            cv.Optional(CONF_PUBLISH_INITIAL_STATE): cv.boolean,
 | 
				
			||||||
            {
 | 
					            cv.Optional(CONF_DEVICE_CLASS): validate_device_class,
 | 
				
			||||||
                cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PressTrigger),
 | 
					            cv.Optional(CONF_FILTERS): validate_filters,
 | 
				
			||||||
            }
 | 
					            cv.Optional(CONF_ON_PRESS): automation.validate_automation(
 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        cv.Optional(CONF_ON_RELEASE): automation.validate_automation(
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ReleaseTrigger),
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        cv.Optional(CONF_ON_CLICK): cv.All(
 | 
					 | 
				
			||||||
            automation.validate_automation(
 | 
					 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClickTrigger),
 | 
					                    cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PressTrigger),
 | 
				
			||||||
                    cv.Optional(
 | 
					 | 
				
			||||||
                        CONF_MIN_LENGTH, default="50ms"
 | 
					 | 
				
			||||||
                    ): cv.positive_time_period_milliseconds,
 | 
					 | 
				
			||||||
                    cv.Optional(
 | 
					 | 
				
			||||||
                        CONF_MAX_LENGTH, default="350ms"
 | 
					 | 
				
			||||||
                    ): cv.positive_time_period_milliseconds,
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            validate_click_timing,
 | 
					            cv.Optional(CONF_ON_RELEASE): automation.validate_automation(
 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        cv.Optional(CONF_ON_DOUBLE_CLICK): cv.All(
 | 
					 | 
				
			||||||
            automation.validate_automation(
 | 
					 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DoubleClickTrigger),
 | 
					                    cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ReleaseTrigger),
 | 
				
			||||||
                    cv.Optional(
 | 
					 | 
				
			||||||
                        CONF_MIN_LENGTH, default="50ms"
 | 
					 | 
				
			||||||
                    ): cv.positive_time_period_milliseconds,
 | 
					 | 
				
			||||||
                    cv.Optional(
 | 
					 | 
				
			||||||
                        CONF_MAX_LENGTH, default="350ms"
 | 
					 | 
				
			||||||
                    ): cv.positive_time_period_milliseconds,
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            validate_click_timing,
 | 
					            cv.Optional(CONF_ON_CLICK): cv.All(
 | 
				
			||||||
        ),
 | 
					                automation.validate_automation(
 | 
				
			||||||
        cv.Optional(CONF_ON_MULTI_CLICK): automation.validate_automation(
 | 
					                    {
 | 
				
			||||||
            {
 | 
					                        cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ClickTrigger),
 | 
				
			||||||
                cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(MultiClickTrigger),
 | 
					                        cv.Optional(
 | 
				
			||||||
                cv.Required(CONF_TIMING): cv.All(
 | 
					                            CONF_MIN_LENGTH, default="50ms"
 | 
				
			||||||
                    [parse_multi_click_timing_str], validate_multi_click_timing
 | 
					                        ): cv.positive_time_period_milliseconds,
 | 
				
			||||||
 | 
					                        cv.Optional(
 | 
				
			||||||
 | 
					                            CONF_MAX_LENGTH, default="350ms"
 | 
				
			||||||
 | 
					                        ): cv.positive_time_period_milliseconds,
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                cv.Optional(
 | 
					                validate_click_timing,
 | 
				
			||||||
                    CONF_INVALID_COOLDOWN, default="1s"
 | 
					            ),
 | 
				
			||||||
                ): cv.positive_time_period_milliseconds,
 | 
					            cv.Optional(CONF_ON_DOUBLE_CLICK): cv.All(
 | 
				
			||||||
            }
 | 
					                automation.validate_automation(
 | 
				
			||||||
        ),
 | 
					                    {
 | 
				
			||||||
        cv.Optional(CONF_ON_STATE): automation.validate_automation(
 | 
					                        cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
 | 
				
			||||||
            {
 | 
					                            DoubleClickTrigger
 | 
				
			||||||
                cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger),
 | 
					                        ),
 | 
				
			||||||
            }
 | 
					                        cv.Optional(
 | 
				
			||||||
        ),
 | 
					                            CONF_MIN_LENGTH, default="50ms"
 | 
				
			||||||
    }
 | 
					                        ): cv.positive_time_period_milliseconds,
 | 
				
			||||||
 | 
					                        cv.Optional(
 | 
				
			||||||
 | 
					                            CONF_MAX_LENGTH, default="350ms"
 | 
				
			||||||
 | 
					                        ): cv.positive_time_period_milliseconds,
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                validate_click_timing,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_ON_MULTI_CLICK): automation.validate_automation(
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(MultiClickTrigger),
 | 
				
			||||||
 | 
					                    cv.Required(CONF_TIMING): cv.All(
 | 
				
			||||||
 | 
					                        [parse_multi_click_timing_str], validate_multi_click_timing
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                    cv.Optional(
 | 
				
			||||||
 | 
					                        CONF_INVALID_COOLDOWN, default="1s"
 | 
				
			||||||
 | 
					                    ): cv.positive_time_period_milliseconds,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_ON_STATE): automation.validate_automation(
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger),
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_UNDEF = object()
 | 
					_UNDEF = object()
 | 
				
			||||||
@@ -536,6 +543,10 @@ async def setup_binary_sensor_core_(var, config):
 | 
				
			|||||||
        mqtt_ = cg.new_Pvariable(mqtt_id, var)
 | 
					        mqtt_ = cg.new_Pvariable(mqtt_id, var)
 | 
				
			||||||
        await mqtt.register_mqtt_component(mqtt_, config)
 | 
					        await mqtt.register_mqtt_component(mqtt_, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
 | 
				
			||||||
 | 
					        web_server_ = await cg.get_variable(webserver_id)
 | 
				
			||||||
 | 
					        web_server.add_entity_to_sorting_list(web_server_, var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def register_binary_sensor(var, config):
 | 
					async def register_binary_sensor(var, config):
 | 
				
			||||||
    if not CORE.has_id(config[CONF_ID]):
 | 
					    if not CORE.has_id(config[CONF_ID]):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -98,6 +98,11 @@ void binary_sensor::MultiClickTrigger::schedule_is_not_valid_(uint32_t max_lengt
 | 
				
			|||||||
    this->schedule_cooldown_();
 | 
					    this->schedule_cooldown_();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					void binary_sensor::MultiClickTrigger::cancel() {
 | 
				
			||||||
 | 
					  ESP_LOGV(TAG, "Multi Click: Sequence explicitly cancelled.");
 | 
				
			||||||
 | 
					  this->is_valid_ = false;
 | 
				
			||||||
 | 
					  this->schedule_cooldown_();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
void binary_sensor::MultiClickTrigger::trigger_() {
 | 
					void binary_sensor::MultiClickTrigger::trigger_() {
 | 
				
			||||||
  ESP_LOGV(TAG, "Multi Click: Hooray, multi click is valid. Triggering!");
 | 
					  ESP_LOGV(TAG, "Multi Click: Hooray, multi click is valid. Triggering!");
 | 
				
			||||||
  this->at_index_.reset();
 | 
					  this->at_index_.reset();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -105,6 +105,8 @@ class MultiClickTrigger : public Trigger<>, public Component {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  void set_invalid_cooldown(uint32_t invalid_cooldown) { this->invalid_cooldown_ = invalid_cooldown; }
 | 
					  void set_invalid_cooldown(uint32_t invalid_cooldown) { this->invalid_cooldown_ = invalid_cooldown; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void cancel();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
  void on_state_(bool state);
 | 
					  void on_state_(bool state);
 | 
				
			||||||
  void schedule_cooldown_();
 | 
					  void schedule_cooldown_();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,16 +6,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ARDUINO
 | 
					 | 
				
			||||||
#include "mbedtls/aes.h"
 | 
					 | 
				
			||||||
#include "mbedtls/base64.h"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_ESP_IDF
 | 
					 | 
				
			||||||
#define MBEDTLS_AES_ALT
 | 
					 | 
				
			||||||
#include <aes_alt.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace ble_presence {
 | 
					namespace ble_presence {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -72,7 +62,7 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff,
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      case MATCH_BY_IRK:
 | 
					      case MATCH_BY_IRK:
 | 
				
			||||||
        if (resolve_irk_(device.address_uint64(), this->irk_)) {
 | 
					        if (device.resolve_irk(this->irk_)) {
 | 
				
			||||||
          this->set_found_(true);
 | 
					          this->set_found_(true);
 | 
				
			||||||
          return true;
 | 
					          return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -142,43 +132,6 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff,
 | 
				
			|||||||
  bool check_ibeacon_minor_{false};
 | 
					  bool check_ibeacon_minor_{false};
 | 
				
			||||||
  bool check_minimum_rssi_{false};
 | 
					  bool check_minimum_rssi_{false};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool resolve_irk_(uint64_t addr64, const uint8_t *irk) {
 | 
					 | 
				
			||||||
    uint8_t ecb_key[16];
 | 
					 | 
				
			||||||
    uint8_t ecb_plaintext[16];
 | 
					 | 
				
			||||||
    uint8_t ecb_ciphertext[16];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    memcpy(&ecb_key, irk, 16);
 | 
					 | 
				
			||||||
    memset(&ecb_plaintext, 0, 16);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ecb_plaintext[13] = (addr64 >> 40) & 0xff;
 | 
					 | 
				
			||||||
    ecb_plaintext[14] = (addr64 >> 32) & 0xff;
 | 
					 | 
				
			||||||
    ecb_plaintext[15] = (addr64 >> 24) & 0xff;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mbedtls_aes_context ctx = {0, 0, {0}};
 | 
					 | 
				
			||||||
    mbedtls_aes_init(&ctx);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (mbedtls_aes_setkey_enc(&ctx, ecb_key, 128) != 0) {
 | 
					 | 
				
			||||||
      mbedtls_aes_free(&ctx);
 | 
					 | 
				
			||||||
      return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (mbedtls_aes_crypt_ecb(&ctx,
 | 
					 | 
				
			||||||
#ifdef USE_ARDUINO
 | 
					 | 
				
			||||||
                              MBEDTLS_AES_ENCRYPT,
 | 
					 | 
				
			||||||
#elif defined(USE_ESP_IDF)
 | 
					 | 
				
			||||||
                              ESP_AES_ENCRYPT,
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
                              ecb_plaintext, ecb_ciphertext) != 0) {
 | 
					 | 
				
			||||||
      mbedtls_aes_free(&ctx);
 | 
					 | 
				
			||||||
      return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mbedtls_aes_free(&ctx);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return ecb_ciphertext[15] == (addr64 & 0xff) && ecb_ciphertext[14] == ((addr64 >> 8) & 0xff) &&
 | 
					 | 
				
			||||||
           ecb_ciphertext[13] == ((addr64 >> 16) & 0xff);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  bool found_{false};
 | 
					  bool found_{false};
 | 
				
			||||||
  uint32_t last_seen_{};
 | 
					  uint32_t last_seen_{};
 | 
				
			||||||
  uint32_t timeout_{};
 | 
					  uint32_t timeout_{};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,10 @@ class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDevi
 | 
				
			|||||||
    this->match_by_ = MATCH_BY_MAC_ADDRESS;
 | 
					    this->match_by_ = MATCH_BY_MAC_ADDRESS;
 | 
				
			||||||
    this->address_ = address;
 | 
					    this->address_ = address;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  void set_irk(uint8_t *irk) {
 | 
				
			||||||
 | 
					    this->match_by_ = MATCH_BY_IRK;
 | 
				
			||||||
 | 
					    this->irk_ = irk;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  void set_service_uuid16(uint16_t uuid) {
 | 
					  void set_service_uuid16(uint16_t uuid) {
 | 
				
			||||||
    this->match_by_ = MATCH_BY_SERVICE_UUID;
 | 
					    this->match_by_ = MATCH_BY_SERVICE_UUID;
 | 
				
			||||||
    this->uuid_ = esp32_ble_tracker::ESPBTUUID::from_uint16(uuid);
 | 
					    this->uuid_ = esp32_ble_tracker::ESPBTUUID::from_uint16(uuid);
 | 
				
			||||||
@@ -53,6 +57,13 @@ class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDevi
 | 
				
			|||||||
          return true;
 | 
					          return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					      case MATCH_BY_IRK:
 | 
				
			||||||
 | 
					        if (device.resolve_irk(this->irk_)) {
 | 
				
			||||||
 | 
					          this->publish_state(device.get_rssi());
 | 
				
			||||||
 | 
					          this->found_ = true;
 | 
				
			||||||
 | 
					          return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
      case MATCH_BY_SERVICE_UUID:
 | 
					      case MATCH_BY_SERVICE_UUID:
 | 
				
			||||||
        for (auto uuid : device.get_service_uuids()) {
 | 
					        for (auto uuid : device.get_service_uuids()) {
 | 
				
			||||||
          if (this->uuid_ == uuid) {
 | 
					          if (this->uuid_ == uuid) {
 | 
				
			||||||
@@ -91,12 +102,13 @@ class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDevi
 | 
				
			|||||||
  float get_setup_priority() const override { return setup_priority::DATA; }
 | 
					  float get_setup_priority() const override { return setup_priority::DATA; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
  enum MatchType { MATCH_BY_MAC_ADDRESS, MATCH_BY_SERVICE_UUID, MATCH_BY_IBEACON_UUID };
 | 
					  enum MatchType { MATCH_BY_MAC_ADDRESS, MATCH_BY_IRK, MATCH_BY_SERVICE_UUID, MATCH_BY_IBEACON_UUID };
 | 
				
			||||||
  MatchType match_by_;
 | 
					  MatchType match_by_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool found_{false};
 | 
					  bool found_{false};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  uint64_t address_;
 | 
					  uint64_t address_;
 | 
				
			||||||
 | 
					  uint8_t *irk_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  esp32_ble_tracker::ESPBTUUID uuid_;
 | 
					  esp32_ble_tracker::ESPBTUUID uuid_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,8 @@ from esphome.const import (
 | 
				
			|||||||
    UNIT_DECIBEL_MILLIWATT,
 | 
					    UNIT_DECIBEL_MILLIWATT,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONF_IRK = "irk"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEPENDENCIES = ["esp32_ble_tracker"]
 | 
					DEPENDENCIES = ["esp32_ble_tracker"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ble_rssi_ns = cg.esphome_ns.namespace("ble_rssi")
 | 
					ble_rssi_ns = cg.esphome_ns.namespace("ble_rssi")
 | 
				
			||||||
@@ -39,6 +41,7 @@ CONFIG_SCHEMA = cv.All(
 | 
				
			|||||||
    .extend(
 | 
					    .extend(
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            cv.Optional(CONF_MAC_ADDRESS): cv.mac_address,
 | 
					            cv.Optional(CONF_MAC_ADDRESS): cv.mac_address,
 | 
				
			||||||
 | 
					            cv.Optional(CONF_IRK): cv.uuid,
 | 
				
			||||||
            cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
 | 
					            cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
 | 
				
			||||||
            cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t,
 | 
					            cv.Optional(CONF_IBEACON_MAJOR): cv.uint16_t,
 | 
				
			||||||
            cv.Optional(CONF_IBEACON_MINOR): cv.uint16_t,
 | 
					            cv.Optional(CONF_IBEACON_MINOR): cv.uint16_t,
 | 
				
			||||||
@@ -47,7 +50,9 @@ CONFIG_SCHEMA = cv.All(
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
    .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
 | 
					    .extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA)
 | 
				
			||||||
    .extend(cv.COMPONENT_SCHEMA),
 | 
					    .extend(cv.COMPONENT_SCHEMA),
 | 
				
			||||||
    cv.has_exactly_one_key(CONF_MAC_ADDRESS, CONF_SERVICE_UUID, CONF_IBEACON_UUID),
 | 
					    cv.has_exactly_one_key(
 | 
				
			||||||
 | 
					        CONF_MAC_ADDRESS, CONF_IRK, CONF_SERVICE_UUID, CONF_IBEACON_UUID
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
    _validate,
 | 
					    _validate,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -60,6 +65,10 @@ async def to_code(config):
 | 
				
			|||||||
    if mac_address := config.get(CONF_MAC_ADDRESS):
 | 
					    if mac_address := config.get(CONF_MAC_ADDRESS):
 | 
				
			||||||
        cg.add(var.set_address(mac_address.as_hex))
 | 
					        cg.add(var.set_address(mac_address.as_hex))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if irk := config.get(CONF_IRK):
 | 
				
			||||||
 | 
					        irk = esp32_ble_tracker.as_hex_array(str(irk))
 | 
				
			||||||
 | 
					        cg.add(var.set_irk(irk))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if service_uuid := config.get(CONF_SERVICE_UUID):
 | 
					    if service_uuid := config.get(CONF_SERVICE_UUID):
 | 
				
			||||||
        if len(service_uuid) == len(esp32_ble_tracker.bt_uuid16_format):
 | 
					        if len(service_uuid) == len(esp32_ble_tracker.bt_uuid16_format):
 | 
				
			||||||
            cg.add(var.set_service_uuid16(esp32_ble_tracker.as_hex(service_uuid)))
 | 
					            cg.add(var.set_service_uuid16(esp32_ble_tracker.as_hex(service_uuid)))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ import esphome.codegen as cg
 | 
				
			|||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome import automation
 | 
					from esphome import automation
 | 
				
			||||||
from esphome.automation import maybe_simple_id
 | 
					from esphome.automation import maybe_simple_id
 | 
				
			||||||
from esphome.components import mqtt
 | 
					from esphome.components import mqtt, web_server
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_DEVICE_CLASS,
 | 
					    CONF_DEVICE_CLASS,
 | 
				
			||||||
    CONF_ENTITY_CATEGORY,
 | 
					    CONF_ENTITY_CATEGORY,
 | 
				
			||||||
@@ -11,6 +11,7 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_ON_PRESS,
 | 
					    CONF_ON_PRESS,
 | 
				
			||||||
    CONF_TRIGGER_ID,
 | 
					    CONF_TRIGGER_ID,
 | 
				
			||||||
    CONF_MQTT_ID,
 | 
					    CONF_MQTT_ID,
 | 
				
			||||||
 | 
					    CONF_WEB_SERVER_ID,
 | 
				
			||||||
    DEVICE_CLASS_EMPTY,
 | 
					    DEVICE_CLASS_EMPTY,
 | 
				
			||||||
    DEVICE_CLASS_IDENTIFY,
 | 
					    DEVICE_CLASS_IDENTIFY,
 | 
				
			||||||
    DEVICE_CLASS_RESTART,
 | 
					    DEVICE_CLASS_RESTART,
 | 
				
			||||||
@@ -43,16 +44,20 @@ ButtonPressTrigger = button_ns.class_(
 | 
				
			|||||||
validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
 | 
					validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BUTTON_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
 | 
					BUTTON_SCHEMA = (
 | 
				
			||||||
    {
 | 
					    cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
 | 
				
			||||||
        cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTButtonComponent),
 | 
					    .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
 | 
				
			||||||
        cv.Optional(CONF_DEVICE_CLASS): validate_device_class,
 | 
					    .extend(
 | 
				
			||||||
        cv.Optional(CONF_ON_PRESS): automation.validate_automation(
 | 
					        {
 | 
				
			||||||
            {
 | 
					            cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTButtonComponent),
 | 
				
			||||||
                cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ButtonPressTrigger),
 | 
					            cv.Optional(CONF_DEVICE_CLASS): validate_device_class,
 | 
				
			||||||
            }
 | 
					            cv.Optional(CONF_ON_PRESS): automation.validate_automation(
 | 
				
			||||||
        ),
 | 
					                {
 | 
				
			||||||
    }
 | 
					                    cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ButtonPressTrigger),
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_UNDEF = object()
 | 
					_UNDEF = object()
 | 
				
			||||||
@@ -92,6 +97,10 @@ async def setup_button_core_(var, config):
 | 
				
			|||||||
        mqtt_ = cg.new_Pvariable(mqtt_id, var)
 | 
					        mqtt_ = cg.new_Pvariable(mqtt_id, var)
 | 
				
			||||||
        await mqtt.register_mqtt_component(mqtt_, config)
 | 
					        await mqtt.register_mqtt_component(mqtt_, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
 | 
				
			||||||
 | 
					        web_server_ = await cg.get_variable(webserver_id)
 | 
				
			||||||
 | 
					        web_server.add_entity_to_sorting_list(web_server_, var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def register_button(var, config):
 | 
					async def register_button(var, config):
 | 
				
			||||||
    if not CORE.has_id(config[CONF_ID]):
 | 
					    if not CORE.has_id(config[CONF_ID]):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ import esphome.codegen as cg
 | 
				
			|||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.cpp_helpers import setup_entity
 | 
					from esphome.cpp_helpers import setup_entity
 | 
				
			||||||
from esphome import automation
 | 
					from esphome import automation
 | 
				
			||||||
from esphome.components import mqtt
 | 
					from esphome.components import mqtt, web_server
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_ACTION_STATE_TOPIC,
 | 
					    CONF_ACTION_STATE_TOPIC,
 | 
				
			||||||
    CONF_AWAY,
 | 
					    CONF_AWAY,
 | 
				
			||||||
@@ -44,6 +44,7 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_TRIGGER_ID,
 | 
					    CONF_TRIGGER_ID,
 | 
				
			||||||
    CONF_VISUAL,
 | 
					    CONF_VISUAL,
 | 
				
			||||||
    CONF_MQTT_ID,
 | 
					    CONF_MQTT_ID,
 | 
				
			||||||
 | 
					    CONF_WEB_SERVER_ID,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from esphome.core import CORE, coroutine_with_priority
 | 
					from esphome.core import CORE, coroutine_with_priority
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -150,93 +151,97 @@ VISUAL_TEMPERATURE_STEP_SCHEMA = cv.Any(
 | 
				
			|||||||
    ),
 | 
					    ),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CLIMATE_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
 | 
					CLIMATE_SCHEMA = (
 | 
				
			||||||
    {
 | 
					    cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
 | 
				
			||||||
        cv.GenerateID(): cv.declare_id(Climate),
 | 
					    .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
 | 
				
			||||||
        cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTClimateComponent),
 | 
					    .extend(
 | 
				
			||||||
        cv.Optional(CONF_VISUAL, default={}): cv.Schema(
 | 
					        {
 | 
				
			||||||
            {
 | 
					            cv.GenerateID(): cv.declare_id(Climate),
 | 
				
			||||||
                cv.Optional(CONF_MIN_TEMPERATURE): cv.temperature,
 | 
					            cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTClimateComponent),
 | 
				
			||||||
                cv.Optional(CONF_MAX_TEMPERATURE): cv.temperature,
 | 
					            cv.Optional(CONF_VISUAL, default={}): cv.Schema(
 | 
				
			||||||
                cv.Optional(CONF_TEMPERATURE_STEP): VISUAL_TEMPERATURE_STEP_SCHEMA,
 | 
					                {
 | 
				
			||||||
                cv.Optional(CONF_MIN_HUMIDITY): cv.percentage_int,
 | 
					                    cv.Optional(CONF_MIN_TEMPERATURE): cv.temperature,
 | 
				
			||||||
                cv.Optional(CONF_MAX_HUMIDITY): cv.percentage_int,
 | 
					                    cv.Optional(CONF_MAX_TEMPERATURE): cv.temperature,
 | 
				
			||||||
            }
 | 
					                    cv.Optional(CONF_TEMPERATURE_STEP): VISUAL_TEMPERATURE_STEP_SCHEMA,
 | 
				
			||||||
        ),
 | 
					                    cv.Optional(CONF_MIN_HUMIDITY): cv.percentage_int,
 | 
				
			||||||
        cv.Optional(CONF_ACTION_STATE_TOPIC): cv.All(
 | 
					                    cv.Optional(CONF_MAX_HUMIDITY): cv.percentage_int,
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                }
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_AWAY_COMMAND_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_ACTION_STATE_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_AWAY_STATE_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_AWAY_COMMAND_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_CURRENT_TEMPERATURE_STATE_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_AWAY_STATE_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_CURRENT_HUMIDITY_STATE_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_CURRENT_TEMPERATURE_STATE_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_FAN_MODE_COMMAND_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_CURRENT_HUMIDITY_STATE_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_FAN_MODE_STATE_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_FAN_MODE_COMMAND_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_MODE_COMMAND_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_FAN_MODE_STATE_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_MODE_STATE_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_MODE_COMMAND_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_PRESET_COMMAND_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_MODE_STATE_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_PRESET_STATE_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_PRESET_COMMAND_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_SWING_MODE_COMMAND_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_PRESET_STATE_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_SWING_MODE_STATE_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_SWING_MODE_COMMAND_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_TARGET_TEMPERATURE_COMMAND_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_SWING_MODE_STATE_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_TARGET_TEMPERATURE_STATE_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_TARGET_TEMPERATURE_COMMAND_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_TARGET_TEMPERATURE_HIGH_COMMAND_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_TARGET_TEMPERATURE_STATE_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_TARGET_TEMPERATURE_HIGH_STATE_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_TARGET_TEMPERATURE_HIGH_COMMAND_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_TARGET_TEMPERATURE_LOW_COMMAND_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_TARGET_TEMPERATURE_HIGH_STATE_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_TARGET_TEMPERATURE_LOW_STATE_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_TARGET_TEMPERATURE_LOW_COMMAND_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_TARGET_HUMIDITY_COMMAND_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_TARGET_TEMPERATURE_LOW_STATE_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_TARGET_HUMIDITY_STATE_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_TARGET_HUMIDITY_COMMAND_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.publish_topic
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_ON_CONTROL): automation.validate_automation(
 | 
					            cv.Optional(CONF_TARGET_HUMIDITY_STATE_TOPIC): cv.All(
 | 
				
			||||||
            {
 | 
					                cv.requires_component("mqtt"), cv.publish_topic
 | 
				
			||||||
                cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ControlTrigger),
 | 
					            ),
 | 
				
			||||||
            }
 | 
					            cv.Optional(CONF_ON_CONTROL): automation.validate_automation(
 | 
				
			||||||
        ),
 | 
					                {
 | 
				
			||||||
        cv.Optional(CONF_ON_STATE): automation.validate_automation(
 | 
					                    cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(ControlTrigger),
 | 
				
			||||||
            {
 | 
					                }
 | 
				
			||||||
                cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger),
 | 
					            ),
 | 
				
			||||||
            }
 | 
					            cv.Optional(CONF_ON_STATE): automation.validate_automation(
 | 
				
			||||||
        ),
 | 
					                {
 | 
				
			||||||
    }
 | 
					                    cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger),
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -403,6 +408,10 @@ async def setup_climate_core_(var, config):
 | 
				
			|||||||
            trigger, [(ClimateCall.operator("ref"), "x")], conf
 | 
					            trigger, [(ClimateCall.operator("ref"), "x")], conf
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
 | 
				
			||||||
 | 
					        web_server_ = await cg.get_variable(webserver_id)
 | 
				
			||||||
 | 
					        web_server.add_entity_to_sorting_list(web_server_, var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def register_climate(var, config):
 | 
					async def register_climate(var, config):
 | 
				
			||||||
    if not CORE.has_id(config[CONF_ID]):
 | 
					    if not CORE.has_id(config[CONF_ID]):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ import esphome.codegen as cg
 | 
				
			|||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome import automation
 | 
					from esphome import automation
 | 
				
			||||||
from esphome.automation import maybe_simple_id, Condition
 | 
					from esphome.automation import maybe_simple_id, Condition
 | 
				
			||||||
from esphome.components import mqtt
 | 
					from esphome.components import mqtt, web_server
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_ID,
 | 
					    CONF_ID,
 | 
				
			||||||
    CONF_DEVICE_CLASS,
 | 
					    CONF_DEVICE_CLASS,
 | 
				
			||||||
@@ -16,6 +16,7 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_TILT_STATE_TOPIC,
 | 
					    CONF_TILT_STATE_TOPIC,
 | 
				
			||||||
    CONF_STOP,
 | 
					    CONF_STOP,
 | 
				
			||||||
    CONF_MQTT_ID,
 | 
					    CONF_MQTT_ID,
 | 
				
			||||||
 | 
					    CONF_WEB_SERVER_ID,
 | 
				
			||||||
    CONF_TRIGGER_ID,
 | 
					    CONF_TRIGGER_ID,
 | 
				
			||||||
    DEVICE_CLASS_AWNING,
 | 
					    DEVICE_CLASS_AWNING,
 | 
				
			||||||
    DEVICE_CLASS_BLIND,
 | 
					    DEVICE_CLASS_BLIND,
 | 
				
			||||||
@@ -88,34 +89,38 @@ CoverClosedTrigger = cover_ns.class_(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
CONF_ON_CLOSED = "on_closed"
 | 
					CONF_ON_CLOSED = "on_closed"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
COVER_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend(
 | 
					COVER_SCHEMA = (
 | 
				
			||||||
    {
 | 
					    cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
 | 
				
			||||||
        cv.GenerateID(): cv.declare_id(Cover),
 | 
					    .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
 | 
				
			||||||
        cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTCoverComponent),
 | 
					    .extend(
 | 
				
			||||||
        cv.Optional(CONF_DEVICE_CLASS): cv.one_of(*DEVICE_CLASSES, lower=True),
 | 
					        {
 | 
				
			||||||
        cv.Optional(CONF_POSITION_COMMAND_TOPIC): cv.All(
 | 
					            cv.GenerateID(): cv.declare_id(Cover),
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.subscribe_topic
 | 
					            cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTCoverComponent),
 | 
				
			||||||
        ),
 | 
					            cv.Optional(CONF_DEVICE_CLASS): cv.one_of(*DEVICE_CLASSES, lower=True),
 | 
				
			||||||
        cv.Optional(CONF_POSITION_STATE_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_POSITION_COMMAND_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.subscribe_topic
 | 
					                cv.requires_component("mqtt"), cv.subscribe_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_TILT_COMMAND_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_POSITION_STATE_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.subscribe_topic
 | 
					                cv.requires_component("mqtt"), cv.subscribe_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_TILT_STATE_TOPIC): cv.All(
 | 
					            cv.Optional(CONF_TILT_COMMAND_TOPIC): cv.All(
 | 
				
			||||||
            cv.requires_component("mqtt"), cv.subscribe_topic
 | 
					                cv.requires_component("mqtt"), cv.subscribe_topic
 | 
				
			||||||
        ),
 | 
					            ),
 | 
				
			||||||
        cv.Optional(CONF_ON_OPEN): automation.validate_automation(
 | 
					            cv.Optional(CONF_TILT_STATE_TOPIC): cv.All(
 | 
				
			||||||
            {
 | 
					                cv.requires_component("mqtt"), cv.subscribe_topic
 | 
				
			||||||
                cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CoverOpenTrigger),
 | 
					            ),
 | 
				
			||||||
            }
 | 
					            cv.Optional(CONF_ON_OPEN): automation.validate_automation(
 | 
				
			||||||
        ),
 | 
					                {
 | 
				
			||||||
        cv.Optional(CONF_ON_CLOSED): automation.validate_automation(
 | 
					                    cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CoverOpenTrigger),
 | 
				
			||||||
            {
 | 
					                }
 | 
				
			||||||
                cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CoverClosedTrigger),
 | 
					            ),
 | 
				
			||||||
            }
 | 
					            cv.Optional(CONF_ON_CLOSED): automation.validate_automation(
 | 
				
			||||||
        ),
 | 
					                {
 | 
				
			||||||
    }
 | 
					                    cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CoverClosedTrigger),
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -132,6 +137,10 @@ async def setup_cover_core_(var, config):
 | 
				
			|||||||
        trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
 | 
					        trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
 | 
				
			||||||
        await automation.build_automation(trigger, [], conf)
 | 
					        await automation.build_automation(trigger, [], conf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
 | 
				
			||||||
 | 
					        web_server_ = await cg.get_variable(webserver_id)
 | 
				
			||||||
 | 
					        web_server.add_entity_to_sorting_list(web_server_, var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (mqtt_id := config.get(CONF_MQTT_ID)) is not None:
 | 
					    if (mqtt_id := config.get(CONF_MQTT_ID)) is not None:
 | 
				
			||||||
        mqtt_ = cg.new_Pvariable(mqtt_id, var)
 | 
					        mqtt_ = cg.new_Pvariable(mqtt_id, var)
 | 
				
			||||||
        await mqtt.register_mqtt_component(mqtt_, config)
 | 
					        await mqtt.register_mqtt_component(mqtt_, config)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,7 @@ void CST816Touchscreen::continue_setup_() {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
  switch (this->chip_id_) {
 | 
					  switch (this->chip_id_) {
 | 
				
			||||||
    case CST820_CHIP_ID:
 | 
					    case CST820_CHIP_ID:
 | 
				
			||||||
 | 
					    case CST826_CHIP_ID:
 | 
				
			||||||
    case CST716_CHIP_ID:
 | 
					    case CST716_CHIP_ID:
 | 
				
			||||||
    case CST816S_CHIP_ID:
 | 
					    case CST816S_CHIP_ID:
 | 
				
			||||||
    case CST816D_CHIP_ID:
 | 
					    case CST816D_CHIP_ID:
 | 
				
			||||||
@@ -90,6 +91,9 @@ void CST816Touchscreen::dump_config() {
 | 
				
			|||||||
    case CST820_CHIP_ID:
 | 
					    case CST820_CHIP_ID:
 | 
				
			||||||
      name = "CST820";
 | 
					      name = "CST820";
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					    case CST826_CHIP_ID:
 | 
				
			||||||
 | 
					      name = "CST826";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
    case CST816S_CHIP_ID:
 | 
					    case CST816S_CHIP_ID:
 | 
				
			||||||
      name = "CST816S";
 | 
					      name = "CST816S";
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@ static const uint8_t REG_SLEEP = 0xE5;
 | 
				
			|||||||
static const uint8_t REG_IRQ_CTL = 0xFA;
 | 
					static const uint8_t REG_IRQ_CTL = 0xFA;
 | 
				
			||||||
static const uint8_t IRQ_EN_MOTION = 0x70;
 | 
					static const uint8_t IRQ_EN_MOTION = 0x70;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const uint8_t CST826_CHIP_ID = 0x11;
 | 
				
			||||||
static const uint8_t CST820_CHIP_ID = 0xB7;
 | 
					static const uint8_t CST820_CHIP_ID = 0xB7;
 | 
				
			||||||
static const uint8_t CST816S_CHIP_ID = 0xB4;
 | 
					static const uint8_t CST816S_CHIP_ID = 0xB4;
 | 
				
			||||||
static const uint8_t CST816D_CHIP_ID = 0xB6;
 | 
					static const uint8_t CST816D_CHIP_ID = 0xB6;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
#include "ct_clamp_sensor.h"
 | 
					#include "ct_clamp_sensor.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "esphome/core/log.h"
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					#include <cinttypes>
 | 
				
			||||||
#include <cmath>
 | 
					#include <cmath>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
@@ -37,8 +38,8 @@ void CTClampSensor::update() {
 | 
				
			|||||||
    float rms_ac = 0;
 | 
					    float rms_ac = 0;
 | 
				
			||||||
    if (rms_ac_squared > 0)
 | 
					    if (rms_ac_squared > 0)
 | 
				
			||||||
      rms_ac = std::sqrt(rms_ac_squared);
 | 
					      rms_ac = std::sqrt(rms_ac_squared);
 | 
				
			||||||
    ESP_LOGD(TAG, "'%s' - Raw AC Value: %.3fA after %d different samples (%d SPS)", this->name_.c_str(), rms_ac,
 | 
					    ESP_LOGD(TAG, "'%s' - Raw AC Value: %.3fA after %" PRIu32 " different samples (%" PRIu32 " SPS)",
 | 
				
			||||||
             this->num_samples_, 1000 * this->num_samples_ / this->sample_duration_);
 | 
					             this->name_.c_str(), rms_ac, this->num_samples_, 1000 * this->num_samples_ / this->sample_duration_);
 | 
				
			||||||
    this->publish_state(rms_ac);
 | 
					    this->publish_state(rms_ac);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ import esphome.codegen as cg
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome import automation
 | 
					from esphome import automation
 | 
				
			||||||
from esphome.components import mqtt, time
 | 
					from esphome.components import mqtt, web_server, time
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_ID,
 | 
					    CONF_ID,
 | 
				
			||||||
    CONF_ON_TIME,
 | 
					    CONF_ON_TIME,
 | 
				
			||||||
@@ -11,6 +11,7 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_TRIGGER_ID,
 | 
					    CONF_TRIGGER_ID,
 | 
				
			||||||
    CONF_TYPE,
 | 
					    CONF_TYPE,
 | 
				
			||||||
    CONF_MQTT_ID,
 | 
					    CONF_MQTT_ID,
 | 
				
			||||||
 | 
					    CONF_WEB_SERVER_ID,
 | 
				
			||||||
    CONF_DATE,
 | 
					    CONF_DATE,
 | 
				
			||||||
    CONF_DATETIME,
 | 
					    CONF_DATETIME,
 | 
				
			||||||
    CONF_TIME,
 | 
					    CONF_TIME,
 | 
				
			||||||
@@ -63,16 +64,20 @@ DATETIME_MODES = [
 | 
				
			|||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_DATETIME_SCHEMA = cv.Schema(
 | 
					_DATETIME_SCHEMA = (
 | 
				
			||||||
    {
 | 
					    cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
 | 
				
			||||||
        cv.Optional(CONF_ON_VALUE): automation.validate_automation(
 | 
					    .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
 | 
				
			||||||
            {
 | 
					    .extend(
 | 
				
			||||||
                cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DateTimeStateTrigger),
 | 
					        {
 | 
				
			||||||
            }
 | 
					            cv.Optional(CONF_ON_VALUE): automation.validate_automation(
 | 
				
			||||||
        ),
 | 
					                {
 | 
				
			||||||
        cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock),
 | 
					                    cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(DateTimeStateTrigger),
 | 
				
			||||||
    }
 | 
					                }
 | 
				
			||||||
).extend(cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA))
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def date_schema(class_: MockObjClass) -> cv.Schema:
 | 
					def date_schema(class_: MockObjClass) -> cv.Schema:
 | 
				
			||||||
@@ -128,6 +133,9 @@ async def setup_datetime_core_(var, config):
 | 
				
			|||||||
    if (mqtt_id := config.get(CONF_MQTT_ID)) is not None:
 | 
					    if (mqtt_id := config.get(CONF_MQTT_ID)) is not None:
 | 
				
			||||||
        mqtt_ = cg.new_Pvariable(mqtt_id, var)
 | 
					        mqtt_ = cg.new_Pvariable(mqtt_id, var)
 | 
				
			||||||
        await mqtt.register_mqtt_component(mqtt_, config)
 | 
					        await mqtt.register_mqtt_component(mqtt_, config)
 | 
				
			||||||
 | 
					    if (webserver_id := config.get(CONF_WEB_SERVER_ID)) is not None:
 | 
				
			||||||
 | 
					        web_server_ = await cg.get_variable(webserver_id)
 | 
				
			||||||
 | 
					        web_server.add_entity_to_sorting_list(web_server_, var, config)
 | 
				
			||||||
    for conf in config.get(CONF_ON_VALUE, []):
 | 
					    for conf in config.get(CONF_ON_VALUE, []):
 | 
				
			||||||
        trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
 | 
					        trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
 | 
				
			||||||
        await automation.build_automation(trigger, [(cg.ESPTime, "x")], conf)
 | 
					        await automation.build_automation(trigger, [(cg.ESPTime, "x")], conf)
 | 
				
			||||||
@@ -156,7 +164,7 @@ async def new_datetime(config, *args):
 | 
				
			|||||||
    return var
 | 
					    return var
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@coroutine_with_priority(40.0)
 | 
					@coroutine_with_priority(100.0)
 | 
				
			||||||
async def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    cg.add_define("USE_DATETIME")
 | 
					    cg.add_define("USE_DATETIME")
 | 
				
			||||||
    cg.add_global(datetime_ns.using)
 | 
					    cg.add_global(datetime_ns.using)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,62 +8,16 @@
 | 
				
			|||||||
#include <cinttypes>
 | 
					#include <cinttypes>
 | 
				
			||||||
#include <climits>
 | 
					#include <climits>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <esp_heap_caps.h>
 | 
					 | 
				
			||||||
#include <esp_system.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <esp_chip_info.h>
 | 
					 | 
				
			||||||
#if defined(USE_ESP32_VARIANT_ESP32)
 | 
					 | 
				
			||||||
#include <esp32/rom/rtc.h>
 | 
					 | 
				
			||||||
#elif defined(USE_ESP32_VARIANT_ESP32C3)
 | 
					 | 
				
			||||||
#include <esp32c3/rom/rtc.h>
 | 
					 | 
				
			||||||
#elif defined(USE_ESP32_VARIANT_ESP32C6)
 | 
					 | 
				
			||||||
#include <esp32c6/rom/rtc.h>
 | 
					 | 
				
			||||||
#elif defined(USE_ESP32_VARIANT_ESP32S2)
 | 
					 | 
				
			||||||
#include <esp32s2/rom/rtc.h>
 | 
					 | 
				
			||||||
#elif defined(USE_ESP32_VARIANT_ESP32S3)
 | 
					 | 
				
			||||||
#include <esp32s3/rom/rtc.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif  // USE_ESP32
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_ARDUINO
 | 
					 | 
				
			||||||
#ifdef USE_RP2040
 | 
					 | 
				
			||||||
#include <Arduino.h>
 | 
					 | 
				
			||||||
#elif defined(USE_ESP32) || defined(USE_ESP8266)
 | 
					 | 
				
			||||||
#include <Esp.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace debug {
 | 
					namespace debug {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *const TAG = "debug";
 | 
					static const char *const TAG = "debug";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static uint32_t get_free_heap() {
 | 
					 | 
				
			||||||
#if defined(USE_ESP8266)
 | 
					 | 
				
			||||||
  return ESP.getFreeHeap();  // NOLINT(readability-static-accessed-through-instance)
 | 
					 | 
				
			||||||
#elif defined(USE_ESP32)
 | 
					 | 
				
			||||||
  return heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
 | 
					 | 
				
			||||||
#elif defined(USE_RP2040)
 | 
					 | 
				
			||||||
  return rp2040.getFreeHeap();
 | 
					 | 
				
			||||||
#elif defined(USE_LIBRETINY)
 | 
					 | 
				
			||||||
  return lt_heap_get_free();
 | 
					 | 
				
			||||||
#elif defined(USE_HOST)
 | 
					 | 
				
			||||||
  return INT_MAX;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void DebugComponent::dump_config() {
 | 
					void DebugComponent::dump_config() {
 | 
				
			||||||
#ifndef ESPHOME_LOG_HAS_DEBUG
 | 
					#ifndef ESPHOME_LOG_HAS_DEBUG
 | 
				
			||||||
  return;  // Can't log below if debug logging is disabled
 | 
					  return;  // Can't log below if debug logging is disabled
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string device_info;
 | 
					 | 
				
			||||||
  std::string reset_reason;
 | 
					 | 
				
			||||||
  device_info.reserve(256);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Debug component:");
 | 
					  ESP_LOGCONFIG(TAG, "Debug component:");
 | 
				
			||||||
#ifdef USE_TEXT_SENSOR
 | 
					#ifdef USE_TEXT_SENSOR
 | 
				
			||||||
  LOG_TEXT_SENSOR("  ", "Device info", this->device_info_);
 | 
					  LOG_TEXT_SENSOR("  ", "Device info", this->device_info_);
 | 
				
			||||||
@@ -76,305 +30,15 @@ void DebugComponent::dump_config() {
 | 
				
			|||||||
#endif  // defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
 | 
					#endif  // defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
 | 
				
			||||||
#endif  // USE_SENSOR
 | 
					#endif  // USE_SENSOR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::string device_info;
 | 
				
			||||||
 | 
					  device_info.reserve(256);
 | 
				
			||||||
  ESP_LOGD(TAG, "ESPHome version %s", ESPHOME_VERSION);
 | 
					  ESP_LOGD(TAG, "ESPHome version %s", ESPHOME_VERSION);
 | 
				
			||||||
  device_info += ESPHOME_VERSION;
 | 
					  device_info += ESPHOME_VERSION;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  this->free_heap_ = get_free_heap();
 | 
					  this->free_heap_ = get_free_heap_();
 | 
				
			||||||
  ESP_LOGD(TAG, "Free Heap Size: %" PRIu32 " bytes", this->free_heap_);
 | 
					  ESP_LOGD(TAG, "Free Heap Size: %" PRIu32 " bytes", this->free_heap_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(USE_ARDUINO) && (defined(USE_ESP32) || defined(USE_ESP8266))
 | 
					  get_device_info_(device_info);
 | 
				
			||||||
  const char *flash_mode;
 | 
					 | 
				
			||||||
  switch (ESP.getFlashChipMode()) {  // NOLINT(readability-static-accessed-through-instance)
 | 
					 | 
				
			||||||
    case FM_QIO:
 | 
					 | 
				
			||||||
      flash_mode = "QIO";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case FM_QOUT:
 | 
					 | 
				
			||||||
      flash_mode = "QOUT";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case FM_DIO:
 | 
					 | 
				
			||||||
      flash_mode = "DIO";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case FM_DOUT:
 | 
					 | 
				
			||||||
      flash_mode = "DOUT";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
#ifdef USE_ESP32
 | 
					 | 
				
			||||||
    case FM_FAST_READ:
 | 
					 | 
				
			||||||
      flash_mode = "FAST_READ";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case FM_SLOW_READ:
 | 
					 | 
				
			||||||
      flash_mode = "SLOW_READ";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      flash_mode = "UNKNOWN";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s",
 | 
					 | 
				
			||||||
           ESP.getFlashChipSize() / 1024,                                                   // NOLINT
 | 
					 | 
				
			||||||
           ESP.getFlashChipSpeed() / 1000000, flash_mode);                                  // NOLINT
 | 
					 | 
				
			||||||
  device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) +                    // NOLINT
 | 
					 | 
				
			||||||
                 "kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:";  // NOLINT
 | 
					 | 
				
			||||||
  device_info += flash_mode;
 | 
					 | 
				
			||||||
#endif  // USE_ARDUINO && (USE_ESP32 || USE_ESP8266)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_ESP32
 | 
					 | 
				
			||||||
  esp_chip_info_t info;
 | 
					 | 
				
			||||||
  esp_chip_info(&info);
 | 
					 | 
				
			||||||
  const char *model;
 | 
					 | 
				
			||||||
#if defined(USE_ESP32_VARIANT_ESP32)
 | 
					 | 
				
			||||||
  model = "ESP32";
 | 
					 | 
				
			||||||
#elif defined(USE_ESP32_VARIANT_ESP32C3)
 | 
					 | 
				
			||||||
  model = "ESP32-C3";
 | 
					 | 
				
			||||||
#elif defined(USE_ESP32_VARIANT_ESP32C6)
 | 
					 | 
				
			||||||
  model = "ESP32-C6";
 | 
					 | 
				
			||||||
#elif defined(USE_ESP32_VARIANT_ESP32S2)
 | 
					 | 
				
			||||||
  model = "ESP32-S2";
 | 
					 | 
				
			||||||
#elif defined(USE_ESP32_VARIANT_ESP32S3)
 | 
					 | 
				
			||||||
  model = "ESP32-S3";
 | 
					 | 
				
			||||||
#elif defined(USE_ESP32_VARIANT_ESP32H2)
 | 
					 | 
				
			||||||
  model = "ESP32-H2";
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
  model = "UNKNOWN";
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  std::string features;
 | 
					 | 
				
			||||||
  if (info.features & CHIP_FEATURE_EMB_FLASH) {
 | 
					 | 
				
			||||||
    features += "EMB_FLASH,";
 | 
					 | 
				
			||||||
    info.features &= ~CHIP_FEATURE_EMB_FLASH;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (info.features & CHIP_FEATURE_WIFI_BGN) {
 | 
					 | 
				
			||||||
    features += "WIFI_BGN,";
 | 
					 | 
				
			||||||
    info.features &= ~CHIP_FEATURE_WIFI_BGN;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (info.features & CHIP_FEATURE_BLE) {
 | 
					 | 
				
			||||||
    features += "BLE,";
 | 
					 | 
				
			||||||
    info.features &= ~CHIP_FEATURE_BLE;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (info.features & CHIP_FEATURE_BT) {
 | 
					 | 
				
			||||||
    features += "BT,";
 | 
					 | 
				
			||||||
    info.features &= ~CHIP_FEATURE_BT;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (info.features & CHIP_FEATURE_EMB_PSRAM) {
 | 
					 | 
				
			||||||
    features += "EMB_PSRAM,";
 | 
					 | 
				
			||||||
    info.features &= ~CHIP_FEATURE_EMB_PSRAM;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (info.features)
 | 
					 | 
				
			||||||
    features += "Other:" + format_hex(info.features);
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "Chip: Model=%s, Features=%s Cores=%u, Revision=%u", model, features.c_str(), info.cores,
 | 
					 | 
				
			||||||
           info.revision);
 | 
					 | 
				
			||||||
  device_info += "|Chip: ";
 | 
					 | 
				
			||||||
  device_info += model;
 | 
					 | 
				
			||||||
  device_info += " Features:";
 | 
					 | 
				
			||||||
  device_info += features;
 | 
					 | 
				
			||||||
  device_info += " Cores:" + to_string(info.cores);
 | 
					 | 
				
			||||||
  device_info += " Revision:" + to_string(info.revision);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "ESP-IDF Version: %s", esp_get_idf_version());
 | 
					 | 
				
			||||||
  device_info += "|ESP-IDF: ";
 | 
					 | 
				
			||||||
  device_info += esp_get_idf_version();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::string mac = get_mac_address_pretty();
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "EFuse MAC: %s", mac.c_str());
 | 
					 | 
				
			||||||
  device_info += "|EFuse MAC: ";
 | 
					 | 
				
			||||||
  device_info += mac;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (rtc_get_reset_reason(0)) {
 | 
					 | 
				
			||||||
    case POWERON_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "Power On Reset";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
#if defined(USE_ESP32_VARIANT_ESP32)
 | 
					 | 
				
			||||||
    case SW_RESET:
 | 
					 | 
				
			||||||
#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
 | 
					 | 
				
			||||||
    case RTC_SW_SYS_RESET:
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
      reset_reason = "Software Reset Digital Core";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
#if defined(USE_ESP32_VARIANT_ESP32)
 | 
					 | 
				
			||||||
    case OWDT_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "Watch Dog Reset Digital Core";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    case DEEPSLEEP_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "Deep Sleep Reset Digital Core";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
#if defined(USE_ESP32_VARIANT_ESP32)
 | 
					 | 
				
			||||||
    case SDIO_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "SLC Module Reset Digital Core";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    case TG0WDT_SYS_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "Timer Group 0 Watch Dog Reset Digital Core";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case TG1WDT_SYS_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "Timer Group 1 Watch Dog Reset Digital Core";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case RTCWDT_SYS_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "RTC Watch Dog Reset Digital Core";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
#if !defined(USE_ESP32_VARIANT_ESP32C6)
 | 
					 | 
				
			||||||
    case INTRUSION_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "Intrusion Reset CPU";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#if defined(USE_ESP32_VARIANT_ESP32)
 | 
					 | 
				
			||||||
    case TGWDT_CPU_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "Timer Group Reset CPU";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
 | 
					 | 
				
			||||||
    case TG0WDT_CPU_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "Timer Group 0 Reset CPU";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#if defined(USE_ESP32_VARIANT_ESP32)
 | 
					 | 
				
			||||||
    case SW_CPU_RESET:
 | 
					 | 
				
			||||||
#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
 | 
					 | 
				
			||||||
    case RTC_SW_CPU_RESET:
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
      reset_reason = "Software Reset CPU";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case RTCWDT_CPU_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "RTC Watch Dog Reset CPU";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
#if defined(USE_ESP32_VARIANT_ESP32)
 | 
					 | 
				
			||||||
    case EXT_CPU_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "External CPU Reset";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    case RTCWDT_BROWN_OUT_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "Voltage Unstable Reset";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case RTCWDT_RTC_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "RTC Watch Dog Reset Digital Core And RTC Module";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
 | 
					 | 
				
			||||||
    case TG1WDT_CPU_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "Timer Group 1 Reset CPU";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case SUPER_WDT_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "Super Watchdog Reset Digital Core And RTC Module";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case GLITCH_RTC_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "Glitch Reset Digital Core And RTC Module";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case EFUSE_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "eFuse Reset Digital Core";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S3)
 | 
					 | 
				
			||||||
    case USB_UART_CHIP_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "USB UART Reset Digital Core";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case USB_JTAG_CHIP_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "USB JTAG Reset Digital Core";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case POWER_GLITCH_RESET:
 | 
					 | 
				
			||||||
      reset_reason = "Power Glitch Reset Digital Core And RTC Module";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      reset_reason = "Unknown Reset Reason";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str());
 | 
					 | 
				
			||||||
  device_info += "|Reset: ";
 | 
					 | 
				
			||||||
  device_info += reset_reason;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const char *wakeup_reason;
 | 
					 | 
				
			||||||
  switch (rtc_get_wakeup_cause()) {
 | 
					 | 
				
			||||||
    case NO_SLEEP:
 | 
					 | 
				
			||||||
      wakeup_reason = "No Sleep";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case EXT_EVENT0_TRIG:
 | 
					 | 
				
			||||||
      wakeup_reason = "External Event 0";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case EXT_EVENT1_TRIG:
 | 
					 | 
				
			||||||
      wakeup_reason = "External Event 1";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case GPIO_TRIG:
 | 
					 | 
				
			||||||
      wakeup_reason = "GPIO";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case TIMER_EXPIRE:
 | 
					 | 
				
			||||||
      wakeup_reason = "Wakeup Timer";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case SDIO_TRIG:
 | 
					 | 
				
			||||||
      wakeup_reason = "SDIO";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case MAC_TRIG:
 | 
					 | 
				
			||||||
      wakeup_reason = "MAC";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case UART0_TRIG:
 | 
					 | 
				
			||||||
      wakeup_reason = "UART0";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case UART1_TRIG:
 | 
					 | 
				
			||||||
      wakeup_reason = "UART1";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case TOUCH_TRIG:
 | 
					 | 
				
			||||||
      wakeup_reason = "Touch";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case SAR_TRIG:
 | 
					 | 
				
			||||||
      wakeup_reason = "SAR";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case BT_TRIG:
 | 
					 | 
				
			||||||
      wakeup_reason = "BT";
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      wakeup_reason = "Unknown";
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "Wakeup Reason: %s", wakeup_reason);
 | 
					 | 
				
			||||||
  device_info += "|Wakeup: ";
 | 
					 | 
				
			||||||
  device_info += wakeup_reason;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(USE_ESP8266) && !defined(CLANG_TIDY)
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "Chip ID: 0x%08X", ESP.getChipId());
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "SDK Version: %s", ESP.getSdkVersion());
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "Core Version: %s", ESP.getCoreVersion().c_str());
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "Boot Version=%u Mode=%u", ESP.getBootVersion(), ESP.getBootMode());
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "CPU Frequency: %u", ESP.getCpuFreqMHz());
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "Flash Chip ID=0x%08X", ESP.getFlashChipId());
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "Reset Reason: %s", ESP.getResetReason().c_str());
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "Reset Info: %s", ESP.getResetInfo().c_str());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  device_info += "|Chip: 0x" + format_hex(ESP.getChipId());
 | 
					 | 
				
			||||||
  device_info += "|SDK: ";
 | 
					 | 
				
			||||||
  device_info += ESP.getSdkVersion();
 | 
					 | 
				
			||||||
  device_info += "|Core: ";
 | 
					 | 
				
			||||||
  device_info += ESP.getCoreVersion().c_str();
 | 
					 | 
				
			||||||
  device_info += "|Boot: ";
 | 
					 | 
				
			||||||
  device_info += to_string(ESP.getBootVersion());
 | 
					 | 
				
			||||||
  device_info += "|Mode: " + to_string(ESP.getBootMode());
 | 
					 | 
				
			||||||
  device_info += "|CPU: " + to_string(ESP.getCpuFreqMHz());
 | 
					 | 
				
			||||||
  device_info += "|Flash: 0x" + format_hex(ESP.getFlashChipId());
 | 
					 | 
				
			||||||
  device_info += "|Reset: ";
 | 
					 | 
				
			||||||
  device_info += ESP.getResetReason().c_str();
 | 
					 | 
				
			||||||
  device_info += "|";
 | 
					 | 
				
			||||||
  device_info += ESP.getResetInfo().c_str();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  reset_reason = ESP.getResetReason().c_str();
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_RP2040
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "CPU Frequency: %u", rp2040.f_cpu());
 | 
					 | 
				
			||||||
  device_info += "CPU Frequency: " + to_string(rp2040.f_cpu());
 | 
					 | 
				
			||||||
#endif  // USE_RP2040
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_LIBRETINY
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "LibreTiny Version: %s", lt_get_version());
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "Chip: %s (%04x) @ %u MHz", lt_cpu_get_model_name(), lt_cpu_get_model(), lt_cpu_get_freq_mhz());
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "Chip ID: 0x%06X", lt_cpu_get_mac_id());
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "Board: %s", lt_get_board_code());
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "Flash: %u KiB / RAM: %u KiB", lt_flash_get_size() / 1024, lt_ram_get_size() / 1024);
 | 
					 | 
				
			||||||
  ESP_LOGD(TAG, "Reset Reason: %s", lt_get_reboot_reason_name(lt_get_reboot_reason()));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  device_info += "|Version: ";
 | 
					 | 
				
			||||||
  device_info += LT_BANNER_STR + 10;
 | 
					 | 
				
			||||||
  device_info += "|Reset Reason: ";
 | 
					 | 
				
			||||||
  device_info += lt_get_reboot_reason_name(lt_get_reboot_reason());
 | 
					 | 
				
			||||||
  device_info += "|Chip Name: ";
 | 
					 | 
				
			||||||
  device_info += lt_cpu_get_model_name();
 | 
					 | 
				
			||||||
  device_info += "|Chip ID: 0x" + format_hex(lt_cpu_get_mac_id());
 | 
					 | 
				
			||||||
  device_info += "|Flash: " + to_string(lt_flash_get_size() / 1024) + " KiB";
 | 
					 | 
				
			||||||
  device_info += "|RAM: " + to_string(lt_ram_get_size() / 1024) + " KiB";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  reset_reason = lt_get_reboot_reason_name(lt_get_reboot_reason());
 | 
					 | 
				
			||||||
#endif  // USE_LIBRETINY
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_TEXT_SENSOR
 | 
					#ifdef USE_TEXT_SENSOR
 | 
				
			||||||
  if (this->device_info_ != nullptr) {
 | 
					  if (this->device_info_ != nullptr) {
 | 
				
			||||||
@@ -383,14 +47,14 @@ void DebugComponent::dump_config() {
 | 
				
			|||||||
    this->device_info_->publish_state(device_info);
 | 
					    this->device_info_->publish_state(device_info);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (this->reset_reason_ != nullptr) {
 | 
					  if (this->reset_reason_ != nullptr) {
 | 
				
			||||||
    this->reset_reason_->publish_state(reset_reason);
 | 
					    this->reset_reason_->publish_state(get_reset_reason_());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif  // USE_TEXT_SENSOR
 | 
					#endif  // USE_TEXT_SENSOR
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DebugComponent::loop() {
 | 
					void DebugComponent::loop() {
 | 
				
			||||||
  // log when free heap space has halved
 | 
					  // log when free heap space has halved
 | 
				
			||||||
  uint32_t new_free_heap = get_free_heap();
 | 
					  uint32_t new_free_heap = get_free_heap_();
 | 
				
			||||||
  if (new_free_heap < this->free_heap_ / 2) {
 | 
					  if (new_free_heap < this->free_heap_ / 2) {
 | 
				
			||||||
    this->free_heap_ = new_free_heap;
 | 
					    this->free_heap_ = new_free_heap;
 | 
				
			||||||
    ESP_LOGD(TAG, "Free Heap Size: %" PRIu32 " bytes", this->free_heap_);
 | 
					    ESP_LOGD(TAG, "Free Heap Size: %" PRIu32 " bytes", this->free_heap_);
 | 
				
			||||||
@@ -411,38 +75,16 @@ void DebugComponent::loop() {
 | 
				
			|||||||
void DebugComponent::update() {
 | 
					void DebugComponent::update() {
 | 
				
			||||||
#ifdef USE_SENSOR
 | 
					#ifdef USE_SENSOR
 | 
				
			||||||
  if (this->free_sensor_ != nullptr) {
 | 
					  if (this->free_sensor_ != nullptr) {
 | 
				
			||||||
    this->free_sensor_->publish_state(get_free_heap());
 | 
					    this->free_sensor_->publish_state(get_free_heap_());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (this->block_sensor_ != nullptr) {
 | 
					 | 
				
			||||||
#if defined(USE_ESP8266)
 | 
					 | 
				
			||||||
    // NOLINTNEXTLINE(readability-static-accessed-through-instance)
 | 
					 | 
				
			||||||
    this->block_sensor_->publish_state(ESP.getMaxFreeBlockSize());
 | 
					 | 
				
			||||||
#elif defined(USE_ESP32)
 | 
					 | 
				
			||||||
    this->block_sensor_->publish_state(heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL));
 | 
					 | 
				
			||||||
#elif defined(USE_LIBRETINY)
 | 
					 | 
				
			||||||
    this->block_sensor_->publish_state(lt_heap_get_max_alloc());
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(USE_ESP8266) && USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
 | 
					 | 
				
			||||||
  if (this->fragmentation_sensor_ != nullptr) {
 | 
					 | 
				
			||||||
    // NOLINTNEXTLINE(readability-static-accessed-through-instance)
 | 
					 | 
				
			||||||
    this->fragmentation_sensor_->publish_state(ESP.getHeapFragmentation());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (this->loop_time_sensor_ != nullptr) {
 | 
					  if (this->loop_time_sensor_ != nullptr) {
 | 
				
			||||||
    this->loop_time_sensor_->publish_state(this->max_loop_time_);
 | 
					    this->loop_time_sensor_->publish_state(this->max_loop_time_);
 | 
				
			||||||
    this->max_loop_time_ = 0;
 | 
					    this->max_loop_time_ = 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					 | 
				
			||||||
  if (this->psram_sensor_ != nullptr) {
 | 
					 | 
				
			||||||
    this->psram_sensor_->publish_state(heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#endif  // USE_ESP32
 | 
					 | 
				
			||||||
#endif  // USE_SENSOR
 | 
					#endif  // USE_SENSOR
 | 
				
			||||||
 | 
					  update_platform_();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
float DebugComponent::get_setup_priority() const { return setup_priority::LATE; }
 | 
					float DebugComponent::get_setup_priority() const { return setup_priority::LATE; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,6 +59,11 @@ class DebugComponent : public PollingComponent {
 | 
				
			|||||||
  text_sensor::TextSensor *device_info_{nullptr};
 | 
					  text_sensor::TextSensor *device_info_{nullptr};
 | 
				
			||||||
  text_sensor::TextSensor *reset_reason_{nullptr};
 | 
					  text_sensor::TextSensor *reset_reason_{nullptr};
 | 
				
			||||||
#endif  // USE_TEXT_SENSOR
 | 
					#endif  // USE_TEXT_SENSOR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::string get_reset_reason_();
 | 
				
			||||||
 | 
					  uint32_t get_free_heap_();
 | 
				
			||||||
 | 
					  void get_device_info_(std::string &device_info);
 | 
				
			||||||
 | 
					  void update_platform_();
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace debug
 | 
					}  // namespace debug
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										287
									
								
								esphome/components/debug/debug_esp32.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										287
									
								
								esphome/components/debug/debug_esp32.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,287 @@
 | 
				
			|||||||
 | 
					#include "debug_component.h"
 | 
				
			||||||
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <esp_heap_caps.h>
 | 
				
			||||||
 | 
					#include <esp_system.h>
 | 
				
			||||||
 | 
					#include <esp_chip_info.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(USE_ESP32_VARIANT_ESP32)
 | 
				
			||||||
 | 
					#include <esp32/rom/rtc.h>
 | 
				
			||||||
 | 
					#elif defined(USE_ESP32_VARIANT_ESP32C3)
 | 
				
			||||||
 | 
					#include <esp32c3/rom/rtc.h>
 | 
				
			||||||
 | 
					#elif defined(USE_ESP32_VARIANT_ESP32C6)
 | 
				
			||||||
 | 
					#include <esp32c6/rom/rtc.h>
 | 
				
			||||||
 | 
					#elif defined(USE_ESP32_VARIANT_ESP32S2)
 | 
				
			||||||
 | 
					#include <esp32s2/rom/rtc.h>
 | 
				
			||||||
 | 
					#elif defined(USE_ESP32_VARIANT_ESP32S3)
 | 
				
			||||||
 | 
					#include <esp32s3/rom/rtc.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_ARDUINO
 | 
				
			||||||
 | 
					#include <Esp.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace debug {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "debug";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string DebugComponent::get_reset_reason_() {
 | 
				
			||||||
 | 
					  std::string reset_reason;
 | 
				
			||||||
 | 
					  switch (rtc_get_reset_reason(0)) {
 | 
				
			||||||
 | 
					    case POWERON_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "Power On Reset";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					#if defined(USE_ESP32_VARIANT_ESP32)
 | 
				
			||||||
 | 
					    case SW_RESET:
 | 
				
			||||||
 | 
					#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
 | 
				
			||||||
 | 
					    case RTC_SW_SYS_RESET:
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					      reset_reason = "Software Reset Digital Core";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					#if defined(USE_ESP32_VARIANT_ESP32)
 | 
				
			||||||
 | 
					    case OWDT_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "Watch Dog Reset Digital Core";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    case DEEPSLEEP_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "Deep Sleep Reset Digital Core";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					#if defined(USE_ESP32_VARIANT_ESP32)
 | 
				
			||||||
 | 
					    case SDIO_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "SLC Module Reset Digital Core";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    case TG0WDT_SYS_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "Timer Group 0 Watch Dog Reset Digital Core";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case TG1WDT_SYS_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "Timer Group 1 Watch Dog Reset Digital Core";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case RTCWDT_SYS_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "RTC Watch Dog Reset Digital Core";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					#if !defined(USE_ESP32_VARIANT_ESP32C6)
 | 
				
			||||||
 | 
					    case INTRUSION_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "Intrusion Reset CPU";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if defined(USE_ESP32_VARIANT_ESP32)
 | 
				
			||||||
 | 
					    case TGWDT_CPU_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "Timer Group Reset CPU";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
 | 
				
			||||||
 | 
					    case TG0WDT_CPU_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "Timer Group 0 Reset CPU";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if defined(USE_ESP32_VARIANT_ESP32)
 | 
				
			||||||
 | 
					    case SW_CPU_RESET:
 | 
				
			||||||
 | 
					#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
 | 
				
			||||||
 | 
					    case RTC_SW_CPU_RESET:
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					      reset_reason = "Software Reset CPU";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case RTCWDT_CPU_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "RTC Watch Dog Reset CPU";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					#if defined(USE_ESP32_VARIANT_ESP32)
 | 
				
			||||||
 | 
					    case EXT_CPU_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "External CPU Reset";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    case RTCWDT_BROWN_OUT_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "Voltage Unstable Reset";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case RTCWDT_RTC_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "RTC Watch Dog Reset Digital Core And RTC Module";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
 | 
				
			||||||
 | 
					    case TG1WDT_CPU_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "Timer Group 1 Reset CPU";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case SUPER_WDT_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "Super Watchdog Reset Digital Core And RTC Module";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case GLITCH_RTC_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "Glitch Reset Digital Core And RTC Module";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case EFUSE_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "eFuse Reset Digital Core";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S3)
 | 
				
			||||||
 | 
					    case USB_UART_CHIP_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "USB UART Reset Digital Core";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case USB_JTAG_CHIP_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "USB JTAG Reset Digital Core";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case POWER_GLITCH_RESET:
 | 
				
			||||||
 | 
					      reset_reason = "Power Glitch Reset Digital Core And RTC Module";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      reset_reason = "Unknown Reset Reason";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str());
 | 
				
			||||||
 | 
					  return reset_reason;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t DebugComponent::get_free_heap_() { return heap_caps_get_free_size(MALLOC_CAP_INTERNAL); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DebugComponent::get_device_info_(std::string &device_info) {
 | 
				
			||||||
 | 
					#if defined(USE_ARDUINO)
 | 
				
			||||||
 | 
					  const char *flash_mode;
 | 
				
			||||||
 | 
					  switch (ESP.getFlashChipMode()) {  // NOLINT(readability-static-accessed-through-instance)
 | 
				
			||||||
 | 
					    case FM_QIO:
 | 
				
			||||||
 | 
					      flash_mode = "QIO";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case FM_QOUT:
 | 
				
			||||||
 | 
					      flash_mode = "QOUT";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case FM_DIO:
 | 
				
			||||||
 | 
					      flash_mode = "DIO";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case FM_DOUT:
 | 
				
			||||||
 | 
					      flash_mode = "DOUT";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case FM_FAST_READ:
 | 
				
			||||||
 | 
					      flash_mode = "FAST_READ";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case FM_SLOW_READ:
 | 
				
			||||||
 | 
					      flash_mode = "SLOW_READ";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      flash_mode = "UNKNOWN";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s",
 | 
				
			||||||
 | 
					           ESP.getFlashChipSize() / 1024,                                                   // NOLINT
 | 
				
			||||||
 | 
					           ESP.getFlashChipSpeed() / 1000000, flash_mode);                                  // NOLINT
 | 
				
			||||||
 | 
					  device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) +                    // NOLINT
 | 
				
			||||||
 | 
					                 "kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:";  // NOLINT
 | 
				
			||||||
 | 
					  device_info += flash_mode;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  esp_chip_info_t info;
 | 
				
			||||||
 | 
					  esp_chip_info(&info);
 | 
				
			||||||
 | 
					  const char *model;
 | 
				
			||||||
 | 
					#if defined(USE_ESP32_VARIANT_ESP32)
 | 
				
			||||||
 | 
					  model = "ESP32";
 | 
				
			||||||
 | 
					#elif defined(USE_ESP32_VARIANT_ESP32C3)
 | 
				
			||||||
 | 
					  model = "ESP32-C3";
 | 
				
			||||||
 | 
					#elif defined(USE_ESP32_VARIANT_ESP32C6)
 | 
				
			||||||
 | 
					  model = "ESP32-C6";
 | 
				
			||||||
 | 
					#elif defined(USE_ESP32_VARIANT_ESP32S2)
 | 
				
			||||||
 | 
					  model = "ESP32-S2";
 | 
				
			||||||
 | 
					#elif defined(USE_ESP32_VARIANT_ESP32S3)
 | 
				
			||||||
 | 
					  model = "ESP32-S3";
 | 
				
			||||||
 | 
					#elif defined(USE_ESP32_VARIANT_ESP32H2)
 | 
				
			||||||
 | 
					  model = "ESP32-H2";
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					  model = "UNKNOWN";
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					  std::string features;
 | 
				
			||||||
 | 
					  if (info.features & CHIP_FEATURE_EMB_FLASH) {
 | 
				
			||||||
 | 
					    features += "EMB_FLASH,";
 | 
				
			||||||
 | 
					    info.features &= ~CHIP_FEATURE_EMB_FLASH;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (info.features & CHIP_FEATURE_WIFI_BGN) {
 | 
				
			||||||
 | 
					    features += "WIFI_BGN,";
 | 
				
			||||||
 | 
					    info.features &= ~CHIP_FEATURE_WIFI_BGN;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (info.features & CHIP_FEATURE_BLE) {
 | 
				
			||||||
 | 
					    features += "BLE,";
 | 
				
			||||||
 | 
					    info.features &= ~CHIP_FEATURE_BLE;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (info.features & CHIP_FEATURE_BT) {
 | 
				
			||||||
 | 
					    features += "BT,";
 | 
				
			||||||
 | 
					    info.features &= ~CHIP_FEATURE_BT;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (info.features & CHIP_FEATURE_EMB_PSRAM) {
 | 
				
			||||||
 | 
					    features += "EMB_PSRAM,";
 | 
				
			||||||
 | 
					    info.features &= ~CHIP_FEATURE_EMB_PSRAM;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (info.features)
 | 
				
			||||||
 | 
					    features += "Other:" + format_hex(info.features);
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "Chip: Model=%s, Features=%s Cores=%u, Revision=%u", model, features.c_str(), info.cores,
 | 
				
			||||||
 | 
					           info.revision);
 | 
				
			||||||
 | 
					  device_info += "|Chip: ";
 | 
				
			||||||
 | 
					  device_info += model;
 | 
				
			||||||
 | 
					  device_info += " Features:";
 | 
				
			||||||
 | 
					  device_info += features;
 | 
				
			||||||
 | 
					  device_info += " Cores:" + to_string(info.cores);
 | 
				
			||||||
 | 
					  device_info += " Revision:" + to_string(info.revision);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "ESP-IDF Version: %s", esp_get_idf_version());
 | 
				
			||||||
 | 
					  device_info += "|ESP-IDF: ";
 | 
				
			||||||
 | 
					  device_info += esp_get_idf_version();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::string mac = get_mac_address_pretty();
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "EFuse MAC: %s", mac.c_str());
 | 
				
			||||||
 | 
					  device_info += "|EFuse MAC: ";
 | 
				
			||||||
 | 
					  device_info += mac;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  device_info += "|Reset: ";
 | 
				
			||||||
 | 
					  device_info += get_reset_reason_();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const char *wakeup_reason;
 | 
				
			||||||
 | 
					  switch (rtc_get_wakeup_cause()) {
 | 
				
			||||||
 | 
					    case NO_SLEEP:
 | 
				
			||||||
 | 
					      wakeup_reason = "No Sleep";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case EXT_EVENT0_TRIG:
 | 
				
			||||||
 | 
					      wakeup_reason = "External Event 0";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case EXT_EVENT1_TRIG:
 | 
				
			||||||
 | 
					      wakeup_reason = "External Event 1";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case GPIO_TRIG:
 | 
				
			||||||
 | 
					      wakeup_reason = "GPIO";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case TIMER_EXPIRE:
 | 
				
			||||||
 | 
					      wakeup_reason = "Wakeup Timer";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case SDIO_TRIG:
 | 
				
			||||||
 | 
					      wakeup_reason = "SDIO";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case MAC_TRIG:
 | 
				
			||||||
 | 
					      wakeup_reason = "MAC";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case UART0_TRIG:
 | 
				
			||||||
 | 
					      wakeup_reason = "UART0";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case UART1_TRIG:
 | 
				
			||||||
 | 
					      wakeup_reason = "UART1";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case TOUCH_TRIG:
 | 
				
			||||||
 | 
					      wakeup_reason = "Touch";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case SAR_TRIG:
 | 
				
			||||||
 | 
					      wakeup_reason = "SAR";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case BT_TRIG:
 | 
				
			||||||
 | 
					      wakeup_reason = "BT";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      wakeup_reason = "Unknown";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "Wakeup Reason: %s", wakeup_reason);
 | 
				
			||||||
 | 
					  device_info += "|Wakeup: ";
 | 
				
			||||||
 | 
					  device_info += wakeup_reason;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DebugComponent::update_platform_() {
 | 
				
			||||||
 | 
					#ifdef USE_SENSOR
 | 
				
			||||||
 | 
					  if (this->block_sensor_ != nullptr) {
 | 
				
			||||||
 | 
					    this->block_sensor_->publish_state(heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (this->psram_sensor_ != nullptr) {
 | 
				
			||||||
 | 
					    this->psram_sensor_->publish_state(heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace debug
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										94
									
								
								esphome/components/debug/debug_esp8266.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								esphome/components/debug/debug_esp8266.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
				
			|||||||
 | 
					#include "debug_component.h"
 | 
				
			||||||
 | 
					#ifdef USE_ESP8266
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					#include <Esp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace debug {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "debug";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string DebugComponent::get_reset_reason_() {
 | 
				
			||||||
 | 
					#if !defined(CLANG_TIDY)
 | 
				
			||||||
 | 
					  return ESP.getResetReason().c_str();
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					  return "";
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t DebugComponent::get_free_heap_() {
 | 
				
			||||||
 | 
					  return ESP.getFreeHeap();  // NOLINT(readability-static-accessed-through-instance)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DebugComponent::get_device_info_(std::string &device_info) {
 | 
				
			||||||
 | 
					  const char *flash_mode;
 | 
				
			||||||
 | 
					  switch (ESP.getFlashChipMode()) {  // NOLINT(readability-static-accessed-through-instance)
 | 
				
			||||||
 | 
					    case FM_QIO:
 | 
				
			||||||
 | 
					      flash_mode = "QIO";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case FM_QOUT:
 | 
				
			||||||
 | 
					      flash_mode = "QOUT";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case FM_DIO:
 | 
				
			||||||
 | 
					      flash_mode = "DIO";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case FM_DOUT:
 | 
				
			||||||
 | 
					      flash_mode = "DOUT";
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      flash_mode = "UNKNOWN";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "Flash Chip: Size=%ukB Speed=%uMHz Mode=%s",
 | 
				
			||||||
 | 
					           ESP.getFlashChipSize() / 1024,                                                   // NOLINT
 | 
				
			||||||
 | 
					           ESP.getFlashChipSpeed() / 1000000, flash_mode);                                  // NOLINT
 | 
				
			||||||
 | 
					  device_info += "|Flash: " + to_string(ESP.getFlashChipSize() / 1024) +                    // NOLINT
 | 
				
			||||||
 | 
					                 "kB Speed:" + to_string(ESP.getFlashChipSpeed() / 1000000) + "MHz Mode:";  // NOLINT
 | 
				
			||||||
 | 
					  device_info += flash_mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !defined(CLANG_TIDY)
 | 
				
			||||||
 | 
					  auto reset_reason = get_reset_reason_();
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "Chip ID: 0x%08X", ESP.getChipId());
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "SDK Version: %s", ESP.getSdkVersion());
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "Core Version: %s", ESP.getCoreVersion().c_str());
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "Boot Version=%u Mode=%u", ESP.getBootVersion(), ESP.getBootMode());
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "CPU Frequency: %u", ESP.getCpuFreqMHz());
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "Flash Chip ID=0x%08X", ESP.getFlashChipId());
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str());
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "Reset Info: %s", ESP.getResetInfo().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  device_info += "|Chip: 0x" + format_hex(ESP.getChipId());
 | 
				
			||||||
 | 
					  device_info += "|SDK: ";
 | 
				
			||||||
 | 
					  device_info += ESP.getSdkVersion();
 | 
				
			||||||
 | 
					  device_info += "|Core: ";
 | 
				
			||||||
 | 
					  device_info += ESP.getCoreVersion().c_str();
 | 
				
			||||||
 | 
					  device_info += "|Boot: ";
 | 
				
			||||||
 | 
					  device_info += to_string(ESP.getBootVersion());
 | 
				
			||||||
 | 
					  device_info += "|Mode: " + to_string(ESP.getBootMode());
 | 
				
			||||||
 | 
					  device_info += "|CPU: " + to_string(ESP.getCpuFreqMHz());
 | 
				
			||||||
 | 
					  device_info += "|Flash: 0x" + format_hex(ESP.getFlashChipId());
 | 
				
			||||||
 | 
					  device_info += "|Reset: ";
 | 
				
			||||||
 | 
					  device_info += reset_reason;
 | 
				
			||||||
 | 
					  device_info += "|";
 | 
				
			||||||
 | 
					  device_info += ESP.getResetInfo().c_str();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DebugComponent::update_platform_() {
 | 
				
			||||||
 | 
					#ifdef USE_SENSOR
 | 
				
			||||||
 | 
					  if (this->block_sensor_ != nullptr) {
 | 
				
			||||||
 | 
					    // NOLINTNEXTLINE(readability-static-accessed-through-instance)
 | 
				
			||||||
 | 
					    this->block_sensor_->publish_state(ESP.getMaxFreeBlockSize());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 2)
 | 
				
			||||||
 | 
					  if (this->fragmentation_sensor_ != nullptr) {
 | 
				
			||||||
 | 
					    // NOLINTNEXTLINE(readability-static-accessed-through-instance)
 | 
				
			||||||
 | 
					    this->fragmentation_sensor_->publish_state(ESP.getHeapFragmentation());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace debug
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										18
									
								
								esphome/components/debug/debug_host.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								esphome/components/debug/debug_host.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					#include "debug_component.h"
 | 
				
			||||||
 | 
					#ifdef USE_HOST
 | 
				
			||||||
 | 
					#include <climits>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace debug {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string DebugComponent::get_reset_reason_() { return ""; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t DebugComponent::get_free_heap_() { return INT_MAX; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DebugComponent::get_device_info_(std::string &device_info) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DebugComponent::update_platform_() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace debug
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										44
									
								
								esphome/components/debug/debug_libretiny.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								esphome/components/debug/debug_libretiny.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					#include "debug_component.h"
 | 
				
			||||||
 | 
					#ifdef USE_LIBRETINY
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace debug {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "debug";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string DebugComponent::get_reset_reason_() { return lt_get_reboot_reason_name(lt_get_reboot_reason()); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t DebugComponent::get_free_heap_() { return lt_heap_get_free(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DebugComponent::get_device_info_(std::string &device_info) {
 | 
				
			||||||
 | 
					  str::string reset_reason = get_reset_reason_();
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "LibreTiny Version: %s", lt_get_version());
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "Chip: %s (%04x) @ %u MHz", lt_cpu_get_model_name(), lt_cpu_get_model(), lt_cpu_get_freq_mhz());
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "Chip ID: 0x%06X", lt_cpu_get_mac_id());
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "Board: %s", lt_get_board_code());
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "Flash: %u KiB / RAM: %u KiB", lt_flash_get_size() / 1024, lt_ram_get_size() / 1024);
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "Reset Reason: %s", reset_reason.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  device_info += "|Version: ";
 | 
				
			||||||
 | 
					  device_info += LT_BANNER_STR + 10;
 | 
				
			||||||
 | 
					  device_info += "|Reset Reason: ";
 | 
				
			||||||
 | 
					  device_info += reset_reason;
 | 
				
			||||||
 | 
					  device_info += "|Chip Name: ";
 | 
				
			||||||
 | 
					  device_info += lt_cpu_get_model_name();
 | 
				
			||||||
 | 
					  device_info += "|Chip ID: 0x" + format_hex(lt_cpu_get_mac_id());
 | 
				
			||||||
 | 
					  device_info += "|Flash: " + to_string(lt_flash_get_size() / 1024) + " KiB";
 | 
				
			||||||
 | 
					  device_info += "|RAM: " + to_string(lt_ram_get_size() / 1024) + " KiB";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DebugComponent::update_platform_() {
 | 
				
			||||||
 | 
					#ifdef USE_SENSOR
 | 
				
			||||||
 | 
					  if (this->block_sensor_ != nullptr) {
 | 
				
			||||||
 | 
					    this->block_sensor_->publish_state(lt_heap_get_max_alloc());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace debug
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										23
									
								
								esphome/components/debug/debug_rp2040.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								esphome/components/debug/debug_rp2040.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					#include "debug_component.h"
 | 
				
			||||||
 | 
					#ifdef USE_RP2040
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					#include <Arduino.h>
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace debug {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "debug";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string DebugComponent::get_reset_reason_() { return ""; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t DebugComponent::get_free_heap_() { return rp2040.getFreeHeap(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DebugComponent::get_device_info_(std::string &device_info) {
 | 
				
			||||||
 | 
					  ESP_LOGD(TAG, "CPU Frequency: %u", rp2040.f_cpu());
 | 
				
			||||||
 | 
					  device_info += "CPU Frequency: " + to_string(rp2040.f_cpu());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DebugComponent::update_platform_() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace debug
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@@ -1,12 +1,7 @@
 | 
				
			|||||||
#include "deep_sleep_component.h"
 | 
					#include "deep_sleep_component.h"
 | 
				
			||||||
#include <cinttypes>
 | 
					 | 
				
			||||||
#include "esphome/core/application.h"
 | 
					#include "esphome/core/application.h"
 | 
				
			||||||
#include "esphome/core/log.h"
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP8266
 | 
					 | 
				
			||||||
#include <Esp.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace deep_sleep {
 | 
					namespace deep_sleep {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -14,25 +9,6 @@ static const char *const TAG = "deep_sleep";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bool global_has_deep_sleep = false;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 | 
					bool global_has_deep_sleep = false;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
optional<uint32_t> DeepSleepComponent::get_run_duration_() const {
 | 
					 | 
				
			||||||
#ifdef USE_ESP32
 | 
					 | 
				
			||||||
  if (this->wakeup_cause_to_run_duration_.has_value()) {
 | 
					 | 
				
			||||||
    esp_sleep_wakeup_cause_t wakeup_cause = esp_sleep_get_wakeup_cause();
 | 
					 | 
				
			||||||
    switch (wakeup_cause) {
 | 
					 | 
				
			||||||
      case ESP_SLEEP_WAKEUP_EXT0:
 | 
					 | 
				
			||||||
      case ESP_SLEEP_WAKEUP_EXT1:
 | 
					 | 
				
			||||||
      case ESP_SLEEP_WAKEUP_GPIO:
 | 
					 | 
				
			||||||
        return this->wakeup_cause_to_run_duration_->gpio_cause;
 | 
					 | 
				
			||||||
      case ESP_SLEEP_WAKEUP_TOUCHPAD:
 | 
					 | 
				
			||||||
        return this->wakeup_cause_to_run_duration_->touch_cause;
 | 
					 | 
				
			||||||
      default:
 | 
					 | 
				
			||||||
        return this->wakeup_cause_to_run_duration_->default_cause;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  return this->run_duration_;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void DeepSleepComponent::setup() {
 | 
					void DeepSleepComponent::setup() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up Deep Sleep...");
 | 
					  ESP_LOGCONFIG(TAG, "Setting up Deep Sleep...");
 | 
				
			||||||
  global_has_deep_sleep = true;
 | 
					  global_has_deep_sleep = true;
 | 
				
			||||||
@@ -45,6 +21,7 @@ void DeepSleepComponent::setup() {
 | 
				
			|||||||
    ESP_LOGD(TAG, "Not scheduling Deep Sleep, as no run duration is configured.");
 | 
					    ESP_LOGD(TAG, "Not scheduling Deep Sleep, as no run duration is configured.");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DeepSleepComponent::dump_config() {
 | 
					void DeepSleepComponent::dump_config() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up Deep Sleep...");
 | 
					  ESP_LOGCONFIG(TAG, "Setting up Deep Sleep...");
 | 
				
			||||||
  if (this->sleep_duration_.has_value()) {
 | 
					  if (this->sleep_duration_.has_value()) {
 | 
				
			||||||
@@ -54,65 +31,31 @@ void DeepSleepComponent::dump_config() {
 | 
				
			|||||||
  if (this->run_duration_.has_value()) {
 | 
					  if (this->run_duration_.has_value()) {
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "  Run Duration: %" PRIu32 " ms", *this->run_duration_);
 | 
					    ESP_LOGCONFIG(TAG, "  Run Duration: %" PRIu32 " ms", *this->run_duration_);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					  this->dump_config_platform_();
 | 
				
			||||||
  if (wakeup_pin_ != nullptr) {
 | 
					 | 
				
			||||||
    LOG_PIN("  Wakeup Pin: ", this->wakeup_pin_);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (this->wakeup_cause_to_run_duration_.has_value()) {
 | 
					 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "  Default Wakeup Run Duration: %" PRIu32 " ms",
 | 
					 | 
				
			||||||
                  this->wakeup_cause_to_run_duration_->default_cause);
 | 
					 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "  Touch Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->touch_cause);
 | 
					 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "  GPIO Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->gpio_cause);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DeepSleepComponent::loop() {
 | 
					void DeepSleepComponent::loop() {
 | 
				
			||||||
  if (this->next_enter_deep_sleep_)
 | 
					  if (this->next_enter_deep_sleep_)
 | 
				
			||||||
    this->begin_sleep();
 | 
					    this->begin_sleep();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
float DeepSleepComponent::get_loop_priority() const {
 | 
					float DeepSleepComponent::get_loop_priority() const {
 | 
				
			||||||
  return -100.0f;  // run after everything else is ready
 | 
					  return -100.0f;  // run after everything else is ready
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DeepSleepComponent::set_sleep_duration(uint32_t time_ms) { this->sleep_duration_ = uint64_t(time_ms) * 1000; }
 | 
					void DeepSleepComponent::set_sleep_duration(uint32_t time_ms) { this->sleep_duration_ = uint64_t(time_ms) * 1000; }
 | 
				
			||||||
#if defined(USE_ESP32)
 | 
					 | 
				
			||||||
void DeepSleepComponent::set_wakeup_pin_mode(WakeupPinMode wakeup_pin_mode) {
 | 
					 | 
				
			||||||
  this->wakeup_pin_mode_ = wakeup_pin_mode;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(USE_ESP32)
 | 
					 | 
				
			||||||
#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void DeepSleepComponent::set_ext1_wakeup(Ext1Wakeup ext1_wakeup) { this->ext1_wakeup_ = ext1_wakeup; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void DeepSleepComponent::set_touch_wakeup(bool touch_wakeup) { this->touch_wakeup_ = touch_wakeup; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void DeepSleepComponent::set_run_duration(WakeupCauseToRunDuration wakeup_cause_to_run_duration) {
 | 
					 | 
				
			||||||
  wakeup_cause_to_run_duration_ = wakeup_cause_to_run_duration;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DeepSleepComponent::set_run_duration(uint32_t time_ms) { this->run_duration_ = time_ms; }
 | 
					void DeepSleepComponent::set_run_duration(uint32_t time_ms) { this->run_duration_ = time_ms; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DeepSleepComponent::begin_sleep(bool manual) {
 | 
					void DeepSleepComponent::begin_sleep(bool manual) {
 | 
				
			||||||
  if (this->prevent_ && !manual) {
 | 
					  if (this->prevent_ && !manual) {
 | 
				
			||||||
    this->next_enter_deep_sleep_ = true;
 | 
					    this->next_enter_deep_sleep_ = true;
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					
 | 
				
			||||||
  if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_KEEP_AWAKE && this->wakeup_pin_ != nullptr &&
 | 
					  if (!this->prepare_to_sleep_()) {
 | 
				
			||||||
      !this->sleep_duration_.has_value() && this->wakeup_pin_->digital_read()) {
 | 
					 | 
				
			||||||
    // Defer deep sleep until inactive
 | 
					 | 
				
			||||||
    if (!this->next_enter_deep_sleep_) {
 | 
					 | 
				
			||||||
      this->status_set_warning();
 | 
					 | 
				
			||||||
      ESP_LOGW(TAG, "Waiting for pin_ to switch state to enter deep sleep...");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    this->next_enter_deep_sleep_ = true;
 | 
					 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ESP_LOGI(TAG, "Beginning Deep Sleep");
 | 
					  ESP_LOGI(TAG, "Beginning Deep Sleep");
 | 
				
			||||||
  if (this->sleep_duration_.has_value()) {
 | 
					  if (this->sleep_duration_.has_value()) {
 | 
				
			||||||
@@ -120,47 +63,13 @@ void DeepSleepComponent::begin_sleep(bool manual) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
  App.run_safe_shutdown_hooks();
 | 
					  App.run_safe_shutdown_hooks();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(USE_ESP32)
 | 
					  this->deep_sleep_();
 | 
				
			||||||
#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6)
 | 
					 | 
				
			||||||
  if (this->sleep_duration_.has_value())
 | 
					 | 
				
			||||||
    esp_sleep_enable_timer_wakeup(*this->sleep_duration_);
 | 
					 | 
				
			||||||
  if (this->wakeup_pin_ != nullptr) {
 | 
					 | 
				
			||||||
    bool level = !this->wakeup_pin_->is_inverted();
 | 
					 | 
				
			||||||
    if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) {
 | 
					 | 
				
			||||||
      level = !level;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    esp_sleep_enable_ext0_wakeup(gpio_num_t(this->wakeup_pin_->get_pin()), level);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (this->ext1_wakeup_.has_value()) {
 | 
					 | 
				
			||||||
    esp_sleep_enable_ext1_wakeup(this->ext1_wakeup_->mask, this->ext1_wakeup_->wakeup_mode);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (this->touch_wakeup_.has_value() && *(this->touch_wakeup_)) {
 | 
					 | 
				
			||||||
    esp_sleep_enable_touchpad_wakeup();
 | 
					 | 
				
			||||||
    esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6)
 | 
					 | 
				
			||||||
  if (this->sleep_duration_.has_value())
 | 
					 | 
				
			||||||
    esp_sleep_enable_timer_wakeup(*this->sleep_duration_);
 | 
					 | 
				
			||||||
  if (this->wakeup_pin_ != nullptr) {
 | 
					 | 
				
			||||||
    bool level = !this->wakeup_pin_->is_inverted();
 | 
					 | 
				
			||||||
    if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) {
 | 
					 | 
				
			||||||
      level = !level;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    esp_deep_sleep_enable_gpio_wakeup(1 << this->wakeup_pin_->get_pin(),
 | 
					 | 
				
			||||||
                                      static_cast<esp_deepsleep_gpio_wake_up_mode_t>(level));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  esp_deep_sleep_start();
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_ESP8266
 | 
					 | 
				
			||||||
  ESP.deepSleep(*this->sleep_duration_);  // NOLINT(readability-static-accessed-through-instance)
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
float DeepSleepComponent::get_setup_priority() const { return setup_priority::LATE; }
 | 
					float DeepSleepComponent::get_setup_priority() const { return setup_priority::LATE; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DeepSleepComponent::prevent_deep_sleep() { this->prevent_ = true; }
 | 
					void DeepSleepComponent::prevent_deep_sleep() { this->prevent_ = true; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DeepSleepComponent::allow_deep_sleep() { this->prevent_ = false; }
 | 
					void DeepSleepComponent::allow_deep_sleep() { this->prevent_ = false; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace deep_sleep
 | 
					}  // namespace deep_sleep
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -106,6 +106,10 @@ class DeepSleepComponent : public Component {
 | 
				
			|||||||
  // duration before entering deep sleep.
 | 
					  // duration before entering deep sleep.
 | 
				
			||||||
  optional<uint32_t> get_run_duration_() const;
 | 
					  optional<uint32_t> get_run_duration_() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void dump_config_platform_();
 | 
				
			||||||
 | 
					  bool prepare_to_sleep_();
 | 
				
			||||||
 | 
					  void deep_sleep_();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  optional<uint64_t> sleep_duration_;
 | 
					  optional<uint64_t> sleep_duration_;
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
  InternalGPIOPin *wakeup_pin_;
 | 
					  InternalGPIOPin *wakeup_pin_;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										104
									
								
								esphome/components/deep_sleep/deep_sleep_esp32.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								esphome/components/deep_sleep/deep_sleep_esp32.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
				
			|||||||
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
 | 
					#include "deep_sleep_component.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace deep_sleep {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "deep_sleep";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					optional<uint32_t> DeepSleepComponent::get_run_duration_() const {
 | 
				
			||||||
 | 
					  if (this->wakeup_cause_to_run_duration_.has_value()) {
 | 
				
			||||||
 | 
					    esp_sleep_wakeup_cause_t wakeup_cause = esp_sleep_get_wakeup_cause();
 | 
				
			||||||
 | 
					    switch (wakeup_cause) {
 | 
				
			||||||
 | 
					      case ESP_SLEEP_WAKEUP_EXT0:
 | 
				
			||||||
 | 
					      case ESP_SLEEP_WAKEUP_EXT1:
 | 
				
			||||||
 | 
					      case ESP_SLEEP_WAKEUP_GPIO:
 | 
				
			||||||
 | 
					        return this->wakeup_cause_to_run_duration_->gpio_cause;
 | 
				
			||||||
 | 
					      case ESP_SLEEP_WAKEUP_TOUCHPAD:
 | 
				
			||||||
 | 
					        return this->wakeup_cause_to_run_duration_->touch_cause;
 | 
				
			||||||
 | 
					      default:
 | 
				
			||||||
 | 
					        return this->wakeup_cause_to_run_duration_->default_cause;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return this->run_duration_;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DeepSleepComponent::set_wakeup_pin_mode(WakeupPinMode wakeup_pin_mode) {
 | 
				
			||||||
 | 
					  this->wakeup_pin_mode_ = wakeup_pin_mode;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6)
 | 
				
			||||||
 | 
					void DeepSleepComponent::set_ext1_wakeup(Ext1Wakeup ext1_wakeup) { this->ext1_wakeup_ = ext1_wakeup; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DeepSleepComponent::set_touch_wakeup(bool touch_wakeup) { this->touch_wakeup_ = touch_wakeup; }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DeepSleepComponent::set_run_duration(WakeupCauseToRunDuration wakeup_cause_to_run_duration) {
 | 
				
			||||||
 | 
					  wakeup_cause_to_run_duration_ = wakeup_cause_to_run_duration;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DeepSleepComponent::dump_config_platform_() {
 | 
				
			||||||
 | 
					  if (wakeup_pin_ != nullptr) {
 | 
				
			||||||
 | 
					    LOG_PIN("  Wakeup Pin: ", this->wakeup_pin_);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (this->wakeup_cause_to_run_duration_.has_value()) {
 | 
				
			||||||
 | 
					    ESP_LOGCONFIG(TAG, "  Default Wakeup Run Duration: %" PRIu32 " ms",
 | 
				
			||||||
 | 
					                  this->wakeup_cause_to_run_duration_->default_cause);
 | 
				
			||||||
 | 
					    ESP_LOGCONFIG(TAG, "  Touch Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->touch_cause);
 | 
				
			||||||
 | 
					    ESP_LOGCONFIG(TAG, "  GPIO Wakeup Run Duration: %" PRIu32 " ms", this->wakeup_cause_to_run_duration_->gpio_cause);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool DeepSleepComponent::prepare_to_sleep_() {
 | 
				
			||||||
 | 
					  if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_KEEP_AWAKE && this->wakeup_pin_ != nullptr &&
 | 
				
			||||||
 | 
					      !this->sleep_duration_.has_value() && this->wakeup_pin_->digital_read()) {
 | 
				
			||||||
 | 
					    // Defer deep sleep until inactive
 | 
				
			||||||
 | 
					    if (!this->next_enter_deep_sleep_) {
 | 
				
			||||||
 | 
					      this->status_set_warning();
 | 
				
			||||||
 | 
					      ESP_LOGW(TAG, "Waiting for pin_ to switch state to enter deep sleep...");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this->next_enter_deep_sleep_ = true;
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DeepSleepComponent::deep_sleep_() {
 | 
				
			||||||
 | 
					#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6)
 | 
				
			||||||
 | 
					  if (this->sleep_duration_.has_value())
 | 
				
			||||||
 | 
					    esp_sleep_enable_timer_wakeup(*this->sleep_duration_);
 | 
				
			||||||
 | 
					  if (this->wakeup_pin_ != nullptr) {
 | 
				
			||||||
 | 
					    bool level = !this->wakeup_pin_->is_inverted();
 | 
				
			||||||
 | 
					    if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) {
 | 
				
			||||||
 | 
					      level = !level;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    esp_sleep_enable_ext0_wakeup(gpio_num_t(this->wakeup_pin_->get_pin()), level);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (this->ext1_wakeup_.has_value()) {
 | 
				
			||||||
 | 
					    esp_sleep_enable_ext1_wakeup(this->ext1_wakeup_->mask, this->ext1_wakeup_->wakeup_mode);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (this->touch_wakeup_.has_value() && *(this->touch_wakeup_)) {
 | 
				
			||||||
 | 
					    esp_sleep_enable_touchpad_wakeup();
 | 
				
			||||||
 | 
					    esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6)
 | 
				
			||||||
 | 
					  if (this->sleep_duration_.has_value())
 | 
				
			||||||
 | 
					    esp_sleep_enable_timer_wakeup(*this->sleep_duration_);
 | 
				
			||||||
 | 
					  if (this->wakeup_pin_ != nullptr) {
 | 
				
			||||||
 | 
					    bool level = !this->wakeup_pin_->is_inverted();
 | 
				
			||||||
 | 
					    if (this->wakeup_pin_mode_ == WAKEUP_PIN_MODE_INVERT_WAKEUP && this->wakeup_pin_->digital_read()) {
 | 
				
			||||||
 | 
					      level = !level;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    esp_deep_sleep_enable_gpio_wakeup(1 << this->wakeup_pin_->get_pin(),
 | 
				
			||||||
 | 
					                                      static_cast<esp_deepsleep_gpio_wake_up_mode_t>(level));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					  esp_deep_sleep_start();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace deep_sleep
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										23
									
								
								esphome/components/deep_sleep/deep_sleep_esp8266.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								esphome/components/deep_sleep/deep_sleep_esp8266.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					#ifdef USE_ESP8266
 | 
				
			||||||
 | 
					#include "deep_sleep_component.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <Esp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace deep_sleep {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "deep_sleep";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					optional<uint32_t> DeepSleepComponent::get_run_duration_() const { return this->run_duration_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DeepSleepComponent::dump_config_platform_() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool DeepSleepComponent::prepare_to_sleep_() { return true; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DeepSleepComponent::deep_sleep_() {
 | 
				
			||||||
 | 
					  ESP.deepSleep(*this->sleep_duration_);  // NOLINT(readability-static-accessed-through-instance)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace deep_sleep
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@@ -86,9 +86,14 @@ bool HOT IRAM_ATTR DHT::read_sensor_(float *temperature, float *humidity, bool r
 | 
				
			|||||||
  if (this->model_ == DHT_MODEL_DHT11) {
 | 
					  if (this->model_ == DHT_MODEL_DHT11) {
 | 
				
			||||||
    delayMicroseconds(18000);
 | 
					    delayMicroseconds(18000);
 | 
				
			||||||
  } else if (this->model_ == DHT_MODEL_SI7021) {
 | 
					  } else if (this->model_ == DHT_MODEL_SI7021) {
 | 
				
			||||||
 | 
					#ifdef USE_ESP8266
 | 
				
			||||||
    delayMicroseconds(500);
 | 
					    delayMicroseconds(500);
 | 
				
			||||||
    this->pin_->digital_write(true);
 | 
					    this->pin_->digital_write(true);
 | 
				
			||||||
    delayMicroseconds(40);
 | 
					    delayMicroseconds(40);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    delayMicroseconds(400);
 | 
				
			||||||
 | 
					    this->pin_->digital_write(true);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
  } else if (this->model_ == DHT_MODEL_DHT22_TYPE2) {
 | 
					  } else if (this->model_ == DHT_MODEL_DHT22_TYPE2) {
 | 
				
			||||||
    delayMicroseconds(2000);
 | 
					    delayMicroseconds(2000);
 | 
				
			||||||
  } else if (this->model_ == DHT_MODEL_AM2120 || this->model_ == DHT_MODEL_AM2302) {
 | 
					  } else if (this->model_ == DHT_MODEL_AM2120 || this->model_ == DHT_MODEL_AM2302) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@ CHANNELS = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
CONF_UNIVERSE = "universe"
 | 
					CONF_UNIVERSE = "universe"
 | 
				
			||||||
CONF_E131_ID = "e131_id"
 | 
					CONF_E131_ID = "e131_id"
 | 
				
			||||||
 | 
					CONF_CHANNEL_OFFSET = "channel_offset"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONFIG_SCHEMA = cv.Schema(
 | 
					CONFIG_SCHEMA = cv.Schema(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -46,6 +47,7 @@ async def to_code(config):
 | 
				
			|||||||
        cv.GenerateID(CONF_E131_ID): cv.use_id(E131Component),
 | 
					        cv.GenerateID(CONF_E131_ID): cv.use_id(E131Component),
 | 
				
			||||||
        cv.Required(CONF_UNIVERSE): cv.int_range(min=1, max=512),
 | 
					        cv.Required(CONF_UNIVERSE): cv.int_range(min=1, max=512),
 | 
				
			||||||
        cv.Optional(CONF_CHANNELS, default="RGB"): cv.one_of(*CHANNELS, upper=True),
 | 
					        cv.Optional(CONF_CHANNELS, default="RGB"): cv.one_of(*CHANNELS, upper=True),
 | 
				
			||||||
 | 
					        cv.Optional(CONF_CHANNEL_OFFSET, default=0): cv.int_range(min=0, max=512),
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
async def e131_light_effect_to_code(config, effect_id):
 | 
					async def e131_light_effect_to_code(config, effect_id):
 | 
				
			||||||
@@ -54,5 +56,6 @@ async def e131_light_effect_to_code(config, effect_id):
 | 
				
			|||||||
    effect = cg.new_Pvariable(effect_id, config[CONF_NAME])
 | 
					    effect = cg.new_Pvariable(effect_id, config[CONF_NAME])
 | 
				
			||||||
    cg.add(effect.set_first_universe(config[CONF_UNIVERSE]))
 | 
					    cg.add(effect.set_first_universe(config[CONF_UNIVERSE]))
 | 
				
			||||||
    cg.add(effect.set_channels(CHANNELS[config[CONF_CHANNELS]]))
 | 
					    cg.add(effect.set_channels(CHANNELS[config[CONF_CHANNELS]]))
 | 
				
			||||||
 | 
					    cg.add(effect.set_channel_offset(config[CONF_CHANNEL_OFFSET]))
 | 
				
			||||||
    cg.add(effect.set_e131(parent))
 | 
					    cg.add(effect.set_e131(parent))
 | 
				
			||||||
    return effect
 | 
					    return effect
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,7 +55,7 @@ bool E131AddressableLightEffect::process_(int universe, const E131Packet &packet
 | 
				
			|||||||
  // limit amount of lights per universe and received
 | 
					  // limit amount of lights per universe and received
 | 
				
			||||||
  int output_end =
 | 
					  int output_end =
 | 
				
			||||||
      std::min(it->size(), std::min(output_offset + get_lights_per_universe(), output_offset + packet.count - 1));
 | 
					      std::min(it->size(), std::min(output_offset + get_lights_per_universe(), output_offset + packet.count - 1));
 | 
				
			||||||
  auto *input_data = packet.values + 1;
 | 
					  auto *input_data = packet.values + 1 + (this->channel_offset_ * this->channels_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ESP_LOGV(TAG, "Applying data for '%s' on %d universe, for %" PRId32 "-%d.", get_name().c_str(), universe,
 | 
					  ESP_LOGV(TAG, "Applying data for '%s' on %d universe, for %" PRId32 "-%d.", get_name().c_str(), universe,
 | 
				
			||||||
           output_offset, output_end);
 | 
					           output_offset, output_end);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,7 @@ class E131AddressableLightEffect : public light::AddressableLightEffect {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  void set_first_universe(int universe) { this->first_universe_ = universe; }
 | 
					  void set_first_universe(int universe) { this->first_universe_ = universe; }
 | 
				
			||||||
  void set_channels(E131LightChannels channels) { this->channels_ = channels; }
 | 
					  void set_channels(E131LightChannels channels) { this->channels_ = channels; }
 | 
				
			||||||
 | 
					  void set_channel_offset(int offset) { this->channel_offset_ = offset; }
 | 
				
			||||||
  void set_e131(E131Component *e131) { this->e131_ = e131; }
 | 
					  void set_e131(E131Component *e131) { this->e131_ = e131; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
@@ -34,6 +35,7 @@ class E131AddressableLightEffect : public light::AddressableLightEffect {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  int first_universe_{0};
 | 
					  int first_universe_{0};
 | 
				
			||||||
  int last_universe_{0};
 | 
					  int last_universe_{0};
 | 
				
			||||||
 | 
					  int channel_offset_{0};
 | 
				
			||||||
  E131LightChannels channels_{E131_RGB};
 | 
					  E131LightChannels channels_{E131_RGB};
 | 
				
			||||||
  E131Component *e131_{nullptr};
 | 
					  E131Component *e131_{nullptr};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
CODEOWNERS = ["@vincentscode"]
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,87 +1,7 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.components import i2c, sensor
 | 
					
 | 
				
			||||||
from esphome.const import (
 | 
					CODEOWNERS = ["@latonita"]
 | 
				
			||||||
    CONF_COMPENSATION,
 | 
					
 | 
				
			||||||
    CONF_ECO2,
 | 
					CONFIG_SCHEMA = CONFIG_SCHEMA = cv.invalid(
 | 
				
			||||||
    CONF_HUMIDITY,
 | 
					    "The ens160 sensor component has been renamed to ens160_i2c."
 | 
				
			||||||
    CONF_ID,
 | 
					 | 
				
			||||||
    CONF_TEMPERATURE,
 | 
					 | 
				
			||||||
    CONF_TVOC,
 | 
					 | 
				
			||||||
    DEVICE_CLASS_AQI,
 | 
					 | 
				
			||||||
    DEVICE_CLASS_CARBON_DIOXIDE,
 | 
					 | 
				
			||||||
    DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
 | 
					 | 
				
			||||||
    ICON_CHEMICAL_WEAPON,
 | 
					 | 
				
			||||||
    ICON_MOLECULE_CO2,
 | 
					 | 
				
			||||||
    ICON_RADIATOR,
 | 
					 | 
				
			||||||
    STATE_CLASS_MEASUREMENT,
 | 
					 | 
				
			||||||
    UNIT_PARTS_PER_BILLION,
 | 
					 | 
				
			||||||
    UNIT_PARTS_PER_MILLION,
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					 | 
				
			||||||
CODEOWNERS = ["@vincentscode"]
 | 
					 | 
				
			||||||
DEPENDENCIES = ["i2c"]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ens160_ns = cg.esphome_ns.namespace("ens160")
 | 
					 | 
				
			||||||
ENS160Component = ens160_ns.class_(
 | 
					 | 
				
			||||||
    "ENS160Component", cg.PollingComponent, i2c.I2CDevice, sensor.Sensor
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CONF_AQI = "aqi"
 | 
					 | 
				
			||||||
UNIT_INDEX = "index"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CONFIG_SCHEMA = (
 | 
					 | 
				
			||||||
    cv.Schema(
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            cv.GenerateID(): cv.declare_id(ENS160Component),
 | 
					 | 
				
			||||||
            cv.Required(CONF_ECO2): sensor.sensor_schema(
 | 
					 | 
				
			||||||
                unit_of_measurement=UNIT_PARTS_PER_MILLION,
 | 
					 | 
				
			||||||
                icon=ICON_MOLECULE_CO2,
 | 
					 | 
				
			||||||
                accuracy_decimals=0,
 | 
					 | 
				
			||||||
                device_class=DEVICE_CLASS_CARBON_DIOXIDE,
 | 
					 | 
				
			||||||
                state_class=STATE_CLASS_MEASUREMENT,
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            cv.Required(CONF_TVOC): sensor.sensor_schema(
 | 
					 | 
				
			||||||
                unit_of_measurement=UNIT_PARTS_PER_BILLION,
 | 
					 | 
				
			||||||
                icon=ICON_RADIATOR,
 | 
					 | 
				
			||||||
                accuracy_decimals=0,
 | 
					 | 
				
			||||||
                device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
 | 
					 | 
				
			||||||
                state_class=STATE_CLASS_MEASUREMENT,
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            cv.Required(CONF_AQI): sensor.sensor_schema(
 | 
					 | 
				
			||||||
                icon=ICON_CHEMICAL_WEAPON,
 | 
					 | 
				
			||||||
                accuracy_decimals=0,
 | 
					 | 
				
			||||||
                device_class=DEVICE_CLASS_AQI,
 | 
					 | 
				
			||||||
                state_class=STATE_CLASS_MEASUREMENT,
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            cv.Optional(CONF_COMPENSATION): cv.Schema(
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    cv.Required(CONF_TEMPERATURE): cv.use_id(sensor.Sensor),
 | 
					 | 
				
			||||||
                    cv.Required(CONF_HUMIDITY): cv.use_id(sensor.Sensor),
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    .extend(cv.polling_component_schema("60s"))
 | 
					 | 
				
			||||||
    .extend(i2c.i2c_device_schema(0x53))
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
async def to_code(config):
 | 
					 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					 | 
				
			||||||
    await cg.register_component(var, config)
 | 
					 | 
				
			||||||
    await i2c.register_i2c_device(var, config)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sens = await sensor.new_sensor(config[CONF_ECO2])
 | 
					 | 
				
			||||||
    cg.add(var.set_co2(sens))
 | 
					 | 
				
			||||||
    sens = await sensor.new_sensor(config[CONF_TVOC])
 | 
					 | 
				
			||||||
    cg.add(var.set_tvoc(sens))
 | 
					 | 
				
			||||||
    sens = await sensor.new_sensor(config[CONF_AQI])
 | 
					 | 
				
			||||||
    cg.add(var.set_aqi(sens))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if CONF_COMPENSATION in config:
 | 
					 | 
				
			||||||
        compensation_config = config[CONF_COMPENSATION]
 | 
					 | 
				
			||||||
        sens = await cg.get_variable(compensation_config[CONF_TEMPERATURE])
 | 
					 | 
				
			||||||
        cg.add(var.set_temperature(sens))
 | 
					 | 
				
			||||||
        sens = await cg.get_variable(compensation_config[CONF_HUMIDITY])
 | 
					 | 
				
			||||||
        cg.add(var.set_humidity(sens))
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										78
									
								
								esphome/components/ens160_base/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								esphome/components/ens160_base/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,78 @@
 | 
				
			|||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome.components import sensor
 | 
				
			||||||
 | 
					from esphome.const import (
 | 
				
			||||||
 | 
					    CONF_COMPENSATION,
 | 
				
			||||||
 | 
					    CONF_ECO2,
 | 
				
			||||||
 | 
					    CONF_HUMIDITY,
 | 
				
			||||||
 | 
					    CONF_ID,
 | 
				
			||||||
 | 
					    CONF_TEMPERATURE,
 | 
				
			||||||
 | 
					    CONF_TVOC,
 | 
				
			||||||
 | 
					    DEVICE_CLASS_AQI,
 | 
				
			||||||
 | 
					    DEVICE_CLASS_CARBON_DIOXIDE,
 | 
				
			||||||
 | 
					    DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
 | 
				
			||||||
 | 
					    ICON_CHEMICAL_WEAPON,
 | 
				
			||||||
 | 
					    ICON_MOLECULE_CO2,
 | 
				
			||||||
 | 
					    ICON_RADIATOR,
 | 
				
			||||||
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					    UNIT_PARTS_PER_BILLION,
 | 
				
			||||||
 | 
					    UNIT_PARTS_PER_MILLION,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CODEOWNERS = ["@vincentscode", "@latonita"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ens160_ns = cg.esphome_ns.namespace("ens160_base")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONF_AQI = "aqi"
 | 
				
			||||||
 | 
					UNIT_INDEX = "index"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONFIG_SCHEMA_BASE = cv.Schema(
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cv.Required(CONF_ECO2): sensor.sensor_schema(
 | 
				
			||||||
 | 
					            unit_of_measurement=UNIT_PARTS_PER_MILLION,
 | 
				
			||||||
 | 
					            icon=ICON_MOLECULE_CO2,
 | 
				
			||||||
 | 
					            accuracy_decimals=0,
 | 
				
			||||||
 | 
					            device_class=DEVICE_CLASS_CARBON_DIOXIDE,
 | 
				
			||||||
 | 
					            state_class=STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        cv.Required(CONF_TVOC): sensor.sensor_schema(
 | 
				
			||||||
 | 
					            unit_of_measurement=UNIT_PARTS_PER_BILLION,
 | 
				
			||||||
 | 
					            icon=ICON_RADIATOR,
 | 
				
			||||||
 | 
					            accuracy_decimals=0,
 | 
				
			||||||
 | 
					            device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
 | 
				
			||||||
 | 
					            state_class=STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        cv.Required(CONF_AQI): sensor.sensor_schema(
 | 
				
			||||||
 | 
					            icon=ICON_CHEMICAL_WEAPON,
 | 
				
			||||||
 | 
					            accuracy_decimals=0,
 | 
				
			||||||
 | 
					            device_class=DEVICE_CLASS_AQI,
 | 
				
			||||||
 | 
					            state_class=STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        cv.Optional(CONF_COMPENSATION): cv.Schema(
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                cv.Required(CONF_TEMPERATURE): cv.use_id(sensor.Sensor),
 | 
				
			||||||
 | 
					                cv.Required(CONF_HUMIDITY): cv.use_id(sensor.Sensor),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					).extend(cv.polling_component_schema("60s"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def to_code_base(config):
 | 
				
			||||||
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sens = await sensor.new_sensor(config[CONF_ECO2])
 | 
				
			||||||
 | 
					    cg.add(var.set_co2(sens))
 | 
				
			||||||
 | 
					    sens = await sensor.new_sensor(config[CONF_TVOC])
 | 
				
			||||||
 | 
					    cg.add(var.set_tvoc(sens))
 | 
				
			||||||
 | 
					    sens = await sensor.new_sensor(config[CONF_AQI])
 | 
				
			||||||
 | 
					    cg.add(var.set_aqi(sens))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if compensation_config := config.get(CONF_COMPENSATION):
 | 
				
			||||||
 | 
					        sens = await cg.get_variable(compensation_config[CONF_TEMPERATURE])
 | 
				
			||||||
 | 
					        cg.add(var.set_temperature(sens))
 | 
				
			||||||
 | 
					        sens = await cg.get_variable(compensation_config[CONF_HUMIDITY])
 | 
				
			||||||
 | 
					        cg.add(var.set_humidity(sens))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return var
 | 
				
			||||||
@@ -5,12 +5,12 @@
 | 
				
			|||||||
// Implementation based on:
 | 
					// Implementation based on:
 | 
				
			||||||
//   https://github.com/sciosense/ENS160_driver
 | 
					//   https://github.com/sciosense/ENS160_driver
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "ens160.h"
 | 
					#include "ens160_base.h"
 | 
				
			||||||
#include "esphome/core/log.h"
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
#include "esphome/core/hal.h"
 | 
					#include "esphome/core/hal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace ens160 {
 | 
					namespace ens160_base {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *const TAG = "ens160";
 | 
					static const char *const TAG = "ens160";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -303,7 +303,6 @@ void ENS160Component::dump_config() {
 | 
				
			|||||||
  ESP_LOGI(TAG, "Firmware Version: %d.%d.%d", this->firmware_ver_major_, this->firmware_ver_minor_,
 | 
					  ESP_LOGI(TAG, "Firmware Version: %d.%d.%d", this->firmware_ver_major_, this->firmware_ver_minor_,
 | 
				
			||||||
           this->firmware_ver_build_);
 | 
					           this->firmware_ver_build_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  LOG_I2C_DEVICE(this);
 | 
					 | 
				
			||||||
  LOG_UPDATE_INTERVAL(this);
 | 
					  LOG_UPDATE_INTERVAL(this);
 | 
				
			||||||
  LOG_SENSOR("  ", "CO2 Sensor:", this->co2_);
 | 
					  LOG_SENSOR("  ", "CO2 Sensor:", this->co2_);
 | 
				
			||||||
  LOG_SENSOR("  ", "TVOC Sensor:", this->tvoc_);
 | 
					  LOG_SENSOR("  ", "TVOC Sensor:", this->tvoc_);
 | 
				
			||||||
@@ -317,5 +316,5 @@ void ENS160Component::dump_config() {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace ens160
 | 
					}  // namespace ens160_base
 | 
				
			||||||
}  // namespace esphome
 | 
					}  // namespace esphome
 | 
				
			||||||
@@ -2,12 +2,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "esphome/core/component.h"
 | 
					#include "esphome/core/component.h"
 | 
				
			||||||
#include "esphome/components/sensor/sensor.h"
 | 
					#include "esphome/components/sensor/sensor.h"
 | 
				
			||||||
#include "esphome/components/i2c/i2c.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace ens160 {
 | 
					namespace ens160_base {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ENS160Component : public PollingComponent, public i2c::I2CDevice, public sensor::Sensor {
 | 
					class ENS160Component : public PollingComponent, public sensor::Sensor {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  void set_co2(sensor::Sensor *co2) { co2_ = co2; }
 | 
					  void set_co2(sensor::Sensor *co2) { co2_ = co2; }
 | 
				
			||||||
  void set_tvoc(sensor::Sensor *tvoc) { tvoc_ = tvoc; }
 | 
					  void set_tvoc(sensor::Sensor *tvoc) { tvoc_ = tvoc; }
 | 
				
			||||||
@@ -44,6 +43,11 @@ class ENS160Component : public PollingComponent, public i2c::I2CDevice, public s
 | 
				
			|||||||
  bool warming_up_{false};
 | 
					  bool warming_up_{false};
 | 
				
			||||||
  bool initial_startup_{false};
 | 
					  bool initial_startup_{false};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  virtual bool read_byte(uint8_t a_register, uint8_t *data) = 0;
 | 
				
			||||||
 | 
					  virtual bool write_byte(uint8_t a_register, uint8_t data) = 0;
 | 
				
			||||||
 | 
					  virtual bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) = 0;
 | 
				
			||||||
 | 
					  virtual bool write_bytes(uint8_t a_register, uint8_t *data, size_t len) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  uint8_t firmware_ver_major_{0};
 | 
					  uint8_t firmware_ver_major_{0};
 | 
				
			||||||
  uint8_t firmware_ver_minor_{0};
 | 
					  uint8_t firmware_ver_minor_{0};
 | 
				
			||||||
  uint8_t firmware_ver_build_{0};
 | 
					  uint8_t firmware_ver_build_{0};
 | 
				
			||||||
@@ -56,5 +60,5 @@ class ENS160Component : public PollingComponent, public i2c::I2CDevice, public s
 | 
				
			|||||||
  sensor::Sensor *temperature_{nullptr};
 | 
					  sensor::Sensor *temperature_{nullptr};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace ens160
 | 
					}  // namespace ens160_base
 | 
				
			||||||
}  // namespace esphome
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										0
									
								
								esphome/components/ens160_i2c/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								esphome/components/ens160_i2c/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										32
									
								
								esphome/components/ens160_i2c/ens160_i2c.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								esphome/components/ens160_i2c/ens160_i2c.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					#include <cstddef>
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ens160_i2c.h"
 | 
				
			||||||
 | 
					#include "esphome/components/i2c/i2c.h"
 | 
				
			||||||
 | 
					#include "../ens160_base/ens160_base.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace ens160_i2c {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "ens160_i2c.sensor";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ENS160I2CComponent::read_byte(uint8_t a_register, uint8_t *data) {
 | 
				
			||||||
 | 
					  return I2CDevice::read_byte(a_register, data);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					bool ENS160I2CComponent::write_byte(uint8_t a_register, uint8_t data) {
 | 
				
			||||||
 | 
					  return I2CDevice::write_byte(a_register, data);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					bool ENS160I2CComponent::read_bytes(uint8_t a_register, uint8_t *data, size_t len) {
 | 
				
			||||||
 | 
					  return I2CDevice::read_bytes(a_register, data, len);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					bool ENS160I2CComponent::write_bytes(uint8_t a_register, uint8_t *data, size_t len) {
 | 
				
			||||||
 | 
					  return I2CDevice::write_bytes(a_register, data, len);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ENS160I2CComponent::dump_config() {
 | 
				
			||||||
 | 
					  ENS160Component::dump_config();
 | 
				
			||||||
 | 
					  LOG_I2C_DEVICE(this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace ens160_i2c
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										19
									
								
								esphome/components/ens160_i2c/ens160_i2c.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								esphome/components/ens160_i2c/ens160_i2c.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "esphome/components/ens160_base/ens160_base.h"
 | 
				
			||||||
 | 
					#include "esphome/components/i2c/i2c.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace ens160_i2c {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ENS160I2CComponent : public esphome::ens160_base::ENS160Component, public i2c::I2CDevice {
 | 
				
			||||||
 | 
					  void dump_config() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool read_byte(uint8_t a_register, uint8_t *data) override;
 | 
				
			||||||
 | 
					  bool write_byte(uint8_t a_register, uint8_t data) override;
 | 
				
			||||||
 | 
					  bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) override;
 | 
				
			||||||
 | 
					  bool write_bytes(uint8_t a_register, uint8_t *data, size_t len) override;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace ens160_i2c
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										22
									
								
								esphome/components/ens160_i2c/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								esphome/components/ens160_i2c/sensor.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					from esphome.components import i2c
 | 
				
			||||||
 | 
					from ..ens160_base import to_code_base, cv, CONFIG_SCHEMA_BASE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AUTO_LOAD = ["ens160_base"]
 | 
				
			||||||
 | 
					CODEOWNERS = ["@latonita"]
 | 
				
			||||||
 | 
					DEPENDENCIES = ["i2c"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ens160_ns = cg.esphome_ns.namespace("ens160_i2c")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ENS160I2CComponent = ens160_ns.class_(
 | 
				
			||||||
 | 
					    "ENS160I2CComponent", cg.PollingComponent, i2c.I2CDevice
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend(
 | 
				
			||||||
 | 
					    i2c.i2c_device_schema(default_address=0x52)
 | 
				
			||||||
 | 
					).extend({cv.GenerateID(): cv.declare_id(ENS160I2CComponent)})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def to_code(config):
 | 
				
			||||||
 | 
					    var = await to_code_base(config)
 | 
				
			||||||
 | 
					    await i2c.register_i2c_device(var, config)
 | 
				
			||||||
							
								
								
									
										0
									
								
								esphome/components/ens160_spi/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								esphome/components/ens160_spi/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										59
									
								
								esphome/components/ens160_spi/ens160_spi.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								esphome/components/ens160_spi/ens160_spi.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
				
			|||||||
 | 
					#include <cstdint>
 | 
				
			||||||
 | 
					#include <cstddef>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ens160_spi.h"
 | 
				
			||||||
 | 
					#include <esphome/components/ens160_base/ens160_base.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace ens160_spi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "ens160_spi.sensor";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline uint8_t reg_read(uint8_t reg) { return (reg << 1) | 0x01; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline uint8_t reg_write(uint8_t reg) { return (reg << 1) & 0xFE; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ENS160SPIComponent::setup() {
 | 
				
			||||||
 | 
					  this->spi_setup();
 | 
				
			||||||
 | 
					  ENS160Component::setup();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ENS160SPIComponent::dump_config() {
 | 
				
			||||||
 | 
					  ENS160Component::dump_config();
 | 
				
			||||||
 | 
					  LOG_PIN("  CS Pin: ", this->cs_);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ENS160SPIComponent::read_byte(uint8_t a_register, uint8_t *data) {
 | 
				
			||||||
 | 
					  this->enable();
 | 
				
			||||||
 | 
					  this->transfer_byte(reg_read(a_register));
 | 
				
			||||||
 | 
					  *data = this->transfer_byte(0);
 | 
				
			||||||
 | 
					  this->disable();
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ENS160SPIComponent::write_byte(uint8_t a_register, uint8_t data) {
 | 
				
			||||||
 | 
					  this->enable();
 | 
				
			||||||
 | 
					  this->transfer_byte(reg_write(a_register));
 | 
				
			||||||
 | 
					  this->transfer_byte(data);
 | 
				
			||||||
 | 
					  this->disable();
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ENS160SPIComponent::read_bytes(uint8_t a_register, uint8_t *data, size_t len) {
 | 
				
			||||||
 | 
					  this->enable();
 | 
				
			||||||
 | 
					  this->transfer_byte(reg_read(a_register));
 | 
				
			||||||
 | 
					  this->read_array(data, len);
 | 
				
			||||||
 | 
					  this->disable();
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ENS160SPIComponent::write_bytes(uint8_t a_register, uint8_t *data, size_t len) {
 | 
				
			||||||
 | 
					  this->enable();
 | 
				
			||||||
 | 
					  this->transfer_byte(reg_write(a_register));
 | 
				
			||||||
 | 
					  this->transfer_array(data, len);
 | 
				
			||||||
 | 
					  this->disable();
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace ens160_spi
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										22
									
								
								esphome/components/ens160_spi/ens160_spi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								esphome/components/ens160_spi/ens160_spi.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "esphome/components/ens160_base/ens160_base.h"
 | 
				
			||||||
 | 
					#include "esphome/components/spi/spi.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace ens160_spi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ENS160SPIComponent : public esphome::ens160_base::ENS160Component,
 | 
				
			||||||
 | 
					                           public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
 | 
				
			||||||
 | 
					                                                 spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_200KHZ> {
 | 
				
			||||||
 | 
					  void setup() override;
 | 
				
			||||||
 | 
					  void dump_config() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool read_byte(uint8_t a_register, uint8_t *data) override;
 | 
				
			||||||
 | 
					  bool write_byte(uint8_t a_register, uint8_t data) override;
 | 
				
			||||||
 | 
					  bool read_bytes(uint8_t a_register, uint8_t *data, size_t len) override;
 | 
				
			||||||
 | 
					  bool write_bytes(uint8_t a_register, uint8_t *data, size_t len) override;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace ens160_spi
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										22
									
								
								esphome/components/ens160_spi/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								esphome/components/ens160_spi/sensor.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					from esphome.components import spi
 | 
				
			||||||
 | 
					from ..ens160_base import to_code_base, cv, CONFIG_SCHEMA_BASE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AUTO_LOAD = ["ens160_base"]
 | 
				
			||||||
 | 
					CODEOWNERS = ["@latonita"]
 | 
				
			||||||
 | 
					DEPENDENCIES = ["spi"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ens160_spi_ns = cg.esphome_ns.namespace("ens160_spi")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ENS160SPIComponent = ens160_spi_ns.class_(
 | 
				
			||||||
 | 
					    "ENS160SPIComponent", cg.PollingComponent, spi.SPIDevice
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONFIG_SCHEMA = CONFIG_SCHEMA_BASE.extend(spi.spi_device_schema()).extend(
 | 
				
			||||||
 | 
					    {cv.GenerateID(): cv.declare_id(ENS160SPIComponent)}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def to_code(config):
 | 
				
			||||||
 | 
					    var = await to_code_base(config)
 | 
				
			||||||
 | 
					    await spi.register_spi_device(var, config)
 | 
				
			||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
from dataclasses import dataclass
 | 
					from dataclasses import dataclass
 | 
				
			||||||
from typing import Any
 | 
					from typing import Any
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_ID,
 | 
					    CONF_ID,
 | 
				
			||||||
@@ -8,6 +9,7 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_NUMBER,
 | 
					    CONF_NUMBER,
 | 
				
			||||||
    CONF_OPEN_DRAIN,
 | 
					    CONF_OPEN_DRAIN,
 | 
				
			||||||
    CONF_OUTPUT,
 | 
					    CONF_OUTPUT,
 | 
				
			||||||
 | 
					    CONF_IGNORE_PIN_VALIDATION_ERROR,
 | 
				
			||||||
    CONF_IGNORE_STRAPPING_WARNING,
 | 
					    CONF_IGNORE_STRAPPING_WARNING,
 | 
				
			||||||
    PLATFORM_ESP32,
 | 
					    PLATFORM_ESP32,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -42,6 +44,9 @@ from .gpio_esp32_h2 import esp32_h2_validate_gpio_pin, esp32_h2_validate_support
 | 
				
			|||||||
ESP32InternalGPIOPin = esp32_ns.class_("ESP32InternalGPIOPin", cg.InternalGPIOPin)
 | 
					ESP32InternalGPIOPin = esp32_ns.class_("ESP32InternalGPIOPin", cg.InternalGPIOPin)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_LOGGER = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _lookup_pin(value):
 | 
					def _lookup_pin(value):
 | 
				
			||||||
    board = CORE.data[KEY_ESP32][KEY_BOARD]
 | 
					    board = CORE.data[KEY_ESP32][KEY_BOARD]
 | 
				
			||||||
    board_pins = boards.ESP32_BOARD_PINS.get(board, {})
 | 
					    board_pins = boards.ESP32_BOARD_PINS.get(board, {})
 | 
				
			||||||
@@ -111,7 +116,7 @@ _esp32_validations = {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def validate_gpio_pin(value):
 | 
					def gpio_pin_number_validator(value):
 | 
				
			||||||
    value = _translate_pin(value)
 | 
					    value = _translate_pin(value)
 | 
				
			||||||
    board = CORE.data[KEY_ESP32][KEY_BOARD]
 | 
					    board = CORE.data[KEY_ESP32][KEY_BOARD]
 | 
				
			||||||
    board_pins = boards.ESP32_BOARD_PINS.get(board, {})
 | 
					    board_pins = boards.ESP32_BOARD_PINS.get(board, {})
 | 
				
			||||||
@@ -127,7 +132,33 @@ def validate_gpio_pin(value):
 | 
				
			|||||||
    if variant not in _esp32_validations:
 | 
					    if variant not in _esp32_validations:
 | 
				
			||||||
        raise cv.Invalid(f"Unsupported ESP32 variant {variant}")
 | 
					        raise cv.Invalid(f"Unsupported ESP32 variant {variant}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return _esp32_validations[variant].pin_validation(value)
 | 
					    return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def validate_gpio_pin(pin):
 | 
				
			||||||
 | 
					    variant = CORE.data[KEY_ESP32][KEY_VARIANT]
 | 
				
			||||||
 | 
					    if variant not in _esp32_validations:
 | 
				
			||||||
 | 
					        raise cv.Invalid(f"Unsupported ESP32 variant {variant}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ignore_pin_validation_warning = pin[CONF_IGNORE_PIN_VALIDATION_ERROR]
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        pin[CONF_NUMBER] = _esp32_validations[variant].pin_validation(pin[CONF_NUMBER])
 | 
				
			||||||
 | 
					    except cv.Invalid as exc:
 | 
				
			||||||
 | 
					        if not ignore_pin_validation_warning:
 | 
				
			||||||
 | 
					            raise
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _LOGGER.warning(
 | 
				
			||||||
 | 
					            "Ignoring validation error on pin %d; error: %s",
 | 
				
			||||||
 | 
					            pin[CONF_NUMBER],
 | 
				
			||||||
 | 
					            exc,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        # Throw an exception if used for a pin that would not have resulted
 | 
				
			||||||
 | 
					        # in a validation error anyway!
 | 
				
			||||||
 | 
					        if ignore_pin_validation_warning:
 | 
				
			||||||
 | 
					            raise cv.Invalid(f"GPIO{pin[CONF_NUMBER]} is not a reserved pin")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return pin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def validate_supports(value):
 | 
					def validate_supports(value):
 | 
				
			||||||
@@ -158,9 +189,11 @@ DRIVE_STRENGTHS = {
 | 
				
			|||||||
gpio_num_t = cg.global_ns.enum("gpio_num_t")
 | 
					gpio_num_t = cg.global_ns.enum("gpio_num_t")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONF_DRIVE_STRENGTH = "drive_strength"
 | 
					CONF_DRIVE_STRENGTH = "drive_strength"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ESP32_PIN_SCHEMA = cv.All(
 | 
					ESP32_PIN_SCHEMA = cv.All(
 | 
				
			||||||
    pins.gpio_base_schema(ESP32InternalGPIOPin, validate_gpio_pin).extend(
 | 
					    pins.gpio_base_schema(ESP32InternalGPIOPin, gpio_pin_number_validator).extend(
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            cv.Optional(CONF_IGNORE_PIN_VALIDATION_ERROR, default=False): cv.boolean,
 | 
				
			||||||
            cv.Optional(CONF_IGNORE_STRAPPING_WARNING, default=False): cv.boolean,
 | 
					            cv.Optional(CONF_IGNORE_STRAPPING_WARNING, default=False): cv.boolean,
 | 
				
			||||||
            cv.Optional(CONF_DRIVE_STRENGTH, default="20mA"): cv.All(
 | 
					            cv.Optional(CONF_DRIVE_STRENGTH, default="20mA"): cv.All(
 | 
				
			||||||
                cv.float_with_unit("current", "mA", optional_unit=True),
 | 
					                cv.float_with_unit("current", "mA", optional_unit=True),
 | 
				
			||||||
@@ -168,6 +201,7 @@ ESP32_PIN_SCHEMA = cv.All(
 | 
				
			|||||||
            ),
 | 
					            ),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
 | 
					    validate_gpio_pin,
 | 
				
			||||||
    validate_supports,
 | 
					    validate_supports,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,11 @@
 | 
				
			|||||||
#ifdef USE_ESP32
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "ble.h"
 | 
					#include "ble.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_ESP32_VARIANT_ESP32C6
 | 
				
			||||||
 | 
					#include "const_esp32c6.h"
 | 
				
			||||||
 | 
					#endif  // USE_ESP32_VARIANT_ESP32C6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "esphome/core/application.h"
 | 
					#include "esphome/core/application.h"
 | 
				
			||||||
#include "esphome/core/log.h"
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -114,7 +119,11 @@ bool ESP32BLE::ble_setup_() {
 | 
				
			|||||||
  if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
 | 
					  if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) {
 | 
				
			||||||
    // start bt controller
 | 
					    // start bt controller
 | 
				
			||||||
    if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) {
 | 
					    if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE) {
 | 
				
			||||||
 | 
					#ifdef USE_ESP32_VARIANT_ESP32C6
 | 
				
			||||||
 | 
					      esp_bt_controller_config_t cfg = BT_CONTROLLER_CONFIG;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
      esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
 | 
					      esp_bt_controller_config_t cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
      err = esp_bt_controller_init(&cfg);
 | 
					      err = esp_bt_controller_init(&cfg);
 | 
				
			||||||
      if (err != ESP_OK) {
 | 
					      if (err != ESP_OK) {
 | 
				
			||||||
        ESP_LOGE(TAG, "esp_bt_controller_init failed: %s", esp_err_to_name(err));
 | 
					        ESP_LOGE(TAG, "esp_bt_controller_init failed: %s", esp_err_to_name(err));
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										67
									
								
								esphome/components/esp32_ble/const_esp32c6.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								esphome/components/esp32_ble/const_esp32c6.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_ESP32_VARIANT_ESP32C6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <esp_bt.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace esp32_ble {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const esp_bt_controller_config_t BT_CONTROLLER_CONFIG = {
 | 
				
			||||||
 | 
					    .config_version = CONFIG_VERSION,
 | 
				
			||||||
 | 
					    .ble_ll_resolv_list_size = CONFIG_BT_LE_LL_RESOLV_LIST_SIZE,
 | 
				
			||||||
 | 
					    .ble_hci_evt_hi_buf_count = DEFAULT_BT_LE_HCI_EVT_HI_BUF_COUNT,
 | 
				
			||||||
 | 
					    .ble_hci_evt_lo_buf_count = DEFAULT_BT_LE_HCI_EVT_LO_BUF_COUNT,
 | 
				
			||||||
 | 
					    .ble_ll_sync_list_cnt = DEFAULT_BT_LE_MAX_PERIODIC_ADVERTISER_LIST,
 | 
				
			||||||
 | 
					    .ble_ll_sync_cnt = DEFAULT_BT_LE_MAX_PERIODIC_SYNCS,
 | 
				
			||||||
 | 
					    .ble_ll_rsp_dup_list_count = CONFIG_BT_LE_LL_DUP_SCAN_LIST_COUNT,
 | 
				
			||||||
 | 
					    .ble_ll_adv_dup_list_count = CONFIG_BT_LE_LL_DUP_SCAN_LIST_COUNT,
 | 
				
			||||||
 | 
					    .ble_ll_tx_pwr_dbm = BLE_LL_TX_PWR_DBM_N,
 | 
				
			||||||
 | 
					    .rtc_freq = RTC_FREQ_N,
 | 
				
			||||||
 | 
					    .ble_ll_sca = CONFIG_BT_LE_LL_SCA,
 | 
				
			||||||
 | 
					    .ble_ll_scan_phy_number = BLE_LL_SCAN_PHY_NUMBER_N,
 | 
				
			||||||
 | 
					    .ble_ll_conn_def_auth_pyld_tmo = BLE_LL_CONN_DEF_AUTH_PYLD_TMO_N,
 | 
				
			||||||
 | 
					    .ble_ll_jitter_usecs = BLE_LL_JITTER_USECS_N,
 | 
				
			||||||
 | 
					    .ble_ll_sched_max_adv_pdu_usecs = BLE_LL_SCHED_MAX_ADV_PDU_USECS_N,
 | 
				
			||||||
 | 
					    .ble_ll_sched_direct_adv_max_usecs = BLE_LL_SCHED_DIRECT_ADV_MAX_USECS_N,
 | 
				
			||||||
 | 
					    .ble_ll_sched_adv_max_usecs = BLE_LL_SCHED_ADV_MAX_USECS_N,
 | 
				
			||||||
 | 
					    .ble_scan_rsp_data_max_len = DEFAULT_BT_LE_SCAN_RSP_DATA_MAX_LEN_N,
 | 
				
			||||||
 | 
					    .ble_ll_cfg_num_hci_cmd_pkts = BLE_LL_CFG_NUM_HCI_CMD_PKTS_N,
 | 
				
			||||||
 | 
					    .ble_ll_ctrl_proc_timeout_ms = BLE_LL_CTRL_PROC_TIMEOUT_MS_N,
 | 
				
			||||||
 | 
					    .nimble_max_connections = DEFAULT_BT_LE_MAX_CONNECTIONS,
 | 
				
			||||||
 | 
					    .ble_whitelist_size = DEFAULT_BT_NIMBLE_WHITELIST_SIZE,  // NOLINT
 | 
				
			||||||
 | 
					    .ble_acl_buf_size = DEFAULT_BT_LE_ACL_BUF_SIZE,
 | 
				
			||||||
 | 
					    .ble_acl_buf_count = DEFAULT_BT_LE_ACL_BUF_COUNT,
 | 
				
			||||||
 | 
					    .ble_hci_evt_buf_size = DEFAULT_BT_LE_HCI_EVT_BUF_SIZE,
 | 
				
			||||||
 | 
					    .ble_multi_adv_instances = DEFAULT_BT_LE_MAX_EXT_ADV_INSTANCES,
 | 
				
			||||||
 | 
					    .ble_ext_adv_max_size = DEFAULT_BT_LE_EXT_ADV_MAX_SIZE,
 | 
				
			||||||
 | 
					    .controller_task_stack_size = NIMBLE_LL_STACK_SIZE,
 | 
				
			||||||
 | 
					    .controller_task_prio = ESP_TASK_BT_CONTROLLER_PRIO,
 | 
				
			||||||
 | 
					    .controller_run_cpu = 0,
 | 
				
			||||||
 | 
					    .enable_qa_test = RUN_QA_TEST,
 | 
				
			||||||
 | 
					    .enable_bqb_test = RUN_BQB_TEST,
 | 
				
			||||||
 | 
					    .enable_uart_hci = HCI_UART_EN,
 | 
				
			||||||
 | 
					    .ble_hci_uart_port = DEFAULT_BT_LE_HCI_UART_PORT,
 | 
				
			||||||
 | 
					    .ble_hci_uart_baud = DEFAULT_BT_LE_HCI_UART_BAUD,
 | 
				
			||||||
 | 
					    .ble_hci_uart_data_bits = DEFAULT_BT_LE_HCI_UART_DATA_BITS,
 | 
				
			||||||
 | 
					    .ble_hci_uart_stop_bits = DEFAULT_BT_LE_HCI_UART_STOP_BITS,
 | 
				
			||||||
 | 
					    .ble_hci_uart_flow_ctrl = DEFAULT_BT_LE_HCI_UART_FLOW_CTRL,
 | 
				
			||||||
 | 
					    .ble_hci_uart_uart_parity = DEFAULT_BT_LE_HCI_UART_PARITY,
 | 
				
			||||||
 | 
					    .enable_tx_cca = DEFAULT_BT_LE_TX_CCA_ENABLED,
 | 
				
			||||||
 | 
					    .cca_rssi_thresh = 256 - DEFAULT_BT_LE_CCA_RSSI_THRESH,
 | 
				
			||||||
 | 
					    .sleep_en = NIMBLE_SLEEP_ENABLE,
 | 
				
			||||||
 | 
					    .coex_phy_coded_tx_rx_time_limit = DEFAULT_BT_LE_COEX_PHY_CODED_TX_RX_TLIM_EFF,
 | 
				
			||||||
 | 
					    .dis_scan_backoff = NIMBLE_DISABLE_SCAN_BACKOFF,
 | 
				
			||||||
 | 
					    .ble_scan_classify_filter_enable = 1,
 | 
				
			||||||
 | 
					    .main_xtal_freq = CONFIG_XTAL_FREQ,
 | 
				
			||||||
 | 
					    .version_num = (uint8_t) efuse_hal_chip_revision(),
 | 
				
			||||||
 | 
					    .cpu_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ,
 | 
				
			||||||
 | 
					    .ignore_wl_for_direct_adv = 0,
 | 
				
			||||||
 | 
					    .enable_pcl = DEFAULT_BT_LE_POWER_CONTROL_ENABLED,
 | 
				
			||||||
 | 
					    .config_magic = CONFIG_MAGIC,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace esp32_ble
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  // USE_ESP32_VARIANT_ESP32C6
 | 
				
			||||||
@@ -18,13 +18,16 @@
 | 
				
			|||||||
#include <cinttypes>
 | 
					#include <cinttypes>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_OTA
 | 
					#ifdef USE_OTA
 | 
				
			||||||
#include "esphome/components/ota/ota_component.h"
 | 
					#include "esphome/components/ota/ota_backend.h"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ARDUINO
 | 
					#ifdef USE_ARDUINO
 | 
				
			||||||
#include <esp32-hal-bt.h>
 | 
					#include <esp32-hal-bt.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MBEDTLS_AES_ALT
 | 
				
			||||||
 | 
					#include <aes_alt.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// bt_trace.h
 | 
					// bt_trace.h
 | 
				
			||||||
#undef TAG
 | 
					#undef TAG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -58,11 +61,12 @@ void ESP32BLETracker::setup() {
 | 
				
			|||||||
  this->scanner_idle_ = true;
 | 
					  this->scanner_idle_ = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_OTA
 | 
					#ifdef USE_OTA
 | 
				
			||||||
  ota::global_ota_component->add_on_state_callback([this](ota::OTAState state, float progress, uint8_t error) {
 | 
					  ota::get_global_ota_callback()->add_on_state_callback(
 | 
				
			||||||
    if (state == ota::OTA_STARTED) {
 | 
					      [this](ota::OTAState state, float progress, uint8_t error, ota::OTAComponent *comp) {
 | 
				
			||||||
      this->stop_scan();
 | 
					        if (state == ota::OTA_STARTED) {
 | 
				
			||||||
    }
 | 
					          this->stop_scan();
 | 
				
			||||||
  });
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -692,6 +696,39 @@ void ESP32BLETracker::print_bt_device_info(const ESPBTDevice &device) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ESPBTDevice::resolve_irk(const uint8_t *irk) const {
 | 
				
			||||||
 | 
					  uint8_t ecb_key[16];
 | 
				
			||||||
 | 
					  uint8_t ecb_plaintext[16];
 | 
				
			||||||
 | 
					  uint8_t ecb_ciphertext[16];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint64_t addr64 = esp32_ble::ble_addr_to_uint64(this->address_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  memcpy(&ecb_key, irk, 16);
 | 
				
			||||||
 | 
					  memset(&ecb_plaintext, 0, 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ecb_plaintext[13] = (addr64 >> 40) & 0xff;
 | 
				
			||||||
 | 
					  ecb_plaintext[14] = (addr64 >> 32) & 0xff;
 | 
				
			||||||
 | 
					  ecb_plaintext[15] = (addr64 >> 24) & 0xff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mbedtls_aes_context ctx = {0, 0, {0}};
 | 
				
			||||||
 | 
					  mbedtls_aes_init(&ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (mbedtls_aes_setkey_enc(&ctx, ecb_key, 128) != 0) {
 | 
				
			||||||
 | 
					    mbedtls_aes_free(&ctx);
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (mbedtls_aes_crypt_ecb(&ctx, ESP_AES_ENCRYPT, ecb_plaintext, ecb_ciphertext) != 0) {
 | 
				
			||||||
 | 
					    mbedtls_aes_free(&ctx);
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mbedtls_aes_free(&ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return ecb_ciphertext[15] == (addr64 & 0xff) && ecb_ciphertext[14] == ((addr64 >> 8) & 0xff) &&
 | 
				
			||||||
 | 
					         ecb_ciphertext[13] == ((addr64 >> 16) & 0xff);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace esp32_ble_tracker
 | 
					}  // namespace esp32_ble_tracker
 | 
				
			||||||
}  // namespace esphome
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -86,6 +86,8 @@ class ESPBTDevice {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  const esp_ble_gap_cb_param_t::ble_scan_result_evt_param &get_scan_result() const { return scan_result_; }
 | 
					  const esp_ble_gap_cb_param_t::ble_scan_result_evt_param &get_scan_result() const { return scan_result_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool resolve_irk(const uint8_t *irk) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  optional<ESPBLEiBeacon> get_ibeacon() const {
 | 
					  optional<ESPBLEiBeacon> get_ibeacon() const {
 | 
				
			||||||
    for (auto &it : this->manufacturer_datas_) {
 | 
					    for (auto &it : this->manufacturer_datas_) {
 | 
				
			||||||
      auto res = ESPBLEiBeacon::from_manufacturer_data(it);
 | 
					      auto res = ESPBLEiBeacon::from_manufacturer_data(it);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ from esphome import pins
 | 
				
			|||||||
from esphome.components import esp32_rmt, light
 | 
					from esphome.components import esp32_rmt, light
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_CHIPSET,
 | 
					    CONF_CHIPSET,
 | 
				
			||||||
 | 
					    CONF_IS_RGBW,
 | 
				
			||||||
    CONF_MAX_REFRESH_RATE,
 | 
					    CONF_MAX_REFRESH_RATE,
 | 
				
			||||||
    CONF_NUM_LEDS,
 | 
					    CONF_NUM_LEDS,
 | 
				
			||||||
    CONF_OUTPUT_ID,
 | 
					    CONF_OUTPUT_ID,
 | 
				
			||||||
@@ -52,7 +53,6 @@ CHIPSETS = {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONF_IS_RGBW = "is_rgbw"
 | 
					 | 
				
			||||||
CONF_IS_WRGB = "is_wrgb"
 | 
					CONF_IS_WRGB = "is_wrgb"
 | 
				
			||||||
CONF_BIT0_HIGH = "bit0_high"
 | 
					CONF_BIT0_HIGH = "bit0_high"
 | 
				
			||||||
CONF_BIT0_LOW = "bit0_low"
 | 
					CONF_BIT0_LOW = "bit0_low"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -150,7 +150,7 @@ TOUCH_PAD_WATERPROOF_SHIELD_DRIVER = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def validate_touch_pad(value):
 | 
					def validate_touch_pad(value):
 | 
				
			||||||
    value = gpio.validate_gpio_pin(value)
 | 
					    value = gpio.gpio_pin_number_validator(value)
 | 
				
			||||||
    variant = get_esp32_variant()
 | 
					    variant = get_esp32_variant()
 | 
				
			||||||
    if variant not in TOUCH_PADS:
 | 
					    if variant not in TOUCH_PADS:
 | 
				
			||||||
        raise cv.Invalid(f"ESP32 variant {variant} does not support touch pads.")
 | 
					        raise cv.Invalid(f"ESP32 variant {variant} does not support touch pads.")
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										64
									
								
								esphome/components/esphome/ota/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								esphome/components/esphome/ota/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome.components.ota import BASE_OTA_SCHEMA, ota_to_code, OTAComponent
 | 
				
			||||||
 | 
					from esphome.const import (
 | 
				
			||||||
 | 
					    CONF_ID,
 | 
				
			||||||
 | 
					    CONF_NUM_ATTEMPTS,
 | 
				
			||||||
 | 
					    CONF_PASSWORD,
 | 
				
			||||||
 | 
					    CONF_PORT,
 | 
				
			||||||
 | 
					    CONF_REBOOT_TIMEOUT,
 | 
				
			||||||
 | 
					    CONF_SAFE_MODE,
 | 
				
			||||||
 | 
					    CONF_VERSION,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					from esphome.core import coroutine_with_priority
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CODEOWNERS = ["@esphome/core"]
 | 
				
			||||||
 | 
					AUTO_LOAD = ["md5", "socket"]
 | 
				
			||||||
 | 
					DEPENDENCIES = ["network"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					esphome = cg.esphome_ns.namespace("esphome")
 | 
				
			||||||
 | 
					ESPHomeOTAComponent = esphome.class_("ESPHomeOTAComponent", OTAComponent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONFIG_SCHEMA = (
 | 
				
			||||||
 | 
					    cv.Schema(
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            cv.GenerateID(): cv.declare_id(ESPHomeOTAComponent),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2, int=True),
 | 
				
			||||||
 | 
					            cv.SplitDefault(
 | 
				
			||||||
 | 
					                CONF_PORT,
 | 
				
			||||||
 | 
					                esp8266=8266,
 | 
				
			||||||
 | 
					                esp32=3232,
 | 
				
			||||||
 | 
					                rp2040=2040,
 | 
				
			||||||
 | 
					                bk72xx=8892,
 | 
				
			||||||
 | 
					                rtl87xx=8892,
 | 
				
			||||||
 | 
					            ): cv.port,
 | 
				
			||||||
 | 
					            cv.Optional(CONF_PASSWORD): cv.string,
 | 
				
			||||||
 | 
					            cv.Optional(CONF_NUM_ATTEMPTS): cv.invalid(
 | 
				
			||||||
 | 
					                f"'{CONF_SAFE_MODE}' (and its related configuration variables) has moved from 'ota' to its own component. See https://esphome.io/components/safe_mode"
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_REBOOT_TIMEOUT): cv.invalid(
 | 
				
			||||||
 | 
					                f"'{CONF_SAFE_MODE}' (and its related configuration variables) has moved from 'ota' to its own component. See https://esphome.io/components/safe_mode"
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_SAFE_MODE): cv.invalid(
 | 
				
			||||||
 | 
					                f"'{CONF_SAFE_MODE}' (and its related configuration variables) has moved from 'ota' to its own component. See https://esphome.io/components/safe_mode"
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    .extend(BASE_OTA_SCHEMA)
 | 
				
			||||||
 | 
					    .extend(cv.COMPONENT_SCHEMA)
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@coroutine_with_priority(52.0)
 | 
				
			||||||
 | 
					async def to_code(config):
 | 
				
			||||||
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
 | 
					    await ota_to_code(var, config)
 | 
				
			||||||
 | 
					    cg.add(var.set_port(config[CONF_PORT]))
 | 
				
			||||||
 | 
					    if CONF_PASSWORD in config:
 | 
				
			||||||
 | 
					        cg.add(var.set_auth_password(config[CONF_PASSWORD]))
 | 
				
			||||||
 | 
					        cg.add_define("USE_OTA_PASSWORD")
 | 
				
			||||||
 | 
					    cg.add_define("USE_OTA_VERSION", config[CONF_VERSION])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
@@ -1,55 +1,34 @@
 | 
				
			|||||||
#include "ota_component.h"
 | 
					#include "ota_esphome.h"
 | 
				
			||||||
#include "ota_backend.h"
 | 
					 | 
				
			||||||
#include "ota_backend_arduino_esp32.h"
 | 
					 | 
				
			||||||
#include "ota_backend_arduino_esp8266.h"
 | 
					 | 
				
			||||||
#include "ota_backend_arduino_rp2040.h"
 | 
					 | 
				
			||||||
#include "ota_backend_arduino_libretiny.h"
 | 
					 | 
				
			||||||
#include "ota_backend_esp_idf.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "esphome/core/log.h"
 | 
					 | 
				
			||||||
#include "esphome/core/application.h"
 | 
					 | 
				
			||||||
#include "esphome/core/hal.h"
 | 
					 | 
				
			||||||
#include "esphome/core/util.h"
 | 
					 | 
				
			||||||
#include "esphome/components/md5/md5.h"
 | 
					#include "esphome/components/md5/md5.h"
 | 
				
			||||||
#include "esphome/components/network/util.h"
 | 
					#include "esphome/components/network/util.h"
 | 
				
			||||||
 | 
					#include "esphome/components/ota/ota_backend.h"
 | 
				
			||||||
 | 
					#include "esphome/components/ota/ota_backend_arduino_esp32.h"
 | 
				
			||||||
 | 
					#include "esphome/components/ota/ota_backend_arduino_esp8266.h"
 | 
				
			||||||
 | 
					#include "esphome/components/ota/ota_backend_arduino_libretiny.h"
 | 
				
			||||||
 | 
					#include "esphome/components/ota/ota_backend_arduino_rp2040.h"
 | 
				
			||||||
 | 
					#include "esphome/components/ota/ota_backend_esp_idf.h"
 | 
				
			||||||
 | 
					#include "esphome/core/application.h"
 | 
				
			||||||
 | 
					#include "esphome/core/hal.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					#include "esphome/core/util.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <cerrno>
 | 
					#include <cerrno>
 | 
				
			||||||
#include <cstdio>
 | 
					#include <cstdio>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace ota {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *const TAG = "ota";
 | 
					static const char *const TAG = "esphome.ota";
 | 
				
			||||||
static constexpr u_int16_t OTA_BLOCK_SIZE = 8192;
 | 
					static constexpr u_int16_t OTA_BLOCK_SIZE = 8192;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OTAComponent *global_ota_component = nullptr;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 | 
					void ESPHomeOTAComponent::setup() {
 | 
				
			||||||
 | 
					#ifdef USE_OTA_STATE_CALLBACK
 | 
				
			||||||
std::unique_ptr<OTABackend> make_ota_backend() {
 | 
					  ota::register_ota_platform(this);
 | 
				
			||||||
#ifdef USE_ARDUINO
 | 
					 | 
				
			||||||
#ifdef USE_ESP8266
 | 
					 | 
				
			||||||
  return make_unique<ArduinoESP8266OTABackend>();
 | 
					 | 
				
			||||||
#endif  // USE_ESP8266
 | 
					 | 
				
			||||||
#ifdef USE_ESP32
 | 
					 | 
				
			||||||
  return make_unique<ArduinoESP32OTABackend>();
 | 
					 | 
				
			||||||
#endif  // USE_ESP32
 | 
					 | 
				
			||||||
#endif  // USE_ARDUINO
 | 
					 | 
				
			||||||
#ifdef USE_ESP_IDF
 | 
					 | 
				
			||||||
  return make_unique<IDFOTABackend>();
 | 
					 | 
				
			||||||
#endif  // USE_ESP_IDF
 | 
					 | 
				
			||||||
#ifdef USE_RP2040
 | 
					 | 
				
			||||||
  return make_unique<ArduinoRP2040OTABackend>();
 | 
					 | 
				
			||||||
#endif  // USE_RP2040
 | 
					 | 
				
			||||||
#ifdef USE_LIBRETINY
 | 
					 | 
				
			||||||
  return make_unique<ArduinoLibreTinyOTABackend>();
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
OTAComponent::OTAComponent() { global_ota_component = this; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void OTAComponent::setup() {
 | 
					 | 
				
			||||||
  server_ = socket::socket_ip(SOCK_STREAM, 0);
 | 
					  server_ = socket::socket_ip(SOCK_STREAM, 0);
 | 
				
			||||||
  if (server_ == nullptr) {
 | 
					  if (server_ == nullptr) {
 | 
				
			||||||
    ESP_LOGW(TAG, "Could not create socket.");
 | 
					    ESP_LOGW(TAG, "Could not create socket");
 | 
				
			||||||
    this->mark_failed();
 | 
					    this->mark_failed();
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -88,41 +67,25 @@ void OTAComponent::setup() {
 | 
				
			|||||||
    this->mark_failed();
 | 
					    this->mark_failed();
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  this->dump_config();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void OTAComponent::dump_config() {
 | 
					void ESPHomeOTAComponent::dump_config() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Over-The-Air Updates:");
 | 
					  ESP_LOGCONFIG(TAG, "Over-The-Air updates:");
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  Address: %s:%u", network::get_use_address().c_str(), this->port_);
 | 
					  ESP_LOGCONFIG(TAG, "  Address: %s:%u", network::get_use_address().c_str(), this->port_);
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "  Version: %d", USE_OTA_VERSION);
 | 
				
			||||||
#ifdef USE_OTA_PASSWORD
 | 
					#ifdef USE_OTA_PASSWORD
 | 
				
			||||||
  if (!this->password_.empty()) {
 | 
					  if (!this->password_.empty()) {
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "  Using Password.");
 | 
					    ESP_LOGCONFIG(TAG, "  Password configured");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  OTA version: %d.", USE_OTA_VERSION);
 | 
					 | 
				
			||||||
  if (this->has_safe_mode_ && this->safe_mode_rtc_value_ > 1 &&
 | 
					 | 
				
			||||||
      this->safe_mode_rtc_value_ != esphome::ota::OTAComponent::ENTER_SAFE_MODE_MAGIC) {
 | 
					 | 
				
			||||||
    ESP_LOGW(TAG, "Last Boot was an unhandled reset, will proceed to safe mode in %" PRIu32 " restarts",
 | 
					 | 
				
			||||||
             this->safe_mode_num_attempts_ - this->safe_mode_rtc_value_);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void OTAComponent::loop() {
 | 
					void ESPHomeOTAComponent::loop() { this->handle_(); }
 | 
				
			||||||
  this->handle_();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (this->has_safe_mode_ && (millis() - this->safe_mode_start_time_) > this->safe_mode_enable_time_) {
 | 
					 | 
				
			||||||
    this->has_safe_mode_ = false;
 | 
					 | 
				
			||||||
    // successful boot, reset counter
 | 
					 | 
				
			||||||
    ESP_LOGI(TAG, "Boot seems successful, resetting boot loop counter.");
 | 
					 | 
				
			||||||
    this->clean_rtc();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const uint8_t FEATURE_SUPPORTS_COMPRESSION = 0x01;
 | 
					static const uint8_t FEATURE_SUPPORTS_COMPRESSION = 0x01;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void OTAComponent::handle_() {
 | 
					void ESPHomeOTAComponent::handle_() {
 | 
				
			||||||
  OTAResponseTypes error_code = OTA_RESPONSE_ERROR_UNKNOWN;
 | 
					  ota::OTAResponseTypes error_code = ota::OTA_RESPONSE_ERROR_UNKNOWN;
 | 
				
			||||||
  bool update_started = false;
 | 
					  bool update_started = false;
 | 
				
			||||||
  size_t total = 0;
 | 
					  size_t total = 0;
 | 
				
			||||||
  uint32_t last_progress = 0;
 | 
					  uint32_t last_progress = 0;
 | 
				
			||||||
@@ -130,7 +93,7 @@ void OTAComponent::handle_() {
 | 
				
			|||||||
  char *sbuf = reinterpret_cast<char *>(buf);
 | 
					  char *sbuf = reinterpret_cast<char *>(buf);
 | 
				
			||||||
  size_t ota_size;
 | 
					  size_t ota_size;
 | 
				
			||||||
  uint8_t ota_features;
 | 
					  uint8_t ota_features;
 | 
				
			||||||
  std::unique_ptr<OTABackend> backend;
 | 
					  std::unique_ptr<ota::OTABackend> backend;
 | 
				
			||||||
  (void) ota_features;
 | 
					  (void) ota_features;
 | 
				
			||||||
#if USE_OTA_VERSION == 2
 | 
					#if USE_OTA_VERSION == 2
 | 
				
			||||||
  size_t size_acknowledged = 0;
 | 
					  size_t size_acknowledged = 0;
 | 
				
			||||||
@@ -147,54 +110,54 @@ void OTAComponent::handle_() {
 | 
				
			|||||||
  int enable = 1;
 | 
					  int enable = 1;
 | 
				
			||||||
  int err = client_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(int));
 | 
					  int err = client_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(int));
 | 
				
			||||||
  if (err != 0) {
 | 
					  if (err != 0) {
 | 
				
			||||||
    ESP_LOGW(TAG, "Socket could not enable tcp nodelay, errno: %d", errno);
 | 
					    ESP_LOGW(TAG, "Socket could not enable TCP nodelay, errno %d", errno);
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ESP_LOGD(TAG, "Starting OTA Update from %s...", this->client_->getpeername().c_str());
 | 
					  ESP_LOGD(TAG, "Starting update from %s...", this->client_->getpeername().c_str());
 | 
				
			||||||
  this->status_set_warning();
 | 
					  this->status_set_warning();
 | 
				
			||||||
#ifdef USE_OTA_STATE_CALLBACK
 | 
					#ifdef USE_OTA_STATE_CALLBACK
 | 
				
			||||||
  this->state_callback_.call(OTA_STARTED, 0.0f, 0);
 | 
					  this->state_callback_.call(ota::OTA_STARTED, 0.0f, 0);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!this->readall_(buf, 5)) {
 | 
					  if (!this->readall_(buf, 5)) {
 | 
				
			||||||
    ESP_LOGW(TAG, "Reading magic bytes failed!");
 | 
					    ESP_LOGW(TAG, "Reading magic bytes failed");
 | 
				
			||||||
    goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
					    goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  // 0x6C, 0x26, 0xF7, 0x5C, 0x45
 | 
					  // 0x6C, 0x26, 0xF7, 0x5C, 0x45
 | 
				
			||||||
  if (buf[0] != 0x6C || buf[1] != 0x26 || buf[2] != 0xF7 || buf[3] != 0x5C || buf[4] != 0x45) {
 | 
					  if (buf[0] != 0x6C || buf[1] != 0x26 || buf[2] != 0xF7 || buf[3] != 0x5C || buf[4] != 0x45) {
 | 
				
			||||||
    ESP_LOGW(TAG, "Magic bytes do not match! 0x%02X-0x%02X-0x%02X-0x%02X-0x%02X", buf[0], buf[1], buf[2], buf[3],
 | 
					    ESP_LOGW(TAG, "Magic bytes do not match! 0x%02X-0x%02X-0x%02X-0x%02X-0x%02X", buf[0], buf[1], buf[2], buf[3],
 | 
				
			||||||
             buf[4]);
 | 
					             buf[4]);
 | 
				
			||||||
    error_code = OTA_RESPONSE_ERROR_MAGIC;
 | 
					    error_code = ota::OTA_RESPONSE_ERROR_MAGIC;
 | 
				
			||||||
    goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
					    goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Send OK and version - 2 bytes
 | 
					  // Send OK and version - 2 bytes
 | 
				
			||||||
  buf[0] = OTA_RESPONSE_OK;
 | 
					  buf[0] = ota::OTA_RESPONSE_OK;
 | 
				
			||||||
  buf[1] = USE_OTA_VERSION;
 | 
					  buf[1] = USE_OTA_VERSION;
 | 
				
			||||||
  this->writeall_(buf, 2);
 | 
					  this->writeall_(buf, 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  backend = make_ota_backend();
 | 
					  backend = ota::make_ota_backend();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Read features - 1 byte
 | 
					  // Read features - 1 byte
 | 
				
			||||||
  if (!this->readall_(buf, 1)) {
 | 
					  if (!this->readall_(buf, 1)) {
 | 
				
			||||||
    ESP_LOGW(TAG, "Reading features failed!");
 | 
					    ESP_LOGW(TAG, "Reading features failed");
 | 
				
			||||||
    goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
					    goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  ota_features = buf[0];  // NOLINT
 | 
					  ota_features = buf[0];  // NOLINT
 | 
				
			||||||
  ESP_LOGV(TAG, "OTA features is 0x%02X", ota_features);
 | 
					  ESP_LOGV(TAG, "Features: 0x%02X", ota_features);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Acknowledge header - 1 byte
 | 
					  // Acknowledge header - 1 byte
 | 
				
			||||||
  buf[0] = OTA_RESPONSE_HEADER_OK;
 | 
					  buf[0] = ota::OTA_RESPONSE_HEADER_OK;
 | 
				
			||||||
  if ((ota_features & FEATURE_SUPPORTS_COMPRESSION) != 0 && backend->supports_compression()) {
 | 
					  if ((ota_features & FEATURE_SUPPORTS_COMPRESSION) != 0 && backend->supports_compression()) {
 | 
				
			||||||
    buf[0] = OTA_RESPONSE_SUPPORTS_COMPRESSION;
 | 
					    buf[0] = ota::OTA_RESPONSE_SUPPORTS_COMPRESSION;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  this->writeall_(buf, 1);
 | 
					  this->writeall_(buf, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_OTA_PASSWORD
 | 
					#ifdef USE_OTA_PASSWORD
 | 
				
			||||||
  if (!this->password_.empty()) {
 | 
					  if (!this->password_.empty()) {
 | 
				
			||||||
    buf[0] = OTA_RESPONSE_REQUEST_AUTH;
 | 
					    buf[0] = ota::OTA_RESPONSE_REQUEST_AUTH;
 | 
				
			||||||
    this->writeall_(buf, 1);
 | 
					    this->writeall_(buf, 1);
 | 
				
			||||||
    md5::MD5Digest md5{};
 | 
					    md5::MD5Digest md5{};
 | 
				
			||||||
    md5.init();
 | 
					    md5.init();
 | 
				
			||||||
@@ -206,7 +169,7 @@ void OTAComponent::handle_() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Send nonce, 32 bytes hex MD5
 | 
					    // Send nonce, 32 bytes hex MD5
 | 
				
			||||||
    if (!this->writeall_(reinterpret_cast<uint8_t *>(sbuf), 32)) {
 | 
					    if (!this->writeall_(reinterpret_cast<uint8_t *>(sbuf), 32)) {
 | 
				
			||||||
      ESP_LOGW(TAG, "Auth: Writing nonce failed!");
 | 
					      ESP_LOGW(TAG, "Auth: Writing nonce failed");
 | 
				
			||||||
      goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
					      goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -218,7 +181,7 @@ void OTAComponent::handle_() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Receive cnonce, 32 bytes hex MD5
 | 
					    // Receive cnonce, 32 bytes hex MD5
 | 
				
			||||||
    if (!this->readall_(buf, 32)) {
 | 
					    if (!this->readall_(buf, 32)) {
 | 
				
			||||||
      ESP_LOGW(TAG, "Auth: Reading cnonce failed!");
 | 
					      ESP_LOGW(TAG, "Auth: Reading cnonce failed");
 | 
				
			||||||
      goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
					      goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    sbuf[32] = '\0';
 | 
					    sbuf[32] = '\0';
 | 
				
			||||||
@@ -233,7 +196,7 @@ void OTAComponent::handle_() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Receive result, 32 bytes hex MD5
 | 
					    // Receive result, 32 bytes hex MD5
 | 
				
			||||||
    if (!this->readall_(buf + 64, 32)) {
 | 
					    if (!this->readall_(buf + 64, 32)) {
 | 
				
			||||||
      ESP_LOGW(TAG, "Auth: Reading response failed!");
 | 
					      ESP_LOGW(TAG, "Auth: Reading response failed");
 | 
				
			||||||
      goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
					      goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    sbuf[64 + 32] = '\0';
 | 
					    sbuf[64 + 32] = '\0';
 | 
				
			||||||
@@ -244,20 +207,20 @@ void OTAComponent::handle_() {
 | 
				
			|||||||
      matches = matches && buf[i] == buf[64 + i];
 | 
					      matches = matches && buf[i] == buf[64 + i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!matches) {
 | 
					    if (!matches) {
 | 
				
			||||||
      ESP_LOGW(TAG, "Auth failed! Passwords do not match!");
 | 
					      ESP_LOGW(TAG, "Auth failed! Passwords do not match");
 | 
				
			||||||
      error_code = OTA_RESPONSE_ERROR_AUTH_INVALID;
 | 
					      error_code = ota::OTA_RESPONSE_ERROR_AUTH_INVALID;
 | 
				
			||||||
      goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
					      goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif  // USE_OTA_PASSWORD
 | 
					#endif  // USE_OTA_PASSWORD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Acknowledge auth OK - 1 byte
 | 
					  // Acknowledge auth OK - 1 byte
 | 
				
			||||||
  buf[0] = OTA_RESPONSE_AUTH_OK;
 | 
					  buf[0] = ota::OTA_RESPONSE_AUTH_OK;
 | 
				
			||||||
  this->writeall_(buf, 1);
 | 
					  this->writeall_(buf, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Read size, 4 bytes MSB first
 | 
					  // Read size, 4 bytes MSB first
 | 
				
			||||||
  if (!this->readall_(buf, 4)) {
 | 
					  if (!this->readall_(buf, 4)) {
 | 
				
			||||||
    ESP_LOGW(TAG, "Reading size failed!");
 | 
					    ESP_LOGW(TAG, "Reading size failed");
 | 
				
			||||||
    goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
					    goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  ota_size = 0;
 | 
					  ota_size = 0;
 | 
				
			||||||
@@ -265,20 +228,20 @@ void OTAComponent::handle_() {
 | 
				
			|||||||
    ota_size <<= 8;
 | 
					    ota_size <<= 8;
 | 
				
			||||||
    ota_size |= buf[i];
 | 
					    ota_size |= buf[i];
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  ESP_LOGV(TAG, "OTA size is %u bytes", ota_size);
 | 
					  ESP_LOGV(TAG, "Size is %u bytes", ota_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  error_code = backend->begin(ota_size);
 | 
					  error_code = backend->begin(ota_size);
 | 
				
			||||||
  if (error_code != OTA_RESPONSE_OK)
 | 
					  if (error_code != ota::OTA_RESPONSE_OK)
 | 
				
			||||||
    goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
					    goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
				
			||||||
  update_started = true;
 | 
					  update_started = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Acknowledge prepare OK - 1 byte
 | 
					  // Acknowledge prepare OK - 1 byte
 | 
				
			||||||
  buf[0] = OTA_RESPONSE_UPDATE_PREPARE_OK;
 | 
					  buf[0] = ota::OTA_RESPONSE_UPDATE_PREPARE_OK;
 | 
				
			||||||
  this->writeall_(buf, 1);
 | 
					  this->writeall_(buf, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Read binary MD5, 32 bytes
 | 
					  // Read binary MD5, 32 bytes
 | 
				
			||||||
  if (!this->readall_(buf, 32)) {
 | 
					  if (!this->readall_(buf, 32)) {
 | 
				
			||||||
    ESP_LOGW(TAG, "Reading binary MD5 checksum failed!");
 | 
					    ESP_LOGW(TAG, "Reading binary MD5 checksum failed");
 | 
				
			||||||
    goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
					    goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  sbuf[32] = '\0';
 | 
					  sbuf[32] = '\0';
 | 
				
			||||||
@@ -286,7 +249,7 @@ void OTAComponent::handle_() {
 | 
				
			|||||||
  backend->set_update_md5(sbuf);
 | 
					  backend->set_update_md5(sbuf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Acknowledge MD5 OK - 1 byte
 | 
					  // Acknowledge MD5 OK - 1 byte
 | 
				
			||||||
  buf[0] = OTA_RESPONSE_BIN_MD5_OK;
 | 
					  buf[0] = ota::OTA_RESPONSE_BIN_MD5_OK;
 | 
				
			||||||
  this->writeall_(buf, 1);
 | 
					  this->writeall_(buf, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  while (total < ota_size) {
 | 
					  while (total < ota_size) {
 | 
				
			||||||
@@ -299,7 +262,7 @@ void OTAComponent::handle_() {
 | 
				
			|||||||
        delay(1);
 | 
					        delay(1);
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      ESP_LOGW(TAG, "Error receiving data for update, errno: %d", errno);
 | 
					      ESP_LOGW(TAG, "Error receiving data for update, errno %d", errno);
 | 
				
			||||||
      goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
					      goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
				
			||||||
    } else if (read == 0) {
 | 
					    } else if (read == 0) {
 | 
				
			||||||
      // $ man recv
 | 
					      // $ man recv
 | 
				
			||||||
@@ -310,14 +273,14 @@ void OTAComponent::handle_() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    error_code = backend->write(buf, read);
 | 
					    error_code = backend->write(buf, read);
 | 
				
			||||||
    if (error_code != OTA_RESPONSE_OK) {
 | 
					    if (error_code != ota::OTA_RESPONSE_OK) {
 | 
				
			||||||
      ESP_LOGW(TAG, "Error writing binary data to flash!, error_code: %d", error_code);
 | 
					      ESP_LOGW(TAG, "Error writing binary data to flash!, error_code: %d", error_code);
 | 
				
			||||||
      goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
					      goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    total += read;
 | 
					    total += read;
 | 
				
			||||||
#if USE_OTA_VERSION == 2
 | 
					#if USE_OTA_VERSION == 2
 | 
				
			||||||
    while (size_acknowledged + OTA_BLOCK_SIZE <= total || (total == ota_size && size_acknowledged < ota_size)) {
 | 
					    while (size_acknowledged + OTA_BLOCK_SIZE <= total || (total == ota_size && size_acknowledged < ota_size)) {
 | 
				
			||||||
      buf[0] = OTA_RESPONSE_CHUNK_OK;
 | 
					      buf[0] = ota::OTA_RESPONSE_CHUNK_OK;
 | 
				
			||||||
      this->writeall_(buf, 1);
 | 
					      this->writeall_(buf, 1);
 | 
				
			||||||
      size_acknowledged += OTA_BLOCK_SIZE;
 | 
					      size_acknowledged += OTA_BLOCK_SIZE;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -327,9 +290,9 @@ void OTAComponent::handle_() {
 | 
				
			|||||||
    if (now - last_progress > 1000) {
 | 
					    if (now - last_progress > 1000) {
 | 
				
			||||||
      last_progress = now;
 | 
					      last_progress = now;
 | 
				
			||||||
      float percentage = (total * 100.0f) / ota_size;
 | 
					      float percentage = (total * 100.0f) / ota_size;
 | 
				
			||||||
      ESP_LOGD(TAG, "OTA in progress: %0.1f%%", percentage);
 | 
					      ESP_LOGD(TAG, "Progress: %0.1f%%", percentage);
 | 
				
			||||||
#ifdef USE_OTA_STATE_CALLBACK
 | 
					#ifdef USE_OTA_STATE_CALLBACK
 | 
				
			||||||
      this->state_callback_.call(OTA_IN_PROGRESS, percentage, 0);
 | 
					      this->state_callback_.call(ota::OTA_IN_PROGRESS, percentage, 0);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
      // feed watchdog and give other tasks a chance to run
 | 
					      // feed watchdog and give other tasks a chance to run
 | 
				
			||||||
      App.feed_wdt();
 | 
					      App.feed_wdt();
 | 
				
			||||||
@@ -338,32 +301,32 @@ void OTAComponent::handle_() {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Acknowledge receive OK - 1 byte
 | 
					  // Acknowledge receive OK - 1 byte
 | 
				
			||||||
  buf[0] = OTA_RESPONSE_RECEIVE_OK;
 | 
					  buf[0] = ota::OTA_RESPONSE_RECEIVE_OK;
 | 
				
			||||||
  this->writeall_(buf, 1);
 | 
					  this->writeall_(buf, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  error_code = backend->end();
 | 
					  error_code = backend->end();
 | 
				
			||||||
  if (error_code != OTA_RESPONSE_OK) {
 | 
					  if (error_code != ota::OTA_RESPONSE_OK) {
 | 
				
			||||||
    ESP_LOGW(TAG, "Error ending OTA!, error_code: %d", error_code);
 | 
					    ESP_LOGW(TAG, "Error ending update! error_code: %d", error_code);
 | 
				
			||||||
    goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
					    goto error;  // NOLINT(cppcoreguidelines-avoid-goto)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Acknowledge Update end OK - 1 byte
 | 
					  // Acknowledge Update end OK - 1 byte
 | 
				
			||||||
  buf[0] = OTA_RESPONSE_UPDATE_END_OK;
 | 
					  buf[0] = ota::OTA_RESPONSE_UPDATE_END_OK;
 | 
				
			||||||
  this->writeall_(buf, 1);
 | 
					  this->writeall_(buf, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Read ACK
 | 
					  // Read ACK
 | 
				
			||||||
  if (!this->readall_(buf, 1) || buf[0] != OTA_RESPONSE_OK) {
 | 
					  if (!this->readall_(buf, 1) || buf[0] != ota::OTA_RESPONSE_OK) {
 | 
				
			||||||
    ESP_LOGW(TAG, "Reading back acknowledgement failed!");
 | 
					    ESP_LOGW(TAG, "Reading back acknowledgement failed");
 | 
				
			||||||
    // do not go to error, this is not fatal
 | 
					    // do not go to error, this is not fatal
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  this->client_->close();
 | 
					  this->client_->close();
 | 
				
			||||||
  this->client_ = nullptr;
 | 
					  this->client_ = nullptr;
 | 
				
			||||||
  delay(10);
 | 
					  delay(10);
 | 
				
			||||||
  ESP_LOGI(TAG, "OTA update finished!");
 | 
					  ESP_LOGI(TAG, "Update complete");
 | 
				
			||||||
  this->status_clear_warning();
 | 
					  this->status_clear_warning();
 | 
				
			||||||
#ifdef USE_OTA_STATE_CALLBACK
 | 
					#ifdef USE_OTA_STATE_CALLBACK
 | 
				
			||||||
  this->state_callback_.call(OTA_COMPLETED, 100.0f, 0);
 | 
					  this->state_callback_.call(ota::OTA_COMPLETED, 100.0f, 0);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  delay(100);  // NOLINT
 | 
					  delay(100);  // NOLINT
 | 
				
			||||||
  App.safe_reboot();
 | 
					  App.safe_reboot();
 | 
				
			||||||
@@ -380,11 +343,11 @@ error:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  this->status_momentary_error("onerror", 5000);
 | 
					  this->status_momentary_error("onerror", 5000);
 | 
				
			||||||
#ifdef USE_OTA_STATE_CALLBACK
 | 
					#ifdef USE_OTA_STATE_CALLBACK
 | 
				
			||||||
  this->state_callback_.call(OTA_ERROR, 0.0f, static_cast<uint8_t>(error_code));
 | 
					  this->state_callback_.call(ota::OTA_ERROR, 0.0f, static_cast<uint8_t>(error_code));
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool OTAComponent::readall_(uint8_t *buf, size_t len) {
 | 
					bool ESPHomeOTAComponent::readall_(uint8_t *buf, size_t len) {
 | 
				
			||||||
  uint32_t start = millis();
 | 
					  uint32_t start = millis();
 | 
				
			||||||
  uint32_t at = 0;
 | 
					  uint32_t at = 0;
 | 
				
			||||||
  while (len - at > 0) {
 | 
					  while (len - at > 0) {
 | 
				
			||||||
@@ -401,7 +364,7 @@ bool OTAComponent::readall_(uint8_t *buf, size_t len) {
 | 
				
			|||||||
        delay(1);
 | 
					        delay(1);
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      ESP_LOGW(TAG, "Failed to read %d bytes of data, errno: %d", len, errno);
 | 
					      ESP_LOGW(TAG, "Failed to read %d bytes of data, errno %d", len, errno);
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
    } else if (read == 0) {
 | 
					    } else if (read == 0) {
 | 
				
			||||||
      ESP_LOGW(TAG, "Remote closed connection");
 | 
					      ESP_LOGW(TAG, "Remote closed connection");
 | 
				
			||||||
@@ -415,7 +378,7 @@ bool OTAComponent::readall_(uint8_t *buf, size_t len) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
bool OTAComponent::writeall_(const uint8_t *buf, size_t len) {
 | 
					bool ESPHomeOTAComponent::writeall_(const uint8_t *buf, size_t len) {
 | 
				
			||||||
  uint32_t start = millis();
 | 
					  uint32_t start = millis();
 | 
				
			||||||
  uint32_t at = 0;
 | 
					  uint32_t at = 0;
 | 
				
			||||||
  while (len - at > 0) {
 | 
					  while (len - at > 0) {
 | 
				
			||||||
@@ -432,7 +395,7 @@ bool OTAComponent::writeall_(const uint8_t *buf, size_t len) {
 | 
				
			|||||||
        delay(1);
 | 
					        delay(1);
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      ESP_LOGW(TAG, "Failed to write %d bytes of data, errno: %d", len, errno);
 | 
					      ESP_LOGW(TAG, "Failed to write %d bytes of data, errno %d", len, errno);
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      at += written;
 | 
					      at += written;
 | 
				
			||||||
@@ -443,93 +406,7 @@ bool OTAComponent::writeall_(const uint8_t *buf, size_t len) {
 | 
				
			|||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
float OTAComponent::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
 | 
					float ESPHomeOTAComponent::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
 | 
				
			||||||
uint16_t OTAComponent::get_port() const { return this->port_; }
 | 
					uint16_t ESPHomeOTAComponent::get_port() const { return this->port_; }
 | 
				
			||||||
void OTAComponent::set_port(uint16_t port) { this->port_ = port; }
 | 
					void ESPHomeOTAComponent::set_port(uint16_t port) { this->port_ = port; }
 | 
				
			||||||
 | 
					 | 
				
			||||||
void OTAComponent::set_safe_mode_pending(const bool &pending) {
 | 
					 | 
				
			||||||
  if (!this->has_safe_mode_)
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  uint32_t current_rtc = this->read_rtc_();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (pending && current_rtc != esphome::ota::OTAComponent::ENTER_SAFE_MODE_MAGIC) {
 | 
					 | 
				
			||||||
    ESP_LOGI(TAG, "Device will enter safe mode on next boot.");
 | 
					 | 
				
			||||||
    this->write_rtc_(esphome::ota::OTAComponent::ENTER_SAFE_MODE_MAGIC);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!pending && current_rtc == esphome::ota::OTAComponent::ENTER_SAFE_MODE_MAGIC) {
 | 
					 | 
				
			||||||
    ESP_LOGI(TAG, "Safe mode pending has been cleared");
 | 
					 | 
				
			||||||
    this->clean_rtc();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
bool OTAComponent::get_safe_mode_pending() {
 | 
					 | 
				
			||||||
  return this->has_safe_mode_ && this->read_rtc_() == esphome::ota::OTAComponent::ENTER_SAFE_MODE_MAGIC;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool OTAComponent::should_enter_safe_mode(uint8_t num_attempts, uint32_t enable_time) {
 | 
					 | 
				
			||||||
  this->has_safe_mode_ = true;
 | 
					 | 
				
			||||||
  this->safe_mode_start_time_ = millis();
 | 
					 | 
				
			||||||
  this->safe_mode_enable_time_ = enable_time;
 | 
					 | 
				
			||||||
  this->safe_mode_num_attempts_ = num_attempts;
 | 
					 | 
				
			||||||
  this->rtc_ = global_preferences->make_preference<uint32_t>(233825507UL, false);
 | 
					 | 
				
			||||||
  this->safe_mode_rtc_value_ = this->read_rtc_();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  bool is_manual_safe_mode = this->safe_mode_rtc_value_ == esphome::ota::OTAComponent::ENTER_SAFE_MODE_MAGIC;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (is_manual_safe_mode) {
 | 
					 | 
				
			||||||
    ESP_LOGI(TAG, "Safe mode has been entered manually");
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "There have been %" PRIu32 " suspected unsuccessful boot attempts.", this->safe_mode_rtc_value_);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (this->safe_mode_rtc_value_ >= num_attempts || is_manual_safe_mode) {
 | 
					 | 
				
			||||||
    this->clean_rtc();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!is_manual_safe_mode) {
 | 
					 | 
				
			||||||
      ESP_LOGE(TAG, "Boot loop detected. Proceeding to safe mode.");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    this->status_set_error();
 | 
					 | 
				
			||||||
    this->set_timeout(enable_time, []() {
 | 
					 | 
				
			||||||
      ESP_LOGE(TAG, "No OTA attempt made, restarting.");
 | 
					 | 
				
			||||||
      App.reboot();
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Delay here to allow power to stabilise before Wi-Fi/Ethernet is initialised.
 | 
					 | 
				
			||||||
    delay(300);  // NOLINT
 | 
					 | 
				
			||||||
    App.setup();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ESP_LOGI(TAG, "Waiting for OTA attempt.");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    // increment counter
 | 
					 | 
				
			||||||
    this->write_rtc_(this->safe_mode_rtc_value_ + 1);
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
void OTAComponent::write_rtc_(uint32_t val) {
 | 
					 | 
				
			||||||
  this->rtc_.save(&val);
 | 
					 | 
				
			||||||
  global_preferences->sync();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
uint32_t OTAComponent::read_rtc_() {
 | 
					 | 
				
			||||||
  uint32_t val;
 | 
					 | 
				
			||||||
  if (!this->rtc_.load(&val))
 | 
					 | 
				
			||||||
    return 0;
 | 
					 | 
				
			||||||
  return val;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
void OTAComponent::clean_rtc() { this->write_rtc_(0); }
 | 
					 | 
				
			||||||
void OTAComponent::on_safe_shutdown() {
 | 
					 | 
				
			||||||
  if (this->has_safe_mode_ && this->read_rtc_() != esphome::ota::OTAComponent::ENTER_SAFE_MODE_MAGIC)
 | 
					 | 
				
			||||||
    this->clean_rtc();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_OTA_STATE_CALLBACK
 | 
					 | 
				
			||||||
void OTAComponent::add_on_state_callback(std::function<void(OTAState, float, uint8_t)> &&callback) {
 | 
					 | 
				
			||||||
  this->state_callback_.add(std::move(callback));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}  // namespace ota
 | 
					 | 
				
			||||||
}  // namespace esphome
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										43
									
								
								esphome/components/esphome/ota/ota_esphome.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								esphome/components/esphome/ota/ota_esphome.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "esphome/core/defines.h"
 | 
				
			||||||
 | 
					#include "esphome/core/helpers.h"
 | 
				
			||||||
 | 
					#include "esphome/core/preferences.h"
 | 
				
			||||||
 | 
					#include "esphome/components/ota/ota_backend.h"
 | 
				
			||||||
 | 
					#include "esphome/components/socket/socket.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// ESPHomeOTAComponent provides a simple way to integrate Over-the-Air updates into your app using ArduinoOTA.
 | 
				
			||||||
 | 
					class ESPHomeOTAComponent : public ota::OTAComponent {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					#ifdef USE_OTA_PASSWORD
 | 
				
			||||||
 | 
					  void set_auth_password(const std::string &password) { password_ = password; }
 | 
				
			||||||
 | 
					#endif  // USE_OTA_PASSWORD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Manually set the port OTA should listen on
 | 
				
			||||||
 | 
					  void set_port(uint16_t port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void setup() override;
 | 
				
			||||||
 | 
					  void dump_config() override;
 | 
				
			||||||
 | 
					  float get_setup_priority() const override;
 | 
				
			||||||
 | 
					  void loop() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint16_t get_port() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 protected:
 | 
				
			||||||
 | 
					  void handle_();
 | 
				
			||||||
 | 
					  bool readall_(uint8_t *buf, size_t len);
 | 
				
			||||||
 | 
					  bool writeall_(const uint8_t *buf, size_t len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_OTA_PASSWORD
 | 
				
			||||||
 | 
					  std::string password_;
 | 
				
			||||||
 | 
					#endif  // USE_OTA_PASSWORD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint16_t port_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::unique_ptr<socket::Socket> server_;
 | 
				
			||||||
 | 
					  std::unique_ptr<socket::Socket> client_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
@@ -11,6 +11,7 @@ from esphome.components.esp32.const import (
 | 
				
			|||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_DOMAIN,
 | 
					    CONF_DOMAIN,
 | 
				
			||||||
    CONF_ID,
 | 
					    CONF_ID,
 | 
				
			||||||
 | 
					    CONF_VALUE,
 | 
				
			||||||
    CONF_MANUAL_IP,
 | 
					    CONF_MANUAL_IP,
 | 
				
			||||||
    CONF_STATIC_IP,
 | 
					    CONF_STATIC_IP,
 | 
				
			||||||
    CONF_TYPE,
 | 
					    CONF_TYPE,
 | 
				
			||||||
@@ -26,6 +27,8 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_INTERRUPT_PIN,
 | 
					    CONF_INTERRUPT_PIN,
 | 
				
			||||||
    CONF_RESET_PIN,
 | 
					    CONF_RESET_PIN,
 | 
				
			||||||
    CONF_SPI,
 | 
					    CONF_SPI,
 | 
				
			||||||
 | 
					    CONF_PAGE_ID,
 | 
				
			||||||
 | 
					    CONF_ADDRESS,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from esphome.core import CORE, coroutine_with_priority
 | 
					from esphome.core import CORE, coroutine_with_priority
 | 
				
			||||||
from esphome.components.network import IPAddress
 | 
					from esphome.components.network import IPAddress
 | 
				
			||||||
@@ -36,11 +39,13 @@ DEPENDENCIES = ["esp32"]
 | 
				
			|||||||
AUTO_LOAD = ["network"]
 | 
					AUTO_LOAD = ["network"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ethernet_ns = cg.esphome_ns.namespace("ethernet")
 | 
					ethernet_ns = cg.esphome_ns.namespace("ethernet")
 | 
				
			||||||
 | 
					PHYRegister = ethernet_ns.struct("PHYRegister")
 | 
				
			||||||
CONF_PHY_ADDR = "phy_addr"
 | 
					CONF_PHY_ADDR = "phy_addr"
 | 
				
			||||||
CONF_MDC_PIN = "mdc_pin"
 | 
					CONF_MDC_PIN = "mdc_pin"
 | 
				
			||||||
CONF_MDIO_PIN = "mdio_pin"
 | 
					CONF_MDIO_PIN = "mdio_pin"
 | 
				
			||||||
CONF_CLK_MODE = "clk_mode"
 | 
					CONF_CLK_MODE = "clk_mode"
 | 
				
			||||||
CONF_POWER_PIN = "power_pin"
 | 
					CONF_POWER_PIN = "power_pin"
 | 
				
			||||||
 | 
					CONF_PHY_REGISTERS = "phy_registers"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONF_CLOCK_SPEED = "clock_speed"
 | 
					CONF_CLOCK_SPEED = "clock_speed"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -117,6 +122,13 @@ BASE_SCHEMA = cv.Schema(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
).extend(cv.COMPONENT_SCHEMA)
 | 
					).extend(cv.COMPONENT_SCHEMA)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PHY_REGISTER_SCHEMA = cv.Schema(
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cv.Required(CONF_ADDRESS): cv.hex_int,
 | 
				
			||||||
 | 
					        cv.Required(CONF_VALUE): cv.hex_int,
 | 
				
			||||||
 | 
					        cv.Optional(CONF_PAGE_ID): cv.hex_int,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
RMII_SCHEMA = BASE_SCHEMA.extend(
 | 
					RMII_SCHEMA = BASE_SCHEMA.extend(
 | 
				
			||||||
    cv.Schema(
 | 
					    cv.Schema(
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -127,6 +139,7 @@ RMII_SCHEMA = BASE_SCHEMA.extend(
 | 
				
			|||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cv.Optional(CONF_PHY_ADDR, default=0): cv.int_range(min=0, max=31),
 | 
					            cv.Optional(CONF_PHY_ADDR, default=0): cv.int_range(min=0, max=31),
 | 
				
			||||||
            cv.Optional(CONF_POWER_PIN): pins.internal_gpio_output_pin_number,
 | 
					            cv.Optional(CONF_POWER_PIN): pins.internal_gpio_output_pin_number,
 | 
				
			||||||
 | 
					            cv.Optional(CONF_PHY_REGISTERS): cv.ensure_list(PHY_REGISTER_SCHEMA),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -198,6 +211,15 @@ def manual_ip(config):
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def phy_register(address: int, value: int, page: int):
 | 
				
			||||||
 | 
					    return cg.StructInitializer(
 | 
				
			||||||
 | 
					        PHYRegister,
 | 
				
			||||||
 | 
					        ("address", address),
 | 
				
			||||||
 | 
					        ("value", value),
 | 
				
			||||||
 | 
					        ("page", page),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@coroutine_with_priority(60.0)
 | 
					@coroutine_with_priority(60.0)
 | 
				
			||||||
async def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
@@ -225,6 +247,13 @@ async def to_code(config):
 | 
				
			|||||||
        cg.add(var.set_clk_mode(*CLK_MODES[config[CONF_CLK_MODE]]))
 | 
					        cg.add(var.set_clk_mode(*CLK_MODES[config[CONF_CLK_MODE]]))
 | 
				
			||||||
        if CONF_POWER_PIN in config:
 | 
					        if CONF_POWER_PIN in config:
 | 
				
			||||||
            cg.add(var.set_power_pin(config[CONF_POWER_PIN]))
 | 
					            cg.add(var.set_power_pin(config[CONF_POWER_PIN]))
 | 
				
			||||||
 | 
					        for register_value in config.get(CONF_PHY_REGISTERS, []):
 | 
				
			||||||
 | 
					            reg = phy_register(
 | 
				
			||||||
 | 
					                register_value.get(CONF_ADDRESS),
 | 
				
			||||||
 | 
					                register_value.get(CONF_VALUE),
 | 
				
			||||||
 | 
					                register_value.get(CONF_PAGE_ID),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            cg.add(var.add_phy_register(reg))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cg.add(var.set_type(ETHERNET_TYPES[config[CONF_TYPE]]))
 | 
					    cg.add(var.set_type(ETHERNET_TYPES[config[CONF_TYPE]]))
 | 
				
			||||||
    cg.add(var.set_use_address(config[CONF_USE_ADDRESS]))
 | 
					    cg.add(var.set_use_address(config[CONF_USE_ADDRESS]))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,6 +28,13 @@ EthernetComponent *global_eth_component;  // NOLINT(cppcoreguidelines-avoid-non-
 | 
				
			|||||||
    return; \
 | 
					    return; \
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ESPHL_ERROR_CHECK_RET(err, message, ret) \
 | 
				
			||||||
 | 
					  if ((err) != ESP_OK) { \
 | 
				
			||||||
 | 
					    ESP_LOGE(TAG, message ": (%d) %s", err, esp_err_to_name(err)); \
 | 
				
			||||||
 | 
					    this->mark_failed(); \
 | 
				
			||||||
 | 
					    return ret; \
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EthernetComponent::EthernetComponent() { global_eth_component = this; }
 | 
					EthernetComponent::EthernetComponent() { global_eth_component = this; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EthernetComponent::setup() {
 | 
					void EthernetComponent::setup() {
 | 
				
			||||||
@@ -98,11 +105,15 @@ void EthernetComponent::setup() {
 | 
				
			|||||||
      .post_cb = nullptr,
 | 
					      .post_cb = nullptr,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if USE_ESP_IDF && (ESP_IDF_VERSION_MAJOR >= 5)
 | 
				
			||||||
 | 
					  eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(host, &devcfg);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
  spi_device_handle_t spi_handle = nullptr;
 | 
					  spi_device_handle_t spi_handle = nullptr;
 | 
				
			||||||
  err = spi_bus_add_device(host, &devcfg, &spi_handle);
 | 
					  err = spi_bus_add_device(host, &devcfg, &spi_handle);
 | 
				
			||||||
  ESPHL_ERROR_CHECK(err, "SPI bus add device error");
 | 
					  ESPHL_ERROR_CHECK(err, "SPI bus add device error");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
 | 
					  eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
  w5500_config.int_gpio_num = this->interrupt_pin_;
 | 
					  w5500_config.int_gpio_num = this->interrupt_pin_;
 | 
				
			||||||
  phy_config.phy_addr = this->phy_addr_spi_;
 | 
					  phy_config.phy_addr = this->phy_addr_spi_;
 | 
				
			||||||
  phy_config.reset_gpio_num = this->reset_pin_;
 | 
					  phy_config.reset_gpio_num = this->reset_pin_;
 | 
				
			||||||
@@ -184,9 +195,9 @@ void EthernetComponent::setup() {
 | 
				
			|||||||
    // KSZ8081RNA default is incorrect. It expects a 25MHz clock instead of the 50MHz we provide.
 | 
					    // KSZ8081RNA default is incorrect. It expects a 25MHz clock instead of the 50MHz we provide.
 | 
				
			||||||
    this->ksz8081_set_clock_reference_(mac);
 | 
					    this->ksz8081_set_clock_reference_(mac);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (this->type_ == ETHERNET_TYPE_RTL8201 && this->clk_mode_ == EMAC_CLK_EXT_IN) {
 | 
					
 | 
				
			||||||
    // Change in default behavior of RTL8201FI may require register setting to enable external clock
 | 
					  for (const auto &phy_register : this->phy_registers_) {
 | 
				
			||||||
    this->rtl8201_set_rmii_mode_(mac);
 | 
					    this->write_phy_register_(mac, phy_register);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -406,7 +417,7 @@ void EthernetComponent::start_connect_() {
 | 
				
			|||||||
  global_eth_component->ipv6_count_ = 0;
 | 
					  global_eth_component->ipv6_count_ = 0;
 | 
				
			||||||
#endif /* USE_NETWORK_IPV6 */
 | 
					#endif /* USE_NETWORK_IPV6 */
 | 
				
			||||||
  this->connect_begin_ = millis();
 | 
					  this->connect_begin_ = millis();
 | 
				
			||||||
  this->status_set_warning();
 | 
					  this->status_set_warning("waiting for IP configuration");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  esp_err_t err;
 | 
					  esp_err_t err;
 | 
				
			||||||
  err = esp_netif_set_hostname(this->eth_netif_, App.get_name().c_str());
 | 
					  err = esp_netif_set_hostname(this->eth_netif_, App.get_name().c_str());
 | 
				
			||||||
@@ -494,22 +505,9 @@ void EthernetComponent::dump_connect_params_() {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
#endif /* USE_NETWORK_IPV6 */
 | 
					#endif /* USE_NETWORK_IPV6 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  esp_err_t err;
 | 
					  ESP_LOGCONFIG(TAG, "  MAC Address: %s", this->get_eth_mac_address_pretty().c_str());
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "  Is Full Duplex: %s", YESNO(this->get_duplex_mode() == ETH_DUPLEX_FULL));
 | 
				
			||||||
  uint8_t mac[6];
 | 
					  ESP_LOGCONFIG(TAG, "  Link Speed: %u", this->get_link_speed() == ETH_SPEED_100M ? 100 : 10);
 | 
				
			||||||
  err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_MAC_ADDR, &mac);
 | 
					 | 
				
			||||||
  ESPHL_ERROR_CHECK(err, "ETH_CMD_G_MAC error");
 | 
					 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  MAC Address: %02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  eth_duplex_t duplex_mode;
 | 
					 | 
				
			||||||
  err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_DUPLEX_MODE, &duplex_mode);
 | 
					 | 
				
			||||||
  ESPHL_ERROR_CHECK(err, "ETH_CMD_G_DUPLEX_MODE error");
 | 
					 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  Is Full Duplex: %s", YESNO(duplex_mode == ETH_DUPLEX_FULL));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  eth_speed_t speed;
 | 
					 | 
				
			||||||
  err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_SPEED, &speed);
 | 
					 | 
				
			||||||
  ESPHL_ERROR_CHECK(err, "ETH_CMD_G_SPEED error");
 | 
					 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  Link Speed: %u", speed == ETH_SPEED_100M ? 100 : 10);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ETHERNET_SPI
 | 
					#ifdef USE_ETHERNET_SPI
 | 
				
			||||||
@@ -529,6 +527,7 @@ void EthernetComponent::set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_
 | 
				
			|||||||
  this->clk_mode_ = clk_mode;
 | 
					  this->clk_mode_ = clk_mode;
 | 
				
			||||||
  this->clk_gpio_ = clk_gpio;
 | 
					  this->clk_gpio_ = clk_gpio;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					void EthernetComponent::add_phy_register(PHYRegister register_value) { this->phy_registers_.push_back(register_value); }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
void EthernetComponent::set_type(EthernetType type) { this->type_ = type; }
 | 
					void EthernetComponent::set_type(EthernetType type) { this->type_ = type; }
 | 
				
			||||||
void EthernetComponent::set_manual_ip(const ManualIP &manual_ip) { this->manual_ip_ = manual_ip; }
 | 
					void EthernetComponent::set_manual_ip(const ManualIP &manual_ip) { this->manual_ip_ = manual_ip; }
 | 
				
			||||||
@@ -542,6 +541,34 @@ std::string EthernetComponent::get_use_address() const {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void EthernetComponent::set_use_address(const std::string &use_address) { this->use_address_ = use_address; }
 | 
					void EthernetComponent::set_use_address(const std::string &use_address) { this->use_address_ = use_address; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EthernetComponent::get_eth_mac_address_raw(uint8_t *mac) {
 | 
				
			||||||
 | 
					  esp_err_t err;
 | 
				
			||||||
 | 
					  err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_MAC_ADDR, mac);
 | 
				
			||||||
 | 
					  ESPHL_ERROR_CHECK(err, "ETH_CMD_G_MAC error");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string EthernetComponent::get_eth_mac_address_pretty() {
 | 
				
			||||||
 | 
					  uint8_t mac[6];
 | 
				
			||||||
 | 
					  get_mac_address_raw(mac);
 | 
				
			||||||
 | 
					  return str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					eth_duplex_t EthernetComponent::get_duplex_mode() {
 | 
				
			||||||
 | 
					  esp_err_t err;
 | 
				
			||||||
 | 
					  eth_duplex_t duplex_mode;
 | 
				
			||||||
 | 
					  err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_DUPLEX_MODE, &duplex_mode);
 | 
				
			||||||
 | 
					  ESPHL_ERROR_CHECK_RET(err, "ETH_CMD_G_DUPLEX_MODE error", ETH_DUPLEX_HALF);
 | 
				
			||||||
 | 
					  return duplex_mode;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					eth_speed_t EthernetComponent::get_link_speed() {
 | 
				
			||||||
 | 
					  esp_err_t err;
 | 
				
			||||||
 | 
					  eth_speed_t speed;
 | 
				
			||||||
 | 
					  err = esp_eth_ioctl(this->eth_handle_, ETH_CMD_G_SPEED, &speed);
 | 
				
			||||||
 | 
					  ESPHL_ERROR_CHECK_RET(err, "ETH_CMD_G_SPEED error", ETH_SPEED_10M);
 | 
				
			||||||
 | 
					  return speed;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool EthernetComponent::powerdown() {
 | 
					bool EthernetComponent::powerdown() {
 | 
				
			||||||
  ESP_LOGI(TAG, "Powering down ethernet PHY");
 | 
					  ESP_LOGI(TAG, "Powering down ethernet PHY");
 | 
				
			||||||
  if (this->phy_ == nullptr) {
 | 
					  if (this->phy_ == nullptr) {
 | 
				
			||||||
@@ -572,11 +599,11 @@ void EthernetComponent::ksz8081_set_clock_reference_(esp_eth_mac_t *mac) {
 | 
				
			|||||||
  /*
 | 
					  /*
 | 
				
			||||||
   * Bit 7 is `RMII Reference Clock Select`. Default is `0`.
 | 
					   * Bit 7 is `RMII Reference Clock Select`. Default is `0`.
 | 
				
			||||||
   * KSZ8081RNA:
 | 
					   * KSZ8081RNA:
 | 
				
			||||||
   *   0 - clock input to XI (Pin 8) is 25 MHz for RMII – 25 MHz clock mode.
 | 
					   *   0 - clock input to XI (Pin 8) is 25 MHz for RMII - 25 MHz clock mode.
 | 
				
			||||||
   *   1 - clock input to XI (Pin 8) is 50 MHz for RMII – 50 MHz clock mode.
 | 
					   *   1 - clock input to XI (Pin 8) is 50 MHz for RMII - 50 MHz clock mode.
 | 
				
			||||||
   * KSZ8081RND:
 | 
					   * KSZ8081RND:
 | 
				
			||||||
   *   0 - clock input to XI (Pin 8) is 50 MHz for RMII – 50 MHz clock mode.
 | 
					   *   0 - clock input to XI (Pin 8) is 50 MHz for RMII - 50 MHz clock mode.
 | 
				
			||||||
   *   1 - clock input to XI (Pin 8) is 25 MHz (driven clock only, not a crystal) for RMII – 25 MHz clock mode.
 | 
					   *   1 - clock input to XI (Pin 8) is 25 MHz (driven clock only, not a crystal) for RMII - 25 MHz clock mode.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  if ((phy_control_2 & (1 << 7)) != (1 << 7)) {
 | 
					  if ((phy_control_2 & (1 << 7)) != (1 << 7)) {
 | 
				
			||||||
    phy_control_2 |= 1 << 7;
 | 
					    phy_control_2 |= 1 << 7;
 | 
				
			||||||
@@ -587,44 +614,27 @@ void EthernetComponent::ksz8081_set_clock_reference_(esp_eth_mac_t *mac) {
 | 
				
			|||||||
    ESP_LOGVV(TAG, "KSZ8081 PHY Control 2: %s", format_hex_pretty((u_int8_t *) &phy_control_2, 2).c_str());
 | 
					    ESP_LOGVV(TAG, "KSZ8081 PHY Control 2: %s", format_hex_pretty((u_int8_t *) &phy_control_2, 2).c_str());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
constexpr uint8_t RTL8201_RMSR_REG_ADDR = 0x10;
 | 
					
 | 
				
			||||||
void EthernetComponent::rtl8201_set_rmii_mode_(esp_eth_mac_t *mac) {
 | 
					void EthernetComponent::write_phy_register_(esp_eth_mac_t *mac, PHYRegister register_data) {
 | 
				
			||||||
  esp_err_t err;
 | 
					  esp_err_t err;
 | 
				
			||||||
  uint32_t phy_rmii_mode;
 | 
					  constexpr uint8_t eth_phy_psr_reg_addr = 0x1F;
 | 
				
			||||||
  err = mac->write_phy_reg(mac, this->phy_addr_, 0x1f, 0x07);
 | 
					 | 
				
			||||||
  ESPHL_ERROR_CHECK(err, "Setting Page 7 failed");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*
 | 
					  if (this->type_ == ETHERNET_TYPE_RTL8201 && register_data.page) {
 | 
				
			||||||
   * RTL8201 RMII Mode Setting Register (RMSR)
 | 
					    ESP_LOGD(TAG, "Select PHY Register Page: 0x%02" PRIX32, register_data.page);
 | 
				
			||||||
   * Page 7 Register 16
 | 
					    err = mac->write_phy_reg(mac, this->phy_addr_, eth_phy_psr_reg_addr, register_data.page);
 | 
				
			||||||
   *
 | 
					    ESPHL_ERROR_CHECK(err, "Select PHY Register page failed");
 | 
				
			||||||
   * bit 0      Reserved            0
 | 
					  }
 | 
				
			||||||
   * bit 1      Rg_rmii_rxdsel      1 (default)
 | 
					 | 
				
			||||||
   * bit 2      Rg_rmii_rxdv_sel:   0 (default)
 | 
					 | 
				
			||||||
   * bit 3      RMII Mode:          1 (RMII Mode)
 | 
					 | 
				
			||||||
   * bit 4~7    Rg_rmii_rx_offset:  1111 (default)
 | 
					 | 
				
			||||||
   * bit 8~11   Rg_rmii_tx_offset:  1111 (default)
 | 
					 | 
				
			||||||
   * bit 12     Rg_rmii_clkdir:     1 (Input)
 | 
					 | 
				
			||||||
   * bit 13~15  Reserved            000
 | 
					 | 
				
			||||||
   *
 | 
					 | 
				
			||||||
   * Binary: 0001 1111 1111 1010
 | 
					 | 
				
			||||||
   * Hex: 0x1FFA
 | 
					 | 
				
			||||||
   *
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  err = mac->read_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, &(phy_rmii_mode));
 | 
					  ESP_LOGD(TAG, "Writing to PHY Register Address: 0x%02" PRIX32, register_data.address);
 | 
				
			||||||
  ESPHL_ERROR_CHECK(err, "Read PHY RMSR Register failed");
 | 
					  ESP_LOGD(TAG, "Writing to PHY Register Value: 0x%04" PRIX32, register_data.value);
 | 
				
			||||||
  ESP_LOGV(TAG, "Hardware default RTL8201 RMII Mode Register is: 0x%04X", phy_rmii_mode);
 | 
					  err = mac->write_phy_reg(mac, this->phy_addr_, register_data.address, register_data.value);
 | 
				
			||||||
 | 
					  ESPHL_ERROR_CHECK(err, "Writing PHY Register failed");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  err = mac->write_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, 0x1FFA);
 | 
					  if (this->type_ == ETHERNET_TYPE_RTL8201 && register_data.page) {
 | 
				
			||||||
  ESPHL_ERROR_CHECK(err, "Setting Register 16 RMII Mode Setting failed");
 | 
					    ESP_LOGD(TAG, "Select PHY Register Page 0x%02" PRIX32, 0x0);
 | 
				
			||||||
 | 
					    err = mac->write_phy_reg(mac, this->phy_addr_, eth_phy_psr_reg_addr, 0x0);
 | 
				
			||||||
  err = mac->read_phy_reg(mac, this->phy_addr_, RTL8201_RMSR_REG_ADDR, &(phy_rmii_mode));
 | 
					    ESPHL_ERROR_CHECK(err, "Select PHY Register Page 0 failed");
 | 
				
			||||||
  ESPHL_ERROR_CHECK(err, "Read PHY RMSR Register failed");
 | 
					  }
 | 
				
			||||||
  ESP_LOGV(TAG, "Setting RTL8201 RMII Mode Register to: 0x%04X", phy_rmii_mode);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  err = mac->write_phy_reg(mac, this->phy_addr_, 0x1f, 0x0);
 | 
					 | 
				
			||||||
  ESPHL_ERROR_CHECK(err, "Setting Page 0 failed");
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@
 | 
				
			|||||||
#include "esp_eth.h"
 | 
					#include "esp_eth.h"
 | 
				
			||||||
#include "esp_eth_mac.h"
 | 
					#include "esp_eth_mac.h"
 | 
				
			||||||
#include "esp_netif.h"
 | 
					#include "esp_netif.h"
 | 
				
			||||||
 | 
					#include "esp_mac.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace ethernet {
 | 
					namespace ethernet {
 | 
				
			||||||
@@ -34,6 +35,12 @@ struct ManualIP {
 | 
				
			|||||||
  network::IPAddress dns2;  ///< The second DNS server. 0.0.0.0 for default.
 | 
					  network::IPAddress dns2;  ///< The second DNS server. 0.0.0.0 for default.
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct PHYRegister {
 | 
				
			||||||
 | 
					  uint32_t address;
 | 
				
			||||||
 | 
					  uint32_t value;
 | 
				
			||||||
 | 
					  uint32_t page;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class EthernetComponentState {
 | 
					enum class EthernetComponentState {
 | 
				
			||||||
  STOPPED,
 | 
					  STOPPED,
 | 
				
			||||||
  CONNECTING,
 | 
					  CONNECTING,
 | 
				
			||||||
@@ -65,6 +72,7 @@ class EthernetComponent : public Component {
 | 
				
			|||||||
  void set_mdc_pin(uint8_t mdc_pin);
 | 
					  void set_mdc_pin(uint8_t mdc_pin);
 | 
				
			||||||
  void set_mdio_pin(uint8_t mdio_pin);
 | 
					  void set_mdio_pin(uint8_t mdio_pin);
 | 
				
			||||||
  void set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_clock_gpio_t clk_gpio);
 | 
					  void set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_clock_gpio_t clk_gpio);
 | 
				
			||||||
 | 
					  void add_phy_register(PHYRegister register_value);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  void set_type(EthernetType type);
 | 
					  void set_type(EthernetType type);
 | 
				
			||||||
  void set_manual_ip(const ManualIP &manual_ip);
 | 
					  void set_manual_ip(const ManualIP &manual_ip);
 | 
				
			||||||
@@ -73,6 +81,10 @@ class EthernetComponent : public Component {
 | 
				
			|||||||
  network::IPAddress get_dns_address(uint8_t num);
 | 
					  network::IPAddress get_dns_address(uint8_t num);
 | 
				
			||||||
  std::string get_use_address() const;
 | 
					  std::string get_use_address() const;
 | 
				
			||||||
  void set_use_address(const std::string &use_address);
 | 
					  void set_use_address(const std::string &use_address);
 | 
				
			||||||
 | 
					  void get_eth_mac_address_raw(uint8_t *mac);
 | 
				
			||||||
 | 
					  std::string get_eth_mac_address_pretty();
 | 
				
			||||||
 | 
					  eth_duplex_t get_duplex_mode();
 | 
				
			||||||
 | 
					  eth_speed_t get_link_speed();
 | 
				
			||||||
  bool powerdown();
 | 
					  bool powerdown();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
@@ -86,8 +98,8 @@ class EthernetComponent : public Component {
 | 
				
			|||||||
  void dump_connect_params_();
 | 
					  void dump_connect_params_();
 | 
				
			||||||
  /// @brief Set `RMII Reference Clock Select` bit for KSZ8081.
 | 
					  /// @brief Set `RMII Reference Clock Select` bit for KSZ8081.
 | 
				
			||||||
  void ksz8081_set_clock_reference_(esp_eth_mac_t *mac);
 | 
					  void ksz8081_set_clock_reference_(esp_eth_mac_t *mac);
 | 
				
			||||||
  /// @brief Set `RMII Mode Setting Register` for RTL8201.
 | 
					  /// @brief Set arbitratry PHY registers from config.
 | 
				
			||||||
  void rtl8201_set_rmii_mode_(esp_eth_mac_t *mac);
 | 
					  void write_phy_register_(esp_eth_mac_t *mac, PHYRegister register_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string use_address_;
 | 
					  std::string use_address_;
 | 
				
			||||||
#ifdef USE_ETHERNET_SPI
 | 
					#ifdef USE_ETHERNET_SPI
 | 
				
			||||||
@@ -106,6 +118,7 @@ class EthernetComponent : public Component {
 | 
				
			|||||||
  uint8_t mdio_pin_{18};
 | 
					  uint8_t mdio_pin_{18};
 | 
				
			||||||
  emac_rmii_clock_mode_t clk_mode_{EMAC_CLK_EXT_IN};
 | 
					  emac_rmii_clock_mode_t clk_mode_{EMAC_CLK_EXT_IN};
 | 
				
			||||||
  emac_rmii_clock_gpio_t clk_gpio_{EMAC_CLK_IN_GPIO};
 | 
					  emac_rmii_clock_gpio_t clk_gpio_{EMAC_CLK_IN_GPIO};
 | 
				
			||||||
 | 
					  std::vector<PHYRegister> phy_registers_{};
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  EthernetType type_{ETHERNET_TYPE_UNKNOWN};
 | 
					  EthernetType type_{ETHERNET_TYPE_UNKNOWN};
 | 
				
			||||||
  optional<ManualIP> manual_ip_{};
 | 
					  optional<ManualIP> manual_ip_{};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@ static const char *const TAG = "ethernet_info";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void IPAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo IPAddress", this); }
 | 
					void IPAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo IPAddress", this); }
 | 
				
			||||||
void DNSAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo DNS Address", this); }
 | 
					void DNSAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo DNS Address", this); }
 | 
				
			||||||
 | 
					void MACAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo MAC Address", this); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace ethernet_info
 | 
					}  // namespace ethernet_info
 | 
				
			||||||
}  // namespace esphome
 | 
					}  // namespace esphome
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,6 +59,13 @@ class DNSAddressEthernetInfo : public PollingComponent, public text_sensor::Text
 | 
				
			|||||||
  std::string last_results_;
 | 
					  std::string last_results_;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MACAddressEthernetInfo : public Component, public text_sensor::TextSensor {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  void setup() override { this->publish_state(ethernet::global_eth_component->get_eth_mac_address_pretty()); }
 | 
				
			||||||
 | 
					  std::string unique_id() override { return get_mac_address() + "-ethernetinfo-mac"; }
 | 
				
			||||||
 | 
					  void dump_config() override;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace ethernet_info
 | 
					}  // namespace ethernet_info
 | 
				
			||||||
}  // namespace esphome
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user