mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-04 00:51:49 +00:00 
			
		
		
		
	Compare commits
	
		
			364 Commits
		
	
	
		
			2022.11.0b
			...
			2023.2.2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					b5927322e6 | ||
| 
						 | 
					1cf4107e1c | ||
| 
						 | 
					c12408326c | ||
| 
						 | 
					4434e59e5a | ||
| 
						 | 
					45180d98f6 | ||
| 
						 | 
					44494ad18e | ||
| 
						 | 
					1447536906 | ||
| 
						 | 
					27ec517084 | ||
| 
						 | 
					ce1f034bac | ||
| 
						 | 
					f1f96f16e9 | ||
| 
						 | 
					7665e9b076 | ||
| 
						 | 
					227d94f38d | ||
| 
						 | 
					b724ae9e0e | ||
| 
						 | 
					df6cc14201 | ||
| 
						 | 
					d981d7859d | ||
| 
						 | 
					0f1ec515c1 | ||
| 
						 | 
					78e18256f7 | ||
| 
						 | 
					4899dfe642 | ||
| 
						 | 
					d6b6e94059 | ||
| 
						 | 
					310355a00b | ||
| 
						 | 
					8cf26d6f3c | ||
| 
						 | 
					b15a10f905 | ||
| 
						 | 
					5dcf1debd7 | ||
| 
						 | 
					9b57e1ac1d | ||
| 
						 | 
					68683e3a50 | ||
| 
						 | 
					d83324c4dc | ||
| 
						 | 
					ecde4c1d2d | ||
| 
						 | 
					bd8e470726 | ||
| 
						 | 
					d2913fe627 | ||
| 
						 | 
					43acc7dc2c | ||
| 
						 | 
					e2a16d758b | ||
| 
						 | 
					17ea0efb08 | ||
| 
						 | 
					2fbd33267e | ||
| 
						 | 
					cf3977f088 | ||
| 
						 | 
					d20d4947ac | ||
| 
						 | 
					7810ad40d7 | ||
| 
						 | 
					7e1e799b3a | ||
| 
						 | 
					dfafc41ce6 | ||
| 
						 | 
					e460792c43 | ||
| 
						 | 
					a9dc491a54 | ||
| 
						 | 
					ac6693f177 | ||
| 
						 | 
					c6742117d3 | ||
| 
						 | 
					b5c47b9669 | ||
| 
						 | 
					40df3aa55e | ||
| 
						 | 
					393ca64d70 | ||
| 
						 | 
					d3627f0972 | ||
| 
						 | 
					124ab31f22 | ||
| 
						 | 
					1b66fa5004 | ||
| 
						 | 
					9494c27ad8 | ||
| 
						 | 
					3facfa5c21 | ||
| 
						 | 
					93ddce2e79 | ||
| 
						 | 
					0bf6e21e1a | ||
| 
						 | 
					6b7b076875 | ||
| 
						 | 
					8d6ffb9169 | ||
| 
						 | 
					e95d6041d8 | ||
| 
						 | 
					0554b06b7e | ||
| 
						 | 
					e3d9c44bdc | ||
| 
						 | 
					e847766514 | ||
| 
						 | 
					d4a8df04b8 | ||
| 
						 | 
					4af4649e23 | ||
| 
						 | 
					8bcddef39d | ||
| 
						 | 
					4ac96ccea2 | ||
| 
						 | 
					3c5de77ae9 | ||
| 
						 | 
					a2925b1d37 | ||
| 
						 | 
					73748e9e20 | ||
| 
						 | 
					034b47c23a | ||
| 
						 | 
					3e017efa30 | ||
| 
						 | 
					aca56fcdcc | ||
| 
						 | 
					75c9823899 | ||
| 
						 | 
					c8c0bd3351 | ||
| 
						 | 
					e1cdeb7c8f | ||
| 
						 | 
					7f97f42552 | ||
| 
						 | 
					aa7f3569ec | ||
| 
						 | 
					2d0a08442e | ||
| 
						 | 
					d2380756b2 | ||
| 
						 | 
					e778a445d9 | ||
| 
						 | 
					ded86493c2 | ||
| 
						 | 
					4d72eb42a5 | ||
| 
						 | 
					267f0587c6 | ||
| 
						 | 
					4a374a466a | ||
| 
						 | 
					b27a328d1e | ||
| 
						 | 
					d94e9d92ca | ||
| 
						 | 
					36c2e770bf | ||
| 
						 | 
					79040c116d | ||
| 
						 | 
					4aac76c549 | ||
| 
						 | 
					0ea97df1af | ||
| 
						 | 
					92e66a2764 | ||
| 
						 | 
					925e3cb6c9 | ||
| 
						 | 
					6757acba56 | ||
| 
						 | 
					5cc91cdd95 | ||
| 
						 | 
					2b41886819 | ||
| 
						 | 
					72c6efd6a0 | ||
| 
						 | 
					a1f1804112 | ||
| 
						 | 
					a8b1ceb4e9 | ||
| 
						 | 
					4fb0f7f8c6 | ||
| 
						 | 
					958cadeca8 | ||
| 
						 | 
					00f2655f1a | ||
| 
						 | 
					074f5029eb | ||
| 
						 | 
					615d591367 | ||
| 
						 | 
					e236c53f05 | ||
| 
						 | 
					10c7055b41 | ||
| 
						 | 
					a127e60e1b | ||
| 
						 | 
					66a3361e9d | ||
| 
						 | 
					13cfe11a19 | ||
| 
						 | 
					6d65671f92 | ||
| 
						 | 
					f2eafa8fbe | ||
| 
						 | 
					e4ca3b18cc | ||
| 
						 | 
					84698ae888 | ||
| 
						 | 
					fd6d6cfb6c | ||
| 
						 | 
					8cad9dfc83 | ||
| 
						 | 
					5e2f33fde5 | ||
| 
						 | 
					029ac75a04 | ||
| 
						 | 
					3aa5953cd9 | ||
| 
						 | 
					582d90ad72 | ||
| 
						 | 
					bbb0105c2f | ||
| 
						 | 
					37d17feecf | ||
| 
						 | 
					4bf5faf808 | ||
| 
						 | 
					ddedc1cd76 | ||
| 
						 | 
					1bb90f304c | ||
| 
						 | 
					efc6a8df35 | ||
| 
						 | 
					e35f90d6e4 | ||
| 
						 | 
					11518364a1 | ||
| 
						 | 
					05420291ce | ||
| 
						 | 
					442faf92c6 | ||
| 
						 | 
					62c68f4d60 | ||
| 
						 | 
					c301ae3645 | ||
| 
						 | 
					3d2d681a7b | ||
| 
						 | 
					a45646af1b | ||
| 
						 | 
					27185265f6 | ||
| 
						 | 
					a9b7d98194 | ||
| 
						 | 
					ed4a7210d3 | ||
| 
						 | 
					351ea04517 | ||
| 
						 | 
					86a8e1f4a6 | ||
| 
						 | 
					1cf3424ebe | ||
| 
						 | 
					a19f0c0db0 | ||
| 
						 | 
					530df91044 | ||
| 
						 | 
					c16c0b11cb | ||
| 
						 | 
					74556b28a8 | ||
| 
						 | 
					48340d41d6 | ||
| 
						 | 
					6306348379 | ||
| 
						 | 
					b1f1329cee | ||
| 
						 | 
					75dff1e102 | ||
| 
						 | 
					fe55f3a43d | ||
| 
						 | 
					657fd9d0d5 | ||
| 
						 | 
					1511a6ebcd | ||
| 
						 | 
					ecac26aeba | ||
| 
						 | 
					19bf9b1e36 | ||
| 
						 | 
					119a6920f2 | ||
| 
						 | 
					8237e13c44 | ||
| 
						 | 
					53b60ac817 | ||
| 
						 | 
					a18ab748fd | ||
| 
						 | 
					917488bbc3 | ||
| 
						 | 
					7e376ae952 | ||
| 
						 | 
					57a1c207c2 | ||
| 
						 | 
					50e8e92f0b | ||
| 
						 | 
					ff4fd497c4 | ||
| 
						 | 
					33b1a853b9 | ||
| 
						 | 
					f2df542cb1 | ||
| 
						 | 
					ecbbf2d3f4 | ||
| 
						 | 
					b76c7a0131 | ||
| 
						 | 
					0b0984f9a0 | ||
| 
						 | 
					9767856784 | ||
| 
						 | 
					c1f09684e6 | ||
| 
						 | 
					22b384363b | ||
| 
						 | 
					5b23331751 | ||
| 
						 | 
					7a2bb32843 | ||
| 
						 | 
					c0a4e07e5a | ||
| 
						 | 
					322158cccb | ||
| 
						 | 
					8db3b59e0f | ||
| 
						 | 
					1691976587 | ||
| 
						 | 
					60e6b4d21e | ||
| 
						 | 
					5750591df2 | ||
| 
						 | 
					0d50caa179 | ||
| 
						 | 
					8b06135b41 | ||
| 
						 | 
					a75da54455 | ||
| 
						 | 
					de7f6c3f5f | ||
| 
						 | 
					4245480656 | ||
| 
						 | 
					1824c8131e | ||
| 
						 | 
					573ea55187 | ||
| 
						 | 
					b48b5d6cc7 | ||
| 
						 | 
					4e9606d2e0 | ||
| 
						 | 
					78500fa933 | ||
| 
						 | 
					9c69b98a49 | ||
| 
						 | 
					e6d8ef98d3 | ||
| 
						 | 
					3f1af1690b | ||
| 
						 | 
					39af967433 | ||
| 
						 | 
					83b5e01a28 | ||
| 
						 | 
					1eacbd50fa | ||
| 
						 | 
					84374b6b1e | ||
| 
						 | 
					391316c9b5 | ||
| 
						 | 
					705c62ebd7 | ||
| 
						 | 
					cb520c00a5 | ||
| 
						 | 
					2f24138345 | ||
| 
						 | 
					96512b80cc | ||
| 
						 | 
					fcb9b51978 | ||
| 
						 | 
					9bf7c97775 | ||
| 
						 | 
					24bf3674f3 | ||
| 
						 | 
					f408f1a368 | ||
| 
						 | 
					7d8d563c62 | ||
| 
						 | 
					0a1f705fda | ||
| 
						 | 
					1952c1880b | ||
| 
						 | 
					c47dc09d34 | ||
| 
						 | 
					db3096c6e1 | ||
| 
						 | 
					b03967dac1 | ||
| 
						 | 
					bcae2596a6 | ||
| 
						 | 
					fc0347c86c | ||
| 
						 | 
					eef578f4b8 | ||
| 
						 | 
					d9563d4de1 | ||
| 
						 | 
					cc7e2bf8db | ||
| 
						 | 
					5d98e2923b | ||
| 
						 | 
					d4e232f267 | ||
| 
						 | 
					cc45945fcf | ||
| 
						 | 
					07197d12f6 | ||
| 
						 | 
					7b0a298497 | ||
| 
						 | 
					21679cf2ba | ||
| 
						 | 
					0c24d951ff | ||
| 
						 | 
					92e44b8238 | ||
| 
						 | 
					4be7cd12a1 | ||
| 
						 | 
					34387adbcd | ||
| 
						 | 
					dee4d0ccb7 | ||
| 
						 | 
					c6885c1bf4 | ||
| 
						 | 
					8b8efb57af | ||
| 
						 | 
					499e120aa4 | ||
| 
						 | 
					6f198a4736 | ||
| 
						 | 
					f500f448b1 | ||
| 
						 | 
					6ad9baa870 | ||
| 
						 | 
					f843925301 | ||
| 
						 | 
					4a3b628946 | ||
| 
						 | 
					4ffdc38cf5 | ||
| 
						 | 
					f83f1bff19 | ||
| 
						 | 
					9370ff3dfa | ||
| 
						 | 
					2053b02c61 | ||
| 
						 | 
					f34e797a0d | ||
| 
						 | 
					30a2fc1273 | ||
| 
						 | 
					48da5ef1c4 | ||
| 
						 | 
					7209dd8bae | ||
| 
						 | 
					ab736c89bb | ||
| 
						 | 
					6911639617 | ||
| 
						 | 
					dbbbba3cf8 | ||
| 
						 | 
					16e523ca68 | ||
| 
						 | 
					3b2bbd306f | ||
| 
						 | 
					54caed36f7 | ||
| 
						 | 
					dfcccda69e | ||
| 
						 | 
					de352c1609 | ||
| 
						 | 
					c30068fc97 | ||
| 
						 | 
					f28f712827 | ||
| 
						 | 
					b9720d0715 | ||
| 
						 | 
					47b3267ed4 | ||
| 
						 | 
					e16ba2adb5 | ||
| 
						 | 
					0a19b1e32c | ||
| 
						 | 
					bae9a950c0 | ||
| 
						 | 
					b63ade298f | ||
| 
						 | 
					f117d4f50a | ||
| 
						 | 
					6e4267b797 | ||
| 
						 | 
					2dd032475b | ||
| 
						 | 
					db0ed055dd | ||
| 
						 | 
					106c1bfac2 | ||
| 
						 | 
					eb2a0f45db | ||
| 
						 | 
					2b4fdd6c39 | ||
| 
						 | 
					3669320398 | ||
| 
						 | 
					d706f40ce1 | ||
| 
						 | 
					027284c29c | ||
| 
						 | 
					c55e01ff3f | ||
| 
						 | 
					a59ce7bfa2 | ||
| 
						 | 
					a6196267c9 | ||
| 
						 | 
					eb664b99ba | ||
| 
						 | 
					8414bb9a7a | ||
| 
						 | 
					ccef7c322f | ||
| 
						 | 
					120327866f | ||
| 
						 | 
					bc5c2d4eb4 | ||
| 
						 | 
					d5ff8f6117 | ||
| 
						 | 
					ad0d6f6337 | ||
| 
						 | 
					873de13b3d | ||
| 
						 | 
					56de8e5cc4 | ||
| 
						 | 
					73c82862cf | ||
| 
						 | 
					75573a3ed1 | ||
| 
						 | 
					1166d93805 | ||
| 
						 | 
					ac112a32c9 | ||
| 
						 | 
					cee45c1221 | ||
| 
						 | 
					fb56b5388e | ||
| 
						 | 
					ed42cefeee | ||
| 
						 | 
					9052947a71 | ||
| 
						 | 
					53e0af18fb | ||
| 
						 | 
					c5f59fad62 | ||
| 
						 | 
					b089a4ea80 | ||
| 
						 | 
					72b2943332 | ||
| 
						 | 
					4ec0ef7548 | ||
| 
						 | 
					25bc6761f6 | ||
| 
						 | 
					81b6562c25 | ||
| 
						 | 
					ae74189fc2 | ||
| 
						 | 
					555bba7698 | ||
| 
						 | 
					294901fbe9 | ||
| 
						 | 
					ec576bf9f9 | ||
| 
						 | 
					9273e3775b | ||
| 
						 | 
					ce5cedb466 | ||
| 
						 | 
					b184b01600 | ||
| 
						 | 
					81b4078871 | ||
| 
						 | 
					d067c8f80b | ||
| 
						 | 
					9e516efe10 | ||
| 
						 | 
					366e29439e | ||
| 
						 | 
					1c9c700d7f | ||
| 
						 | 
					b2e6b9d31f | ||
| 
						 | 
					7623f63846 | ||
| 
						 | 
					2bfaf9dce3 | ||
| 
						 | 
					5c2c1560bb | ||
| 
						 | 
					8975b4b3f6 | ||
| 
						 | 
					20da03f8c6 | ||
| 
						 | 
					ef26677b67 | ||
| 
						 | 
					91925b1826 | ||
| 
						 | 
					1f33ad037d | ||
| 
						 | 
					fef60e335e | ||
| 
						 | 
					195c78846f | ||
| 
						 | 
					0f9c956c04 | ||
| 
						 | 
					7258a82875 | ||
| 
						 | 
					c1f696c32a | ||
| 
						 | 
					f2b63d9c67 | ||
| 
						 | 
					7896a7783b | ||
| 
						 | 
					621771e1ee | ||
| 
						 | 
					2b032e8606 | ||
| 
						 | 
					5e1b724697 | ||
| 
						 | 
					e6db61c2f0 | ||
| 
						 | 
					c2e198311c | ||
| 
						 | 
					d874626662 | ||
| 
						 | 
					eead72333e | ||
| 
						 | 
					f7096ab78e | ||
| 
						 | 
					98f8feb625 | ||
| 
						 | 
					9944ca414e | ||
| 
						 | 
					719c212009 | ||
| 
						 | 
					65030e1c37 | ||
| 
						 | 
					3f88b63920 | ||
| 
						 | 
					70f1c71a9f | ||
| 
						 | 
					816df5ad47 | ||
| 
						 | 
					f7b1602adf | ||
| 
						 | 
					7e88eea532 | ||
| 
						 | 
					d1cdfd3b72 | ||
| 
						 | 
					d6a03d48f5 | ||
| 
						 | 
					d453b42b1a | ||
| 
						 | 
					7c19b961e2 | ||
| 
						 | 
					147b113b62 | ||
| 
						 | 
					392dc8b0db | ||
| 
						 | 
					2f62426f09 | ||
| 
						 | 
					cb2d9e4bec | ||
| 
						 | 
					9e3ee28744 | ||
| 
						 | 
					472dcebf2c | ||
| 
						 | 
					9f30f53c6b | ||
| 
						 | 
					2f18ae00c5 | ||
| 
						 | 
					27a339fa12 | ||
| 
						 | 
					2c2e68123a | ||
| 
						 | 
					fcec7d45cb | ||
| 
						 | 
					7c8f502e7e | ||
| 
						 | 
					dc17c47634 | ||
| 
						 | 
					3d927c2f44 | ||
| 
						 | 
					0ae61410d2 | ||
| 
						 | 
					2455589f61 | ||
| 
						 | 
					3155f02be6 | ||
| 
						 | 
					fd8b9fb028 | ||
| 
						 | 
					bdf1813b3a | ||
| 
						 | 
					45b6c93f5f | ||
| 
						 | 
					6124531479 | ||
| 
						 | 
					b8549d323c | ||
| 
						 | 
					01adece673 | ||
| 
						 | 
					0220934e4c | ||
| 
						 | 
					ca09693efa | ||
| 
						 | 
					e96d7483b3 | 
							
								
								
									
										6
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							@@ -52,6 +52,10 @@ jobs:
 | 
				
			|||||||
            file: tests/test6.yaml
 | 
					            file: tests/test6.yaml
 | 
				
			||||||
            name: Test tests/test6.yaml
 | 
					            name: Test tests/test6.yaml
 | 
				
			||||||
            pio_cache_key: test6
 | 
					            pio_cache_key: test6
 | 
				
			||||||
 | 
					          - id: test
 | 
				
			||||||
 | 
					            file: tests/test7.yaml
 | 
				
			||||||
 | 
					            name: Test tests/test7.yaml
 | 
				
			||||||
 | 
					            pio_cache_key: test7
 | 
				
			||||||
          - id: pytest
 | 
					          - id: pytest
 | 
				
			||||||
            name: Run pytest
 | 
					            name: Run pytest
 | 
				
			||||||
          - id: clang-format
 | 
					          - id: clang-format
 | 
				
			||||||
@@ -177,7 +181,7 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      - name: Run yamllint
 | 
					      - name: Run yamllint
 | 
				
			||||||
        if: matrix.id == 'yamllint'
 | 
					        if: matrix.id == 'yamllint'
 | 
				
			||||||
        uses: frenck/action-yamllint@v1.3.0
 | 
					        uses: frenck/action-yamllint@v1.3.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Suggested changes
 | 
					      - name: Suggested changes
 | 
				
			||||||
        run: script/ci-suggest-changes
 | 
					        run: script/ci-suggest-changes
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/lock.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/lock.yml
									
									
									
									
										vendored
									
									
								
							@@ -18,7 +18,7 @@ jobs:
 | 
				
			|||||||
  lock:
 | 
					  lock:
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: dessant/lock-threads@v3
 | 
					      - uses: dessant/lock-threads@v4
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          pr-inactive-days: "1"
 | 
					          pr-inactive-days: "1"
 | 
				
			||||||
          pr-lock-reason: ""
 | 
					          pr-lock-reason: ""
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										117
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										117
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@@ -30,6 +30,10 @@ jobs:
 | 
				
			|||||||
            TAG=$(cat esphome/const.py | sed -n -E "s/^__version__\s+=\s+\"(.+)\"$/\1/p")
 | 
					            TAG=$(cat esphome/const.py | sed -n -E "s/^__version__\s+=\s+\"(.+)\"$/\1/p")
 | 
				
			||||||
            today="$(date --utc '+%Y%m%d')"
 | 
					            today="$(date --utc '+%Y%m%d')"
 | 
				
			||||||
            TAG="${TAG}${today}"
 | 
					            TAG="${TAG}${today}"
 | 
				
			||||||
 | 
					            BRANCH=${GITHUB_REF#refs/heads/}
 | 
				
			||||||
 | 
					            if [[ "$BRANCH" != "dev" ]]; then
 | 
				
			||||||
 | 
					              TAG="${TAG}-${BRANCH}"
 | 
				
			||||||
 | 
					            fi
 | 
				
			||||||
          fi
 | 
					          fi
 | 
				
			||||||
          echo "tag=${TAG}" >> $GITHUB_OUTPUT
 | 
					          echo "tag=${TAG}" >> $GITHUB_OUTPUT
 | 
				
			||||||
        # yamllint enable rule:line-length
 | 
					        # yamllint enable rule:line-length
 | 
				
			||||||
@@ -57,17 +61,30 @@ jobs:
 | 
				
			|||||||
        run: twine upload dist/*
 | 
					        run: twine upload dist/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  deploy-docker:
 | 
					  deploy-docker:
 | 
				
			||||||
    name: Build and publish docker containers
 | 
					    name: Build and publish ESPHome ${{ matrix.image.title}}
 | 
				
			||||||
    if: github.repository == 'esphome/esphome'
 | 
					    if: github.repository == 'esphome/esphome'
 | 
				
			||||||
    permissions:
 | 
					    permissions:
 | 
				
			||||||
      contents: read
 | 
					      contents: read
 | 
				
			||||||
      packages: write
 | 
					      packages: write
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    continue-on-error: ${{ matrix.image.title == 'lint' }}
 | 
				
			||||||
    needs: [init]
 | 
					    needs: [init]
 | 
				
			||||||
    strategy:
 | 
					    strategy:
 | 
				
			||||||
 | 
					      fail-fast: false
 | 
				
			||||||
      matrix:
 | 
					      matrix:
 | 
				
			||||||
        arch: [amd64, armv7, aarch64]
 | 
					        image:
 | 
				
			||||||
        build_type: ["ha-addon", "docker", "lint"]
 | 
					          - title: "ha-addon"
 | 
				
			||||||
 | 
					            suffix: "hassio"
 | 
				
			||||||
 | 
					            target: "hassio"
 | 
				
			||||||
 | 
					            baseimg: "hassio"
 | 
				
			||||||
 | 
					          - title: "docker"
 | 
				
			||||||
 | 
					            suffix: ""
 | 
				
			||||||
 | 
					            target: "docker"
 | 
				
			||||||
 | 
					            baseimg: "docker"
 | 
				
			||||||
 | 
					          - title: "lint"
 | 
				
			||||||
 | 
					            suffix: "lint"
 | 
				
			||||||
 | 
					            target: "lint"
 | 
				
			||||||
 | 
					            baseimg: "docker"
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v3
 | 
					      - uses: actions/checkout@v3
 | 
				
			||||||
      - name: Set up Python
 | 
					      - name: Set up Python
 | 
				
			||||||
@@ -92,69 +109,47 @@ jobs:
 | 
				
			|||||||
          username: ${{ github.actor }}
 | 
					          username: ${{ github.actor }}
 | 
				
			||||||
          password: ${{ secrets.GITHUB_TOKEN }}
 | 
					          password: ${{ secrets.GITHUB_TOKEN }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Generate short tags
 | 
				
			||||||
 | 
					        id: tags
 | 
				
			||||||
 | 
					        run: |
 | 
				
			||||||
 | 
					          docker/generate_tags.py \
 | 
				
			||||||
 | 
					            --tag "${{ needs.init.outputs.tag }}" \
 | 
				
			||||||
 | 
					            --suffix "${{ matrix.image.suffix }}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Build and push
 | 
					      - name: Build and push
 | 
				
			||||||
        run: |
 | 
					        uses: docker/build-push-action@v3
 | 
				
			||||||
          docker/build.py \
 | 
					 | 
				
			||||||
            --tag "${{ needs.init.outputs.tag }}" \
 | 
					 | 
				
			||||||
            --arch "${{ matrix.arch }}" \
 | 
					 | 
				
			||||||
            --build-type "${{ matrix.build_type }}" \
 | 
					 | 
				
			||||||
            build \
 | 
					 | 
				
			||||||
            --push
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  deploy-docker-manifest:
 | 
					 | 
				
			||||||
    if: github.repository == 'esphome/esphome'
 | 
					 | 
				
			||||||
    permissions:
 | 
					 | 
				
			||||||
      contents: read
 | 
					 | 
				
			||||||
      packages: write
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    needs: [init, deploy-docker]
 | 
					 | 
				
			||||||
    strategy:
 | 
					 | 
				
			||||||
      matrix:
 | 
					 | 
				
			||||||
        build_type: ["ha-addon", "docker", "lint"]
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - uses: actions/checkout@v3
 | 
					 | 
				
			||||||
      - name: Set up Python
 | 
					 | 
				
			||||||
        uses: actions/setup-python@v4
 | 
					 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          python-version: "3.9"
 | 
					          context: .
 | 
				
			||||||
      - name: Enable experimental manifest support
 | 
					          file: ./docker/Dockerfile
 | 
				
			||||||
        run: |
 | 
					          platforms: linux/amd64,linux/arm/v7,linux/arm64
 | 
				
			||||||
          mkdir -p ~/.docker
 | 
					          target: ${{ matrix.image.target }}
 | 
				
			||||||
          echo "{\"experimental\": \"enabled\"}" > ~/.docker/config.json
 | 
					          push: true
 | 
				
			||||||
 | 
					          # yamllint disable rule:line-length
 | 
				
			||||||
      - name: Log in to docker hub
 | 
					          cache-from: type=registry,ref=ghcr.io/${{ steps.tags.outputs.image }}:cache-${{ steps.tags.outputs.channel }}
 | 
				
			||||||
        uses: docker/login-action@v2
 | 
					          cache-to: type=registry,ref=ghcr.io/${{ steps.tags.outputs.image }}:cache-${{ steps.tags.outputs.channel }},mode=max
 | 
				
			||||||
        with:
 | 
					          # yamllint enable rule:line-length
 | 
				
			||||||
          username: ${{ secrets.DOCKER_USER }}
 | 
					          tags: ${{ steps.tags.outputs.tags }}
 | 
				
			||||||
          password: ${{ secrets.DOCKER_PASSWORD }}
 | 
					          build-args: |
 | 
				
			||||||
      - name: Log in to the GitHub container registry
 | 
					            BASEIMGTYPE=${{ matrix.image.baseimg }}
 | 
				
			||||||
        uses: docker/login-action@v2
 | 
					            BUILD_VERSION=${{ needs.init.outputs.tag }}
 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          registry: ghcr.io
 | 
					 | 
				
			||||||
          username: ${{ github.actor }}
 | 
					 | 
				
			||||||
          password: ${{ secrets.GITHUB_TOKEN }}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Run manifest
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          docker/build.py \
 | 
					 | 
				
			||||||
            --tag "${{ needs.init.outputs.tag }}" \
 | 
					 | 
				
			||||||
            --build-type "${{ matrix.build_type }}" \
 | 
					 | 
				
			||||||
            manifest
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  deploy-ha-addon-repo:
 | 
					  deploy-ha-addon-repo:
 | 
				
			||||||
    if: github.repository == 'esphome/esphome' && github.event_name == 'release'
 | 
					    if: github.repository == 'esphome/esphome' && github.event_name == 'release'
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    needs: [deploy-docker]
 | 
					    needs: [deploy-docker]
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - env:
 | 
					      - name: Trigger Workflow
 | 
				
			||||||
          TOKEN: ${{ secrets.DEPLOY_HA_ADDON_REPO_TOKEN }}
 | 
					        uses: actions/github-script@v6
 | 
				
			||||||
        # yamllint disable rule:line-length
 | 
					        with:
 | 
				
			||||||
        run: |
 | 
					          github-token: ${{ secrets.DEPLOY_HA_ADDON_REPO_TOKEN }}
 | 
				
			||||||
          TAG="${GITHUB_REF#refs/tags/}"
 | 
					          script: |
 | 
				
			||||||
          curl \
 | 
					            github.rest.actions.createWorkflowDispatch({
 | 
				
			||||||
            -u ":$TOKEN" \
 | 
					              owner: "esphome",
 | 
				
			||||||
            -X POST \
 | 
					              repo: "home-assistant-addon",
 | 
				
			||||||
            -H "Accept: application/vnd.github.v3+json" \
 | 
					              workflow_id: "bump-version.yml",
 | 
				
			||||||
            https://api.github.com/repos/esphome/home-assistant-addon/actions/workflows/bump-version.yml/dispatches \
 | 
					              ref: "main",
 | 
				
			||||||
            -d "{\"ref\":\"main\",\"inputs\":{\"version\":\"$TAG\"}}"
 | 
					              inputs: {
 | 
				
			||||||
        # yamllint enable rule:line-length
 | 
					                version: "${{ github.event.release.tag_name }}",
 | 
				
			||||||
 | 
					                content: ${{ toJSON(github.event.release.body) }}
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
								
							@@ -18,7 +18,7 @@ jobs:
 | 
				
			|||||||
  stale:
 | 
					  stale:
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/stale@v6
 | 
					      - uses: actions/stale@v7
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          days-before-pr-stale: 90
 | 
					          days-before-pr-stale: 90
 | 
				
			||||||
          days-before-pr-close: 7
 | 
					          days-before-pr-close: 7
 | 
				
			||||||
@@ -38,7 +38,7 @@ jobs:
 | 
				
			|||||||
  close-issues:
 | 
					  close-issues:
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/stale@v6
 | 
					      - uses: actions/stale@v7
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          days-before-pr-stale: -1
 | 
					          days-before-pr-stale: -1
 | 
				
			||||||
          days-before-pr-close: -1
 | 
					          days-before-pr-close: -1
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -128,3 +128,5 @@ tests/.esphome/
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
sdkconfig.*
 | 
					sdkconfig.*
 | 
				
			||||||
!sdkconfig.defaults
 | 
					!sdkconfig.defaults
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.tests/
 | 
				
			||||||
@@ -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/ambv/black
 | 
					  - repo: https://github.com/ambv/black
 | 
				
			||||||
    rev: 22.10.0
 | 
					    rev: 22.12.0
 | 
				
			||||||
    hooks:
 | 
					    hooks:
 | 
				
			||||||
      - id: black
 | 
					      - id: black
 | 
				
			||||||
        args:
 | 
					        args:
 | 
				
			||||||
@@ -11,7 +11,7 @@ repos:
 | 
				
			|||||||
          - --quiet
 | 
					          - --quiet
 | 
				
			||||||
        files: ^((esphome|script|tests)/.+)?[^/]+\.py$
 | 
					        files: ^((esphome|script|tests)/.+)?[^/]+\.py$
 | 
				
			||||||
  - repo: https://github.com/PyCQA/flake8
 | 
					  - repo: https://github.com/PyCQA/flake8
 | 
				
			||||||
    rev: 5.0.4
 | 
					    rev: 6.0.0
 | 
				
			||||||
    hooks:
 | 
					    hooks:
 | 
				
			||||||
      - id: flake8
 | 
					      - id: flake8
 | 
				
			||||||
        additional_dependencies:
 | 
					        additional_dependencies:
 | 
				
			||||||
@@ -27,7 +27,7 @@ repos:
 | 
				
			|||||||
          - --branch=release
 | 
					          - --branch=release
 | 
				
			||||||
          - --branch=beta
 | 
					          - --branch=beta
 | 
				
			||||||
  - repo: https://github.com/asottile/pyupgrade
 | 
					  - repo: https://github.com/asottile/pyupgrade
 | 
				
			||||||
    rev: v3.2.0
 | 
					    rev: v3.3.0
 | 
				
			||||||
    hooks:
 | 
					    hooks:
 | 
				
			||||||
      - id: pyupgrade
 | 
					      - id: pyupgrade
 | 
				
			||||||
        args: [--py39-plus]
 | 
					        args: [--py39-plus]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								CODEOWNERS
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								CODEOWNERS
									
									
									
									
									
								
							@@ -41,6 +41,8 @@ esphome/components/ble_client/* @buxtronix
 | 
				
			|||||||
esphome/components/bluetooth_proxy/* @jesserockz
 | 
					esphome/components/bluetooth_proxy/* @jesserockz
 | 
				
			||||||
esphome/components/bme680_bsec/* @trvrnrth
 | 
					esphome/components/bme680_bsec/* @trvrnrth
 | 
				
			||||||
esphome/components/bmp3xx/* @martgras
 | 
					esphome/components/bmp3xx/* @martgras
 | 
				
			||||||
 | 
					esphome/components/bp1658cj/* @Cossid
 | 
				
			||||||
 | 
					esphome/components/bp5758d/* @Cossid
 | 
				
			||||||
esphome/components/button/* @esphome/core
 | 
					esphome/components/button/* @esphome/core
 | 
				
			||||||
esphome/components/canbus/* @danielschramm @mvturnho
 | 
					esphome/components/canbus/* @danielschramm @mvturnho
 | 
				
			||||||
esphome/components/cap1188/* @MrEditor97
 | 
					esphome/components/cap1188/* @MrEditor97
 | 
				
			||||||
@@ -69,6 +71,7 @@ esphome/components/display_menu_base/* @numo68
 | 
				
			|||||||
esphome/components/dps310/* @kbx81
 | 
					esphome/components/dps310/* @kbx81
 | 
				
			||||||
esphome/components/ds1307/* @badbadc0ffee
 | 
					esphome/components/ds1307/* @badbadc0ffee
 | 
				
			||||||
esphome/components/dsmr/* @glmnet @zuidwijk
 | 
					esphome/components/dsmr/* @glmnet @zuidwijk
 | 
				
			||||||
 | 
					esphome/components/ee895/* @Stock-M
 | 
				
			||||||
esphome/components/ektf2232/* @jesserockz
 | 
					esphome/components/ektf2232/* @jesserockz
 | 
				
			||||||
esphome/components/ens210/* @itn3rd77
 | 
					esphome/components/ens210/* @itn3rd77
 | 
				
			||||||
esphome/components/esp32/* @esphome/core
 | 
					esphome/components/esp32/* @esphome/core
 | 
				
			||||||
@@ -100,9 +103,11 @@ esphome/components/hitachi_ac424/* @sourabhjaiswal
 | 
				
			|||||||
esphome/components/homeassistant/* @OttoWinter
 | 
					esphome/components/homeassistant/* @OttoWinter
 | 
				
			||||||
esphome/components/honeywellabp/* @RubyBailey
 | 
					esphome/components/honeywellabp/* @RubyBailey
 | 
				
			||||||
esphome/components/hrxl_maxsonar_wr/* @netmikey
 | 
					esphome/components/hrxl_maxsonar_wr/* @netmikey
 | 
				
			||||||
 | 
					esphome/components/hte501/* @Stock-M
 | 
				
			||||||
esphome/components/hydreon_rgxx/* @functionpointer
 | 
					esphome/components/hydreon_rgxx/* @functionpointer
 | 
				
			||||||
esphome/components/i2c/* @esphome/core
 | 
					esphome/components/i2c/* @esphome/core
 | 
				
			||||||
esphome/components/i2s_audio/* @jesserockz
 | 
					esphome/components/i2s_audio/* @jesserockz
 | 
				
			||||||
 | 
					esphome/components/improv_base/* @esphome/core
 | 
				
			||||||
esphome/components/improv_serial/* @esphome/core
 | 
					esphome/components/improv_serial/* @esphome/core
 | 
				
			||||||
esphome/components/ina260/* @MrEditor97
 | 
					esphome/components/ina260/* @MrEditor97
 | 
				
			||||||
esphome/components/inkbird_ibsth1_mini/* @fkirill
 | 
					esphome/components/inkbird_ibsth1_mini/* @fkirill
 | 
				
			||||||
@@ -111,13 +116,17 @@ esphome/components/integration/* @OttoWinter
 | 
				
			|||||||
esphome/components/interval/* @esphome/core
 | 
					esphome/components/interval/* @esphome/core
 | 
				
			||||||
esphome/components/json/* @OttoWinter
 | 
					esphome/components/json/* @OttoWinter
 | 
				
			||||||
esphome/components/kalman_combinator/* @Cat-Ion
 | 
					esphome/components/kalman_combinator/* @Cat-Ion
 | 
				
			||||||
 | 
					esphome/components/key_collector/* @ssieb
 | 
				
			||||||
 | 
					esphome/components/key_provider/* @ssieb
 | 
				
			||||||
esphome/components/lcd_menu/* @numo68
 | 
					esphome/components/lcd_menu/* @numo68
 | 
				
			||||||
 | 
					esphome/components/ld2410/* @sebcaps
 | 
				
			||||||
esphome/components/ledc/* @OttoWinter
 | 
					esphome/components/ledc/* @OttoWinter
 | 
				
			||||||
esphome/components/light/* @esphome/core
 | 
					esphome/components/light/* @esphome/core
 | 
				
			||||||
esphome/components/lilygo_t5_47/touchscreen/* @jesserockz
 | 
					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/matrix_keypad/* @ssieb
 | 
				
			||||||
esphome/components/max31865/* @DAVe3283
 | 
					esphome/components/max31865/* @DAVe3283
 | 
				
			||||||
esphome/components/max44009/* @berfenger
 | 
					esphome/components/max44009/* @berfenger
 | 
				
			||||||
esphome/components/max7219digit/* @rspaargaren
 | 
					esphome/components/max7219digit/* @rspaargaren
 | 
				
			||||||
@@ -138,6 +147,7 @@ esphome/components/mcp9808/* @k7hpn
 | 
				
			|||||||
esphome/components/md5/* @esphome/core
 | 
					esphome/components/md5/* @esphome/core
 | 
				
			||||||
esphome/components/mdns/* @esphome/core
 | 
					esphome/components/mdns/* @esphome/core
 | 
				
			||||||
esphome/components/media_player/* @jesserockz
 | 
					esphome/components/media_player/* @jesserockz
 | 
				
			||||||
 | 
					esphome/components/mics_4514/* @jesserockz
 | 
				
			||||||
esphome/components/midea/* @dudanov
 | 
					esphome/components/midea/* @dudanov
 | 
				
			||||||
esphome/components/midea_ir/* @dudanov
 | 
					esphome/components/midea_ir/* @dudanov
 | 
				
			||||||
esphome/components/mitsubishi/* @RubyBailey
 | 
					esphome/components/mitsubishi/* @RubyBailey
 | 
				
			||||||
@@ -164,6 +174,8 @@ esphome/components/nfc/* @jesserockz
 | 
				
			|||||||
esphome/components/number/* @esphome/core
 | 
					esphome/components/number/* @esphome/core
 | 
				
			||||||
esphome/components/ota/* @esphome/core
 | 
					esphome/components/ota/* @esphome/core
 | 
				
			||||||
esphome/components/output/* @esphome/core
 | 
					esphome/components/output/* @esphome/core
 | 
				
			||||||
 | 
					esphome/components/pca9554/* @hwstar
 | 
				
			||||||
 | 
					esphome/components/pcf85063/* @brogon
 | 
				
			||||||
esphome/components/pid/* @OttoWinter
 | 
					esphome/components/pid/* @OttoWinter
 | 
				
			||||||
esphome/components/pipsolar/* @andreashergert1984
 | 
					esphome/components/pipsolar/* @andreashergert1984
 | 
				
			||||||
esphome/components/pm1006/* @habbie
 | 
					esphome/components/pm1006/* @habbie
 | 
				
			||||||
@@ -204,10 +216,15 @@ esphome/components/sgp4x/* @SenexCrenshaw @martgras
 | 
				
			|||||||
esphome/components/shelly_dimmer/* @edge90 @rnauber
 | 
					esphome/components/shelly_dimmer/* @edge90 @rnauber
 | 
				
			||||||
esphome/components/sht4x/* @sjtrny
 | 
					esphome/components/sht4x/* @sjtrny
 | 
				
			||||||
esphome/components/shutdown/* @esphome/core @jsuanet
 | 
					esphome/components/shutdown/* @esphome/core @jsuanet
 | 
				
			||||||
 | 
					esphome/components/sigma_delta_output/* @Cat-Ion
 | 
				
			||||||
esphome/components/sim800l/* @glmnet
 | 
					esphome/components/sim800l/* @glmnet
 | 
				
			||||||
 | 
					esphome/components/sm10bit_base/* @Cossid
 | 
				
			||||||
esphome/components/sm2135/* @BoukeHaarsma23
 | 
					esphome/components/sm2135/* @BoukeHaarsma23
 | 
				
			||||||
 | 
					esphome/components/sm2235/* @Cossid
 | 
				
			||||||
 | 
					esphome/components/sm2335/* @Cossid
 | 
				
			||||||
esphome/components/sml/* @alengwenus
 | 
					esphome/components/sml/* @alengwenus
 | 
				
			||||||
esphome/components/smt100/* @piechade
 | 
					esphome/components/smt100/* @piechade
 | 
				
			||||||
 | 
					esphome/components/sn74hc165/* @jesserockz
 | 
				
			||||||
esphome/components/socket/* @esphome/core
 | 
					esphome/components/socket/* @esphome/core
 | 
				
			||||||
esphome/components/sonoff_d1/* @anatoly-savchenkov
 | 
					esphome/components/sonoff_d1/* @anatoly-savchenkov
 | 
				
			||||||
esphome/components/spi/* @esphome/core
 | 
					esphome/components/spi/* @esphome/core
 | 
				
			||||||
@@ -233,6 +250,7 @@ esphome/components/switch/* @esphome/core
 | 
				
			|||||||
esphome/components/t6615/* @tylermenezes
 | 
					esphome/components/t6615/* @tylermenezes
 | 
				
			||||||
esphome/components/tca9548a/* @andreashergert1984
 | 
					esphome/components/tca9548a/* @andreashergert1984
 | 
				
			||||||
esphome/components/tcl112/* @glmnet
 | 
					esphome/components/tcl112/* @glmnet
 | 
				
			||||||
 | 
					esphome/components/tee501/* @Stock-M
 | 
				
			||||||
esphome/components/teleinfo/* @0hax
 | 
					esphome/components/teleinfo/* @0hax
 | 
				
			||||||
esphome/components/thermostat/* @kbx81
 | 
					esphome/components/thermostat/* @kbx81
 | 
				
			||||||
esphome/components/time/* @OttoWinter
 | 
					esphome/components/time/* @OttoWinter
 | 
				
			||||||
@@ -257,12 +275,15 @@ esphome/components/uart/* @esphome/core
 | 
				
			|||||||
esphome/components/ufire_ec/* @pvizeli
 | 
					esphome/components/ufire_ec/* @pvizeli
 | 
				
			||||||
esphome/components/ufire_ise/* @pvizeli
 | 
					esphome/components/ufire_ise/* @pvizeli
 | 
				
			||||||
esphome/components/ultrasonic/* @OttoWinter
 | 
					esphome/components/ultrasonic/* @OttoWinter
 | 
				
			||||||
 | 
					esphome/components/vbus/* @ssieb
 | 
				
			||||||
esphome/components/version/* @esphome/core
 | 
					esphome/components/version/* @esphome/core
 | 
				
			||||||
esphome/components/wake_on_lan/* @willwill2will54
 | 
					esphome/components/wake_on_lan/* @willwill2will54
 | 
				
			||||||
esphome/components/web_server_base/* @OttoWinter
 | 
					esphome/components/web_server_base/* @OttoWinter
 | 
				
			||||||
esphome/components/whirlpool/* @glmnet
 | 
					esphome/components/whirlpool/* @glmnet
 | 
				
			||||||
esphome/components/whynter/* @aeonsablaze
 | 
					esphome/components/whynter/* @aeonsablaze
 | 
				
			||||||
 | 
					esphome/components/wiegand/* @ssieb
 | 
				
			||||||
esphome/components/wl_134/* @hobbypunk90
 | 
					esphome/components/wl_134/* @hobbypunk90
 | 
				
			||||||
 | 
					esphome/components/x9c/* @EtienneMD
 | 
				
			||||||
esphome/components/xiaomi_lywsd03mmc/* @ahpohl
 | 
					esphome/components/xiaomi_lywsd03mmc/* @ahpohl
 | 
				
			||||||
esphome/components/xiaomi_mhoc303/* @drug123
 | 
					esphome/components/xiaomi_mhoc303/* @drug123
 | 
				
			||||||
esphome/components/xiaomi_mhoc401/* @vevsvevs
 | 
					esphome/components/xiaomi_mhoc401/* @vevsvevs
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,17 +6,14 @@
 | 
				
			|||||||
ARG BASEIMGTYPE=docker
 | 
					ARG BASEIMGTYPE=docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# https://github.com/hassio-addons/addon-debian-base/releases
 | 
					# https://github.com/hassio-addons/addon-debian-base/releases
 | 
				
			||||||
FROM ghcr.io/hassio-addons/debian-base/amd64:5.3.0 AS base-hassio-amd64
 | 
					FROM ghcr.io/hassio-addons/debian-base:6.2.0 AS base-hassio
 | 
				
			||||||
FROM ghcr.io/hassio-addons/debian-base/aarch64:5.3.0 AS base-hassio-arm64
 | 
					 | 
				
			||||||
FROM ghcr.io/hassio-addons/debian-base/armv7:5.3.0 AS base-hassio-armv7
 | 
					 | 
				
			||||||
# https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye
 | 
					# https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye
 | 
				
			||||||
FROM debian:bullseye-20220328-slim AS base-docker-amd64
 | 
					FROM debian:bullseye-20221024-slim AS base-docker
 | 
				
			||||||
FROM debian:bullseye-20220328-slim AS base-docker-arm64
 | 
					 | 
				
			||||||
FROM debian:bullseye-20220328-slim AS base-docker-armv7
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Use TARGETARCH/TARGETVARIANT defined by docker
 | 
					FROM base-${BASEIMGTYPE} AS base
 | 
				
			||||||
# https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope
 | 
					
 | 
				
			||||||
FROM base-${BASEIMGTYPE}-${TARGETARCH}${TARGETVARIANT} AS base
 | 
					ARG TARGETARCH
 | 
				
			||||||
 | 
					ARG TARGETVARIANT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN \
 | 
					RUN \
 | 
				
			||||||
    apt-get update \
 | 
					    apt-get update \
 | 
				
			||||||
@@ -29,8 +26,8 @@ RUN \
 | 
				
			|||||||
        python3-cryptography=3.3.2-1 \
 | 
					        python3-cryptography=3.3.2-1 \
 | 
				
			||||||
        iputils-ping=3:20210202-1 \
 | 
					        iputils-ping=3:20210202-1 \
 | 
				
			||||||
        git=1:2.30.2-1 \
 | 
					        git=1:2.30.2-1 \
 | 
				
			||||||
        curl=7.74.0-1.3+deb11u1 \
 | 
					        curl=7.74.0-1.3+deb11u5 \
 | 
				
			||||||
        openssh-client=1:8.4p1-5 \
 | 
					        openssh-client=1:8.4p1-5+deb11u1 \
 | 
				
			||||||
    && rm -rf \
 | 
					    && rm -rf \
 | 
				
			||||||
        /tmp/* \
 | 
					        /tmp/* \
 | 
				
			||||||
        /var/{cache,log}/* \
 | 
					        /var/{cache,log}/* \
 | 
				
			||||||
@@ -42,6 +39,14 @@ ENV \
 | 
				
			|||||||
  # Store globally installed pio libs in /piolibs
 | 
					  # Store globally installed pio libs in /piolibs
 | 
				
			||||||
  PLATFORMIO_GLOBALLIB_DIR=/piolibs
 | 
					  PLATFORMIO_GLOBALLIB_DIR=/piolibs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Support legacy binaries on Debian multiarch system. There is no "correct" way
 | 
				
			||||||
 | 
					# to do this, other than using properly built toolchains...
 | 
				
			||||||
 | 
					# See: https://unix.stackexchange.com/questions/553743/correct-way-to-add-lib-ld-linux-so-3-in-debian
 | 
				
			||||||
 | 
					RUN \
 | 
				
			||||||
 | 
					    if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
 | 
				
			||||||
 | 
					        ln -s /lib/arm-linux-gnueabihf/ld-linux.so.3 /lib/ld-linux.so.3; \
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN \
 | 
					RUN \
 | 
				
			||||||
    # Ubuntu python3-pip is missing wheel
 | 
					    # Ubuntu python3-pip is missing wheel
 | 
				
			||||||
    pip3 install --no-cache-dir \
 | 
					    pip3 install --no-cache-dir \
 | 
				
			||||||
@@ -94,7 +99,7 @@ RUN \
 | 
				
			|||||||
    apt-get update \
 | 
					    apt-get update \
 | 
				
			||||||
    # Use pinned versions so that we get updates with build caching
 | 
					    # Use pinned versions so that we get updates with build caching
 | 
				
			||||||
    && apt-get install -y --no-install-recommends \
 | 
					    && apt-get install -y --no-install-recommends \
 | 
				
			||||||
        nginx-light=1.18.0-6.1+deb11u2 \
 | 
					        nginx-light=1.18.0-6.1+deb11u3 \
 | 
				
			||||||
    && rm -rf \
 | 
					    && rm -rf \
 | 
				
			||||||
        /tmp/* \
 | 
					        /tmp/* \
 | 
				
			||||||
        /var/{cache,log}/* \
 | 
					        /var/{cache,log}/* \
 | 
				
			||||||
@@ -134,7 +139,7 @@ RUN \
 | 
				
			|||||||
        clang-tidy-11=1:11.0.1-2 \
 | 
					        clang-tidy-11=1:11.0.1-2 \
 | 
				
			||||||
        patch=2.7.6-7 \
 | 
					        patch=2.7.6-7 \
 | 
				
			||||||
        software-properties-common=0.96.20.2-2.1 \
 | 
					        software-properties-common=0.96.20.2-2.1 \
 | 
				
			||||||
        nano=5.4-2+deb11u1 \
 | 
					        nano=5.4-2+deb11u2 \
 | 
				
			||||||
        build-essential=12.9 \
 | 
					        build-essential=12.9 \
 | 
				
			||||||
        python3-dev=3.9.2-3 \
 | 
					        python3-dev=3.9.2-3 \
 | 
				
			||||||
    && rm -rf \
 | 
					    && rm -rf \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,32 +8,49 @@ import re
 | 
				
			|||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CHANNEL_DEV = 'dev'
 | 
					CHANNEL_DEV = "dev"
 | 
				
			||||||
CHANNEL_BETA = 'beta'
 | 
					CHANNEL_BETA = "beta"
 | 
				
			||||||
CHANNEL_RELEASE = 'release'
 | 
					CHANNEL_RELEASE = "release"
 | 
				
			||||||
CHANNELS = [CHANNEL_DEV, CHANNEL_BETA, CHANNEL_RELEASE]
 | 
					CHANNELS = [CHANNEL_DEV, CHANNEL_BETA, CHANNEL_RELEASE]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ARCH_AMD64 = 'amd64'
 | 
					ARCH_AMD64 = "amd64"
 | 
				
			||||||
ARCH_ARMV7 = 'armv7'
 | 
					ARCH_ARMV7 = "armv7"
 | 
				
			||||||
ARCH_AARCH64 = 'aarch64'
 | 
					ARCH_AARCH64 = "aarch64"
 | 
				
			||||||
ARCHS = [ARCH_AMD64, ARCH_ARMV7, ARCH_AARCH64]
 | 
					ARCHS = [ARCH_AMD64, ARCH_ARMV7, ARCH_AARCH64]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TYPE_DOCKER = 'docker'
 | 
					TYPE_DOCKER = "docker"
 | 
				
			||||||
TYPE_HA_ADDON = 'ha-addon'
 | 
					TYPE_HA_ADDON = "ha-addon"
 | 
				
			||||||
TYPE_LINT = 'lint'
 | 
					TYPE_LINT = "lint"
 | 
				
			||||||
TYPES = [TYPE_DOCKER, TYPE_HA_ADDON, TYPE_LINT]
 | 
					TYPES = [TYPE_DOCKER, TYPE_HA_ADDON, TYPE_LINT]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
parser = argparse.ArgumentParser()
 | 
					parser = argparse.ArgumentParser()
 | 
				
			||||||
parser.add_argument("--tag", type=str, required=True, help="The main docker tag to push to. If a version number also adds latest and/or beta tag")
 | 
					parser.add_argument(
 | 
				
			||||||
parser.add_argument("--arch", choices=ARCHS, required=False, help="The architecture to build for")
 | 
					    "--tag",
 | 
				
			||||||
parser.add_argument("--build-type", choices=TYPES, required=True, help="The type of build to run")
 | 
					    type=str,
 | 
				
			||||||
parser.add_argument("--dry-run", action="store_true", help="Don't run any commands, just print them")
 | 
					    required=True,
 | 
				
			||||||
subparsers = parser.add_subparsers(help="Action to perform", dest="command", required=True)
 | 
					    help="The main docker tag to push to. If a version number also adds latest and/or beta tag",
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					parser.add_argument(
 | 
				
			||||||
 | 
					    "--arch", choices=ARCHS, required=False, help="The architecture to build for"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					parser.add_argument(
 | 
				
			||||||
 | 
					    "--build-type", choices=TYPES, required=True, help="The type of build to run"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					parser.add_argument(
 | 
				
			||||||
 | 
					    "--dry-run", action="store_true", help="Don't run any commands, just print them"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					subparsers = parser.add_subparsers(
 | 
				
			||||||
 | 
					    help="Action to perform", dest="command", required=True
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
build_parser = subparsers.add_parser("build", help="Build the image")
 | 
					build_parser = subparsers.add_parser("build", help="Build the image")
 | 
				
			||||||
build_parser.add_argument("--push", help="Also push the images", action="store_true")
 | 
					build_parser.add_argument("--push", help="Also push the images", action="store_true")
 | 
				
			||||||
build_parser.add_argument("--load", help="Load the docker image locally", action="store_true")
 | 
					build_parser.add_argument(
 | 
				
			||||||
manifest_parser = subparsers.add_parser("manifest", help="Create a manifest from already pushed images")
 | 
					    "--load", help="Load the docker image locally", action="store_true"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					manifest_parser = subparsers.add_parser(
 | 
				
			||||||
 | 
					    "manifest", help="Create a manifest from already pushed images"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@dataclass(frozen=True)
 | 
					@dataclass(frozen=True)
 | 
				
			||||||
@@ -49,7 +66,7 @@ class DockerParams:
 | 
				
			|||||||
        prefix = {
 | 
					        prefix = {
 | 
				
			||||||
            TYPE_DOCKER: "esphome/esphome",
 | 
					            TYPE_DOCKER: "esphome/esphome",
 | 
				
			||||||
            TYPE_HA_ADDON: "esphome/esphome-hassio",
 | 
					            TYPE_HA_ADDON: "esphome/esphome-hassio",
 | 
				
			||||||
            TYPE_LINT: "esphome/esphome-lint"
 | 
					            TYPE_LINT: "esphome/esphome-lint",
 | 
				
			||||||
        }[build_type]
 | 
					        }[build_type]
 | 
				
			||||||
        build_to = f"{prefix}-{arch}"
 | 
					        build_to = f"{prefix}-{arch}"
 | 
				
			||||||
        baseimgtype = {
 | 
					        baseimgtype = {
 | 
				
			||||||
@@ -128,13 +145,21 @@ def main():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        # 3. build
 | 
					        # 3. build
 | 
				
			||||||
        cmd = [
 | 
					        cmd = [
 | 
				
			||||||
            "docker", "buildx", "build",
 | 
					            "docker",
 | 
				
			||||||
            "--build-arg", f"BASEIMGTYPE={params.baseimgtype}",
 | 
					            "buildx",
 | 
				
			||||||
            "--build-arg", f"BUILD_VERSION={args.tag}",
 | 
					            "build",
 | 
				
			||||||
            "--cache-from", f"type=registry,ref={cache_img}",
 | 
					            "--build-arg",
 | 
				
			||||||
            "--file", "docker/Dockerfile",
 | 
					            f"BASEIMGTYPE={params.baseimgtype}",
 | 
				
			||||||
            "--platform", params.platform,
 | 
					            "--build-arg",
 | 
				
			||||||
            "--target", params.target,
 | 
					            f"BUILD_VERSION={args.tag}",
 | 
				
			||||||
 | 
					            "--cache-from",
 | 
				
			||||||
 | 
					            f"type=registry,ref={cache_img}",
 | 
				
			||||||
 | 
					            "--file",
 | 
				
			||||||
 | 
					            "docker/Dockerfile",
 | 
				
			||||||
 | 
					            "--platform",
 | 
				
			||||||
 | 
					            params.platform,
 | 
				
			||||||
 | 
					            "--target",
 | 
				
			||||||
 | 
					            params.target,
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
        for img in imgs:
 | 
					        for img in imgs:
 | 
				
			||||||
            cmd += ["--tag", img]
 | 
					            cmd += ["--tag", img]
 | 
				
			||||||
@@ -160,9 +185,7 @@ def main():
 | 
				
			|||||||
            run_command(*cmd)
 | 
					            run_command(*cmd)
 | 
				
			||||||
        # 2. Push manifests
 | 
					        # 2. Push manifests
 | 
				
			||||||
        for target in targets:
 | 
					        for target in targets:
 | 
				
			||||||
            run_command(
 | 
					            run_command("docker", "manifest", "push", target)
 | 
				
			||||||
                "docker", "manifest", "push", target
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										68
									
								
								docker/generate_tags.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										68
									
								
								docker/generate_tags.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import argparse
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CHANNEL_DEV = "dev"
 | 
				
			||||||
 | 
					CHANNEL_BETA = "beta"
 | 
				
			||||||
 | 
					CHANNEL_RELEASE = "release"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					parser = argparse.ArgumentParser()
 | 
				
			||||||
 | 
					parser.add_argument(
 | 
				
			||||||
 | 
					    "--tag",
 | 
				
			||||||
 | 
					    type=str,
 | 
				
			||||||
 | 
					    required=True,
 | 
				
			||||||
 | 
					    help="The main docker tag to push to. If a version number also adds latest and/or beta tag",
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					parser.add_argument(
 | 
				
			||||||
 | 
					    "--suffix",
 | 
				
			||||||
 | 
					    type=str,
 | 
				
			||||||
 | 
					    required=True,
 | 
				
			||||||
 | 
					    help="The suffix of the tag.",
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    args = parser.parse_args()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # detect channel from tag
 | 
				
			||||||
 | 
					    match = re.match(r"^(\d+\.\d+)(?:\.\d+)?(b\d+)?$", args.tag)
 | 
				
			||||||
 | 
					    major_minor_version = None
 | 
				
			||||||
 | 
					    if match is None:
 | 
				
			||||||
 | 
					        channel = CHANNEL_DEV
 | 
				
			||||||
 | 
					    elif match.group(2) is None:
 | 
				
			||||||
 | 
					        major_minor_version = match.group(1)
 | 
				
			||||||
 | 
					        channel = CHANNEL_RELEASE
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        channel = CHANNEL_BETA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tags_to_push = [args.tag]
 | 
				
			||||||
 | 
					    if channel == CHANNEL_DEV:
 | 
				
			||||||
 | 
					        tags_to_push.append("dev")
 | 
				
			||||||
 | 
					    elif channel == CHANNEL_BETA:
 | 
				
			||||||
 | 
					        tags_to_push.append("beta")
 | 
				
			||||||
 | 
					    elif channel == CHANNEL_RELEASE:
 | 
				
			||||||
 | 
					        # Additionally push to beta
 | 
				
			||||||
 | 
					        tags_to_push.append("beta")
 | 
				
			||||||
 | 
					        tags_to_push.append("latest")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if major_minor_version:
 | 
				
			||||||
 | 
					            tags_to_push.append("stable")
 | 
				
			||||||
 | 
					            tags_to_push.append(major_minor_version)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    suffix = f"-{args.suffix}" if args.suffix else ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    with open(os.environ["GITHUB_OUTPUT"], "w") as f:
 | 
				
			||||||
 | 
					        print(f"channel={channel}", file=f)
 | 
				
			||||||
 | 
					        print(f"image=esphome/esphome{suffix}", file=f)
 | 
				
			||||||
 | 
					        full_tags = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for tag in tags_to_push:
 | 
				
			||||||
 | 
					            full_tags += [f"ghcr.io/esphome/esphome{suffix}:{tag}"]
 | 
				
			||||||
 | 
					            full_tags += [f"esphome/esphome{suffix}:{tag}"]
 | 
				
			||||||
 | 
					        print(f"tags={','.join(full_tags)}", file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
@@ -1,41 +0,0 @@
 | 
				
			|||||||
#!/usr/bin/with-contenv bashio
 | 
					 | 
				
			||||||
# ==============================================================================
 | 
					 | 
				
			||||||
# Community Hass.io Add-ons: ESPHome
 | 
					 | 
				
			||||||
# This files check if all user configuration requirements are met
 | 
					 | 
				
			||||||
# ==============================================================================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Check SSL requirements, if enabled
 | 
					 | 
				
			||||||
if bashio::config.true 'ssl'; then
 | 
					 | 
				
			||||||
    if ! bashio::config.has_value 'certfile'; then
 | 
					 | 
				
			||||||
        bashio::log.fatal 'SSL is enabled, but no certfile was specified.'
 | 
					 | 
				
			||||||
        bashio::exit.nok
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ! bashio::config.has_value 'keyfile'; then
 | 
					 | 
				
			||||||
        bashio::log.fatal 'SSL is enabled, but no keyfile was specified'
 | 
					 | 
				
			||||||
        bashio::exit.nok
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    certfile="/ssl/$(bashio::config 'certfile')"
 | 
					 | 
				
			||||||
    keyfile="/ssl/$(bashio::config 'keyfile')"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ! bashio::fs.file_exists "${certfile}"; then
 | 
					 | 
				
			||||||
        if ! bashio::fs.file_exists "${keyfile}"; then
 | 
					 | 
				
			||||||
            # Both files are missing, let's print a friendlier error message
 | 
					 | 
				
			||||||
            bashio::log.fatal 'You enabled encrypted connections using the "ssl": true option.'
 | 
					 | 
				
			||||||
            bashio::log.fatal "However, the SSL files '${certfile}' and '${keyfile}'"
 | 
					 | 
				
			||||||
            bashio::log.fatal "were not found. If you're using Hass.io on your local network and don't want"
 | 
					 | 
				
			||||||
            bashio::log.fatal 'to encrypt connections to the ESPHome dashboard, you can manually disable'
 | 
					 | 
				
			||||||
            bashio::log.fatal 'SSL by setting "ssl" to false."'
 | 
					 | 
				
			||||||
            bashio::exit.nok
 | 
					 | 
				
			||||||
        fi
 | 
					 | 
				
			||||||
        bashio::log.fatal "The configured certfile '${certfile}' was not found."
 | 
					 | 
				
			||||||
        bashio::exit.nok
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ! bashio::fs.file_exists "/ssl/$(bashio::config 'keyfile')"; then
 | 
					 | 
				
			||||||
        bashio::log.fatal "The configured keyfile '${keyfile}' was not found."
 | 
					 | 
				
			||||||
        bashio::exit.nok
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
@@ -1,34 +0,0 @@
 | 
				
			|||||||
#!/usr/bin/with-contenv bashio
 | 
					 | 
				
			||||||
# ==============================================================================
 | 
					 | 
				
			||||||
# Community Hass.io Add-ons: ESPHome
 | 
					 | 
				
			||||||
# Configures NGINX for use with ESPHome
 | 
					 | 
				
			||||||
# ==============================================================================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
declare certfile
 | 
					 | 
				
			||||||
declare keyfile
 | 
					 | 
				
			||||||
declare direct_port
 | 
					 | 
				
			||||||
declare ingress_interface
 | 
					 | 
				
			||||||
declare ingress_port
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
mkdir -p /var/log/nginx
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
direct_port=$(bashio::addon.port 6052)
 | 
					 | 
				
			||||||
if bashio::var.has_value "${direct_port}"; then
 | 
					 | 
				
			||||||
    if bashio::config.true 'ssl'; then
 | 
					 | 
				
			||||||
        certfile=$(bashio::config 'certfile')
 | 
					 | 
				
			||||||
        keyfile=$(bashio::config 'keyfile')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        mv /etc/nginx/servers/direct-ssl.disabled /etc/nginx/servers/direct.conf
 | 
					 | 
				
			||||||
        sed -i "s/%%certfile%%/${certfile}/g" /etc/nginx/servers/direct.conf
 | 
					 | 
				
			||||||
        sed -i "s/%%keyfile%%/${keyfile}/g" /etc/nginx/servers/direct.conf
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        mv /etc/nginx/servers/direct.disabled /etc/nginx/servers/direct.conf
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sed -i "s/%%port%%/${direct_port}/g" /etc/nginx/servers/direct.conf
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ingress_port=$(bashio::addon.ingress_port)
 | 
					 | 
				
			||||||
ingress_interface=$(bashio::addon.ip_address)
 | 
					 | 
				
			||||||
sed -i "s/%%port%%/${ingress_port}/g" /etc/nginx/servers/ingress.conf
 | 
					 | 
				
			||||||
sed -i "s/%%interface%%/${ingress_interface}/g" /etc/nginx/servers/ingress.conf
 | 
					 | 
				
			||||||
@@ -1,9 +0,0 @@
 | 
				
			|||||||
#!/usr/bin/with-contenv bashio
 | 
					 | 
				
			||||||
# ==============================================================================
 | 
					 | 
				
			||||||
# Community Hass.io Add-ons: ESPHome
 | 
					 | 
				
			||||||
# This files creates all directories used by esphome
 | 
					 | 
				
			||||||
# ==============================================================================
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pio_cache_base=/data/cache/platformio
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
mkdir -p "${pio_cache_base}"
 | 
					 | 
				
			||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
proxy_http_version 1.1;
 | 
					proxy_http_version          1.1;
 | 
				
			||||||
proxy_ignore_client_abort off;
 | 
					proxy_ignore_client_abort   off;
 | 
				
			||||||
proxy_read_timeout 86400s;
 | 
					proxy_read_timeout          86400s;
 | 
				
			||||||
proxy_redirect off;
 | 
					proxy_redirect              off;
 | 
				
			||||||
proxy_send_timeout 86400s;
 | 
					proxy_send_timeout          86400s;
 | 
				
			||||||
proxy_max_temp_file_size 0;
 | 
					proxy_max_temp_file_size    0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
proxy_set_header Accept-Encoding "";
 | 
					proxy_set_header Accept-Encoding "";
 | 
				
			||||||
proxy_set_header Connection $connection_upgrade;
 | 
					proxy_set_header Connection $connection_upgrade;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
root /dev/null;
 | 
					root            /dev/null;
 | 
				
			||||||
server_name $hostname;
 | 
					server_name     $hostname;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					client_max_body_size 512m;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_header X-Content-Type-Options nosniff;
 | 
					add_header X-Content-Type-Options nosniff;
 | 
				
			||||||
add_header X-XSS-Protection "1; mode=block";
 | 
					add_header X-XSS-Protection "1; mode=block";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,6 @@
 | 
				
			|||||||
ssl_protocols TLSv1.2;
 | 
					ssl_protocols TLSv1.2 TLSv1.3;
 | 
				
			||||||
ssl_prefer_server_ciphers on;
 | 
					ssl_prefer_server_ciphers off;
 | 
				
			||||||
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA;
 | 
					ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
 | 
				
			||||||
ssl_ecdh_curve secp384r1;
 | 
					 | 
				
			||||||
ssl_session_timeout  10m;
 | 
					ssl_session_timeout  10m;
 | 
				
			||||||
ssl_session_cache shared:SSL:10m;
 | 
					ssl_session_cache shared:SSL:10m;
 | 
				
			||||||
ssl_session_tickets off;
 | 
					ssl_session_tickets off;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								docker/ha-addon-rootfs/etc/nginx/includes/upstream.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								docker/ha-addon-rootfs/etc/nginx/includes/upstream.conf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					upstream esphome {
 | 
				
			||||||
 | 
					    server unix:/var/run/esphome.sock;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -2,7 +2,6 @@ daemon off;
 | 
				
			|||||||
user root;
 | 
					user root;
 | 
				
			||||||
pid /var/run/nginx.pid;
 | 
					pid /var/run/nginx.pid;
 | 
				
			||||||
worker_processes 1;
 | 
					worker_processes 1;
 | 
				
			||||||
# Hass.io addon log
 | 
					 | 
				
			||||||
error_log /proc/1/fd/1 error;
 | 
					error_log /proc/1/fd/1 error;
 | 
				
			||||||
events {
 | 
					events {
 | 
				
			||||||
    worker_connections 1024;
 | 
					    worker_connections 1024;
 | 
				
			||||||
@@ -10,24 +9,22 @@ events {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
http {
 | 
					http {
 | 
				
			||||||
    include /etc/nginx/includes/mime.types;
 | 
					    include /etc/nginx/includes/mime.types;
 | 
				
			||||||
    access_log stdout;
 | 
					
 | 
				
			||||||
    default_type application/octet-stream;
 | 
					    access_log              off;
 | 
				
			||||||
    gzip on;
 | 
					    default_type            application/octet-stream;
 | 
				
			||||||
    keepalive_timeout 65;
 | 
					    gzip                    on;
 | 
				
			||||||
    sendfile on;
 | 
					    keepalive_timeout       65;
 | 
				
			||||||
    server_tokens off;
 | 
					    sendfile                on;
 | 
				
			||||||
 | 
					    server_tokens           off;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tcp_nodelay             on;
 | 
				
			||||||
 | 
					    tcp_nopush              on;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    map $http_upgrade $connection_upgrade {
 | 
					    map $http_upgrade $connection_upgrade {
 | 
				
			||||||
        default upgrade;
 | 
					        default upgrade;
 | 
				
			||||||
        ''      close;
 | 
					        ''      close;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Use Hass.io supervisor as resolver
 | 
					    include /etc/nginx/includes/upstream.conf;
 | 
				
			||||||
    resolver 172.30.32.2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    upstream esphome {
 | 
					 | 
				
			||||||
        server unix:/var/run/esphome.sock;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    include /etc/nginx/servers/*.conf;
 | 
					    include /etc/nginx/servers/*.conf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								docker/ha-addon-rootfs/etc/nginx/servers/.gitkeep
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								docker/ha-addon-rootfs/etc/nginx/servers/.gitkeep
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					Without requirements or design, programming is the art of adding bugs to an empty text file. (Louis Srygley)
 | 
				
			||||||
@@ -1,12 +0,0 @@
 | 
				
			|||||||
server {
 | 
					 | 
				
			||||||
    listen %%port%% default_server;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    include /etc/nginx/includes/server_params.conf;
 | 
					 | 
				
			||||||
    include /etc/nginx/includes/proxy_params.conf;
 | 
					 | 
				
			||||||
    # Clear Hass.io Ingress header
 | 
					 | 
				
			||||||
    proxy_set_header X-HA-Ingress "";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    location / {
 | 
					 | 
				
			||||||
        proxy_pass http://esphome;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,20 +1,26 @@
 | 
				
			|||||||
server {
 | 
					server {
 | 
				
			||||||
    listen %%port%% default_server ssl http2;
 | 
					    {{ if not .ssl }}
 | 
				
			||||||
 | 
					    listen 6052 default_server;
 | 
				
			||||||
 | 
					    {{ else }}
 | 
				
			||||||
 | 
					    listen 6052 default_server ssl http2;
 | 
				
			||||||
 | 
					    {{ end }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    include /etc/nginx/includes/server_params.conf;
 | 
					    include /etc/nginx/includes/server_params.conf;
 | 
				
			||||||
    include /etc/nginx/includes/proxy_params.conf;
 | 
					    include /etc/nginx/includes/proxy_params.conf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {{ if .ssl }}
 | 
				
			||||||
    include /etc/nginx/includes/ssl_params.conf;
 | 
					    include /etc/nginx/includes/ssl_params.conf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ssl on;
 | 
					    ssl_certificate /ssl/{{ .certfile }};
 | 
				
			||||||
    ssl_certificate /ssl/%%certfile%%;
 | 
					    ssl_certificate_key /ssl/{{ .keyfile }};
 | 
				
			||||||
    ssl_certificate_key /ssl/%%keyfile%%;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Clear Hass.io Ingress header
 | 
					 | 
				
			||||||
    proxy_set_header X-HA-Ingress "";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Redirect http requests to https on the same port.
 | 
					    # Redirect http requests to https on the same port.
 | 
				
			||||||
    # https://rageagainstshell.com/2016/11/redirect-http-to-https-on-the-same-port-in-nginx/
 | 
					    # https://rageagainstshell.com/2016/11/redirect-http-to-https-on-the-same-port-in-nginx/
 | 
				
			||||||
    error_page 497 https://$http_host$request_uri;
 | 
					    error_page 497 https://$http_host$request_uri;
 | 
				
			||||||
 | 
					    {{ end }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Clear Home Assistant Ingress header
 | 
				
			||||||
 | 
					    proxy_set_header X-HA-Ingress "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    location / {
 | 
					    location / {
 | 
				
			||||||
        proxy_pass http://esphome;
 | 
					        proxy_pass http://esphome;
 | 
				
			||||||
@@ -1,14 +1,16 @@
 | 
				
			|||||||
server {
 | 
					server {
 | 
				
			||||||
    listen %%interface%%:%%port%% default_server;
 | 
					    listen 127.0.0.1:{{ .port }} default_server;
 | 
				
			||||||
 | 
					    listen {{ .interface }}:{{ .port }} default_server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    include /etc/nginx/includes/server_params.conf;
 | 
					    include /etc/nginx/includes/server_params.conf;
 | 
				
			||||||
    include /etc/nginx/includes/proxy_params.conf;
 | 
					    include /etc/nginx/includes/proxy_params.conf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Set Home Assistant Ingress header
 | 
					    # Set Home Assistant Ingress header
 | 
				
			||||||
    proxy_set_header X-HA-Ingress "YES";
 | 
					    proxy_set_header X-HA-Ingress "YES";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    location / {
 | 
					    location / {
 | 
				
			||||||
        # Only allow from Hass.io supervisor
 | 
					 | 
				
			||||||
        allow   172.30.32.2;
 | 
					        allow   172.30.32.2;
 | 
				
			||||||
 | 
					        allow   127.0.0.1;
 | 
				
			||||||
        deny    all;
 | 
					        deny    all;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        proxy_pass http://esphome;
 | 
					        proxy_pass http://esphome;
 | 
				
			||||||
							
								
								
									
										32
									
								
								docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/discovery/run
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										32
									
								
								docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/discovery/run
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					#!/command/with-contenv bashio
 | 
				
			||||||
 | 
					# shellcheck shell=bash
 | 
				
			||||||
 | 
					# ==============================================================================
 | 
				
			||||||
 | 
					# Home Assistant Add-on: ESPHome
 | 
				
			||||||
 | 
					# Sends discovery information to Home Assistant.
 | 
				
			||||||
 | 
					# ==============================================================================
 | 
				
			||||||
 | 
					declare config
 | 
				
			||||||
 | 
					declare port
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# We only disable it when disabled explicitly
 | 
				
			||||||
 | 
					if bashio::config.false 'home_assistant_dashboard_integration';
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
					    bashio::log.info "Home Assistant discovery is disabled for this add-on."
 | 
				
			||||||
 | 
					    bashio::exit.ok
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					port=$(bashio::addon.ingress_port)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Wait for NGINX to become available
 | 
				
			||||||
 | 
					bashio::net.wait_for "${port}" "127.0.0.1" 300
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config=$(\
 | 
				
			||||||
 | 
					    bashio::var.json \
 | 
				
			||||||
 | 
					        host "127.0.0.1" \
 | 
				
			||||||
 | 
					        port "^${port}" \
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if bashio::discovery "esphome" "${config}" > /dev/null; then
 | 
				
			||||||
 | 
					    bashio::log.info "Successfully send discovery information to Home Assistant."
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					    bashio::log.error "Discovery message to Home Assistant failed!"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					oneshot
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					/etc/s6-overlay/s6-rc.d/discovery/run
 | 
				
			||||||
							
								
								
									
										26
									
								
								docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/finish
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										26
									
								
								docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/esphome/finish
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					#!/command/with-contenv bashio
 | 
				
			||||||
 | 
					# shellcheck shell=bash
 | 
				
			||||||
 | 
					# ==============================================================================
 | 
				
			||||||
 | 
					# Home Assistant Community Add-on: ESPHome
 | 
				
			||||||
 | 
					# Take down the S6 supervision tree when ESPHome dashboard fails
 | 
				
			||||||
 | 
					# ==============================================================================
 | 
				
			||||||
 | 
					declare exit_code
 | 
				
			||||||
 | 
					readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
 | 
				
			||||||
 | 
					readonly exit_code_service="${1}"
 | 
				
			||||||
 | 
					readonly exit_code_signal="${2}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bashio::log.info \
 | 
				
			||||||
 | 
					  "Service ESPHome dashboard exited with code ${exit_code_service}" \
 | 
				
			||||||
 | 
					  "(by signal ${exit_code_signal})"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [[ "${exit_code_service}" -eq 256 ]]; then
 | 
				
			||||||
 | 
					  if [[ "${exit_code_container}" -eq 0 ]]; then
 | 
				
			||||||
 | 
					    echo $((128 + $exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					  [[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
 | 
				
			||||||
 | 
					elif [[ "${exit_code_service}" -ne 0 ]]; then
 | 
				
			||||||
 | 
					  if [[ "${exit_code_container}" -eq 0 ]]; then
 | 
				
			||||||
 | 
					    echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					  exec /run/s6/basedir/bin/halt
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
@@ -1,10 +1,19 @@
 | 
				
			|||||||
#!/usr/bin/with-contenv bashio
 | 
					#!/command/with-contenv bashio
 | 
				
			||||||
 | 
					# shellcheck shell=bash
 | 
				
			||||||
# ==============================================================================
 | 
					# ==============================================================================
 | 
				
			||||||
# Community Hass.io Add-ons: ESPHome
 | 
					# Community Hass.io Add-ons: ESPHome
 | 
				
			||||||
# Runs the ESPHome dashboard
 | 
					# Runs the ESPHome dashboard
 | 
				
			||||||
# ==============================================================================
 | 
					# ==============================================================================
 | 
				
			||||||
 | 
					readonly pio_cache_base=/data/cache/platformio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export ESPHOME_IS_HA_ADDON=true
 | 
					export ESPHOME_IS_HA_ADDON=true
 | 
				
			||||||
 | 
					export PLATFORMIO_GLOBALLIB_DIR=/piolibs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# we can't set core_dir, because the settings file is stored in `core_dir/appstate.json`
 | 
				
			||||||
 | 
					# setting `core_dir` would therefore prevent pio from accessing
 | 
				
			||||||
 | 
					export PLATFORMIO_PLATFORMS_DIR="${pio_cache_base}/platforms"
 | 
				
			||||||
 | 
					export PLATFORMIO_PACKAGES_DIR="${pio_cache_base}/packages"
 | 
				
			||||||
 | 
					export PLATFORMIO_CACHE_DIR="${pio_cache_base}/cache"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if bashio::config.true 'leave_front_door_open'; then
 | 
					if bashio::config.true 'leave_front_door_open'; then
 | 
				
			||||||
    export DISABLE_HA_AUTHENTICATION=true
 | 
					    export DISABLE_HA_AUTHENTICATION=true
 | 
				
			||||||
@@ -22,14 +31,15 @@ if bashio::config.has_value 'relative_url'; then
 | 
				
			|||||||
    export ESPHOME_DASHBOARD_RELATIVE_URL=$(bashio::config 'relative_url')
 | 
					    export ESPHOME_DASHBOARD_RELATIVE_URL=$(bashio::config 'relative_url')
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pio_cache_base=/data/cache/platformio
 | 
					if bashio::config.has_value 'default_compile_process_limit'; then
 | 
				
			||||||
# we can't set core_dir, because the settings file is stored in `core_dir/appstate.json`
 | 
					    export ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT=$(bashio::config 'default_compile_process_limit')
 | 
				
			||||||
# setting `core_dir` would therefore prevent pio from accessing
 | 
					else
 | 
				
			||||||
export PLATFORMIO_PLATFORMS_DIR="${pio_cache_base}/platforms"
 | 
					    if grep -q 'Raspberry Pi 3' /proc/cpuinfo; then
 | 
				
			||||||
export PLATFORMIO_PACKAGES_DIR="${pio_cache_base}/packages"
 | 
					        export ESPHOME_DEFAULT_COMPILE_PROCESS_LIMIT=1;
 | 
				
			||||||
export PLATFORMIO_CACHE_DIR="${pio_cache_base}/cache"
 | 
					    fi
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export PLATFORMIO_GLOBALLIB_DIR=/piolibs
 | 
					mkdir -p "${pio_cache_base}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bashio::log.info "Starting ESPHome dashboard..."
 | 
					bashio::log.info "Starting ESPHome dashboard..."
 | 
				
			||||||
exec esphome dashboard /config/esphome --socket /var/run/esphome.sock --ha-addon
 | 
					exec esphome dashboard /config/esphome --socket /var/run/esphome.sock --ha-addon
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					longrun
 | 
				
			||||||
							
								
								
									
										27
									
								
								docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/init-nginx/run
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										27
									
								
								docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/init-nginx/run
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					#!/command/with-contenv bashio
 | 
				
			||||||
 | 
					# shellcheck shell=bash
 | 
				
			||||||
 | 
					# ==============================================================================
 | 
				
			||||||
 | 
					# Community Hass.io Add-ons: ESPHome
 | 
				
			||||||
 | 
					# Configures NGINX for use with ESPHome
 | 
				
			||||||
 | 
					# ==============================================================================
 | 
				
			||||||
 | 
					mkdir -p /var/log/nginx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Generate Ingress configuration
 | 
				
			||||||
 | 
					bashio::var.json \
 | 
				
			||||||
 | 
					    interface "$(bashio::addon.ip_address)" \
 | 
				
			||||||
 | 
					    port "^$(bashio::addon.ingress_port)" \
 | 
				
			||||||
 | 
					    | tempio \
 | 
				
			||||||
 | 
					        -template /etc/nginx/templates/ingress.gtpl \
 | 
				
			||||||
 | 
					        -out /etc/nginx/servers/ingress.conf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Generate direct access configuration, if enabled.
 | 
				
			||||||
 | 
					if bashio::var.has_value "$(bashio::addon.port 6052)"; then
 | 
				
			||||||
 | 
					    bashio::config.require.ssl
 | 
				
			||||||
 | 
					    bashio::var.json \
 | 
				
			||||||
 | 
					        certfile "$(bashio::config 'certfile')" \
 | 
				
			||||||
 | 
					        keyfile "$(bashio::config 'keyfile')" \
 | 
				
			||||||
 | 
					        ssl "^$(bashio::config 'ssl')" \
 | 
				
			||||||
 | 
					        | tempio \
 | 
				
			||||||
 | 
					            -template /etc/nginx/templates/direct.gtpl \
 | 
				
			||||||
 | 
					            -out /etc/nginx/servers/direct.conf
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					oneshot
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					/etc/s6-overlay/s6-rc.d/init-nginx/run
 | 
				
			||||||
							
								
								
									
										25
									
								
								docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/nginx/finish
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										25
									
								
								docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/nginx/finish
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					#!/command/with-contenv bashio
 | 
				
			||||||
 | 
					# ==============================================================================
 | 
				
			||||||
 | 
					# Community Hass.io Add-ons: ESPHome
 | 
				
			||||||
 | 
					# Take down the S6 supervision tree when NGINX fails
 | 
				
			||||||
 | 
					# ==============================================================================
 | 
				
			||||||
 | 
					declare exit_code
 | 
				
			||||||
 | 
					readonly exit_code_container=$(</run/s6-linux-init-container-results/exitcode)
 | 
				
			||||||
 | 
					readonly exit_code_service="${1}"
 | 
				
			||||||
 | 
					readonly exit_code_signal="${2}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bashio::log.info \
 | 
				
			||||||
 | 
					  "Service NGINX exited with code ${exit_code_service}" \
 | 
				
			||||||
 | 
					  "(by signal ${exit_code_signal})"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [[ "${exit_code_service}" -eq 256 ]]; then
 | 
				
			||||||
 | 
					  if [[ "${exit_code_container}" -eq 0 ]]; then
 | 
				
			||||||
 | 
					    echo $((128 + $exit_code_signal)) > /run/s6-linux-init-container-results/exitcode
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					  [[ "${exit_code_signal}" -eq 15 ]] && exec /run/s6/basedir/bin/halt
 | 
				
			||||||
 | 
					elif [[ "${exit_code_service}" -ne 0 ]]; then
 | 
				
			||||||
 | 
					  if [[ "${exit_code_container}" -eq 0 ]]; then
 | 
				
			||||||
 | 
					    echo "${exit_code_service}" > /run/s6-linux-init-container-results/exitcode
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					  exec /run/s6/basedir/bin/halt
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
@@ -1,10 +1,11 @@
 | 
				
			|||||||
#!/usr/bin/with-contenv bashio
 | 
					#!/command/with-contenv bashio
 | 
				
			||||||
 | 
					# shellcheck shell=bash
 | 
				
			||||||
# ==============================================================================
 | 
					# ==============================================================================
 | 
				
			||||||
# Community Hass.io Add-ons: ESPHome
 | 
					# Community Hass.io Add-ons: ESPHome
 | 
				
			||||||
# Runs the NGINX proxy
 | 
					# Runs the NGINX proxy
 | 
				
			||||||
# ==============================================================================
 | 
					# ==============================================================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bashio::log.info "Waiting for dashboard to come up..."
 | 
					bashio::log.info "Waiting for ESPHome dashboard to come up..."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
while [[ ! -S /var/run/esphome.sock ]]; do
 | 
					while [[ ! -S /var/run/esphome.sock ]]; do
 | 
				
			||||||
  sleep 0.5
 | 
					  sleep 0.5
 | 
				
			||||||
							
								
								
									
										1
									
								
								docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/nginx/type
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								docker/ha-addon-rootfs/etc/s6-overlay/s6-rc.d/nginx/type
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					longrun
 | 
				
			||||||
@@ -1,9 +0,0 @@
 | 
				
			|||||||
#!/usr/bin/execlineb -S0
 | 
					 | 
				
			||||||
# ==============================================================================
 | 
					 | 
				
			||||||
# Community Hass.io Add-ons: ESPHome
 | 
					 | 
				
			||||||
# Take down the S6 supervision tree when ESPHome fails
 | 
					 | 
				
			||||||
# ==============================================================================
 | 
					 | 
				
			||||||
if -n { s6-test $# -ne 0 }
 | 
					 | 
				
			||||||
if -n { s6-test ${1} -eq 256 }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
s6-svscanctl -t /var/run/s6/services
 | 
					 | 
				
			||||||
@@ -1,9 +0,0 @@
 | 
				
			|||||||
#!/usr/bin/execlineb -S0
 | 
					 | 
				
			||||||
# ==============================================================================
 | 
					 | 
				
			||||||
# Community Hass.io Add-ons: ESPHome
 | 
					 | 
				
			||||||
# Take down the S6 supervision tree when NGINX fails
 | 
					 | 
				
			||||||
# ==============================================================================
 | 
					 | 
				
			||||||
if -n { s6-test $# -ne 0 }
 | 
					 | 
				
			||||||
if -n { s6-test ${1} -eq 256 }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
s6-svscanctl -t /var/run/s6/services
 | 
					 | 
				
			||||||
@@ -254,8 +254,7 @@ def upload_using_esptool(config, port):
 | 
				
			|||||||
        if os.environ.get("ESPHOME_USE_SUBPROCESS") is None:
 | 
					        if os.environ.get("ESPHOME_USE_SUBPROCESS") is None:
 | 
				
			||||||
            import esptool
 | 
					            import esptool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # pylint: disable=protected-access
 | 
					            return run_external_command(esptool.main, *cmd)  # pylint: disable=no-member
 | 
				
			||||||
            return run_external_command(esptool._main, *cmd)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return run_external_process(*cmd)
 | 
					        return run_external_process(*cmd)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -298,6 +297,8 @@ def upload_program(config, args, host):
 | 
				
			|||||||
    ota_conf = config[CONF_OTA]
 | 
					    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, "")
 | 
				
			||||||
 | 
					    if getattr(args, "file", None) is not None:
 | 
				
			||||||
 | 
					        return espota2.run_ota(host, remote_port, password, args.file)
 | 
				
			||||||
    return espota2.run_ota(host, remote_port, password, CORE.firmware_bin)
 | 
					    return espota2.run_ota(host, remote_port, password, CORE.firmware_bin)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -338,7 +339,7 @@ def command_config(args, config):
 | 
				
			|||||||
    _LOGGER.info("Configuration is valid!")
 | 
					    _LOGGER.info("Configuration is valid!")
 | 
				
			||||||
    if not CORE.verbose:
 | 
					    if not CORE.verbose:
 | 
				
			||||||
        config = strip_default_ids(config)
 | 
					        config = strip_default_ids(config)
 | 
				
			||||||
    safe_print(yaml_util.dump(config))
 | 
					    safe_print(yaml_util.dump(config, args.show_secrets))
 | 
				
			||||||
    return 0
 | 
					    return 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -664,6 +665,9 @@ def parse_args(argv):
 | 
				
			|||||||
    parser_config.add_argument(
 | 
					    parser_config.add_argument(
 | 
				
			||||||
        "configuration", help="Your YAML configuration file(s).", nargs="+"
 | 
					        "configuration", help="Your YAML configuration file(s).", nargs="+"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					    parser_config.add_argument(
 | 
				
			||||||
 | 
					        "--show-secrets", help="Show secrets in output.", action="store_true"
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    parser_compile = subparsers.add_parser(
 | 
					    parser_compile = subparsers.add_parser(
 | 
				
			||||||
        "compile", help="Read the configuration and compile a program."
 | 
					        "compile", help="Read the configuration and compile a program."
 | 
				
			||||||
@@ -687,6 +691,10 @@ def parse_args(argv):
 | 
				
			|||||||
        "--device",
 | 
					        "--device",
 | 
				
			||||||
        help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
 | 
					        help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					    parser_upload.add_argument(
 | 
				
			||||||
 | 
					        "--file",
 | 
				
			||||||
 | 
					        help="Manually specify the binary file to upload.",
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    parser_logs = subparsers.add_parser(
 | 
					    parser_logs = subparsers.add_parser(
 | 
				
			||||||
        "logs",
 | 
					        "logs",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,6 +46,7 @@ void A4988::loop() {
 | 
				
			|||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  this->dir_pin_->digital_write(dir == 1);
 | 
					  this->dir_pin_->digital_write(dir == 1);
 | 
				
			||||||
 | 
					  delayMicroseconds(50);
 | 
				
			||||||
  this->step_pin_->digital_write(true);
 | 
					  this->step_pin_->digital_write(true);
 | 
				
			||||||
  delayMicroseconds(5);
 | 
					  delayMicroseconds(5);
 | 
				
			||||||
  this->step_pin_->digital_write(false);
 | 
					  this->step_pin_->digital_write(false);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,10 @@ ADC_MODE(ADC_VCC)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_RP2040
 | 
				
			||||||
 | 
					#include <hardware/adc.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace adc {
 | 
					namespace adc {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,9 +36,13 @@ static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1;    // 4095 (12 b
 | 
				
			|||||||
static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1;  // 2048 (12 bit) or 4096 (13 bit)
 | 
					static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1;  // 2048 (12 bit) or 4096 (13 bit)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ADCSensor::setup() {
 | 
					#ifdef USE_RP2040
 | 
				
			||||||
 | 
					extern "C"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    void
 | 
				
			||||||
 | 
					    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());
 | 
				
			||||||
#ifndef USE_ADC_SENSOR_VCC
 | 
					#if !defined(USE_ADC_SENSOR_VCC) && !defined(USE_RP2040)
 | 
				
			||||||
  pin_->setup();
 | 
					  pin_->setup();
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -63,6 +71,16 @@ void ADCSensor::setup() {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif  // USE_ESP32
 | 
					#endif  // USE_ESP32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_RP2040
 | 
				
			||||||
 | 
					  static bool initialized = false;
 | 
				
			||||||
 | 
					  if (!initialized) {
 | 
				
			||||||
 | 
					    adc_init();
 | 
				
			||||||
 | 
					    initialized = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "ADC '%s' setup finished!", this->get_name().c_str());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ADCSensor::dump_config() {
 | 
					void ADCSensor::dump_config() {
 | 
				
			||||||
@@ -98,6 +116,13 @@ void ADCSensor::dump_config() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif  // USE_ESP32
 | 
					#endif  // USE_ESP32
 | 
				
			||||||
 | 
					#ifdef USE_RP2040
 | 
				
			||||||
 | 
					  if (this->is_temperature_) {
 | 
				
			||||||
 | 
					    ESP_LOGCONFIG(TAG, "  Pin: Temperature");
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    LOG_PIN("  Pin: ", pin_);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
  LOG_UPDATE_INTERVAL(this);
 | 
					  LOG_UPDATE_INTERVAL(this);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -175,6 +200,29 @@ float ADCSensor::sample() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
#endif  // USE_ESP32
 | 
					#endif  // USE_ESP32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_RP2040
 | 
				
			||||||
 | 
					float ADCSensor::sample() {
 | 
				
			||||||
 | 
					  if (this->is_temperature_) {
 | 
				
			||||||
 | 
					    adc_set_temp_sensor_enabled(true);
 | 
				
			||||||
 | 
					    delay(1);
 | 
				
			||||||
 | 
					    adc_select_input(4);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    uint8_t pin = this->pin_->get_pin();
 | 
				
			||||||
 | 
					    adc_gpio_init(pin);
 | 
				
			||||||
 | 
					    adc_select_input(pin - 26);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int raw = adc_read();
 | 
				
			||||||
 | 
					  if (this->is_temperature_) {
 | 
				
			||||||
 | 
					    adc_set_temp_sensor_enabled(false);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (output_raw_) {
 | 
				
			||||||
 | 
					    return raw;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return raw * 3.3f / 4096.0f;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP8266
 | 
					#ifdef USE_ESP8266
 | 
				
			||||||
std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; }
 | 
					std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,10 +38,18 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
 | 
				
			|||||||
  std::string unique_id() override;
 | 
					  std::string unique_id() override;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_RP2040
 | 
				
			||||||
 | 
					  void set_is_temperature() { is_temperature_ = true; }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
  InternalGPIOPin *pin_;
 | 
					  InternalGPIOPin *pin_;
 | 
				
			||||||
  bool output_raw_{false};
 | 
					  bool output_raw_{false};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_RP2040
 | 
				
			||||||
 | 
					  bool is_temperature_{false};
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
  adc_atten_t attenuation_{ADC_ATTEN_DB_0};
 | 
					  adc_atten_t attenuation_{ADC_ATTEN_DB_0};
 | 
				
			||||||
  adc1_channel_t channel_{};
 | 
					  adc1_channel_t channel_{};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -94,6 +94,9 @@ def validate_adc_pin(value):
 | 
				
			|||||||
    if str(value).upper() == "VCC":
 | 
					    if str(value).upper() == "VCC":
 | 
				
			||||||
        return cv.only_on_esp8266("VCC")
 | 
					        return cv.only_on_esp8266("VCC")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if str(value).upper() == "TEMPERATURE":
 | 
				
			||||||
 | 
					        return cv.only_on_rp2040("TEMPERATURE")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if CORE.is_esp32:
 | 
					    if CORE.is_esp32:
 | 
				
			||||||
        value = pins.internal_gpio_input_pin_number(value)
 | 
					        value = pins.internal_gpio_input_pin_number(value)
 | 
				
			||||||
        variant = get_esp32_variant()
 | 
					        variant = get_esp32_variant()
 | 
				
			||||||
@@ -117,6 +120,12 @@ def validate_adc_pin(value):
 | 
				
			|||||||
            {CONF_ANALOG: True, CONF_INPUT: True}, internal=True
 | 
					            {CONF_ANALOG: True, CONF_INPUT: True}, internal=True
 | 
				
			||||||
        )(value)
 | 
					        )(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if CORE.is_rp2040:
 | 
				
			||||||
 | 
					        value = pins.internal_gpio_input_pin_number(value)
 | 
				
			||||||
 | 
					        if value not in (26, 27, 28, 29):
 | 
				
			||||||
 | 
					            raise cv.Invalid("RP2040: Only pins 26, 27, 28 and 29 support ADC.")
 | 
				
			||||||
 | 
					        return pins.internal_gpio_input_pin_schema(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    raise NotImplementedError
 | 
					    raise NotImplementedError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -160,6 +169,8 @@ async def to_code(config):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if config[CONF_PIN] == "VCC":
 | 
					    if config[CONF_PIN] == "VCC":
 | 
				
			||||||
        cg.add_define("USE_ADC_SENSOR_VCC")
 | 
					        cg.add_define("USE_ADC_SENSOR_VCC")
 | 
				
			||||||
 | 
					    elif config[CONF_PIN] == "TEMPERATURE":
 | 
				
			||||||
 | 
					        cg.add(var.set_is_temperature())
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        pin = await cg.gpio_pin_expression(config[CONF_PIN])
 | 
					        pin = await cg.gpio_pin_expression(config[CONF_PIN])
 | 
				
			||||||
        cg.add(var.set_pin(pin))
 | 
					        cg.add(var.set_pin(pin))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@
 | 
				
			|||||||
#include "esphome/components/display/display_buffer.h"
 | 
					#include "esphome/components/display/display_buffer.h"
 | 
				
			||||||
#include "esphome/components/light/addressable_light.h"
 | 
					#include "esphome/components/light/addressable_light.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace addressable_light {
 | 
					namespace addressable_light {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@
 | 
				
			|||||||
#include "esphome/components/i2c/i2c.h"
 | 
					#include "esphome/components/i2c/i2c.h"
 | 
				
			||||||
#include "esphome/components/sensor/sensor.h"
 | 
					#include "esphome/components/sensor/sensor.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace ade7953 {
 | 
					namespace ade7953 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ static const char *const TAG = "ads1115";
 | 
				
			|||||||
static const uint8_t ADS1115_REGISTER_CONVERSION = 0x00;
 | 
					static const uint8_t ADS1115_REGISTER_CONVERSION = 0x00;
 | 
				
			||||||
static const uint8_t ADS1115_REGISTER_CONFIG = 0x01;
 | 
					static const uint8_t ADS1115_REGISTER_CONFIG = 0x01;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const uint8_t ADS1115_DATA_RATE_860_SPS = 0b111;
 | 
					static const uint8_t ADS1115_DATA_RATE_860_SPS = 0b111;  // 3300_SPS for ADS1015
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ADS1115Component::setup() {
 | 
					void ADS1115Component::setup() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up ADS1115...");
 | 
					  ESP_LOGCONFIG(TAG, "Setting up ADS1115...");
 | 
				
			||||||
@@ -18,6 +18,9 @@ void ADS1115Component::setup() {
 | 
				
			|||||||
    this->mark_failed();
 | 
					    this->mark_failed();
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "Configuring ADS1115...");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  uint16_t config = 0;
 | 
					  uint16_t config = 0;
 | 
				
			||||||
  // Clear single-shot bit
 | 
					  // Clear single-shot bit
 | 
				
			||||||
  //        0b0xxxxxxxxxxxxxxx
 | 
					  //        0b0xxxxxxxxxxxxxxx
 | 
				
			||||||
@@ -77,6 +80,7 @@ void ADS1115Component::dump_config() {
 | 
				
			|||||||
    LOG_SENSOR("  ", "Sensor", sensor);
 | 
					    LOG_SENSOR("  ", "Sensor", sensor);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "    Multiplexer: %u", sensor->get_multiplexer());
 | 
					    ESP_LOGCONFIG(TAG, "    Multiplexer: %u", sensor->get_multiplexer());
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "    Gain: %u", sensor->get_gain());
 | 
					    ESP_LOGCONFIG(TAG, "    Gain: %u", sensor->get_gain());
 | 
				
			||||||
 | 
					    ESP_LOGCONFIG(TAG, "    Resolution: %u", sensor->get_resolution());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
float ADS1115Component::request_measurement(ADS1115Sensor *sensor) {
 | 
					float ADS1115Component::request_measurement(ADS1115Sensor *sensor) {
 | 
				
			||||||
@@ -127,27 +131,45 @@ float ADS1115Component::request_measurement(ADS1115Sensor *sensor) {
 | 
				
			|||||||
    this->status_set_warning();
 | 
					    this->status_set_warning();
 | 
				
			||||||
    return NAN;
 | 
					    return NAN;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (sensor->get_resolution() == ADS1015_12_BITS) {
 | 
				
			||||||
 | 
					    bool negative = (raw_conversion >> 15) == 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // shift raw_conversion as it's only 12-bits, left justified
 | 
				
			||||||
 | 
					    raw_conversion = raw_conversion >> (16 - ADS1015_12_BITS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // check if number was negative in order to keep the sign
 | 
				
			||||||
 | 
					    if (negative) {
 | 
				
			||||||
 | 
					      // the number was negative
 | 
				
			||||||
 | 
					      // 1) set the negative bit back
 | 
				
			||||||
 | 
					      raw_conversion |= 0x8000;
 | 
				
			||||||
 | 
					      // 2) reset the former (shifted) negative bit
 | 
				
			||||||
 | 
					      raw_conversion &= 0xF7FF;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto signed_conversion = static_cast<int16_t>(raw_conversion);
 | 
					  auto signed_conversion = static_cast<int16_t>(raw_conversion);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  float millivolts;
 | 
					  float millivolts;
 | 
				
			||||||
 | 
					  float divider = (sensor->get_resolution() == ADS1115_16_BITS) ? 32768.0f : 2048.0f;
 | 
				
			||||||
  switch (sensor->get_gain()) {
 | 
					  switch (sensor->get_gain()) {
 | 
				
			||||||
    case ADS1115_GAIN_6P144:
 | 
					    case ADS1115_GAIN_6P144:
 | 
				
			||||||
      millivolts = signed_conversion * 0.187500f;
 | 
					      millivolts = (signed_conversion * 6144) / divider;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case ADS1115_GAIN_4P096:
 | 
					    case ADS1115_GAIN_4P096:
 | 
				
			||||||
      millivolts = signed_conversion * 0.125000f;
 | 
					      millivolts = (signed_conversion * 4096) / divider;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case ADS1115_GAIN_2P048:
 | 
					    case ADS1115_GAIN_2P048:
 | 
				
			||||||
      millivolts = signed_conversion * 0.062500f;
 | 
					      millivolts = (signed_conversion * 2048) / divider;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case ADS1115_GAIN_1P024:
 | 
					    case ADS1115_GAIN_1P024:
 | 
				
			||||||
      millivolts = signed_conversion * 0.031250f;
 | 
					      millivolts = (signed_conversion * 1024) / divider;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case ADS1115_GAIN_0P512:
 | 
					    case ADS1115_GAIN_0P512:
 | 
				
			||||||
      millivolts = signed_conversion * 0.015625f;
 | 
					      millivolts = (signed_conversion * 512) / divider;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case ADS1115_GAIN_0P256:
 | 
					    case ADS1115_GAIN_0P256:
 | 
				
			||||||
      millivolts = signed_conversion * 0.007813f;
 | 
					      millivolts = (signed_conversion * 256) / divider;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      millivolts = NAN;
 | 
					      millivolts = NAN;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@
 | 
				
			|||||||
#include "esphome/components/i2c/i2c.h"
 | 
					#include "esphome/components/i2c/i2c.h"
 | 
				
			||||||
#include "esphome/components/voltage_sampler/voltage_sampler.h"
 | 
					#include "esphome/components/voltage_sampler/voltage_sampler.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace ads1115 {
 | 
					namespace ads1115 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -28,6 +30,11 @@ enum ADS1115Gain {
 | 
				
			|||||||
  ADS1115_GAIN_0P256 = 0b101,
 | 
					  ADS1115_GAIN_0P256 = 0b101,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum ADS1115Resolution {
 | 
				
			||||||
 | 
					  ADS1115_16_BITS = 16,
 | 
				
			||||||
 | 
					  ADS1015_12_BITS = 12,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ADS1115Sensor;
 | 
					class ADS1115Sensor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ADS1115Component : public Component, public i2c::I2CDevice {
 | 
					class ADS1115Component : public Component, public i2c::I2CDevice {
 | 
				
			||||||
@@ -56,15 +63,17 @@ class ADS1115Sensor : public sensor::Sensor, public PollingComponent, public vol
 | 
				
			|||||||
  void update() override;
 | 
					  void update() override;
 | 
				
			||||||
  void set_multiplexer(ADS1115Multiplexer multiplexer) { multiplexer_ = multiplexer; }
 | 
					  void set_multiplexer(ADS1115Multiplexer multiplexer) { multiplexer_ = multiplexer; }
 | 
				
			||||||
  void set_gain(ADS1115Gain gain) { gain_ = gain; }
 | 
					  void set_gain(ADS1115Gain gain) { gain_ = gain; }
 | 
				
			||||||
 | 
					  void set_resolution(ADS1115Resolution resolution) { resolution_ = resolution; }
 | 
				
			||||||
  float sample() override;
 | 
					  float sample() override;
 | 
				
			||||||
  uint8_t get_multiplexer() const { return multiplexer_; }
 | 
					  uint8_t get_multiplexer() const { return multiplexer_; }
 | 
				
			||||||
  uint8_t get_gain() const { return gain_; }
 | 
					  uint8_t get_gain() const { return gain_; }
 | 
				
			||||||
 | 
					  uint8_t get_resolution() const { return resolution_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
  ADS1115Component *parent_;
 | 
					  ADS1115Component *parent_;
 | 
				
			||||||
  ADS1115Multiplexer multiplexer_;
 | 
					  ADS1115Multiplexer multiplexer_;
 | 
				
			||||||
  ADS1115Gain gain_;
 | 
					  ADS1115Gain gain_;
 | 
				
			||||||
 | 
					  ADS1115Resolution resolution_;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace ads1115
 | 
					}  // namespace ads1115
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@ from esphome.components import sensor, voltage_sampler
 | 
				
			|||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_GAIN,
 | 
					    CONF_GAIN,
 | 
				
			||||||
    CONF_MULTIPLEXER,
 | 
					    CONF_MULTIPLEXER,
 | 
				
			||||||
 | 
					    CONF_RESOLUTION,
 | 
				
			||||||
    DEVICE_CLASS_VOLTAGE,
 | 
					    DEVICE_CLASS_VOLTAGE,
 | 
				
			||||||
    STATE_CLASS_MEASUREMENT,
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_VOLT,
 | 
					    UNIT_VOLT,
 | 
				
			||||||
@@ -35,6 +36,12 @@ GAIN = {
 | 
				
			|||||||
    "0.256": ADS1115Gain.ADS1115_GAIN_0P256,
 | 
					    "0.256": ADS1115Gain.ADS1115_GAIN_0P256,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ADS1115Resolution = ads1115_ns.enum("ADS1115Resolution")
 | 
				
			||||||
 | 
					RESOLUTION = {
 | 
				
			||||||
 | 
					    "16_BITS": ADS1115Resolution.ADS1115_16_BITS,
 | 
				
			||||||
 | 
					    "12_BITS": ADS1115Resolution.ADS1015_12_BITS,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def validate_gain(value):
 | 
					def validate_gain(value):
 | 
				
			||||||
    if isinstance(value, float):
 | 
					    if isinstance(value, float):
 | 
				
			||||||
@@ -63,6 +70,9 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
            cv.GenerateID(CONF_ADS1115_ID): cv.use_id(ADS1115Component),
 | 
					            cv.GenerateID(CONF_ADS1115_ID): cv.use_id(ADS1115Component),
 | 
				
			||||||
            cv.Required(CONF_MULTIPLEXER): cv.enum(MUX, upper=True, space="_"),
 | 
					            cv.Required(CONF_MULTIPLEXER): cv.enum(MUX, upper=True, space="_"),
 | 
				
			||||||
            cv.Required(CONF_GAIN): validate_gain,
 | 
					            cv.Required(CONF_GAIN): validate_gain,
 | 
				
			||||||
 | 
					            cv.Optional(CONF_RESOLUTION, default="16_BITS"): cv.enum(
 | 
				
			||||||
 | 
					                RESOLUTION, upper=True, space="_"
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    .extend(cv.polling_component_schema("60s"))
 | 
					    .extend(cv.polling_component_schema("60s"))
 | 
				
			||||||
@@ -77,5 +87,6 @@ async def to_code(config):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER]))
 | 
					    cg.add(var.set_multiplexer(config[CONF_MULTIPLEXER]))
 | 
				
			||||||
    cg.add(var.set_gain(config[CONF_GAIN]))
 | 
					    cg.add(var.set_gain(config[CONF_GAIN]))
 | 
				
			||||||
 | 
					    cg.add(var.set_resolution(config[CONF_RESOLUTION]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cg.add(paren.register_sensor(var))
 | 
					    cg.add(paren.register_sensor(var))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -122,8 +122,9 @@ void AHT10Component::update() {
 | 
				
			|||||||
    this->temperature_sensor_->publish_state(temperature);
 | 
					    this->temperature_sensor_->publish_state(temperature);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (this->humidity_sensor_ != nullptr) {
 | 
					  if (this->humidity_sensor_ != nullptr) {
 | 
				
			||||||
    if (std::isnan(humidity))
 | 
					    if (std::isnan(humidity)) {
 | 
				
			||||||
      ESP_LOGW(TAG, "Invalid humidity! Sensor reported 0%% Hum");
 | 
					      ESP_LOGW(TAG, "Invalid humidity! Sensor reported 0%% Hum");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    this->humidity_sensor_->publish_state(humidity);
 | 
					    this->humidity_sensor_->publish_state(humidity);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  this->status_clear_warning();
 | 
					  this->status_clear_warning();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -104,8 +104,9 @@ void Am43::update() {
 | 
				
			|||||||
      auto status =
 | 
					      auto status =
 | 
				
			||||||
          esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
 | 
					          esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
 | 
				
			||||||
                                   packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
					                                   packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
				
			||||||
      if (status)
 | 
					      if (status) {
 | 
				
			||||||
        ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
 | 
					        ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this->current_sensor_++;
 | 
					    this->current_sensor_++;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,8 +56,9 @@ void Am43Component::control(const CoverCall &call) {
 | 
				
			|||||||
    auto status =
 | 
					    auto status =
 | 
				
			||||||
        esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
 | 
					        esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
 | 
				
			||||||
                                 packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
					                                 packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
				
			||||||
    if (status)
 | 
					    if (status) {
 | 
				
			||||||
      ESP_LOGW(TAG, "[%s] Error writing stop command to device, error = %d", this->get_name().c_str(), status);
 | 
					      ESP_LOGW(TAG, "[%s] Error writing stop command to device, error = %d", this->get_name().c_str(), status);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (call.get_position().has_value()) {
 | 
					  if (call.get_position().has_value()) {
 | 
				
			||||||
    auto pos = *call.get_position();
 | 
					    auto pos = *call.get_position();
 | 
				
			||||||
@@ -68,8 +69,9 @@ void Am43Component::control(const CoverCall &call) {
 | 
				
			|||||||
    auto status =
 | 
					    auto status =
 | 
				
			||||||
        esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
 | 
					        esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
 | 
				
			||||||
                                 packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
					                                 packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
				
			||||||
    if (status)
 | 
					    if (status) {
 | 
				
			||||||
      ESP_LOGW(TAG, "[%s] Error writing set_position command to device, error = %d", this->get_name().c_str(), status);
 | 
					      ESP_LOGW(TAG, "[%s] Error writing set_position command to device, error = %d", this->get_name().c_str(), status);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -126,18 +128,21 @@ void Am43Component::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_
 | 
				
			|||||||
          auto status = esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(),
 | 
					          auto status = esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(),
 | 
				
			||||||
                                                 this->char_handle_, packet->length, packet->data,
 | 
					                                                 this->char_handle_, packet->length, packet->data,
 | 
				
			||||||
                                                 ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
					                                                 ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
				
			||||||
          if (status)
 | 
					          if (status) {
 | 
				
			||||||
            ESP_LOGW(TAG, "[%s] Error writing set_position to device, error = %d", this->get_name().c_str(), status);
 | 
					            ESP_LOGW(TAG, "[%s] Error writing set_position to device, error = %d", this->get_name().c_str(), status);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          ESP_LOGW(TAG, "[%s] AM43 pin rejected!", this->get_name().c_str());
 | 
					          ESP_LOGW(TAG, "[%s] AM43 pin rejected!", this->get_name().c_str());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (this->decoder_->has_set_position_response() && !this->decoder_->set_position_ok_)
 | 
					      if (this->decoder_->has_set_position_response() && !this->decoder_->set_position_ok_) {
 | 
				
			||||||
        ESP_LOGW(TAG, "[%s] Got nack after sending set_position. Bad pin?", this->get_name().c_str());
 | 
					        ESP_LOGW(TAG, "[%s] Got nack after sending set_position. Bad pin?", this->get_name().c_str());
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (this->decoder_->has_set_state_response() && !this->decoder_->set_state_ok_)
 | 
					      if (this->decoder_->has_set_state_response() && !this->decoder_->set_state_ok_) {
 | 
				
			||||||
        ESP_LOGW(TAG, "[%s] Got nack after sending set_state. Bad pin?", this->get_name().c_str());
 | 
					        ESP_LOGW(TAG, "[%s] Got nack after sending set_state. Bad pin?", this->get_name().c_str());
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -117,7 +117,7 @@ async def to_code(config):
 | 
				
			|||||||
                data[pos] = rgb & 255
 | 
					                data[pos] = rgb & 255
 | 
				
			||||||
                pos += 1
 | 
					                pos += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    elif config[CONF_TYPE] == "BINARY":
 | 
					    elif config[CONF_TYPE] in ["BINARY", "TRANSPARENT_BINARY"]:
 | 
				
			||||||
        width8 = ((width + 7) // 8) * 8
 | 
					        width8 = ((width + 7) // 8) * 8
 | 
				
			||||||
        data = [0 for _ in range((height * width8 // 8) * frames)]
 | 
					        data = [0 for _ in range((height * width8 // 8) * frames)]
 | 
				
			||||||
        for frameIndex in range(frames):
 | 
					        for frameIndex in range(frames):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,16 +37,18 @@ void Anova::control(const ClimateCall &call) {
 | 
				
			|||||||
    auto status =
 | 
					    auto status =
 | 
				
			||||||
        esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
 | 
					        esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
 | 
				
			||||||
                                 pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
					                                 pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
				
			||||||
    if (status)
 | 
					    if (status) {
 | 
				
			||||||
      ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
 | 
					      ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (call.get_target_temperature().has_value()) {
 | 
					  if (call.get_target_temperature().has_value()) {
 | 
				
			||||||
    auto *pkt = this->codec_->get_set_target_temp_request(*call.get_target_temperature());
 | 
					    auto *pkt = this->codec_->get_set_target_temp_request(*call.get_target_temperature());
 | 
				
			||||||
    auto status =
 | 
					    auto status =
 | 
				
			||||||
        esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
 | 
					        esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
 | 
				
			||||||
                                 pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
					                                 pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
				
			||||||
    if (status)
 | 
					    if (status) {
 | 
				
			||||||
      ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
 | 
					      ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -143,8 +145,9 @@ void Anova::update() {
 | 
				
			|||||||
    auto status =
 | 
					    auto status =
 | 
				
			||||||
        esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
 | 
					        esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
 | 
				
			||||||
                                 pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
					                                 pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
				
			||||||
    if (status)
 | 
					    if (status) {
 | 
				
			||||||
      ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
 | 
					      ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    this->current_request_++;
 | 
					    this->current_request_++;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,7 +23,7 @@ void APDS9960::setup() {
 | 
				
			|||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (id != 0xAB && id != 0x9C) {  // APDS9960 all should have one of these IDs
 | 
					  if (id != 0xAB && id != 0x9C && id != 0xA8) {  // APDS9960 all should have one of these IDs
 | 
				
			||||||
    this->error_code_ = WRONG_ID;
 | 
					    this->error_code_ = WRONG_ID;
 | 
				
			||||||
    this->mark_failed();
 | 
					    this->mark_failed();
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -206,6 +206,8 @@ message DeviceInfoResponse {
 | 
				
			|||||||
  uint32 bluetooth_proxy_version = 11;
 | 
					  uint32 bluetooth_proxy_version = 11;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  string manufacturer = 12;
 | 
					  string manufacturer = 12;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  string friendly_name = 13;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
message ListEntitiesRequest {
 | 
					message ListEntitiesRequest {
 | 
				
			||||||
@@ -785,6 +787,7 @@ enum ClimateFanMode {
 | 
				
			|||||||
  CLIMATE_FAN_MIDDLE = 6;
 | 
					  CLIMATE_FAN_MIDDLE = 6;
 | 
				
			||||||
  CLIMATE_FAN_FOCUS = 7;
 | 
					  CLIMATE_FAN_FOCUS = 7;
 | 
				
			||||||
  CLIMATE_FAN_DIFFUSE = 8;
 | 
					  CLIMATE_FAN_DIFFUSE = 8;
 | 
				
			||||||
 | 
					  CLIMATE_FAN_QUIET = 9;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
enum ClimateSwingMode {
 | 
					enum ClimateSwingMode {
 | 
				
			||||||
  CLIMATE_SWING_OFF = 0;
 | 
					  CLIMATE_SWING_OFF = 0;
 | 
				
			||||||
@@ -915,6 +918,7 @@ message ListEntitiesNumberResponse {
 | 
				
			|||||||
  EntityCategory entity_category = 10;
 | 
					  EntityCategory entity_category = 10;
 | 
				
			||||||
  string unit_of_measurement = 11;
 | 
					  string unit_of_measurement = 11;
 | 
				
			||||||
  NumberMode mode = 12;
 | 
					  NumberMode mode = 12;
 | 
				
			||||||
 | 
					  string device_class = 13;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
message NumberStateResponse {
 | 
					message NumberStateResponse {
 | 
				
			||||||
  option (id) = 50;
 | 
					  option (id) = 50;
 | 
				
			||||||
@@ -1140,6 +1144,8 @@ message BluetoothLEAdvertisementResponse {
 | 
				
			|||||||
  repeated string service_uuids = 4;
 | 
					  repeated string service_uuids = 4;
 | 
				
			||||||
  repeated BluetoothServiceData service_data = 5;
 | 
					  repeated BluetoothServiceData service_data = 5;
 | 
				
			||||||
  repeated BluetoothServiceData manufacturer_data = 6;
 | 
					  repeated BluetoothServiceData manufacturer_data = 6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint32 address_type = 7;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum BluetoothDeviceRequestType {
 | 
					enum BluetoothDeviceRequestType {
 | 
				
			||||||
@@ -1147,6 +1153,8 @@ enum BluetoothDeviceRequestType {
 | 
				
			|||||||
  BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1;
 | 
					  BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1;
 | 
				
			||||||
  BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2;
 | 
					  BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2;
 | 
				
			||||||
  BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3;
 | 
					  BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3;
 | 
				
			||||||
 | 
					  BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4;
 | 
				
			||||||
 | 
					  BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
message BluetoothDeviceRequest {
 | 
					message BluetoothDeviceRequest {
 | 
				
			||||||
@@ -1156,6 +1164,8 @@ message BluetoothDeviceRequest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  uint64 address = 1;
 | 
					  uint64 address = 1;
 | 
				
			||||||
  BluetoothDeviceRequestType request_type = 2;
 | 
					  BluetoothDeviceRequestType request_type = 2;
 | 
				
			||||||
 | 
					  bool has_address_type = 3;
 | 
				
			||||||
 | 
					  uint32 address_type = 4;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
message BluetoothDeviceConnectionResponse {
 | 
					message BluetoothDeviceConnectionResponse {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -616,6 +616,7 @@ bool APIConnection::send_number_info(number::Number *number) {
 | 
				
			|||||||
  msg.entity_category = static_cast<enums::EntityCategory>(number->get_entity_category());
 | 
					  msg.entity_category = static_cast<enums::EntityCategory>(number->get_entity_category());
 | 
				
			||||||
  msg.unit_of_measurement = number->traits.get_unit_of_measurement();
 | 
					  msg.unit_of_measurement = number->traits.get_unit_of_measurement();
 | 
				
			||||||
  msg.mode = static_cast<enums::NumberMode>(number->traits.get_mode());
 | 
					  msg.mode = static_cast<enums::NumberMode>(number->traits.get_mode());
 | 
				
			||||||
 | 
					  msg.device_class = number->traits.get_device_class();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  msg.min_value = number->traits.get_min_value();
 | 
					  msg.min_value = number->traits.get_min_value();
 | 
				
			||||||
  msg.max_value = number->traits.get_max_value();
 | 
					  msg.max_value = number->traits.get_max_value();
 | 
				
			||||||
@@ -929,6 +930,7 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
 | 
				
			|||||||
  DeviceInfoResponse resp{};
 | 
					  DeviceInfoResponse resp{};
 | 
				
			||||||
  resp.uses_password = this->parent_->uses_password();
 | 
					  resp.uses_password = this->parent_->uses_password();
 | 
				
			||||||
  resp.name = App.get_name();
 | 
					  resp.name = App.get_name();
 | 
				
			||||||
 | 
					  resp.friendly_name = App.get_friendly_name();
 | 
				
			||||||
  resp.mac_address = get_mac_address_pretty();
 | 
					  resp.mac_address = get_mac_address_pretty();
 | 
				
			||||||
  resp.esphome_version = ESPHOME_VERSION;
 | 
					  resp.esphome_version = ESPHOME_VERSION;
 | 
				
			||||||
  resp.compilation_time = App.get_compilation_time();
 | 
					  resp.compilation_time = App.get_compilation_time();
 | 
				
			||||||
@@ -949,7 +951,7 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
 | 
				
			|||||||
  resp.webserver_port = USE_WEBSERVER_PORT;
 | 
					  resp.webserver_port = USE_WEBSERVER_PORT;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef USE_BLUETOOTH_PROXY
 | 
					#ifdef USE_BLUETOOTH_PROXY
 | 
				
			||||||
  resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() ? 2 : 1;
 | 
					  resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() ? 3 : 1;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  return resp;
 | 
					  return resp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,8 @@
 | 
				
			|||||||
#include "esphome/core/application.h"
 | 
					#include "esphome/core/application.h"
 | 
				
			||||||
#include "esphome/core/component.h"
 | 
					#include "esphome/core/component.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace api {
 | 
					namespace api {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -616,6 +616,9 @@ APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, size_t len) {
 | 
				
			|||||||
  struct iovec iov[2];
 | 
					  struct iovec iov[2];
 | 
				
			||||||
  iov[0].iov_base = header;
 | 
					  iov[0].iov_base = header;
 | 
				
			||||||
  iov[0].iov_len = 3;
 | 
					  iov[0].iov_len = 3;
 | 
				
			||||||
 | 
					  if (len == 0) {
 | 
				
			||||||
 | 
					    return write_raw_(iov, 1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  iov[1].iov_base = const_cast<uint8_t *>(data);
 | 
					  iov[1].iov_base = const_cast<uint8_t *>(data);
 | 
				
			||||||
  iov[1].iov_len = len;
 | 
					  iov[1].iov_len = len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -913,6 +916,9 @@ APIError APIPlaintextFrameHelper::write_packet(uint16_t type, const uint8_t *pay
 | 
				
			|||||||
  struct iovec iov[2];
 | 
					  struct iovec iov[2];
 | 
				
			||||||
  iov[0].iov_base = &header[0];
 | 
					  iov[0].iov_base = &header[0];
 | 
				
			||||||
  iov[0].iov_len = header.size();
 | 
					  iov[0].iov_len = header.size();
 | 
				
			||||||
 | 
					  if (payload_len == 0) {
 | 
				
			||||||
 | 
					    return write_raw_(iov, 1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  iov[1].iov_base = const_cast<uint8_t *>(payload);
 | 
					  iov[1].iov_base = const_cast<uint8_t *>(payload);
 | 
				
			||||||
  iov[1].iov_len = payload_len;
 | 
					  iov[1].iov_len = payload_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace api {
 | 
					namespace api {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::EntityCategory>(enums::EntityCategory value) {
 | 
					template<> const char *proto_enum_to_string<enums::EntityCategory>(enums::EntityCategory value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::ENTITY_CATEGORY_NONE:
 | 
					    case enums::ENTITY_CATEGORY_NONE:
 | 
				
			||||||
@@ -18,6 +19,8 @@ template<> const char *proto_enum_to_string<enums::EntityCategory>(enums::Entity
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::LegacyCoverState>(enums::LegacyCoverState value) {
 | 
					template<> const char *proto_enum_to_string<enums::LegacyCoverState>(enums::LegacyCoverState value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::LEGACY_COVER_STATE_OPEN:
 | 
					    case enums::LEGACY_COVER_STATE_OPEN:
 | 
				
			||||||
@@ -28,6 +31,8 @@ template<> const char *proto_enum_to_string<enums::LegacyCoverState>(enums::Lega
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::CoverOperation>(enums::CoverOperation value) {
 | 
					template<> const char *proto_enum_to_string<enums::CoverOperation>(enums::CoverOperation value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::COVER_OPERATION_IDLE:
 | 
					    case enums::COVER_OPERATION_IDLE:
 | 
				
			||||||
@@ -40,6 +45,8 @@ template<> const char *proto_enum_to_string<enums::CoverOperation>(enums::CoverO
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::LegacyCoverCommand>(enums::LegacyCoverCommand value) {
 | 
					template<> const char *proto_enum_to_string<enums::LegacyCoverCommand>(enums::LegacyCoverCommand value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::LEGACY_COVER_COMMAND_OPEN:
 | 
					    case enums::LEGACY_COVER_COMMAND_OPEN:
 | 
				
			||||||
@@ -52,6 +59,8 @@ template<> const char *proto_enum_to_string<enums::LegacyCoverCommand>(enums::Le
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::FanSpeed>(enums::FanSpeed value) {
 | 
					template<> const char *proto_enum_to_string<enums::FanSpeed>(enums::FanSpeed value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::FAN_SPEED_LOW:
 | 
					    case enums::FAN_SPEED_LOW:
 | 
				
			||||||
@@ -64,6 +73,8 @@ template<> const char *proto_enum_to_string<enums::FanSpeed>(enums::FanSpeed val
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::FanDirection>(enums::FanDirection value) {
 | 
					template<> const char *proto_enum_to_string<enums::FanDirection>(enums::FanDirection value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::FAN_DIRECTION_FORWARD:
 | 
					    case enums::FAN_DIRECTION_FORWARD:
 | 
				
			||||||
@@ -74,6 +85,8 @@ template<> const char *proto_enum_to_string<enums::FanDirection>(enums::FanDirec
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::ColorMode>(enums::ColorMode value) {
 | 
					template<> const char *proto_enum_to_string<enums::ColorMode>(enums::ColorMode value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::COLOR_MODE_UNKNOWN:
 | 
					    case enums::COLOR_MODE_UNKNOWN:
 | 
				
			||||||
@@ -100,6 +113,8 @@ template<> const char *proto_enum_to_string<enums::ColorMode>(enums::ColorMode v
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::SensorStateClass>(enums::SensorStateClass value) {
 | 
					template<> const char *proto_enum_to_string<enums::SensorStateClass>(enums::SensorStateClass value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::STATE_CLASS_NONE:
 | 
					    case enums::STATE_CLASS_NONE:
 | 
				
			||||||
@@ -114,6 +129,8 @@ template<> const char *proto_enum_to_string<enums::SensorStateClass>(enums::Sens
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::SensorLastResetType>(enums::SensorLastResetType value) {
 | 
					template<> const char *proto_enum_to_string<enums::SensorLastResetType>(enums::SensorLastResetType value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::LAST_RESET_NONE:
 | 
					    case enums::LAST_RESET_NONE:
 | 
				
			||||||
@@ -126,6 +143,8 @@ template<> const char *proto_enum_to_string<enums::SensorLastResetType>(enums::S
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::LogLevel>(enums::LogLevel value) {
 | 
					template<> const char *proto_enum_to_string<enums::LogLevel>(enums::LogLevel value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::LOG_LEVEL_NONE:
 | 
					    case enums::LOG_LEVEL_NONE:
 | 
				
			||||||
@@ -148,6 +167,8 @@ template<> const char *proto_enum_to_string<enums::LogLevel>(enums::LogLevel val
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::ServiceArgType>(enums::ServiceArgType value) {
 | 
					template<> const char *proto_enum_to_string<enums::ServiceArgType>(enums::ServiceArgType value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::SERVICE_ARG_TYPE_BOOL:
 | 
					    case enums::SERVICE_ARG_TYPE_BOOL:
 | 
				
			||||||
@@ -170,6 +191,8 @@ template<> const char *proto_enum_to_string<enums::ServiceArgType>(enums::Servic
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::ClimateMode>(enums::ClimateMode value) {
 | 
					template<> const char *proto_enum_to_string<enums::ClimateMode>(enums::ClimateMode value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::CLIMATE_MODE_OFF:
 | 
					    case enums::CLIMATE_MODE_OFF:
 | 
				
			||||||
@@ -190,6 +213,8 @@ template<> const char *proto_enum_to_string<enums::ClimateMode>(enums::ClimateMo
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::ClimateFanMode>(enums::ClimateFanMode value) {
 | 
					template<> const char *proto_enum_to_string<enums::ClimateFanMode>(enums::ClimateFanMode value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::CLIMATE_FAN_ON:
 | 
					    case enums::CLIMATE_FAN_ON:
 | 
				
			||||||
@@ -210,10 +235,14 @@ template<> const char *proto_enum_to_string<enums::ClimateFanMode>(enums::Climat
 | 
				
			|||||||
      return "CLIMATE_FAN_FOCUS";
 | 
					      return "CLIMATE_FAN_FOCUS";
 | 
				
			||||||
    case enums::CLIMATE_FAN_DIFFUSE:
 | 
					    case enums::CLIMATE_FAN_DIFFUSE:
 | 
				
			||||||
      return "CLIMATE_FAN_DIFFUSE";
 | 
					      return "CLIMATE_FAN_DIFFUSE";
 | 
				
			||||||
 | 
					    case enums::CLIMATE_FAN_QUIET:
 | 
				
			||||||
 | 
					      return "CLIMATE_FAN_QUIET";
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::ClimateSwingMode>(enums::ClimateSwingMode value) {
 | 
					template<> const char *proto_enum_to_string<enums::ClimateSwingMode>(enums::ClimateSwingMode value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::CLIMATE_SWING_OFF:
 | 
					    case enums::CLIMATE_SWING_OFF:
 | 
				
			||||||
@@ -228,6 +257,8 @@ template<> const char *proto_enum_to_string<enums::ClimateSwingMode>(enums::Clim
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::ClimateAction>(enums::ClimateAction value) {
 | 
					template<> const char *proto_enum_to_string<enums::ClimateAction>(enums::ClimateAction value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::CLIMATE_ACTION_OFF:
 | 
					    case enums::CLIMATE_ACTION_OFF:
 | 
				
			||||||
@@ -246,6 +277,8 @@ template<> const char *proto_enum_to_string<enums::ClimateAction>(enums::Climate
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::ClimatePreset>(enums::ClimatePreset value) {
 | 
					template<> const char *proto_enum_to_string<enums::ClimatePreset>(enums::ClimatePreset value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::CLIMATE_PRESET_NONE:
 | 
					    case enums::CLIMATE_PRESET_NONE:
 | 
				
			||||||
@@ -268,6 +301,8 @@ template<> const char *proto_enum_to_string<enums::ClimatePreset>(enums::Climate
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::NumberMode>(enums::NumberMode value) {
 | 
					template<> const char *proto_enum_to_string<enums::NumberMode>(enums::NumberMode value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::NUMBER_MODE_AUTO:
 | 
					    case enums::NUMBER_MODE_AUTO:
 | 
				
			||||||
@@ -280,6 +315,8 @@ template<> const char *proto_enum_to_string<enums::NumberMode>(enums::NumberMode
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::LockState>(enums::LockState value) {
 | 
					template<> const char *proto_enum_to_string<enums::LockState>(enums::LockState value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::LOCK_STATE_NONE:
 | 
					    case enums::LOCK_STATE_NONE:
 | 
				
			||||||
@@ -298,6 +335,8 @@ template<> const char *proto_enum_to_string<enums::LockState>(enums::LockState v
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::LockCommand>(enums::LockCommand value) {
 | 
					template<> const char *proto_enum_to_string<enums::LockCommand>(enums::LockCommand value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::LOCK_UNLOCK:
 | 
					    case enums::LOCK_UNLOCK:
 | 
				
			||||||
@@ -310,6 +349,8 @@ template<> const char *proto_enum_to_string<enums::LockCommand>(enums::LockComma
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::MediaPlayerState>(enums::MediaPlayerState value) {
 | 
					template<> const char *proto_enum_to_string<enums::MediaPlayerState>(enums::MediaPlayerState value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::MEDIA_PLAYER_STATE_NONE:
 | 
					    case enums::MEDIA_PLAYER_STATE_NONE:
 | 
				
			||||||
@@ -324,6 +365,8 @@ template<> const char *proto_enum_to_string<enums::MediaPlayerState>(enums::Medi
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::MediaPlayerCommand>(enums::MediaPlayerCommand value) {
 | 
					template<> const char *proto_enum_to_string<enums::MediaPlayerCommand>(enums::MediaPlayerCommand value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::MEDIA_PLAYER_COMMAND_PLAY:
 | 
					    case enums::MEDIA_PLAYER_COMMAND_PLAY:
 | 
				
			||||||
@@ -340,6 +383,8 @@ template<> const char *proto_enum_to_string<enums::MediaPlayerCommand>(enums::Me
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
template<>
 | 
					template<>
 | 
				
			||||||
const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::BluetoothDeviceRequestType value) {
 | 
					const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::BluetoothDeviceRequestType value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
@@ -351,10 +396,15 @@ const char *proto_enum_to_string<enums::BluetoothDeviceRequestType>(enums::Bluet
 | 
				
			|||||||
      return "BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR";
 | 
					      return "BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR";
 | 
				
			||||||
    case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR:
 | 
					    case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR:
 | 
				
			||||||
      return "BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR";
 | 
					      return "BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR";
 | 
				
			||||||
 | 
					    case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE:
 | 
				
			||||||
 | 
					      return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE";
 | 
				
			||||||
 | 
					    case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE:
 | 
				
			||||||
 | 
					      return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE";
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
 | 
					bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
 | 
				
			||||||
  switch (field_id) {
 | 
					  switch (field_id) {
 | 
				
			||||||
    case 2: {
 | 
					    case 2: {
 | 
				
			||||||
@@ -580,6 +630,10 @@ bool DeviceInfoResponse::decode_length(uint32_t field_id, ProtoLengthDelimited v
 | 
				
			|||||||
      this->manufacturer = value.as_string();
 | 
					      this->manufacturer = value.as_string();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case 13: {
 | 
				
			||||||
 | 
					      this->friendly_name = value.as_string();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -597,6 +651,7 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
 | 
				
			|||||||
  buffer.encode_uint32(10, this->webserver_port);
 | 
					  buffer.encode_uint32(10, this->webserver_port);
 | 
				
			||||||
  buffer.encode_uint32(11, this->bluetooth_proxy_version);
 | 
					  buffer.encode_uint32(11, this->bluetooth_proxy_version);
 | 
				
			||||||
  buffer.encode_string(12, this->manufacturer);
 | 
					  buffer.encode_string(12, this->manufacturer);
 | 
				
			||||||
 | 
					  buffer.encode_string(13, this->friendly_name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
void DeviceInfoResponse::dump_to(std::string &out) const {
 | 
					void DeviceInfoResponse::dump_to(std::string &out) const {
 | 
				
			||||||
@@ -651,6 +706,10 @@ void DeviceInfoResponse::dump_to(std::string &out) const {
 | 
				
			|||||||
  out.append("  manufacturer: ");
 | 
					  out.append("  manufacturer: ");
 | 
				
			||||||
  out.append("'").append(this->manufacturer).append("'");
 | 
					  out.append("'").append(this->manufacturer).append("'");
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  friendly_name: ");
 | 
				
			||||||
 | 
					  out.append("'").append(this->friendly_name).append("'");
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
  out.append("}");
 | 
					  out.append("}");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -3942,6 +4001,10 @@ bool ListEntitiesNumberResponse::decode_length(uint32_t field_id, ProtoLengthDel
 | 
				
			|||||||
      this->unit_of_measurement = value.as_string();
 | 
					      this->unit_of_measurement = value.as_string();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case 13: {
 | 
				
			||||||
 | 
					      this->device_class = value.as_string();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -3981,6 +4044,7 @@ void ListEntitiesNumberResponse::encode(ProtoWriteBuffer buffer) const {
 | 
				
			|||||||
  buffer.encode_enum<enums::EntityCategory>(10, this->entity_category);
 | 
					  buffer.encode_enum<enums::EntityCategory>(10, this->entity_category);
 | 
				
			||||||
  buffer.encode_string(11, this->unit_of_measurement);
 | 
					  buffer.encode_string(11, this->unit_of_measurement);
 | 
				
			||||||
  buffer.encode_enum<enums::NumberMode>(12, this->mode);
 | 
					  buffer.encode_enum<enums::NumberMode>(12, this->mode);
 | 
				
			||||||
 | 
					  buffer.encode_string(13, this->device_class);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
void ListEntitiesNumberResponse::dump_to(std::string &out) const {
 | 
					void ListEntitiesNumberResponse::dump_to(std::string &out) const {
 | 
				
			||||||
@@ -4037,6 +4101,10 @@ void ListEntitiesNumberResponse::dump_to(std::string &out) const {
 | 
				
			|||||||
  out.append("  mode: ");
 | 
					  out.append("  mode: ");
 | 
				
			||||||
  out.append(proto_enum_to_string<enums::NumberMode>(this->mode));
 | 
					  out.append(proto_enum_to_string<enums::NumberMode>(this->mode));
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  device_class: ");
 | 
				
			||||||
 | 
					  out.append("'").append(this->device_class).append("'");
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
  out.append("}");
 | 
					  out.append("}");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -4984,6 +5052,10 @@ bool BluetoothLEAdvertisementResponse::decode_varint(uint32_t field_id, ProtoVar
 | 
				
			|||||||
      this->rssi = value.as_sint32();
 | 
					      this->rssi = value.as_sint32();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case 7: {
 | 
				
			||||||
 | 
					      this->address_type = value.as_uint32();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -5023,6 +5095,7 @@ void BluetoothLEAdvertisementResponse::encode(ProtoWriteBuffer buffer) const {
 | 
				
			|||||||
  for (auto &it : this->manufacturer_data) {
 | 
					  for (auto &it : this->manufacturer_data) {
 | 
				
			||||||
    buffer.encode_message<BluetoothServiceData>(6, it, true);
 | 
					    buffer.encode_message<BluetoothServiceData>(6, it, true);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  buffer.encode_uint32(7, this->address_type);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const {
 | 
					void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const {
 | 
				
			||||||
@@ -5059,6 +5132,11 @@ void BluetoothLEAdvertisementResponse::dump_to(std::string &out) const {
 | 
				
			|||||||
    it.dump_to(out);
 | 
					    it.dump_to(out);
 | 
				
			||||||
    out.append("\n");
 | 
					    out.append("\n");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  address_type: ");
 | 
				
			||||||
 | 
					  sprintf(buffer, "%u", this->address_type);
 | 
				
			||||||
 | 
					  out.append(buffer);
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
  out.append("}");
 | 
					  out.append("}");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -5072,6 +5150,14 @@ bool BluetoothDeviceRequest::decode_varint(uint32_t field_id, ProtoVarInt value)
 | 
				
			|||||||
      this->request_type = value.as_enum<enums::BluetoothDeviceRequestType>();
 | 
					      this->request_type = value.as_enum<enums::BluetoothDeviceRequestType>();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case 3: {
 | 
				
			||||||
 | 
					      this->has_address_type = value.as_bool();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 4: {
 | 
				
			||||||
 | 
					      this->address_type = value.as_uint32();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -5079,6 +5165,8 @@ bool BluetoothDeviceRequest::decode_varint(uint32_t field_id, ProtoVarInt value)
 | 
				
			|||||||
void BluetoothDeviceRequest::encode(ProtoWriteBuffer buffer) const {
 | 
					void BluetoothDeviceRequest::encode(ProtoWriteBuffer buffer) const {
 | 
				
			||||||
  buffer.encode_uint64(1, this->address);
 | 
					  buffer.encode_uint64(1, this->address);
 | 
				
			||||||
  buffer.encode_enum<enums::BluetoothDeviceRequestType>(2, this->request_type);
 | 
					  buffer.encode_enum<enums::BluetoothDeviceRequestType>(2, this->request_type);
 | 
				
			||||||
 | 
					  buffer.encode_bool(3, this->has_address_type);
 | 
				
			||||||
 | 
					  buffer.encode_uint32(4, this->address_type);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
					#ifdef HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
void BluetoothDeviceRequest::dump_to(std::string &out) const {
 | 
					void BluetoothDeviceRequest::dump_to(std::string &out) const {
 | 
				
			||||||
@@ -5092,6 +5180,15 @@ void BluetoothDeviceRequest::dump_to(std::string &out) const {
 | 
				
			|||||||
  out.append("  request_type: ");
 | 
					  out.append("  request_type: ");
 | 
				
			||||||
  out.append(proto_enum_to_string<enums::BluetoothDeviceRequestType>(this->request_type));
 | 
					  out.append(proto_enum_to_string<enums::BluetoothDeviceRequestType>(this->request_type));
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  has_address_type: ");
 | 
				
			||||||
 | 
					  out.append(YESNO(this->has_address_type));
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  address_type: ");
 | 
				
			||||||
 | 
					  sprintf(buffer, "%u", this->address_type);
 | 
				
			||||||
 | 
					  out.append(buffer);
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
  out.append("}");
 | 
					  out.append("}");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -99,6 +99,7 @@ enum ClimateFanMode : uint32_t {
 | 
				
			|||||||
  CLIMATE_FAN_MIDDLE = 6,
 | 
					  CLIMATE_FAN_MIDDLE = 6,
 | 
				
			||||||
  CLIMATE_FAN_FOCUS = 7,
 | 
					  CLIMATE_FAN_FOCUS = 7,
 | 
				
			||||||
  CLIMATE_FAN_DIFFUSE = 8,
 | 
					  CLIMATE_FAN_DIFFUSE = 8,
 | 
				
			||||||
 | 
					  CLIMATE_FAN_QUIET = 9,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
enum ClimateSwingMode : uint32_t {
 | 
					enum ClimateSwingMode : uint32_t {
 | 
				
			||||||
  CLIMATE_SWING_OFF = 0,
 | 
					  CLIMATE_SWING_OFF = 0,
 | 
				
			||||||
@@ -160,6 +161,8 @@ enum BluetoothDeviceRequestType : uint32_t {
 | 
				
			|||||||
  BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1,
 | 
					  BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1,
 | 
				
			||||||
  BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2,
 | 
					  BLUETOOTH_DEVICE_REQUEST_TYPE_PAIR = 2,
 | 
				
			||||||
  BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3,
 | 
					  BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3,
 | 
				
			||||||
 | 
					  BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4,
 | 
				
			||||||
 | 
					  BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace enums
 | 
					}  // namespace enums
 | 
				
			||||||
@@ -274,6 +277,7 @@ class DeviceInfoResponse : public ProtoMessage {
 | 
				
			|||||||
  uint32_t webserver_port{0};
 | 
					  uint32_t webserver_port{0};
 | 
				
			||||||
  uint32_t bluetooth_proxy_version{0};
 | 
					  uint32_t bluetooth_proxy_version{0};
 | 
				
			||||||
  std::string manufacturer{};
 | 
					  std::string manufacturer{};
 | 
				
			||||||
 | 
					  std::string friendly_name{};
 | 
				
			||||||
  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;
 | 
				
			||||||
@@ -1004,6 +1008,7 @@ class ListEntitiesNumberResponse : public ProtoMessage {
 | 
				
			|||||||
  enums::EntityCategory entity_category{};
 | 
					  enums::EntityCategory entity_category{};
 | 
				
			||||||
  std::string unit_of_measurement{};
 | 
					  std::string unit_of_measurement{};
 | 
				
			||||||
  enums::NumberMode mode{};
 | 
					  enums::NumberMode mode{};
 | 
				
			||||||
 | 
					  std::string device_class{};
 | 
				
			||||||
  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;
 | 
				
			||||||
@@ -1256,6 +1261,7 @@ class BluetoothLEAdvertisementResponse : public ProtoMessage {
 | 
				
			|||||||
  std::vector<std::string> service_uuids{};
 | 
					  std::vector<std::string> service_uuids{};
 | 
				
			||||||
  std::vector<BluetoothServiceData> service_data{};
 | 
					  std::vector<BluetoothServiceData> service_data{};
 | 
				
			||||||
  std::vector<BluetoothServiceData> manufacturer_data{};
 | 
					  std::vector<BluetoothServiceData> manufacturer_data{};
 | 
				
			||||||
 | 
					  uint32_t address_type{0};
 | 
				
			||||||
  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;
 | 
				
			||||||
@@ -1269,6 +1275,8 @@ class BluetoothDeviceRequest : public ProtoMessage {
 | 
				
			|||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint64_t address{0};
 | 
					  uint64_t address{0};
 | 
				
			||||||
  enums::BluetoothDeviceRequestType request_type{};
 | 
					  enums::BluetoothDeviceRequestType request_type{};
 | 
				
			||||||
 | 
					  bool has_address_type{false};
 | 
				
			||||||
 | 
					  uint32_t address_type{0};
 | 
				
			||||||
  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;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,8 @@
 | 
				
			|||||||
#include "user_services.h"
 | 
					#include "user_services.h"
 | 
				
			||||||
#include "api_noise_context.h"
 | 
					#include "api_noise_context.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace api {
 | 
					namespace api {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@
 | 
				
			|||||||
#include "api_pb2.h"
 | 
					#include "api_pb2.h"
 | 
				
			||||||
#include "api_server.h"
 | 
					#include "api_server.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace api {
 | 
					namespace api {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,8 @@
 | 
				
			|||||||
#include "esphome/core/log.h"
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
#include "esphome/core/helpers.h"
 | 
					#include "esphome/core/helpers.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
 | 
					#ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
 | 
				
			||||||
#define HAS_PROTO_MESSAGE_DUMP
 | 
					#define HAS_PROTO_MESSAGE_DUMP
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <utility>
 | 
					#include <utility>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "esphome/core/component.h"
 | 
					#include "esphome/core/component.h"
 | 
				
			||||||
#include "esphome/core/automation.h"
 | 
					#include "esphome/core/automation.h"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,8 @@
 | 
				
			|||||||
#include "esphome/components/sensor/sensor.h"
 | 
					#include "esphome/components/sensor/sensor.h"
 | 
				
			||||||
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
 | 
					#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,8 @@
 | 
				
			|||||||
#include "bedjet_child.h"
 | 
					#include "bedjet_child.h"
 | 
				
			||||||
#include "bedjet_codec.h"
 | 
					#include "bedjet_codec.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_TIME
 | 
					#ifdef USE_TIME
 | 
				
			||||||
#include "esphome/components/time/real_time_clock.h"
 | 
					#include "esphome/components/time/real_time_clock.h"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,9 +37,13 @@ void BedJetFan::control(const fan::FanCall &call) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // ignore speed changes if not on or turning on
 | 
					  // ignore speed changes if not on or turning on
 | 
				
			||||||
  if (this->state && call.get_speed().has_value()) {
 | 
					  if (this->state && call.get_speed().has_value()) {
 | 
				
			||||||
    this->speed = *call.get_speed();
 | 
					    auto speed = *call.get_speed();
 | 
				
			||||||
    this->parent_->set_fan_index(this->speed);
 | 
					    if (speed >= 1) {
 | 
				
			||||||
    did_change = true;
 | 
					      this->speed = speed;
 | 
				
			||||||
 | 
					      // Fan.speed is 1-20, but Bedjet expects 0-19, so subtract 1
 | 
				
			||||||
 | 
					      this->parent_->set_fan_index(this->speed - 1);
 | 
				
			||||||
 | 
					      did_change = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (did_change) {
 | 
					  if (did_change) {
 | 
				
			||||||
@@ -57,8 +61,9 @@ void BedJetFan::on_status(const BedjetStatusPacket *data) {
 | 
				
			|||||||
    did_change = true;
 | 
					    did_change = true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (data->fan_step != this->speed) {
 | 
					  // BedjetStatusPacket.fan_step is in range 0-19, but Fan.speed wants 1-20.
 | 
				
			||||||
    this->speed = data->fan_step;
 | 
					  if (data->fan_step + 1 != this->speed) {
 | 
				
			||||||
 | 
					    this->speed = data->fan_step + 1;
 | 
				
			||||||
    did_change = true;
 | 
					    did_change = true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <utility>
 | 
					#include <utility>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "esphome/core/component.h"
 | 
					#include "esphome/core/component.h"
 | 
				
			||||||
#include "esphome/core/automation.h"
 | 
					#include "esphome/core/automation.h"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@
 | 
				
			|||||||
#include "esphome/core/helpers.h"
 | 
					#include "esphome/core/helpers.h"
 | 
				
			||||||
#include "esphome/components/binary_sensor/filter.h"
 | 
					#include "esphome/components/binary_sensor/filter.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace binary_sensor {
 | 
					namespace binary_sensor {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,8 @@
 | 
				
			|||||||
#include "esphome/core/component.h"
 | 
					#include "esphome/core/component.h"
 | 
				
			||||||
#include "esphome/core/helpers.h"
 | 
					#include "esphome/core/helpers.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace binary_sensor {
 | 
					namespace binary_sensor {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,8 @@
 | 
				
			|||||||
#include "esphome/components/binary_sensor/binary_sensor.h"
 | 
					#include "esphome/components/binary_sensor/binary_sensor.h"
 | 
				
			||||||
#include "esphome/components/sensor/sensor.h"
 | 
					#include "esphome/components/sensor/sensor.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace binary_sensor_map {
 | 
					namespace binary_sensor_map {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,7 +66,7 @@ CONF_BLE_CLIENT_ID = "ble_client_id"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
BLE_CLIENT_SCHEMA = cv.Schema(
 | 
					BLE_CLIENT_SCHEMA = cv.Schema(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        cv.Required(CONF_BLE_CLIENT_ID): cv.use_id(BLEClient),
 | 
					        cv.GenerateID(CONF_BLE_CLIENT_ID): cv.use_id(BLEClient),
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -78,7 +78,7 @@ async def register_ble_node(var, config):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
BLE_WRITE_ACTION_SCHEMA = cv.Schema(
 | 
					BLE_WRITE_ACTION_SCHEMA = cv.Schema(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        cv.Required(CONF_ID): cv.use_id(BLEClient),
 | 
					        cv.GenerateID(CONF_ID): cv.use_id(BLEClient),
 | 
				
			||||||
        cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
 | 
					        cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
 | 
				
			||||||
        cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid,
 | 
					        cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid,
 | 
				
			||||||
        cv.Required(CONF_VALUE): cv.templatable(cv.ensure_list(cv.hex_uint8_t)),
 | 
					        cv.Required(CONF_VALUE): cv.templatable(cv.ensure_list(cv.hex_uint8_t)),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <utility>
 | 
					#include <utility>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "esphome/core/automation.h"
 | 
					#include "esphome/core/automation.h"
 | 
				
			||||||
#include "esphome/components/ble_client/ble_client.h"
 | 
					#include "esphome/components/ble_client/ble_client.h"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,12 +7,13 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <array>
 | 
					 | 
				
			||||||
#include <esp_gap_ble_api.h>
 | 
					 | 
				
			||||||
#include <esp_gattc_api.h>
 | 
					 | 
				
			||||||
#include <esp_bt_defs.h>
 | 
					#include <esp_bt_defs.h>
 | 
				
			||||||
 | 
					#include <esp_gap_ble_api.h>
 | 
				
			||||||
#include <esp_gatt_common_api.h>
 | 
					#include <esp_gatt_common_api.h>
 | 
				
			||||||
 | 
					#include <esp_gattc_api.h>
 | 
				
			||||||
 | 
					#include <array>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace ble_client {
 | 
					namespace ble_client {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@
 | 
				
			|||||||
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
 | 
					#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
 | 
				
			||||||
#include "esphome/components/sensor/sensor.h"
 | 
					#include "esphome/components/sensor/sensor.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
#include <esp_gattc_api.h>
 | 
					#include <esp_gattc_api.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,11 +2,13 @@ from esphome.components import esp32_ble_tracker, esp32_ble_client
 | 
				
			|||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
from esphome.const import CONF_ACTIVE, CONF_ID
 | 
					from esphome.const import CONF_ACTIVE, CONF_ID
 | 
				
			||||||
 | 
					from esphome.components.esp32 import add_idf_sdkconfig_option
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AUTO_LOAD = ["esp32_ble_client", "esp32_ble_tracker"]
 | 
					AUTO_LOAD = ["esp32_ble_client", "esp32_ble_tracker"]
 | 
				
			||||||
DEPENDENCIES = ["api", "esp32"]
 | 
					DEPENDENCIES = ["api", "esp32"]
 | 
				
			||||||
CODEOWNERS = ["@jesserockz"]
 | 
					CODEOWNERS = ["@jesserockz"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONF_CACHE_SERVICES = "cache_services"
 | 
				
			||||||
CONF_CONNECTIONS = "connections"
 | 
					CONF_CONNECTIONS = "connections"
 | 
				
			||||||
MAX_CONNECTIONS = 3
 | 
					MAX_CONNECTIONS = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -47,6 +49,9 @@ CONFIG_SCHEMA = cv.All(
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            cv.GenerateID(): cv.declare_id(BluetoothProxy),
 | 
					            cv.GenerateID(): cv.declare_id(BluetoothProxy),
 | 
				
			||||||
            cv.Optional(CONF_ACTIVE, default=False): cv.boolean,
 | 
					            cv.Optional(CONF_ACTIVE, default=False): cv.boolean,
 | 
				
			||||||
 | 
					            cv.SplitDefault(CONF_CACHE_SERVICES, esp32_idf=True): cv.All(
 | 
				
			||||||
 | 
					                cv.only_with_esp_idf, cv.boolean
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
            cv.Optional(CONF_CONNECTIONS): cv.All(
 | 
					            cv.Optional(CONF_CONNECTIONS): cv.All(
 | 
				
			||||||
                cv.ensure_list(CONNECTION_SCHEMA),
 | 
					                cv.ensure_list(CONNECTION_SCHEMA),
 | 
				
			||||||
                cv.Length(min=1, max=MAX_CONNECTIONS),
 | 
					                cv.Length(min=1, max=MAX_CONNECTIONS),
 | 
				
			||||||
@@ -72,4 +77,7 @@ async def to_code(config):
 | 
				
			|||||||
        cg.add(var.register_connection(connection_var))
 | 
					        cg.add(var.register_connection(connection_var))
 | 
				
			||||||
        await esp32_ble_tracker.register_client(connection_var, connection_conf)
 | 
					        await esp32_ble_tracker.register_client(connection_var, connection_conf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if config.get(CONF_CACHE_SERVICES):
 | 
				
			||||||
 | 
					        add_idf_sdkconfig_option("CONFIG_BT_GATTC_CACHE_NVS_FLASH", True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cg.add_define("USE_BLUETOOTH_PROXY")
 | 
					    cg.add_define("USE_BLUETOOTH_PROXY")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,12 +34,39 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
 | 
				
			|||||||
        this->set_address(0);
 | 
					        this->set_address(0);
 | 
				
			||||||
        api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
 | 
					        api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
 | 
				
			||||||
                                                                this->proxy_->get_bluetooth_connections_limit());
 | 
					                                                                this->proxy_->get_bluetooth_connections_limit());
 | 
				
			||||||
 | 
					      } else if (this->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE) {
 | 
				
			||||||
 | 
					        api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_);
 | 
				
			||||||
 | 
					        api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
 | 
				
			||||||
 | 
					                                                                this->proxy_->get_bluetooth_connections_limit());
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      this->seen_mtu_or_services_ = false;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case ESP_GATTC_CFG_MTU_EVT: {
 | 
				
			||||||
 | 
					      if (param->cfg_mtu.conn_id != this->conn_id_)
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      if (!this->seen_mtu_or_services_) {
 | 
				
			||||||
 | 
					        // We don't know if we will get the MTU or the services first, so
 | 
				
			||||||
 | 
					        // only send the device connection true if we have already received
 | 
				
			||||||
 | 
					        // the services.
 | 
				
			||||||
 | 
					        this->seen_mtu_or_services_ = true;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_);
 | 
				
			||||||
 | 
					      api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
 | 
				
			||||||
 | 
					                                                              this->proxy_->get_bluetooth_connections_limit());
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case ESP_GATTC_SEARCH_CMPL_EVT: {
 | 
					    case ESP_GATTC_SEARCH_CMPL_EVT: {
 | 
				
			||||||
      if (param->search_cmpl.conn_id != this->conn_id_)
 | 
					      if (param->search_cmpl.conn_id != this->conn_id_)
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					      if (!this->seen_mtu_or_services_) {
 | 
				
			||||||
 | 
					        // We don't know if we will get the MTU or the services first, so
 | 
				
			||||||
 | 
					        // only send the device connection true if we have already received
 | 
				
			||||||
 | 
					        // the mtu.
 | 
				
			||||||
 | 
					        this->seen_mtu_or_services_ = true;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_);
 | 
					      api::global_api_server->send_bluetooth_device_connection(this->address_, true, this->mtu_);
 | 
				
			||||||
      api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
 | 
					      api::global_api_server->send_bluetooth_connections_free(this->proxy_->get_bluetooth_connections_free(),
 | 
				
			||||||
                                                              this->proxy_->get_bluetooth_connections_limit());
 | 
					                                                              this->proxy_->get_bluetooth_connections_limit());
 | 
				
			||||||
@@ -82,8 +109,6 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
 | 
				
			|||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case ESP_GATTC_UNREG_FOR_NOTIFY_EVT: {
 | 
					    case ESP_GATTC_UNREG_FOR_NOTIFY_EVT: {
 | 
				
			||||||
      if (this->get_characteristic(param->unreg_for_notify.handle) == nullptr)  // No conn_id in this event
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      if (param->unreg_for_notify.status != ESP_GATT_OK) {
 | 
					      if (param->unreg_for_notify.status != ESP_GATT_OK) {
 | 
				
			||||||
        ESP_LOGW(TAG, "[%d] [%s] Error unregistering notifications for handle 0x%2X, status=%d",
 | 
					        ESP_LOGW(TAG, "[%d] [%s] Error unregistering notifications for handle 0x%2X, status=%d",
 | 
				
			||||||
                 this->connection_index_, this->address_str_.c_str(), param->unreg_for_notify.handle,
 | 
					                 this->connection_index_, this->address_str_.c_str(), param->unreg_for_notify.handle,
 | 
				
			||||||
@@ -99,8 +124,6 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
 | 
				
			|||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
 | 
					    case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
 | 
				
			||||||
      if (this->get_characteristic(param->reg_for_notify.handle) == nullptr)  // No conn_id in this event
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      if (param->reg_for_notify.status != ESP_GATT_OK) {
 | 
					      if (param->reg_for_notify.status != ESP_GATT_OK) {
 | 
				
			||||||
        ESP_LOGW(TAG, "[%d] [%s] Error registering notifications for handle 0x%2X, status=%d", this->connection_index_,
 | 
					        ESP_LOGW(TAG, "[%d] [%s] Error registering notifications for handle 0x%2X, status=%d", this->connection_index_,
 | 
				
			||||||
                 this->address_str_.c_str(), param->reg_for_notify.handle, param->reg_for_notify.status);
 | 
					                 this->address_str_.c_str(), param->reg_for_notify.handle, param->reg_for_notify.status);
 | 
				
			||||||
@@ -141,18 +164,11 @@ esp_err_t BluetoothConnection::read_characteristic(uint16_t handle) {
 | 
				
			|||||||
             this->address_str_.c_str());
 | 
					             this->address_str_.c_str());
 | 
				
			||||||
    return ESP_GATT_NOT_CONNECTED;
 | 
					    return ESP_GATT_NOT_CONNECTED;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  auto *characteristic = this->get_characteristic(handle);
 | 
					 | 
				
			||||||
  if (characteristic == nullptr) {
 | 
					 | 
				
			||||||
    ESP_LOGW(TAG, "[%d] [%s] Cannot read GATT characteristic, not found.", this->connection_index_,
 | 
					 | 
				
			||||||
             this->address_str_.c_str());
 | 
					 | 
				
			||||||
    return ESP_GATT_INVALID_HANDLE;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ESP_LOGV(TAG, "[%d] [%s] Reading GATT characteristic %s", this->connection_index_, this->address_str_.c_str(),
 | 
					  ESP_LOGV(TAG, "[%d] [%s] Reading GATT characteristic handle %d", this->connection_index_, this->address_str_.c_str(),
 | 
				
			||||||
           characteristic->uuid.to_string().c_str());
 | 
					           handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  esp_err_t err =
 | 
					  esp_err_t err = esp_ble_gattc_read_char(this->gattc_if_, this->conn_id_, handle, ESP_GATT_AUTH_REQ_NONE);
 | 
				
			||||||
      esp_ble_gattc_read_char(this->gattc_if_, this->conn_id_, characteristic->handle, ESP_GATT_AUTH_REQ_NONE);
 | 
					 | 
				
			||||||
  if (err != ERR_OK) {
 | 
					  if (err != ERR_OK) {
 | 
				
			||||||
    ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_read_char error, err=%d", this->connection_index_,
 | 
					    ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_read_char error, err=%d", this->connection_index_,
 | 
				
			||||||
             this->address_str_.c_str(), err);
 | 
					             this->address_str_.c_str(), err);
 | 
				
			||||||
@@ -167,18 +183,12 @@ esp_err_t BluetoothConnection::write_characteristic(uint16_t handle, const std::
 | 
				
			|||||||
             this->address_str_.c_str());
 | 
					             this->address_str_.c_str());
 | 
				
			||||||
    return ESP_GATT_NOT_CONNECTED;
 | 
					    return ESP_GATT_NOT_CONNECTED;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  auto *characteristic = this->get_characteristic(handle);
 | 
					  ESP_LOGV(TAG, "[%d] [%s] Writing GATT characteristic handle %d", this->connection_index_, this->address_str_.c_str(),
 | 
				
			||||||
  if (characteristic == nullptr) {
 | 
					           handle);
 | 
				
			||||||
    ESP_LOGW(TAG, "[%d] [%s] Cannot write GATT characteristic, not found.", this->connection_index_,
 | 
					 | 
				
			||||||
             this->address_str_.c_str());
 | 
					 | 
				
			||||||
    return ESP_GATT_INVALID_HANDLE;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ESP_LOGV(TAG, "[%d] [%s] Writing GATT characteristic %s", this->connection_index_, this->address_str_.c_str(),
 | 
					  esp_err_t err =
 | 
				
			||||||
           characteristic->uuid.to_string().c_str());
 | 
					      esp_ble_gattc_write_char(this->gattc_if_, this->conn_id_, handle, data.size(), (uint8_t *) data.data(),
 | 
				
			||||||
 | 
					                               response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
				
			||||||
  auto err = characteristic->write_value((uint8_t *) data.data(), data.size(),
 | 
					 | 
				
			||||||
                                         response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP);
 | 
					 | 
				
			||||||
  if (err != ERR_OK) {
 | 
					  if (err != ERR_OK) {
 | 
				
			||||||
    ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_write_char error, err=%d", this->connection_index_,
 | 
					    ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_write_char error, err=%d", this->connection_index_,
 | 
				
			||||||
             this->address_str_.c_str(), err);
 | 
					             this->address_str_.c_str(), err);
 | 
				
			||||||
@@ -193,18 +203,10 @@ esp_err_t BluetoothConnection::read_descriptor(uint16_t handle) {
 | 
				
			|||||||
             this->address_str_.c_str());
 | 
					             this->address_str_.c_str());
 | 
				
			||||||
    return ESP_GATT_NOT_CONNECTED;
 | 
					    return ESP_GATT_NOT_CONNECTED;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  auto *descriptor = this->get_descriptor(handle);
 | 
					  ESP_LOGV(TAG, "[%d] [%s] Reading GATT descriptor handle %d", this->connection_index_, this->address_str_.c_str(),
 | 
				
			||||||
  if (descriptor == nullptr) {
 | 
					           handle);
 | 
				
			||||||
    ESP_LOGW(TAG, "[%d] [%s] Cannot read GATT descriptor, not found.", this->connection_index_,
 | 
					 | 
				
			||||||
             this->address_str_.c_str());
 | 
					 | 
				
			||||||
    return ESP_GATT_INVALID_HANDLE;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ESP_LOGV(TAG, "[%d] [%s] Reading GATT descriptor %s", this->connection_index_, this->address_str_.c_str(),
 | 
					  esp_err_t err = esp_ble_gattc_read_char_descr(this->gattc_if_, this->conn_id_, handle, ESP_GATT_AUTH_REQ_NONE);
 | 
				
			||||||
           descriptor->uuid.to_string().c_str());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  esp_err_t err =
 | 
					 | 
				
			||||||
      esp_ble_gattc_read_char_descr(this->gattc_if_, this->conn_id_, descriptor->handle, ESP_GATT_AUTH_REQ_NONE);
 | 
					 | 
				
			||||||
  if (err != ERR_OK) {
 | 
					  if (err != ERR_OK) {
 | 
				
			||||||
    ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_read_char_descr error, err=%d", this->connection_index_,
 | 
					    ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_read_char_descr error, err=%d", this->connection_index_,
 | 
				
			||||||
             this->address_str_.c_str(), err);
 | 
					             this->address_str_.c_str(), err);
 | 
				
			||||||
@@ -213,25 +215,18 @@ esp_err_t BluetoothConnection::read_descriptor(uint16_t handle) {
 | 
				
			|||||||
  return ESP_OK;
 | 
					  return ESP_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
esp_err_t BluetoothConnection::write_descriptor(uint16_t handle, const std::string &data) {
 | 
					esp_err_t BluetoothConnection::write_descriptor(uint16_t handle, const std::string &data, bool response) {
 | 
				
			||||||
  if (!this->connected()) {
 | 
					  if (!this->connected()) {
 | 
				
			||||||
    ESP_LOGW(TAG, "[%d] [%s] Cannot write GATT descriptor, not connected.", this->connection_index_,
 | 
					    ESP_LOGW(TAG, "[%d] [%s] Cannot write GATT descriptor, not connected.", this->connection_index_,
 | 
				
			||||||
             this->address_str_.c_str());
 | 
					             this->address_str_.c_str());
 | 
				
			||||||
    return ESP_GATT_NOT_CONNECTED;
 | 
					    return ESP_GATT_NOT_CONNECTED;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  auto *descriptor = this->get_descriptor(handle);
 | 
					  ESP_LOGV(TAG, "[%d] [%s] Writing GATT descriptor handle %d", this->connection_index_, this->address_str_.c_str(),
 | 
				
			||||||
  if (descriptor == nullptr) {
 | 
					           handle);
 | 
				
			||||||
    ESP_LOGW(TAG, "[%d] [%s] Cannot write GATT descriptor, not found.", this->connection_index_,
 | 
					 | 
				
			||||||
             this->address_str_.c_str());
 | 
					 | 
				
			||||||
    return ESP_GATT_INVALID_HANDLE;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ESP_LOGV(TAG, "[%d] [%s] Writing GATT descriptor %s", this->connection_index_, this->address_str_.c_str(),
 | 
					  esp_err_t err = esp_ble_gattc_write_char_descr(
 | 
				
			||||||
           descriptor->uuid.to_string().c_str());
 | 
					      this->gattc_if_, this->conn_id_, handle, data.size(), (uint8_t *) data.data(),
 | 
				
			||||||
 | 
					      response ? ESP_GATT_WRITE_TYPE_RSP : ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
				
			||||||
  auto err =
 | 
					 | 
				
			||||||
      esp_ble_gattc_write_char_descr(this->gattc_if_, this->conn_id_, descriptor->handle, data.size(),
 | 
					 | 
				
			||||||
                                     (uint8_t *) data.data(), ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
					 | 
				
			||||||
  if (err != ERR_OK) {
 | 
					  if (err != ERR_OK) {
 | 
				
			||||||
    ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_write_char_descr error, err=%d", this->connection_index_,
 | 
					    ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_write_char_descr error, err=%d", this->connection_index_,
 | 
				
			||||||
             this->address_str_.c_str(), err);
 | 
					             this->address_str_.c_str(), err);
 | 
				
			||||||
@@ -246,26 +241,20 @@ esp_err_t BluetoothConnection::notify_characteristic(uint16_t handle, bool enabl
 | 
				
			|||||||
             this->address_str_.c_str());
 | 
					             this->address_str_.c_str());
 | 
				
			||||||
    return ESP_GATT_NOT_CONNECTED;
 | 
					    return ESP_GATT_NOT_CONNECTED;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  auto *characteristic = this->get_characteristic(handle);
 | 
					 | 
				
			||||||
  if (characteristic == nullptr) {
 | 
					 | 
				
			||||||
    ESP_LOGW(TAG, "[%d] [%s] Cannot notify GATT characteristic, not found.", this->connection_index_,
 | 
					 | 
				
			||||||
             this->address_str_.c_str());
 | 
					 | 
				
			||||||
    return ESP_GATT_INVALID_HANDLE;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (enable) {
 | 
					  if (enable) {
 | 
				
			||||||
    ESP_LOGV(TAG, "[%d] [%s] Registering for GATT characteristic notifications %s", this->connection_index_,
 | 
					    ESP_LOGV(TAG, "[%d] [%s] Registering for GATT characteristic notifications handle %d", this->connection_index_,
 | 
				
			||||||
             this->address_str_.c_str(), characteristic->uuid.to_string().c_str());
 | 
					             this->address_str_.c_str(), handle);
 | 
				
			||||||
    esp_err_t err = esp_ble_gattc_register_for_notify(this->gattc_if_, this->remote_bda_, characteristic->handle);
 | 
					    esp_err_t err = esp_ble_gattc_register_for_notify(this->gattc_if_, this->remote_bda_, handle);
 | 
				
			||||||
    if (err != ESP_OK) {
 | 
					    if (err != ESP_OK) {
 | 
				
			||||||
      ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_register_for_notify failed, err=%d", this->connection_index_,
 | 
					      ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_register_for_notify failed, err=%d", this->connection_index_,
 | 
				
			||||||
               this->address_str_.c_str(), err);
 | 
					               this->address_str_.c_str(), err);
 | 
				
			||||||
      return err;
 | 
					      return err;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    ESP_LOGV(TAG, "[%d] [%s] Unregistering for GATT characteristic notifications %s", this->connection_index_,
 | 
					    ESP_LOGV(TAG, "[%d] [%s] Unregistering for GATT characteristic notifications handle %d", this->connection_index_,
 | 
				
			||||||
             this->address_str_.c_str(), characteristic->uuid.to_string().c_str());
 | 
					             this->address_str_.c_str(), handle);
 | 
				
			||||||
    esp_err_t err = esp_ble_gattc_unregister_for_notify(this->gattc_if_, this->remote_bda_, characteristic->handle);
 | 
					    esp_err_t err = esp_ble_gattc_unregister_for_notify(this->gattc_if_, this->remote_bda_, handle);
 | 
				
			||||||
    if (err != ESP_OK) {
 | 
					    if (err != ESP_OK) {
 | 
				
			||||||
      ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_unregister_for_notify failed, err=%d", this->connection_index_,
 | 
					      ESP_LOGW(TAG, "[%d] [%s] esp_ble_gattc_unregister_for_notify failed, err=%d", this->connection_index_,
 | 
				
			||||||
               this->address_str_.c_str(), err);
 | 
					               this->address_str_.c_str(), err);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,14 +17,15 @@ class BluetoothConnection : public esp32_ble_client::BLEClientBase {
 | 
				
			|||||||
  esp_err_t read_characteristic(uint16_t handle);
 | 
					  esp_err_t read_characteristic(uint16_t handle);
 | 
				
			||||||
  esp_err_t write_characteristic(uint16_t handle, const std::string &data, bool response);
 | 
					  esp_err_t write_characteristic(uint16_t handle, const std::string &data, bool response);
 | 
				
			||||||
  esp_err_t read_descriptor(uint16_t handle);
 | 
					  esp_err_t read_descriptor(uint16_t handle);
 | 
				
			||||||
  esp_err_t write_descriptor(uint16_t handle, const std::string &data);
 | 
					  esp_err_t write_descriptor(uint16_t handle, const std::string &data, bool response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  esp_err_t notify_characteristic(uint16_t handle, bool enable);
 | 
					  esp_err_t notify_characteristic(uint16_t handle, bool enable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
  friend class BluetoothProxy;
 | 
					  friend class BluetoothProxy;
 | 
				
			||||||
 | 
					  bool seen_mtu_or_services_{false};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int16_t send_service_{-1};
 | 
					  int16_t send_service_{-2};
 | 
				
			||||||
  BluetoothProxy *proxy_;
 | 
					  BluetoothProxy *proxy_;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,19 @@ namespace esphome {
 | 
				
			|||||||
namespace bluetooth_proxy {
 | 
					namespace bluetooth_proxy {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *const TAG = "bluetooth_proxy";
 | 
					static const char *const TAG = "bluetooth_proxy";
 | 
				
			||||||
 | 
					static const int DONE_SENDING_SERVICES = -2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<uint64_t> get_128bit_uuid_vec(esp_bt_uuid_t uuid_source) {
 | 
				
			||||||
 | 
					  esp_bt_uuid_t uuid = espbt::ESPBTUUID::from_uuid(uuid_source).as_128bit().get_uuid();
 | 
				
			||||||
 | 
					  return std::vector<uint64_t>{((uint64_t) uuid.uuid.uuid128[15] << 56) | ((uint64_t) uuid.uuid.uuid128[14] << 48) |
 | 
				
			||||||
 | 
					                                   ((uint64_t) uuid.uuid.uuid128[13] << 40) | ((uint64_t) uuid.uuid.uuid128[12] << 32) |
 | 
				
			||||||
 | 
					                                   ((uint64_t) uuid.uuid.uuid128[11] << 24) | ((uint64_t) uuid.uuid.uuid128[10] << 16) |
 | 
				
			||||||
 | 
					                                   ((uint64_t) uuid.uuid.uuid128[9] << 8) | ((uint64_t) uuid.uuid.uuid128[8]),
 | 
				
			||||||
 | 
					                               ((uint64_t) uuid.uuid.uuid128[7] << 56) | ((uint64_t) uuid.uuid.uuid128[6] << 48) |
 | 
				
			||||||
 | 
					                                   ((uint64_t) uuid.uuid.uuid128[5] << 40) | ((uint64_t) uuid.uuid.uuid128[4] << 32) |
 | 
				
			||||||
 | 
					                                   ((uint64_t) uuid.uuid.uuid128[3] << 24) | ((uint64_t) uuid.uuid.uuid128[2] << 16) |
 | 
				
			||||||
 | 
					                                   ((uint64_t) uuid.uuid.uuid128[1] << 8) | ((uint64_t) uuid.uuid.uuid128[0])};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BluetoothProxy::BluetoothProxy() { global_bluetooth_proxy = this; }
 | 
					BluetoothProxy::BluetoothProxy() { global_bluetooth_proxy = this; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,6 +39,7 @@ bool BluetoothProxy::parse_device(const esp32_ble_tracker::ESPBTDevice &device)
 | 
				
			|||||||
void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &device) {
 | 
					void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &device) {
 | 
				
			||||||
  api::BluetoothLEAdvertisementResponse resp;
 | 
					  api::BluetoothLEAdvertisementResponse resp;
 | 
				
			||||||
  resp.address = device.address_uint64();
 | 
					  resp.address = device.address_uint64();
 | 
				
			||||||
 | 
					  resp.address_type = device.get_address_type();
 | 
				
			||||||
  if (!device.get_name().empty())
 | 
					  if (!device.get_name().empty())
 | 
				
			||||||
    resp.name = device.get_name();
 | 
					    resp.name = device.get_name();
 | 
				
			||||||
  resp.rssi = device.get_rssi();
 | 
					  resp.rssi = device.get_rssi();
 | 
				
			||||||
@@ -52,6 +66,20 @@ void BluetoothProxy::dump_config() {
 | 
				
			|||||||
  ESP_LOGCONFIG(TAG, "  Active: %s", YESNO(this->active_));
 | 
					  ESP_LOGCONFIG(TAG, "  Active: %s", YESNO(this->active_));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int BluetoothProxy::get_bluetooth_connections_free() {
 | 
				
			||||||
 | 
					  int free = 0;
 | 
				
			||||||
 | 
					  for (auto *connection : this->connections_) {
 | 
				
			||||||
 | 
					    if (connection->address_ == 0) {
 | 
				
			||||||
 | 
					      free++;
 | 
				
			||||||
 | 
					      ESP_LOGV(TAG, "[%d] Free connection", connection->get_connection_index());
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      ESP_LOGV(TAG, "[%d] Used connection by [%s]", connection->get_connection_index(),
 | 
				
			||||||
 | 
					               connection->address_str().c_str());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return free;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void BluetoothProxy::loop() {
 | 
					void BluetoothProxy::loop() {
 | 
				
			||||||
  if (!api::global_api_server->is_connected()) {
 | 
					  if (!api::global_api_server->is_connected()) {
 | 
				
			||||||
    for (auto *connection : this->connections_) {
 | 
					    for (auto *connection : this->connections_) {
 | 
				
			||||||
@@ -62,32 +90,87 @@ void BluetoothProxy::loop() {
 | 
				
			|||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  for (auto *connection : this->connections_) {
 | 
					  for (auto *connection : this->connections_) {
 | 
				
			||||||
    if (connection->send_service_ == connection->services_.size()) {
 | 
					    if (connection->send_service_ == connection->service_count_) {
 | 
				
			||||||
      connection->send_service_ = -1;
 | 
					      connection->send_service_ = DONE_SENDING_SERVICES;
 | 
				
			||||||
      api::global_api_server->send_bluetooth_gatt_services_done(connection->get_address());
 | 
					      api::global_api_server->send_bluetooth_gatt_services_done(connection->get_address());
 | 
				
			||||||
 | 
					      if (connection->connection_type_ == espbt::ConnectionType::V3_WITH_CACHE ||
 | 
				
			||||||
 | 
					          connection->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
 | 
				
			||||||
 | 
					        connection->release_services();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    } else if (connection->send_service_ >= 0) {
 | 
					    } else if (connection->send_service_ >= 0) {
 | 
				
			||||||
      auto &service = connection->services_[connection->send_service_];
 | 
					      esp_gattc_service_elem_t service_result;
 | 
				
			||||||
 | 
					      uint16_t service_count = 1;
 | 
				
			||||||
 | 
					      esp_gatt_status_t service_status =
 | 
				
			||||||
 | 
					          esp_ble_gattc_get_service(connection->get_gattc_if(), connection->get_conn_id(), nullptr, &service_result,
 | 
				
			||||||
 | 
					                                    &service_count, connection->send_service_);
 | 
				
			||||||
 | 
					      connection->send_service_++;
 | 
				
			||||||
 | 
					      if (service_status != ESP_GATT_OK) {
 | 
				
			||||||
 | 
					        ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_service error at offset=%d, status=%d",
 | 
				
			||||||
 | 
					                 connection->get_connection_index(), connection->address_str().c_str(), connection->send_service_ - 1,
 | 
				
			||||||
 | 
					                 service_status);
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (service_count == 0) {
 | 
				
			||||||
 | 
					        ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_service missing, service_count=%d",
 | 
				
			||||||
 | 
					                 connection->get_connection_index(), connection->address_str().c_str(), service_count);
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      api::BluetoothGATTGetServicesResponse resp;
 | 
					      api::BluetoothGATTGetServicesResponse resp;
 | 
				
			||||||
      resp.address = connection->get_address();
 | 
					      resp.address = connection->get_address();
 | 
				
			||||||
      api::BluetoothGATTService service_resp;
 | 
					      api::BluetoothGATTService service_resp;
 | 
				
			||||||
      service_resp.uuid = {service->uuid.get_128bit_high(), service->uuid.get_128bit_low()};
 | 
					      service_resp.uuid = get_128bit_uuid_vec(service_result.uuid);
 | 
				
			||||||
      service_resp.handle = service->start_handle;
 | 
					      service_resp.handle = service_result.start_handle;
 | 
				
			||||||
      for (auto &characteristic : service->characteristics) {
 | 
					      uint16_t char_offset = 0;
 | 
				
			||||||
 | 
					      esp_gattc_char_elem_t char_result;
 | 
				
			||||||
 | 
					      while (true) {  // characteristics
 | 
				
			||||||
 | 
					        uint16_t char_count = 1;
 | 
				
			||||||
 | 
					        esp_gatt_status_t char_status = esp_ble_gattc_get_all_char(
 | 
				
			||||||
 | 
					            connection->get_gattc_if(), connection->get_conn_id(), service_result.start_handle,
 | 
				
			||||||
 | 
					            service_result.end_handle, &char_result, &char_count, char_offset);
 | 
				
			||||||
 | 
					        if (char_status == ESP_GATT_INVALID_OFFSET || char_status == ESP_GATT_NOT_FOUND) {
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (char_status != ESP_GATT_OK) {
 | 
				
			||||||
 | 
					          ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_all_char error, status=%d", connection->get_connection_index(),
 | 
				
			||||||
 | 
					                   connection->address_str().c_str(), char_status);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (char_count == 0) {
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        api::BluetoothGATTCharacteristic characteristic_resp;
 | 
					        api::BluetoothGATTCharacteristic characteristic_resp;
 | 
				
			||||||
        characteristic_resp.uuid = {characteristic->uuid.get_128bit_high(), characteristic->uuid.get_128bit_low()};
 | 
					        characteristic_resp.uuid = get_128bit_uuid_vec(char_result.uuid);
 | 
				
			||||||
        characteristic_resp.handle = characteristic->handle;
 | 
					        characteristic_resp.handle = char_result.char_handle;
 | 
				
			||||||
        characteristic_resp.properties = characteristic->properties;
 | 
					        characteristic_resp.properties = char_result.properties;
 | 
				
			||||||
        for (auto &descriptor : characteristic->descriptors) {
 | 
					        char_offset++;
 | 
				
			||||||
 | 
					        uint16_t desc_offset = 0;
 | 
				
			||||||
 | 
					        esp_gattc_descr_elem_t desc_result;
 | 
				
			||||||
 | 
					        while (true) {  // descriptors
 | 
				
			||||||
 | 
					          uint16_t desc_count = 1;
 | 
				
			||||||
 | 
					          esp_gatt_status_t desc_status =
 | 
				
			||||||
 | 
					              esp_ble_gattc_get_all_descr(connection->get_gattc_if(), connection->get_conn_id(),
 | 
				
			||||||
 | 
					                                          char_result.char_handle, &desc_result, &desc_count, desc_offset);
 | 
				
			||||||
 | 
					          if (desc_status == ESP_GATT_INVALID_OFFSET || desc_status == ESP_GATT_NOT_FOUND) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if (desc_status != ESP_GATT_OK) {
 | 
				
			||||||
 | 
					            ESP_LOGE(TAG, "[%d] [%s] esp_ble_gattc_get_all_descr error, status=%d", connection->get_connection_index(),
 | 
				
			||||||
 | 
					                     connection->address_str().c_str(), desc_status);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if (desc_count == 0) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
          api::BluetoothGATTDescriptor descriptor_resp;
 | 
					          api::BluetoothGATTDescriptor descriptor_resp;
 | 
				
			||||||
          descriptor_resp.uuid = {descriptor->uuid.get_128bit_high(), descriptor->uuid.get_128bit_low()};
 | 
					          descriptor_resp.uuid = get_128bit_uuid_vec(desc_result.uuid);
 | 
				
			||||||
          descriptor_resp.handle = descriptor->handle;
 | 
					          descriptor_resp.handle = desc_result.handle;
 | 
				
			||||||
          characteristic_resp.descriptors.push_back(std::move(descriptor_resp));
 | 
					          characteristic_resp.descriptors.push_back(std::move(descriptor_resp));
 | 
				
			||||||
 | 
					          desc_offset++;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        service_resp.characteristics.push_back(std::move(characteristic_resp));
 | 
					        service_resp.characteristics.push_back(std::move(characteristic_resp));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      resp.services.push_back(std::move(service_resp));
 | 
					      resp.services.push_back(std::move(service_resp));
 | 
				
			||||||
      api::global_api_server->send_bluetooth_gatt_services(resp);
 | 
					      api::global_api_server->send_bluetooth_gatt_services(resp);
 | 
				
			||||||
      connection->send_service_++;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -103,7 +186,13 @@ BluetoothConnection *BluetoothProxy::get_connection_(uint64_t address, bool rese
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  for (auto *connection : this->connections_) {
 | 
					  for (auto *connection : this->connections_) {
 | 
				
			||||||
    if (connection->get_address() == 0) {
 | 
					    if (connection->get_address() == 0) {
 | 
				
			||||||
 | 
					      connection->send_service_ = DONE_SENDING_SERVICES;
 | 
				
			||||||
      connection->set_address(address);
 | 
					      connection->set_address(address);
 | 
				
			||||||
 | 
					      // All connections must start at INIT
 | 
				
			||||||
 | 
					      // We only set the state if we allocate the connection
 | 
				
			||||||
 | 
					      // to avoid a race where multiple connection attempts
 | 
				
			||||||
 | 
					      // are made.
 | 
				
			||||||
 | 
					      connection->set_state(espbt::ClientState::INIT);
 | 
				
			||||||
      return connection;
 | 
					      return connection;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -113,6 +202,8 @@ BluetoothConnection *BluetoothProxy::get_connection_(uint64_t address, bool rese
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest &msg) {
 | 
					void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest &msg) {
 | 
				
			||||||
  switch (msg.request_type) {
 | 
					  switch (msg.request_type) {
 | 
				
			||||||
 | 
					    case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE:
 | 
				
			||||||
 | 
					    case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE:
 | 
				
			||||||
    case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT: {
 | 
					    case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT: {
 | 
				
			||||||
      auto *connection = this->get_connection_(msg.address, true);
 | 
					      auto *connection = this->get_connection_(msg.address, true);
 | 
				
			||||||
      if (connection == nullptr) {
 | 
					      if (connection == nullptr) {
 | 
				
			||||||
@@ -120,9 +211,63 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest
 | 
				
			|||||||
        api::global_api_server->send_bluetooth_device_connection(msg.address, false);
 | 
					        api::global_api_server->send_bluetooth_device_connection(msg.address, false);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      ESP_LOGV(TAG, "[%d] [%s] Searching to connect", connection->get_connection_index(),
 | 
					      if (connection->state() == espbt::ClientState::CONNECTED ||
 | 
				
			||||||
               connection->address_str().c_str());
 | 
					          connection->state() == espbt::ClientState::ESTABLISHED) {
 | 
				
			||||||
      connection->set_state(espbt::ClientState::SEARCHING);
 | 
					        ESP_LOGW(TAG, "[%d] [%s] Connection already established", connection->get_connection_index(),
 | 
				
			||||||
 | 
					                 connection->address_str().c_str());
 | 
				
			||||||
 | 
					        api::global_api_server->send_bluetooth_device_connection(msg.address, true);
 | 
				
			||||||
 | 
					        api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(),
 | 
				
			||||||
 | 
					                                                                this->get_bluetooth_connections_limit());
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      } else if (connection->state() == espbt::ClientState::SEARCHING) {
 | 
				
			||||||
 | 
					        ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, already searching for device",
 | 
				
			||||||
 | 
					                 connection->get_connection_index(), connection->address_str().c_str());
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      } else if (connection->state() == espbt::ClientState::DISCOVERED) {
 | 
				
			||||||
 | 
					        ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, device already discovered",
 | 
				
			||||||
 | 
					                 connection->get_connection_index(), connection->address_str().c_str());
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      } else if (connection->state() == espbt::ClientState::READY_TO_CONNECT) {
 | 
				
			||||||
 | 
					        ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, waiting in line to connect",
 | 
				
			||||||
 | 
					                 connection->get_connection_index(), connection->address_str().c_str());
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      } else if (connection->state() == espbt::ClientState::CONNECTING) {
 | 
				
			||||||
 | 
					        ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, already connecting", connection->get_connection_index(),
 | 
				
			||||||
 | 
					                 connection->address_str().c_str());
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      } else if (connection->state() == espbt::ClientState::DISCONNECTING) {
 | 
				
			||||||
 | 
					        ESP_LOGW(TAG, "[%d] [%s] Connection request ignored, device is disconnecting",
 | 
				
			||||||
 | 
					                 connection->get_connection_index(), connection->address_str().c_str());
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      } else if (connection->state() != espbt::ClientState::INIT) {
 | 
				
			||||||
 | 
					        ESP_LOGW(TAG, "[%d] [%s] Connection already in progress", connection->get_connection_index(),
 | 
				
			||||||
 | 
					                 connection->address_str().c_str());
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (msg.request_type == api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE) {
 | 
				
			||||||
 | 
					        connection->set_connection_type(espbt::ConnectionType::V3_WITH_CACHE);
 | 
				
			||||||
 | 
					        ESP_LOGI(TAG, "[%d] [%s] Connecting v3 with cache", connection->get_connection_index(),
 | 
				
			||||||
 | 
					                 connection->address_str().c_str());
 | 
				
			||||||
 | 
					      } else if (msg.request_type == api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE) {
 | 
				
			||||||
 | 
					        connection->set_connection_type(espbt::ConnectionType::V3_WITHOUT_CACHE);
 | 
				
			||||||
 | 
					        ESP_LOGI(TAG, "[%d] [%s] Connecting v3 without cache", connection->get_connection_index(),
 | 
				
			||||||
 | 
					                 connection->address_str().c_str());
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        connection->set_connection_type(espbt::ConnectionType::V1);
 | 
				
			||||||
 | 
					        ESP_LOGI(TAG, "[%d] [%s] Connecting v1", connection->get_connection_index(), connection->address_str().c_str());
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (msg.has_address_type) {
 | 
				
			||||||
 | 
					        connection->remote_bda_[0] = (msg.address >> 40) & 0xFF;
 | 
				
			||||||
 | 
					        connection->remote_bda_[1] = (msg.address >> 32) & 0xFF;
 | 
				
			||||||
 | 
					        connection->remote_bda_[2] = (msg.address >> 24) & 0xFF;
 | 
				
			||||||
 | 
					        connection->remote_bda_[3] = (msg.address >> 16) & 0xFF;
 | 
				
			||||||
 | 
					        connection->remote_bda_[4] = (msg.address >> 8) & 0xFF;
 | 
				
			||||||
 | 
					        connection->remote_bda_[5] = (msg.address >> 0) & 0xFF;
 | 
				
			||||||
 | 
					        connection->set_remote_addr_type(static_cast<esp_ble_addr_type_t>(msg.address_type));
 | 
				
			||||||
 | 
					        connection->set_state(espbt::ClientState::DISCOVERED);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        connection->set_state(espbt::ClientState::SEARCHING);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(),
 | 
					      api::global_api_server->send_bluetooth_connections_free(this->get_bluetooth_connections_free(),
 | 
				
			||||||
                                                              this->get_bluetooth_connections_limit());
 | 
					                                                              this->get_bluetooth_connections_limit());
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
@@ -201,7 +346,7 @@ void BluetoothProxy::bluetooth_gatt_write_descriptor(const api::BluetoothGATTWri
 | 
				
			|||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto err = connection->write_descriptor(msg.handle, msg.data);
 | 
					  auto err = connection->write_descriptor(msg.handle, msg.data, true);
 | 
				
			||||||
  if (err != ESP_OK) {
 | 
					  if (err != ESP_OK) {
 | 
				
			||||||
    api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, err);
 | 
					    api::global_api_server->send_bluetooth_gatt_error(msg.address, msg.handle, err);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -214,12 +359,13 @@ void BluetoothProxy::bluetooth_gatt_send_services(const api::BluetoothGATTGetSer
 | 
				
			|||||||
    api::global_api_server->send_bluetooth_gatt_error(msg.address, 0, ESP_GATT_NOT_CONNECTED);
 | 
					    api::global_api_server->send_bluetooth_gatt_error(msg.address, 0, ESP_GATT_NOT_CONNECTED);
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (connection->services_.empty()) {
 | 
					  if (!connection->service_count_) {
 | 
				
			||||||
    ESP_LOGW(TAG, "[%d] [%s] No GATT services found", connection->connection_index_, connection->address_str().c_str());
 | 
					    ESP_LOGW(TAG, "[%d] [%s] No GATT services found", connection->connection_index_, connection->address_str().c_str());
 | 
				
			||||||
    api::global_api_server->send_bluetooth_gatt_services_done(msg.address);
 | 
					    api::global_api_server->send_bluetooth_gatt_services_done(msg.address);
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (connection->send_service_ == -1)  // Don't start sending services again if we're already sending them
 | 
					  if (connection->send_service_ ==
 | 
				
			||||||
 | 
					      DONE_SENDING_SERVICES)  // Only start sending services if we're not already sending them
 | 
				
			||||||
    connection->send_service_ = 0;
 | 
					    connection->send_service_ = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@
 | 
				
			|||||||
#ifdef USE_ESP32
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <map>
 | 
					#include <map>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "esphome/components/api/api_pb2.h"
 | 
					#include "esphome/components/api/api_pb2.h"
 | 
				
			||||||
#include "esphome/components/esp32_ble_client/ble_client_base.h"
 | 
					#include "esphome/components/esp32_ble_client/ble_client_base.h"
 | 
				
			||||||
@@ -40,15 +41,7 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
 | 
				
			|||||||
  void bluetooth_gatt_send_services(const api::BluetoothGATTGetServicesRequest &msg);
 | 
					  void bluetooth_gatt_send_services(const api::BluetoothGATTGetServicesRequest &msg);
 | 
				
			||||||
  void bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest &msg);
 | 
					  void bluetooth_gatt_notify(const api::BluetoothGATTNotifyRequest &msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int get_bluetooth_connections_free() {
 | 
					  int get_bluetooth_connections_free();
 | 
				
			||||||
    int free = 0;
 | 
					 | 
				
			||||||
    for (auto *connection : this->connections_) {
 | 
					 | 
				
			||||||
      if (connection->address_ == 0) {
 | 
					 | 
				
			||||||
        free++;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return free;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  int get_bluetooth_connections_limit() { return this->connections_.size(); }
 | 
					  int get_bluetooth_connections_limit() { return this->connections_.size(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void set_active(bool active) { this->active_ = active; }
 | 
					  void set_active(bool active) { this->active_ = active; }
 | 
				
			||||||
@@ -59,7 +52,6 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  BluetoothConnection *get_connection_(uint64_t address, bool reserve);
 | 
					  BluetoothConnection *get_connection_(uint64_t address, bool reserve);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int16_t send_service_{-1};
 | 
					 | 
				
			||||||
  bool active_;
 | 
					  bool active_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::vector<BluetoothConnection *> connections_{};
 | 
					  std::vector<BluetoothConnection *> connections_{};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -88,7 +88,10 @@ void BME280Component::setup() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // Mark as not failed before initializing. Some devices will turn off sensors to save on batteries
 | 
					  // Mark as not failed before initializing. Some devices will turn off sensors to save on batteries
 | 
				
			||||||
  // and when they come back on, the COMPONENT_STATE_FAILED bit must be unset on the component.
 | 
					  // and when they come back on, the COMPONENT_STATE_FAILED bit must be unset on the component.
 | 
				
			||||||
  this->component_state_ &= ~COMPONENT_STATE_FAILED;
 | 
					  if ((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED) {
 | 
				
			||||||
 | 
					    this->component_state_ &= ~COMPONENT_STATE_MASK;
 | 
				
			||||||
 | 
					    this->component_state_ |= COMPONENT_STATE_CONSTRUCTION;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!this->read_byte(BME280_REGISTER_CHIPID, &chip_id)) {
 | 
					  if (!this->read_byte(BME280_REGISTER_CHIPID, &chip_id)) {
 | 
				
			||||||
    this->error_code_ = COMMUNICATION_FAILED;
 | 
					    this->error_code_ = COMMUNICATION_FAILED;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
#include "bmp280.h"
 | 
					#include "bmp280.h"
 | 
				
			||||||
 | 
					#include "esphome/core/hal.h"
 | 
				
			||||||
#include "esphome/core/log.h"
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
@@ -11,8 +12,11 @@ static const uint8_t BMP280_REGISTER_CONTROL = 0xF4;
 | 
				
			|||||||
static const uint8_t BMP280_REGISTER_CONFIG = 0xF5;
 | 
					static const uint8_t BMP280_REGISTER_CONFIG = 0xF5;
 | 
				
			||||||
static const uint8_t BMP280_REGISTER_PRESSUREDATA = 0xF7;
 | 
					static const uint8_t BMP280_REGISTER_PRESSUREDATA = 0xF7;
 | 
				
			||||||
static const uint8_t BMP280_REGISTER_TEMPDATA = 0xFA;
 | 
					static const uint8_t BMP280_REGISTER_TEMPDATA = 0xFA;
 | 
				
			||||||
 | 
					static const uint8_t BMP280_REGISTER_RESET = 0xE0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const uint8_t BMP280_MODE_FORCED = 0b01;
 | 
					static const uint8_t BMP280_MODE_FORCED = 0b01;
 | 
				
			||||||
 | 
					static const uint8_t BMP280_SOFT_RESET = 0xB6;
 | 
				
			||||||
 | 
					static const uint8_t BMP280_STATUS_IM_UPDATE = 0b01;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline uint16_t combine_bytes(uint8_t msb, uint8_t lsb) { return ((msb & 0xFF) << 8) | (lsb & 0xFF); }
 | 
					inline uint16_t combine_bytes(uint8_t msb, uint8_t lsb) { return ((msb & 0xFF) << 8) | (lsb & 0xFF); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -66,6 +70,28 @@ void BMP280Component::setup() {
 | 
				
			|||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Send a soft reset.
 | 
				
			||||||
 | 
					  if (!this->write_byte(BMP280_REGISTER_RESET, BMP280_SOFT_RESET)) {
 | 
				
			||||||
 | 
					    this->mark_failed();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Wait until the NVM data has finished loading.
 | 
				
			||||||
 | 
					  uint8_t status;
 | 
				
			||||||
 | 
					  uint8_t retry = 5;
 | 
				
			||||||
 | 
					  do {
 | 
				
			||||||
 | 
					    delay(2);
 | 
				
			||||||
 | 
					    if (!this->read_byte(BMP280_REGISTER_STATUS, &status)) {
 | 
				
			||||||
 | 
					      ESP_LOGW(TAG, "Error reading status register.");
 | 
				
			||||||
 | 
					      this->mark_failed();
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  } while ((status & BMP280_STATUS_IM_UPDATE) && (--retry));
 | 
				
			||||||
 | 
					  if (status & BMP280_STATUS_IM_UPDATE) {
 | 
				
			||||||
 | 
					    ESP_LOGW(TAG, "Timeout loading NVM.");
 | 
				
			||||||
 | 
					    this->mark_failed();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Read calibration
 | 
					  // Read calibration
 | 
				
			||||||
  this->calibration_.t1 = this->read_u16_le_(0x88);
 | 
					  this->calibration_.t1 = this->read_u16_le_(0x88);
 | 
				
			||||||
  this->calibration_.t2 = this->read_s16_le_(0x8A);
 | 
					  this->calibration_.t2 = this->read_s16_le_(0x8A);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										44
									
								
								esphome/components/bp1658cj/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								esphome/components/bp1658cj/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome import pins
 | 
				
			||||||
 | 
					from esphome.const import (
 | 
				
			||||||
 | 
					    CONF_CLOCK_PIN,
 | 
				
			||||||
 | 
					    CONF_DATA_PIN,
 | 
				
			||||||
 | 
					    CONF_ID,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CODEOWNERS = ["@Cossid"]
 | 
				
			||||||
 | 
					MULTI_CONF = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONF_MAX_POWER_COLOR_CHANNELS = "max_power_color_channels"
 | 
				
			||||||
 | 
					CONF_MAX_POWER_WHITE_CHANNELS = "max_power_white_channels"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AUTO_LOAD = ["output"]
 | 
				
			||||||
 | 
					bp1658cj_ns = cg.esphome_ns.namespace("bp1658cj")
 | 
				
			||||||
 | 
					BP1658CJ = bp1658cj_ns.class_("BP1658CJ", cg.Component)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONFIG_SCHEMA = cv.Schema(
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cv.GenerateID(): cv.declare_id(BP1658CJ),
 | 
				
			||||||
 | 
					        cv.Required(CONF_DATA_PIN): pins.gpio_output_pin_schema,
 | 
				
			||||||
 | 
					        cv.Required(CONF_CLOCK_PIN): pins.gpio_output_pin_schema,
 | 
				
			||||||
 | 
					        cv.Optional(CONF_MAX_POWER_COLOR_CHANNELS, default=2): cv.int_range(
 | 
				
			||||||
 | 
					            min=0, max=15
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        cv.Optional(CONF_MAX_POWER_WHITE_CHANNELS, default=4): cv.int_range(
 | 
				
			||||||
 | 
					            min=0, max=15
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					).extend(cv.COMPONENT_SCHEMA)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def to_code(config):
 | 
				
			||||||
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    data = await cg.gpio_pin_expression(config[CONF_DATA_PIN])
 | 
				
			||||||
 | 
					    cg.add(var.set_data_pin(data))
 | 
				
			||||||
 | 
					    clock = await cg.gpio_pin_expression(config[CONF_CLOCK_PIN])
 | 
				
			||||||
 | 
					    cg.add(var.set_clock_pin(clock))
 | 
				
			||||||
 | 
					    cg.add(var.set_max_power_color_channels(config[CONF_MAX_POWER_COLOR_CHANNELS]))
 | 
				
			||||||
 | 
					    cg.add(var.set_max_power_white_channels(config[CONF_MAX_POWER_WHITE_CHANNELS]))
 | 
				
			||||||
							
								
								
									
										110
									
								
								esphome/components/bp1658cj/bp1658cj.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								esphome/components/bp1658cj/bp1658cj.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
				
			|||||||
 | 
					#include "bp1658cj.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace bp1658cj {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "bp1658cj";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const uint8_t BP1658CJ_MODEL_ID = 0x80;
 | 
				
			||||||
 | 
					static const uint8_t BP1658CJ_ADDR_STANDBY = 0x0;
 | 
				
			||||||
 | 
					static const uint8_t BP1658CJ_ADDR_START_3CH = 0x10;
 | 
				
			||||||
 | 
					static const uint8_t BP1658CJ_ADDR_START_2CH = 0x20;
 | 
				
			||||||
 | 
					static const uint8_t BP1658CJ_ADDR_START_5CH = 0x30;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BP1658CJ::setup() {
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "Setting up BP1658CJ Output Component...");
 | 
				
			||||||
 | 
					  this->data_pin_->setup();
 | 
				
			||||||
 | 
					  this->data_pin_->digital_write(false);
 | 
				
			||||||
 | 
					  this->clock_pin_->setup();
 | 
				
			||||||
 | 
					  this->clock_pin_->digital_write(false);
 | 
				
			||||||
 | 
					  this->pwm_amounts_.resize(5, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void BP1658CJ::dump_config() {
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "BP1658CJ:");
 | 
				
			||||||
 | 
					  LOG_PIN("  Data Pin: ", this->data_pin_);
 | 
				
			||||||
 | 
					  LOG_PIN("  Clock Pin: ", this->clock_pin_);
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "  Color Channels Max Power: %u", this->max_power_color_channels_);
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "  White Channels Max Power: %u", this->max_power_white_channels_);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BP1658CJ::loop() {
 | 
				
			||||||
 | 
					  if (!this->update_)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint8_t data[12];
 | 
				
			||||||
 | 
					  if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
 | 
				
			||||||
 | 
					      this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) {
 | 
				
			||||||
 | 
					    // Off / Sleep
 | 
				
			||||||
 | 
					    data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_STANDBY;
 | 
				
			||||||
 | 
					    for (int i = 1; i < 12; i++)
 | 
				
			||||||
 | 
					      data[i] = 0;
 | 
				
			||||||
 | 
					    this->write_buffer_(data, 12);
 | 
				
			||||||
 | 
					  } else if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
 | 
				
			||||||
 | 
					             (this->pwm_amounts_[3] > 0 || this->pwm_amounts_[4] > 0)) {
 | 
				
			||||||
 | 
					    // Only data on white channels
 | 
				
			||||||
 | 
					    data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_START_2CH;
 | 
				
			||||||
 | 
					    data[1] = 0 << 4 | this->max_power_white_channels_;
 | 
				
			||||||
 | 
					    for (int i = 2, j = 0; i < 12; i += 2, j++) {
 | 
				
			||||||
 | 
					      data[i] = this->pwm_amounts_[j] & 0x1F;
 | 
				
			||||||
 | 
					      data[i + 1] = (this->pwm_amounts_[j] >> 5) & 0x1F;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this->write_buffer_(data, 12);
 | 
				
			||||||
 | 
					  } else if ((this->pwm_amounts_[0] > 0 || this->pwm_amounts_[1] > 0 || this->pwm_amounts_[2] > 0) &&
 | 
				
			||||||
 | 
					             this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) {
 | 
				
			||||||
 | 
					    // Only data on RGB channels
 | 
				
			||||||
 | 
					    data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_START_3CH;
 | 
				
			||||||
 | 
					    data[1] = this->max_power_color_channels_ << 4 | 0;
 | 
				
			||||||
 | 
					    for (int i = 2, j = 0; i < 12; i += 2, j++) {
 | 
				
			||||||
 | 
					      data[i] = this->pwm_amounts_[j] & 0x1F;
 | 
				
			||||||
 | 
					      data[i + 1] = (this->pwm_amounts_[j] >> 5) & 0x1F;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this->write_buffer_(data, 12);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    // All channels
 | 
				
			||||||
 | 
					    data[0] = BP1658CJ_MODEL_ID + BP1658CJ_ADDR_START_5CH;
 | 
				
			||||||
 | 
					    data[1] = this->max_power_color_channels_ << 4 | this->max_power_white_channels_;
 | 
				
			||||||
 | 
					    for (int i = 2, j = 0; i < 12; i += 2, j++) {
 | 
				
			||||||
 | 
					      data[i] = this->pwm_amounts_[j] & 0x1F;
 | 
				
			||||||
 | 
					      data[i + 1] = (this->pwm_amounts_[j] >> 5) & 0x1F;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this->write_buffer_(data, 12);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  this->update_ = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BP1658CJ::set_channel_value_(uint8_t channel, uint16_t value) {
 | 
				
			||||||
 | 
					  if (this->pwm_amounts_[channel] != value) {
 | 
				
			||||||
 | 
					    this->update_ = true;
 | 
				
			||||||
 | 
					    this->update_channel_ = channel;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  this->pwm_amounts_[channel] = value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void BP1658CJ::write_bit_(bool value) {
 | 
				
			||||||
 | 
					  this->clock_pin_->digital_write(false);
 | 
				
			||||||
 | 
					  this->data_pin_->digital_write(value);
 | 
				
			||||||
 | 
					  this->clock_pin_->digital_write(true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BP1658CJ::write_byte_(uint8_t data) {
 | 
				
			||||||
 | 
					  for (uint8_t mask = 0x80; mask; mask >>= 1) {
 | 
				
			||||||
 | 
					    this->write_bit_(data & mask);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  this->clock_pin_->digital_write(false);
 | 
				
			||||||
 | 
					  this->data_pin_->digital_write(true);
 | 
				
			||||||
 | 
					  this->clock_pin_->digital_write(true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BP1658CJ::write_buffer_(uint8_t *buffer, uint8_t size) {
 | 
				
			||||||
 | 
					  this->data_pin_->digital_write(false);
 | 
				
			||||||
 | 
					  for (uint32_t i = 0; i < size; i++) {
 | 
				
			||||||
 | 
					    this->write_byte_(buffer[i]);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  this->clock_pin_->digital_write(false);
 | 
				
			||||||
 | 
					  this->clock_pin_->digital_write(true);
 | 
				
			||||||
 | 
					  this->data_pin_->digital_write(true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace bp1658cj
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										64
									
								
								esphome/components/bp1658cj/bp1658cj.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								esphome/components/bp1658cj/bp1658cj.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "esphome/core/component.h"
 | 
				
			||||||
 | 
					#include "esphome/core/hal.h"
 | 
				
			||||||
 | 
					#include "esphome/components/output/float_output.h"
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace bp1658cj {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BP1658CJ : public Component {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  class Channel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void set_data_pin(GPIOPin *data_pin) { data_pin_ = data_pin; }
 | 
				
			||||||
 | 
					  void set_clock_pin(GPIOPin *clock_pin) { clock_pin_ = clock_pin; }
 | 
				
			||||||
 | 
					  void set_max_power_color_channels(uint8_t max_power_color_channels) {
 | 
				
			||||||
 | 
					    max_power_color_channels_ = max_power_color_channels;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  void set_max_power_white_channels(uint8_t max_power_white_channels) {
 | 
				
			||||||
 | 
					    max_power_white_channels_ = max_power_white_channels;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void setup() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void dump_config() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  float get_setup_priority() const override { return setup_priority::HARDWARE; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Send new values if they were updated.
 | 
				
			||||||
 | 
					  void loop() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  class Channel : public output::FloatOutput {
 | 
				
			||||||
 | 
					   public:
 | 
				
			||||||
 | 
					    void set_parent(BP1658CJ *parent) { parent_ = parent; }
 | 
				
			||||||
 | 
					    void set_channel(uint8_t channel) { channel_ = channel; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   protected:
 | 
				
			||||||
 | 
					    void write_state(float state) override {
 | 
				
			||||||
 | 
					      auto amount = static_cast<uint16_t>(state * 0x3FF);
 | 
				
			||||||
 | 
					      this->parent_->set_channel_value_(this->channel_, amount);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    BP1658CJ *parent_;
 | 
				
			||||||
 | 
					    uint8_t channel_;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 protected:
 | 
				
			||||||
 | 
					  void set_channel_value_(uint8_t channel, uint16_t value);
 | 
				
			||||||
 | 
					  void write_bit_(bool value);
 | 
				
			||||||
 | 
					  void write_byte_(uint8_t data);
 | 
				
			||||||
 | 
					  void write_buffer_(uint8_t *buffer, uint8_t size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  GPIOPin *data_pin_;
 | 
				
			||||||
 | 
					  GPIOPin *clock_pin_;
 | 
				
			||||||
 | 
					  uint8_t max_power_color_channels_{4};
 | 
				
			||||||
 | 
					  uint8_t max_power_white_channels_{6};
 | 
				
			||||||
 | 
					  uint8_t update_channel_;
 | 
				
			||||||
 | 
					  std::vector<uint16_t> pwm_amounts_;
 | 
				
			||||||
 | 
					  bool update_{true};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace bp1658cj
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										27
									
								
								esphome/components/bp1658cj/output.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								esphome/components/bp1658cj/output.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome.components import output
 | 
				
			||||||
 | 
					from esphome.const import CONF_CHANNEL, CONF_ID
 | 
				
			||||||
 | 
					from . import BP1658CJ
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEPENDENCIES = ["bp1658cj"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Channel = BP1658CJ.class_("Channel", output.FloatOutput)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONF_BP1658CJ_ID = "bp1658cj_id"
 | 
				
			||||||
 | 
					CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend(
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cv.GenerateID(CONF_BP1658CJ_ID): cv.use_id(BP1658CJ),
 | 
				
			||||||
 | 
					        cv.Required(CONF_ID): cv.declare_id(Channel),
 | 
				
			||||||
 | 
					        cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=65535),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					).extend(cv.COMPONENT_SCHEMA)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def to_code(config):
 | 
				
			||||||
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
 | 
					    await output.register_output(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    parent = await cg.get_variable(config[CONF_BP1658CJ_ID])
 | 
				
			||||||
 | 
					    cg.add(var.set_parent(parent))
 | 
				
			||||||
 | 
					    cg.add(var.set_channel(config[CONF_CHANNEL]))
 | 
				
			||||||
							
								
								
									
										33
									
								
								esphome/components/bp5758d/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								esphome/components/bp5758d/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome import pins
 | 
				
			||||||
 | 
					from esphome.const import (
 | 
				
			||||||
 | 
					    CONF_CLOCK_PIN,
 | 
				
			||||||
 | 
					    CONF_DATA_PIN,
 | 
				
			||||||
 | 
					    CONF_ID,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CODEOWNERS = ["@Cossid"]
 | 
				
			||||||
 | 
					MULTI_CONF = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AUTO_LOAD = ["output"]
 | 
				
			||||||
 | 
					bp5758d_ns = cg.esphome_ns.namespace("bp5758d")
 | 
				
			||||||
 | 
					BP5758D = bp5758d_ns.class_("BP5758D", cg.Component)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONFIG_SCHEMA = cv.Schema(
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cv.GenerateID(): cv.declare_id(BP5758D),
 | 
				
			||||||
 | 
					        cv.Required(CONF_DATA_PIN): pins.gpio_output_pin_schema,
 | 
				
			||||||
 | 
					        cv.Required(CONF_CLOCK_PIN): pins.gpio_output_pin_schema,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					).extend(cv.COMPONENT_SCHEMA)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def to_code(config):
 | 
				
			||||||
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    data = await cg.gpio_pin_expression(config[CONF_DATA_PIN])
 | 
				
			||||||
 | 
					    cg.add(var.set_data_pin(data))
 | 
				
			||||||
 | 
					    clock = await cg.gpio_pin_expression(config[CONF_CLOCK_PIN])
 | 
				
			||||||
 | 
					    cg.add(var.set_clock_pin(clock))
 | 
				
			||||||
							
								
								
									
										147
									
								
								esphome/components/bp5758d/bp5758d.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								esphome/components/bp5758d/bp5758d.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,147 @@
 | 
				
			|||||||
 | 
					#include "bp5758d.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace bp5758d {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "bp5758d";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const uint8_t BP5758D_MODEL_ID = 0b10000000;
 | 
				
			||||||
 | 
					static const uint8_t BP5758D_ADDR_STANDBY = 0b00000000;
 | 
				
			||||||
 | 
					// Note, channel start address seems ambiguous and mis-translated.
 | 
				
			||||||
 | 
					// Documentation states all are "invalid sleep"
 | 
				
			||||||
 | 
					// All 3 values appear to activate all 5 channels.  Using the mapping
 | 
				
			||||||
 | 
					// from BP1658CJ ordering since it won't break anything.
 | 
				
			||||||
 | 
					static const uint8_t BP5758D_ADDR_START_3CH = 0b00010000;
 | 
				
			||||||
 | 
					static const uint8_t BP5758D_ADDR_START_2CH = 0b00100000;
 | 
				
			||||||
 | 
					static const uint8_t BP5758D_ADDR_START_5CH = 0b00110000;
 | 
				
			||||||
 | 
					static const uint8_t BP5758D_ALL_DATA_CHANNEL_ENABLEMENT = 0b00011111;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BP5758D::setup() {
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "Setting up BP5758D Output Component...");
 | 
				
			||||||
 | 
					  this->data_pin_->setup();
 | 
				
			||||||
 | 
					  this->data_pin_->digital_write(false);
 | 
				
			||||||
 | 
					  this->clock_pin_->setup();
 | 
				
			||||||
 | 
					  this->clock_pin_->digital_write(false);
 | 
				
			||||||
 | 
					  this->channel_current_.resize(5, 0);
 | 
				
			||||||
 | 
					  this->pwm_amounts_.resize(5, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void BP5758D::dump_config() {
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "BP5758D:");
 | 
				
			||||||
 | 
					  LOG_PIN("  Data Pin: ", this->data_pin_);
 | 
				
			||||||
 | 
					  LOG_PIN("  Clock Pin: ", this->clock_pin_);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BP5758D::loop() {
 | 
				
			||||||
 | 
					  if (!this->update_)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint8_t data[17];
 | 
				
			||||||
 | 
					  if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
 | 
				
			||||||
 | 
					      this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) {
 | 
				
			||||||
 | 
					    // Off / Sleep
 | 
				
			||||||
 | 
					    data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_STANDBY;
 | 
				
			||||||
 | 
					    for (int i = 1; i < 16; i++)
 | 
				
			||||||
 | 
					      data[i] = 0;
 | 
				
			||||||
 | 
					    this->write_buffer_(data, 17);
 | 
				
			||||||
 | 
					  } else if (this->pwm_amounts_[0] == 0 && this->pwm_amounts_[1] == 0 && this->pwm_amounts_[2] == 0 &&
 | 
				
			||||||
 | 
					             (this->pwm_amounts_[3] > 0 || this->pwm_amounts_[4] > 0)) {
 | 
				
			||||||
 | 
					    // Only data on white channels
 | 
				
			||||||
 | 
					    data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_START_2CH;
 | 
				
			||||||
 | 
					    data[1] = BP5758D_ALL_DATA_CHANNEL_ENABLEMENT;
 | 
				
			||||||
 | 
					    data[2] = 0;
 | 
				
			||||||
 | 
					    data[3] = 0;
 | 
				
			||||||
 | 
					    data[4] = 0;
 | 
				
			||||||
 | 
					    data[5] = this->pwm_amounts_[3] > 0 ? correct_current_level_bits_(this->channel_current_[3]) : 0;
 | 
				
			||||||
 | 
					    data[6] = this->pwm_amounts_[4] > 0 ? correct_current_level_bits_(this->channel_current_[4]) : 0;
 | 
				
			||||||
 | 
					    for (int i = 7, j = 0; i <= 15; i += 2, j++) {
 | 
				
			||||||
 | 
					      data[i] = this->pwm_amounts_[j] & 0x1F;
 | 
				
			||||||
 | 
					      data[i + 1] = (this->pwm_amounts_[j] >> 5) & 0x1F;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this->write_buffer_(data, 17);
 | 
				
			||||||
 | 
					  } else if ((this->pwm_amounts_[0] > 0 || this->pwm_amounts_[1] > 0 || this->pwm_amounts_[2] > 0) &&
 | 
				
			||||||
 | 
					             this->pwm_amounts_[3] == 0 && this->pwm_amounts_[4] == 0) {
 | 
				
			||||||
 | 
					    // Only data on RGB channels
 | 
				
			||||||
 | 
					    data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_START_3CH;
 | 
				
			||||||
 | 
					    data[1] = BP5758D_ALL_DATA_CHANNEL_ENABLEMENT;
 | 
				
			||||||
 | 
					    data[2] = this->pwm_amounts_[0] > 0 ? correct_current_level_bits_(this->channel_current_[0]) : 0;
 | 
				
			||||||
 | 
					    data[3] = this->pwm_amounts_[1] > 0 ? correct_current_level_bits_(this->channel_current_[1]) : 0;
 | 
				
			||||||
 | 
					    data[4] = this->pwm_amounts_[2] > 0 ? correct_current_level_bits_(this->channel_current_[2]) : 0;
 | 
				
			||||||
 | 
					    data[5] = 0;
 | 
				
			||||||
 | 
					    data[6] = 0;
 | 
				
			||||||
 | 
					    for (int i = 7, j = 0; i <= 15; i += 2, j++) {
 | 
				
			||||||
 | 
					      data[i] = this->pwm_amounts_[j] & 0x1F;
 | 
				
			||||||
 | 
					      data[i + 1] = (this->pwm_amounts_[j] >> 5) & 0x1F;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this->write_buffer_(data, 17);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    // All channels
 | 
				
			||||||
 | 
					    data[0] = BP5758D_MODEL_ID + BP5758D_ADDR_START_5CH;
 | 
				
			||||||
 | 
					    data[1] = BP5758D_ALL_DATA_CHANNEL_ENABLEMENT;
 | 
				
			||||||
 | 
					    data[2] = this->pwm_amounts_[0] > 0 ? correct_current_level_bits_(this->channel_current_[0]) : 0;
 | 
				
			||||||
 | 
					    data[3] = this->pwm_amounts_[1] > 0 ? correct_current_level_bits_(this->channel_current_[1]) : 0;
 | 
				
			||||||
 | 
					    data[4] = this->pwm_amounts_[2] > 0 ? correct_current_level_bits_(this->channel_current_[2]) : 0;
 | 
				
			||||||
 | 
					    data[5] = this->pwm_amounts_[3] > 0 ? correct_current_level_bits_(this->channel_current_[3]) : 0;
 | 
				
			||||||
 | 
					    data[6] = this->pwm_amounts_[4] > 0 ? correct_current_level_bits_(this->channel_current_[4]) : 0;
 | 
				
			||||||
 | 
					    for (int i = 7, j = 0; i <= 15; i += 2, j++) {
 | 
				
			||||||
 | 
					      data[i] = this->pwm_amounts_[j] & 0x1F;
 | 
				
			||||||
 | 
					      data[i + 1] = (this->pwm_amounts_[j] >> 5) & 0x1F;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this->write_buffer_(data, 17);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  this->update_ = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t BP5758D::correct_current_level_bits_(uint8_t current) {
 | 
				
			||||||
 | 
					  // Anything below 64 uses normal bitmapping.
 | 
				
			||||||
 | 
					  if (current < 64) {
 | 
				
			||||||
 | 
					    return current;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Anything above 63 needs to be offset by +34 because the driver remaps bit 7 (normally 64) to 30.
 | 
				
			||||||
 | 
					  // (no idea why(!) but it is documented)
 | 
				
			||||||
 | 
					  // Example:
 | 
				
			||||||
 | 
					  // integer 64 would normally put out 0b01000000 but here 0b01000000 = 30 whereas everything lower
 | 
				
			||||||
 | 
					  // is normal, so we add 34 to the integer where
 | 
				
			||||||
 | 
					  // integer 98 = 0b01100010 which is 30 (7th bit adjusted) + 34 (1st-6th bits).
 | 
				
			||||||
 | 
					  return current + 34;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BP5758D::set_channel_value_(uint8_t channel, uint16_t value) {
 | 
				
			||||||
 | 
					  if (this->pwm_amounts_[channel] != value) {
 | 
				
			||||||
 | 
					    this->update_ = true;
 | 
				
			||||||
 | 
					    this->update_channel_ = channel;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  this->pwm_amounts_[channel] = value;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BP5758D::set_channel_current_(uint8_t channel, uint8_t current) { this->channel_current_[channel] = current; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BP5758D::write_bit_(bool value) {
 | 
				
			||||||
 | 
					  this->clock_pin_->digital_write(false);
 | 
				
			||||||
 | 
					  this->data_pin_->digital_write(value);
 | 
				
			||||||
 | 
					  this->clock_pin_->digital_write(true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BP5758D::write_byte_(uint8_t data) {
 | 
				
			||||||
 | 
					  for (uint8_t mask = 0x80; mask; mask >>= 1) {
 | 
				
			||||||
 | 
					    this->write_bit_(data & mask);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  this->clock_pin_->digital_write(false);
 | 
				
			||||||
 | 
					  this->data_pin_->digital_write(true);
 | 
				
			||||||
 | 
					  this->clock_pin_->digital_write(true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BP5758D::write_buffer_(uint8_t *buffer, uint8_t size) {
 | 
				
			||||||
 | 
					  this->data_pin_->digital_write(false);
 | 
				
			||||||
 | 
					  for (uint32_t i = 0; i < size; i++) {
 | 
				
			||||||
 | 
					    this->write_byte_(buffer[i]);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  this->clock_pin_->digital_write(false);
 | 
				
			||||||
 | 
					  this->clock_pin_->digital_write(true);
 | 
				
			||||||
 | 
					  this->data_pin_->digital_write(true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace bp5758d
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										64
									
								
								esphome/components/bp5758d/bp5758d.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								esphome/components/bp5758d/bp5758d.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "esphome/core/component.h"
 | 
				
			||||||
 | 
					#include "esphome/core/hal.h"
 | 
				
			||||||
 | 
					#include "esphome/components/output/float_output.h"
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace bp5758d {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BP5758D : public Component {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  class Channel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void set_data_pin(GPIOPin *data_pin) { data_pin_ = data_pin; }
 | 
				
			||||||
 | 
					  void set_clock_pin(GPIOPin *clock_pin) { clock_pin_ = clock_pin; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void setup() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void dump_config() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  float get_setup_priority() const override { return setup_priority::HARDWARE; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Send new values if they were updated.
 | 
				
			||||||
 | 
					  void loop() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  class Channel : public output::FloatOutput {
 | 
				
			||||||
 | 
					   public:
 | 
				
			||||||
 | 
					    void set_parent(BP5758D *parent) { parent_ = parent; }
 | 
				
			||||||
 | 
					    void set_channel(uint8_t channel) { channel_ = channel; }
 | 
				
			||||||
 | 
					    void set_current(uint8_t current) { current_ = current; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   protected:
 | 
				
			||||||
 | 
					    void write_state(float state) override {
 | 
				
			||||||
 | 
					      auto amount = static_cast<uint16_t>(state * 0x3FF);
 | 
				
			||||||
 | 
					      // We're enforcing channels start at 1 to mach OUT1-OUT5, we must adjust
 | 
				
			||||||
 | 
					      // to our 0-based array internally here by subtracting 1.
 | 
				
			||||||
 | 
					      this->parent_->set_channel_value_(this->channel_ - 1, amount);
 | 
				
			||||||
 | 
					      this->parent_->set_channel_current_(this->channel_ - 1, this->current_);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    BP5758D *parent_;
 | 
				
			||||||
 | 
					    uint8_t channel_;
 | 
				
			||||||
 | 
					    uint8_t current_;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 protected:
 | 
				
			||||||
 | 
					  uint8_t correct_current_level_bits_(uint8_t current);
 | 
				
			||||||
 | 
					  void set_channel_value_(uint8_t channel, uint16_t value);
 | 
				
			||||||
 | 
					  void set_channel_current_(uint8_t channel, uint8_t current);
 | 
				
			||||||
 | 
					  void write_bit_(bool value);
 | 
				
			||||||
 | 
					  void write_byte_(uint8_t data);
 | 
				
			||||||
 | 
					  void write_buffer_(uint8_t *buffer, uint8_t size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  GPIOPin *data_pin_;
 | 
				
			||||||
 | 
					  GPIOPin *clock_pin_;
 | 
				
			||||||
 | 
					  uint8_t update_channel_;
 | 
				
			||||||
 | 
					  std::vector<uint8_t> channel_current_;
 | 
				
			||||||
 | 
					  std::vector<uint16_t> pwm_amounts_;
 | 
				
			||||||
 | 
					  bool update_{true};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace bp5758d
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										29
									
								
								esphome/components/bp5758d/output.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								esphome/components/bp5758d/output.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome.components import output
 | 
				
			||||||
 | 
					from esphome.const import CONF_CHANNEL, CONF_ID, CONF_CURRENT
 | 
				
			||||||
 | 
					from . import BP5758D
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEPENDENCIES = ["bp5758d"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Channel = BP5758D.class_("Channel", output.FloatOutput)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONF_BP5758D_ID = "bp5758d_id"
 | 
				
			||||||
 | 
					CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend(
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cv.GenerateID(CONF_BP5758D_ID): cv.use_id(BP5758D),
 | 
				
			||||||
 | 
					        cv.Required(CONF_ID): cv.declare_id(Channel),
 | 
				
			||||||
 | 
					        cv.Required(CONF_CHANNEL): cv.int_range(min=1, max=5),
 | 
				
			||||||
 | 
					        cv.Optional(CONF_CURRENT, default=10): cv.int_range(min=0, max=90),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					).extend(cv.COMPONENT_SCHEMA)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def to_code(config):
 | 
				
			||||||
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
 | 
					    await output.register_output(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    parent = await cg.get_variable(config[CONF_BP5758D_ID])
 | 
				
			||||||
 | 
					    cg.add(var.set_parent(parent))
 | 
				
			||||||
 | 
					    cg.add(var.set_channel(config[CONF_CHANNEL]))
 | 
				
			||||||
 | 
					    cg.add(var.set_current(config[CONF_CURRENT]))
 | 
				
			||||||
@@ -4,6 +4,8 @@
 | 
				
			|||||||
#include "esphome/core/component.h"
 | 
					#include "esphome/core/component.h"
 | 
				
			||||||
#include "esphome/core/optional.h"
 | 
					#include "esphome/core/optional.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace canbus {
 | 
					namespace canbus {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,8 @@
 | 
				
			|||||||
#include "esphome/components/output/binary_output.h"
 | 
					#include "esphome/components/output/binary_output.h"
 | 
				
			||||||
#include "esphome/components/binary_sensor/binary_sensor.h"
 | 
					#include "esphome/components/binary_sensor/binary_sensor.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace cap1188 {
 | 
					namespace cap1188 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user