mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-04 09:01:49 +00:00 
			
		
		
		
	Compare commits
	
		
			1454 Commits
		
	
	
		
			2024.10.0b
			...
			2025.6.0b3
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					16a0f9db97 | ||
| 
						 | 
					5269523ca1 | ||
| 
						 | 
					89267b9e06 | ||
| 
						 | 
					4bc9646e8f | ||
| 
						 | 
					fd83628c49 | ||
| 
						 | 
					62abfbec9e | ||
| 
						 | 
					7cc0008837 | ||
| 
						 | 
					426be153db | ||
| 
						 | 
					2a81efda0b | ||
| 
						 | 
					6bad276589 | ||
| 
						 | 
					47d8048a62 | ||
| 
						 | 
					20d7ba5d7c | ||
| 
						 | 
					e435e72654 | ||
| 
						 | 
					497d66f7ec | ||
| 
						 | 
					242b02a416 | ||
| 
						 | 
					9644a6bb9c | ||
| 
						 | 
					70d66062d6 | ||
| 
						 | 
					39f6f9b0dc | ||
| 
						 | 
					0454dd4e07 | ||
| 
						 | 
					6f4e76c8f3 | ||
| 
						 | 
					5cdcf2415d | ||
| 
						 | 
					1719a2e08b | ||
| 
						 | 
					5640a9fe73 | ||
| 
						 | 
					4787e22f61 | ||
| 
						 | 
					fb12e4e66a | ||
| 
						 | 
					77740a1044 | ||
| 
						 | 
					1fdfe7578f | ||
| 
						 | 
					ebecf7047e | ||
| 
						 | 
					00e8332bf5 | ||
| 
						 | 
					5fc1f90822 | ||
| 
						 | 
					0a1be3d19c | ||
| 
						 | 
					40db3146b9 | ||
| 
						 | 
					535c495b33 | ||
| 
						 | 
					592446e430 | ||
| 
						 | 
					7a5c9a821a | ||
| 
						 | 
					44323dc285 | ||
| 
						 | 
					abb4d991ad | ||
| 
						 | 
					dcf41db878 | ||
| 
						 | 
					c3c3a27af2 | ||
| 
						 | 
					052f558131 | ||
| 
						 | 
					e8aa7cff36 | ||
| 
						 | 
					3411e45a0a | ||
| 
						 | 
					a488c8cd5c | ||
| 
						 | 
					9652b1a556 | ||
| 
						 | 
					69f2c79ccb | ||
| 
						 | 
					9d9d210176 | ||
| 
						 | 
					487e1f871f | ||
| 
						 | 
					0e27ac281f | ||
| 
						 | 
					ad37f103fa | ||
| 
						 | 
					b579bbf03b | ||
| 
						 | 
					7f4d2534aa | ||
| 
						 | 
					9e26daeb94 | ||
| 
						 | 
					da6af184a6 | ||
| 
						 | 
					4d347f1cc6 | ||
| 
						 | 
					84e57b8136 | ||
| 
						 | 
					63882c4a74 | ||
| 
						 | 
					2ed5611a08 | ||
| 
						 | 
					1467b704b8 | ||
| 
						 | 
					94848e4811 | ||
| 
						 | 
					3174f7ae86 | ||
| 
						 | 
					962a339a8a | ||
| 
						 | 
					6a76e6ae4a | ||
| 
						 | 
					ce4371a80d | ||
| 
						 | 
					b7ca6e087a | ||
| 
						 | 
					368a0eea8a | ||
| 
						 | 
					99c368fe62 | ||
| 
						 | 
					ff406f8e11 | ||
| 
						 | 
					b98165e077 | ||
| 
						 | 
					e2a9cced94 | ||
| 
						 | 
					cdae06e571 | ||
| 
						 | 
					c0b05ada1a | ||
| 
						 | 
					80dddb4cae | ||
| 
						 | 
					245c89a6c1 | ||
| 
						 | 
					4d044d4ac9 | ||
| 
						 | 
					9cc2a04d54 | ||
| 
						 | 
					50cdec19dd | ||
| 
						 | 
					6d587278bd | ||
| 
						 | 
					dde63e7459 | ||
| 
						 | 
					8894f5030a | ||
| 
						 | 
					9e862b8b53 | ||
| 
						 | 
					24d4ada841 | ||
| 
						 | 
					b1a8887548 | ||
| 
						 | 
					d19997a056 | ||
| 
						 | 
					de7591882d | ||
| 
						 | 
					a00fc75c77 | ||
| 
						 | 
					80fd827f8b | ||
| 
						 | 
					1dd3c6de90 | ||
| 
						 | 
					c8c43f13fd | ||
| 
						 | 
					518bce50a5 | ||
| 
						 | 
					4f87bea788 | ||
| 
						 | 
					8054c9b4f5 | ||
| 
						 | 
					935e0a365f | ||
| 
						 | 
					b39a9924d8 | ||
| 
						 | 
					19ec922e28 | ||
| 
						 | 
					a225d6881f | ||
| 
						 | 
					6675e99862 | ||
| 
						 | 
					8cbe2b41f6 | ||
| 
						 | 
					6a225cb4c0 | ||
| 
						 | 
					e62d8bfabe | ||
| 
						 | 
					d4cea84b1b | ||
| 
						 | 
					b63f90a6c0 | ||
| 
						 | 
					4370b6695e | ||
| 
						 | 
					589f13f0f7 | ||
| 
						 | 
					367017b352 | ||
| 
						 | 
					ec26d31499 | ||
| 
						 | 
					1bbc6db1c3 | ||
| 
						 | 
					162472bdc2 | ||
| 
						 | 
					aecac15809 | ||
| 
						 | 
					6554af21b9 | ||
| 
						 | 
					8583466c6a | ||
| 
						 | 
					6666604069 | ||
| 
						 | 
					13e7aacc9d | ||
| 
						 | 
					737d502614 | ||
| 
						 | 
					67dd649d00 | ||
| 
						 | 
					b2fc51367b | ||
| 
						 | 
					5771bb4907 | ||
| 
						 | 
					9ba9674437 | ||
| 
						 | 
					acb1532e34 | ||
| 
						 | 
					e2093c34da | ||
| 
						 | 
					a2e4ad90ba | ||
| 
						 | 
					32e69c67f2 | ||
| 
						 | 
					df0b5a187e | ||
| 
						 | 
					cee0e5379b | ||
| 
						 | 
					daf2bd7e66 | ||
| 
						 | 
					4031077f6d | ||
| 
						 | 
					fd72a64053 | ||
| 
						 | 
					959a8b91bd | ||
| 
						 | 
					44f1ff10e6 | ||
| 
						 | 
					64e4589f4e | ||
| 
						 | 
					20aba45cbe | ||
| 
						 | 
					0b1c5b825e | ||
| 
						 | 
					455624105b | ||
| 
						 | 
					7ac5746e0d | ||
| 
						 | 
					12997451f6 | ||
| 
						 | 
					8c77e40695 | ||
| 
						 | 
					2ddd91acf2 | ||
| 
						 | 
					729e49cdc3 | ||
| 
						 | 
					d64b49cc13 | ||
| 
						 | 
					cfa8b3b272 | ||
| 
						 | 
					51981335d5 | ||
| 
						 | 
					70c5e1bbf1 | ||
| 
						 | 
					43e88af28a | ||
| 
						 | 
					ffc66f539f | ||
| 
						 | 
					c4cb694d77 | ||
| 
						 | 
					3fb9577ad9 | ||
| 
						 | 
					34169491ac | ||
| 
						 | 
					8eac859bab | ||
| 
						 | 
					d99e3237f9 | ||
| 
						 | 
					d9a9e0aea3 | ||
| 
						 | 
					0ce03ae26b | ||
| 
						 | 
					18653f8f69 | ||
| 
						 | 
					6e0523109a | ||
| 
						 | 
					b6fa4f641d | ||
| 
						 | 
					ca6295d1bd | ||
| 
						 | 
					18a1d31845 | ||
| 
						 | 
					c5239a63ab | ||
| 
						 | 
					1911269dc9 | ||
| 
						 | 
					04ee1a87e9 | ||
| 
						 | 
					a8fdb6db4d | ||
| 
						 | 
					8860c74f0c | ||
| 
						 | 
					d585440d54 | ||
| 
						 | 
					f74f89c6b5 | ||
| 
						 | 
					7d049a61bb | ||
| 
						 | 
					f2e4dc7907 | ||
| 
						 | 
					0c7589caeb | ||
| 
						 | 
					321411e355 | ||
| 
						 | 
					361de22370 | ||
| 
						 | 
					95a17387a8 | ||
| 
						 | 
					caf9930ff9 | ||
| 
						 | 
					42390faf4a | ||
| 
						 | 
					fdc6c4a219 | ||
| 
						 | 
					6c08f5e343 | ||
| 
						 | 
					e0e4ba9592 | ||
| 
						 | 
					ad20825f31 | ||
| 
						 | 
					e4f3a952d5 | ||
| 
						 | 
					90e3c5bba2 | ||
| 
						 | 
					b1d5ad27f3 | ||
| 
						 | 
					5c54f75b7a | ||
| 
						 | 
					a5f85b4437 | ||
| 
						 | 
					da4e710249 | ||
| 
						 | 
					4ac433fddb | ||
| 
						 | 
					73771d5c50 | ||
| 
						 | 
					af7b1a3a23 | ||
| 
						 | 
					430f63fcbb | ||
| 
						 | 
					5921a9cd68 | ||
| 
						 | 
					ca0037d076 | ||
| 
						 | 
					1e18d0b06c | ||
| 
						 | 
					4b5c3e7e2b | ||
| 
						 | 
					d4c4b75eb3 | ||
| 
						 | 
					9dd4045984 | ||
| 
						 | 
					19e2460af2 | ||
| 
						 | 
					149f787035 | ||
| 
						 | 
					2ab1fe1abf | ||
| 
						 | 
					926b42ba1c | ||
| 
						 | 
					377ed2e212 | ||
| 
						 | 
					42912447fb | ||
| 
						 | 
					25ead44f1c | ||
| 
						 | 
					03b003af47 | ||
| 
						 | 
					5baccf0ce7 | ||
| 
						 | 
					e95c92773c | ||
| 
						 | 
					c23ea384fb | ||
| 
						 | 
					69da17742f | ||
| 
						 | 
					1ec57a74b5 | ||
| 
						 | 
					d1e55252d0 | ||
| 
						 | 
					090feb55e9 | ||
| 
						 | 
					6109acb6f3 | ||
| 
						 | 
					5aa13db815 | ||
| 
						 | 
					1b67dd4232 | ||
| 
						 | 
					ba6efcedcb | ||
| 
						 | 
					bd7c2a680c | ||
| 
						 | 
					1466aa7703 | ||
| 
						 | 
					787f4860db | ||
| 
						 | 
					aeb4e63950 | ||
| 
						 | 
					026f47bfb3 | ||
| 
						 | 
					dd47d063b5 | ||
| 
						 | 
					cdcd1cd292 | ||
| 
						 | 
					a6fa963605 | ||
| 
						 | 
					1cba22175f | ||
| 
						 | 
					f2d7720a4e | ||
| 
						 | 
					801138da27 | ||
| 
						 | 
					51740a2e99 | ||
| 
						 | 
					d68a391e67 | ||
| 
						 | 
					e9d832d64a | ||
| 
						 | 
					f8f09bca02 | ||
| 
						 | 
					756aa13779 | ||
| 
						 | 
					25bbc0c221 | ||
| 
						 | 
					220a14e1f8 | ||
| 
						 | 
					ac74b25c46 | ||
| 
						 | 
					c5d809b3dd | ||
| 
						 | 
					b1cf08b261 | ||
| 
						 | 
					6ae83dfe3d | ||
| 
						 | 
					0932e83b15 | ||
| 
						 | 
					86670c4d39 | ||
| 
						 | 
					4ce55b94ec | ||
| 
						 | 
					1c5dc63eb4 | ||
| 
						 | 
					937fe393a1 | ||
| 
						 | 
					4b552d9fba | ||
| 
						 | 
					aa53d8f1ee | ||
| 
						 | 
					a28932bc29 | ||
| 
						 | 
					afa7414ee1 | ||
| 
						 | 
					aed7ef481e | ||
| 
						 | 
					c820fee1f6 | ||
| 
						 | 
					5244ac4ff6 | ||
| 
						 | 
					89d283eee4 | ||
| 
						 | 
					ef053d23b4 | ||
| 
						 | 
					98470d32f0 | ||
| 
						 | 
					cab6edd800 | ||
| 
						 | 
					ef7a22ff04 | ||
| 
						 | 
					dfda0e5c7c | ||
| 
						 | 
					78c63311c6 | ||
| 
						 | 
					1ac51e7b3e | ||
| 
						 | 
					aaaf9b2b62 | ||
| 
						 | 
					5b552b9ec5 | ||
| 
						 | 
					d36ce7c010 | ||
| 
						 | 
					b8a96f59f0 | ||
| 
						 | 
					2e15ee232d | ||
| 
						 | 
					904495e1b8 | ||
| 
						 | 
					99c4f88c3f | ||
| 
						 | 
					87a9dd18c8 | ||
| 
						 | 
					dbce54477a | ||
| 
						 | 
					38cfd32382 | ||
| 
						 | 
					1b9ae57b9d | ||
| 
						 | 
					4d54cb9b31 | ||
| 
						 | 
					15d0b4355e | ||
| 
						 | 
					316fe2f06c | ||
| 
						 | 
					f8681adec4 | ||
| 
						 | 
					868f5ff20c | ||
| 
						 | 
					59295a615e | ||
| 
						 | 
					d8516cfabb | ||
| 
						 | 
					d847b345b8 | ||
| 
						 | 
					c50e33f531 | ||
| 
						 | 
					5a84bab9ec | ||
| 
						 | 
					41f860c2a3 | ||
| 
						 | 
					c7e62d1279 | ||
| 
						 | 
					2341ff651a | ||
| 
						 | 
					9704de6647 | ||
| 
						 | 
					660030d157 | ||
| 
						 | 
					24fbe602dd | ||
| 
						 | 
					b0c1e0e28c | ||
| 
						 | 
					574aabdede | ||
| 
						 | 
					e47741d471 | ||
| 
						 | 
					a78bea78f9 | ||
| 
						 | 
					44470f31f6 | ||
| 
						 | 
					18ac1b7c54 | ||
| 
						 | 
					e87b659483 | ||
| 
						 | 
					fefcb45e1f | ||
| 
						 | 
					5c92367ca2 | ||
| 
						 | 
					b469a504e4 | ||
| 
						 | 
					218f8e0caf | ||
| 
						 | 
					7965558d5e | ||
| 
						 | 
					d9b860088e | ||
| 
						 | 
					115975c409 | ||
| 
						 | 
					4761ffe023 | ||
| 
						 | 
					88edddf07a | ||
| 
						 | 
					0b77cb1d16 | ||
| 
						 | 
					efa6745a5e | ||
| 
						 | 
					dd8d8ad952 | ||
| 
						 | 
					57284b1ac3 | ||
| 
						 | 
					1a651ce66d | ||
| 
						 | 
					730441c120 | ||
| 
						 | 
					bb1f24ab43 | ||
| 
						 | 
					edb8d187be | ||
| 
						 | 
					e7b6081c5c | ||
| 
						 | 
					97fb8c2cdf | ||
| 
						 | 
					5454500024 | ||
| 
						 | 
					d9839f3a5c | ||
| 
						 | 
					498e3904a9 | ||
| 
						 | 
					7cb01bf842 | ||
| 
						 | 
					c050e8d0fb | ||
| 
						 | 
					4f2643e6e9 | ||
| 
						 | 
					7d0262dd1a | ||
| 
						 | 
					c30ffd0098 | ||
| 
						 | 
					ea31122979 | ||
| 
						 | 
					191afd3e69 | ||
| 
						 | 
					de27ce79dc | ||
| 
						 | 
					a12bd78ceb | ||
| 
						 | 
					ddb986b4fa | ||
| 
						 | 
					c98c78e368 | ||
| 
						 | 
					1e20440c8e | ||
| 
						 | 
					5570a788fd | ||
| 
						 | 
					42c355e6d7 | ||
| 
						 | 
					a835ab48bc | ||
| 
						 | 
					f28a373898 | ||
| 
						 | 
					0630244195 | ||
| 
						 | 
					28e29efd98 | ||
| 
						 | 
					183659f527 | ||
| 
						 | 
					4ea63af796 | ||
| 
						 | 
					0aa7911b1b | ||
| 
						 | 
					032949bc77 | ||
| 
						 | 
					6f8ee65919 | ||
| 
						 | 
					c5654b4cb2 | ||
| 
						 | 
					410b6353fe | ||
| 
						 | 
					a36e1aab8e | ||
| 
						 | 
					864ae7a56c | ||
| 
						 | 
					2560d2b9d0 | ||
| 
						 | 
					0cf9b05afd | ||
| 
						 | 
					8b65d1673a | ||
| 
						 | 
					5e164b107a | ||
| 
						 | 
					a83959d738 | ||
| 
						 | 
					0ccc5bf714 | ||
| 
						 | 
					bc0956019b | ||
| 
						 | 
					49f631d6c5 | ||
| 
						 | 
					a9d5eb8470 | ||
| 
						 | 
					7c0546c9f0 | ||
| 
						 | 
					f4eb75e4e0 | ||
| 
						 | 
					5b2c19bc86 | ||
| 
						 | 
					185b84b8b2 | ||
| 
						 | 
					facf94699e | ||
| 
						 | 
					58104229e2 | ||
| 
						 | 
					50c88b7aa7 | ||
| 
						 | 
					81bae96109 | ||
| 
						 | 
					a3ed090594 | ||
| 
						 | 
					cff1820772 | ||
| 
						 | 
					bdd2774544 | ||
| 
						 | 
					38790793dd | ||
| 
						 | 
					dcd786d21c | ||
| 
						 | 
					71e88fe9b2 | ||
| 
						 | 
					11dcaf7383 | ||
| 
						 | 
					dded81d622 | ||
| 
						 | 
					8324b3244c | ||
| 
						 | 
					401c090edd | ||
| 
						 | 
					8757957e17 | ||
| 
						 | 
					e2c8a5b638 | ||
| 
						 | 
					7bb899bfa1 | ||
| 
						 | 
					3e2359ddff | ||
| 
						 | 
					04147a7f27 | ||
| 
						 | 
					cae3c030d2 | ||
| 
						 | 
					d7c615ec43 | ||
| 
						 | 
					1294e8ccd5 | ||
| 
						 | 
					37a2cb07d1 | ||
| 
						 | 
					2af3994f79 | ||
| 
						 | 
					0c0fe81814 | ||
| 
						 | 
					82c8614315 | ||
| 
						 | 
					a85dc65038 | ||
| 
						 | 
					290b8bdca0 | ||
| 
						 | 
					a96ed0b70a | ||
| 
						 | 
					cdc1a7c646 | ||
| 
						 | 
					7f59aff157 | ||
| 
						 | 
					cdce59f7f9 | ||
| 
						 | 
					ff1c3cb52e | ||
| 
						 | 
					bec9d91419 | ||
| 
						 | 
					8399d894c1 | ||
| 
						 | 
					e1732c4945 | ||
| 
						 | 
					ca221d6cb2 | ||
| 
						 | 
					8a90ce882a | ||
| 
						 | 
					b3400a1308 | ||
| 
						 | 
					23fb1bed61 | ||
| 
						 | 
					2b3757dff8 | ||
| 
						 | 
					1da8e99d27 | ||
| 
						 | 
					e94e71ded8 | ||
| 
						 | 
					00f20c1e55 | ||
| 
						 | 
					45d019a7e4 | ||
| 
						 | 
					8465017db9 | ||
| 
						 | 
					782d748210 | ||
| 
						 | 
					b01d85a974 | ||
| 
						 | 
					797a4c61f2 | ||
| 
						 | 
					8e29437900 | ||
| 
						 | 
					9e64e71cdf | ||
| 
						 | 
					ef2621aa54 | ||
| 
						 | 
					882273cb56 | ||
| 
						 | 
					ad2b74d9b4 | ||
| 
						 | 
					26669bd1b6 | ||
| 
						 | 
					54ead9a6b4 | ||
| 
						 | 
					d60e1f02c0 | ||
| 
						 | 
					213648564c | ||
| 
						 | 
					8bdbde9732 | ||
| 
						 | 
					e988762576 | ||
| 
						 | 
					75496849eb | ||
| 
						 | 
					39b119e9cc | ||
| 
						 | 
					4d43caf6c1 | ||
| 
						 | 
					ce5e1a6294 | ||
| 
						 | 
					88be14aaa3 | ||
| 
						 | 
					1ac56b06c5 | ||
| 
						 | 
					8bbc509b0b | ||
| 
						 | 
					6f35d0ac88 | ||
| 
						 | 
					3b8a5db97c | ||
| 
						 | 
					b8d83d0765 | ||
| 
						 | 
					e7a2b395fd | ||
| 
						 | 
					ad99d7fb45 | ||
| 
						 | 
					0b032e5c19 | ||
| 
						 | 
					c7523ace78 | ||
| 
						 | 
					2a6827e1d2 | ||
| 
						 | 
					125aff79ec | ||
| 
						 | 
					a31d8ec309 | ||
| 
						 | 
					3ed03edfec | ||
| 
						 | 
					4dc6cbe2d7 | ||
| 
						 | 
					524cd4b4e3 | ||
| 
						 | 
					84ebbf0762 | ||
| 
						 | 
					670ad7192c | ||
| 
						 | 
					bc6ee20270 | ||
| 
						 | 
					e869a3aec3 | ||
| 
						 | 
					8aff6d2fdd | ||
| 
						 | 
					8d33c6de36 | ||
| 
						 | 
					f4b5f32cb4 | ||
| 
						 | 
					2eb9582d0f | ||
| 
						 | 
					db97440b04 | ||
| 
						 | 
					ced7ae1d7a | ||
| 
						 | 
					d6699fa3c0 | ||
| 
						 | 
					836e5ffa43 | ||
| 
						 | 
					c7f597bc75 | ||
| 
						 | 
					e215fafebe | ||
| 
						 | 
					da9c755f67 | ||
| 
						 | 
					087ff865a7 | ||
| 
						 | 
					8cd62c0308 | ||
| 
						 | 
					f5241ff777 | ||
| 
						 | 
					1aa2b79311 | ||
| 
						 | 
					2dca2d5f85 | ||
| 
						 | 
					f03b42ced5 | ||
| 
						 | 
					0f8a0af244 | ||
| 
						 | 
					62646f5f32 | ||
| 
						 | 
					71f81d2f18 | ||
| 
						 | 
					4ec8414050 | ||
| 
						 | 
					807925fd38 | ||
| 
						 | 
					b597565165 | ||
| 
						 | 
					9a9b91b180 | ||
| 
						 | 
					9dcf295df8 | ||
| 
						 | 
					e8a3de2642 | ||
| 
						 | 
					d2b4dba51f | ||
| 
						 | 
					bf527b0331 | ||
| 
						 | 
					cdc77506de | ||
| 
						 | 
					6de6a0c82c | ||
| 
						 | 
					20062576a3 | ||
| 
						 | 
					07ba9fdf8f | ||
| 
						 | 
					caa255f5d1 | ||
| 
						 | 
					c0be2c14f3 | ||
| 
						 | 
					9f629dcaa2 | ||
| 
						 | 
					0fe6c65ba3 | ||
| 
						 | 
					c756bb3b3e | ||
| 
						 | 
					ecb91b0101 | ||
| 
						 | 
					5f9a509bdc | ||
| 
						 | 
					dc6dd9fe0d | ||
| 
						 | 
					5baa034d0d | ||
| 
						 | 
					b8ba26787e | ||
| 
						 | 
					844569e96b | ||
| 
						 | 
					43580739ac | ||
| 
						 | 
					c9f7ab6948 | ||
| 
						 | 
					7900660bb8 | ||
| 
						 | 
					f096567ac7 | ||
| 
						 | 
					5bfb5ccc34 | ||
| 
						 | 
					1c60038111 | ||
| 
						 | 
					b940db6549 | ||
| 
						 | 
					aa6e172e14 | ||
| 
						 | 
					86033b6612 | ||
| 
						 | 
					59b4a1f554 | ||
| 
						 | 
					b5bdfb3089 | ||
| 
						 | 
					a31a5e74bd | ||
| 
						 | 
					629481a526 | ||
| 
						 | 
					3291a11824 | ||
| 
						 | 
					d2ee2d3b23 | ||
| 
						 | 
					253e3ec6f6 | ||
| 
						 | 
					fdc4ec8a57 | ||
| 
						 | 
					1da0dff8b1 | ||
| 
						 | 
					38dae8489e | ||
| 
						 | 
					22c0e1079e | ||
| 
						 | 
					2d3f141140 | ||
| 
						 | 
					e49252ca3d | ||
| 
						 | 
					c9d1476ae0 | ||
| 
						 | 
					ee646d7324 | ||
| 
						 | 
					e557bca420 | ||
| 
						 | 
					adcd6517db | ||
| 
						 | 
					4c8f5275f9 | ||
| 
						 | 
					526db0102c | ||
| 
						 | 
					8a3fe9ce4c | ||
| 
						 | 
					fb97ef33a8 | ||
| 
						 | 
					805a6d85a5 | ||
| 
						 | 
					8f9fbb15b8 | ||
| 
						 | 
					3d24dea455 | ||
| 
						 | 
					666d5374ea | ||
| 
						 | 
					6792ff6d58 | ||
| 
						 | 
					f29ccb9e75 | ||
| 
						 | 
					911bd54765 | ||
| 
						 | 
					89b1b12993 | ||
| 
						 | 
					33d79e03d9 | ||
| 
						 | 
					991f3d3a10 | ||
| 
						 | 
					97823ddd16 | ||
| 
						 | 
					6ff180152a | ||
| 
						 | 
					dbb7cbed3e | ||
| 
						 | 
					fbf00f0af4 | ||
| 
						 | 
					82c6a40371 | ||
| 
						 | 
					0242ac56df | ||
| 
						 | 
					b82666002d | ||
| 
						 | 
					e11883e431 | ||
| 
						 | 
					ff5b9df607 | ||
| 
						 | 
					e5b7e3039a | ||
| 
						 | 
					31ed1eb6f0 | ||
| 
						 | 
					0c3daab649 | ||
| 
						 | 
					816371e3e9 | ||
| 
						 | 
					3c7bb65a23 | ||
| 
						 | 
					4a65fd76b3 | ||
| 
						 | 
					2704db5eef | ||
| 
						 | 
					f10bc73d31 | ||
| 
						 | 
					55e099450c | ||
| 
						 | 
					248dbd32a5 | ||
| 
						 | 
					a7b676231a | ||
| 
						 | 
					2fd5f9ac58 | ||
| 
						 | 
					ca4838a5f4 | ||
| 
						 | 
					1b72550236 | ||
| 
						 | 
					71afd49e3e | ||
| 
						 | 
					e5d718d1b1 | ||
| 
						 | 
					61f33d6401 | ||
| 
						 | 
					af9b568778 | ||
| 
						 | 
					4a1eec567f | ||
| 
						 | 
					5706b8476f | ||
| 
						 | 
					8981a86793 | ||
| 
						 | 
					a7fd6dc382 | ||
| 
						 | 
					cb0a87c1f9 | ||
| 
						 | 
					b913a0b178 | ||
| 
						 | 
					214454ff51 | ||
| 
						 | 
					3677ef71d1 | ||
| 
						 | 
					7e133171e0 | ||
| 
						 | 
					bc56d319b5 | ||
| 
						 | 
					c423a6fb61 | ||
| 
						 | 
					4034bf4f04 | ||
| 
						 | 
					477abc05ae | ||
| 
						 | 
					ff2b93a3e4 | ||
| 
						 | 
					a52d6388a9 | ||
| 
						 | 
					6259ca9ded | ||
| 
						 | 
					f6ef50505b | ||
| 
						 | 
					b4cf437761 | ||
| 
						 | 
					1d9f5f1f1e | ||
| 
						 | 
					e47489708e | ||
| 
						 | 
					8e1bdcd211 | ||
| 
						 | 
					3432d73584 | ||
| 
						 | 
					2bb86641f8 | ||
| 
						 | 
					6ca72a3a26 | ||
| 
						 | 
					c215098cb7 | ||
| 
						 | 
					566968b6be | ||
| 
						 | 
					fe51ee6257 | ||
| 
						 | 
					2c499b326a | ||
| 
						 | 
					7c4ab7abfe | ||
| 
						 | 
					3c242b7296 | ||
| 
						 | 
					00dd5b8339 | ||
| 
						 | 
					a007a8237a | ||
| 
						 | 
					9b86cc37f0 | ||
| 
						 | 
					2dfcf950fa | ||
| 
						 | 
					5908b93e82 | ||
| 
						 | 
					995db1f961 | ||
| 
						 | 
					abcc656a6f | ||
| 
						 | 
					4a9f323d92 | ||
| 
						 | 
					34a4e70cc5 | ||
| 
						 | 
					fb5d697c22 | ||
| 
						 | 
					df4642208e | ||
| 
						 | 
					264e234efc | ||
| 
						 | 
					ca78dd44b5 | ||
| 
						 | 
					7edf458898 | ||
| 
						 | 
					d9873e24a7 | ||
| 
						 | 
					645bd490ba | ||
| 
						 | 
					27f6d00e7a | ||
| 
						 | 
					f9d668eeca | ||
| 
						 | 
					92d1557efd | ||
| 
						 | 
					6b930595e2 | ||
| 
						 | 
					4a1cbfc533 | ||
| 
						 | 
					1f7a84cc8e | ||
| 
						 | 
					8c5adfb33f | ||
| 
						 | 
					399c9ba4be | ||
| 
						 | 
					a866370a2e | ||
| 
						 | 
					6240bfff97 | ||
| 
						 | 
					1c72fd4674 | ||
| 
						 | 
					2291a1dc39 | ||
| 
						 | 
					8269e2c961 | ||
| 
						 | 
					23dec912ad | ||
| 
						 | 
					9637ef35bd | ||
| 
						 | 
					23e5cdb30e | ||
| 
						 | 
					f3b1b11eba | ||
| 
						 | 
					5ceba618f6 | ||
| 
						 | 
					99d5ca3266 | ||
| 
						 | 
					219ba6152c | ||
| 
						 | 
					ef0f969604 | ||
| 
						 | 
					82adcd656f | ||
| 
						 | 
					fe35eee8df | ||
| 
						 | 
					864dd69038 | ||
| 
						 | 
					79f198ebff | ||
| 
						 | 
					4b0622aa23 | ||
| 
						 | 
					4ecc72ed54 | ||
| 
						 | 
					791740e554 | ||
| 
						 | 
					6bccc7e389 | ||
| 
						 | 
					655075e71b | ||
| 
						 | 
					1df1e3cf48 | ||
| 
						 | 
					05e52cae2b | ||
| 
						 | 
					be60d9be9b | ||
| 
						 | 
					e3eb3ee5d2 | ||
| 
						 | 
					0812b3dd70 | ||
| 
						 | 
					28a9f12595 | ||
| 
						 | 
					36b75c3faa | ||
| 
						 | 
					584c5bd5be | ||
| 
						 | 
					bc372dbeb2 | ||
| 
						 | 
					37a03de849 | ||
| 
						 | 
					c8395cdf0a | ||
| 
						 | 
					79c8a55459 | ||
| 
						 | 
					36d6fe29f2 | ||
| 
						 | 
					e1868ddecb | ||
| 
						 | 
					6151644b96 | ||
| 
						 | 
					a4914eb5b7 | ||
| 
						 | 
					57a57f0d6a | ||
| 
						 | 
					7e9f93a290 | ||
| 
						 | 
					402ada07b5 | ||
| 
						 | 
					9aa9abfc08 | ||
| 
						 | 
					4c1f83614b | ||
| 
						 | 
					d1763f9831 | ||
| 
						 | 
					c49391427f | ||
| 
						 | 
					c42343be3a | ||
| 
						 | 
					ffc233d99d | ||
| 
						 | 
					5ed0046bdd | ||
| 
						 | 
					2e16dd788c | ||
| 
						 | 
					58fe8b39b2 | ||
| 
						 | 
					ccd55a8e84 | ||
| 
						 | 
					4bb59ce1d1 | ||
| 
						 | 
					bb988604c8 | ||
| 
						 | 
					573088aadb | ||
| 
						 | 
					031b1c8bd0 | ||
| 
						 | 
					f95b2ba898 | ||
| 
						 | 
					ea4b573f9a | ||
| 
						 | 
					8fcbd57f2f | ||
| 
						 | 
					f131186e6b | ||
| 
						 | 
					20c7778524 | ||
| 
						 | 
					2d8e86324b | ||
| 
						 | 
					2dfd28ba3e | ||
| 
						 | 
					63221d7a1f | ||
| 
						 | 
					fb9a15f0af | ||
| 
						 | 
					ce2e966005 | ||
| 
						 | 
					e7d1072c85 | ||
| 
						 | 
					bc999b50b3 | ||
| 
						 | 
					6cfe3ac44d | ||
| 
						 | 
					6787730aa4 | ||
| 
						 | 
					48a7927a60 | ||
| 
						 | 
					8ea4d8402f | ||
| 
						 | 
					2c53408cfc | ||
| 
						 | 
					33dce6e522 | ||
| 
						 | 
					e213932b7c | ||
| 
						 | 
					42fb0e2809 | ||
| 
						 | 
					acce0bc45b | ||
| 
						 | 
					f5885de6f1 | ||
| 
						 | 
					17e3bb7324 | ||
| 
						 | 
					d891521ce2 | ||
| 
						 | 
					3320e4112b | ||
| 
						 | 
					c0e4701e1d | ||
| 
						 | 
					f3390ff7f5 | ||
| 
						 | 
					dfbfb2a2bb | ||
| 
						 | 
					874026ca8f | ||
| 
						 | 
					4adda632bb | ||
| 
						 | 
					6ea89644e7 | ||
| 
						 | 
					64ff62c005 | ||
| 
						 | 
					c4de9e87e4 | ||
| 
						 | 
					918924d697 | ||
| 
						 | 
					43805e6c56 | ||
| 
						 | 
					38bbfaccc6 | ||
| 
						 | 
					56b32aae11 | ||
| 
						 | 
					e2c16b4baa | ||
| 
						 | 
					10a9162f48 | ||
| 
						 | 
					fbc884772c | ||
| 
						 | 
					cbf68f1fd2 | ||
| 
						 | 
					cf227d6f32 | ||
| 
						 | 
					54e3153f27 | ||
| 
						 | 
					c2e0a01106 | ||
| 
						 | 
					d2c2439b97 | ||
| 
						 | 
					a8d33dd26a | ||
| 
						 | 
					da41a9204e | ||
| 
						 | 
					f993bb08c7 | ||
| 
						 | 
					afa481aeea | ||
| 
						 | 
					dfb162e7a6 | ||
| 
						 | 
					098921b88f | ||
| 
						 | 
					5c6368b6b8 | ||
| 
						 | 
					9bd7060f6b | ||
| 
						 | 
					fb1d178abc | ||
| 
						 | 
					90c96a0a0f | ||
| 
						 | 
					c63a545750 | ||
| 
						 | 
					89f82be4cd | ||
| 
						 | 
					c336dd9436 | ||
| 
						 | 
					fa25cebed5 | ||
| 
						 | 
					7679c716b3 | ||
| 
						 | 
					225e2585e8 | ||
| 
						 | 
					1bdf0fdc57 | ||
| 
						 | 
					4d95ff2ae0 | ||
| 
						 | 
					f36d400058 | ||
| 
						 | 
					c63cf9d151 | ||
| 
						 | 
					0a02c1461e | ||
| 
						 | 
					b3a69c6c05 | ||
| 
						 | 
					dd113f2972 | ||
| 
						 | 
					3c5a0091ee | ||
| 
						 | 
					bf65b73569 | ||
| 
						 | 
					a2b123a29a | ||
| 
						 | 
					3575f52cdf | ||
| 
						 | 
					c90185854e | ||
| 
						 | 
					7d8c39d295 | ||
| 
						 | 
					59d282489a | ||
| 
						 | 
					f9a0a63290 | ||
| 
						 | 
					00000e0ea8 | ||
| 
						 | 
					bd853e6883 | ||
| 
						 | 
					64d1d93fe0 | ||
| 
						 | 
					266c2ef337 | ||
| 
						 | 
					35199c9b96 | ||
| 
						 | 
					0a29138045 | ||
| 
						 | 
					52269305ec | ||
| 
						 | 
					04dc0ed129 | ||
| 
						 | 
					37fabd7c0a | ||
| 
						 | 
					4aa7ad1e33 | ||
| 
						 | 
					42e432754e | ||
| 
						 | 
					2379f02008 | ||
| 
						 | 
					d3145dd95b | ||
| 
						 | 
					ab77dd691b | ||
| 
						 | 
					b54c0fd60a | ||
| 
						 | 
					75d1eeeffe | ||
| 
						 | 
					10cea51739 | ||
| 
						 | 
					83e090cc7e | ||
| 
						 | 
					583f8f598a | ||
| 
						 | 
					3e9556c6c2 | ||
| 
						 | 
					83cba0d7bd | ||
| 
						 | 
					1d6d0d66dc | ||
| 
						 | 
					4ed78023b6 | ||
| 
						 | 
					323209523b | ||
| 
						 | 
					46a4f4eba9 | ||
| 
						 | 
					53fda0e96d | ||
| 
						 | 
					0350eafc1e | ||
| 
						 | 
					7b8e68c73a | ||
| 
						 | 
					db666e44a7 | ||
| 
						 | 
					903d033e0f | ||
| 
						 | 
					19d938ce48 | ||
| 
						 | 
					653318479a | ||
| 
						 | 
					2af5fd5210 | ||
| 
						 | 
					29e388b231 | ||
| 
						 | 
					d9e23fdb5c | ||
| 
						 | 
					10eacaccba | ||
| 
						 | 
					23687b2afd | ||
| 
						 | 
					f11ad9ad5b | ||
| 
						 | 
					74a25a7e76 | ||
| 
						 | 
					23e04e18f8 | ||
| 
						 | 
					aed5020a83 | ||
| 
						 | 
					476f1b701b | ||
| 
						 | 
					7c3a7b68d3 | ||
| 
						 | 
					75dc0d3fb7 | ||
| 
						 | 
					9bc4f68d87 | ||
| 
						 | 
					1029202848 | ||
| 
						 | 
					a831905bba | ||
| 
						 | 
					faffd79545 | ||
| 
						 | 
					7714147071 | ||
| 
						 | 
					4da42dedc8 | ||
| 
						 | 
					28f283d545 | ||
| 
						 | 
					3048f303c5 | ||
| 
						 | 
					63a7234767 | ||
| 
						 | 
					c19621e238 | ||
| 
						 | 
					bc96eb9d52 | ||
| 
						 | 
					7375dde39c | ||
| 
						 | 
					1b7111affb | ||
| 
						 | 
					a511926aed | ||
| 
						 | 
					6b36cb95c9 | ||
| 
						 | 
					c13174c318 | ||
| 
						 | 
					d5da341138 | ||
| 
						 | 
					8fa157581e | ||
| 
						 | 
					7114d6bdd1 | ||
| 
						 | 
					eca0c21966 | ||
| 
						 | 
					20c9c410af | ||
| 
						 | 
					79af437f48 | ||
| 
						 | 
					6e27003787 | ||
| 
						 | 
					b7b2f3e61c | ||
| 
						 | 
					9448737a92 | ||
| 
						 | 
					6f2bf4ec4c | ||
| 
						 | 
					54cea6c41e | ||
| 
						 | 
					e754d0a58b | ||
| 
						 | 
					5e44a035a3 | ||
| 
						 | 
					c424fea524 | ||
| 
						 | 
					6aba1dbd73 | ||
| 
						 | 
					422fb8f1a5 | ||
| 
						 | 
					2988bbb8ce | ||
| 
						 | 
					59299bffc8 | ||
| 
						 | 
					3410aee42e | ||
| 
						 | 
					96682f5cbe | ||
| 
						 | 
					bfa3254d6c | ||
| 
						 | 
					990d1e3bb0 | ||
| 
						 | 
					755b0bbfc7 | ||
| 
						 | 
					c281351732 | ||
| 
						 | 
					9f603a474f | ||
| 
						 | 
					bf739506c3 | ||
| 
						 | 
					3020083564 | ||
| 
						 | 
					31e90e5544 | ||
| 
						 | 
					7c9726859f | ||
| 
						 | 
					7529fb10b4 | ||
| 
						 | 
					ba79e2d7b1 | ||
| 
						 | 
					7006bd24a5 | ||
| 
						 | 
					58311c9a0d | ||
| 
						 | 
					ae65f76dfe | ||
| 
						 | 
					4d380214df | ||
| 
						 | 
					c5ebf7683e | ||
| 
						 | 
					a973adda67 | ||
| 
						 | 
					d9b419eaf5 | ||
| 
						 | 
					02bf33c548 | ||
| 
						 | 
					b3db04a3d3 | ||
| 
						 | 
					56034e3e79 | ||
| 
						 | 
					abbd72e802 | ||
| 
						 | 
					1257640e48 | ||
| 
						 | 
					2bc9782ce7 | ||
| 
						 | 
					6583e17810 | ||
| 
						 | 
					64c8bcef2e | ||
| 
						 | 
					f9da8dbfb8 | ||
| 
						 | 
					74f7197543 | ||
| 
						 | 
					c21b8bd417 | ||
| 
						 | 
					1eb658cc5b | ||
| 
						 | 
					8b251efb75 | ||
| 
						 | 
					26d25464da | ||
| 
						 | 
					78b55e22ee | ||
| 
						 | 
					9ee5227fe0 | ||
| 
						 | 
					e89603fe3b | ||
| 
						 | 
					c0804d665d | ||
| 
						 | 
					a67b85eabf | ||
| 
						 | 
					a47e27885f | ||
| 
						 | 
					2e66b33672 | ||
| 
						 | 
					e21ef22706 | ||
| 
						 | 
					93c2878c21 | ||
| 
						 | 
					b3ad6a03e6 | ||
| 
						 | 
					6e45a7c9af | ||
| 
						 | 
					e17582544e | ||
| 
						 | 
					daa7960031 | ||
| 
						 | 
					6999cc0581 | ||
| 
						 | 
					92ad6286aa | ||
| 
						 | 
					1111aa167f | ||
| 
						 | 
					143b0d3de4 | ||
| 
						 | 
					788c41e6f4 | ||
| 
						 | 
					46b6dcdfbf | ||
| 
						 | 
					d05f641dd0 | ||
| 
						 | 
					897873496a | ||
| 
						 | 
					b0f6dd7d9c | ||
| 
						 | 
					be5639faf1 | ||
| 
						 | 
					e9a537784e | ||
| 
						 | 
					35d303809e | ||
| 
						 | 
					4740f12ce8 | ||
| 
						 | 
					c8e7e275a4 | ||
| 
						 | 
					077ee5b714 | ||
| 
						 | 
					fa029e8fc7 | ||
| 
						 | 
					ace953bd50 | ||
| 
						 | 
					e190ef9e9b | ||
| 
						 | 
					2868210d46 | ||
| 
						 | 
					72f6461871 | ||
| 
						 | 
					4a95468fd2 | ||
| 
						 | 
					43319d4c8a | ||
| 
						 | 
					3b7a7a2262 | ||
| 
						 | 
					de2d21862b | ||
| 
						 | 
					3d48eb26cd | ||
| 
						 | 
					ab0d38fbda | ||
| 
						 | 
					2b75e34719 | ||
| 
						 | 
					0b6c416680 | ||
| 
						 | 
					7bb2c3c496 | ||
| 
						 | 
					88cfdc33d4 | ||
| 
						 | 
					a2f1b90238 | ||
| 
						 | 
					0401ee9428 | ||
| 
						 | 
					14d7931bd6 | ||
| 
						 | 
					6b3f3e1da6 | ||
| 
						 | 
					33f9d66e81 | ||
| 
						 | 
					46d19d82c2 | ||
| 
						 | 
					c9e7562aff | ||
| 
						 | 
					8b7aa4c110 | ||
| 
						 | 
					b667ceaced | ||
| 
						 | 
					abdf215d3a | ||
| 
						 | 
					84836f15db | ||
| 
						 | 
					8be9f02693 | ||
| 
						 | 
					1ab1768b6a | ||
| 
						 | 
					0d13e2040d | ||
| 
						 | 
					fd24b1423c | ||
| 
						 | 
					66c35a9432 | ||
| 
						 | 
					45b8810ab8 | ||
| 
						 | 
					ff7d232ee6 | ||
| 
						 | 
					0cd3af2fcd | ||
| 
						 | 
					8897a9866d | ||
| 
						 | 
					dc8646cda6 | ||
| 
						 | 
					353924257a | ||
| 
						 | 
					da3d007d7b | ||
| 
						 | 
					9e3359cdf2 | ||
| 
						 | 
					7e626b04f2 | ||
| 
						 | 
					4eb551864d | ||
| 
						 | 
					e337bd7beb | ||
| 
						 | 
					57739b8bb0 | ||
| 
						 | 
					65ca000e6d | ||
| 
						 | 
					bf6874b52e | ||
| 
						 | 
					cecce0f3cb | ||
| 
						 | 
					4d8f58db94 | ||
| 
						 | 
					977333a73c | ||
| 
						 | 
					1215d2ffeb | ||
| 
						 | 
					9b56f9cc6d | ||
| 
						 | 
					2e61229aed | ||
| 
						 | 
					55203143df | ||
| 
						 | 
					4e4566361f | ||
| 
						 | 
					4273449003 | ||
| 
						 | 
					f8fae676b1 | ||
| 
						 | 
					211aee91e5 | ||
| 
						 | 
					6e3527a88b | ||
| 
						 | 
					06f9764f51 | ||
| 
						 | 
					693d813c4b | ||
| 
						 | 
					61ad2510fc | ||
| 
						 | 
					53c15f6716 | ||
| 
						 | 
					d4ac2d3c7e | ||
| 
						 | 
					6f4e8f1fbf | ||
| 
						 | 
					847cff06b3 | ||
| 
						 | 
					bd34697715 | ||
| 
						 | 
					6b55df36c7 | ||
| 
						 | 
					b8f9eaecd8 | ||
| 
						 | 
					c8bbc2e84c | ||
| 
						 | 
					5108b9a8b7 | ||
| 
						 | 
					8de5af4eec | ||
| 
						 | 
					6e5e681055 | ||
| 
						 | 
					f6cf99384b | ||
| 
						 | 
					2b711e532b | ||
| 
						 | 
					72c6f04a97 | ||
| 
						 | 
					03e2701bd0 | ||
| 
						 | 
					051fa3a49f | ||
| 
						 | 
					7392397630 | ||
| 
						 | 
					714e2d3e56 | ||
| 
						 | 
					12d6c1bbca | ||
| 
						 | 
					7727879f01 | ||
| 
						 | 
					334e952a34 | ||
| 
						 | 
					f9856135d0 | ||
| 
						 | 
					ba3e5e8ecb | ||
| 
						 | 
					67ccd0eb7f | ||
| 
						 | 
					619ce93dec | ||
| 
						 | 
					9957840dfc | ||
| 
						 | 
					a23ce416ea | ||
| 
						 | 
					2489f95107 | ||
| 
						 | 
					7dab1a6082 | ||
| 
						 | 
					f7f8bf4da4 | ||
| 
						 | 
					dd18a219db | ||
| 
						 | 
					dbf4c2c4da | ||
| 
						 | 
					fc847c1de8 | ||
| 
						 | 
					7fccc9ff86 | ||
| 
						 | 
					dee1d84979 | ||
| 
						 | 
					65b2d48a6f | ||
| 
						 | 
					8aeb08f868 | ||
| 
						 | 
					d4857a1727 | ||
| 
						 | 
					0c032bc431 | ||
| 
						 | 
					5a103543c4 | ||
| 
						 | 
					01ab6d3ddc | ||
| 
						 | 
					f2170c633a | ||
| 
						 | 
					c2e52f4b11 | ||
| 
						 | 
					4843bbd38a | ||
| 
						 | 
					78ce8f014a | ||
| 
						 | 
					b454f63b36 | ||
| 
						 | 
					db644542ed | ||
| 
						 | 
					716a8b87e1 | ||
| 
						 | 
					0f4e274e52 | ||
| 
						 | 
					576dbd6f0c | ||
| 
						 | 
					c3d00b45f7 | ||
| 
						 | 
					98b872abc7 | ||
| 
						 | 
					75026be951 | ||
| 
						 | 
					47a0ec467a | ||
| 
						 | 
					9e40d4cf45 | ||
| 
						 | 
					fecae2f740 | ||
| 
						 | 
					5a01670803 | ||
| 
						 | 
					c2423b18cb | ||
| 
						 | 
					2363b3dfd6 | ||
| 
						 | 
					628e47f670 | ||
| 
						 | 
					7666581c54 | ||
| 
						 | 
					03c36920ff | ||
| 
						 | 
					abdd6b232f | ||
| 
						 | 
					07be7ad7e2 | ||
| 
						 | 
					820e3488d0 | ||
| 
						 | 
					8c6c45e6c1 | ||
| 
						 | 
					16bf56b0f9 | ||
| 
						 | 
					49c01c26f1 | ||
| 
						 | 
					b4a804cc77 | ||
| 
						 | 
					df26ace0f1 | ||
| 
						 | 
					e779a8bcb2 | ||
| 
						 | 
					c458fd18df | ||
| 
						 | 
					98817a5bbf | ||
| 
						 | 
					c43d8460bd | ||
| 
						 | 
					17b88f2e3e | ||
| 
						 | 
					dac9768f6a | ||
| 
						 | 
					e8d2ad4ce8 | ||
| 
						 | 
					c3412df169 | ||
| 
						 | 
					fc2b15e307 | ||
| 
						 | 
					bdb1094b47 | ||
| 
						 | 
					6262fb8fcf | ||
| 
						 | 
					f319472066 | ||
| 
						 | 
					b4a2b50ee0 | ||
| 
						 | 
					30bb806f26 | ||
| 
						 | 
					9874d17613 | ||
| 
						 | 
					13909b7994 | ||
| 
						 | 
					df50e57409 | ||
| 
						 | 
					3fa67fad32 | ||
| 
						 | 
					8fbd512952 | ||
| 
						 | 
					528d3672b4 | ||
| 
						 | 
					fef50afef8 | ||
| 
						 | 
					aa1879082c | ||
| 
						 | 
					d8c943972b | ||
| 
						 | 
					f3ebb4eb39 | ||
| 
						 | 
					f1c0570e3b | ||
| 
						 | 
					aa87c60717 | ||
| 
						 | 
					92a8ebe1f8 | ||
| 
						 | 
					dd3ffc7f29 | ||
| 
						 | 
					aac3841991 | ||
| 
						 | 
					fb87a1c0bc | ||
| 
						 | 
					4409471cd1 | ||
| 
						 | 
					739edce268 | ||
| 
						 | 
					f25f3334d1 | ||
| 
						 | 
					571935fb3b | ||
| 
						 | 
					7c39422692 | ||
| 
						 | 
					731fb1d172 | ||
| 
						 | 
					40bee2a854 | ||
| 
						 | 
					d69926485c | ||
| 
						 | 
					fe80750743 | ||
| 
						 | 
					109d737d5d | ||
| 
						 | 
					bd17ee8e33 | ||
| 
						 | 
					f1712cffa8 | ||
| 
						 | 
					0df6a913b3 | ||
| 
						 | 
					8a98b69a57 | ||
| 
						 | 
					4530e4d60f | ||
| 
						 | 
					4d7c6b28e1 | ||
| 
						 | 
					de603c7565 | ||
| 
						 | 
					a498fb5dcf | ||
| 
						 | 
					78543e1e15 | ||
| 
						 | 
					5e72b7196b | ||
| 
						 | 
					a0615a92f0 | ||
| 
						 | 
					dc5b408748 | ||
| 
						 | 
					387bde665e | ||
| 
						 | 
					45beea68eb | ||
| 
						 | 
					c457d8835e | ||
| 
						 | 
					4b51ba3fa4 | ||
| 
						 | 
					499953e3f4 | ||
| 
						 | 
					69f1a81e1d | ||
| 
						 | 
					37fcccbb1c | ||
| 
						 | 
					f3cb179f54 | ||
| 
						 | 
					ba2edbc189 | ||
| 
						 | 
					f33b4a714e | ||
| 
						 | 
					85d863601b | ||
| 
						 | 
					fe0700166a | ||
| 
						 | 
					d28cf011d1 | ||
| 
						 | 
					434879ea04 | ||
| 
						 | 
					7da07303c9 | ||
| 
						 | 
					b33b4481ea | ||
| 
						 | 
					ac631711ab | ||
| 
						 | 
					265b6ec445 | ||
| 
						 | 
					61499dbdd8 | ||
| 
						 | 
					0aaef9293b | ||
| 
						 | 
					0f0b829bc6 | ||
| 
						 | 
					a9d883b65a | ||
| 
						 | 
					d330e73c1e | ||
| 
						 | 
					7554e954fe | ||
| 
						 | 
					752af94a75 | ||
| 
						 | 
					561d92d402 | ||
| 
						 | 
					1a69236473 | ||
| 
						 | 
					c86ea99145 | ||
| 
						 | 
					7661609049 | ||
| 
						 | 
					c38826824f | ||
| 
						 | 
					e890486043 | ||
| 
						 | 
					ccc9fd4a3f | ||
| 
						 | 
					54fbf5184e | ||
| 
						 | 
					759df7ae6c | ||
| 
						 | 
					3d56397e58 | ||
| 
						 | 
					9f6c64afa6 | ||
| 
						 | 
					663e18310d | ||
| 
						 | 
					1a89aa8fbf | ||
| 
						 | 
					e04743e381 | ||
| 
						 | 
					a6957b9d3b | ||
| 
						 | 
					9816c27031 | ||
| 
						 | 
					ea06740b46 | ||
| 
						 | 
					9a5ec1b9e6 | ||
| 
						 | 
					6dcbd1a8ae | ||
| 
						 | 
					63b0930ae8 | ||
| 
						 | 
					5382bd2a97 | ||
| 
						 | 
					de1fbd390b | ||
| 
						 | 
					af23357dca | ||
| 
						 | 
					0fbe6c0d8b | ||
| 
						 | 
					4e1ff31342 | ||
| 
						 | 
					df4224e779 | ||
| 
						 | 
					5877c57a35 | ||
| 
						 | 
					7f2ca800c1 | ||
| 
						 | 
					ce7ff15c8a | ||
| 
						 | 
					88742e0399 | ||
| 
						 | 
					c187cb547c | ||
| 
						 | 
					42bc960a36 | ||
| 
						 | 
					ba63d266d8 | ||
| 
						 | 
					90baba4db7 | ||
| 
						 | 
					1656ced351 | ||
| 
						 | 
					1dfd15e607 | ||
| 
						 | 
					5dcaf1241f | ||
| 
						 | 
					7aa54b6879 | ||
| 
						 | 
					444e162c92 | ||
| 
						 | 
					bb27eaaf1e | ||
| 
						 | 
					517f659da8 | ||
| 
						 | 
					5a92e24662 | ||
| 
						 | 
					437b236a4d | ||
| 
						 | 
					14eac3dbce | ||
| 
						 | 
					132a096ae7 | ||
| 
						 | 
					440080a753 | ||
| 
						 | 
					f15e3cfb9b | ||
| 
						 | 
					9d000e9abf | ||
| 
						 | 
					97fd7493b5 | ||
| 
						 | 
					4c87658503 | ||
| 
						 | 
					c80e035bd5 | ||
| 
						 | 
					c8ec0bb7ea | ||
| 
						 | 
					86ae1c5931 | ||
| 
						 | 
					d0958f7cf2 | ||
| 
						 | 
					982ce1db72 | ||
| 
						 | 
					f042c6e643 | ||
| 
						 | 
					5fcd26bfe9 | ||
| 
						 | 
					5717d557f5 | ||
| 
						 | 
					3bac45e737 | ||
| 
						 | 
					e623989878 | ||
| 
						 | 
					39cbc6b183 | ||
| 
						 | 
					749a5e3348 | ||
| 
						 | 
					b0e3ac01e8 | ||
| 
						 | 
					58123845ff | ||
| 
						 | 
					bfd75d736c | ||
| 
						 | 
					4e3195b474 | ||
| 
						 | 
					d3a71a1d45 | ||
| 
						 | 
					555bdac604 | ||
| 
						 | 
					acc8d24a32 | ||
| 
						 | 
					f3cc1e541a | ||
| 
						 | 
					ece72c6b18 | ||
| 
						 | 
					4e839d42d0 | ||
| 
						 | 
					d429aa8bb8 | ||
| 
						 | 
					472402745d | ||
| 
						 | 
					016fac2496 | ||
| 
						 | 
					79478cdb8a | ||
| 
						 | 
					dbed74b50d | ||
| 
						 | 
					d00ec7e544 | ||
| 
						 | 
					a37ff2dbd9 | ||
| 
						 | 
					00ddb0a427 | ||
| 
						 | 
					c95887a14a | ||
| 
						 | 
					dc5942a59b | ||
| 
						 | 
					584dbf2668 | ||
| 
						 | 
					9c8976be13 | ||
| 
						 | 
					e08a9cc3a3 | ||
| 
						 | 
					b79a3d6727 | ||
| 
						 | 
					fb96e3588d | ||
| 
						 | 
					edd847ea40 | ||
| 
						 | 
					83d6834e27 | ||
| 
						 | 
					8f69d07061 | ||
| 
						 | 
					30477c764d | ||
| 
						 | 
					217a80a178 | ||
| 
						 | 
					5486b40aab | ||
| 
						 | 
					beb8ab50e2 | ||
| 
						 | 
					7cdf5b55ef | ||
| 
						 | 
					c9b0490305 | ||
| 
						 | 
					d305870284 | ||
| 
						 | 
					ff5004d7db | ||
| 
						 | 
					7aa3a1a1cc | ||
| 
						 | 
					e124151e5c | ||
| 
						 | 
					e229ed0da3 | ||
| 
						 | 
					12cdeca48a | ||
| 
						 | 
					a825ef59d4 | ||
| 
						 | 
					65a5216d17 | ||
| 
						 | 
					567256bd62 | ||
| 
						 | 
					4da57c35d0 | ||
| 
						 | 
					f2e8e655ba | ||
| 
						 | 
					8439232b11 | ||
| 
						 | 
					e6c730ab10 | ||
| 
						 | 
					e49df765d2 | ||
| 
						 | 
					e6da55b925 | ||
| 
						 | 
					c894645747 | ||
| 
						 | 
					2539cba610 | ||
| 
						 | 
					5ddbe5cdba | ||
| 
						 | 
					4c7552eca4 | ||
| 
						 | 
					72bf0086e4 | ||
| 
						 | 
					1b91e0027b | ||
| 
						 | 
					e9851e7eb2 | ||
| 
						 | 
					80fedbc1a5 | ||
| 
						 | 
					a4a71797d9 | ||
| 
						 | 
					4a97064b2c | ||
| 
						 | 
					a3ef2ed7fd | ||
| 
						 | 
					3a8b41daa3 | ||
| 
						 | 
					921be1a17c | ||
| 
						 | 
					e3d673d16c | ||
| 
						 | 
					39f3f795e2 | ||
| 
						 | 
					53691d28a8 | ||
| 
						 | 
					3730b0310b | ||
| 
						 | 
					2b9013699d | ||
| 
						 | 
					be78827274 | ||
| 
						 | 
					cd1ee96606 | ||
| 
						 | 
					2fa8d907b3 | ||
| 
						 | 
					4c383906c4 | ||
| 
						 | 
					bdc6302ea1 | ||
| 
						 | 
					31c13e4c16 | ||
| 
						 | 
					6b59f55a50 | ||
| 
						 | 
					e6bd2238ce | ||
| 
						 | 
					2d4688a206 | ||
| 
						 | 
					536bcab5de | ||
| 
						 | 
					1c2d2bce5a | ||
| 
						 | 
					2eac8b6c46 | ||
| 
						 | 
					6e50e2aa65 | ||
| 
						 | 
					841d278224 | ||
| 
						 | 
					11076e4614 | ||
| 
						 | 
					72df3d1606 | ||
| 
						 | 
					ae6736311a | ||
| 
						 | 
					c0dcecc465 | ||
| 
						 | 
					d9d368d38e | ||
| 
						 | 
					a70cee1dc1 | ||
| 
						 | 
					f4766ab74f | ||
| 
						 | 
					4fbf41472a | ||
| 
						 | 
					6ee02c47c2 | ||
| 
						 | 
					140d77061b | ||
| 
						 | 
					d6f4f05090 | ||
| 
						 | 
					bdb91112ea | ||
| 
						 | 
					b027b6a711 | ||
| 
						 | 
					89ecfc2004 | ||
| 
						 | 
					cf835d1580 | ||
| 
						 | 
					17a09cd221 | ||
| 
						 | 
					1bd2d41ffd | ||
| 
						 | 
					aa6cea6f7e | ||
| 
						 | 
					ebf895990b | ||
| 
						 | 
					46a435f5f2 | ||
| 
						 | 
					6c548a1596 | ||
| 
						 | 
					7f75f2135d | ||
| 
						 | 
					c49f7293fe | ||
| 
						 | 
					71496574e9 | ||
| 
						 | 
					b95b4a0694 | ||
| 
						 | 
					59653ec785 | ||
| 
						 | 
					e02f3cdac7 | ||
| 
						 | 
					d4d630823c | ||
| 
						 | 
					9fc1377b44 | ||
| 
						 | 
					e3e3d92347 | ||
| 
						 | 
					13077095c2 | ||
| 
						 | 
					4001d82ca2 | ||
| 
						 | 
					4936ca1700 | ||
| 
						 | 
					2ecd5cff07 | ||
| 
						 | 
					dea297c8d7 | ||
| 
						 | 
					ef7c5c6055 | ||
| 
						 | 
					ee3cfb2b76 | ||
| 
						 | 
					2cc2a2153b | ||
| 
						 | 
					e51f3d9498 | ||
| 
						 | 
					1c1f3f7c55 | ||
| 
						 | 
					ea424b0699 | ||
| 
						 | 
					489d0d20d2 | ||
| 
						 | 
					f04e3de7b8 | ||
| 
						 | 
					a0693060e4 | ||
| 
						 | 
					888b237964 | ||
| 
						 | 
					122ff731ef | ||
| 
						 | 
					3232866dc3 | ||
| 
						 | 
					ccf2854b61 | ||
| 
						 | 
					03ae6b2c1b | ||
| 
						 | 
					6bcbbcce02 | ||
| 
						 | 
					fbb9967117 | ||
| 
						 | 
					6d4f787f67 | ||
| 
						 | 
					5e27a8df1f | ||
| 
						 | 
					846b091aac | ||
| 
						 | 
					372d68a177 | ||
| 
						 | 
					4fc19902ab | ||
| 
						 | 
					9a7d5dcad8 | ||
| 
						 | 
					ef78c404dd | ||
| 
						 | 
					c857f98557 | ||
| 
						 | 
					01a24de3a8 | ||
| 
						 | 
					ae46dcef7e | ||
| 
						 | 
					872b8ee753 | ||
| 
						 | 
					eb8a2326ad | ||
| 
						 | 
					cf63d627fe | ||
| 
						 | 
					49e9c43339 | ||
| 
						 | 
					f1dc9537ff | ||
| 
						 | 
					1ad535d030 | ||
| 
						 | 
					1ed27b7cc0 | ||
| 
						 | 
					585586780b | ||
| 
						 | 
					50aeefc662 | ||
| 
						 | 
					6e41c22e9d | ||
| 
						 | 
					e81191ebd2 | ||
| 
						 | 
					b29c119408 | ||
| 
						 | 
					e819185de1 | ||
| 
						 | 
					00465f4a6f | ||
| 
						 | 
					f4dc11477f | ||
| 
						 | 
					754352b4d7 | ||
| 
						 | 
					67a4e56fcf | ||
| 
						 | 
					9bc7b74d01 | ||
| 
						 | 
					15bfc4c91f | ||
| 
						 | 
					a0159a2746 | ||
| 
						 | 
					44545a18a0 | ||
| 
						 | 
					0b51ec2c88 | ||
| 
						 | 
					5e62c489b0 | ||
| 
						 | 
					d015088855 | ||
| 
						 | 
					39c889e662 | ||
| 
						 | 
					c7c8711c9c | ||
| 
						 | 
					0a92405f2d | ||
| 
						 | 
					b4b6b75e84 | ||
| 
						 | 
					a2cab960a9 | ||
| 
						 | 
					1f7f03f563 | ||
| 
						 | 
					80226694d5 | ||
| 
						 | 
					053465d3f6 | ||
| 
						 | 
					7d75c9157b | ||
| 
						 | 
					b367c01b4b | ||
| 
						 | 
					e6a1254e65 | ||
| 
						 | 
					1e80c4807e | ||
| 
						 | 
					928b39f495 | ||
| 
						 | 
					58d028ac13 | ||
| 
						 | 
					a2dccc4730 | ||
| 
						 | 
					ffee2f0e88 | ||
| 
						 | 
					d885d65c9b | ||
| 
						 | 
					c35240ca32 | ||
| 
						 | 
					7c00c5db70 | ||
| 
						 | 
					335faf858b | ||
| 
						 | 
					1829e68730 | ||
| 
						 | 
					b8eadb2ba5 | ||
| 
						 | 
					551ea37882 | ||
| 
						 | 
					3a25eaca3f | ||
| 
						 | 
					e85cbf26f8 | ||
| 
						 | 
					2ec17eed58 | ||
| 
						 | 
					2f77d31690 | ||
| 
						 | 
					3f123d7542 | ||
| 
						 | 
					d189cc1fbe | ||
| 
						 | 
					c0658ffe2c | ||
| 
						 | 
					248b0bc378 | ||
| 
						 | 
					80b4c26481 | ||
| 
						 | 
					5bb4d042e4 | ||
| 
						 | 
					dcc537d0d4 | ||
| 
						 | 
					2dca3d79e4 | ||
| 
						 | 
					01497c891d | ||
| 
						 | 
					77bb46ff3b | ||
| 
						 | 
					cefbfb75bd | ||
| 
						 | 
					749b942132 | ||
| 
						 | 
					a043022444 | ||
| 
						 | 
					8b7e061f3a | ||
| 
						 | 
					74ea1b60e3 | ||
| 
						 | 
					5a2fed3569 | ||
| 
						 | 
					e85157db4b | ||
| 
						 | 
					d3563e4e97 | ||
| 
						 | 
					765579dabb | ||
| 
						 | 
					6afd004ec5 | ||
| 
						 | 
					ee3ee3a63b | ||
| 
						 | 
					aae2ee2ecb | ||
| 
						 | 
					bac6880a1e | ||
| 
						 | 
					0982ab58ac | ||
| 
						 | 
					38dd566e0c | ||
| 
						 | 
					71e1e3b5f8 | ||
| 
						 | 
					abbd7faa64 | ||
| 
						 | 
					aa0e155e22 | ||
| 
						 | 
					0dab280440 | ||
| 
						 | 
					90b076eccd | ||
| 
						 | 
					444c0fc67f | ||
| 
						 | 
					302ba2874e | ||
| 
						 | 
					df750d0d11 | ||
| 
						 | 
					63e4d4b493 | ||
| 
						 | 
					88627095fb | ||
| 
						 | 
					858d97ccef | ||
| 
						 | 
					22f30d42a6 | ||
| 
						 | 
					1e2497748d | ||
| 
						 | 
					34de2bbe99 | ||
| 
						 | 
					21cb941bbe | ||
| 
						 | 
					33fdbbe30c | ||
| 
						 | 
					09f9d91577 | ||
| 
						 | 
					34a8eaddb2 | ||
| 
						 | 
					7dbda12008 | ||
| 
						 | 
					4101d5dad1 | ||
| 
						 | 
					c20e1975d1 | ||
| 
						 | 
					4fa3c6915c | ||
| 
						 | 
					ca5c73d170 | ||
| 
						 | 
					5b5c2fe71b | ||
| 
						 | 
					9acc21e81a | ||
| 
						 | 
					bff0e81ed3 | ||
| 
						 | 
					2feffddc55 | ||
| 
						 | 
					4289e00ad0 | ||
| 
						 | 
					574ee404d2 | ||
| 
						 | 
					9caf5f8b31 | ||
| 
						 | 
					127acfde64 | ||
| 
						 | 
					156ad773c9 | ||
| 
						 | 
					8d90d256bf | ||
| 
						 | 
					833565feb9 | ||
| 
						 | 
					fdebf04196 | ||
| 
						 | 
					dd8d25e43f | ||
| 
						 | 
					68844c4869 | ||
| 
						 | 
					7c0543862a | ||
| 
						 | 
					a932ca2f64 | ||
| 
						 | 
					2597975ae0 | ||
| 
						 | 
					6330177d24 | ||
| 
						 | 
					3ac730fb2f | ||
| 
						 | 
					ff48f53989 | ||
| 
						 | 
					8bb4316956 | ||
| 
						 | 
					40cdb778f5 | ||
| 
						 | 
					dfd174e1a5 | ||
| 
						 | 
					735c04cd69 | ||
| 
						 | 
					d95b370998 | ||
| 
						 | 
					3ebdd62c67 | ||
| 
						 | 
					c26c96b8f4 | ||
| 
						 | 
					748256b3ee | ||
| 
						 | 
					10791db82e | ||
| 
						 | 
					3dd34f6628 | ||
| 
						 | 
					7004053538 | ||
| 
						 | 
					dc42427c60 | ||
| 
						 | 
					40ad6befa8 | ||
| 
						 | 
					612e2c1644 | ||
| 
						 | 
					c8d0cde329 | ||
| 
						 | 
					5e8794175d | ||
| 
						 | 
					657527655d | ||
| 
						 | 
					f7543a7b8d | ||
| 
						 | 
					43a020641b | ||
| 
						 | 
					c019ff34bc | ||
| 
						 | 
					ef6ccddc0d | ||
| 
						 | 
					8bbe4efded | ||
| 
						 | 
					f490585f66 | ||
| 
						 | 
					fcfc76b01b | ||
| 
						 | 
					5ad68e926d | ||
| 
						 | 
					56fa6fef85 | ||
| 
						 | 
					c9e5919739 | ||
| 
						 | 
					0451b31f9e | ||
| 
						 | 
					1c845e0ff8 | ||
| 
						 | 
					22478ffb0f | ||
| 
						 | 
					c38cc128db | ||
| 
						 | 
					fa01149771 | ||
| 
						 | 
					254522dd93 | ||
| 
						 | 
					6a86d92781 | ||
| 
						 | 
					b274d6901a | ||
| 
						 | 
					3ef31e55ca | ||
| 
						 | 
					fb002ac3b0 | ||
| 
						 | 
					de943908bd | ||
| 
						 | 
					b0a25872da | ||
| 
						 | 
					403d450f47 | ||
| 
						 | 
					d6b96ad51d | ||
| 
						 | 
					9b4b50a3a6 | ||
| 
						 | 
					2cca26ada4 | ||
| 
						 | 
					312799babf | ||
| 
						 | 
					5bc5a9dcb6 | ||
| 
						 | 
					39e922580a | ||
| 
						 | 
					77d0bfc4bb | ||
| 
						 | 
					654cee6f83 | ||
| 
						 | 
					cf14c02b8a | ||
| 
						 | 
					42f6095960 | ||
| 
						 | 
					f224984858 | ||
| 
						 | 
					efe4c5e3bc | ||
| 
						 | 
					cedb671f07 | ||
| 
						 | 
					c18bd3ac81 | ||
| 
						 | 
					b08432bd0d | ||
| 
						 | 
					4bac9707fe | ||
| 
						 | 
					7e16cda949 | ||
| 
						 | 
					1c05f5af03 | 
							
								
								
									
										36
									
								
								.clang-tidy
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								.clang-tidy
									
									
									
									
									
								
							@@ -7,28 +7,39 @@ Checks: >-
 | 
				
			|||||||
  -boost-*,
 | 
					  -boost-*,
 | 
				
			||||||
  -bugprone-easily-swappable-parameters,
 | 
					  -bugprone-easily-swappable-parameters,
 | 
				
			||||||
  -bugprone-implicit-widening-of-multiplication-result,
 | 
					  -bugprone-implicit-widening-of-multiplication-result,
 | 
				
			||||||
 | 
					  -bugprone-multi-level-implicit-pointer-conversion,
 | 
				
			||||||
  -bugprone-narrowing-conversions,
 | 
					  -bugprone-narrowing-conversions,
 | 
				
			||||||
  -bugprone-signed-char-misuse,
 | 
					  -bugprone-signed-char-misuse,
 | 
				
			||||||
 | 
					  -bugprone-switch-missing-default-case,
 | 
				
			||||||
  -cert-dcl50-cpp,
 | 
					  -cert-dcl50-cpp,
 | 
				
			||||||
  -cert-err33-c,
 | 
					  -cert-err33-c,
 | 
				
			||||||
  -cert-err58-cpp,
 | 
					  -cert-err58-cpp,
 | 
				
			||||||
  -cert-oop57-cpp,
 | 
					  -cert-oop57-cpp,
 | 
				
			||||||
  -cert-str34-c,
 | 
					  -cert-str34-c,
 | 
				
			||||||
 | 
					  -clang-analyzer-optin.core.EnumCastOutOfRange,
 | 
				
			||||||
  -clang-analyzer-optin.cplusplus.UninitializedObject,
 | 
					  -clang-analyzer-optin.cplusplus.UninitializedObject,
 | 
				
			||||||
  -clang-analyzer-osx.*,
 | 
					  -clang-analyzer-osx.*,
 | 
				
			||||||
  -clang-diagnostic-delete-abstract-non-virtual-dtor,
 | 
					  -clang-diagnostic-delete-abstract-non-virtual-dtor,
 | 
				
			||||||
  -clang-diagnostic-delete-non-abstract-non-virtual-dtor,
 | 
					  -clang-diagnostic-delete-non-abstract-non-virtual-dtor,
 | 
				
			||||||
 | 
					  -clang-diagnostic-deprecated-declarations,
 | 
				
			||||||
  -clang-diagnostic-ignored-optimization-argument,
 | 
					  -clang-diagnostic-ignored-optimization-argument,
 | 
				
			||||||
 | 
					  -clang-diagnostic-missing-field-initializers,
 | 
				
			||||||
  -clang-diagnostic-shadow-field,
 | 
					  -clang-diagnostic-shadow-field,
 | 
				
			||||||
  -clang-diagnostic-unused-const-variable,
 | 
					  -clang-diagnostic-unused-const-variable,
 | 
				
			||||||
  -clang-diagnostic-unused-parameter,
 | 
					  -clang-diagnostic-unused-parameter,
 | 
				
			||||||
 | 
					  -clang-diagnostic-vla-cxx-extension,
 | 
				
			||||||
  -concurrency-*,
 | 
					  -concurrency-*,
 | 
				
			||||||
  -cppcoreguidelines-avoid-c-arrays,
 | 
					  -cppcoreguidelines-avoid-c-arrays,
 | 
				
			||||||
 | 
					  -cppcoreguidelines-avoid-const-or-ref-data-members,
 | 
				
			||||||
 | 
					  -cppcoreguidelines-avoid-do-while,
 | 
				
			||||||
  -cppcoreguidelines-avoid-magic-numbers,
 | 
					  -cppcoreguidelines-avoid-magic-numbers,
 | 
				
			||||||
  -cppcoreguidelines-init-variables,
 | 
					  -cppcoreguidelines-init-variables,
 | 
				
			||||||
 | 
					  -cppcoreguidelines-macro-to-enum,
 | 
				
			||||||
  -cppcoreguidelines-macro-usage,
 | 
					  -cppcoreguidelines-macro-usage,
 | 
				
			||||||
 | 
					  -cppcoreguidelines-missing-std-forward,
 | 
				
			||||||
  -cppcoreguidelines-narrowing-conversions,
 | 
					  -cppcoreguidelines-narrowing-conversions,
 | 
				
			||||||
  -cppcoreguidelines-non-private-member-variables-in-classes,
 | 
					  -cppcoreguidelines-non-private-member-variables-in-classes,
 | 
				
			||||||
 | 
					  -cppcoreguidelines-owning-memory,
 | 
				
			||||||
  -cppcoreguidelines-prefer-member-initializer,
 | 
					  -cppcoreguidelines-prefer-member-initializer,
 | 
				
			||||||
  -cppcoreguidelines-pro-bounds-array-to-pointer-decay,
 | 
					  -cppcoreguidelines-pro-bounds-array-to-pointer-decay,
 | 
				
			||||||
  -cppcoreguidelines-pro-bounds-constant-array-index,
 | 
					  -cppcoreguidelines-pro-bounds-constant-array-index,
 | 
				
			||||||
@@ -40,7 +51,9 @@ Checks: >-
 | 
				
			|||||||
  -cppcoreguidelines-pro-type-static-cast-downcast,
 | 
					  -cppcoreguidelines-pro-type-static-cast-downcast,
 | 
				
			||||||
  -cppcoreguidelines-pro-type-union-access,
 | 
					  -cppcoreguidelines-pro-type-union-access,
 | 
				
			||||||
  -cppcoreguidelines-pro-type-vararg,
 | 
					  -cppcoreguidelines-pro-type-vararg,
 | 
				
			||||||
 | 
					  -cppcoreguidelines-rvalue-reference-param-not-moved,
 | 
				
			||||||
  -cppcoreguidelines-special-member-functions,
 | 
					  -cppcoreguidelines-special-member-functions,
 | 
				
			||||||
 | 
					  -cppcoreguidelines-use-default-member-init,
 | 
				
			||||||
  -cppcoreguidelines-virtual-class-destructor,
 | 
					  -cppcoreguidelines-virtual-class-destructor,
 | 
				
			||||||
  -fuchsia-multiple-inheritance,
 | 
					  -fuchsia-multiple-inheritance,
 | 
				
			||||||
  -fuchsia-overloaded-operator,
 | 
					  -fuchsia-overloaded-operator,
 | 
				
			||||||
@@ -60,20 +73,32 @@ Checks: >-
 | 
				
			|||||||
  -llvm-include-order,
 | 
					  -llvm-include-order,
 | 
				
			||||||
  -llvm-qualified-auto,
 | 
					  -llvm-qualified-auto,
 | 
				
			||||||
  -llvmlibc-*,
 | 
					  -llvmlibc-*,
 | 
				
			||||||
  -misc-non-private-member-variables-in-classes,
 | 
					  -misc-const-correctness,
 | 
				
			||||||
 | 
					  -misc-include-cleaner,
 | 
				
			||||||
  -misc-no-recursion,
 | 
					  -misc-no-recursion,
 | 
				
			||||||
 | 
					  -misc-non-private-member-variables-in-classes,
 | 
				
			||||||
  -misc-unused-parameters,
 | 
					  -misc-unused-parameters,
 | 
				
			||||||
  -modernize-avoid-c-arrays,
 | 
					  -misc-use-anonymous-namespace,
 | 
				
			||||||
  -modernize-avoid-bind,
 | 
					  -modernize-avoid-bind,
 | 
				
			||||||
 | 
					  -modernize-avoid-c-arrays,
 | 
				
			||||||
  -modernize-concat-nested-namespaces,
 | 
					  -modernize-concat-nested-namespaces,
 | 
				
			||||||
 | 
					  -modernize-macro-to-enum,
 | 
				
			||||||
  -modernize-return-braced-init-list,
 | 
					  -modernize-return-braced-init-list,
 | 
				
			||||||
 | 
					  -modernize-type-traits,
 | 
				
			||||||
  -modernize-use-auto,
 | 
					  -modernize-use-auto,
 | 
				
			||||||
 | 
					  -modernize-use-constraints,
 | 
				
			||||||
  -modernize-use-default-member-init,
 | 
					  -modernize-use-default-member-init,
 | 
				
			||||||
  -modernize-use-equals-default,
 | 
					  -modernize-use-equals-default,
 | 
				
			||||||
  -modernize-use-trailing-return-type,
 | 
					 | 
				
			||||||
  -modernize-use-nodiscard,
 | 
					  -modernize-use-nodiscard,
 | 
				
			||||||
 | 
					  -modernize-use-nullptr,
 | 
				
			||||||
 | 
					  -modernize-use-nodiscard,
 | 
				
			||||||
 | 
					  -modernize-use-nullptr,
 | 
				
			||||||
 | 
					  -modernize-use-trailing-return-type,
 | 
				
			||||||
  -mpi-*,
 | 
					  -mpi-*,
 | 
				
			||||||
  -objc-*,
 | 
					  -objc-*,
 | 
				
			||||||
 | 
					  -performance-enum-size,
 | 
				
			||||||
 | 
					  -readability-avoid-nested-conditional-operator,
 | 
				
			||||||
 | 
					  -readability-container-contains,
 | 
				
			||||||
  -readability-container-data-pointer,
 | 
					  -readability-container-data-pointer,
 | 
				
			||||||
  -readability-convert-member-functions-to-static,
 | 
					  -readability-convert-member-functions-to-static,
 | 
				
			||||||
  -readability-else-after-return,
 | 
					  -readability-else-after-return,
 | 
				
			||||||
@@ -82,11 +107,14 @@ Checks: >-
 | 
				
			|||||||
  -readability-isolate-declaration,
 | 
					  -readability-isolate-declaration,
 | 
				
			||||||
  -readability-magic-numbers,
 | 
					  -readability-magic-numbers,
 | 
				
			||||||
  -readability-make-member-function-const,
 | 
					  -readability-make-member-function-const,
 | 
				
			||||||
 | 
					  -readability-named-parameter,
 | 
				
			||||||
 | 
					  -readability-redundant-casting,
 | 
				
			||||||
 | 
					  -readability-redundant-inline-specifier,
 | 
				
			||||||
 | 
					  -readability-redundant-member-init,
 | 
				
			||||||
  -readability-redundant-string-init,
 | 
					  -readability-redundant-string-init,
 | 
				
			||||||
  -readability-uppercase-literal-suffix,
 | 
					  -readability-uppercase-literal-suffix,
 | 
				
			||||||
  -readability-use-anyofallof,
 | 
					  -readability-use-anyofallof,
 | 
				
			||||||
WarningsAsErrors: '*'
 | 
					WarningsAsErrors: '*'
 | 
				
			||||||
AnalyzeTemporaryDtors: false
 | 
					 | 
				
			||||||
FormatStyle:     google
 | 
					FormatStyle:     google
 | 
				
			||||||
CheckOptions:
 | 
					CheckOptions:
 | 
				
			||||||
  - key:             google-readability-function-size.StatementThreshold
 | 
					  - key:             google-readability-function-size.StatementThreshold
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,2 +1,4 @@
 | 
				
			|||||||
[run]
 | 
					[run]
 | 
				
			||||||
omit = esphome/components/*
 | 
					omit = 
 | 
				
			||||||
 | 
					    esphome/components/*
 | 
				
			||||||
 | 
					    tests/integration/*
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										37
									
								
								.devcontainer/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								.devcontainer/Dockerfile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					ARG BUILD_BASE_VERSION=2025.04.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FROM ghcr.io/esphome/docker-base:debian-${BUILD_BASE_VERSION} AS base
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN git config --system --add safe.directory "*"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN apt update \
 | 
				
			||||||
 | 
					    && apt install -y \
 | 
				
			||||||
 | 
					      protobuf-compiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN pip install uv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN useradd esphome -m
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USER esphome
 | 
				
			||||||
 | 
					ENV VIRTUAL_ENV=/home/esphome/.local/esphome-venv
 | 
				
			||||||
 | 
					RUN uv venv $VIRTUAL_ENV
 | 
				
			||||||
 | 
					ENV PATH="$VIRTUAL_ENV/bin:$PATH"
 | 
				
			||||||
 | 
					# Override this set to true in the docker-base image
 | 
				
			||||||
 | 
					ENV UV_SYSTEM_PYTHON=false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WORKDIR /tmp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COPY requirements.txt ./
 | 
				
			||||||
 | 
					RUN uv pip install -r requirements.txt
 | 
				
			||||||
 | 
					COPY requirements_dev.txt requirements_test.txt ./
 | 
				
			||||||
 | 
					RUN uv pip install -r requirements_dev.txt -r requirements_test.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN \
 | 
				
			||||||
 | 
					    platformio settings set enable_telemetry No \
 | 
				
			||||||
 | 
					    && platformio settings set check_platformio_interval 1000000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COPY script/platformio_install_deps.py platformio.ini ./
 | 
				
			||||||
 | 
					RUN ./platformio_install_deps.py platformio.ini --libraries --platforms --tools
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WORKDIR /workspaces
 | 
				
			||||||
@@ -1,18 +1,17 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "ESPHome Dev",
 | 
					  "name": "ESPHome Dev",
 | 
				
			||||||
  "image": "ghcr.io/esphome/esphome-lint:dev",
 | 
					  "context": "..",
 | 
				
			||||||
 | 
					  "dockerFile": "Dockerfile",
 | 
				
			||||||
  "postCreateCommand": [
 | 
					  "postCreateCommand": [
 | 
				
			||||||
    "script/devcontainer-post-create"
 | 
					    "script/devcontainer-post-create"
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  "containerEnv": {
 | 
					  "features": {
 | 
				
			||||||
    "DEVCONTAINER": "1",
 | 
					    "ghcr.io/devcontainers/features/github-cli:1": {}
 | 
				
			||||||
    "PIP_BREAK_SYSTEM_PACKAGES": "1",
 | 
					 | 
				
			||||||
    "PIP_ROOT_USER_ACTION": "ignore"
 | 
					 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "runArgs": [
 | 
					  "runArgs": [
 | 
				
			||||||
    "--privileged",
 | 
					    "--privileged",
 | 
				
			||||||
    "-e",
 | 
					    "-e",
 | 
				
			||||||
    "ESPHOME_DASHBOARD_USE_PING=1"
 | 
					    "GIT_EDITOR=code --wait"
 | 
				
			||||||
    // uncomment and edit the path in order to pass though local USB serial to the conatiner
 | 
					    // uncomment and edit the path in order to pass though local USB serial to the conatiner
 | 
				
			||||||
    // , "--device=/dev/ttyACM0"
 | 
					    // , "--device=/dev/ttyACM0"
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
@@ -31,7 +30,7 @@
 | 
				
			|||||||
        "ms-python.python",
 | 
					        "ms-python.python",
 | 
				
			||||||
        "ms-python.pylint",
 | 
					        "ms-python.pylint",
 | 
				
			||||||
        "ms-python.flake8",
 | 
					        "ms-python.flake8",
 | 
				
			||||||
        "ms-python.black-formatter",
 | 
					        "charliermarsh.ruff",
 | 
				
			||||||
        "visualstudioexptteam.vscodeintellicode",
 | 
					        "visualstudioexptteam.vscodeintellicode",
 | 
				
			||||||
        // yaml
 | 
					        // yaml
 | 
				
			||||||
        "redhat.vscode-yaml",
 | 
					        "redhat.vscode-yaml",
 | 
				
			||||||
@@ -49,14 +48,11 @@
 | 
				
			|||||||
        "flake8.args": [
 | 
					        "flake8.args": [
 | 
				
			||||||
          "--config=${workspaceFolder}/.flake8"
 | 
					          "--config=${workspaceFolder}/.flake8"
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
        "black-formatter.args": [
 | 
					        "ruff.configuration": "${workspaceFolder}/pyproject.toml",
 | 
				
			||||||
          "--config",
 | 
					 | 
				
			||||||
          "${workspaceFolder}/pyproject.toml"
 | 
					 | 
				
			||||||
        ],
 | 
					 | 
				
			||||||
        "[python]": {
 | 
					        "[python]": {
 | 
				
			||||||
          // VS will say "Value is not accepted" before building the devcontainer, but the warning
 | 
					          // VS will say "Value is not accepted" before building the devcontainer, but the warning
 | 
				
			||||||
          // should go away after build is completed.
 | 
					          // should go away after build is completed.
 | 
				
			||||||
          "editor.defaultFormatter": "ms-python.black-formatter"
 | 
					          "editor.defaultFormatter": "charliermarsh.ruff"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "editor.formatOnPaste": false,
 | 
					        "editor.formatOnPaste": false,
 | 
				
			||||||
        "editor.formatOnSave": true,
 | 
					        "editor.formatOnSave": true,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,6 +75,9 @@ target/
 | 
				
			|||||||
# pyenv
 | 
					# pyenv
 | 
				
			||||||
.python-version
 | 
					.python-version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# asdf
 | 
				
			||||||
 | 
					.tool-versions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# celery beat schedule file
 | 
					# celery beat schedule file
 | 
				
			||||||
celerybeat-schedule
 | 
					celerybeat-schedule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -111,4 +114,5 @@ config/
 | 
				
			|||||||
examples/
 | 
					examples/
 | 
				
			||||||
Dockerfile
 | 
					Dockerfile
 | 
				
			||||||
.git/
 | 
					.git/
 | 
				
			||||||
tests/build/
 | 
					tests/
 | 
				
			||||||
 | 
					.*
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								.github/FUNDING.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/FUNDING.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,4 +0,0 @@
 | 
				
			|||||||
---
 | 
					 | 
				
			||||||
# These are supported funding model platforms
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
custom: https://www.nabucasa.com
 | 
					 | 
				
			||||||
							
								
								
									
										15
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							@@ -7,11 +7,16 @@
 | 
				
			|||||||
- [ ] Bugfix (non-breaking change which fixes an issue)
 | 
					- [ ] Bugfix (non-breaking change which fixes an issue)
 | 
				
			||||||
- [ ] New feature (non-breaking change which adds functionality)
 | 
					- [ ] New feature (non-breaking change which adds functionality)
 | 
				
			||||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
 | 
					- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
 | 
				
			||||||
 | 
					- [ ] Code quality improvements to existing code or addition of tests
 | 
				
			||||||
- [ ] Other
 | 
					- [ ] Other
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**Related issue or feature (if applicable):** fixes <link to issue>
 | 
					**Related issue or feature (if applicable):**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):** esphome/esphome-docs#<esphome-docs PR number goes here>
 | 
					- fixes <link to issue>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- esphome/esphome-docs#<esphome-docs PR number goes here>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Test Environment
 | 
					## Test Environment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,12 +28,6 @@
 | 
				
			|||||||
- [ ] RTL87xx
 | 
					- [ ] RTL87xx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Example entry for `config.yaml`:
 | 
					## Example entry for `config.yaml`:
 | 
				
			||||||
<!--
 | 
					 | 
				
			||||||
  Supplying a configuration snippet, makes it easier for a maintainer to test
 | 
					 | 
				
			||||||
  your PR. Furthermore, for new integrations, it gives an impression of how
 | 
					 | 
				
			||||||
  the configuration would look like.
 | 
					 | 
				
			||||||
  Note: Remove this section if this PR does not have an example entry.
 | 
					 | 
				
			||||||
-->
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
```yaml
 | 
					```yaml
 | 
				
			||||||
# Example config.yaml
 | 
					# Example config.yaml
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										33
									
								
								.github/actions/build-image/action.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								.github/actions/build-image/action.yaml
									
									
									
									
										vendored
									
									
								
							@@ -1,15 +1,11 @@
 | 
				
			|||||||
name: Build Image
 | 
					name: Build Image
 | 
				
			||||||
inputs:
 | 
					inputs:
 | 
				
			||||||
  platform:
 | 
					 | 
				
			||||||
    description: "Platform to build for"
 | 
					 | 
				
			||||||
    required: true
 | 
					 | 
				
			||||||
    example: "linux/amd64"
 | 
					 | 
				
			||||||
  target:
 | 
					  target:
 | 
				
			||||||
    description: "Target to build"
 | 
					    description: "Target to build"
 | 
				
			||||||
    required: true
 | 
					    required: true
 | 
				
			||||||
    example: "docker"
 | 
					    example: "docker"
 | 
				
			||||||
  baseimg:
 | 
					  build_type:
 | 
				
			||||||
    description: "Base image type"
 | 
					    description: "Build type"
 | 
				
			||||||
    required: true
 | 
					    required: true
 | 
				
			||||||
    example: "docker"
 | 
					    example: "docker"
 | 
				
			||||||
  suffix:
 | 
					  suffix:
 | 
				
			||||||
@@ -19,6 +15,11 @@ inputs:
 | 
				
			|||||||
    description: "Version to build"
 | 
					    description: "Version to build"
 | 
				
			||||||
    required: true
 | 
					    required: true
 | 
				
			||||||
    example: "2023.12.0"
 | 
					    example: "2023.12.0"
 | 
				
			||||||
 | 
					  base_os:
 | 
				
			||||||
 | 
					    description: "Base OS to use"
 | 
				
			||||||
 | 
					    required: false
 | 
				
			||||||
 | 
					    default: "debian"
 | 
				
			||||||
 | 
					    example: "debian"
 | 
				
			||||||
runs:
 | 
					runs:
 | 
				
			||||||
  using: "composite"
 | 
					  using: "composite"
 | 
				
			||||||
  steps:
 | 
					  steps:
 | 
				
			||||||
@@ -46,52 +47,52 @@ runs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    - name: Build and push to ghcr by digest
 | 
					    - name: Build and push to ghcr by digest
 | 
				
			||||||
      id: build-ghcr
 | 
					      id: build-ghcr
 | 
				
			||||||
      uses: docker/build-push-action@v6.9.0
 | 
					      uses: docker/build-push-action@v6.18.0
 | 
				
			||||||
      env:
 | 
					      env:
 | 
				
			||||||
        DOCKER_BUILD_SUMMARY: false
 | 
					        DOCKER_BUILD_SUMMARY: false
 | 
				
			||||||
        DOCKER_BUILD_RECORD_UPLOAD: false
 | 
					        DOCKER_BUILD_RECORD_UPLOAD: false
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        context: .
 | 
					        context: .
 | 
				
			||||||
        file: ./docker/Dockerfile
 | 
					        file: ./docker/Dockerfile
 | 
				
			||||||
        platforms: ${{ inputs.platform }}
 | 
					 | 
				
			||||||
        target: ${{ inputs.target }}
 | 
					        target: ${{ inputs.target }}
 | 
				
			||||||
        cache-from: type=gha
 | 
					        cache-from: type=gha
 | 
				
			||||||
        cache-to: ${{ steps.cache-to.outputs.value }}
 | 
					        cache-to: ${{ steps.cache-to.outputs.value }}
 | 
				
			||||||
        build-args: |
 | 
					        build-args: |
 | 
				
			||||||
          BASEIMGTYPE=${{ inputs.baseimg }}
 | 
					          BUILD_TYPE=${{ inputs.build_type }}
 | 
				
			||||||
          BUILD_VERSION=${{ inputs.version }}
 | 
					          BUILD_VERSION=${{ inputs.version }}
 | 
				
			||||||
 | 
					          BUILD_OS=${{ inputs.base_os }}
 | 
				
			||||||
        outputs: |
 | 
					        outputs: |
 | 
				
			||||||
          type=image,name=ghcr.io/${{ steps.tags.outputs.image_name }},push-by-digest=true,name-canonical=true,push=true
 | 
					          type=image,name=ghcr.io/${{ steps.tags.outputs.image_name }},push-by-digest=true,name-canonical=true,push=true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: Export ghcr digests
 | 
					    - name: Export ghcr digests
 | 
				
			||||||
      shell: bash
 | 
					      shell: bash
 | 
				
			||||||
      run: |
 | 
					      run: |
 | 
				
			||||||
        mkdir -p /tmp/digests/${{ inputs.target }}/ghcr
 | 
					        mkdir -p /tmp/digests/${{ inputs.build_type }}/ghcr
 | 
				
			||||||
        digest="${{ steps.build-ghcr.outputs.digest }}"
 | 
					        digest="${{ steps.build-ghcr.outputs.digest }}"
 | 
				
			||||||
        touch "/tmp/digests/${{ inputs.target }}/ghcr/${digest#sha256:}"
 | 
					        touch "/tmp/digests/${{ inputs.build_type }}/ghcr/${digest#sha256:}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: Build and push to dockerhub by digest
 | 
					    - name: Build and push to dockerhub by digest
 | 
				
			||||||
      id: build-dockerhub
 | 
					      id: build-dockerhub
 | 
				
			||||||
      uses: docker/build-push-action@v6.9.0
 | 
					      uses: docker/build-push-action@v6.18.0
 | 
				
			||||||
      env:
 | 
					      env:
 | 
				
			||||||
        DOCKER_BUILD_SUMMARY: false
 | 
					        DOCKER_BUILD_SUMMARY: false
 | 
				
			||||||
        DOCKER_BUILD_RECORD_UPLOAD: false
 | 
					        DOCKER_BUILD_RECORD_UPLOAD: false
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        context: .
 | 
					        context: .
 | 
				
			||||||
        file: ./docker/Dockerfile
 | 
					        file: ./docker/Dockerfile
 | 
				
			||||||
        platforms: ${{ inputs.platform }}
 | 
					 | 
				
			||||||
        target: ${{ inputs.target }}
 | 
					        target: ${{ inputs.target }}
 | 
				
			||||||
        cache-from: type=gha
 | 
					        cache-from: type=gha
 | 
				
			||||||
        cache-to: ${{ steps.cache-to.outputs.value }}
 | 
					        cache-to: ${{ steps.cache-to.outputs.value }}
 | 
				
			||||||
        build-args: |
 | 
					        build-args: |
 | 
				
			||||||
          BASEIMGTYPE=${{ inputs.baseimg }}
 | 
					          BUILD_TYPE=${{ inputs.build_type }}
 | 
				
			||||||
          BUILD_VERSION=${{ inputs.version }}
 | 
					          BUILD_VERSION=${{ inputs.version }}
 | 
				
			||||||
 | 
					          BUILD_OS=${{ inputs.base_os }}
 | 
				
			||||||
        outputs: |
 | 
					        outputs: |
 | 
				
			||||||
          type=image,name=docker.io/${{ steps.tags.outputs.image_name }},push-by-digest=true,name-canonical=true,push=true
 | 
					          type=image,name=docker.io/${{ steps.tags.outputs.image_name }},push-by-digest=true,name-canonical=true,push=true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: Export dockerhub digests
 | 
					    - name: Export dockerhub digests
 | 
				
			||||||
      shell: bash
 | 
					      shell: bash
 | 
				
			||||||
      run: |
 | 
					      run: |
 | 
				
			||||||
        mkdir -p /tmp/digests/${{ inputs.target }}/dockerhub
 | 
					        mkdir -p /tmp/digests/${{ inputs.build_type }}/dockerhub
 | 
				
			||||||
        digest="${{ steps.build-dockerhub.outputs.digest }}"
 | 
					        digest="${{ steps.build-dockerhub.outputs.digest }}"
 | 
				
			||||||
        touch "/tmp/digests/${{ inputs.target }}/dockerhub/${digest#sha256:}"
 | 
					        touch "/tmp/digests/${{ inputs.build_type }}/dockerhub/${digest#sha256:}"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8
									
								
								.github/actions/restore-python/action.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/actions/restore-python/action.yml
									
									
									
									
										vendored
									
									
								
							@@ -17,12 +17,12 @@ runs:
 | 
				
			|||||||
  steps:
 | 
					  steps:
 | 
				
			||||||
    - name: Set up Python ${{ inputs.python-version }}
 | 
					    - name: Set up Python ${{ inputs.python-version }}
 | 
				
			||||||
      id: python
 | 
					      id: python
 | 
				
			||||||
      uses: actions/setup-python@v5.2.0
 | 
					      uses: actions/setup-python@v5.6.0
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        python-version: ${{ inputs.python-version }}
 | 
					        python-version: ${{ inputs.python-version }}
 | 
				
			||||||
    - name: Restore Python virtual environment
 | 
					    - name: Restore Python virtual environment
 | 
				
			||||||
      id: cache-venv
 | 
					      id: cache-venv
 | 
				
			||||||
      uses: actions/cache/restore@v4.1.1
 | 
					      uses: actions/cache/restore@v4.2.3
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        path: venv
 | 
					        path: venv
 | 
				
			||||||
        # yamllint disable-line rule:line-length
 | 
					        # yamllint disable-line rule:line-length
 | 
				
			||||||
@@ -34,7 +34,7 @@ runs:
 | 
				
			|||||||
        python -m venv venv
 | 
					        python -m venv venv
 | 
				
			||||||
        source venv/bin/activate
 | 
					        source venv/bin/activate
 | 
				
			||||||
        python --version
 | 
					        python --version
 | 
				
			||||||
        pip install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt
 | 
					        pip install -r requirements.txt -r requirements_test.txt
 | 
				
			||||||
        pip install -e .
 | 
					        pip install -e .
 | 
				
			||||||
    - name: Create Python virtual environment
 | 
					    - name: Create Python virtual environment
 | 
				
			||||||
      if: steps.cache-venv.outputs.cache-hit != 'true' && runner.os == 'Windows'
 | 
					      if: steps.cache-venv.outputs.cache-hit != 'true' && runner.os == 'Windows'
 | 
				
			||||||
@@ -43,5 +43,5 @@ runs:
 | 
				
			|||||||
        python -m venv venv
 | 
					        python -m venv venv
 | 
				
			||||||
        ./venv/Scripts/activate
 | 
					        ./venv/Scripts/activate
 | 
				
			||||||
        python --version
 | 
					        python --version
 | 
				
			||||||
        pip install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt
 | 
					        pip install -r requirements.txt -r requirements_test.txt
 | 
				
			||||||
        pip install -e .
 | 
					        pip install -e .
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							@@ -17,7 +17,6 @@ updates:
 | 
				
			|||||||
      docker-actions:
 | 
					      docker-actions:
 | 
				
			||||||
        applies-to: version-updates
 | 
					        applies-to: version-updates
 | 
				
			||||||
        patterns:
 | 
					        patterns:
 | 
				
			||||||
          - "docker/setup-qemu-action"
 | 
					 | 
				
			||||||
          - "docker/login-action"
 | 
					          - "docker/login-action"
 | 
				
			||||||
          - "docker/setup-buildx-action"
 | 
					          - "docker/setup-buildx-action"
 | 
				
			||||||
  - package-ecosystem: github-actions
 | 
					  - package-ecosystem: github-actions
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								.github/workflows/ci-api-proto.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								.github/workflows/ci-api-proto.yml
									
									
									
									
										vendored
									
									
								
							@@ -21,9 +21,9 @@ jobs:
 | 
				
			|||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Checkout
 | 
					      - name: Checkout
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Set up Python
 | 
					      - name: Set up Python
 | 
				
			||||||
        uses: actions/setup-python@v5.2.0
 | 
					        uses: actions/setup-python@v5.6.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          python-version: "3.11"
 | 
					          python-version: "3.11"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -57,6 +57,17 @@ jobs:
 | 
				
			|||||||
              event: 'REQUEST_CHANGES',
 | 
					              event: 'REQUEST_CHANGES',
 | 
				
			||||||
              body: 'You have altered the generated proto files but they do not match what is expected.\nPlease run "script/api_protobuf/api_protobuf.py" and commit the changes.'
 | 
					              body: 'You have altered the generated proto files but they do not match what is expected.\nPlease run "script/api_protobuf/api_protobuf.py" and commit the changes.'
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
 | 
					      - if: failure()
 | 
				
			||||||
 | 
					        name: Show changes
 | 
				
			||||||
 | 
					        run: git diff
 | 
				
			||||||
 | 
					      - if: failure()
 | 
				
			||||||
 | 
					        name: Archive artifacts
 | 
				
			||||||
 | 
					        uses: actions/upload-artifact@v4.6.2
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          name: generated-proto-files
 | 
				
			||||||
 | 
					          path: |
 | 
				
			||||||
 | 
					            esphome/components/api/api_pb2.*
 | 
				
			||||||
 | 
					            esphome/components/api/api_pb2_service.*
 | 
				
			||||||
      - if: success()
 | 
					      - if: success()
 | 
				
			||||||
        name: Dismiss review
 | 
					        name: Dismiss review
 | 
				
			||||||
        uses: actions/github-script@v7.0.1
 | 
					        uses: actions/github-script@v7.0.1
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								.github/workflows/ci-docker.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								.github/workflows/ci-docker.yml
									
									
									
									
										vendored
									
									
								
							@@ -33,22 +33,23 @@ concurrency:
 | 
				
			|||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  check-docker:
 | 
					  check-docker:
 | 
				
			||||||
    name: Build docker containers
 | 
					    name: Build docker containers
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ${{ matrix.os }}
 | 
				
			||||||
    strategy:
 | 
					    strategy:
 | 
				
			||||||
      fail-fast: false
 | 
					      fail-fast: false
 | 
				
			||||||
      matrix:
 | 
					      matrix:
 | 
				
			||||||
        arch: [amd64, armv7, aarch64]
 | 
					        os: ["ubuntu-24.04", "ubuntu-24.04-arm"]
 | 
				
			||||||
        build_type: ["ha-addon", "docker", "lint"]
 | 
					        build_type:
 | 
				
			||||||
 | 
					          - "ha-addon"
 | 
				
			||||||
 | 
					          - "docker"
 | 
				
			||||||
 | 
					          # - "lint"
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v4.1.7
 | 
					      - uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Set up Python
 | 
					      - name: Set up Python
 | 
				
			||||||
        uses: actions/setup-python@v5.2.0
 | 
					        uses: actions/setup-python@v5.6.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          python-version: "3.9"
 | 
					          python-version: "3.10"
 | 
				
			||||||
      - name: Set up Docker Buildx
 | 
					      - name: Set up Docker Buildx
 | 
				
			||||||
        uses: docker/setup-buildx-action@v3.7.1
 | 
					        uses: docker/setup-buildx-action@v3.10.0
 | 
				
			||||||
      - name: Set up QEMU
 | 
					 | 
				
			||||||
        uses: docker/setup-qemu-action@v3.2.0
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Set TAG
 | 
					      - name: Set TAG
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
@@ -58,6 +59,6 @@ jobs:
 | 
				
			|||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
          docker/build.py \
 | 
					          docker/build.py \
 | 
				
			||||||
            --tag "${TAG}" \
 | 
					            --tag "${TAG}" \
 | 
				
			||||||
            --arch "${{ matrix.arch }}" \
 | 
					            --arch "${{ matrix.os == 'ubuntu-24.04-arm' && 'aarch64' || 'amd64' }}" \
 | 
				
			||||||
            --build-type "${{ matrix.build_type }}" \
 | 
					            --build-type "${{ matrix.build_type }}" \
 | 
				
			||||||
            build
 | 
					            build
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										112
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										112
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							@@ -13,14 +13,15 @@ on:
 | 
				
			|||||||
      - ".github/workflows/ci.yml"
 | 
					      - ".github/workflows/ci.yml"
 | 
				
			||||||
      - "!.yamllint"
 | 
					      - "!.yamllint"
 | 
				
			||||||
      - "!.github/dependabot.yml"
 | 
					      - "!.github/dependabot.yml"
 | 
				
			||||||
 | 
					      - "!docker/**"
 | 
				
			||||||
  merge_group:
 | 
					  merge_group:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
permissions:
 | 
					permissions:
 | 
				
			||||||
  contents: read
 | 
					  contents: read
 | 
				
			||||||
 | 
					
 | 
				
			||||||
env:
 | 
					env:
 | 
				
			||||||
  DEFAULT_PYTHON: "3.9"
 | 
					  DEFAULT_PYTHON: "3.10"
 | 
				
			||||||
  PYUPGRADE_TARGET: "--py39-plus"
 | 
					  PYUPGRADE_TARGET: "--py310-plus"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
concurrency:
 | 
					concurrency:
 | 
				
			||||||
  # yamllint disable-line rule:line-length
 | 
					  # yamllint disable-line rule:line-length
 | 
				
			||||||
@@ -30,23 +31,23 @@ concurrency:
 | 
				
			|||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  common:
 | 
					  common:
 | 
				
			||||||
    name: Create common environment
 | 
					    name: Create common environment
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-24.04
 | 
				
			||||||
    outputs:
 | 
					    outputs:
 | 
				
			||||||
      cache-key: ${{ steps.cache-key.outputs.key }}
 | 
					      cache-key: ${{ steps.cache-key.outputs.key }}
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Generate cache-key
 | 
					      - name: Generate cache-key
 | 
				
			||||||
        id: cache-key
 | 
					        id: cache-key
 | 
				
			||||||
        run: echo key="${{ hashFiles('requirements.txt', 'requirements_optional.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT
 | 
					        run: echo key="${{ hashFiles('requirements.txt', 'requirements_test.txt') }}" >> $GITHUB_OUTPUT
 | 
				
			||||||
      - name: Set up Python ${{ env.DEFAULT_PYTHON }}
 | 
					      - name: Set up Python ${{ env.DEFAULT_PYTHON }}
 | 
				
			||||||
        id: python
 | 
					        id: python
 | 
				
			||||||
        uses: actions/setup-python@v5.2.0
 | 
					        uses: actions/setup-python@v5.6.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          python-version: ${{ env.DEFAULT_PYTHON }}
 | 
					          python-version: ${{ env.DEFAULT_PYTHON }}
 | 
				
			||||||
      - name: Restore Python virtual environment
 | 
					      - name: Restore Python virtual environment
 | 
				
			||||||
        id: cache-venv
 | 
					        id: cache-venv
 | 
				
			||||||
        uses: actions/cache@v4.1.1
 | 
					        uses: actions/cache@v4.2.3
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          path: venv
 | 
					          path: venv
 | 
				
			||||||
          # yamllint disable-line rule:line-length
 | 
					          # yamllint disable-line rule:line-length
 | 
				
			||||||
@@ -57,38 +58,38 @@ jobs:
 | 
				
			|||||||
          python -m venv venv
 | 
					          python -m venv venv
 | 
				
			||||||
          . venv/bin/activate
 | 
					          . venv/bin/activate
 | 
				
			||||||
          python --version
 | 
					          python --version
 | 
				
			||||||
          pip install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt
 | 
					          pip install -r requirements.txt -r requirements_test.txt
 | 
				
			||||||
          pip install -e .
 | 
					          pip install -e .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  black:
 | 
					  ruff:
 | 
				
			||||||
    name: Check black
 | 
					    name: Check ruff
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-24.04
 | 
				
			||||||
    needs:
 | 
					    needs:
 | 
				
			||||||
      - common
 | 
					      - common
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          python-version: ${{ env.DEFAULT_PYTHON }}
 | 
					          python-version: ${{ env.DEFAULT_PYTHON }}
 | 
				
			||||||
          cache-key: ${{ needs.common.outputs.cache-key }}
 | 
					          cache-key: ${{ needs.common.outputs.cache-key }}
 | 
				
			||||||
      - name: Run black
 | 
					      - name: Run Ruff
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
          . venv/bin/activate
 | 
					          . venv/bin/activate
 | 
				
			||||||
          black --verbose esphome tests
 | 
					          ruff format esphome tests
 | 
				
			||||||
      - name: Suggested changes
 | 
					      - name: Suggested changes
 | 
				
			||||||
        run: script/ci-suggest-changes
 | 
					        run: script/ci-suggest-changes
 | 
				
			||||||
        if: always()
 | 
					        if: always()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  flake8:
 | 
					  flake8:
 | 
				
			||||||
    name: Check flake8
 | 
					    name: Check flake8
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-24.04
 | 
				
			||||||
    needs:
 | 
					    needs:
 | 
				
			||||||
      - common
 | 
					      - common
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -104,12 +105,12 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  pylint:
 | 
					  pylint:
 | 
				
			||||||
    name: Check pylint
 | 
					    name: Check pylint
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-24.04
 | 
				
			||||||
    needs:
 | 
					    needs:
 | 
				
			||||||
      - common
 | 
					      - common
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -125,12 +126,12 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  pyupgrade:
 | 
					  pyupgrade:
 | 
				
			||||||
    name: Check pyupgrade
 | 
					    name: Check pyupgrade
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-24.04
 | 
				
			||||||
    needs:
 | 
					    needs:
 | 
				
			||||||
      - common
 | 
					      - common
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -146,12 +147,12 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  ci-custom:
 | 
					  ci-custom:
 | 
				
			||||||
    name: Run script/ci-custom
 | 
					    name: Run script/ci-custom
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-24.04
 | 
				
			||||||
    needs:
 | 
					    needs:
 | 
				
			||||||
      - common
 | 
					      - common
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -164,6 +165,7 @@ jobs:
 | 
				
			|||||||
          . venv/bin/activate
 | 
					          . venv/bin/activate
 | 
				
			||||||
          script/ci-custom.py
 | 
					          script/ci-custom.py
 | 
				
			||||||
          script/build_codeowners.py --check
 | 
					          script/build_codeowners.py --check
 | 
				
			||||||
 | 
					          script/build_language_schema.py --check
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pytest:
 | 
					  pytest:
 | 
				
			||||||
    name: Run pytest
 | 
					    name: Run pytest
 | 
				
			||||||
@@ -171,10 +173,10 @@ jobs:
 | 
				
			|||||||
      fail-fast: false
 | 
					      fail-fast: false
 | 
				
			||||||
      matrix:
 | 
					      matrix:
 | 
				
			||||||
        python-version:
 | 
					        python-version:
 | 
				
			||||||
          - "3.9"
 | 
					 | 
				
			||||||
          - "3.10"
 | 
					          - "3.10"
 | 
				
			||||||
          - "3.11"
 | 
					          - "3.11"
 | 
				
			||||||
          - "3.12"
 | 
					          - "3.12"
 | 
				
			||||||
 | 
					          - "3.13"
 | 
				
			||||||
        os:
 | 
					        os:
 | 
				
			||||||
          - ubuntu-latest
 | 
					          - ubuntu-latest
 | 
				
			||||||
          - macOS-latest
 | 
					          - macOS-latest
 | 
				
			||||||
@@ -183,24 +185,24 @@ jobs:
 | 
				
			|||||||
          # Minimize CI resource usage
 | 
					          # Minimize CI resource usage
 | 
				
			||||||
          # by only running the Python version
 | 
					          # by only running the Python version
 | 
				
			||||||
          # version used for docker images on Windows and macOS
 | 
					          # version used for docker images on Windows and macOS
 | 
				
			||||||
 | 
					          - python-version: "3.13"
 | 
				
			||||||
 | 
					            os: windows-latest
 | 
				
			||||||
          - python-version: "3.12"
 | 
					          - python-version: "3.12"
 | 
				
			||||||
            os: windows-latest
 | 
					            os: windows-latest
 | 
				
			||||||
          - python-version: "3.10"
 | 
					          - python-version: "3.10"
 | 
				
			||||||
            os: windows-latest
 | 
					            os: windows-latest
 | 
				
			||||||
          - python-version: "3.9"
 | 
					          - python-version: "3.13"
 | 
				
			||||||
            os: windows-latest
 | 
					            os: macOS-latest
 | 
				
			||||||
          - python-version: "3.12"
 | 
					          - python-version: "3.12"
 | 
				
			||||||
            os: macOS-latest
 | 
					            os: macOS-latest
 | 
				
			||||||
          - python-version: "3.10"
 | 
					          - python-version: "3.10"
 | 
				
			||||||
            os: macOS-latest
 | 
					            os: macOS-latest
 | 
				
			||||||
          - python-version: "3.9"
 | 
					 | 
				
			||||||
            os: macOS-latest
 | 
					 | 
				
			||||||
    runs-on: ${{ matrix.os }}
 | 
					    runs-on: ${{ matrix.os }}
 | 
				
			||||||
    needs:
 | 
					    needs:
 | 
				
			||||||
      - common
 | 
					      - common
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -212,25 +214,25 @@ jobs:
 | 
				
			|||||||
        if: matrix.os == 'windows-latest'
 | 
					        if: matrix.os == 'windows-latest'
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
          ./venv/Scripts/activate
 | 
					          ./venv/Scripts/activate
 | 
				
			||||||
          pytest -vv --cov-report=xml --tb=native tests
 | 
					          pytest -vv --cov-report=xml --tb=native -n auto tests
 | 
				
			||||||
      - name: Run pytest
 | 
					      - name: Run pytest
 | 
				
			||||||
        if: matrix.os == 'ubuntu-latest' || matrix.os == 'macOS-latest'
 | 
					        if: matrix.os == 'ubuntu-latest' || matrix.os == 'macOS-latest'
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
          . venv/bin/activate
 | 
					          . venv/bin/activate
 | 
				
			||||||
          pytest -vv --cov-report=xml --tb=native tests
 | 
					          pytest -vv --cov-report=xml --tb=native -n auto tests
 | 
				
			||||||
      - name: Upload coverage to Codecov
 | 
					      - name: Upload coverage to Codecov
 | 
				
			||||||
        uses: codecov/codecov-action@v4
 | 
					        uses: codecov/codecov-action@v5.4.3
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          token: ${{ secrets.CODECOV_TOKEN }}
 | 
					          token: ${{ secrets.CODECOV_TOKEN }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  clang-format:
 | 
					  clang-format:
 | 
				
			||||||
    name: Check clang-format
 | 
					    name: Check clang-format
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-24.04
 | 
				
			||||||
    needs:
 | 
					    needs:
 | 
				
			||||||
      - common
 | 
					      - common
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -251,10 +253,10 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  clang-tidy:
 | 
					  clang-tidy:
 | 
				
			||||||
    name: ${{ matrix.name }}
 | 
					    name: ${{ matrix.name }}
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-24.04
 | 
				
			||||||
    needs:
 | 
					    needs:
 | 
				
			||||||
      - common
 | 
					      - common
 | 
				
			||||||
      - black
 | 
					      - ruff
 | 
				
			||||||
      - ci-custom
 | 
					      - ci-custom
 | 
				
			||||||
      - clang-format
 | 
					      - clang-format
 | 
				
			||||||
      - flake8
 | 
					      - flake8
 | 
				
			||||||
@@ -290,10 +292,15 @@ jobs:
 | 
				
			|||||||
            name: Run script/clang-tidy for ESP32 IDF
 | 
					            name: Run script/clang-tidy for ESP32 IDF
 | 
				
			||||||
            options: --environment esp32-idf-tidy --grep USE_ESP_IDF
 | 
					            options: --environment esp32-idf-tidy --grep USE_ESP_IDF
 | 
				
			||||||
            pio_cache_key: tidyesp32-idf
 | 
					            pio_cache_key: tidyesp32-idf
 | 
				
			||||||
 | 
					          - id: clang-tidy
 | 
				
			||||||
 | 
					            name: Run script/clang-tidy for ZEPHYR
 | 
				
			||||||
 | 
					            options: --environment nrf52-tidy --grep USE_ZEPHYR
 | 
				
			||||||
 | 
					            pio_cache_key: tidy-zephyr
 | 
				
			||||||
 | 
					            ignore_errors: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -302,23 +309,18 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      - name: Cache platformio
 | 
					      - name: Cache platformio
 | 
				
			||||||
        if: github.ref == 'refs/heads/dev'
 | 
					        if: github.ref == 'refs/heads/dev'
 | 
				
			||||||
        uses: actions/cache@v4.1.1
 | 
					        uses: actions/cache@v4.2.3
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          path: ~/.platformio
 | 
					          path: ~/.platformio
 | 
				
			||||||
          key: platformio-${{ matrix.pio_cache_key }}
 | 
					          key: platformio-${{ matrix.pio_cache_key }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Cache platformio
 | 
					      - name: Cache platformio
 | 
				
			||||||
        if: github.ref != 'refs/heads/dev'
 | 
					        if: github.ref != 'refs/heads/dev'
 | 
				
			||||||
        uses: actions/cache/restore@v4.1.1
 | 
					        uses: actions/cache/restore@v4.2.3
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          path: ~/.platformio
 | 
					          path: ~/.platformio
 | 
				
			||||||
          key: platformio-${{ matrix.pio_cache_key }}
 | 
					          key: platformio-${{ matrix.pio_cache_key }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Install clang-tidy
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          sudo apt-get update
 | 
					 | 
				
			||||||
          sudo apt-get install clang-tidy-14
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Register problem matchers
 | 
					      - name: Register problem matchers
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/gcc.json"
 | 
					          echo "::add-matcher::.github/workflows/matchers/gcc.json"
 | 
				
			||||||
@@ -334,18 +336,18 @@ jobs:
 | 
				
			|||||||
      - name: Run clang-tidy
 | 
					      - name: Run clang-tidy
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
          . venv/bin/activate
 | 
					          . venv/bin/activate
 | 
				
			||||||
          script/clang-tidy --all-headers --fix ${{ matrix.options }}
 | 
					          script/clang-tidy --all-headers --fix ${{ matrix.options }} ${{ matrix.ignore_errors && '|| true' || '' }}
 | 
				
			||||||
        env:
 | 
					        env:
 | 
				
			||||||
          # Also cache libdeps, store them in a ~/.platformio subfolder
 | 
					          # Also cache libdeps, store them in a ~/.platformio subfolder
 | 
				
			||||||
          PLATFORMIO_LIBDEPS_DIR: ~/.platformio/libdeps
 | 
					          PLATFORMIO_LIBDEPS_DIR: ~/.platformio/libdeps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Suggested changes
 | 
					      - name: Suggested changes
 | 
				
			||||||
        run: script/ci-suggest-changes
 | 
					        run: script/ci-suggest-changes ${{ matrix.ignore_errors && '|| true' || '' }}
 | 
				
			||||||
        # yamllint disable-line rule:line-length
 | 
					        # yamllint disable-line rule:line-length
 | 
				
			||||||
        if: always()
 | 
					        if: always()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  list-components:
 | 
					  list-components:
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-24.04
 | 
				
			||||||
    needs:
 | 
					    needs:
 | 
				
			||||||
      - common
 | 
					      - common
 | 
				
			||||||
    if: github.event_name == 'pull_request'
 | 
					    if: github.event_name == 'pull_request'
 | 
				
			||||||
@@ -354,7 +356,7 @@ jobs:
 | 
				
			|||||||
      count: ${{ steps.list-components.outputs.count }}
 | 
					      count: ${{ steps.list-components.outputs.count }}
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          # Fetch enough history so `git merge-base refs/remotes/origin/dev HEAD` works.
 | 
					          # Fetch enough history so `git merge-base refs/remotes/origin/dev HEAD` works.
 | 
				
			||||||
          fetch-depth: 500
 | 
					          fetch-depth: 500
 | 
				
			||||||
@@ -387,7 +389,7 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  test-build-components:
 | 
					  test-build-components:
 | 
				
			||||||
    name: Component test ${{ matrix.file }}
 | 
					    name: Component test ${{ matrix.file }}
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-24.04
 | 
				
			||||||
    needs:
 | 
					    needs:
 | 
				
			||||||
      - common
 | 
					      - common
 | 
				
			||||||
      - list-components
 | 
					      - list-components
 | 
				
			||||||
@@ -404,7 +406,7 @@ jobs:
 | 
				
			|||||||
          sudo apt-get install libsdl2-dev
 | 
					          sudo apt-get install libsdl2-dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -421,7 +423,7 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  test-build-components-splitter:
 | 
					  test-build-components-splitter:
 | 
				
			||||||
    name: Split components for testing into 20 groups maximum
 | 
					    name: Split components for testing into 20 groups maximum
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-24.04
 | 
				
			||||||
    needs:
 | 
					    needs:
 | 
				
			||||||
      - common
 | 
					      - common
 | 
				
			||||||
      - list-components
 | 
					      - list-components
 | 
				
			||||||
@@ -430,7 +432,7 @@ jobs:
 | 
				
			|||||||
      matrix: ${{ steps.split.outputs.components }}
 | 
					      matrix: ${{ steps.split.outputs.components }}
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Split components into 20 groups
 | 
					      - name: Split components into 20 groups
 | 
				
			||||||
        id: split
 | 
					        id: split
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
@@ -439,7 +441,7 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  test-build-components-split:
 | 
					  test-build-components-split:
 | 
				
			||||||
    name: Test split components
 | 
					    name: Test split components
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-24.04
 | 
				
			||||||
    needs:
 | 
					    needs:
 | 
				
			||||||
      - common
 | 
					      - common
 | 
				
			||||||
      - list-components
 | 
					      - list-components
 | 
				
			||||||
@@ -460,7 +462,7 @@ jobs:
 | 
				
			|||||||
          sudo apt-get install libsdl2-dev
 | 
					          sudo apt-get install libsdl2-dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Restore Python
 | 
					      - name: Restore Python
 | 
				
			||||||
        uses: ./.github/actions/restore-python
 | 
					        uses: ./.github/actions/restore-python
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -483,10 +485,10 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  ci-status:
 | 
					  ci-status:
 | 
				
			||||||
    name: CI Status
 | 
					    name: CI Status
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-24.04
 | 
				
			||||||
    needs:
 | 
					    needs:
 | 
				
			||||||
      - common
 | 
					      - common
 | 
				
			||||||
      - black
 | 
					      - ruff
 | 
				
			||||||
      - ci-custom
 | 
					      - ci-custom
 | 
				
			||||||
      - clang-format
 | 
					      - clang-format
 | 
				
			||||||
      - flake8
 | 
					      - flake8
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								.github/workflows/matchers/lint-python.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/matchers/lint-python.json
									
									
									
									
										vendored
									
									
								
							@@ -1,11 +1,11 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "problemMatcher": [
 | 
					  "problemMatcher": [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      "owner": "black",
 | 
					      "owner": "ruff",
 | 
				
			||||||
      "severity": "error",
 | 
					      "severity": "error",
 | 
				
			||||||
      "pattern": [
 | 
					      "pattern": [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          "regexp": "^(.*): (Please format this file with the black formatter)",
 | 
					          "regexp": "^(.*): (Please format this file with the ruff formatter)",
 | 
				
			||||||
          "file": 1,
 | 
					          "file": 1,
 | 
				
			||||||
          "message": 2
 | 
					          "message": 2
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										133
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										133
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@@ -18,8 +18,9 @@ jobs:
 | 
				
			|||||||
    outputs:
 | 
					    outputs:
 | 
				
			||||||
      tag: ${{ steps.tag.outputs.tag }}
 | 
					      tag: ${{ steps.tag.outputs.tag }}
 | 
				
			||||||
      branch_build: ${{ steps.tag.outputs.branch_build }}
 | 
					      branch_build: ${{ steps.tag.outputs.branch_build }}
 | 
				
			||||||
 | 
					      deploy_env: ${{ steps.tag.outputs.deploy_env }}
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v4.1.7
 | 
					      - uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Get tag
 | 
					      - name: Get tag
 | 
				
			||||||
        id: tag
 | 
					        id: tag
 | 
				
			||||||
        # yamllint disable rule:line-length
 | 
					        # yamllint disable rule:line-length
 | 
				
			||||||
@@ -27,6 +28,11 @@ jobs:
 | 
				
			|||||||
          if [[ "${{ github.event_name }}" = "release" ]]; then
 | 
					          if [[ "${{ github.event_name }}" = "release" ]]; then
 | 
				
			||||||
            TAG="${{ github.event.release.tag_name}}"
 | 
					            TAG="${{ github.event.release.tag_name}}"
 | 
				
			||||||
            BRANCH_BUILD="false"
 | 
					            BRANCH_BUILD="false"
 | 
				
			||||||
 | 
					            if [[ "${{ github.event.release.prerelease }}" = "true" ]]; then
 | 
				
			||||||
 | 
					              ENVIRONMENT="beta"
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					              ENVIRONMENT="production"
 | 
				
			||||||
 | 
					            fi
 | 
				
			||||||
          else
 | 
					          else
 | 
				
			||||||
            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')"
 | 
				
			||||||
@@ -35,12 +41,15 @@ jobs:
 | 
				
			|||||||
            if [[ "$BRANCH" != "dev" ]]; then
 | 
					            if [[ "$BRANCH" != "dev" ]]; then
 | 
				
			||||||
              TAG="${TAG}-${BRANCH}"
 | 
					              TAG="${TAG}-${BRANCH}"
 | 
				
			||||||
              BRANCH_BUILD="true"
 | 
					              BRANCH_BUILD="true"
 | 
				
			||||||
 | 
					              ENVIRONMENT=""
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
              BRANCH_BUILD="false"
 | 
					              BRANCH_BUILD="false"
 | 
				
			||||||
 | 
					              ENVIRONMENT="dev"
 | 
				
			||||||
            fi
 | 
					            fi
 | 
				
			||||||
          fi
 | 
					          fi
 | 
				
			||||||
          echo "tag=${TAG}" >> $GITHUB_OUTPUT
 | 
					          echo "tag=${TAG}" >> $GITHUB_OUTPUT
 | 
				
			||||||
          echo "branch_build=${BRANCH_BUILD}" >> $GITHUB_OUTPUT
 | 
					          echo "branch_build=${BRANCH_BUILD}" >> $GITHUB_OUTPUT
 | 
				
			||||||
 | 
					          echo "deploy_env=${ENVIRONMENT}" >> $GITHUB_OUTPUT
 | 
				
			||||||
        # yamllint enable rule:line-length
 | 
					        # yamllint enable rule:line-length
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  deploy-pypi:
 | 
					  deploy-pypi:
 | 
				
			||||||
@@ -51,57 +60,54 @@ jobs:
 | 
				
			|||||||
      contents: read
 | 
					      contents: read
 | 
				
			||||||
      id-token: write
 | 
					      id-token: write
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v4.1.7
 | 
					      - uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Set up Python
 | 
					      - name: Set up Python
 | 
				
			||||||
        uses: actions/setup-python@v5.2.0
 | 
					        uses: actions/setup-python@v5.6.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          python-version: "3.x"
 | 
					          python-version: "3.x"
 | 
				
			||||||
      - name: Set up python environment
 | 
					 | 
				
			||||||
        env:
 | 
					 | 
				
			||||||
          ESPHOME_NO_VENV: 1
 | 
					 | 
				
			||||||
        run: script/setup
 | 
					 | 
				
			||||||
      - name: Build
 | 
					      - name: Build
 | 
				
			||||||
        run: |-
 | 
					        run: |-
 | 
				
			||||||
          pip3 install build
 | 
					          pip3 install build
 | 
				
			||||||
          python3 -m build
 | 
					          python3 -m build
 | 
				
			||||||
      - name: Publish
 | 
					      - name: Publish
 | 
				
			||||||
        uses: pypa/gh-action-pypi-publish@v1.10.3
 | 
					        uses: pypa/gh-action-pypi-publish@v1.12.4
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          skip-existing: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  deploy-docker:
 | 
					  deploy-docker:
 | 
				
			||||||
    name: Build ESPHome ${{ matrix.platform }}
 | 
					    name: Build ESPHome ${{ matrix.platform.arch }}
 | 
				
			||||||
    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: ${{ matrix.platform.os }}
 | 
				
			||||||
    needs: [init]
 | 
					    needs: [init]
 | 
				
			||||||
    strategy:
 | 
					    strategy:
 | 
				
			||||||
      fail-fast: false
 | 
					      fail-fast: false
 | 
				
			||||||
      matrix:
 | 
					      matrix:
 | 
				
			||||||
        platform:
 | 
					        platform:
 | 
				
			||||||
          - linux/amd64
 | 
					          - arch: amd64
 | 
				
			||||||
          - linux/arm/v7
 | 
					            os: "ubuntu-24.04"
 | 
				
			||||||
          - linux/arm64
 | 
					          - arch: arm64
 | 
				
			||||||
 | 
					            os: "ubuntu-24.04-arm"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v4.1.7
 | 
					      - uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Set up Python
 | 
					      - name: Set up Python
 | 
				
			||||||
        uses: actions/setup-python@v5.2.0
 | 
					        uses: actions/setup-python@v5.6.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          python-version: "3.9"
 | 
					          python-version: "3.10"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Set up Docker Buildx
 | 
					      - name: Set up Docker Buildx
 | 
				
			||||||
        uses: docker/setup-buildx-action@v3.7.1
 | 
					        uses: docker/setup-buildx-action@v3.10.0
 | 
				
			||||||
      - name: Set up QEMU
 | 
					 | 
				
			||||||
        if: matrix.platform != 'linux/amd64'
 | 
					 | 
				
			||||||
        uses: docker/setup-qemu-action@v3.2.0
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Log in to docker hub
 | 
					      - name: Log in to docker hub
 | 
				
			||||||
        uses: docker/login-action@v3.3.0
 | 
					        uses: docker/login-action@v3.4.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          username: ${{ secrets.DOCKER_USER }}
 | 
					          username: ${{ secrets.DOCKER_USER }}
 | 
				
			||||||
          password: ${{ secrets.DOCKER_PASSWORD }}
 | 
					          password: ${{ secrets.DOCKER_PASSWORD }}
 | 
				
			||||||
      - name: Log in to the GitHub container registry
 | 
					      - name: Log in to the GitHub container registry
 | 
				
			||||||
        uses: docker/login-action@v3.3.0
 | 
					        uses: docker/login-action@v3.4.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          registry: ghcr.io
 | 
					          registry: ghcr.io
 | 
				
			||||||
          username: ${{ github.actor }}
 | 
					          username: ${{ github.actor }}
 | 
				
			||||||
@@ -110,45 +116,36 @@ jobs:
 | 
				
			|||||||
      - name: Build docker
 | 
					      - name: Build docker
 | 
				
			||||||
        uses: ./.github/actions/build-image
 | 
					        uses: ./.github/actions/build-image
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          platform: ${{ matrix.platform }}
 | 
					          target: final
 | 
				
			||||||
          target: docker
 | 
					          build_type: docker
 | 
				
			||||||
          baseimg: docker
 | 
					 | 
				
			||||||
          suffix: ""
 | 
					          suffix: ""
 | 
				
			||||||
          version: ${{ needs.init.outputs.tag }}
 | 
					          version: ${{ needs.init.outputs.tag }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Build ha-addon
 | 
					      - name: Build ha-addon
 | 
				
			||||||
        uses: ./.github/actions/build-image
 | 
					        uses: ./.github/actions/build-image
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          platform: ${{ matrix.platform }}
 | 
					          target: final
 | 
				
			||||||
          target: hassio
 | 
					          build_type: ha-addon
 | 
				
			||||||
          baseimg: hassio
 | 
					 | 
				
			||||||
          suffix: "hassio"
 | 
					          suffix: "hassio"
 | 
				
			||||||
          version: ${{ needs.init.outputs.tag }}
 | 
					          version: ${{ needs.init.outputs.tag }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Build lint
 | 
					      # - name: Build lint
 | 
				
			||||||
        uses: ./.github/actions/build-image
 | 
					      #   uses: ./.github/actions/build-image
 | 
				
			||||||
        with:
 | 
					      #   with:
 | 
				
			||||||
          platform: ${{ matrix.platform }}
 | 
					      #     target: lint
 | 
				
			||||||
          target: lint
 | 
					      #     build_type: lint
 | 
				
			||||||
          baseimg: docker
 | 
					      #     suffix: lint
 | 
				
			||||||
          suffix: lint
 | 
					      #     version: ${{ needs.init.outputs.tag }}
 | 
				
			||||||
          version: ${{ needs.init.outputs.tag }}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Sanitize platform name
 | 
					 | 
				
			||||||
        id: sanitize
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          echo "${{ matrix.platform }}" | sed 's|/|-|g' > /tmp/platform
 | 
					 | 
				
			||||||
          echo name=$(cat /tmp/platform) >> $GITHUB_OUTPUT
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Upload digests
 | 
					      - name: Upload digests
 | 
				
			||||||
        uses: actions/upload-artifact@v4.4.2
 | 
					        uses: actions/upload-artifact@v4.6.2
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          name: digests-${{ steps.sanitize.outputs.name }}
 | 
					          name: digests-${{ matrix.platform.arch }}
 | 
				
			||||||
          path: /tmp/digests
 | 
					          path: /tmp/digests
 | 
				
			||||||
          retention-days: 1
 | 
					          retention-days: 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  deploy-manifest:
 | 
					  deploy-manifest:
 | 
				
			||||||
    name: Publish ESPHome ${{ matrix.image.title }} to ${{ matrix.registry }}
 | 
					    name: Publish ESPHome ${{ matrix.image.build_type }} to ${{ matrix.registry }}
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    needs:
 | 
					    needs:
 | 
				
			||||||
      - init
 | 
					      - init
 | 
				
			||||||
@@ -161,40 +158,37 @@ jobs:
 | 
				
			|||||||
      fail-fast: false
 | 
					      fail-fast: false
 | 
				
			||||||
      matrix:
 | 
					      matrix:
 | 
				
			||||||
        image:
 | 
					        image:
 | 
				
			||||||
          - title: "ha-addon"
 | 
					          - build_type: "docker"
 | 
				
			||||||
            target: "hassio"
 | 
					 | 
				
			||||||
            suffix: "hassio"
 | 
					 | 
				
			||||||
          - title: "docker"
 | 
					 | 
				
			||||||
            target: "docker"
 | 
					 | 
				
			||||||
            suffix: ""
 | 
					            suffix: ""
 | 
				
			||||||
          - title: "lint"
 | 
					          - build_type: "ha-addon"
 | 
				
			||||||
            target: "lint"
 | 
					            suffix: "hassio"
 | 
				
			||||||
            suffix: "lint"
 | 
					            # - build_type: "lint"
 | 
				
			||||||
 | 
					            #   suffix: "lint"
 | 
				
			||||||
        registry:
 | 
					        registry:
 | 
				
			||||||
          - ghcr
 | 
					          - ghcr
 | 
				
			||||||
          - dockerhub
 | 
					          - dockerhub
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v4.1.7
 | 
					      - uses: actions/checkout@v4.2.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Download digests
 | 
					      - name: Download digests
 | 
				
			||||||
        uses: actions/download-artifact@v4.1.8
 | 
					        uses: actions/download-artifact@v4.3.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          pattern: digests-*
 | 
					          pattern: digests-*
 | 
				
			||||||
          path: /tmp/digests
 | 
					          path: /tmp/digests
 | 
				
			||||||
          merge-multiple: true
 | 
					          merge-multiple: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Set up Docker Buildx
 | 
					      - name: Set up Docker Buildx
 | 
				
			||||||
        uses: docker/setup-buildx-action@v3.7.1
 | 
					        uses: docker/setup-buildx-action@v3.10.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Log in to docker hub
 | 
					      - name: Log in to docker hub
 | 
				
			||||||
        if: matrix.registry == 'dockerhub'
 | 
					        if: matrix.registry == 'dockerhub'
 | 
				
			||||||
        uses: docker/login-action@v3.3.0
 | 
					        uses: docker/login-action@v3.4.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          username: ${{ secrets.DOCKER_USER }}
 | 
					          username: ${{ secrets.DOCKER_USER }}
 | 
				
			||||||
          password: ${{ secrets.DOCKER_PASSWORD }}
 | 
					          password: ${{ secrets.DOCKER_PASSWORD }}
 | 
				
			||||||
      - name: Log in to the GitHub container registry
 | 
					      - name: Log in to the GitHub container registry
 | 
				
			||||||
        if: matrix.registry == 'ghcr'
 | 
					        if: matrix.registry == 'ghcr'
 | 
				
			||||||
        uses: docker/login-action@v3.3.0
 | 
					        uses: docker/login-action@v3.4.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          registry: ghcr.io
 | 
					          registry: ghcr.io
 | 
				
			||||||
          username: ${{ github.actor }}
 | 
					          username: ${{ github.actor }}
 | 
				
			||||||
@@ -213,7 +207,7 @@ jobs:
 | 
				
			|||||||
          done
 | 
					          done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Create manifest list and push
 | 
					      - name: Create manifest list and push
 | 
				
			||||||
        working-directory: /tmp/digests/${{ matrix.image.target }}/${{ matrix.registry }}
 | 
					        working-directory: /tmp/digests/${{ matrix.image.build_type }}/${{ matrix.registry }}
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
          docker buildx imagetools create $(jq -Rcnr 'inputs | . / "," | map("-t " + .) | join(" ")' <<< "${{ steps.tags.outputs.tags}}") \
 | 
					          docker buildx imagetools create $(jq -Rcnr 'inputs | . / "," | map("-t " + .) | join(" ")' <<< "${{ steps.tags.outputs.tags}}") \
 | 
				
			||||||
            $(printf '${{ steps.tags.outputs.image }}@sha256:%s ' *)
 | 
					            $(printf '${{ steps.tags.outputs.image }}@sha256:%s ' *)
 | 
				
			||||||
@@ -244,3 +238,24 @@ jobs:
 | 
				
			|||||||
                content: description
 | 
					                content: description
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  deploy-esphome-schema:
 | 
				
			||||||
 | 
					    if: github.repository == 'esphome/esphome' && needs.init.outputs.branch_build == 'false'
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    needs: [init]
 | 
				
			||||||
 | 
					    environment: ${{ needs.init.outputs.deploy_env }}
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - name: Trigger Workflow
 | 
				
			||||||
 | 
					        uses: actions/github-script@v7.0.1
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          github-token: ${{ secrets.DEPLOY_ESPHOME_SCHEMA_REPO_TOKEN }}
 | 
				
			||||||
 | 
					          script: |
 | 
				
			||||||
 | 
					            github.rest.actions.createWorkflowDispatch({
 | 
				
			||||||
 | 
					              owner: "esphome",
 | 
				
			||||||
 | 
					              repo: "esphome-schema",
 | 
				
			||||||
 | 
					              workflow_id: "generate-schemas.yml",
 | 
				
			||||||
 | 
					              ref: "main",
 | 
				
			||||||
 | 
					              inputs: {
 | 
				
			||||||
 | 
					                version: "${{ needs.init.outputs.tag }}",
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/stale.yml
									
									
									
									
										vendored
									
									
								
							@@ -17,7 +17,7 @@ jobs:
 | 
				
			|||||||
  stale:
 | 
					  stale:
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/stale@v9.0.0
 | 
					      - uses: actions/stale@v9.1.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          days-before-pr-stale: 90
 | 
					          days-before-pr-stale: 90
 | 
				
			||||||
          days-before-pr-close: 7
 | 
					          days-before-pr-close: 7
 | 
				
			||||||
@@ -37,7 +37,7 @@ jobs:
 | 
				
			|||||||
  close-issues:
 | 
					  close-issues:
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/stale@v9.0.0
 | 
					      - uses: actions/stale@v9.1.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          days-before-pr-stale: -1
 | 
					          days-before-pr-stale: -1
 | 
				
			||||||
          days-before-pr-close: -1
 | 
					          days-before-pr-close: -1
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										14
									
								
								.github/workflows/sync-device-classes.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/workflows/sync-device-classes.yml
									
									
									
									
										vendored
									
									
								
							@@ -13,18 +13,18 @@ jobs:
 | 
				
			|||||||
    if: github.repository == 'esphome/esphome'
 | 
					    if: github.repository == 'esphome/esphome'
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Checkout
 | 
					      - name: Checkout
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Checkout Home Assistant
 | 
					      - name: Checkout Home Assistant
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          repository: home-assistant/core
 | 
					          repository: home-assistant/core
 | 
				
			||||||
          path: lib/home-assistant
 | 
					          path: lib/home-assistant
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Setup Python
 | 
					      - name: Setup Python
 | 
				
			||||||
        uses: actions/setup-python@v5.2.0
 | 
					        uses: actions/setup-python@v5.6.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          python-version: 3.12
 | 
					          python-version: 3.13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Install Home Assistant
 | 
					      - name: Install Home Assistant
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
@@ -36,11 +36,11 @@ jobs:
 | 
				
			|||||||
          python ./script/sync-device_class.py
 | 
					          python ./script/sync-device_class.py
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Commit changes
 | 
					      - name: Commit changes
 | 
				
			||||||
        uses: peter-evans/create-pull-request@v7.0.5
 | 
					        uses: peter-evans/create-pull-request@v7.0.8
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          commit-message: "Synchronise Device Classes from Home Assistant"
 | 
					          commit-message: "Synchronise Device Classes from Home Assistant"
 | 
				
			||||||
          committer: esphomebot <esphome@nabucasa.com>
 | 
					          committer: esphomebot <esphome@openhomefoundation.org>
 | 
				
			||||||
          author: esphomebot <esphome@nabucasa.com>
 | 
					          author: esphomebot <esphome@openhomefoundation.org>
 | 
				
			||||||
          branch: sync/device-classes
 | 
					          branch: sync/device-classes
 | 
				
			||||||
          delete-branch: true
 | 
					          delete-branch: true
 | 
				
			||||||
          title: "Synchronise Device Classes from Home Assistant"
 | 
					          title: "Synchronise Device Classes from Home Assistant"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/yaml-lint.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/yaml-lint.yml
									
									
									
									
										vendored
									
									
								
							@@ -18,7 +18,7 @@ jobs:
 | 
				
			|||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - name: Check out code from GitHub
 | 
					      - name: Check out code from GitHub
 | 
				
			||||||
        uses: actions/checkout@v4.1.7
 | 
					        uses: actions/checkout@v4.2.2
 | 
				
			||||||
      - name: Run yamllint
 | 
					      - name: Run yamllint
 | 
				
			||||||
        uses: frenck/action-yamllint@v1.5.0
 | 
					        uses: frenck/action-yamllint@v1.5.0
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -75,6 +75,9 @@ cov.xml
 | 
				
			|||||||
# pyenv
 | 
					# pyenv
 | 
				
			||||||
.python-version
 | 
					.python-version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# asdf
 | 
				
			||||||
 | 
					.tool-versions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Environments
 | 
					# Environments
 | 
				
			||||||
.env
 | 
					.env
 | 
				
			||||||
.venv
 | 
					.venv
 | 
				
			||||||
@@ -140,3 +143,4 @@ sdkconfig.*
 | 
				
			|||||||
/components
 | 
					/components
 | 
				
			||||||
/managed_components
 | 
					/managed_components
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					api-docs/
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,27 +4,19 @@
 | 
				
			|||||||
repos:
 | 
					repos:
 | 
				
			||||||
  - repo: https://github.com/astral-sh/ruff-pre-commit
 | 
					  - repo: https://github.com/astral-sh/ruff-pre-commit
 | 
				
			||||||
    # Ruff version.
 | 
					    # Ruff version.
 | 
				
			||||||
    rev: v0.5.4
 | 
					    rev: v0.11.10
 | 
				
			||||||
    hooks:
 | 
					    hooks:
 | 
				
			||||||
      # Run the linter.
 | 
					      # Run the linter.
 | 
				
			||||||
      - id: ruff
 | 
					      - id: ruff
 | 
				
			||||||
        args: [--fix]
 | 
					        args: [--fix]
 | 
				
			||||||
      # Run the formatter.
 | 
					      # Run the formatter.
 | 
				
			||||||
      - id: ruff-format
 | 
					      - id: ruff-format
 | 
				
			||||||
  - repo: https://github.com/psf/black-pre-commit-mirror
 | 
					 | 
				
			||||||
    rev: 24.4.2
 | 
					 | 
				
			||||||
    hooks:
 | 
					 | 
				
			||||||
      - id: black
 | 
					 | 
				
			||||||
        args:
 | 
					 | 
				
			||||||
          - --safe
 | 
					 | 
				
			||||||
          - --quiet
 | 
					 | 
				
			||||||
        files: ^((esphome|script|tests)/.+)?[^/]+\.py$
 | 
					 | 
				
			||||||
  - repo: https://github.com/PyCQA/flake8
 | 
					  - repo: https://github.com/PyCQA/flake8
 | 
				
			||||||
    rev: 6.1.0
 | 
					    rev: 7.2.0
 | 
				
			||||||
    hooks:
 | 
					    hooks:
 | 
				
			||||||
      - id: flake8
 | 
					      - id: flake8
 | 
				
			||||||
        additional_dependencies:
 | 
					        additional_dependencies:
 | 
				
			||||||
          - flake8-docstrings==1.5.0
 | 
					          - flake8-docstrings==1.7.0
 | 
				
			||||||
          - pydocstyle==5.1.1
 | 
					          - pydocstyle==5.1.1
 | 
				
			||||||
        files: ^(esphome|tests)/.+\.py$
 | 
					        files: ^(esphome|tests)/.+\.py$
 | 
				
			||||||
  - repo: https://github.com/pre-commit/pre-commit-hooks
 | 
					  - repo: https://github.com/pre-commit/pre-commit-hooks
 | 
				
			||||||
@@ -36,12 +28,12 @@ repos:
 | 
				
			|||||||
          - --branch=release
 | 
					          - --branch=release
 | 
				
			||||||
          - --branch=beta
 | 
					          - --branch=beta
 | 
				
			||||||
  - repo: https://github.com/asottile/pyupgrade
 | 
					  - repo: https://github.com/asottile/pyupgrade
 | 
				
			||||||
    rev: v3.15.2
 | 
					    rev: v3.20.0
 | 
				
			||||||
    hooks:
 | 
					    hooks:
 | 
				
			||||||
      - id: pyupgrade
 | 
					      - id: pyupgrade
 | 
				
			||||||
        args: [--py39-plus]
 | 
					        args: [--py310-plus]
 | 
				
			||||||
  - repo: https://github.com/adrienverge/yamllint.git
 | 
					  - repo: https://github.com/adrienverge/yamllint.git
 | 
				
			||||||
    rev: v1.35.1
 | 
					    rev: v1.37.1
 | 
				
			||||||
    hooks:
 | 
					    hooks:
 | 
				
			||||||
      - id: yamllint
 | 
					      - id: yamllint
 | 
				
			||||||
  - repo: https://github.com/pre-commit/mirrors-clang-format
 | 
					  - repo: https://github.com/pre-commit/mirrors-clang-format
 | 
				
			||||||
@@ -53,6 +45,6 @@ repos:
 | 
				
			|||||||
    hooks:
 | 
					    hooks:
 | 
				
			||||||
      - id: pylint
 | 
					      - id: pylint
 | 
				
			||||||
        name: pylint
 | 
					        name: pylint
 | 
				
			||||||
        entry: script/run-in-env.sh pylint
 | 
					        entry: python3 script/run-in-env.py pylint
 | 
				
			||||||
        language: script
 | 
					        language: system
 | 
				
			||||||
        types: [python]
 | 
					        types: [python]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										57
									
								
								CODEOWNERS
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								CODEOWNERS
									
									
									
									
									
								
							@@ -48,7 +48,10 @@ esphome/components/at581x/* @X-Ryl669
 | 
				
			|||||||
esphome/components/atc_mithermometer/* @ahpohl
 | 
					esphome/components/atc_mithermometer/* @ahpohl
 | 
				
			||||||
esphome/components/atm90e26/* @danieltwagner
 | 
					esphome/components/atm90e26/* @danieltwagner
 | 
				
			||||||
esphome/components/atm90e32/* @circuitsetup @descipher
 | 
					esphome/components/atm90e32/* @circuitsetup @descipher
 | 
				
			||||||
 | 
					esphome/components/audio/* @kahrendt
 | 
				
			||||||
 | 
					esphome/components/audio_adc/* @kbx81
 | 
				
			||||||
esphome/components/audio_dac/* @kbx81
 | 
					esphome/components/audio_dac/* @kbx81
 | 
				
			||||||
 | 
					esphome/components/axs15231/* @clydebarrow
 | 
				
			||||||
esphome/components/b_parasite/* @rbaron
 | 
					esphome/components/b_parasite/* @rbaron
 | 
				
			||||||
esphome/components/ballu/* @bazuchan
 | 
					esphome/components/ballu/* @bazuchan
 | 
				
			||||||
esphome/components/bang_bang/* @OttoWinter
 | 
					esphome/components/bang_bang/* @OttoWinter
 | 
				
			||||||
@@ -83,16 +86,20 @@ esphome/components/bmp581/* @kahrendt
 | 
				
			|||||||
esphome/components/bp1658cj/* @Cossid
 | 
					esphome/components/bp1658cj/* @Cossid
 | 
				
			||||||
esphome/components/bp5758d/* @Cossid
 | 
					esphome/components/bp5758d/* @Cossid
 | 
				
			||||||
esphome/components/button/* @esphome/core
 | 
					esphome/components/button/* @esphome/core
 | 
				
			||||||
 | 
					esphome/components/bytebuffer/* @clydebarrow
 | 
				
			||||||
esphome/components/canbus/* @danielschramm @mvturnho
 | 
					esphome/components/canbus/* @danielschramm @mvturnho
 | 
				
			||||||
esphome/components/cap1188/* @mreditor97
 | 
					esphome/components/cap1188/* @mreditor97
 | 
				
			||||||
esphome/components/captive_portal/* @OttoWinter
 | 
					esphome/components/captive_portal/* @OttoWinter
 | 
				
			||||||
esphome/components/ccs811/* @habbie
 | 
					esphome/components/ccs811/* @habbie
 | 
				
			||||||
esphome/components/cd74hc4067/* @asoehlke
 | 
					esphome/components/cd74hc4067/* @asoehlke
 | 
				
			||||||
esphome/components/ch422g/* @clydebarrow @jesterret
 | 
					esphome/components/ch422g/* @clydebarrow @jesterret
 | 
				
			||||||
 | 
					esphome/components/chsc6x/* @kkosik20
 | 
				
			||||||
esphome/components/climate/* @esphome/core
 | 
					esphome/components/climate/* @esphome/core
 | 
				
			||||||
esphome/components/climate_ir/* @glmnet
 | 
					esphome/components/climate_ir/* @glmnet
 | 
				
			||||||
 | 
					esphome/components/cm1106/* @andrewjswan
 | 
				
			||||||
esphome/components/color_temperature/* @jesserockz
 | 
					esphome/components/color_temperature/* @jesserockz
 | 
				
			||||||
esphome/components/combination/* @Cat-Ion @kahrendt
 | 
					esphome/components/combination/* @Cat-Ion @kahrendt
 | 
				
			||||||
 | 
					esphome/components/const/* @esphome/core
 | 
				
			||||||
esphome/components/coolix/* @glmnet
 | 
					esphome/components/coolix/* @glmnet
 | 
				
			||||||
esphome/components/copy/* @OttoWinter
 | 
					esphome/components/copy/* @OttoWinter
 | 
				
			||||||
esphome/components/cover/* @esphome/core
 | 
					esphome/components/cover/* @esphome/core
 | 
				
			||||||
@@ -128,6 +135,11 @@ esphome/components/ens160_base/* @latonita @vincentscode
 | 
				
			|||||||
esphome/components/ens160_i2c/* @latonita
 | 
					esphome/components/ens160_i2c/* @latonita
 | 
				
			||||||
esphome/components/ens160_spi/* @latonita
 | 
					esphome/components/ens160_spi/* @latonita
 | 
				
			||||||
esphome/components/ens210/* @itn3rd77
 | 
					esphome/components/ens210/* @itn3rd77
 | 
				
			||||||
 | 
					esphome/components/es7210/* @kahrendt
 | 
				
			||||||
 | 
					esphome/components/es7243e/* @kbx81
 | 
				
			||||||
 | 
					esphome/components/es8156/* @kbx81
 | 
				
			||||||
 | 
					esphome/components/es8311/* @kahrendt @kroimon
 | 
				
			||||||
 | 
					esphome/components/es8388/* @P4uLT
 | 
				
			||||||
esphome/components/esp32/* @esphome/core
 | 
					esphome/components/esp32/* @esphome/core
 | 
				
			||||||
esphome/components/esp32_ble/* @Rapsssito @jesserockz
 | 
					esphome/components/esp32_ble/* @Rapsssito @jesserockz
 | 
				
			||||||
esphome/components/esp32_ble_client/* @jesserockz
 | 
					esphome/components/esp32_ble_client/* @jesserockz
 | 
				
			||||||
@@ -138,8 +150,10 @@ esphome/components/esp32_improv/* @jesserockz
 | 
				
			|||||||
esphome/components/esp32_rmt/* @jesserockz
 | 
					esphome/components/esp32_rmt/* @jesserockz
 | 
				
			||||||
esphome/components/esp32_rmt_led_strip/* @jesserockz
 | 
					esphome/components/esp32_rmt_led_strip/* @jesserockz
 | 
				
			||||||
esphome/components/esp8266/* @esphome/core
 | 
					esphome/components/esp8266/* @esphome/core
 | 
				
			||||||
 | 
					esphome/components/esp_ldo/* @clydebarrow
 | 
				
			||||||
esphome/components/ethernet_info/* @gtjadsonsantos
 | 
					esphome/components/ethernet_info/* @gtjadsonsantos
 | 
				
			||||||
esphome/components/event/* @nohat
 | 
					esphome/components/event/* @nohat
 | 
				
			||||||
 | 
					esphome/components/event_emitter/* @Rapsssito
 | 
				
			||||||
esphome/components/exposure_notifications/* @OttoWinter
 | 
					esphome/components/exposure_notifications/* @OttoWinter
 | 
				
			||||||
esphome/components/ezo/* @ssieb
 | 
					esphome/components/ezo/* @ssieb
 | 
				
			||||||
esphome/components/ezo_pmp/* @carlos-sarmiento
 | 
					esphome/components/ezo_pmp/* @carlos-sarmiento
 | 
				
			||||||
@@ -158,7 +172,7 @@ esphome/components/gp2y1010au0f/* @zry98
 | 
				
			|||||||
esphome/components/gp8403/* @jesserockz
 | 
					esphome/components/gp8403/* @jesserockz
 | 
				
			||||||
esphome/components/gpio/* @esphome/core
 | 
					esphome/components/gpio/* @esphome/core
 | 
				
			||||||
esphome/components/gpio/one_wire/* @ssieb
 | 
					esphome/components/gpio/one_wire/* @ssieb
 | 
				
			||||||
esphome/components/gps/* @coogle
 | 
					esphome/components/gps/* @coogle @ximex
 | 
				
			||||||
esphome/components/graph/* @synco
 | 
					esphome/components/graph/* @synco
 | 
				
			||||||
esphome/components/graphical_display_menu/* @MrMDavidson
 | 
					esphome/components/graphical_display_menu/* @MrMDavidson
 | 
				
			||||||
esphome/components/gree/* @orestismers
 | 
					esphome/components/gree/* @orestismers
 | 
				
			||||||
@@ -175,6 +189,7 @@ esphome/components/haier/text_sensor/* @paveldn
 | 
				
			|||||||
esphome/components/havells_solar/* @sourabhjaiswal
 | 
					esphome/components/havells_solar/* @sourabhjaiswal
 | 
				
			||||||
esphome/components/hbridge/fan/* @WeekendWarrior
 | 
					esphome/components/hbridge/fan/* @WeekendWarrior
 | 
				
			||||||
esphome/components/hbridge/light/* @DotNetDann
 | 
					esphome/components/hbridge/light/* @DotNetDann
 | 
				
			||||||
 | 
					esphome/components/hbridge/switch/* @dwmw2
 | 
				
			||||||
esphome/components/he60r/* @clydebarrow
 | 
					esphome/components/he60r/* @clydebarrow
 | 
				
			||||||
esphome/components/heatpumpir/* @rob-deutsch
 | 
					esphome/components/heatpumpir/* @rob-deutsch
 | 
				
			||||||
esphome/components/hitachi_ac424/* @sourabhjaiswal
 | 
					esphome/components/hitachi_ac424/* @sourabhjaiswal
 | 
				
			||||||
@@ -196,10 +211,11 @@ esphome/components/htu31d/* @betterengineering
 | 
				
			|||||||
esphome/components/hydreon_rgxx/* @functionpointer
 | 
					esphome/components/hydreon_rgxx/* @functionpointer
 | 
				
			||||||
esphome/components/hyt271/* @Philippe12
 | 
					esphome/components/hyt271/* @Philippe12
 | 
				
			||||||
esphome/components/i2c/* @esphome/core
 | 
					esphome/components/i2c/* @esphome/core
 | 
				
			||||||
 | 
					esphome/components/i2c_device/* @gabest11
 | 
				
			||||||
esphome/components/i2s_audio/* @jesserockz
 | 
					esphome/components/i2s_audio/* @jesserockz
 | 
				
			||||||
esphome/components/i2s_audio/media_player/* @jesserockz
 | 
					esphome/components/i2s_audio/media_player/* @jesserockz
 | 
				
			||||||
esphome/components/i2s_audio/microphone/* @jesserockz
 | 
					esphome/components/i2s_audio/microphone/* @jesserockz
 | 
				
			||||||
esphome/components/i2s_audio/speaker/* @jesserockz
 | 
					esphome/components/i2s_audio/speaker/* @jesserockz @kahrendt
 | 
				
			||||||
esphome/components/iaqcore/* @yozik04
 | 
					esphome/components/iaqcore/* @yozik04
 | 
				
			||||||
esphome/components/ili9xxx/* @clydebarrow @nielsnl68
 | 
					esphome/components/ili9xxx/* @clydebarrow @nielsnl68
 | 
				
			||||||
esphome/components/improv_base/* @esphome/core
 | 
					esphome/components/improv_base/* @esphome/core
 | 
				
			||||||
@@ -220,9 +236,11 @@ esphome/components/kamstrup_kmp/* @cfeenstra1024
 | 
				
			|||||||
esphome/components/key_collector/* @ssieb
 | 
					esphome/components/key_collector/* @ssieb
 | 
				
			||||||
esphome/components/key_provider/* @ssieb
 | 
					esphome/components/key_provider/* @ssieb
 | 
				
			||||||
esphome/components/kuntze/* @ssieb
 | 
					esphome/components/kuntze/* @ssieb
 | 
				
			||||||
 | 
					esphome/components/lc709203f/* @ilikecake
 | 
				
			||||||
esphome/components/lcd_menu/* @numo68
 | 
					esphome/components/lcd_menu/* @numo68
 | 
				
			||||||
esphome/components/ld2410/* @regevbr @sebcaps
 | 
					esphome/components/ld2410/* @regevbr @sebcaps
 | 
				
			||||||
esphome/components/ld2420/* @descipher
 | 
					esphome/components/ld2420/* @descipher
 | 
				
			||||||
 | 
					esphome/components/ld2450/* @hareeshmu
 | 
				
			||||||
esphome/components/ledc/* @OttoWinter
 | 
					esphome/components/ledc/* @OttoWinter
 | 
				
			||||||
esphome/components/libretiny/* @kuba2k2
 | 
					esphome/components/libretiny/* @kuba2k2
 | 
				
			||||||
esphome/components/libretiny_pwm/* @kuba2k2
 | 
					esphome/components/libretiny_pwm/* @kuba2k2
 | 
				
			||||||
@@ -231,12 +249,15 @@ esphome/components/lightwaverf/* @max246
 | 
				
			|||||||
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/logger/select/* @clydebarrow
 | 
				
			||||||
esphome/components/ltr390/* @latonita @sjtrny
 | 
					esphome/components/ltr390/* @latonita @sjtrny
 | 
				
			||||||
esphome/components/ltr501/* @latonita
 | 
					esphome/components/ltr501/* @latonita
 | 
				
			||||||
esphome/components/ltr_als_ps/* @latonita
 | 
					esphome/components/ltr_als_ps/* @latonita
 | 
				
			||||||
esphome/components/lvgl/* @clydebarrow
 | 
					esphome/components/lvgl/* @clydebarrow
 | 
				
			||||||
esphome/components/m5stack_8angle/* @rnauber
 | 
					esphome/components/m5stack_8angle/* @rnauber
 | 
				
			||||||
 | 
					esphome/components/mapping/* @clydebarrow
 | 
				
			||||||
esphome/components/matrix_keypad/* @ssieb
 | 
					esphome/components/matrix_keypad/* @ssieb
 | 
				
			||||||
 | 
					esphome/components/max17043/* @blacknell
 | 
				
			||||||
esphome/components/max31865/* @DAVe3283
 | 
					esphome/components/max31865/* @DAVe3283
 | 
				
			||||||
esphome/components/max44009/* @berfenger
 | 
					esphome/components/max44009/* @berfenger
 | 
				
			||||||
esphome/components/max6956/* @looping40
 | 
					esphome/components/max6956/* @looping40
 | 
				
			||||||
@@ -251,6 +272,7 @@ esphome/components/mcp23x17_base/* @jesserockz
 | 
				
			|||||||
esphome/components/mcp23xxx_base/* @jesserockz
 | 
					esphome/components/mcp23xxx_base/* @jesserockz
 | 
				
			||||||
esphome/components/mcp2515/* @danielschramm @mvturnho
 | 
					esphome/components/mcp2515/* @danielschramm @mvturnho
 | 
				
			||||||
esphome/components/mcp3204/* @rsumner
 | 
					esphome/components/mcp3204/* @rsumner
 | 
				
			||||||
 | 
					esphome/components/mcp4461/* @p1ngb4ck
 | 
				
			||||||
esphome/components/mcp4728/* @berfenger
 | 
					esphome/components/mcp4728/* @berfenger
 | 
				
			||||||
esphome/components/mcp47a1/* @jesserockz
 | 
					esphome/components/mcp47a1/* @jesserockz
 | 
				
			||||||
esphome/components/mcp9600/* @mreditor97
 | 
					esphome/components/mcp9600/* @mreditor97
 | 
				
			||||||
@@ -260,11 +282,13 @@ esphome/components/mdns/* @esphome/core
 | 
				
			|||||||
esphome/components/media_player/* @jesserockz
 | 
					esphome/components/media_player/* @jesserockz
 | 
				
			||||||
esphome/components/micro_wake_word/* @jesserockz @kahrendt
 | 
					esphome/components/micro_wake_word/* @jesserockz @kahrendt
 | 
				
			||||||
esphome/components/micronova/* @jorre05
 | 
					esphome/components/micronova/* @jorre05
 | 
				
			||||||
esphome/components/microphone/* @jesserockz
 | 
					esphome/components/microphone/* @jesserockz @kahrendt
 | 
				
			||||||
esphome/components/mics_4514/* @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/mipi_spi/* @clydebarrow
 | 
				
			||||||
esphome/components/mitsubishi/* @RubyBailey
 | 
					esphome/components/mitsubishi/* @RubyBailey
 | 
				
			||||||
 | 
					esphome/components/mixer/speaker/* @kahrendt
 | 
				
			||||||
esphome/components/mlx90393/* @functionpointer
 | 
					esphome/components/mlx90393/* @functionpointer
 | 
				
			||||||
esphome/components/mlx90614/* @jesserockz
 | 
					esphome/components/mlx90614/* @jesserockz
 | 
				
			||||||
esphome/components/mmc5603/* @benhoff
 | 
					esphome/components/mmc5603/* @benhoff
 | 
				
			||||||
@@ -283,6 +307,7 @@ esphome/components/mopeka_std_check/* @Fabian-Schmidt
 | 
				
			|||||||
esphome/components/mpl3115a2/* @kbickar
 | 
					esphome/components/mpl3115a2/* @kbickar
 | 
				
			||||||
esphome/components/mpu6886/* @fabaff
 | 
					esphome/components/mpu6886/* @fabaff
 | 
				
			||||||
esphome/components/ms8607/* @e28eta
 | 
					esphome/components/ms8607/* @e28eta
 | 
				
			||||||
 | 
					esphome/components/msa3xx/* @latonita
 | 
				
			||||||
esphome/components/nau7802/* @cujomalainey
 | 
					esphome/components/nau7802/* @cujomalainey
 | 
				
			||||||
esphome/components/network/* @esphome/core
 | 
					esphome/components/network/* @esphome/core
 | 
				
			||||||
esphome/components/nextion/* @edwardtfn @senexcrenshaw
 | 
					esphome/components/nextion/* @edwardtfn @senexcrenshaw
 | 
				
			||||||
@@ -295,10 +320,12 @@ esphome/components/noblex/* @AGalfra
 | 
				
			|||||||
esphome/components/npi19/* @bakerkj
 | 
					esphome/components/npi19/* @bakerkj
 | 
				
			||||||
esphome/components/number/* @esphome/core
 | 
					esphome/components/number/* @esphome/core
 | 
				
			||||||
esphome/components/one_wire/* @ssieb
 | 
					esphome/components/one_wire/* @ssieb
 | 
				
			||||||
esphome/components/online_image/* @guillempages
 | 
					esphome/components/online_image/* @clydebarrow @guillempages
 | 
				
			||||||
esphome/components/opentherm/* @olegtarasov
 | 
					esphome/components/opentherm/* @olegtarasov
 | 
				
			||||||
 | 
					esphome/components/openthread/* @mrene
 | 
				
			||||||
esphome/components/ota/* @esphome/core
 | 
					esphome/components/ota/* @esphome/core
 | 
				
			||||||
esphome/components/output/* @esphome/core
 | 
					esphome/components/output/* @esphome/core
 | 
				
			||||||
 | 
					esphome/components/packet_transport/* @clydebarrow
 | 
				
			||||||
esphome/components/pca6416a/* @Mat931
 | 
					esphome/components/pca6416a/* @Mat931
 | 
				
			||||||
esphome/components/pca9554/* @clydebarrow @hwstar
 | 
					esphome/components/pca9554/* @clydebarrow @hwstar
 | 
				
			||||||
esphome/components/pcf85063/* @brogon
 | 
					esphome/components/pcf85063/* @brogon
 | 
				
			||||||
@@ -306,7 +333,9 @@ esphome/components/pcf8563/* @KoenBreeman
 | 
				
			|||||||
esphome/components/pid/* @OttoWinter
 | 
					esphome/components/pid/* @OttoWinter
 | 
				
			||||||
esphome/components/pipsolar/* @andreashergert1984
 | 
					esphome/components/pipsolar/* @andreashergert1984
 | 
				
			||||||
esphome/components/pm1006/* @habbie
 | 
					esphome/components/pm1006/* @habbie
 | 
				
			||||||
 | 
					esphome/components/pm2005/* @andrewjswan
 | 
				
			||||||
esphome/components/pmsa003i/* @sjtrny
 | 
					esphome/components/pmsa003i/* @sjtrny
 | 
				
			||||||
 | 
					esphome/components/pmsx003/* @ximex
 | 
				
			||||||
esphome/components/pmwcs3/* @SeByDocKy
 | 
					esphome/components/pmwcs3/* @SeByDocKy
 | 
				
			||||||
esphome/components/pn532/* @OttoWinter @jesserockz
 | 
					esphome/components/pn532/* @OttoWinter @jesserockz
 | 
				
			||||||
esphome/components/pn532_i2c/* @OttoWinter @jesserockz
 | 
					esphome/components/pn532_i2c/* @OttoWinter @jesserockz
 | 
				
			||||||
@@ -324,14 +353,14 @@ esphome/components/pvvx_mithermometer/* @pasiz
 | 
				
			|||||||
esphome/components/pylontech/* @functionpointer
 | 
					esphome/components/pylontech/* @functionpointer
 | 
				
			||||||
esphome/components/qmp6988/* @andrewpc
 | 
					esphome/components/qmp6988/* @andrewpc
 | 
				
			||||||
esphome/components/qr_code/* @wjtje
 | 
					esphome/components/qr_code/* @wjtje
 | 
				
			||||||
esphome/components/qspi_amoled/* @clydebarrow
 | 
					esphome/components/qspi_dbi/* @clydebarrow
 | 
				
			||||||
esphome/components/qwiic_pir/* @kahrendt
 | 
					esphome/components/qwiic_pir/* @kahrendt
 | 
				
			||||||
esphome/components/radon_eye_ble/* @jeffeb3
 | 
					esphome/components/radon_eye_ble/* @jeffeb3
 | 
				
			||||||
esphome/components/radon_eye_rd200/* @jeffeb3
 | 
					esphome/components/radon_eye_rd200/* @jeffeb3
 | 
				
			||||||
esphome/components/rc522/* @glmnet
 | 
					esphome/components/rc522/* @glmnet
 | 
				
			||||||
esphome/components/rc522_i2c/* @glmnet
 | 
					esphome/components/rc522_i2c/* @glmnet
 | 
				
			||||||
esphome/components/rc522_spi/* @glmnet
 | 
					esphome/components/rc522_spi/* @glmnet
 | 
				
			||||||
esphome/components/resistance_sampler/* @jesserockz
 | 
					esphome/components/resampler/speaker/* @kahrendt
 | 
				
			||||||
esphome/components/restart/* @esphome/core
 | 
					esphome/components/restart/* @esphome/core
 | 
				
			||||||
esphome/components/rf_bridge/* @jesserockz
 | 
					esphome/components/rf_bridge/* @jesserockz
 | 
				
			||||||
esphome/components/rgbct/* @jesserockz
 | 
					esphome/components/rgbct/* @jesserockz
 | 
				
			||||||
@@ -344,10 +373,12 @@ esphome/components/rtttl/* @glmnet
 | 
				
			|||||||
esphome/components/safe_mode/* @jsuanet @kbx81 @paulmonigatti
 | 
					esphome/components/safe_mode/* @jsuanet @kbx81 @paulmonigatti
 | 
				
			||||||
esphome/components/scd4x/* @martgras @sjtrny
 | 
					esphome/components/scd4x/* @martgras @sjtrny
 | 
				
			||||||
esphome/components/script/* @esphome/core
 | 
					esphome/components/script/* @esphome/core
 | 
				
			||||||
esphome/components/sdl/* @clydebarrow
 | 
					esphome/components/sdl/* @bdm310 @clydebarrow
 | 
				
			||||||
esphome/components/sdm_meter/* @jesserockz @polyfaces
 | 
					esphome/components/sdm_meter/* @jesserockz @polyfaces
 | 
				
			||||||
esphome/components/sdp3x/* @Azimath
 | 
					esphome/components/sdp3x/* @Azimath
 | 
				
			||||||
esphome/components/seeed_mr24hpc1/* @limengdu
 | 
					esphome/components/seeed_mr24hpc1/* @limengdu
 | 
				
			||||||
 | 
					esphome/components/seeed_mr60bha2/* @limengdu
 | 
				
			||||||
 | 
					esphome/components/seeed_mr60fda2/* @limengdu
 | 
				
			||||||
esphome/components/selec_meter/* @sourabhjaiswal
 | 
					esphome/components/selec_meter/* @sourabhjaiswal
 | 
				
			||||||
esphome/components/select/* @esphome/core
 | 
					esphome/components/select/* @esphome/core
 | 
				
			||||||
esphome/components/sen0321/* @notjj
 | 
					esphome/components/sen0321/* @notjj
 | 
				
			||||||
@@ -373,7 +404,9 @@ esphome/components/smt100/* @piechade
 | 
				
			|||||||
esphome/components/sn74hc165/* @jesserockz
 | 
					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/speaker/* @jesserockz
 | 
					esphome/components/sound_level/* @kahrendt
 | 
				
			||||||
 | 
					esphome/components/speaker/* @jesserockz @kahrendt
 | 
				
			||||||
 | 
					esphome/components/speaker/media_player/* @kahrendt @synesthesiam
 | 
				
			||||||
esphome/components/spi/* @clydebarrow @esphome/core
 | 
					esphome/components/spi/* @clydebarrow @esphome/core
 | 
				
			||||||
esphome/components/spi_device/* @clydebarrow
 | 
					esphome/components/spi_device/* @clydebarrow
 | 
				
			||||||
esphome/components/spi_led_strip/* @clydebarrow
 | 
					esphome/components/spi_led_strip/* @clydebarrow
 | 
				
			||||||
@@ -402,7 +435,10 @@ esphome/components/substitutions/* @esphome/core
 | 
				
			|||||||
esphome/components/sun/* @OttoWinter
 | 
					esphome/components/sun/* @OttoWinter
 | 
				
			||||||
esphome/components/sun_gtil2/* @Mat931
 | 
					esphome/components/sun_gtil2/* @Mat931
 | 
				
			||||||
esphome/components/switch/* @esphome/core
 | 
					esphome/components/switch/* @esphome/core
 | 
				
			||||||
 | 
					esphome/components/switch/binary_sensor/* @ssieb
 | 
				
			||||||
 | 
					esphome/components/syslog/* @clydebarrow
 | 
				
			||||||
esphome/components/t6615/* @tylermenezes
 | 
					esphome/components/t6615/* @tylermenezes
 | 
				
			||||||
 | 
					esphome/components/tc74/* @sethgirvan
 | 
				
			||||||
esphome/components/tca9548a/* @andreashergert1984
 | 
					esphome/components/tca9548a/* @andreashergert1984
 | 
				
			||||||
esphome/components/tca9555/* @mobrembski
 | 
					esphome/components/tca9555/* @mobrembski
 | 
				
			||||||
esphome/components/tcl112/* @glmnet
 | 
					esphome/components/tcl112/* @glmnet
 | 
				
			||||||
@@ -426,6 +462,7 @@ esphome/components/tmp102/* @timsavage
 | 
				
			|||||||
esphome/components/tmp1075/* @sybrenstuvel
 | 
					esphome/components/tmp1075/* @sybrenstuvel
 | 
				
			||||||
esphome/components/tmp117/* @Azimath
 | 
					esphome/components/tmp117/* @Azimath
 | 
				
			||||||
esphome/components/tof10120/* @wstrzalka
 | 
					esphome/components/tof10120/* @wstrzalka
 | 
				
			||||||
 | 
					esphome/components/tormatic/* @ti-mo
 | 
				
			||||||
esphome/components/toshiba/* @kbx81
 | 
					esphome/components/toshiba/* @kbx81
 | 
				
			||||||
esphome/components/touchscreen/* @jesserockz @nielsnl68
 | 
					esphome/components/touchscreen/* @jesserockz @nielsnl68
 | 
				
			||||||
esphome/components/tsl2591/* @wjcarpenter
 | 
					esphome/components/tsl2591/* @wjcarpenter
 | 
				
			||||||
@@ -439,12 +476,15 @@ esphome/components/tuya/switch/* @jesserockz
 | 
				
			|||||||
esphome/components/tuya/text_sensor/* @dentra
 | 
					esphome/components/tuya/text_sensor/* @dentra
 | 
				
			||||||
esphome/components/uart/* @esphome/core
 | 
					esphome/components/uart/* @esphome/core
 | 
				
			||||||
esphome/components/uart/button/* @ssieb
 | 
					esphome/components/uart/button/* @ssieb
 | 
				
			||||||
 | 
					esphome/components/uart/packet_transport/* @clydebarrow
 | 
				
			||||||
esphome/components/udp/* @clydebarrow
 | 
					esphome/components/udp/* @clydebarrow
 | 
				
			||||||
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/update/* @jesserockz
 | 
					esphome/components/update/* @jesserockz
 | 
				
			||||||
esphome/components/uponor_smatrix/* @kroimon
 | 
					esphome/components/uponor_smatrix/* @kroimon
 | 
				
			||||||
 | 
					esphome/components/usb_host/* @clydebarrow
 | 
				
			||||||
 | 
					esphome/components/usb_uart/* @clydebarrow
 | 
				
			||||||
esphome/components/valve/* @esphome/core
 | 
					esphome/components/valve/* @esphome/core
 | 
				
			||||||
esphome/components/vbus/* @ssieb
 | 
					esphome/components/vbus/* @ssieb
 | 
				
			||||||
esphome/components/veml3235/* @kbx81
 | 
					esphome/components/veml3235/* @kbx81
 | 
				
			||||||
@@ -482,5 +522,6 @@ esphome/components/xiaomi_mhoc401/* @vevsvevs
 | 
				
			|||||||
esphome/components/xiaomi_rtcgq02lm/* @jesserockz
 | 
					esphome/components/xiaomi_rtcgq02lm/* @jesserockz
 | 
				
			||||||
esphome/components/xl9535/* @mreditor97
 | 
					esphome/components/xl9535/* @mreditor97
 | 
				
			||||||
esphome/components/xpt2046/touchscreen/* @nielsnl68 @numo68
 | 
					esphome/components/xpt2046/touchscreen/* @nielsnl68 @numo68
 | 
				
			||||||
 | 
					esphome/components/xxtea/* @clydebarrow
 | 
				
			||||||
esphome/components/zhlt01/* @cfeenstra1024
 | 
					esphome/components/zhlt01/* @cfeenstra1024
 | 
				
			||||||
esphome/components/zio_ultrasonic/* @kahrendt
 | 
					esphome/components/zio_ultrasonic/* @kahrendt
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Enforcement
 | 
					## Enforcement
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at esphome@nabucasa.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
 | 
					Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at esphome@openhomefoundation.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
 | 
					Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,14 @@
 | 
				
			|||||||
# Contributing to ESPHome
 | 
					# Contributing to ESPHome [](https://discord.gg/KhAMKrd) [](https://GitHub.com/esphome/esphome/releases/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
For a detailed guide, please see https://esphome.io/guides/contributing.html#contributing-to-esphome
 | 
					We welcome contributions to the ESPHome suite of code and documentation!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Things to note when contributing:
 | 
					Please read our [contributing guide](https://esphome.io/guides/contributing.html) if you wish to contribute to the
 | 
				
			||||||
 | 
					project and be sure to join us on [Discord](https://discord.gg/KhAMKrd).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 - Please test your changes :)
 | 
					**See also:**
 | 
				
			||||||
 - If a new feature is added or an existing user-facing feature is changed, you should also
 | 
					
 | 
				
			||||||
   update the [docs](https://github.com/esphome/esphome-docs). See [contributing to esphome-docs](https://esphome.io/guides/contributing.html#contributing-to-esphomedocs)
 | 
					[Documentation](https://esphome.io) -- [Issues](https://github.com/esphome/issues/issues) -- [Feature requests](https://github.com/esphome/feature-requests/issues)
 | 
				
			||||||
   for more information.
 | 
					
 | 
				
			||||||
 - Please also update the tests in the `tests/` folder. You can do so by just adding a line in one of the YAML files
 | 
					---
 | 
				
			||||||
   which checks if your new feature compiles correctly.
 | 
					
 | 
				
			||||||
 | 
					[](https://www.openhomefoundation.org/)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								README.md
									
									
									
									
									
								
							@@ -1,11 +1,16 @@
 | 
				
			|||||||
# ESPHome [](https://discord.gg/KhAMKrd) [](https://GitHub.com/esphome/esphome/releases/)
 | 
					# ESPHome [](https://discord.gg/KhAMKrd) [](https://GitHub.com/esphome/esphome/releases/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[](https://esphome.io/)
 | 
					<a href="https://esphome.io/">
 | 
				
			||||||
 | 
					  <picture>
 | 
				
			||||||
 | 
					    <source media="(prefers-color-scheme: dark)" srcset="https://esphome.io/_static/logo-text-on-dark.svg", alt="ESPHome Logo">
 | 
				
			||||||
 | 
					    <img src="https://esphome.io/_static/logo-text-on-light.svg" alt="ESPHome Logo">
 | 
				
			||||||
 | 
					  </picture>
 | 
				
			||||||
 | 
					</a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**Documentation:** https://esphome.io/
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
For issues, please go to [the issue tracker](https://github.com/esphome/issues/issues).
 | 
					[Documentation](https://esphome.io) -- [Issues](https://github.com/esphome/issues/issues) -- [Feature requests](https://github.com/esphome/feature-requests/issues)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
For feature requests, please see [feature requests](https://github.com/esphome/feature-requests/issues).
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[](https://www.openhomefoundation.org/)
 | 
					[](https://www.openhomefoundation.org/)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,139 +1,56 @@
 | 
				
			|||||||
# Build these with the build.py script
 | 
					ARG BUILD_VERSION=dev
 | 
				
			||||||
# Example:
 | 
					ARG BUILD_OS=alpine
 | 
				
			||||||
#   python3 docker/build.py --tag dev --arch amd64 --build-type docker build
 | 
					ARG BUILD_BASE_VERSION=2025.04.0
 | 
				
			||||||
 | 
					ARG BUILD_TYPE=docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# One of "docker", "hassio"
 | 
					FROM ghcr.io/esphome/docker-base:${BUILD_OS}-${BUILD_BASE_VERSION} AS base-source-docker
 | 
				
			||||||
ARG BASEIMGTYPE=docker
 | 
					FROM ghcr.io/esphome/docker-base:${BUILD_OS}-ha-addon-${BUILD_BASE_VERSION} AS base-source-ha-addon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ARG BUILD_TYPE
 | 
				
			||||||
 | 
					FROM base-source-${BUILD_TYPE} AS base
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# https://github.com/hassio-addons/addon-debian-base/releases
 | 
					RUN git config --system --add safe.directory "*"
 | 
				
			||||||
FROM ghcr.io/hassio-addons/debian-base:7.2.0 AS base-hassio
 | 
					 | 
				
			||||||
# https://hub.docker.com/_/debian?tab=tags&page=1&name=bookworm
 | 
					 | 
				
			||||||
FROM debian:12.2-slim AS base-docker
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM base-${BASEIMGTYPE} AS base
 | 
					ENV PIP_DISABLE_PIP_VERSION_CHECK=1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN pip install --no-cache-dir -U pip uv==0.6.14
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ARG TARGETARCH
 | 
					COPY requirements.txt /
 | 
				
			||||||
ARG TARGETVARIANT
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Note that --break-system-packages is used below because
 | 
					 | 
				
			||||||
# https://peps.python.org/pep-0668/ added a safety check that prevents
 | 
					 | 
				
			||||||
# installing packages with the same name as a system package. This is
 | 
					 | 
				
			||||||
# not a problem for us because we are not concerned about overwriting
 | 
					 | 
				
			||||||
# system packages because we are running in an isolated container.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN \
 | 
					RUN \
 | 
				
			||||||
    apt-get update \
 | 
					    uv pip install --no-cache-dir \
 | 
				
			||||||
    # Use pinned versions so that we get updates with build caching
 | 
					    -r /requirements.txt
 | 
				
			||||||
    && apt-get install -y --no-install-recommends \
 | 
					 | 
				
			||||||
        python3-pip=23.0.1+dfsg-1 \
 | 
					 | 
				
			||||||
        python3-setuptools=66.1.1-1 \
 | 
					 | 
				
			||||||
        python3-venv=3.11.2-1+b1 \
 | 
					 | 
				
			||||||
        python3-wheel=0.38.4-2 \
 | 
					 | 
				
			||||||
        iputils-ping=3:20221126-1 \
 | 
					 | 
				
			||||||
        git=1:2.39.5-0+deb12u1 \
 | 
					 | 
				
			||||||
        curl=7.88.1-10+deb12u7 \
 | 
					 | 
				
			||||||
        openssh-client=1:9.2p1-2+deb12u3 \
 | 
					 | 
				
			||||||
        python3-cffi=1.15.1-5 \
 | 
					 | 
				
			||||||
        libcairo2=1.16.0-7 \
 | 
					 | 
				
			||||||
        libmagic1=1:5.44-3 \
 | 
					 | 
				
			||||||
        patch=2.7.6-7 \
 | 
					 | 
				
			||||||
    && ( \
 | 
					 | 
				
			||||||
        ( \
 | 
					 | 
				
			||||||
            [ "$TARGETARCH$TARGETVARIANT" = "armv7" ] && \
 | 
					 | 
				
			||||||
                apt-get install -y --no-install-recommends \
 | 
					 | 
				
			||||||
                build-essential=12.9 \
 | 
					 | 
				
			||||||
                python3-dev=3.11.2-1+b1 \
 | 
					 | 
				
			||||||
                zlib1g-dev=1:1.2.13.dfsg-1 \
 | 
					 | 
				
			||||||
                libjpeg-dev=1:2.1.5-2 \
 | 
					 | 
				
			||||||
                libfreetype-dev=2.12.1+dfsg-5+deb12u3 \
 | 
					 | 
				
			||||||
                libssl-dev=3.0.14-1~deb12u2 \
 | 
					 | 
				
			||||||
                libffi-dev=3.4.4-1 \
 | 
					 | 
				
			||||||
                libopenjp2-7=2.5.0-2 \
 | 
					 | 
				
			||||||
                libtiff6=4.5.0-6+deb12u1 \
 | 
					 | 
				
			||||||
                cargo=0.66.0+ds1-1 \
 | 
					 | 
				
			||||||
                pkg-config=1.8.1-1 \
 | 
					 | 
				
			||||||
                gcc-arm-linux-gnueabihf=4:12.2.0-3 \
 | 
					 | 
				
			||||||
        ) \
 | 
					 | 
				
			||||||
        || [ "$TARGETARCH$TARGETVARIANT" != "armv7" ] \
 | 
					 | 
				
			||||||
    ) \
 | 
					 | 
				
			||||||
    && rm -rf \
 | 
					 | 
				
			||||||
        /tmp/* \
 | 
					 | 
				
			||||||
        /var/{cache,log}/* \
 | 
					 | 
				
			||||||
        /var/lib/apt/lists/*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ENV \
 | 
					 | 
				
			||||||
  # Fix click python3 lang warning https://click.palletsprojects.com/en/7.x/python3/
 | 
					 | 
				
			||||||
  LANG=C.UTF-8 LC_ALL=C.UTF-8 \
 | 
					 | 
				
			||||||
  # Store globally installed pio libs in /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-armhf.so.3 /lib/ld-linux.so.3; \
 | 
					 | 
				
			||||||
    fi
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN \
 | 
					RUN \
 | 
				
			||||||
    # Ubuntu python3-pip is missing wheel
 | 
					    platformio settings set enable_telemetry No \
 | 
				
			||||||
    if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
 | 
					 | 
				
			||||||
        export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
 | 
					 | 
				
			||||||
    fi; \
 | 
					 | 
				
			||||||
    pip3 install \
 | 
					 | 
				
			||||||
    --break-system-packages --no-cache-dir \
 | 
					 | 
				
			||||||
    # Keep platformio version in sync with requirements.txt
 | 
					 | 
				
			||||||
    platformio==6.1.15 \
 | 
					 | 
				
			||||||
    # Change some platformio settings
 | 
					 | 
				
			||||||
    && platformio settings set enable_telemetry No \
 | 
					 | 
				
			||||||
    && platformio settings set check_platformio_interval 1000000 \
 | 
					    && platformio settings set check_platformio_interval 1000000 \
 | 
				
			||||||
    && mkdir -p /piolibs
 | 
					    && mkdir -p /piolibs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
# First install requirements to leverage caching when requirements don't change
 | 
					 | 
				
			||||||
# tmpfs is for https://github.com/rust-lang/cargo/issues/8719
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
COPY requirements.txt requirements_optional.txt /
 | 
					 | 
				
			||||||
RUN --mount=type=tmpfs,target=/root/.cargo if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
 | 
					 | 
				
			||||||
        curl -L https://www.piwheels.org/cp311/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl -o /tmp/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl \
 | 
					 | 
				
			||||||
        && pip3 install --break-system-packages --no-cache-dir /tmp/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl \
 | 
					 | 
				
			||||||
        && rm /tmp/cryptography-43.0.0-cp37-abi3-linux_armv7l.whl \
 | 
					 | 
				
			||||||
        && export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
 | 
					 | 
				
			||||||
    fi; \
 | 
					 | 
				
			||||||
    CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse CARGO_HOME=/root/.cargo \
 | 
					 | 
				
			||||||
    pip3 install \
 | 
					 | 
				
			||||||
    --break-system-packages --no-cache-dir -r /requirements.txt -r /requirements_optional.txt
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
COPY script/platformio_install_deps.py platformio.ini /
 | 
					COPY script/platformio_install_deps.py platformio.ini /
 | 
				
			||||||
RUN /platformio_install_deps.py /platformio.ini --libraries
 | 
					RUN /platformio_install_deps.py /platformio.ini --libraries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Avoid unsafe git error when container user and file config volume permissions don't match
 | 
					ARG BUILD_VERSION
 | 
				
			||||||
RUN git config --system --add safe.directory '*'
 | 
					
 | 
				
			||||||
 | 
					LABEL \
 | 
				
			||||||
 | 
					    org.opencontainers.image.authors="The ESPHome Authors" \
 | 
				
			||||||
 | 
					    org.opencontainers.image.title="ESPHome" \
 | 
				
			||||||
 | 
					    org.opencontainers.image.description="ESPHome is a system to configure your microcontrollers by simple yet powerful configuration files and control them remotely through Home Automation systems" \
 | 
				
			||||||
 | 
					    org.opencontainers.image.url="https://esphome.io/" \
 | 
				
			||||||
 | 
					    org.opencontainers.image.documentation="https://esphome.io/" \
 | 
				
			||||||
 | 
					    org.opencontainers.image.source="https://github.com/esphome/esphome" \
 | 
				
			||||||
 | 
					    org.opencontainers.image.licenses="ESPHome" \
 | 
				
			||||||
 | 
					    org.opencontainers.image.version=${BUILD_VERSION}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ======================= docker-type image =======================
 | 
					# ======================= docker-type image =======================
 | 
				
			||||||
FROM base AS docker
 | 
					FROM base AS base-docker
 | 
				
			||||||
 | 
					 | 
				
			||||||
# Copy esphome and install
 | 
					 | 
				
			||||||
COPY . /esphome
 | 
					 | 
				
			||||||
RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
 | 
					 | 
				
			||||||
        export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
 | 
					 | 
				
			||||||
  fi; \
 | 
					 | 
				
			||||||
  pip3 install \
 | 
					 | 
				
			||||||
  --break-system-packages --no-cache-dir -e /esphome
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Settings for dashboard
 | 
					 | 
				
			||||||
ENV USERNAME="" PASSWORD=""
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Expose the dashboard to Docker
 | 
					# Expose the dashboard to Docker
 | 
				
			||||||
EXPOSE 6052
 | 
					EXPOSE 6052
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Run healthcheck (heartbeat)
 | 
					# Run healthcheck (heartbeat)
 | 
				
			||||||
HEALTHCHECK --interval=30s --timeout=30s \
 | 
					HEALTHCHECK --interval=30s --timeout=30s \
 | 
				
			||||||
  CMD curl --fail http://localhost:6052/version -A "HealthCheck" || exit 1
 | 
					    CMD curl --fail http://localhost:6052/version -A "HealthCheck" || exit 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
COPY docker/docker_entrypoint.sh /entrypoint.sh
 | 
					COPY docker/docker_entrypoint.sh /entrypoint.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -147,73 +64,23 @@ ENTRYPOINT ["/entrypoint.sh"]
 | 
				
			|||||||
CMD ["dashboard", "/config"]
 | 
					CMD ["dashboard", "/config"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ======================= ha-addon-type image =======================
 | 
				
			||||||
 | 
					FROM base AS base-ha-addon
 | 
				
			||||||
# ======================= hassio-type image =======================
 | 
					 | 
				
			||||||
FROM base AS hassio
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RUN \
 | 
					 | 
				
			||||||
    apt-get update \
 | 
					 | 
				
			||||||
    # Use pinned versions so that we get updates with build caching
 | 
					 | 
				
			||||||
    && apt-get install -y --no-install-recommends \
 | 
					 | 
				
			||||||
        nginx-light=1.22.1-9 \
 | 
					 | 
				
			||||||
    && rm -rf \
 | 
					 | 
				
			||||||
        /tmp/* \
 | 
					 | 
				
			||||||
        /var/{cache,log}/* \
 | 
					 | 
				
			||||||
        /var/lib/apt/lists/*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ARG BUILD_VERSION=dev
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Copy root filesystem
 | 
					# Copy root filesystem
 | 
				
			||||||
COPY docker/ha-addon-rootfs/ /
 | 
					COPY docker/ha-addon-rootfs/ /
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Copy esphome and install
 | 
					ARG BUILD_VERSION
 | 
				
			||||||
COPY . /esphome
 | 
					 | 
				
			||||||
RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
 | 
					 | 
				
			||||||
        export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
 | 
					 | 
				
			||||||
  fi; \
 | 
					 | 
				
			||||||
  pip3 install \
 | 
					 | 
				
			||||||
  --break-system-packages --no-cache-dir -e /esphome
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Labels
 | 
					 | 
				
			||||||
LABEL \
 | 
					LABEL \
 | 
				
			||||||
    io.hass.name="ESPHome" \
 | 
					    io.hass.name="ESPHome" \
 | 
				
			||||||
    io.hass.description="Manage and program ESP8266/ESP32 microcontrollers through YAML configuration files" \
 | 
					    io.hass.description="ESPHome is a system to configure your microcontrollers by simple yet powerful configuration files and control them remotely through Home Automation systems" \
 | 
				
			||||||
    io.hass.type="addon" \
 | 
					    io.hass.type="addon" \
 | 
				
			||||||
    io.hass.version="${BUILD_VERSION}"
 | 
					    io.hass.version="${BUILD_VERSION}"
 | 
				
			||||||
    # io.hass.arch is inherited from addon-debian-base
 | 
					    # io.hass.arch is inherited from addon-debian-base
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ARG BUILD_TYPE
 | 
				
			||||||
 | 
					FROM base-${BUILD_TYPE} AS final
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Copy esphome and install
 | 
				
			||||||
 | 
					COPY . /esphome
 | 
				
			||||||
# ======================= lint-type image =======================
 | 
					RUN uv pip install --no-cache-dir -e /esphome
 | 
				
			||||||
FROM base AS lint
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ENV \
 | 
					 | 
				
			||||||
  PLATFORMIO_CORE_DIR=/esphome/.temp/platformio
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RUN \
 | 
					 | 
				
			||||||
    apt-get update \
 | 
					 | 
				
			||||||
    # Use pinned versions so that we get updates with build caching
 | 
					 | 
				
			||||||
    && apt-get install -y --no-install-recommends \
 | 
					 | 
				
			||||||
        clang-format-13=1:13.0.1-11+b2 \
 | 
					 | 
				
			||||||
        clang-tidy-14=1:14.0.6-12 \
 | 
					 | 
				
			||||||
        patch=2.7.6-7 \
 | 
					 | 
				
			||||||
        software-properties-common=0.99.30-4.1~deb12u1 \
 | 
					 | 
				
			||||||
        nano=7.2-1+deb12u1 \
 | 
					 | 
				
			||||||
        build-essential=12.9 \
 | 
					 | 
				
			||||||
        python3-dev=3.11.2-1+b1 \
 | 
					 | 
				
			||||||
    && rm -rf \
 | 
					 | 
				
			||||||
        /tmp/* \
 | 
					 | 
				
			||||||
        /var/{cache,log}/* \
 | 
					 | 
				
			||||||
        /var/lib/apt/lists/*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
COPY requirements_test.txt /
 | 
					 | 
				
			||||||
RUN if [ "$TARGETARCH$TARGETVARIANT" = "armv7" ]; then \
 | 
					 | 
				
			||||||
        export PIP_EXTRA_INDEX_URL="https://www.piwheels.org/simple"; \
 | 
					 | 
				
			||||||
  fi; \
 | 
					 | 
				
			||||||
  pip3 install \
 | 
					 | 
				
			||||||
  --break-system-packages --no-cache-dir -r /requirements_test.txt
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VOLUME ["/esphome"]
 | 
					 | 
				
			||||||
WORKDIR /esphome
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,22 +1,19 @@
 | 
				
			|||||||
#!/usr/bin/env python3
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
from dataclasses import dataclass
 | 
					 | 
				
			||||||
import subprocess
 | 
					 | 
				
			||||||
import argparse
 | 
					import argparse
 | 
				
			||||||
from platform import machine
 | 
					from dataclasses import dataclass
 | 
				
			||||||
import shlex
 | 
					 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
 | 
					import shlex
 | 
				
			||||||
 | 
					import subprocess
 | 
				
			||||||
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_AARCH64 = "aarch64"
 | 
					ARCH_AARCH64 = "aarch64"
 | 
				
			||||||
ARCHS = [ARCH_AMD64, ARCH_ARMV7, ARCH_AARCH64]
 | 
					ARCHS = [ARCH_AMD64, ARCH_AARCH64]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TYPE_DOCKER = "docker"
 | 
					TYPE_DOCKER = "docker"
 | 
				
			||||||
TYPE_HA_ADDON = "ha-addon"
 | 
					TYPE_HA_ADDON = "ha-addon"
 | 
				
			||||||
@@ -57,7 +54,7 @@ manifest_parser = subparsers.add_parser(
 | 
				
			|||||||
class DockerParams:
 | 
					class DockerParams:
 | 
				
			||||||
    build_to: str
 | 
					    build_to: str
 | 
				
			||||||
    manifest_to: str
 | 
					    manifest_to: str
 | 
				
			||||||
    baseimgtype: str
 | 
					    build_type: str
 | 
				
			||||||
    platform: str
 | 
					    platform: str
 | 
				
			||||||
    target: str
 | 
					    target: str
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -69,25 +66,19 @@ class DockerParams:
 | 
				
			|||||||
            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 = {
 | 
					 | 
				
			||||||
            TYPE_DOCKER: "docker",
 | 
					 | 
				
			||||||
            TYPE_HA_ADDON: "hassio",
 | 
					 | 
				
			||||||
            TYPE_LINT: "docker",
 | 
					 | 
				
			||||||
        }[build_type]
 | 
					 | 
				
			||||||
        platform = {
 | 
					        platform = {
 | 
				
			||||||
            ARCH_AMD64: "linux/amd64",
 | 
					            ARCH_AMD64: "linux/amd64",
 | 
				
			||||||
            ARCH_ARMV7: "linux/arm/v7",
 | 
					 | 
				
			||||||
            ARCH_AARCH64: "linux/arm64",
 | 
					            ARCH_AARCH64: "linux/arm64",
 | 
				
			||||||
        }[arch]
 | 
					        }[arch]
 | 
				
			||||||
        target = {
 | 
					        target = {
 | 
				
			||||||
            TYPE_DOCKER: "docker",
 | 
					            TYPE_DOCKER: "final",
 | 
				
			||||||
            TYPE_HA_ADDON: "hassio",
 | 
					            TYPE_HA_ADDON: "final",
 | 
				
			||||||
            TYPE_LINT: "lint",
 | 
					            TYPE_LINT: "lint",
 | 
				
			||||||
        }[build_type]
 | 
					        }[build_type]
 | 
				
			||||||
        return cls(
 | 
					        return cls(
 | 
				
			||||||
            build_to=build_to,
 | 
					            build_to=build_to,
 | 
				
			||||||
            manifest_to=prefix,
 | 
					            manifest_to=prefix,
 | 
				
			||||||
            baseimgtype=baseimgtype,
 | 
					            build_type=build_type,
 | 
				
			||||||
            platform=platform,
 | 
					            platform=platform,
 | 
				
			||||||
            target=target,
 | 
					            target=target,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
@@ -149,7 +140,7 @@ def main():
 | 
				
			|||||||
            "buildx",
 | 
					            "buildx",
 | 
				
			||||||
            "build",
 | 
					            "build",
 | 
				
			||||||
            "--build-arg",
 | 
					            "--build-arg",
 | 
				
			||||||
            f"BASEIMGTYPE={params.baseimgtype}",
 | 
					            f"BUILD_TYPE={params.build_type}",
 | 
				
			||||||
            "--build-arg",
 | 
					            "--build-arg",
 | 
				
			||||||
            f"BUILD_VERSION={args.tag}",
 | 
					            f"BUILD_VERSION={args.tag}",
 | 
				
			||||||
            "--cache-from",
 | 
					            "--cache-from",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
#!/usr/bin/env python3
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
import re
 | 
					 | 
				
			||||||
import argparse
 | 
					import argparse
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CHANNEL_DEV = "dev"
 | 
					CHANNEL_DEV = "dev"
 | 
				
			||||||
CHANNEL_BETA = "beta"
 | 
					CHANNEL_BETA = "beta"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,10 +23,6 @@ if bashio::config.true 'streamer_mode'; then
 | 
				
			|||||||
    export ESPHOME_STREAMER_MODE=true
 | 
					    export ESPHOME_STREAMER_MODE=true
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if bashio::config.true 'status_use_ping'; then
 | 
					 | 
				
			||||||
    export ESPHOME_DASHBOARD_USE_PING=true
 | 
					 | 
				
			||||||
fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if bashio::config.has_value 'relative_url'; then
 | 
					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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
import argparse
 | 
					import argparse
 | 
				
			||||||
from datetime import datetime
 | 
					from datetime import datetime
 | 
				
			||||||
import functools
 | 
					import functools
 | 
				
			||||||
 | 
					import importlib
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
@@ -20,6 +21,8 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_DEASSERT_RTS_DTR,
 | 
					    CONF_DEASSERT_RTS_DTR,
 | 
				
			||||||
    CONF_DISABLED,
 | 
					    CONF_DISABLED,
 | 
				
			||||||
    CONF_ESPHOME,
 | 
					    CONF_ESPHOME,
 | 
				
			||||||
 | 
					    CONF_LEVEL,
 | 
				
			||||||
 | 
					    CONF_LOG_TOPIC,
 | 
				
			||||||
    CONF_LOGGER,
 | 
					    CONF_LOGGER,
 | 
				
			||||||
    CONF_MDNS,
 | 
					    CONF_MDNS,
 | 
				
			||||||
    CONF_MQTT,
 | 
					    CONF_MQTT,
 | 
				
			||||||
@@ -30,6 +33,7 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_PLATFORMIO_OPTIONS,
 | 
					    CONF_PLATFORMIO_OPTIONS,
 | 
				
			||||||
    CONF_PORT,
 | 
					    CONF_PORT,
 | 
				
			||||||
    CONF_SUBSTITUTIONS,
 | 
					    CONF_SUBSTITUTIONS,
 | 
				
			||||||
 | 
					    CONF_TOPIC,
 | 
				
			||||||
    PLATFORM_BK72XX,
 | 
					    PLATFORM_BK72XX,
 | 
				
			||||||
    PLATFORM_ESP32,
 | 
					    PLATFORM_ESP32,
 | 
				
			||||||
    PLATFORM_ESP8266,
 | 
					    PLATFORM_ESP8266,
 | 
				
			||||||
@@ -38,8 +42,8 @@ from esphome.const import (
 | 
				
			|||||||
    SECRETS_FILES,
 | 
					    SECRETS_FILES,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from esphome.core import CORE, EsphomeError, coroutine
 | 
					from esphome.core import CORE, EsphomeError, coroutine
 | 
				
			||||||
from esphome.helpers import indent, is_ip_address, get_bool_env
 | 
					from esphome.helpers import get_bool_env, indent, is_ip_address
 | 
				
			||||||
from esphome.log import Fore, color, setup_log
 | 
					from esphome.log import AnsiFore, color, setup_log
 | 
				
			||||||
from esphome.util import (
 | 
					from esphome.util import (
 | 
				
			||||||
    get_serial_ports,
 | 
					    get_serial_ports,
 | 
				
			||||||
    list_yaml_files,
 | 
					    list_yaml_files,
 | 
				
			||||||
@@ -63,7 +67,7 @@ def choose_prompt(options, purpose: str = None):
 | 
				
			|||||||
        return options[0][1]
 | 
					        return options[0][1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    safe_print(
 | 
					    safe_print(
 | 
				
			||||||
        f'Found multiple options{f" for {purpose}" if purpose else ""}, please choose one:'
 | 
					        f"Found multiple options{f' for {purpose}' if purpose else ''}, please choose one:"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    for i, (desc, _) in enumerate(options):
 | 
					    for i, (desc, _) in enumerate(options):
 | 
				
			||||||
        safe_print(f"  [{i + 1}] {desc}")
 | 
					        safe_print(f"  [{i + 1}] {desc}")
 | 
				
			||||||
@@ -79,7 +83,7 @@ def choose_prompt(options, purpose: str = None):
 | 
				
			|||||||
                raise ValueError
 | 
					                raise ValueError
 | 
				
			||||||
            break
 | 
					            break
 | 
				
			||||||
        except ValueError:
 | 
					        except ValueError:
 | 
				
			||||||
            safe_print(color(Fore.RED, f"Invalid option: '{opt}'"))
 | 
					            safe_print(color(AnsiFore.RED, f"Invalid option: '{opt}'"))
 | 
				
			||||||
    return options[opt - 1][1]
 | 
					    return options[opt - 1][1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -95,8 +99,12 @@ def choose_upload_log_host(
 | 
				
			|||||||
        options.append((f"Over The Air ({CORE.address})", CORE.address))
 | 
					        options.append((f"Over The Air ({CORE.address})", CORE.address))
 | 
				
			||||||
        if default == "OTA":
 | 
					        if default == "OTA":
 | 
				
			||||||
            return CORE.address
 | 
					            return CORE.address
 | 
				
			||||||
    if show_mqtt and CONF_MQTT in CORE.config:
 | 
					    if (
 | 
				
			||||||
        options.append((f"MQTT ({CORE.config['mqtt'][CONF_BROKER]})", "MQTT"))
 | 
					        show_mqtt
 | 
				
			||||||
 | 
					        and (mqtt_config := CORE.config.get(CONF_MQTT))
 | 
				
			||||||
 | 
					        and mqtt_logging_enabled(mqtt_config)
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
 | 
					        options.append((f"MQTT ({mqtt_config[CONF_BROKER]})", "MQTT"))
 | 
				
			||||||
        if default == "OTA":
 | 
					        if default == "OTA":
 | 
				
			||||||
            return "MQTT"
 | 
					            return "MQTT"
 | 
				
			||||||
    if default is not None:
 | 
					    if default is not None:
 | 
				
			||||||
@@ -106,6 +114,17 @@ def choose_upload_log_host(
 | 
				
			|||||||
    return choose_prompt(options, purpose=purpose)
 | 
					    return choose_prompt(options, purpose=purpose)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def mqtt_logging_enabled(mqtt_config):
 | 
				
			||||||
 | 
					    log_topic = mqtt_config[CONF_LOG_TOPIC]
 | 
				
			||||||
 | 
					    if log_topic is None:
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					    if CONF_TOPIC not in log_topic:
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					    if log_topic.get(CONF_LEVEL, None) == "NONE":
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					    return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_port_type(port):
 | 
					def get_port_type(port):
 | 
				
			||||||
    if port.startswith("/") or port.startswith("COM"):
 | 
					    if port.startswith("/") or port.startswith("COM"):
 | 
				
			||||||
        return "SERIAL"
 | 
					        return "SERIAL"
 | 
				
			||||||
@@ -114,7 +133,8 @@ def get_port_type(port):
 | 
				
			|||||||
    return "NETWORK"
 | 
					    return "NETWORK"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def run_miniterm(config, port):
 | 
					def run_miniterm(config, port, args):
 | 
				
			||||||
 | 
					    from aioesphomeapi import LogParser
 | 
				
			||||||
    import serial
 | 
					    import serial
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from esphome import platformio_api
 | 
					    from esphome import platformio_api
 | 
				
			||||||
@@ -135,10 +155,11 @@ def run_miniterm(config, port):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    # We can't set to False by default since it leads to toggling and hence
 | 
					    # We can't set to False by default since it leads to toggling and hence
 | 
				
			||||||
    # ESP32 resets on some platforms.
 | 
					    # ESP32 resets on some platforms.
 | 
				
			||||||
    if config["logger"][CONF_DEASSERT_RTS_DTR]:
 | 
					    if config["logger"][CONF_DEASSERT_RTS_DTR] or args.reset:
 | 
				
			||||||
        ser.dtr = False
 | 
					        ser.dtr = False
 | 
				
			||||||
        ser.rts = False
 | 
					        ser.rts = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    parser = LogParser()
 | 
				
			||||||
    tries = 0
 | 
					    tries = 0
 | 
				
			||||||
    while tries < 5:
 | 
					    while tries < 5:
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
@@ -155,8 +176,7 @@ def run_miniterm(config, port):
 | 
				
			|||||||
                        .decode("utf8", "backslashreplace")
 | 
					                        .decode("utf8", "backslashreplace")
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
                    time_str = datetime.now().time().strftime("[%H:%M:%S]")
 | 
					                    time_str = datetime.now().time().strftime("[%H:%M:%S]")
 | 
				
			||||||
                    message = time_str + line
 | 
					                    safe_print(parser.parse_line(line, time_str))
 | 
				
			||||||
                    safe_print(message)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    backtrace_state = platformio_api.process_stacktrace(
 | 
					                    backtrace_state = platformio_api.process_stacktrace(
 | 
				
			||||||
                        config, line, backtrace_state=backtrace_state
 | 
					                        config, line, backtrace_state=backtrace_state
 | 
				
			||||||
@@ -225,11 +245,11 @@ def compile_program(args, config):
 | 
				
			|||||||
    return 0 if idedata is not None else 1
 | 
					    return 0 if idedata is not None else 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def upload_using_esptool(config, port, file):
 | 
					def upload_using_esptool(config, port, file, speed):
 | 
				
			||||||
    from esphome import platformio_api
 | 
					    from esphome import platformio_api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    first_baudrate = config[CONF_ESPHOME][CONF_PLATFORMIO_OPTIONS].get(
 | 
					    first_baudrate = speed or config[CONF_ESPHOME][CONF_PLATFORMIO_OPTIONS].get(
 | 
				
			||||||
        "upload_speed", 460800
 | 
					        "upload_speed", os.getenv("ESPHOME_UPLOAD_SPEED", "460800")
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if file is not None:
 | 
					    if file is not None:
 | 
				
			||||||
@@ -318,11 +338,18 @@ def check_permissions(port):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def upload_program(config, args, host):
 | 
					def upload_program(config, args, host):
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        module = importlib.import_module("esphome.components." + CORE.target_platform)
 | 
				
			||||||
 | 
					        if getattr(module, "upload_program")(config, args, host):
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					    except AttributeError:
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if get_port_type(host) == "SERIAL":
 | 
					    if get_port_type(host) == "SERIAL":
 | 
				
			||||||
        check_permissions(host)
 | 
					        check_permissions(host)
 | 
				
			||||||
        if CORE.target_platform in (PLATFORM_ESP32, PLATFORM_ESP8266):
 | 
					        if CORE.target_platform in (PLATFORM_ESP32, PLATFORM_ESP8266):
 | 
				
			||||||
            file = getattr(args, "file", None)
 | 
					            file = getattr(args, "file", None)
 | 
				
			||||||
            return upload_using_esptool(config, host, file)
 | 
					            return upload_using_esptool(config, host, file, args.upload_speed)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if CORE.target_platform in (PLATFORM_RP2040):
 | 
					        if CORE.target_platform in (PLATFORM_RP2040):
 | 
				
			||||||
            return upload_using_platformio(config, args.device)
 | 
					            return upload_using_platformio(config, args.device)
 | 
				
			||||||
@@ -345,14 +372,16 @@ def upload_program(config, args, host):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    from esphome import espota2
 | 
					    from esphome import espota2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    remote_port = ota_conf[CONF_PORT]
 | 
					    remote_port = int(ota_conf[CONF_PORT])
 | 
				
			||||||
    password = ota_conf.get(CONF_PASSWORD, "")
 | 
					    password = ota_conf.get(CONF_PASSWORD, "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (
 | 
					    if (
 | 
				
			||||||
        not is_ip_address(CORE.address)  # pylint: disable=too-many-boolean-expressions
 | 
					        CONF_MQTT in config  # pylint: disable=too-many-boolean-expressions
 | 
				
			||||||
        and (get_port_type(host) == "MQTT" or config[CONF_MDNS][CONF_DISABLED])
 | 
					 | 
				
			||||||
        and CONF_MQTT in config
 | 
					 | 
				
			||||||
        and (not args.device or args.device in ("MQTT", "OTA"))
 | 
					        and (not args.device or args.device in ("MQTT", "OTA"))
 | 
				
			||||||
 | 
					        and (
 | 
				
			||||||
 | 
					            ((config[CONF_MDNS][CONF_DISABLED]) and not is_ip_address(CORE.address))
 | 
				
			||||||
 | 
					            or get_port_type(host) == "MQTT"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
        from esphome import mqtt
 | 
					        from esphome import mqtt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -371,14 +400,14 @@ def show_logs(config, args, port):
 | 
				
			|||||||
        raise EsphomeError("Logger is not configured!")
 | 
					        raise EsphomeError("Logger is not configured!")
 | 
				
			||||||
    if get_port_type(port) == "SERIAL":
 | 
					    if get_port_type(port) == "SERIAL":
 | 
				
			||||||
        check_permissions(port)
 | 
					        check_permissions(port)
 | 
				
			||||||
        return run_miniterm(config, port)
 | 
					        return run_miniterm(config, port, args)
 | 
				
			||||||
    if get_port_type(port) == "NETWORK" and "api" in config:
 | 
					    if get_port_type(port) == "NETWORK" and "api" in config:
 | 
				
			||||||
        if config[CONF_MDNS][CONF_DISABLED] and CONF_MQTT in config:
 | 
					        if config[CONF_MDNS][CONF_DISABLED] and CONF_MQTT in config:
 | 
				
			||||||
            from esphome import mqtt
 | 
					            from esphome import mqtt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            port = mqtt.get_esphome_device_ip(
 | 
					            port = mqtt.get_esphome_device_ip(
 | 
				
			||||||
                config, args.username, args.password, args.client_id
 | 
					                config, args.username, args.password, args.client_id
 | 
				
			||||||
            )
 | 
					            )[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        from esphome.components.api.client import run_logs
 | 
					        from esphome.components.api.client import run_logs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -565,33 +594,38 @@ def command_update_all(args):
 | 
				
			|||||||
        middle_text = f" {middle_text} "
 | 
					        middle_text = f" {middle_text} "
 | 
				
			||||||
        width = len(click.unstyle(middle_text))
 | 
					        width = len(click.unstyle(middle_text))
 | 
				
			||||||
        half_line = "=" * ((twidth - width) // 2)
 | 
					        half_line = "=" * ((twidth - width) // 2)
 | 
				
			||||||
        click.echo(f"{half_line}{middle_text}{half_line}")
 | 
					        safe_print(f"{half_line}{middle_text}{half_line}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for f in files:
 | 
					    for f in files:
 | 
				
			||||||
        print(f"Updating {color(Fore.CYAN, f)}")
 | 
					        safe_print(f"Updating {color(AnsiFore.CYAN, f)}")
 | 
				
			||||||
        print("-" * twidth)
 | 
					        safe_print("-" * twidth)
 | 
				
			||||||
        print()
 | 
					        safe_print()
 | 
				
			||||||
        rc = run_external_process(
 | 
					        if CORE.dashboard:
 | 
				
			||||||
            "esphome", "--dashboard", "run", f, "--no-logs", "--device", "OTA"
 | 
					            rc = run_external_process(
 | 
				
			||||||
        )
 | 
					                "esphome", "--dashboard", "run", f, "--no-logs", "--device", "OTA"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            rc = run_external_process(
 | 
				
			||||||
 | 
					                "esphome", "run", f, "--no-logs", "--device", "OTA"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
        if rc == 0:
 | 
					        if rc == 0:
 | 
				
			||||||
            print_bar(f"[{color(Fore.BOLD_GREEN, 'SUCCESS')}] {f}")
 | 
					            print_bar(f"[{color(AnsiFore.BOLD_GREEN, 'SUCCESS')}] {f}")
 | 
				
			||||||
            success[f] = True
 | 
					            success[f] = True
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            print_bar(f"[{color(Fore.BOLD_RED, 'ERROR')}] {f}")
 | 
					            print_bar(f"[{color(AnsiFore.BOLD_RED, 'ERROR')}] {f}")
 | 
				
			||||||
            success[f] = False
 | 
					            success[f] = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        print()
 | 
					        safe_print()
 | 
				
			||||||
        print()
 | 
					        safe_print()
 | 
				
			||||||
        print()
 | 
					        safe_print()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    print_bar(f"[{color(Fore.BOLD_WHITE, 'SUMMARY')}]")
 | 
					    print_bar(f"[{color(AnsiFore.BOLD_WHITE, 'SUMMARY')}]")
 | 
				
			||||||
    failed = 0
 | 
					    failed = 0
 | 
				
			||||||
    for f in files:
 | 
					    for f in files:
 | 
				
			||||||
        if success[f]:
 | 
					        if success[f]:
 | 
				
			||||||
            print(f"  - {f}: {color(Fore.GREEN, 'SUCCESS')}")
 | 
					            safe_print(f"  - {f}: {color(AnsiFore.GREEN, 'SUCCESS')}")
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            print(f"  - {f}: {color(Fore.BOLD_RED, 'FAILED')}")
 | 
					            safe_print(f"  - {f}: {color(AnsiFore.BOLD_RED, 'FAILED')}")
 | 
				
			||||||
            failed += 1
 | 
					            failed += 1
 | 
				
			||||||
    return failed
 | 
					    return failed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -617,7 +651,7 @@ def command_rename(args, config):
 | 
				
			|||||||
        if c not in ALLOWED_NAME_CHARS:
 | 
					        if c not in ALLOWED_NAME_CHARS:
 | 
				
			||||||
            print(
 | 
					            print(
 | 
				
			||||||
                color(
 | 
					                color(
 | 
				
			||||||
                    Fore.BOLD_RED,
 | 
					                    AnsiFore.BOLD_RED,
 | 
				
			||||||
                    f"'{c}' is an invalid character for names. Valid characters are: "
 | 
					                    f"'{c}' is an invalid character for names. Valid characters are: "
 | 
				
			||||||
                    f"{ALLOWED_NAME_CHARS} (lowercase, no spaces)",
 | 
					                    f"{ALLOWED_NAME_CHARS} (lowercase, no spaces)",
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
@@ -630,7 +664,9 @@ def command_rename(args, config):
 | 
				
			|||||||
    yaml = yaml_util.load_yaml(CORE.config_path)
 | 
					    yaml = yaml_util.load_yaml(CORE.config_path)
 | 
				
			||||||
    if CONF_ESPHOME not in yaml or CONF_NAME not in yaml[CONF_ESPHOME]:
 | 
					    if CONF_ESPHOME not in yaml or CONF_NAME not in yaml[CONF_ESPHOME]:
 | 
				
			||||||
        print(
 | 
					        print(
 | 
				
			||||||
            color(Fore.BOLD_RED, "Complex YAML files cannot be automatically renamed.")
 | 
					            color(
 | 
				
			||||||
 | 
					                AnsiFore.BOLD_RED, "Complex YAML files cannot be automatically renamed."
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        return 1
 | 
					        return 1
 | 
				
			||||||
    old_name = yaml[CONF_ESPHOME][CONF_NAME]
 | 
					    old_name = yaml[CONF_ESPHOME][CONF_NAME]
 | 
				
			||||||
@@ -653,7 +689,7 @@ def command_rename(args, config):
 | 
				
			|||||||
            )
 | 
					            )
 | 
				
			||||||
            > 1
 | 
					            > 1
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            print(color(Fore.BOLD_RED, "Too many matches in YAML to safely rename"))
 | 
					            print(color(AnsiFore.BOLD_RED, "Too many matches in YAML to safely rename"))
 | 
				
			||||||
            return 1
 | 
					            return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        new_raw = re.sub(
 | 
					        new_raw = re.sub(
 | 
				
			||||||
@@ -665,7 +701,7 @@ def command_rename(args, config):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    new_path = os.path.join(CORE.config_dir, args.name + ".yaml")
 | 
					    new_path = os.path.join(CORE.config_dir, args.name + ".yaml")
 | 
				
			||||||
    print(
 | 
					    print(
 | 
				
			||||||
        f"Updating {color(Fore.CYAN, CORE.config_path)} to {color(Fore.CYAN, new_path)}"
 | 
					        f"Updating {color(AnsiFore.CYAN, CORE.config_path)} to {color(AnsiFore.CYAN, new_path)}"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    print()
 | 
					    print()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -674,7 +710,7 @@ def command_rename(args, config):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    rc = run_external_process("esphome", "config", new_path)
 | 
					    rc = run_external_process("esphome", "config", new_path)
 | 
				
			||||||
    if rc != 0:
 | 
					    if rc != 0:
 | 
				
			||||||
        print(color(Fore.BOLD_RED, "Rename failed. Reverting changes."))
 | 
					        print(color(AnsiFore.BOLD_RED, "Rename failed. Reverting changes."))
 | 
				
			||||||
        os.remove(new_path)
 | 
					        os.remove(new_path)
 | 
				
			||||||
        return 1
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -700,7 +736,7 @@ def command_rename(args, config):
 | 
				
			|||||||
    if CORE.config_path != new_path:
 | 
					    if CORE.config_path != new_path:
 | 
				
			||||||
        os.remove(CORE.config_path)
 | 
					        os.remove(CORE.config_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    print(color(Fore.BOLD_GREEN, "SUCCESS"))
 | 
					    print(color(AnsiFore.BOLD_GREEN, "SUCCESS"))
 | 
				
			||||||
    print()
 | 
					    print()
 | 
				
			||||||
    return 0
 | 
					    return 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -740,6 +776,14 @@ def parse_args(argv):
 | 
				
			|||||||
    options_parser.add_argument(
 | 
					    options_parser.add_argument(
 | 
				
			||||||
        "-q", "--quiet", help="Disable all ESPHome logs.", action="store_true"
 | 
					        "-q", "--quiet", help="Disable all ESPHome logs.", action="store_true"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					    options_parser.add_argument(
 | 
				
			||||||
 | 
					        "-l",
 | 
				
			||||||
 | 
					        "--log-level",
 | 
				
			||||||
 | 
					        help="Set the log level.",
 | 
				
			||||||
 | 
					        default=os.getenv("ESPHOME_LOG_LEVEL", "INFO"),
 | 
				
			||||||
 | 
					        action="store",
 | 
				
			||||||
 | 
					        choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    options_parser.add_argument(
 | 
					    options_parser.add_argument(
 | 
				
			||||||
        "--dashboard", help=argparse.SUPPRESS, action="store_true"
 | 
					        "--dashboard", help=argparse.SUPPRESS, action="store_true"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@@ -808,6 +852,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(
 | 
				
			||||||
 | 
					        "--upload_speed",
 | 
				
			||||||
 | 
					        help="Override the default or configured upload speed.",
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    parser_upload.add_argument(
 | 
					    parser_upload.add_argument(
 | 
				
			||||||
        "--file",
 | 
					        "--file",
 | 
				
			||||||
        help="Manually specify the binary file to upload.",
 | 
					        help="Manually specify the binary file to upload.",
 | 
				
			||||||
@@ -826,6 +874,13 @@ 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_logs.add_argument(
 | 
				
			||||||
 | 
					        "--reset",
 | 
				
			||||||
 | 
					        "-r",
 | 
				
			||||||
 | 
					        action="store_true",
 | 
				
			||||||
 | 
					        help="Reset the device before starting serial logs.",
 | 
				
			||||||
 | 
					        default=os.getenv("ESPHOME_SERIAL_LOGGING_RESET"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    parser_discover = subparsers.add_parser(
 | 
					    parser_discover = subparsers.add_parser(
 | 
				
			||||||
        "discover",
 | 
					        "discover",
 | 
				
			||||||
@@ -848,9 +903,20 @@ 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_run.add_argument(
 | 
				
			||||||
 | 
					        "--upload_speed",
 | 
				
			||||||
 | 
					        help="Override the default or configured upload speed.",
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    parser_run.add_argument(
 | 
					    parser_run.add_argument(
 | 
				
			||||||
        "--no-logs", help="Disable starting logs.", action="store_true"
 | 
					        "--no-logs", help="Disable starting logs.", action="store_true"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					    parser_run.add_argument(
 | 
				
			||||||
 | 
					        "--reset",
 | 
				
			||||||
 | 
					        "-r",
 | 
				
			||||||
 | 
					        action="store_true",
 | 
				
			||||||
 | 
					        help="Reset the device before starting serial logs.",
 | 
				
			||||||
 | 
					        default=os.getenv("ESPHOME_SERIAL_LOGGING_RESET"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    parser_clean = subparsers.add_parser(
 | 
					    parser_clean = subparsers.add_parser(
 | 
				
			||||||
        "clean-mqtt",
 | 
					        "clean-mqtt",
 | 
				
			||||||
@@ -969,11 +1035,16 @@ def run_esphome(argv):
 | 
				
			|||||||
    args = parse_args(argv)
 | 
					    args = parse_args(argv)
 | 
				
			||||||
    CORE.dashboard = args.dashboard
 | 
					    CORE.dashboard = args.dashboard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Override log level if verbose is set
 | 
				
			||||||
 | 
					    if args.verbose:
 | 
				
			||||||
 | 
					        args.log_level = "DEBUG"
 | 
				
			||||||
 | 
					    elif args.quiet:
 | 
				
			||||||
 | 
					        args.log_level = "CRITICAL"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setup_log(
 | 
					    setup_log(
 | 
				
			||||||
        args.verbose,
 | 
					        log_level=args.log_level,
 | 
				
			||||||
        args.quiet,
 | 
					 | 
				
			||||||
        # Show timestamp for dashboard access logs
 | 
					        # Show timestamp for dashboard access logs
 | 
				
			||||||
        args.command == "dashboard",
 | 
					        include_timestamp=args.command == "dashboard",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if args.command in PRE_CONFIG_ACTIONS:
 | 
					    if args.command in PRE_CONFIG_ACTIONS:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,8 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
 | 
					    CONF_ALL,
 | 
				
			||||||
 | 
					    CONF_ANY,
 | 
				
			||||||
    CONF_AUTOMATION_ID,
 | 
					    CONF_AUTOMATION_ID,
 | 
				
			||||||
    CONF_CONDITION,
 | 
					    CONF_CONDITION,
 | 
				
			||||||
    CONF_COUNT,
 | 
					    CONF_COUNT,
 | 
				
			||||||
@@ -73,6 +75,13 @@ def validate_potentially_and_condition(value):
 | 
				
			|||||||
    return validate_condition(value)
 | 
					    return validate_condition(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def validate_potentially_or_condition(value):
 | 
				
			||||||
 | 
					    if isinstance(value, list):
 | 
				
			||||||
 | 
					        with cv.remove_prepend_path(["or"]):
 | 
				
			||||||
 | 
					            return validate_condition({"or": value})
 | 
				
			||||||
 | 
					    return validate_condition(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DelayAction = cg.esphome_ns.class_("DelayAction", Action, cg.Component)
 | 
					DelayAction = cg.esphome_ns.class_("DelayAction", Action, cg.Component)
 | 
				
			||||||
LambdaAction = cg.esphome_ns.class_("LambdaAction", Action)
 | 
					LambdaAction = cg.esphome_ns.class_("LambdaAction", Action)
 | 
				
			||||||
IfAction = cg.esphome_ns.class_("IfAction", Action)
 | 
					IfAction = cg.esphome_ns.class_("IfAction", Action)
 | 
				
			||||||
@@ -166,6 +175,18 @@ async def or_condition_to_code(config, condition_id, template_arg, args):
 | 
				
			|||||||
    return cg.new_Pvariable(condition_id, template_arg, conditions)
 | 
					    return cg.new_Pvariable(condition_id, template_arg, conditions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@register_condition("all", AndCondition, validate_condition_list)
 | 
				
			||||||
 | 
					async def all_condition_to_code(config, condition_id, template_arg, args):
 | 
				
			||||||
 | 
					    conditions = await build_condition_list(config, template_arg, args)
 | 
				
			||||||
 | 
					    return cg.new_Pvariable(condition_id, template_arg, conditions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@register_condition("any", OrCondition, validate_condition_list)
 | 
				
			||||||
 | 
					async def any_condition_to_code(config, condition_id, template_arg, args):
 | 
				
			||||||
 | 
					    conditions = await build_condition_list(config, template_arg, args)
 | 
				
			||||||
 | 
					    return cg.new_Pvariable(condition_id, template_arg, conditions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@register_condition("not", NotCondition, validate_potentially_and_condition)
 | 
					@register_condition("not", NotCondition, validate_potentially_and_condition)
 | 
				
			||||||
async def not_condition_to_code(config, condition_id, template_arg, args):
 | 
					async def not_condition_to_code(config, condition_id, template_arg, args):
 | 
				
			||||||
    condition = await build_condition(config, template_arg, args)
 | 
					    condition = await build_condition(config, template_arg, args)
 | 
				
			||||||
@@ -223,15 +244,21 @@ async def delay_action_to_code(config, action_id, template_arg, args):
 | 
				
			|||||||
    IfAction,
 | 
					    IfAction,
 | 
				
			||||||
    cv.All(
 | 
					    cv.All(
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            cv.Required(CONF_CONDITION): validate_potentially_and_condition,
 | 
					            cv.Exclusive(
 | 
				
			||||||
 | 
					                CONF_CONDITION, CONF_CONDITION
 | 
				
			||||||
 | 
					            ): validate_potentially_and_condition,
 | 
				
			||||||
 | 
					            cv.Exclusive(CONF_ANY, CONF_CONDITION): validate_potentially_or_condition,
 | 
				
			||||||
 | 
					            cv.Exclusive(CONF_ALL, CONF_CONDITION): validate_potentially_and_condition,
 | 
				
			||||||
            cv.Optional(CONF_THEN): validate_action_list,
 | 
					            cv.Optional(CONF_THEN): validate_action_list,
 | 
				
			||||||
            cv.Optional(CONF_ELSE): validate_action_list,
 | 
					            cv.Optional(CONF_ELSE): validate_action_list,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        cv.has_at_least_one_key(CONF_THEN, CONF_ELSE),
 | 
					        cv.has_at_least_one_key(CONF_THEN, CONF_ELSE),
 | 
				
			||||||
 | 
					        cv.has_at_least_one_key(CONF_CONDITION, CONF_ANY, CONF_ALL),
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
async def if_action_to_code(config, action_id, template_arg, args):
 | 
					async def if_action_to_code(config, action_id, template_arg, args):
 | 
				
			||||||
    conditions = await build_condition(config[CONF_CONDITION], template_arg, args)
 | 
					    cond_conf = next(el for el in config if el in (CONF_ANY, CONF_ALL, CONF_CONDITION))
 | 
				
			||||||
 | 
					    conditions = await build_condition(config[cond_conf], template_arg, args)
 | 
				
			||||||
    var = cg.new_Pvariable(action_id, template_arg, conditions)
 | 
					    var = cg.new_Pvariable(action_id, template_arg, conditions)
 | 
				
			||||||
    if CONF_THEN in config:
 | 
					    if CONF_THEN in config:
 | 
				
			||||||
        actions = await build_action_list(config[CONF_THEN], template_arg, args)
 | 
					        actions = await build_action_list(config[CONF_THEN], template_arg, args)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
from esphome.components import sensor, uart
 | 
					from esphome.components import sensor, uart
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
 | 
					    DEVICE_CLASS_DISTANCE,
 | 
				
			||||||
 | 
					    ICON_ARROW_EXPAND_VERTICAL,
 | 
				
			||||||
    STATE_CLASS_MEASUREMENT,
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_METER,
 | 
					    UNIT_METER,
 | 
				
			||||||
    ICON_ARROW_EXPAND_VERTICAL,
 | 
					 | 
				
			||||||
    DEVICE_CLASS_DISTANCE,
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CODEOWNERS = ["@MrSuicideParrot"]
 | 
					CODEOWNERS = ["@MrSuicideParrot"]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
from esphome.components import sensor, uart
 | 
					from esphome.components import sensor, uart
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    STATE_CLASS_MEASUREMENT,
 | 
					 | 
				
			||||||
    ICON_ARROW_EXPAND_VERTICAL,
 | 
					 | 
				
			||||||
    DEVICE_CLASS_DISTANCE,
 | 
					    DEVICE_CLASS_DISTANCE,
 | 
				
			||||||
 | 
					    ICON_ARROW_EXPAND_VERTICAL,
 | 
				
			||||||
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_MILLIMETER,
 | 
					    UNIT_MILLIMETER,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ namespace a4988 {
 | 
				
			|||||||
static const char *const TAG = "a4988.stepper";
 | 
					static const char *const TAG = "a4988.stepper";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void A4988::setup() {
 | 
					void A4988::setup() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up A4988...");
 | 
					  ESP_LOGCONFIG(TAG, "Running setup");
 | 
				
			||||||
  if (this->sleep_pin_ != nullptr) {
 | 
					  if (this->sleep_pin_ != nullptr) {
 | 
				
			||||||
    this->sleep_pin_->setup();
 | 
					    this->sleep_pin_->setup();
 | 
				
			||||||
    this->sleep_pin_->digital_write(false);
 | 
					    this->sleep_pin_->digital_write(false);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,9 @@
 | 
				
			|||||||
from esphome import pins
 | 
					from esphome import pins
 | 
				
			||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
from esphome.components import stepper
 | 
					from esphome.components import stepper
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
import esphome.codegen as cg
 | 
					 | 
				
			||||||
from esphome.const import CONF_DIR_PIN, CONF_ID, CONF_SLEEP_PIN, CONF_STEP_PIN
 | 
					from esphome.const import CONF_DIR_PIN, CONF_ID, CONF_SLEEP_PIN, CONF_STEP_PIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
a4988_ns = cg.esphome_ns.namespace("a4988")
 | 
					a4988_ns = cg.esphome_ns.namespace("a4988")
 | 
				
			||||||
A4988 = a4988_ns.class_("A4988", stepper.Stepper, cg.Component)
 | 
					A4988 = a4988_ns.class_("A4988", stepper.Stepper, cg.Component)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ namespace absolute_humidity {
 | 
				
			|||||||
static const char *const TAG = "absolute_humidity.sensor";
 | 
					static const char *const TAG = "absolute_humidity.sensor";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void AbsoluteHumidityComponent::setup() {
 | 
					void AbsoluteHumidityComponent::setup() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up absolute humidity '%s'...", this->get_name().c_str());
 | 
					  ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ESP_LOGD(TAG, "  Added callback for temperature '%s'", this->temperature_sensor_->get_name().c_str());
 | 
					  ESP_LOGD(TAG, "  Added callback for temperature '%s'", this->temperature_sensor_->get_name().c_str());
 | 
				
			||||||
  this->temperature_sensor_->add_on_state_callback([this](float state) { this->temperature_callback_(state); });
 | 
					  this->temperature_sensor_->add_on_state_callback([this](float state) { this->temperature_callback_(state); });
 | 
				
			||||||
@@ -40,9 +40,11 @@ void AbsoluteHumidityComponent::dump_config() {
 | 
				
			|||||||
      break;
 | 
					      break;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Sources");
 | 
					  ESP_LOGCONFIG(TAG,
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  Temperature: '%s'", this->temperature_sensor_->get_name().c_str());
 | 
					                "Sources\n"
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  Relative Humidity: '%s'", this->humidity_sensor_->get_name().c_str());
 | 
					                "  Temperature: '%s'\n"
 | 
				
			||||||
 | 
					                "  Relative Humidity: '%s'",
 | 
				
			||||||
 | 
					                this->temperature_sensor_->get_name().c_str(), this->humidity_sensor_->get_name().c_str());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
float AbsoluteHumidityComponent::get_setup_priority() const { return setup_priority::DATA; }
 | 
					float AbsoluteHumidityComponent::get_setup_priority() const { return setup_priority::DATA; }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,12 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import sensor
 | 
					from esphome.components import sensor
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
 | 
					    CONF_EQUATION,
 | 
				
			||||||
    CONF_HUMIDITY,
 | 
					    CONF_HUMIDITY,
 | 
				
			||||||
    CONF_TEMPERATURE,
 | 
					    CONF_TEMPERATURE,
 | 
				
			||||||
    STATE_CLASS_MEASUREMENT,
 | 
					 | 
				
			||||||
    CONF_EQUATION,
 | 
					 | 
				
			||||||
    ICON_WATER,
 | 
					    ICON_WATER,
 | 
				
			||||||
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_GRAMS_PER_CUBIC_METER,
 | 
					    UNIT_GRAMS_PER_CUBIC_METER,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -114,13 +114,14 @@ void IRAM_ATTR HOT AcDimmerDataStore::gpio_intr() {
 | 
				
			|||||||
    // fully off, disable output immediately
 | 
					    // fully off, disable output immediately
 | 
				
			||||||
    this->gate_pin.digital_write(false);
 | 
					    this->gate_pin.digital_write(false);
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
 | 
					    auto min_us = this->cycle_time_us * this->min_power / 1000;
 | 
				
			||||||
    if (this->method == DIM_METHOD_TRAILING) {
 | 
					    if (this->method == DIM_METHOD_TRAILING) {
 | 
				
			||||||
      this->enable_time_us = 1;  // cannot be 0
 | 
					      this->enable_time_us = 1;  // cannot be 0
 | 
				
			||||||
      this->disable_time_us = std::max((uint32_t) 10, this->value * this->cycle_time_us / 65535);
 | 
					      // calculate time until disable in µs with integer arithmetic and take into account min_power
 | 
				
			||||||
 | 
					      this->disable_time_us = std::max((uint32_t) 10, this->value * (this->cycle_time_us - min_us) / 65535 + min_us);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      // calculate time until enable in µs: (1.0-value)*cycle_time, but with integer arithmetic
 | 
					      // calculate time until enable in µs: (1.0-value)*cycle_time, but with integer arithmetic
 | 
				
			||||||
      // also take into account min_power
 | 
					      // also take into account min_power
 | 
				
			||||||
      auto min_us = this->cycle_time_us * this->min_power / 1000;
 | 
					 | 
				
			||||||
      this->enable_time_us = std::max((uint32_t) 1, ((65535 - this->value) * (this->cycle_time_us - min_us)) / 65535);
 | 
					      this->enable_time_us = std::max((uint32_t) 1, ((65535 - this->value) * (this->cycle_time_us - min_us)) / 65535);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (this->method == DIM_METHOD_LEADING_PULSE) {
 | 
					      if (this->method == DIM_METHOD_LEADING_PULSE) {
 | 
				
			||||||
@@ -213,8 +214,10 @@ void AcDimmer::dump_config() {
 | 
				
			|||||||
  ESP_LOGCONFIG(TAG, "AcDimmer:");
 | 
					  ESP_LOGCONFIG(TAG, "AcDimmer:");
 | 
				
			||||||
  LOG_PIN("  Output Pin: ", this->gate_pin_);
 | 
					  LOG_PIN("  Output Pin: ", this->gate_pin_);
 | 
				
			||||||
  LOG_PIN("  Zero-Cross Pin: ", this->zero_cross_pin_);
 | 
					  LOG_PIN("  Zero-Cross Pin: ", this->zero_cross_pin_);
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "   Min Power: %.1f%%", this->store_.min_power / 10.0f);
 | 
					  ESP_LOGCONFIG(TAG,
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "   Init with half cycle: %s", YESNO(this->init_with_half_cycle_));
 | 
					                "   Min Power: %.1f%%\n"
 | 
				
			||||||
 | 
					                "   Init with half cycle: %s",
 | 
				
			||||||
 | 
					                this->store_.min_power / 10.0f, YESNO(this->init_with_half_cycle_));
 | 
				
			||||||
  if (method_ == DIM_METHOD_LEADING_PULSE) {
 | 
					  if (method_ == DIM_METHOD_LEADING_PULSE) {
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "   Method: leading pulse");
 | 
					    ESP_LOGCONFIG(TAG, "   Method: leading pulse");
 | 
				
			||||||
  } else if (method_ == DIM_METHOD_LEADING) {
 | 
					  } else if (method_ == DIM_METHOD_LEADING) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome import pins
 | 
					from esphome import pins
 | 
				
			||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
from esphome.components import output
 | 
					from esphome.components import output
 | 
				
			||||||
from esphome.const import CONF_ID, CONF_MIN_POWER, CONF_METHOD
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome.const import CONF_ID, CONF_METHOD, CONF_MIN_POWER
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CODEOWNERS = ["@glmnet"]
 | 
					CODEOWNERS = ["@glmnet"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import uart
 | 
					from esphome.components import uart
 | 
				
			||||||
from esphome.components.light.types import AddressableLightEffect
 | 
					 | 
				
			||||||
from esphome.components.light.effects import register_addressable_effect
 | 
					from esphome.components.light.effects import register_addressable_effect
 | 
				
			||||||
 | 
					from esphome.components.light.types import AddressableLightEffect
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import CONF_NAME, CONF_UART_ID
 | 
					from esphome.const import CONF_NAME, CONF_UART_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEPENDENCIES = ["uart"]
 | 
					DEPENDENCIES = ["uart"]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,6 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome import pins
 | 
					from esphome import pins
 | 
				
			||||||
from esphome.const import CONF_ANALOG, CONF_INPUT, CONF_NUMBER
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					 | 
				
			||||||
from esphome.core import CORE
 | 
					 | 
				
			||||||
from esphome.components.esp32 import get_esp32_variant
 | 
					from esphome.components.esp32 import get_esp32_variant
 | 
				
			||||||
from esphome.const import PLATFORM_ESP8266
 | 
					 | 
				
			||||||
from esphome.components.esp32.const import (
 | 
					from esphome.components.esp32.const import (
 | 
				
			||||||
    VARIANT_ESP32,
 | 
					    VARIANT_ESP32,
 | 
				
			||||||
    VARIANT_ESP32C2,
 | 
					    VARIANT_ESP32C2,
 | 
				
			||||||
@@ -15,6 +10,9 @@ from esphome.components.esp32.const import (
 | 
				
			|||||||
    VARIANT_ESP32S2,
 | 
					    VARIANT_ESP32S2,
 | 
				
			||||||
    VARIANT_ESP32S3,
 | 
					    VARIANT_ESP32S3,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome.const import CONF_ANALOG, CONF_INPUT, CONF_NUMBER, PLATFORM_ESP8266
 | 
				
			||||||
 | 
					from esphome.core import CORE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CODEOWNERS = ["@esphome/core"]
 | 
					CODEOWNERS = ["@esphome/core"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -38,12 +36,21 @@ ATTENUATION_MODES = {
 | 
				
			|||||||
    "auto": "auto",
 | 
					    "auto": "auto",
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sampling_mode = adc_ns.enum("SamplingMode", is_class=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SAMPLING_MODES = {
 | 
				
			||||||
 | 
					    "avg": sampling_mode.AVG,
 | 
				
			||||||
 | 
					    "min": sampling_mode.MIN,
 | 
				
			||||||
 | 
					    "max": sampling_mode.MAX,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
adc1_channel_t = cg.global_ns.enum("adc1_channel_t")
 | 
					adc1_channel_t = cg.global_ns.enum("adc1_channel_t")
 | 
				
			||||||
adc2_channel_t = cg.global_ns.enum("adc2_channel_t")
 | 
					adc2_channel_t = cg.global_ns.enum("adc2_channel_t")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# From https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/adc_common.h
 | 
					 | 
				
			||||||
# pin to adc1 channel mapping
 | 
					# pin to adc1 channel mapping
 | 
				
			||||||
 | 
					# https://github.com/espressif/esp-idf/blob/v4.4.8/components/driver/include/driver/adc.h
 | 
				
			||||||
ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
 | 
					ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
 | 
				
			||||||
 | 
					    # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32/include/soc/adc_channel.h
 | 
				
			||||||
    VARIANT_ESP32: {
 | 
					    VARIANT_ESP32: {
 | 
				
			||||||
        36: adc1_channel_t.ADC1_CHANNEL_0,
 | 
					        36: adc1_channel_t.ADC1_CHANNEL_0,
 | 
				
			||||||
        37: adc1_channel_t.ADC1_CHANNEL_1,
 | 
					        37: adc1_channel_t.ADC1_CHANNEL_1,
 | 
				
			||||||
@@ -54,6 +61,41 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
 | 
				
			|||||||
        34: adc1_channel_t.ADC1_CHANNEL_6,
 | 
					        34: adc1_channel_t.ADC1_CHANNEL_6,
 | 
				
			||||||
        35: adc1_channel_t.ADC1_CHANNEL_7,
 | 
					        35: adc1_channel_t.ADC1_CHANNEL_7,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c2/include/soc/adc_channel.h
 | 
				
			||||||
 | 
					    VARIANT_ESP32C2: {
 | 
				
			||||||
 | 
					        0: adc1_channel_t.ADC1_CHANNEL_0,
 | 
				
			||||||
 | 
					        1: adc1_channel_t.ADC1_CHANNEL_1,
 | 
				
			||||||
 | 
					        2: adc1_channel_t.ADC1_CHANNEL_2,
 | 
				
			||||||
 | 
					        3: adc1_channel_t.ADC1_CHANNEL_3,
 | 
				
			||||||
 | 
					        4: adc1_channel_t.ADC1_CHANNEL_4,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c3/include/soc/adc_channel.h
 | 
				
			||||||
 | 
					    VARIANT_ESP32C3: {
 | 
				
			||||||
 | 
					        0: adc1_channel_t.ADC1_CHANNEL_0,
 | 
				
			||||||
 | 
					        1: adc1_channel_t.ADC1_CHANNEL_1,
 | 
				
			||||||
 | 
					        2: adc1_channel_t.ADC1_CHANNEL_2,
 | 
				
			||||||
 | 
					        3: adc1_channel_t.ADC1_CHANNEL_3,
 | 
				
			||||||
 | 
					        4: adc1_channel_t.ADC1_CHANNEL_4,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c6/include/soc/adc_channel.h
 | 
				
			||||||
 | 
					    VARIANT_ESP32C6: {
 | 
				
			||||||
 | 
					        0: adc1_channel_t.ADC1_CHANNEL_0,
 | 
				
			||||||
 | 
					        1: adc1_channel_t.ADC1_CHANNEL_1,
 | 
				
			||||||
 | 
					        2: adc1_channel_t.ADC1_CHANNEL_2,
 | 
				
			||||||
 | 
					        3: adc1_channel_t.ADC1_CHANNEL_3,
 | 
				
			||||||
 | 
					        4: adc1_channel_t.ADC1_CHANNEL_4,
 | 
				
			||||||
 | 
					        5: adc1_channel_t.ADC1_CHANNEL_5,
 | 
				
			||||||
 | 
					        6: adc1_channel_t.ADC1_CHANNEL_6,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32h2/include/soc/adc_channel.h
 | 
				
			||||||
 | 
					    VARIANT_ESP32H2: {
 | 
				
			||||||
 | 
					        1: adc1_channel_t.ADC1_CHANNEL_0,
 | 
				
			||||||
 | 
					        2: adc1_channel_t.ADC1_CHANNEL_1,
 | 
				
			||||||
 | 
					        3: adc1_channel_t.ADC1_CHANNEL_2,
 | 
				
			||||||
 | 
					        4: adc1_channel_t.ADC1_CHANNEL_3,
 | 
				
			||||||
 | 
					        5: adc1_channel_t.ADC1_CHANNEL_4,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s2/include/soc/adc_channel.h
 | 
				
			||||||
    VARIANT_ESP32S2: {
 | 
					    VARIANT_ESP32S2: {
 | 
				
			||||||
        1: adc1_channel_t.ADC1_CHANNEL_0,
 | 
					        1: adc1_channel_t.ADC1_CHANNEL_0,
 | 
				
			||||||
        2: adc1_channel_t.ADC1_CHANNEL_1,
 | 
					        2: adc1_channel_t.ADC1_CHANNEL_1,
 | 
				
			||||||
@@ -66,6 +108,7 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
 | 
				
			|||||||
        9: adc1_channel_t.ADC1_CHANNEL_8,
 | 
					        9: adc1_channel_t.ADC1_CHANNEL_8,
 | 
				
			||||||
        10: adc1_channel_t.ADC1_CHANNEL_9,
 | 
					        10: adc1_channel_t.ADC1_CHANNEL_9,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s3/include/soc/adc_channel.h
 | 
				
			||||||
    VARIANT_ESP32S3: {
 | 
					    VARIANT_ESP32S3: {
 | 
				
			||||||
        1: adc1_channel_t.ADC1_CHANNEL_0,
 | 
					        1: adc1_channel_t.ADC1_CHANNEL_0,
 | 
				
			||||||
        2: adc1_channel_t.ADC1_CHANNEL_1,
 | 
					        2: adc1_channel_t.ADC1_CHANNEL_1,
 | 
				
			||||||
@@ -78,40 +121,12 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
 | 
				
			|||||||
        9: adc1_channel_t.ADC1_CHANNEL_8,
 | 
					        9: adc1_channel_t.ADC1_CHANNEL_8,
 | 
				
			||||||
        10: adc1_channel_t.ADC1_CHANNEL_9,
 | 
					        10: adc1_channel_t.ADC1_CHANNEL_9,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    VARIANT_ESP32C3: {
 | 
					 | 
				
			||||||
        0: adc1_channel_t.ADC1_CHANNEL_0,
 | 
					 | 
				
			||||||
        1: adc1_channel_t.ADC1_CHANNEL_1,
 | 
					 | 
				
			||||||
        2: adc1_channel_t.ADC1_CHANNEL_2,
 | 
					 | 
				
			||||||
        3: adc1_channel_t.ADC1_CHANNEL_3,
 | 
					 | 
				
			||||||
        4: adc1_channel_t.ADC1_CHANNEL_4,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    VARIANT_ESP32C2: {
 | 
					 | 
				
			||||||
        0: adc1_channel_t.ADC1_CHANNEL_0,
 | 
					 | 
				
			||||||
        1: adc1_channel_t.ADC1_CHANNEL_1,
 | 
					 | 
				
			||||||
        2: adc1_channel_t.ADC1_CHANNEL_2,
 | 
					 | 
				
			||||||
        3: adc1_channel_t.ADC1_CHANNEL_3,
 | 
					 | 
				
			||||||
        4: adc1_channel_t.ADC1_CHANNEL_4,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    VARIANT_ESP32C6: {
 | 
					 | 
				
			||||||
        0: adc1_channel_t.ADC1_CHANNEL_0,
 | 
					 | 
				
			||||||
        1: adc1_channel_t.ADC1_CHANNEL_1,
 | 
					 | 
				
			||||||
        2: adc1_channel_t.ADC1_CHANNEL_2,
 | 
					 | 
				
			||||||
        3: adc1_channel_t.ADC1_CHANNEL_3,
 | 
					 | 
				
			||||||
        4: adc1_channel_t.ADC1_CHANNEL_4,
 | 
					 | 
				
			||||||
        5: adc1_channel_t.ADC1_CHANNEL_5,
 | 
					 | 
				
			||||||
        6: adc1_channel_t.ADC1_CHANNEL_6,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    VARIANT_ESP32H2: {
 | 
					 | 
				
			||||||
        0: adc1_channel_t.ADC1_CHANNEL_0,
 | 
					 | 
				
			||||||
        1: adc1_channel_t.ADC1_CHANNEL_1,
 | 
					 | 
				
			||||||
        2: adc1_channel_t.ADC1_CHANNEL_2,
 | 
					 | 
				
			||||||
        3: adc1_channel_t.ADC1_CHANNEL_3,
 | 
					 | 
				
			||||||
        4: adc1_channel_t.ADC1_CHANNEL_4,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# pin to adc2 channel mapping
 | 
				
			||||||
 | 
					# https://github.com/espressif/esp-idf/blob/v4.4.8/components/driver/include/driver/adc.h
 | 
				
			||||||
ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
 | 
					ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
 | 
				
			||||||
    # TODO: add other variants
 | 
					    # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32/include/soc/adc_channel.h
 | 
				
			||||||
    VARIANT_ESP32: {
 | 
					    VARIANT_ESP32: {
 | 
				
			||||||
        4: adc2_channel_t.ADC2_CHANNEL_0,
 | 
					        4: adc2_channel_t.ADC2_CHANNEL_0,
 | 
				
			||||||
        0: adc2_channel_t.ADC2_CHANNEL_1,
 | 
					        0: adc2_channel_t.ADC2_CHANNEL_1,
 | 
				
			||||||
@@ -124,6 +139,19 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
 | 
				
			|||||||
        25: adc2_channel_t.ADC2_CHANNEL_8,
 | 
					        25: adc2_channel_t.ADC2_CHANNEL_8,
 | 
				
			||||||
        26: adc2_channel_t.ADC2_CHANNEL_9,
 | 
					        26: adc2_channel_t.ADC2_CHANNEL_9,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c2/include/soc/adc_channel.h
 | 
				
			||||||
 | 
					    VARIANT_ESP32C2: {
 | 
				
			||||||
 | 
					        5: adc2_channel_t.ADC2_CHANNEL_0,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c3/include/soc/adc_channel.h
 | 
				
			||||||
 | 
					    VARIANT_ESP32C3: {
 | 
				
			||||||
 | 
					        5: adc2_channel_t.ADC2_CHANNEL_0,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c6/include/soc/adc_channel.h
 | 
				
			||||||
 | 
					    VARIANT_ESP32C6: {},  # no ADC2
 | 
				
			||||||
 | 
					    # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32h2/include/soc/adc_channel.h
 | 
				
			||||||
 | 
					    VARIANT_ESP32H2: {},  # no ADC2
 | 
				
			||||||
 | 
					    # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s2/include/soc/adc_channel.h
 | 
				
			||||||
    VARIANT_ESP32S2: {
 | 
					    VARIANT_ESP32S2: {
 | 
				
			||||||
        11: adc2_channel_t.ADC2_CHANNEL_0,
 | 
					        11: adc2_channel_t.ADC2_CHANNEL_0,
 | 
				
			||||||
        12: adc2_channel_t.ADC2_CHANNEL_1,
 | 
					        12: adc2_channel_t.ADC2_CHANNEL_1,
 | 
				
			||||||
@@ -136,6 +164,7 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
 | 
				
			|||||||
        19: adc2_channel_t.ADC2_CHANNEL_8,
 | 
					        19: adc2_channel_t.ADC2_CHANNEL_8,
 | 
				
			||||||
        20: adc2_channel_t.ADC2_CHANNEL_9,
 | 
					        20: adc2_channel_t.ADC2_CHANNEL_9,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    # https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s3/include/soc/adc_channel.h
 | 
				
			||||||
    VARIANT_ESP32S3: {
 | 
					    VARIANT_ESP32S3: {
 | 
				
			||||||
        11: adc2_channel_t.ADC2_CHANNEL_0,
 | 
					        11: adc2_channel_t.ADC2_CHANNEL_0,
 | 
				
			||||||
        12: adc2_channel_t.ADC2_CHANNEL_1,
 | 
					        12: adc2_channel_t.ADC2_CHANNEL_1,
 | 
				
			||||||
@@ -148,12 +177,6 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
 | 
				
			|||||||
        19: adc2_channel_t.ADC2_CHANNEL_8,
 | 
					        19: adc2_channel_t.ADC2_CHANNEL_8,
 | 
				
			||||||
        20: adc2_channel_t.ADC2_CHANNEL_9,
 | 
					        20: adc2_channel_t.ADC2_CHANNEL_9,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    VARIANT_ESP32C3: {
 | 
					 | 
				
			||||||
        5: adc2_channel_t.ADC2_CHANNEL_0,
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    VARIANT_ESP32C2: {},
 | 
					 | 
				
			||||||
    VARIANT_ESP32C6: {},
 | 
					 | 
				
			||||||
    VARIANT_ESP32H2: {},
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,332 +0,0 @@
 | 
				
			|||||||
#include "adc_sensor.h"
 | 
					 | 
				
			||||||
#include "esphome/core/helpers.h"
 | 
					 | 
				
			||||||
#include "esphome/core/log.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_ESP8266
 | 
					 | 
				
			||||||
#ifdef USE_ADC_SENSOR_VCC
 | 
					 | 
				
			||||||
#include <Esp.h>
 | 
					 | 
				
			||||||
ADC_MODE(ADC_VCC)
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#include <Arduino.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_RP2040
 | 
					 | 
				
			||||||
#ifdef CYW43_USES_VSYS_PIN
 | 
					 | 
				
			||||||
#include "pico/cyw43_arch.h"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#include <hardware/adc.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace esphome {
 | 
					 | 
				
			||||||
namespace adc {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const char *const TAG = "adc";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 13-bit for S2, 12-bit for all other ESP32 variants
 | 
					 | 
				
			||||||
#ifdef USE_ESP32
 | 
					 | 
				
			||||||
static const adc_bits_width_t ADC_WIDTH_MAX_SOC_BITS = static_cast<adc_bits_width_t>(ADC_WIDTH_MAX - 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef SOC_ADC_RTC_MAX_BITWIDTH
 | 
					 | 
				
			||||||
#if USE_ESP32_VARIANT_ESP32S2
 | 
					 | 
				
			||||||
static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 13;
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 12;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1;    // 4095 (12 bit) or 8191 (13 bit)
 | 
					 | 
				
			||||||
static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1;  // 2048 (12 bit) or 4096 (13 bit)
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_RP2040
 | 
					 | 
				
			||||||
extern "C"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    void
 | 
					 | 
				
			||||||
    ADCSensor::setup() {
 | 
					 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up ADC '%s'...", this->get_name().c_str());
 | 
					 | 
				
			||||||
#if !defined(USE_ADC_SENSOR_VCC) && !defined(USE_RP2040)
 | 
					 | 
				
			||||||
  this->pin_->setup();
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_ESP32
 | 
					 | 
				
			||||||
  if (this->channel1_ != ADC1_CHANNEL_MAX) {
 | 
					 | 
				
			||||||
    adc1_config_width(ADC_WIDTH_MAX_SOC_BITS);
 | 
					 | 
				
			||||||
    if (!this->autorange_) {
 | 
					 | 
				
			||||||
      adc1_config_channel_atten(this->channel1_, this->attenuation_);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  } else if (this->channel2_ != ADC2_CHANNEL_MAX) {
 | 
					 | 
				
			||||||
    if (!this->autorange_) {
 | 
					 | 
				
			||||||
      adc2_config_channel_atten(this->channel2_, this->attenuation_);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // load characteristics for each attenuation
 | 
					 | 
				
			||||||
  for (int32_t i = 0; i <= ADC_ATTEN_DB_12_COMPAT; i++) {
 | 
					 | 
				
			||||||
    auto adc_unit = this->channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2;
 | 
					 | 
				
			||||||
    auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS,
 | 
					 | 
				
			||||||
                                              1100,  // default vref
 | 
					 | 
				
			||||||
                                              &this->cal_characteristics_[i]);
 | 
					 | 
				
			||||||
    switch (cal_value) {
 | 
					 | 
				
			||||||
      case ESP_ADC_CAL_VAL_EFUSE_VREF:
 | 
					 | 
				
			||||||
        ESP_LOGV(TAG, "Using eFuse Vref for calibration");
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case ESP_ADC_CAL_VAL_EFUSE_TP:
 | 
					 | 
				
			||||||
        ESP_LOGV(TAG, "Using two-point eFuse Vref for calibration");
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case ESP_ADC_CAL_VAL_DEFAULT_VREF:
 | 
					 | 
				
			||||||
      default:
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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() {
 | 
					 | 
				
			||||||
  LOG_SENSOR("", "ADC Sensor", this);
 | 
					 | 
				
			||||||
#if defined(USE_ESP8266) || defined(USE_LIBRETINY)
 | 
					 | 
				
			||||||
#ifdef USE_ADC_SENSOR_VCC
 | 
					 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  Pin: VCC");
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
  LOG_PIN("  Pin: ", this->pin_);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#endif  // USE_ESP8266 || USE_LIBRETINY
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_ESP32
 | 
					 | 
				
			||||||
  LOG_PIN("  Pin: ", this->pin_);
 | 
					 | 
				
			||||||
  if (this->autorange_) {
 | 
					 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "  Attenuation: auto");
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    switch (this->attenuation_) {
 | 
					 | 
				
			||||||
      case ADC_ATTEN_DB_0:
 | 
					 | 
				
			||||||
        ESP_LOGCONFIG(TAG, "  Attenuation: 0db");
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case ADC_ATTEN_DB_2_5:
 | 
					 | 
				
			||||||
        ESP_LOGCONFIG(TAG, "  Attenuation: 2.5db");
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case ADC_ATTEN_DB_6:
 | 
					 | 
				
			||||||
        ESP_LOGCONFIG(TAG, "  Attenuation: 6db");
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      case ADC_ATTEN_DB_12_COMPAT:
 | 
					 | 
				
			||||||
        ESP_LOGCONFIG(TAG, "  Attenuation: 12db");
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      default:  // This is to satisfy the unused ADC_ATTEN_MAX
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#endif  // USE_ESP32
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_RP2040
 | 
					 | 
				
			||||||
  if (this->is_temperature_) {
 | 
					 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "  Pin: Temperature");
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
#ifdef USE_ADC_SENSOR_VCC
 | 
					 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "  Pin: VCC");
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
    LOG_PIN("  Pin: ", this->pin_);
 | 
					 | 
				
			||||||
#endif  // USE_ADC_SENSOR_VCC
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#endif  // USE_RP2040
 | 
					 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  Samples: %i", this->sample_count_);
 | 
					 | 
				
			||||||
  LOG_UPDATE_INTERVAL(this);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
float ADCSensor::get_setup_priority() const { return setup_priority::DATA; }
 | 
					 | 
				
			||||||
void ADCSensor::update() {
 | 
					 | 
				
			||||||
  float value_v = this->sample();
 | 
					 | 
				
			||||||
  ESP_LOGV(TAG, "'%s': Got voltage=%.4fV", this->get_name().c_str(), value_v);
 | 
					 | 
				
			||||||
  this->publish_state(value_v);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ADCSensor::set_sample_count(uint8_t sample_count) {
 | 
					 | 
				
			||||||
  if (sample_count != 0) {
 | 
					 | 
				
			||||||
    this->sample_count_ = sample_count;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_ESP8266
 | 
					 | 
				
			||||||
float ADCSensor::sample() {
 | 
					 | 
				
			||||||
  uint32_t raw = 0;
 | 
					 | 
				
			||||||
  for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
					 | 
				
			||||||
#ifdef USE_ADC_SENSOR_VCC
 | 
					 | 
				
			||||||
    raw += ESP.getVcc();  // NOLINT(readability-static-accessed-through-instance)
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
    raw += analogRead(this->pin_->get_pin());  // NOLINT
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
					 | 
				
			||||||
  if (this->output_raw_) {
 | 
					 | 
				
			||||||
    return raw;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return raw / 1024.0f;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_ESP32
 | 
					 | 
				
			||||||
float ADCSensor::sample() {
 | 
					 | 
				
			||||||
  if (!this->autorange_) {
 | 
					 | 
				
			||||||
    uint32_t sum = 0;
 | 
					 | 
				
			||||||
    for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
					 | 
				
			||||||
      int raw = -1;
 | 
					 | 
				
			||||||
      if (this->channel1_ != ADC1_CHANNEL_MAX) {
 | 
					 | 
				
			||||||
        raw = adc1_get_raw(this->channel1_);
 | 
					 | 
				
			||||||
      } else if (this->channel2_ != ADC2_CHANNEL_MAX) {
 | 
					 | 
				
			||||||
        adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (raw == -1) {
 | 
					 | 
				
			||||||
        return NAN;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      sum += raw;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    sum = (sum + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
					 | 
				
			||||||
    if (this->output_raw_) {
 | 
					 | 
				
			||||||
      return sum;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    uint32_t mv = esp_adc_cal_raw_to_voltage(sum, &this->cal_characteristics_[(int32_t) this->attenuation_]);
 | 
					 | 
				
			||||||
    return mv / 1000.0f;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int raw12 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (this->channel1_ != ADC1_CHANNEL_MAX) {
 | 
					 | 
				
			||||||
    adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_12_COMPAT);
 | 
					 | 
				
			||||||
    raw12 = adc1_get_raw(this->channel1_);
 | 
					 | 
				
			||||||
    if (raw12 < ADC_MAX) {
 | 
					 | 
				
			||||||
      adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_6);
 | 
					 | 
				
			||||||
      raw6 = adc1_get_raw(this->channel1_);
 | 
					 | 
				
			||||||
      if (raw6 < ADC_MAX) {
 | 
					 | 
				
			||||||
        adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_2_5);
 | 
					 | 
				
			||||||
        raw2 = adc1_get_raw(this->channel1_);
 | 
					 | 
				
			||||||
        if (raw2 < ADC_MAX) {
 | 
					 | 
				
			||||||
          adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_0);
 | 
					 | 
				
			||||||
          raw0 = adc1_get_raw(this->channel1_);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  } else if (this->channel2_ != ADC2_CHANNEL_MAX) {
 | 
					 | 
				
			||||||
    adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_12_COMPAT);
 | 
					 | 
				
			||||||
    adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw12);
 | 
					 | 
				
			||||||
    if (raw12 < ADC_MAX) {
 | 
					 | 
				
			||||||
      adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_6);
 | 
					 | 
				
			||||||
      adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6);
 | 
					 | 
				
			||||||
      if (raw6 < ADC_MAX) {
 | 
					 | 
				
			||||||
        adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_2_5);
 | 
					 | 
				
			||||||
        adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw2);
 | 
					 | 
				
			||||||
        if (raw2 < ADC_MAX) {
 | 
					 | 
				
			||||||
          adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_0);
 | 
					 | 
				
			||||||
          adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw0);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (raw0 == -1 || raw2 == -1 || raw6 == -1 || raw12 == -1) {
 | 
					 | 
				
			||||||
    return NAN;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  uint32_t mv12 = esp_adc_cal_raw_to_voltage(raw12, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_12_COMPAT]);
 | 
					 | 
				
			||||||
  uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_6]);
 | 
					 | 
				
			||||||
  uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]);
 | 
					 | 
				
			||||||
  uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Contribution of each value, in range 0-2048 (12 bit ADC) or 0-4096 (13 bit ADC)
 | 
					 | 
				
			||||||
  uint32_t c12 = std::min(raw12, ADC_HALF);
 | 
					 | 
				
			||||||
  uint32_t c6 = ADC_HALF - std::abs(raw6 - ADC_HALF);
 | 
					 | 
				
			||||||
  uint32_t c2 = ADC_HALF - std::abs(raw2 - ADC_HALF);
 | 
					 | 
				
			||||||
  uint32_t c0 = std::min(ADC_MAX - raw0, ADC_HALF);
 | 
					 | 
				
			||||||
  // max theoretical csum value is 4096*4 = 16384
 | 
					 | 
				
			||||||
  uint32_t csum = c12 + c6 + c2 + c0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // each mv is max 3900; so max value is 3900*4096*4, fits in unsigned32
 | 
					 | 
				
			||||||
  uint32_t mv_scaled = (mv12 * c12) + (mv6 * c6) + (mv2 * c2) + (mv0 * c0);
 | 
					 | 
				
			||||||
  return mv_scaled / (float) (csum * 1000U);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#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);
 | 
					 | 
				
			||||||
    uint32_t raw = 0;
 | 
					 | 
				
			||||||
    for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
					 | 
				
			||||||
      raw += adc_read();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
					 | 
				
			||||||
    adc_set_temp_sensor_enabled(false);
 | 
					 | 
				
			||||||
    if (this->output_raw_) {
 | 
					 | 
				
			||||||
      return raw;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return raw * 3.3f / 4096.0f;
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    uint8_t pin = this->pin_->get_pin();
 | 
					 | 
				
			||||||
#ifdef CYW43_USES_VSYS_PIN
 | 
					 | 
				
			||||||
    if (pin == PICO_VSYS_PIN) {
 | 
					 | 
				
			||||||
      // Measuring VSYS on Raspberry Pico W needs to be wrapped with
 | 
					 | 
				
			||||||
      // `cyw43_thread_enter()`/`cyw43_thread_exit()` as discussed in
 | 
					 | 
				
			||||||
      // https://github.com/raspberrypi/pico-sdk/issues/1222, since Wifi chip and
 | 
					 | 
				
			||||||
      // VSYS ADC both share GPIO29
 | 
					 | 
				
			||||||
      cyw43_thread_enter();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
#endif  // CYW43_USES_VSYS_PIN
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    adc_gpio_init(pin);
 | 
					 | 
				
			||||||
    adc_select_input(pin - 26);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    uint32_t raw = 0;
 | 
					 | 
				
			||||||
    for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
					 | 
				
			||||||
      raw += adc_read();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CYW43_USES_VSYS_PIN
 | 
					 | 
				
			||||||
    if (pin == PICO_VSYS_PIN) {
 | 
					 | 
				
			||||||
      cyw43_thread_exit();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
#endif  // CYW43_USES_VSYS_PIN
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (this->output_raw_) {
 | 
					 | 
				
			||||||
      return raw;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    float coeff = pin == PICO_VSYS_PIN ? 3.0 : 1.0;
 | 
					 | 
				
			||||||
    return raw * 3.3f / 4096.0f * coeff;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_LIBRETINY
 | 
					 | 
				
			||||||
float ADCSensor::sample() {
 | 
					 | 
				
			||||||
  uint32_t raw = 0;
 | 
					 | 
				
			||||||
  if (this->output_raw_) {
 | 
					 | 
				
			||||||
    for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
					 | 
				
			||||||
      raw += analogRead(this->pin_->get_pin());  // NOLINT
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
					 | 
				
			||||||
    return raw;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
					 | 
				
			||||||
    raw += analogReadVoltage(this->pin_->get_pin());  // NOLINT
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  raw = (raw + (this->sample_count_ >> 1)) / this->sample_count_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
					 | 
				
			||||||
  return raw / 1000.0f;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif  // USE_LIBRETINY
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef USE_ESP8266
 | 
					 | 
				
			||||||
std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}  // namespace adc
 | 
					 | 
				
			||||||
}  // namespace esphome
 | 
					 | 
				
			||||||
@@ -3,13 +3,12 @@
 | 
				
			|||||||
#include "esphome/components/sensor/sensor.h"
 | 
					#include "esphome/components/sensor/sensor.h"
 | 
				
			||||||
#include "esphome/components/voltage_sampler/voltage_sampler.h"
 | 
					#include "esphome/components/voltage_sampler/voltage_sampler.h"
 | 
				
			||||||
#include "esphome/core/component.h"
 | 
					#include "esphome/core/component.h"
 | 
				
			||||||
#include "esphome/core/defines.h"
 | 
					 | 
				
			||||||
#include "esphome/core/hal.h"
 | 
					#include "esphome/core/hal.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
#include <esp_adc_cal.h>
 | 
					#include <esp_adc_cal.h>
 | 
				
			||||||
#include "driver/adc.h"
 | 
					#include "driver/adc.h"
 | 
				
			||||||
#endif
 | 
					#endif  // USE_ESP32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace adc {
 | 
					namespace adc {
 | 
				
			||||||
@@ -29,6 +28,21 @@ static const adc_atten_t ADC_ATTEN_DB_12_COMPAT = ADC_ATTEN_DB_11;
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
#endif  // USE_ESP32
 | 
					#endif  // USE_ESP32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class SamplingMode : uint8_t { AVG = 0, MIN = 1, MAX = 2 };
 | 
				
			||||||
 | 
					const LogString *sampling_mode_to_str(SamplingMode mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Aggregator {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  void add_sample(uint32_t value);
 | 
				
			||||||
 | 
					  uint32_t aggregate();
 | 
				
			||||||
 | 
					  Aggregator(SamplingMode mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 protected:
 | 
				
			||||||
 | 
					  SamplingMode mode_{SamplingMode::AVG};
 | 
				
			||||||
 | 
					  uint32_t aggr_{0};
 | 
				
			||||||
 | 
					  uint32_t samples_{0};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler {
 | 
					class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
@@ -43,7 +57,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
 | 
				
			|||||||
    this->channel1_ = ADC1_CHANNEL_MAX;
 | 
					    this->channel1_ = ADC1_CHANNEL_MAX;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  void set_autorange(bool autorange) { this->autorange_ = autorange; }
 | 
					  void set_autorange(bool autorange) { this->autorange_ = autorange; }
 | 
				
			||||||
#endif
 | 
					#endif  // USE_ESP32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Update ADC values
 | 
					  /// Update ADC values
 | 
				
			||||||
  void update() override;
 | 
					  void update() override;
 | 
				
			||||||
@@ -55,24 +69,26 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
 | 
				
			|||||||
  void set_pin(InternalGPIOPin *pin) { this->pin_ = pin; }
 | 
					  void set_pin(InternalGPIOPin *pin) { this->pin_ = pin; }
 | 
				
			||||||
  void set_output_raw(bool output_raw) { this->output_raw_ = output_raw; }
 | 
					  void set_output_raw(bool output_raw) { this->output_raw_ = output_raw; }
 | 
				
			||||||
  void set_sample_count(uint8_t sample_count);
 | 
					  void set_sample_count(uint8_t sample_count);
 | 
				
			||||||
 | 
					  void set_sampling_mode(SamplingMode sampling_mode);
 | 
				
			||||||
  float sample() override;
 | 
					  float sample() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP8266
 | 
					#ifdef USE_ESP8266
 | 
				
			||||||
  std::string unique_id() override;
 | 
					  std::string unique_id() override;
 | 
				
			||||||
#endif
 | 
					#endif  // USE_ESP8266
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_RP2040
 | 
					#ifdef USE_RP2040
 | 
				
			||||||
  void set_is_temperature() { this->is_temperature_ = true; }
 | 
					  void set_is_temperature() { this->is_temperature_ = true; }
 | 
				
			||||||
#endif
 | 
					#endif  // USE_RP2040
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
  InternalGPIOPin *pin_;
 | 
					  InternalGPIOPin *pin_;
 | 
				
			||||||
  bool output_raw_{false};
 | 
					  bool output_raw_{false};
 | 
				
			||||||
  uint8_t sample_count_{1};
 | 
					  uint8_t sample_count_{1};
 | 
				
			||||||
 | 
					  SamplingMode sampling_mode_{SamplingMode::AVG};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_RP2040
 | 
					#ifdef USE_RP2040
 | 
				
			||||||
  bool is_temperature_{false};
 | 
					  bool is_temperature_{false};
 | 
				
			||||||
#endif
 | 
					#endif  // USE_RP2040
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP32
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
  adc_atten_t attenuation_{ADC_ATTEN_DB_0};
 | 
					  adc_atten_t attenuation_{ADC_ATTEN_DB_0};
 | 
				
			||||||
@@ -83,8 +99,8 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
 | 
				
			|||||||
  esp_adc_cal_characteristics_t cal_characteristics_[SOC_ADC_ATTEN_NUM] = {};
 | 
					  esp_adc_cal_characteristics_t cal_characteristics_[SOC_ADC_ATTEN_NUM] = {};
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  esp_adc_cal_characteristics_t cal_characteristics_[ADC_ATTEN_MAX] = {};
 | 
					  esp_adc_cal_characteristics_t cal_characteristics_[ADC_ATTEN_MAX] = {};
 | 
				
			||||||
#endif
 | 
					#endif  // ESP_IDF_VERSION_MAJOR
 | 
				
			||||||
#endif
 | 
					#endif  // USE_ESP32
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace adc
 | 
					}  // namespace adc
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										79
									
								
								esphome/components/adc/adc_sensor_common.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								esphome/components/adc/adc_sensor_common.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					#include "adc_sensor.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace adc {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "adc.common";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const LogString *sampling_mode_to_str(SamplingMode mode) {
 | 
				
			||||||
 | 
					  switch (mode) {
 | 
				
			||||||
 | 
					    case SamplingMode::AVG:
 | 
				
			||||||
 | 
					      return LOG_STR("average");
 | 
				
			||||||
 | 
					    case SamplingMode::MIN:
 | 
				
			||||||
 | 
					      return LOG_STR("minimum");
 | 
				
			||||||
 | 
					    case SamplingMode::MAX:
 | 
				
			||||||
 | 
					      return LOG_STR("maximum");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return LOG_STR("unknown");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Aggregator::Aggregator(SamplingMode mode) {
 | 
				
			||||||
 | 
					  this->mode_ = mode;
 | 
				
			||||||
 | 
					  // set to max uint if mode is "min"
 | 
				
			||||||
 | 
					  if (mode == SamplingMode::MIN) {
 | 
				
			||||||
 | 
					    this->aggr_ = UINT32_MAX;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Aggregator::add_sample(uint32_t value) {
 | 
				
			||||||
 | 
					  this->samples_ += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  switch (this->mode_) {
 | 
				
			||||||
 | 
					    case SamplingMode::AVG:
 | 
				
			||||||
 | 
					      this->aggr_ += value;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case SamplingMode::MIN:
 | 
				
			||||||
 | 
					      if (value < this->aggr_) {
 | 
				
			||||||
 | 
					        this->aggr_ = value;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case SamplingMode::MAX:
 | 
				
			||||||
 | 
					      if (value > this->aggr_) {
 | 
				
			||||||
 | 
					        this->aggr_ = value;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint32_t Aggregator::aggregate() {
 | 
				
			||||||
 | 
					  if (this->mode_ == SamplingMode::AVG) {
 | 
				
			||||||
 | 
					    if (this->samples_ == 0) {
 | 
				
			||||||
 | 
					      return this->aggr_;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (this->aggr_ + (this->samples_ >> 1)) / this->samples_;  // NOLINT(clang-analyzer-core.DivideZero)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return this->aggr_;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ADCSensor::update() {
 | 
				
			||||||
 | 
					  float value_v = this->sample();
 | 
				
			||||||
 | 
					  ESP_LOGV(TAG, "'%s': Got voltage=%.4fV", this->get_name().c_str(), value_v);
 | 
				
			||||||
 | 
					  this->publish_state(value_v);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ADCSensor::set_sample_count(uint8_t sample_count) {
 | 
				
			||||||
 | 
					  if (sample_count != 0) {
 | 
				
			||||||
 | 
					    this->sample_count_ = sample_count;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ADCSensor::set_sampling_mode(SamplingMode sampling_mode) { this->sampling_mode_ = sampling_mode; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float ADCSensor::get_setup_priority() const { return setup_priority::DATA; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace adc
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										168
									
								
								esphome/components/adc/adc_sensor_esp32.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								esphome/components/adc/adc_sensor_esp32.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,168 @@
 | 
				
			|||||||
 | 
					#ifdef USE_ESP32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "adc_sensor.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace adc {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "adc.esp32";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const adc_bits_width_t ADC_WIDTH_MAX_SOC_BITS = static_cast<adc_bits_width_t>(ADC_WIDTH_MAX - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef SOC_ADC_RTC_MAX_BITWIDTH
 | 
				
			||||||
 | 
					#if USE_ESP32_VARIANT_ESP32S2
 | 
				
			||||||
 | 
					static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 13;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static const int32_t SOC_ADC_RTC_MAX_BITWIDTH = 12;
 | 
				
			||||||
 | 
					#endif  // USE_ESP32_VARIANT_ESP32S2
 | 
				
			||||||
 | 
					#endif  // SOC_ADC_RTC_MAX_BITWIDTH
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const int ADC_MAX = (1 << SOC_ADC_RTC_MAX_BITWIDTH) - 1;
 | 
				
			||||||
 | 
					static const int ADC_HALF = (1 << SOC_ADC_RTC_MAX_BITWIDTH) >> 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ADCSensor::setup() {
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (this->channel1_ != ADC1_CHANNEL_MAX) {
 | 
				
			||||||
 | 
					    adc1_config_width(ADC_WIDTH_MAX_SOC_BITS);
 | 
				
			||||||
 | 
					    if (!this->autorange_) {
 | 
				
			||||||
 | 
					      adc1_config_channel_atten(this->channel1_, this->attenuation_);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  } else if (this->channel2_ != ADC2_CHANNEL_MAX) {
 | 
				
			||||||
 | 
					    if (!this->autorange_) {
 | 
				
			||||||
 | 
					      adc2_config_channel_atten(this->channel2_, this->attenuation_);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (int32_t i = 0; i <= ADC_ATTEN_DB_12_COMPAT; i++) {
 | 
				
			||||||
 | 
					    auto adc_unit = this->channel1_ != ADC1_CHANNEL_MAX ? ADC_UNIT_1 : ADC_UNIT_2;
 | 
				
			||||||
 | 
					    auto cal_value = esp_adc_cal_characterize(adc_unit, (adc_atten_t) i, ADC_WIDTH_MAX_SOC_BITS,
 | 
				
			||||||
 | 
					                                              1100,  // default vref
 | 
				
			||||||
 | 
					                                              &this->cal_characteristics_[i]);
 | 
				
			||||||
 | 
					    switch (cal_value) {
 | 
				
			||||||
 | 
					      case ESP_ADC_CAL_VAL_EFUSE_VREF:
 | 
				
			||||||
 | 
					        ESP_LOGV(TAG, "Using eFuse Vref for calibration");
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case ESP_ADC_CAL_VAL_EFUSE_TP:
 | 
				
			||||||
 | 
					        ESP_LOGV(TAG, "Using two-point eFuse Vref for calibration");
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case ESP_ADC_CAL_VAL_DEFAULT_VREF:
 | 
				
			||||||
 | 
					      default:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ADCSensor::dump_config() {
 | 
				
			||||||
 | 
					  LOG_SENSOR("", "ADC Sensor", this);
 | 
				
			||||||
 | 
					  LOG_PIN("  Pin: ", this->pin_);
 | 
				
			||||||
 | 
					  if (this->autorange_) {
 | 
				
			||||||
 | 
					    ESP_LOGCONFIG(TAG, "  Attenuation: auto");
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    switch (this->attenuation_) {
 | 
				
			||||||
 | 
					      case ADC_ATTEN_DB_0:
 | 
				
			||||||
 | 
					        ESP_LOGCONFIG(TAG, "  Attenuation: 0db");
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case ADC_ATTEN_DB_2_5:
 | 
				
			||||||
 | 
					        ESP_LOGCONFIG(TAG, "  Attenuation: 2.5db");
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case ADC_ATTEN_DB_6:
 | 
				
			||||||
 | 
					        ESP_LOGCONFIG(TAG, "  Attenuation: 6db");
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case ADC_ATTEN_DB_12_COMPAT:
 | 
				
			||||||
 | 
					        ESP_LOGCONFIG(TAG, "  Attenuation: 12db");
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      default:  // This is to satisfy the unused ADC_ATTEN_MAX
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG,
 | 
				
			||||||
 | 
					                "  Samples: %i\n"
 | 
				
			||||||
 | 
					                "  Sampling mode: %s",
 | 
				
			||||||
 | 
					                this->sample_count_, LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_)));
 | 
				
			||||||
 | 
					  LOG_UPDATE_INTERVAL(this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float ADCSensor::sample() {
 | 
				
			||||||
 | 
					  if (!this->autorange_) {
 | 
				
			||||||
 | 
					    auto aggr = Aggregator(this->sampling_mode_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
				
			||||||
 | 
					      int raw = -1;
 | 
				
			||||||
 | 
					      if (this->channel1_ != ADC1_CHANNEL_MAX) {
 | 
				
			||||||
 | 
					        raw = adc1_get_raw(this->channel1_);
 | 
				
			||||||
 | 
					      } else if (this->channel2_ != ADC2_CHANNEL_MAX) {
 | 
				
			||||||
 | 
					        adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (raw == -1) {
 | 
				
			||||||
 | 
					        return NAN;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      aggr.add_sample(raw);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (this->output_raw_) {
 | 
				
			||||||
 | 
					      return aggr.aggregate();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    uint32_t mv =
 | 
				
			||||||
 | 
					        esp_adc_cal_raw_to_voltage(aggr.aggregate(), &this->cal_characteristics_[(int32_t) this->attenuation_]);
 | 
				
			||||||
 | 
					    return mv / 1000.0f;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int raw12 = ADC_MAX, raw6 = ADC_MAX, raw2 = ADC_MAX, raw0 = ADC_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (this->channel1_ != ADC1_CHANNEL_MAX) {
 | 
				
			||||||
 | 
					    adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_12_COMPAT);
 | 
				
			||||||
 | 
					    raw12 = adc1_get_raw(this->channel1_);
 | 
				
			||||||
 | 
					    if (raw12 < ADC_MAX) {
 | 
				
			||||||
 | 
					      adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_6);
 | 
				
			||||||
 | 
					      raw6 = adc1_get_raw(this->channel1_);
 | 
				
			||||||
 | 
					      if (raw6 < ADC_MAX) {
 | 
				
			||||||
 | 
					        adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_2_5);
 | 
				
			||||||
 | 
					        raw2 = adc1_get_raw(this->channel1_);
 | 
				
			||||||
 | 
					        if (raw2 < ADC_MAX) {
 | 
				
			||||||
 | 
					          adc1_config_channel_atten(this->channel1_, ADC_ATTEN_DB_0);
 | 
				
			||||||
 | 
					          raw0 = adc1_get_raw(this->channel1_);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  } else if (this->channel2_ != ADC2_CHANNEL_MAX) {
 | 
				
			||||||
 | 
					    adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_12_COMPAT);
 | 
				
			||||||
 | 
					    adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw12);
 | 
				
			||||||
 | 
					    if (raw12 < ADC_MAX) {
 | 
				
			||||||
 | 
					      adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_6);
 | 
				
			||||||
 | 
					      adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw6);
 | 
				
			||||||
 | 
					      if (raw6 < ADC_MAX) {
 | 
				
			||||||
 | 
					        adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_2_5);
 | 
				
			||||||
 | 
					        adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw2);
 | 
				
			||||||
 | 
					        if (raw2 < ADC_MAX) {
 | 
				
			||||||
 | 
					          adc2_config_channel_atten(this->channel2_, ADC_ATTEN_DB_0);
 | 
				
			||||||
 | 
					          adc2_get_raw(this->channel2_, ADC_WIDTH_MAX_SOC_BITS, &raw0);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (raw0 == -1 || raw2 == -1 || raw6 == -1 || raw12 == -1) {
 | 
				
			||||||
 | 
					    return NAN;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint32_t mv12 = esp_adc_cal_raw_to_voltage(raw12, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_12_COMPAT]);
 | 
				
			||||||
 | 
					  uint32_t mv6 = esp_adc_cal_raw_to_voltage(raw6, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_6]);
 | 
				
			||||||
 | 
					  uint32_t mv2 = esp_adc_cal_raw_to_voltage(raw2, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_2_5]);
 | 
				
			||||||
 | 
					  uint32_t mv0 = esp_adc_cal_raw_to_voltage(raw0, &this->cal_characteristics_[(int32_t) ADC_ATTEN_DB_0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint32_t c12 = std::min(raw12, ADC_HALF);
 | 
				
			||||||
 | 
					  uint32_t c6 = ADC_HALF - std::abs(raw6 - ADC_HALF);
 | 
				
			||||||
 | 
					  uint32_t c2 = ADC_HALF - std::abs(raw2 - ADC_HALF);
 | 
				
			||||||
 | 
					  uint32_t c0 = std::min(ADC_MAX - raw0, ADC_HALF);
 | 
				
			||||||
 | 
					  uint32_t csum = c12 + c6 + c2 + c0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint32_t mv_scaled = (mv12 * c12) + (mv6 * c6) + (mv2 * c2) + (mv0 * c0);
 | 
				
			||||||
 | 
					  return mv_scaled / (float) (csum * 1000U);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace adc
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  // USE_ESP32
 | 
				
			||||||
							
								
								
									
										64
									
								
								esphome/components/adc/adc_sensor_esp8266.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								esphome/components/adc/adc_sensor_esp8266.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					#ifdef USE_ESP8266
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "adc_sensor.h"
 | 
				
			||||||
 | 
					#include "esphome/core/helpers.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_ADC_SENSOR_VCC
 | 
				
			||||||
 | 
					#include <Esp.h>
 | 
				
			||||||
 | 
					ADC_MODE(ADC_VCC)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#include <Arduino.h>
 | 
				
			||||||
 | 
					#endif  // USE_ADC_SENSOR_VCC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace adc {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "adc.esp8266";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ADCSensor::setup() {
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
 | 
				
			||||||
 | 
					#ifndef USE_ADC_SENSOR_VCC
 | 
				
			||||||
 | 
					  this->pin_->setup();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ADCSensor::dump_config() {
 | 
				
			||||||
 | 
					  LOG_SENSOR("", "ADC Sensor", this);
 | 
				
			||||||
 | 
					#ifdef USE_ADC_SENSOR_VCC
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "  Pin: VCC");
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					  LOG_PIN("  Pin: ", this->pin_);
 | 
				
			||||||
 | 
					#endif  // USE_ADC_SENSOR_VCC
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG,
 | 
				
			||||||
 | 
					                "  Samples: %i\n"
 | 
				
			||||||
 | 
					                "  Sampling mode: %s",
 | 
				
			||||||
 | 
					                this->sample_count_, LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_)));
 | 
				
			||||||
 | 
					  LOG_UPDATE_INTERVAL(this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float ADCSensor::sample() {
 | 
				
			||||||
 | 
					  auto aggr = Aggregator(this->sampling_mode_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
				
			||||||
 | 
					    uint32_t raw = 0;
 | 
				
			||||||
 | 
					#ifdef USE_ADC_SENSOR_VCC
 | 
				
			||||||
 | 
					    raw = ESP.getVcc();  // NOLINT(readability-static-accessed-through-instance)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    raw = analogRead(this->pin_->get_pin());  // NOLINT
 | 
				
			||||||
 | 
					#endif  // USE_ADC_SENSOR_VCC
 | 
				
			||||||
 | 
					    aggr.add_sample(raw);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (this->output_raw_) {
 | 
				
			||||||
 | 
					    return aggr.aggregate();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return aggr.aggregate() / 1024.0f;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string ADCSensor::unique_id() { return get_mac_address() + "-adc"; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace adc
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  // USE_ESP8266
 | 
				
			||||||
							
								
								
									
										55
									
								
								esphome/components/adc/adc_sensor_libretiny.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								esphome/components/adc/adc_sensor_libretiny.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					#ifdef USE_LIBRETINY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "adc_sensor.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace adc {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "adc.libretiny";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ADCSensor::setup() {
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
 | 
				
			||||||
 | 
					#ifndef USE_ADC_SENSOR_VCC
 | 
				
			||||||
 | 
					  this->pin_->setup();
 | 
				
			||||||
 | 
					#endif  // !USE_ADC_SENSOR_VCC
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ADCSensor::dump_config() {
 | 
				
			||||||
 | 
					  LOG_SENSOR("", "ADC Sensor", this);
 | 
				
			||||||
 | 
					#ifdef USE_ADC_SENSOR_VCC
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "  Pin: VCC");
 | 
				
			||||||
 | 
					#else   // USE_ADC_SENSOR_VCC
 | 
				
			||||||
 | 
					  LOG_PIN("  Pin: ", this->pin_);
 | 
				
			||||||
 | 
					#endif  // USE_ADC_SENSOR_VCC
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG,
 | 
				
			||||||
 | 
					                "  Samples: %i\n"
 | 
				
			||||||
 | 
					                "  Sampling mode: %s",
 | 
				
			||||||
 | 
					                this->sample_count_, LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_)));
 | 
				
			||||||
 | 
					  LOG_UPDATE_INTERVAL(this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float ADCSensor::sample() {
 | 
				
			||||||
 | 
					  uint32_t raw = 0;
 | 
				
			||||||
 | 
					  auto aggr = Aggregator(this->sampling_mode_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (this->output_raw_) {
 | 
				
			||||||
 | 
					    for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
				
			||||||
 | 
					      raw = analogRead(this->pin_->get_pin());  // NOLINT
 | 
				
			||||||
 | 
					      aggr.add_sample(raw);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return aggr.aggregate();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
				
			||||||
 | 
					    raw = analogReadVoltage(this->pin_->get_pin());  // NOLINT
 | 
				
			||||||
 | 
					    aggr.add_sample(raw);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return aggr.aggregate() / 1000.0f;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace adc
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  // USE_LIBRETINY
 | 
				
			||||||
							
								
								
									
										98
									
								
								esphome/components/adc/adc_sensor_rp2040.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								esphome/components/adc/adc_sensor_rp2040.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
				
			|||||||
 | 
					#ifdef USE_RP2040
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "adc_sensor.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CYW43_USES_VSYS_PIN
 | 
				
			||||||
 | 
					#include "pico/cyw43_arch.h"
 | 
				
			||||||
 | 
					#endif  // CYW43_USES_VSYS_PIN
 | 
				
			||||||
 | 
					#include <hardware/adc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace adc {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "adc.rp2040";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ADCSensor::setup() {
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "Running setup for '%s'", this->get_name().c_str());
 | 
				
			||||||
 | 
					  static bool initialized = false;
 | 
				
			||||||
 | 
					  if (!initialized) {
 | 
				
			||||||
 | 
					    adc_init();
 | 
				
			||||||
 | 
					    initialized = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ADCSensor::dump_config() {
 | 
				
			||||||
 | 
					  LOG_SENSOR("", "ADC Sensor", this);
 | 
				
			||||||
 | 
					  if (this->is_temperature_) {
 | 
				
			||||||
 | 
					    ESP_LOGCONFIG(TAG, "  Pin: Temperature");
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					#ifdef USE_ADC_SENSOR_VCC
 | 
				
			||||||
 | 
					    ESP_LOGCONFIG(TAG, "  Pin: VCC");
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    LOG_PIN("  Pin: ", this->pin_);
 | 
				
			||||||
 | 
					#endif  // USE_ADC_SENSOR_VCC
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG,
 | 
				
			||||||
 | 
					                "  Samples: %i\n"
 | 
				
			||||||
 | 
					                "  Sampling mode: %s",
 | 
				
			||||||
 | 
					                this->sample_count_, LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_)));
 | 
				
			||||||
 | 
					  LOG_UPDATE_INTERVAL(this);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float ADCSensor::sample() {
 | 
				
			||||||
 | 
					  uint32_t raw = 0;
 | 
				
			||||||
 | 
					  auto aggr = Aggregator(this->sampling_mode_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (this->is_temperature_) {
 | 
				
			||||||
 | 
					    adc_set_temp_sensor_enabled(true);
 | 
				
			||||||
 | 
					    delay(1);
 | 
				
			||||||
 | 
					    adc_select_input(4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
				
			||||||
 | 
					      raw = adc_read();
 | 
				
			||||||
 | 
					      aggr.add_sample(raw);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    adc_set_temp_sensor_enabled(false);
 | 
				
			||||||
 | 
					    if (this->output_raw_) {
 | 
				
			||||||
 | 
					      return aggr.aggregate();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return aggr.aggregate() * 3.3f / 4096.0f;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint8_t pin = this->pin_->get_pin();
 | 
				
			||||||
 | 
					#ifdef CYW43_USES_VSYS_PIN
 | 
				
			||||||
 | 
					  if (pin == PICO_VSYS_PIN) {
 | 
				
			||||||
 | 
					    // Measuring VSYS on Raspberry Pico W needs to be wrapped with
 | 
				
			||||||
 | 
					    // `cyw43_thread_enter()`/`cyw43_thread_exit()` as discussed in
 | 
				
			||||||
 | 
					    // https://github.com/raspberrypi/pico-sdk/issues/1222, since Wifi chip and
 | 
				
			||||||
 | 
					    // VSYS ADC both share GPIO29
 | 
				
			||||||
 | 
					    cyw43_thread_enter();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#endif  // CYW43_USES_VSYS_PIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  adc_gpio_init(pin);
 | 
				
			||||||
 | 
					  adc_select_input(pin - 26);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (uint8_t sample = 0; sample < this->sample_count_; sample++) {
 | 
				
			||||||
 | 
					    raw = adc_read();
 | 
				
			||||||
 | 
					    aggr.add_sample(raw);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CYW43_USES_VSYS_PIN
 | 
				
			||||||
 | 
					  if (pin == PICO_VSYS_PIN) {
 | 
				
			||||||
 | 
					    cyw43_thread_exit();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#endif  // CYW43_USES_VSYS_PIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (this->output_raw_) {
 | 
				
			||||||
 | 
					    return aggr.aggregate();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  float coeff = pin == PICO_VSYS_PIN ? 3.0f : 1.0f;
 | 
				
			||||||
 | 
					  return aggr.aggregate() * 3.3f / 4096.0f * coeff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace adc
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  // USE_RP2040
 | 
				
			||||||
@@ -1,11 +1,9 @@
 | 
				
			|||||||
import logging
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
import esphome.final_validate as fv
 | 
					 | 
				
			||||||
from esphome.core import CORE
 | 
					 | 
				
			||||||
from esphome.components import sensor, voltage_sampler
 | 
					from esphome.components import sensor, voltage_sampler
 | 
				
			||||||
from esphome.components.esp32 import get_esp32_variant
 | 
					from esphome.components.esp32 import get_esp32_variant
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_ATTENUATION,
 | 
					    CONF_ATTENUATION,
 | 
				
			||||||
    CONF_ID,
 | 
					    CONF_ID,
 | 
				
			||||||
@@ -17,10 +15,14 @@ from esphome.const import (
 | 
				
			|||||||
    STATE_CLASS_MEASUREMENT,
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_VOLT,
 | 
					    UNIT_VOLT,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					from esphome.core import CORE
 | 
				
			||||||
 | 
					import esphome.final_validate as fv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from . import (
 | 
					from . import (
 | 
				
			||||||
    ATTENUATION_MODES,
 | 
					    ATTENUATION_MODES,
 | 
				
			||||||
    ESP32_VARIANT_ADC1_PIN_TO_CHANNEL,
 | 
					    ESP32_VARIANT_ADC1_PIN_TO_CHANNEL,
 | 
				
			||||||
    ESP32_VARIANT_ADC2_PIN_TO_CHANNEL,
 | 
					    ESP32_VARIANT_ADC2_PIN_TO_CHANNEL,
 | 
				
			||||||
 | 
					    SAMPLING_MODES,
 | 
				
			||||||
    adc_ns,
 | 
					    adc_ns,
 | 
				
			||||||
    validate_adc_pin,
 | 
					    validate_adc_pin,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -30,9 +32,11 @@ _LOGGER = logging.getLogger(__name__)
 | 
				
			|||||||
AUTO_LOAD = ["voltage_sampler"]
 | 
					AUTO_LOAD = ["voltage_sampler"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONF_SAMPLES = "samples"
 | 
					CONF_SAMPLES = "samples"
 | 
				
			||||||
 | 
					CONF_SAMPLING_MODE = "sampling_mode"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_attenuation = cv.enum(ATTENUATION_MODES, lower=True)
 | 
					_attenuation = cv.enum(ATTENUATION_MODES, lower=True)
 | 
				
			||||||
 | 
					_sampling_mode = cv.enum(SAMPLING_MODES, lower=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def validate_config(config):
 | 
					def validate_config(config):
 | 
				
			||||||
@@ -88,6 +92,7 @@ CONFIG_SCHEMA = cv.All(
 | 
				
			|||||||
                cv.only_on_esp32, _attenuation
 | 
					                cv.only_on_esp32, _attenuation
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cv.Optional(CONF_SAMPLES, default=1): cv.int_range(min=1, max=255),
 | 
					            cv.Optional(CONF_SAMPLES, default=1): cv.int_range(min=1, max=255),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_SAMPLING_MODE, default="avg"): _sampling_mode,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    .extend(cv.polling_component_schema("60s")),
 | 
					    .extend(cv.polling_component_schema("60s")),
 | 
				
			||||||
@@ -112,6 +117,7 @@ async def to_code(config):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    cg.add(var.set_output_raw(config[CONF_RAW]))
 | 
					    cg.add(var.set_output_raw(config[CONF_RAW]))
 | 
				
			||||||
    cg.add(var.set_sample_count(config[CONF_SAMPLES]))
 | 
					    cg.add(var.set_sample_count(config[CONF_SAMPLES]))
 | 
				
			||||||
 | 
					    cg.add(var.set_sampling_mode(config[CONF_SAMPLING_MODE]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if attenuation := config.get(CONF_ATTENUATION):
 | 
					    if attenuation := config.get(CONF_ATTENUATION):
 | 
				
			||||||
        if attenuation == "auto":
 | 
					        if attenuation == "auto":
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import spi
 | 
					from esphome.components import spi
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import CONF_ID
 | 
					from esphome.const import CONF_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEPENDENCIES = ["spi"]
 | 
					DEPENDENCIES = ["spi"]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ static const char *const TAG = "adc128s102";
 | 
				
			|||||||
float ADC128S102::get_setup_priority() const { return setup_priority::HARDWARE; }
 | 
					float ADC128S102::get_setup_priority() const { return setup_priority::HARDWARE; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ADC128S102::setup() {
 | 
					void ADC128S102::setup() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up adc128s102");
 | 
					  ESP_LOGCONFIG(TAG, "Running setup");
 | 
				
			||||||
  this->spi_setup();
 | 
					  this->spi_setup();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,9 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import sensor, voltage_sampler
 | 
					from esphome.components import sensor, voltage_sampler
 | 
				
			||||||
from esphome.const import CONF_ID, CONF_CHANNEL
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome.const import CONF_CHANNEL, CONF_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .. import adc128s102_ns, ADC128S102
 | 
					from .. import ADC128S102, adc128s102_ns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AUTO_LOAD = ["voltage_sampler"]
 | 
					AUTO_LOAD = ["voltage_sampler"]
 | 
				
			||||||
DEPENDENCIES = ["adc128s102"]
 | 
					DEPENDENCIES = ["adc128s102"]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,15 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import display, light
 | 
					from esphome.components import display, light
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
 | 
					    CONF_ADDRESSABLE_LIGHT_ID,
 | 
				
			||||||
 | 
					    CONF_HEIGHT,
 | 
				
			||||||
    CONF_ID,
 | 
					    CONF_ID,
 | 
				
			||||||
    CONF_LAMBDA,
 | 
					    CONF_LAMBDA,
 | 
				
			||||||
    CONF_PAGES,
 | 
					    CONF_PAGES,
 | 
				
			||||||
    CONF_ADDRESSABLE_LIGHT_ID,
 | 
					 | 
				
			||||||
    CONF_HEIGHT,
 | 
					 | 
				
			||||||
    CONF_WIDTH,
 | 
					 | 
				
			||||||
    CONF_UPDATE_INTERVAL,
 | 
					 | 
				
			||||||
    CONF_PIXEL_MAPPER,
 | 
					    CONF_PIXEL_MAPPER,
 | 
				
			||||||
 | 
					    CONF_UPDATE_INTERVAL,
 | 
				
			||||||
 | 
					    CONF_WIDTH,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CODEOWNERS = ["@justfalter"]
 | 
					CODEOWNERS = ["@justfalter"]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -177,11 +177,14 @@ void ADE7880::dump_config() {
 | 
				
			|||||||
    LOG_SENSOR("    ", "Power Factor", this->channel_a_->power_factor);
 | 
					    LOG_SENSOR("    ", "Power Factor", this->channel_a_->power_factor);
 | 
				
			||||||
    LOG_SENSOR("    ", "Forward Active Energy", this->channel_a_->forward_active_energy);
 | 
					    LOG_SENSOR("    ", "Forward Active Energy", this->channel_a_->forward_active_energy);
 | 
				
			||||||
    LOG_SENSOR("    ", "Reverse Active Energy", this->channel_a_->reverse_active_energy);
 | 
					    LOG_SENSOR("    ", "Reverse Active Energy", this->channel_a_->reverse_active_energy);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "    Calibration:");
 | 
					    ESP_LOGCONFIG(TAG,
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Current: %" PRId32, this->channel_a_->current_gain_calibration);
 | 
					                  "    Calibration:\n"
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Voltage: %" PRId32, this->channel_a_->voltage_gain_calibration);
 | 
					                  "     Current: %" PRId32 "\n"
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Power: %" PRId32, this->channel_a_->power_gain_calibration);
 | 
					                  "     Voltage: %" PRId32 "\n"
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Phase Angle: %u", this->channel_a_->phase_angle_calibration);
 | 
					                  "     Power: %" PRId32 "\n"
 | 
				
			||||||
 | 
					                  "     Phase Angle: %u",
 | 
				
			||||||
 | 
					                  this->channel_a_->current_gain_calibration, this->channel_a_->voltage_gain_calibration,
 | 
				
			||||||
 | 
					                  this->channel_a_->power_gain_calibration, this->channel_a_->phase_angle_calibration);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (this->channel_b_ != nullptr) {
 | 
					  if (this->channel_b_ != nullptr) {
 | 
				
			||||||
@@ -193,11 +196,14 @@ void ADE7880::dump_config() {
 | 
				
			|||||||
    LOG_SENSOR("    ", "Power Factor", this->channel_b_->power_factor);
 | 
					    LOG_SENSOR("    ", "Power Factor", this->channel_b_->power_factor);
 | 
				
			||||||
    LOG_SENSOR("    ", "Forward Active Energy", this->channel_b_->forward_active_energy);
 | 
					    LOG_SENSOR("    ", "Forward Active Energy", this->channel_b_->forward_active_energy);
 | 
				
			||||||
    LOG_SENSOR("    ", "Reverse Active Energy", this->channel_b_->reverse_active_energy);
 | 
					    LOG_SENSOR("    ", "Reverse Active Energy", this->channel_b_->reverse_active_energy);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "    Calibration:");
 | 
					    ESP_LOGCONFIG(TAG,
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Current: %" PRId32, this->channel_b_->current_gain_calibration);
 | 
					                  "    Calibration:\n"
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Voltage: %" PRId32, this->channel_b_->voltage_gain_calibration);
 | 
					                  "     Current: %" PRId32 "\n"
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Power: %" PRId32, this->channel_b_->power_gain_calibration);
 | 
					                  "     Voltage: %" PRId32 "\n"
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Phase Angle: %u", this->channel_b_->phase_angle_calibration);
 | 
					                  "     Power: %" PRId32 "\n"
 | 
				
			||||||
 | 
					                  "     Phase Angle: %u",
 | 
				
			||||||
 | 
					                  this->channel_b_->current_gain_calibration, this->channel_b_->voltage_gain_calibration,
 | 
				
			||||||
 | 
					                  this->channel_b_->power_gain_calibration, this->channel_b_->phase_angle_calibration);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (this->channel_c_ != nullptr) {
 | 
					  if (this->channel_c_ != nullptr) {
 | 
				
			||||||
@@ -209,18 +215,23 @@ void ADE7880::dump_config() {
 | 
				
			|||||||
    LOG_SENSOR("    ", "Power Factor", this->channel_c_->power_factor);
 | 
					    LOG_SENSOR("    ", "Power Factor", this->channel_c_->power_factor);
 | 
				
			||||||
    LOG_SENSOR("    ", "Forward Active Energy", this->channel_c_->forward_active_energy);
 | 
					    LOG_SENSOR("    ", "Forward Active Energy", this->channel_c_->forward_active_energy);
 | 
				
			||||||
    LOG_SENSOR("    ", "Reverse Active Energy", this->channel_c_->reverse_active_energy);
 | 
					    LOG_SENSOR("    ", "Reverse Active Energy", this->channel_c_->reverse_active_energy);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "    Calibration:");
 | 
					    ESP_LOGCONFIG(TAG,
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Current: %" PRId32, this->channel_c_->current_gain_calibration);
 | 
					                  "    Calibration:\n"
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Voltage: %" PRId32, this->channel_c_->voltage_gain_calibration);
 | 
					                  "     Current: %" PRId32 "\n"
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Power: %" PRId32, this->channel_c_->power_gain_calibration);
 | 
					                  "     Voltage: %" PRId32 "\n"
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Phase Angle: %u", this->channel_c_->phase_angle_calibration);
 | 
					                  "     Power: %" PRId32 "\n"
 | 
				
			||||||
 | 
					                  "     Phase Angle: %u",
 | 
				
			||||||
 | 
					                  this->channel_c_->current_gain_calibration, this->channel_c_->voltage_gain_calibration,
 | 
				
			||||||
 | 
					                  this->channel_c_->power_gain_calibration, this->channel_c_->phase_angle_calibration);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (this->channel_n_ != nullptr) {
 | 
					  if (this->channel_n_ != nullptr) {
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "  Neutral:");
 | 
					    ESP_LOGCONFIG(TAG, "  Neutral:");
 | 
				
			||||||
    LOG_SENSOR("    ", "Current", this->channel_n_->current);
 | 
					    LOG_SENSOR("    ", "Current", this->channel_n_->current);
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "    Calibration:");
 | 
					    ESP_LOGCONFIG(TAG,
 | 
				
			||||||
    ESP_LOGCONFIG(TAG, "     Current: %" PRId32, this->channel_n_->current_gain_calibration);
 | 
					                  "    Calibration:\n"
 | 
				
			||||||
 | 
					                  "     Current: %" PRId32,
 | 
				
			||||||
 | 
					                  this->channel_n_->current_gain_calibration);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  LOG_I2C_DEVICE(this);
 | 
					  LOG_I2C_DEVICE(this);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import sensor, i2c
 | 
					 | 
				
			||||||
from esphome import pins
 | 
					from esphome import pins
 | 
				
			||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					from esphome.components import i2c, sensor
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_ACTIVE_POWER,
 | 
					    CONF_ACTIVE_POWER,
 | 
				
			||||||
    CONF_APPARENT_POWER,
 | 
					    CONF_APPARENT_POWER,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,27 +1,27 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import sensor
 | 
					 | 
				
			||||||
from esphome import pins
 | 
					from esphome import pins
 | 
				
			||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					from esphome.components import sensor
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
 | 
					    CONF_FREQUENCY,
 | 
				
			||||||
    CONF_IRQ_PIN,
 | 
					    CONF_IRQ_PIN,
 | 
				
			||||||
    CONF_VOLTAGE,
 | 
					    CONF_VOLTAGE,
 | 
				
			||||||
    CONF_FREQUENCY,
 | 
					 | 
				
			||||||
    CONF_VOLTAGE_GAIN,
 | 
					    CONF_VOLTAGE_GAIN,
 | 
				
			||||||
    DEVICE_CLASS_CURRENT,
 | 
					 | 
				
			||||||
    DEVICE_CLASS_APPARENT_POWER,
 | 
					    DEVICE_CLASS_APPARENT_POWER,
 | 
				
			||||||
    DEVICE_CLASS_POWER,
 | 
					    DEVICE_CLASS_CURRENT,
 | 
				
			||||||
    DEVICE_CLASS_REACTIVE_POWER,
 | 
					 | 
				
			||||||
    DEVICE_CLASS_POWER_FACTOR,
 | 
					 | 
				
			||||||
    DEVICE_CLASS_VOLTAGE,
 | 
					 | 
				
			||||||
    DEVICE_CLASS_FREQUENCY,
 | 
					    DEVICE_CLASS_FREQUENCY,
 | 
				
			||||||
 | 
					    DEVICE_CLASS_POWER,
 | 
				
			||||||
 | 
					    DEVICE_CLASS_POWER_FACTOR,
 | 
				
			||||||
 | 
					    DEVICE_CLASS_REACTIVE_POWER,
 | 
				
			||||||
 | 
					    DEVICE_CLASS_VOLTAGE,
 | 
				
			||||||
    STATE_CLASS_MEASUREMENT,
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_VOLT,
 | 
					 | 
				
			||||||
    UNIT_HERTZ,
 | 
					 | 
				
			||||||
    UNIT_AMPERE,
 | 
					    UNIT_AMPERE,
 | 
				
			||||||
    UNIT_VOLT_AMPS,
 | 
					    UNIT_HERTZ,
 | 
				
			||||||
    UNIT_WATT,
 | 
					 | 
				
			||||||
    UNIT_VOLT_AMPS_REACTIVE,
 | 
					 | 
				
			||||||
    UNIT_PERCENT,
 | 
					    UNIT_PERCENT,
 | 
				
			||||||
 | 
					    UNIT_VOLT,
 | 
				
			||||||
 | 
					    UNIT_VOLT_AMPS,
 | 
				
			||||||
 | 
					    UNIT_VOLT_AMPS_REACTIVE,
 | 
				
			||||||
 | 
					    UNIT_WATT,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONF_CURRENT_A = "current_a"
 | 
					CONF_CURRENT_A = "current_a"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,15 +58,18 @@ void ADE7953::dump_config() {
 | 
				
			|||||||
  LOG_SENSOR("  ", "Active Power B Sensor", this->active_power_b_sensor_);
 | 
					  LOG_SENSOR("  ", "Active Power B Sensor", this->active_power_b_sensor_);
 | 
				
			||||||
  LOG_SENSOR("  ", "Rective Power A Sensor", this->reactive_power_a_sensor_);
 | 
					  LOG_SENSOR("  ", "Rective Power A Sensor", this->reactive_power_a_sensor_);
 | 
				
			||||||
  LOG_SENSOR("  ", "Reactive Power B Sensor", this->reactive_power_b_sensor_);
 | 
					  LOG_SENSOR("  ", "Reactive Power B Sensor", this->reactive_power_b_sensor_);
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  USE_ACC_ENERGY_REGS: %d", this->use_acc_energy_regs_);
 | 
					  ESP_LOGCONFIG(TAG,
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  PGA_V_8: 0x%X", pga_v_);
 | 
					                "  USE_ACC_ENERGY_REGS: %d\n"
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  PGA_IA_8: 0x%X", pga_ia_);
 | 
					                "  PGA_V_8: 0x%X\n"
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  PGA_IB_8: 0x%X", pga_ib_);
 | 
					                "  PGA_IA_8: 0x%X\n"
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  VGAIN_32: 0x%08jX", (uintmax_t) vgain_);
 | 
					                "  PGA_IB_8: 0x%X\n"
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  AIGAIN_32: 0x%08jX", (uintmax_t) aigain_);
 | 
					                "  VGAIN_32: 0x%08jX\n"
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  BIGAIN_32: 0x%08jX", (uintmax_t) bigain_);
 | 
					                "  AIGAIN_32: 0x%08jX\n"
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  AWGAIN_32: 0x%08jX", (uintmax_t) awgain_);
 | 
					                "  BIGAIN_32: 0x%08jX\n"
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  BWGAIN_32: 0x%08jX", (uintmax_t) bwgain_);
 | 
					                "  AWGAIN_32: 0x%08jX\n"
 | 
				
			||||||
 | 
					                "  BWGAIN_32: 0x%08jX",
 | 
				
			||||||
 | 
					                this->use_acc_energy_regs_, pga_v_, pga_ia_, pga_ib_, (uintmax_t) vgain_, (uintmax_t) aigain_,
 | 
				
			||||||
 | 
					                (uintmax_t) bigain_, (uintmax_t) awgain_, (uintmax_t) bwgain_);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ADE_PUBLISH_(name, val, factor) \
 | 
					#define ADE_PUBLISH_(name, val, factor) \
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
#include "ade7953_i2c.h"
 | 
					#include "ade7953_i2c.h"
 | 
				
			||||||
#include "esphome/core/log.h"
 | 
					 | 
				
			||||||
#include "esphome/core/helpers.h"
 | 
					#include "esphome/core/helpers.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace ade7953_i2c {
 | 
					namespace ade7953_i2c {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,8 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					from esphome.components import ade7953_base, i2c
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.components import i2c, ade7953_base
 | 
					 | 
				
			||||||
from esphome.const import CONF_ID
 | 
					from esphome.const import CONF_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
DEPENDENCIES = ["i2c"]
 | 
					DEPENDENCIES = ["i2c"]
 | 
				
			||||||
AUTO_LOAD = ["ade7953_base"]
 | 
					AUTO_LOAD = ["ade7953_base"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
#include "ade7953_spi.h"
 | 
					#include "ade7953_spi.h"
 | 
				
			||||||
#include "esphome/core/log.h"
 | 
					 | 
				
			||||||
#include "esphome/core/helpers.h"
 | 
					#include "esphome/core/helpers.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace ade7953_spi {
 | 
					namespace ade7953_spi {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,8 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					from esphome.components import ade7953_base, spi
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.components import spi, ade7953_base
 | 
					 | 
				
			||||||
from esphome.const import CONF_ID
 | 
					from esphome.const import CONF_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
DEPENDENCIES = ["spi"]
 | 
					DEPENDENCIES = ["spi"]
 | 
				
			||||||
AUTO_LOAD = ["ade7953_base"]
 | 
					AUTO_LOAD = ["ade7953_base"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import i2c
 | 
					from esphome.components import i2c
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import CONF_ID
 | 
					from esphome.const import CONF_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEPENDENCIES = ["i2c"]
 | 
					DEPENDENCIES = ["i2c"]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,18 +9,14 @@ 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;  // 3300_SPS for ADS1015
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ADS1115Component::setup() {
 | 
					void ADS1115Component::setup() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up ADS1115...");
 | 
					  ESP_LOGCONFIG(TAG, "Running setup");
 | 
				
			||||||
  uint16_t value;
 | 
					  uint16_t value;
 | 
				
			||||||
  if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &value)) {
 | 
					  if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &value)) {
 | 
				
			||||||
    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
 | 
				
			||||||
@@ -43,9 +39,9 @@ void ADS1115Component::setup() {
 | 
				
			|||||||
    config |= 0b0000000100000000;
 | 
					    config |= 0b0000000100000000;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Set data rate - 860 samples per second (we're in singleshot mode)
 | 
					  // Set data rate - 860 samples per second
 | 
				
			||||||
  //        0bxxxxxxxx100xxxxx
 | 
					  //        0bxxxxxxxx100xxxxx
 | 
				
			||||||
  config |= ADS1115_DATA_RATE_860_SPS << 5;
 | 
					  config |= ADS1115_860SPS << 5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Set comparator mode - hysteresis
 | 
					  // Set comparator mode - hysteresis
 | 
				
			||||||
  //        0bxxxxxxxxxxx0xxxx
 | 
					  //        0bxxxxxxxxxxx0xxxx
 | 
				
			||||||
@@ -70,14 +66,14 @@ void ADS1115Component::setup() {
 | 
				
			|||||||
  this->prev_config_ = config;
 | 
					  this->prev_config_ = config;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void ADS1115Component::dump_config() {
 | 
					void ADS1115Component::dump_config() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up ADS1115...");
 | 
					  ESP_LOGCONFIG(TAG, "ADS1115:");
 | 
				
			||||||
  LOG_I2C_DEVICE(this);
 | 
					  LOG_I2C_DEVICE(this);
 | 
				
			||||||
  if (this->is_failed()) {
 | 
					  if (this->is_failed()) {
 | 
				
			||||||
    ESP_LOGE(TAG, "Communication with ADS1115 failed!");
 | 
					    ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain,
 | 
					float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain,
 | 
				
			||||||
                                            ADS1115Resolution resolution) {
 | 
					                                            ADS1115Resolution resolution, ADS1115Samplerate samplerate) {
 | 
				
			||||||
  uint16_t config = this->prev_config_;
 | 
					  uint16_t config = this->prev_config_;
 | 
				
			||||||
  // Multiplexer
 | 
					  // Multiplexer
 | 
				
			||||||
  //        0bxBBBxxxxxxxxxxxx
 | 
					  //        0bxBBBxxxxxxxxxxxx
 | 
				
			||||||
@@ -89,6 +85,11 @@ float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1
 | 
				
			|||||||
  config &= 0b1111000111111111;
 | 
					  config &= 0b1111000111111111;
 | 
				
			||||||
  config |= (gain & 0b111) << 9;
 | 
					  config |= (gain & 0b111) << 9;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Sample rate
 | 
				
			||||||
 | 
					  //        0bxxxxxxxxBBBxxxxx
 | 
				
			||||||
 | 
					  config &= 0b1111111100011111;
 | 
				
			||||||
 | 
					  config |= (samplerate & 0b111) << 5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!this->continuous_mode_) {
 | 
					  if (!this->continuous_mode_) {
 | 
				
			||||||
    // Start conversion
 | 
					    // Start conversion
 | 
				
			||||||
    config |= 0b1000000000000000;
 | 
					    config |= 0b1000000000000000;
 | 
				
			||||||
@@ -101,8 +102,54 @@ float ADS1115Component::request_measurement(ADS1115Multiplexer multiplexer, ADS1
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    this->prev_config_ = config;
 | 
					    this->prev_config_ = config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // about 1.2 ms with 860 samples per second
 | 
					    // Delay calculated as: ceil((1000/SPS)+.5)
 | 
				
			||||||
    delay(2);
 | 
					    if (resolution == ADS1015_12_BITS) {
 | 
				
			||||||
 | 
					      switch (samplerate) {
 | 
				
			||||||
 | 
					        case ADS1115_8SPS:
 | 
				
			||||||
 | 
					          delay(9);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case ADS1115_16SPS:
 | 
				
			||||||
 | 
					          delay(5);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case ADS1115_32SPS:
 | 
				
			||||||
 | 
					          delay(3);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case ADS1115_64SPS:
 | 
				
			||||||
 | 
					        case ADS1115_128SPS:
 | 
				
			||||||
 | 
					          delay(2);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					          delay(1);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      switch (samplerate) {
 | 
				
			||||||
 | 
					        case ADS1115_8SPS:
 | 
				
			||||||
 | 
					          delay(126);  // NOLINT
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case ADS1115_16SPS:
 | 
				
			||||||
 | 
					          delay(63);  // NOLINT
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case ADS1115_32SPS:
 | 
				
			||||||
 | 
					          delay(32);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case ADS1115_64SPS:
 | 
				
			||||||
 | 
					          delay(17);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case ADS1115_128SPS:
 | 
				
			||||||
 | 
					          delay(9);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case ADS1115_250SPS:
 | 
				
			||||||
 | 
					          delay(5);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case ADS1115_475SPS:
 | 
				
			||||||
 | 
					          delay(3);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case ADS1115_860SPS:
 | 
				
			||||||
 | 
					          delay(2);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // in continuous mode, conversion will always be running, rely on the delay
 | 
					    // in continuous mode, conversion will always be running, rely on the delay
 | 
				
			||||||
    // to ensure conversion is taking place with the correct settings
 | 
					    // to ensure conversion is taking place with the correct settings
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,17 @@ enum ADS1115Resolution {
 | 
				
			|||||||
  ADS1015_12_BITS = 12,
 | 
					  ADS1015_12_BITS = 12,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum ADS1115Samplerate {
 | 
				
			||||||
 | 
					  ADS1115_8SPS = 0b000,
 | 
				
			||||||
 | 
					  ADS1115_16SPS = 0b001,
 | 
				
			||||||
 | 
					  ADS1115_32SPS = 0b010,
 | 
				
			||||||
 | 
					  ADS1115_64SPS = 0b011,
 | 
				
			||||||
 | 
					  ADS1115_128SPS = 0b100,
 | 
				
			||||||
 | 
					  ADS1115_250SPS = 0b101,
 | 
				
			||||||
 | 
					  ADS1115_475SPS = 0b110,
 | 
				
			||||||
 | 
					  ADS1115_860SPS = 0b111
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ADS1115Component : public Component, public i2c::I2CDevice {
 | 
					class ADS1115Component : public Component, public i2c::I2CDevice {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  void setup() override;
 | 
					  void setup() override;
 | 
				
			||||||
@@ -42,7 +53,8 @@ class ADS1115Component : public Component, public i2c::I2CDevice {
 | 
				
			|||||||
  void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; }
 | 
					  void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Helper method to request a measurement from a sensor.
 | 
					  /// Helper method to request a measurement from a sensor.
 | 
				
			||||||
  float request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution);
 | 
					  float request_measurement(ADS1115Multiplexer multiplexer, ADS1115Gain gain, ADS1115Resolution resolution,
 | 
				
			||||||
 | 
					                            ADS1115Samplerate samplerate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
  uint16_t prev_config_{0};
 | 
					  uint16_t prev_config_{0};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,18 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import sensor, voltage_sampler
 | 
					from esphome.components import sensor, voltage_sampler
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_GAIN,
 | 
					    CONF_GAIN,
 | 
				
			||||||
 | 
					    CONF_ID,
 | 
				
			||||||
    CONF_MULTIPLEXER,
 | 
					    CONF_MULTIPLEXER,
 | 
				
			||||||
    CONF_RESOLUTION,
 | 
					    CONF_RESOLUTION,
 | 
				
			||||||
 | 
					    CONF_SAMPLE_RATE,
 | 
				
			||||||
    DEVICE_CLASS_VOLTAGE,
 | 
					    DEVICE_CLASS_VOLTAGE,
 | 
				
			||||||
    STATE_CLASS_MEASUREMENT,
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_VOLT,
 | 
					    UNIT_VOLT,
 | 
				
			||||||
    CONF_ID,
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from .. import ads1115_ns, ADS1115Component, CONF_ADS1115_ID
 | 
					
 | 
				
			||||||
 | 
					from .. import CONF_ADS1115_ID, ADS1115Component, ads1115_ns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AUTO_LOAD = ["voltage_sampler"]
 | 
					AUTO_LOAD = ["voltage_sampler"]
 | 
				
			||||||
DEPENDENCIES = ["ads1115"]
 | 
					DEPENDENCIES = ["ads1115"]
 | 
				
			||||||
@@ -43,6 +45,17 @@ RESOLUTION = {
 | 
				
			|||||||
    "12_BITS": ADS1115Resolution.ADS1015_12_BITS,
 | 
					    "12_BITS": ADS1115Resolution.ADS1015_12_BITS,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ADS1115Samplerate = ads1115_ns.enum("ADS1115Samplerate")
 | 
				
			||||||
 | 
					SAMPLERATE = {
 | 
				
			||||||
 | 
					    "8": ADS1115Samplerate.ADS1115_8SPS,
 | 
				
			||||||
 | 
					    "16": ADS1115Samplerate.ADS1115_16SPS,
 | 
				
			||||||
 | 
					    "32": ADS1115Samplerate.ADS1115_32SPS,
 | 
				
			||||||
 | 
					    "64": ADS1115Samplerate.ADS1115_64SPS,
 | 
				
			||||||
 | 
					    "128": ADS1115Samplerate.ADS1115_128SPS,
 | 
				
			||||||
 | 
					    "250": ADS1115Samplerate.ADS1115_250SPS,
 | 
				
			||||||
 | 
					    "475": ADS1115Samplerate.ADS1115_475SPS,
 | 
				
			||||||
 | 
					    "860": ADS1115Samplerate.ADS1115_860SPS,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ADS1115Sensor = ads1115_ns.class_(
 | 
					ADS1115Sensor = ads1115_ns.class_(
 | 
				
			||||||
    "ADS1115Sensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler
 | 
					    "ADS1115Sensor", sensor.Sensor, cg.PollingComponent, voltage_sampler.VoltageSampler
 | 
				
			||||||
@@ -64,6 +77,9 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
            cv.Optional(CONF_RESOLUTION, default="16_BITS"): cv.enum(
 | 
					            cv.Optional(CONF_RESOLUTION, default="16_BITS"): cv.enum(
 | 
				
			||||||
                RESOLUTION, upper=True, space="_"
 | 
					                RESOLUTION, upper=True, space="_"
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
 | 
					            cv.Optional(CONF_SAMPLE_RATE, default="860"): cv.enum(
 | 
				
			||||||
 | 
					                SAMPLERATE, string=True
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    .extend(cv.polling_component_schema("60s"))
 | 
					    .extend(cv.polling_component_schema("60s"))
 | 
				
			||||||
@@ -79,3 +95,4 @@ 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(var.set_resolution(config[CONF_RESOLUTION]))
 | 
				
			||||||
 | 
					    cg.add(var.set_samplerate(config[CONF_SAMPLE_RATE]))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@ namespace ads1115 {
 | 
				
			|||||||
static const char *const TAG = "ads1115.sensor";
 | 
					static const char *const TAG = "ads1115.sensor";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
float ADS1115Sensor::sample() {
 | 
					float ADS1115Sensor::sample() {
 | 
				
			||||||
  return this->parent_->request_measurement(this->multiplexer_, this->gain_, this->resolution_);
 | 
					  return this->parent_->request_measurement(this->multiplexer_, this->gain_, this->resolution_, this->samplerate_);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ADS1115Sensor::update() {
 | 
					void ADS1115Sensor::update() {
 | 
				
			||||||
@@ -24,6 +24,7 @@ void ADS1115Sensor::dump_config() {
 | 
				
			|||||||
  ESP_LOGCONFIG(TAG, "    Multiplexer: %u", this->multiplexer_);
 | 
					  ESP_LOGCONFIG(TAG, "    Multiplexer: %u", this->multiplexer_);
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "    Gain: %u", this->gain_);
 | 
					  ESP_LOGCONFIG(TAG, "    Gain: %u", this->gain_);
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "    Resolution: %u", this->resolution_);
 | 
					  ESP_LOGCONFIG(TAG, "    Resolution: %u", this->resolution_);
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "    Sample rate: %u", this->samplerate_);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace ads1115
 | 
					}  // namespace ads1115
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@ class ADS1115Sensor : public sensor::Sensor,
 | 
				
			|||||||
  void set_multiplexer(ADS1115Multiplexer multiplexer) { this->multiplexer_ = multiplexer; }
 | 
					  void set_multiplexer(ADS1115Multiplexer multiplexer) { this->multiplexer_ = multiplexer; }
 | 
				
			||||||
  void set_gain(ADS1115Gain gain) { this->gain_ = gain; }
 | 
					  void set_gain(ADS1115Gain gain) { this->gain_ = gain; }
 | 
				
			||||||
  void set_resolution(ADS1115Resolution resolution) { this->resolution_ = resolution; }
 | 
					  void set_resolution(ADS1115Resolution resolution) { this->resolution_ = resolution; }
 | 
				
			||||||
 | 
					  void set_samplerate(ADS1115Samplerate samplerate) { this->samplerate_ = samplerate; }
 | 
				
			||||||
  float sample() override;
 | 
					  float sample() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void dump_config() override;
 | 
					  void dump_config() override;
 | 
				
			||||||
@@ -29,6 +30,7 @@ class ADS1115Sensor : public sensor::Sensor,
 | 
				
			|||||||
  ADS1115Multiplexer multiplexer_;
 | 
					  ADS1115Multiplexer multiplexer_;
 | 
				
			||||||
  ADS1115Gain gain_;
 | 
					  ADS1115Gain gain_;
 | 
				
			||||||
  ADS1115Resolution resolution_;
 | 
					  ADS1115Resolution resolution_;
 | 
				
			||||||
 | 
					  ADS1115Samplerate samplerate_;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace ads1115
 | 
					}  // namespace ads1115
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import spi
 | 
					from esphome.components import spi
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import CONF_ID
 | 
					from esphome.const import CONF_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CODEOWNERS = ["@solomondg1"]
 | 
					CODEOWNERS = ["@solomondg1"]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
#include "ads1118.h"
 | 
					#include "ads1118.h"
 | 
				
			||||||
 | 
					#include "esphome/core/helpers.h"
 | 
				
			||||||
#include "esphome/core/log.h"
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
@@ -8,7 +9,7 @@ static const char *const TAG = "ads1118";
 | 
				
			|||||||
static const uint8_t ADS1118_DATA_RATE_860_SPS = 0b111;
 | 
					static const uint8_t ADS1118_DATA_RATE_860_SPS = 0b111;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ADS1118::setup() {
 | 
					void ADS1118::setup() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up ads1118");
 | 
					  ESP_LOGCONFIG(TAG, "Running setup");
 | 
				
			||||||
  this->spi_setup();
 | 
					  this->spi_setup();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  this->config_ = 0;
 | 
					  this->config_ = 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,17 +1,18 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import sensor, voltage_sampler
 | 
					from esphome.components import sensor, voltage_sampler
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_GAIN,
 | 
					    CONF_GAIN,
 | 
				
			||||||
    CONF_MULTIPLEXER,
 | 
					    CONF_MULTIPLEXER,
 | 
				
			||||||
    DEVICE_CLASS_VOLTAGE,
 | 
					    CONF_TYPE,
 | 
				
			||||||
    DEVICE_CLASS_TEMPERATURE,
 | 
					    DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
 | 
					    DEVICE_CLASS_VOLTAGE,
 | 
				
			||||||
    STATE_CLASS_MEASUREMENT,
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_CELSIUS,
 | 
					    UNIT_CELSIUS,
 | 
				
			||||||
    UNIT_VOLT,
 | 
					    UNIT_VOLT,
 | 
				
			||||||
    CONF_TYPE,
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from .. import ads1118_ns, ADS1118, CONF_ADS1118_ID
 | 
					
 | 
				
			||||||
 | 
					from .. import ADS1118, CONF_ADS1118_ID, ads1118_ns
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AUTO_LOAD = ["voltage_sampler"]
 | 
					AUTO_LOAD = ["voltage_sampler"]
 | 
				
			||||||
DEPENDENCIES = ["ads1118"]
 | 
					DEPENDENCIES = ["ads1118"]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
#include "ags10.h"
 | 
					#include "ags10.h"
 | 
				
			||||||
 | 
					#include "esphome/core/helpers.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <cinttypes>
 | 
					#include <cinttypes>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,7 +24,7 @@ static const uint16_t ZP_CURRENT = 0x0000;
 | 
				
			|||||||
static const uint16_t ZP_DEFAULT = 0xFFFF;
 | 
					static const uint16_t ZP_DEFAULT = 0xFFFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void AGS10Component::setup() {
 | 
					void AGS10Component::setup() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up ags10...");
 | 
					  ESP_LOGCONFIG(TAG, "Running setup");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  auto version = this->read_version_();
 | 
					  auto version = this->read_version_();
 | 
				
			||||||
  if (version) {
 | 
					  if (version) {
 | 
				
			||||||
@@ -65,7 +66,7 @@ void AGS10Component::dump_config() {
 | 
				
			|||||||
    case NONE:
 | 
					    case NONE:
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case COMMUNICATION_FAILED:
 | 
					    case COMMUNICATION_FAILED:
 | 
				
			||||||
      ESP_LOGE(TAG, "Communication with AGS10 failed!");
 | 
					      ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case CRC_CHECK_FAILED:
 | 
					    case CRC_CHECK_FAILED:
 | 
				
			||||||
      ESP_LOGE(TAG, "The crc check failed");
 | 
					      ESP_LOGE(TAG, "The crc check failed");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,21 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					 | 
				
			||||||
from esphome import automation
 | 
					from esphome import automation
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.codegen as cg
 | 
				
			||||||
from esphome.components import i2c, sensor
 | 
					from esphome.components import i2c, sensor
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
 | 
					    CONF_ADDRESS,
 | 
				
			||||||
    CONF_ID,
 | 
					    CONF_ID,
 | 
				
			||||||
    ICON_RADIATOR,
 | 
					    CONF_MODE,
 | 
				
			||||||
    ICON_RESTART,
 | 
					    CONF_TVOC,
 | 
				
			||||||
 | 
					    CONF_VALUE,
 | 
				
			||||||
 | 
					    CONF_VERSION,
 | 
				
			||||||
    DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
 | 
					    DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
 | 
				
			||||||
    ENTITY_CATEGORY_DIAGNOSTIC,
 | 
					    ENTITY_CATEGORY_DIAGNOSTIC,
 | 
				
			||||||
 | 
					    ICON_RADIATOR,
 | 
				
			||||||
 | 
					    ICON_RESTART,
 | 
				
			||||||
    STATE_CLASS_MEASUREMENT,
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_OHM,
 | 
					    UNIT_OHM,
 | 
				
			||||||
    UNIT_PARTS_PER_BILLION,
 | 
					    UNIT_PARTS_PER_BILLION,
 | 
				
			||||||
    CONF_ADDRESS,
 | 
					 | 
				
			||||||
    CONF_TVOC,
 | 
					 | 
				
			||||||
    CONF_VERSION,
 | 
					 | 
				
			||||||
    CONF_MODE,
 | 
					 | 
				
			||||||
    CONF_VALUE,
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONF_RESISTANCE = "resistance"
 | 
					CONF_RESISTANCE = "resistance"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,8 +13,9 @@
 | 
				
			|||||||
// results making successive requests; the current implementation makes 3 attempts with a delay of 30ms each time.
 | 
					// results making successive requests; the current implementation makes 3 attempts with a delay of 30ms each time.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "aht10.h"
 | 
					#include "aht10.h"
 | 
				
			||||||
#include "esphome/core/log.h"
 | 
					 | 
				
			||||||
#include "esphome/core/hal.h"
 | 
					#include "esphome/core/hal.h"
 | 
				
			||||||
 | 
					#include "esphome/core/helpers.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace aht10 {
 | 
					namespace aht10 {
 | 
				
			||||||
@@ -34,57 +35,59 @@ static const uint8_t AHT10_INIT_ATTEMPTS = 10;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static const uint8_t AHT10_STATUS_BUSY = 0x80;
 | 
					static const uint8_t AHT10_STATUS_BUSY = 0x80;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const float AHT10_DIVISOR = 1048576.0f;  // 2^20, used for temperature and humidity calculations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void AHT10Component::setup() {
 | 
					void AHT10Component::setup() {
 | 
				
			||||||
 | 
					  ESP_LOGCONFIG(TAG, "Running setup");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (this->write(AHT10_SOFTRESET_CMD, sizeof(AHT10_SOFTRESET_CMD)) != i2c::ERROR_OK) {
 | 
					  if (this->write(AHT10_SOFTRESET_CMD, sizeof(AHT10_SOFTRESET_CMD)) != i2c::ERROR_OK) {
 | 
				
			||||||
    ESP_LOGE(TAG, "Reset AHT10 failed!");
 | 
					    ESP_LOGE(TAG, "Reset failed");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  delay(AHT10_SOFTRESET_DELAY);
 | 
					  delay(AHT10_SOFTRESET_DELAY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  i2c::ErrorCode error_code = i2c::ERROR_INVALID_ARGUMENT;
 | 
					  i2c::ErrorCode error_code = i2c::ERROR_INVALID_ARGUMENT;
 | 
				
			||||||
  switch (this->variant_) {
 | 
					  switch (this->variant_) {
 | 
				
			||||||
    case AHT10Variant::AHT20:
 | 
					    case AHT10Variant::AHT20:
 | 
				
			||||||
      ESP_LOGCONFIG(TAG, "Setting up AHT20");
 | 
					 | 
				
			||||||
      error_code = this->write(AHT20_INITIALIZE_CMD, sizeof(AHT20_INITIALIZE_CMD));
 | 
					      error_code = this->write(AHT20_INITIALIZE_CMD, sizeof(AHT20_INITIALIZE_CMD));
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case AHT10Variant::AHT10:
 | 
					    case AHT10Variant::AHT10:
 | 
				
			||||||
      ESP_LOGCONFIG(TAG, "Setting up AHT10");
 | 
					 | 
				
			||||||
      error_code = this->write(AHT10_INITIALIZE_CMD, sizeof(AHT10_INITIALIZE_CMD));
 | 
					      error_code = this->write(AHT10_INITIALIZE_CMD, sizeof(AHT10_INITIALIZE_CMD));
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (error_code != i2c::ERROR_OK) {
 | 
					  if (error_code != i2c::ERROR_OK) {
 | 
				
			||||||
    ESP_LOGE(TAG, "Communication with AHT10 failed!");
 | 
					    ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
 | 
				
			||||||
    this->mark_failed();
 | 
					    this->mark_failed();
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  uint8_t cal_attempts = 0;
 | 
				
			||||||
  uint8_t data = AHT10_STATUS_BUSY;
 | 
					  uint8_t data = AHT10_STATUS_BUSY;
 | 
				
			||||||
  int cal_attempts = 0;
 | 
					 | 
				
			||||||
  while (data & AHT10_STATUS_BUSY) {
 | 
					  while (data & AHT10_STATUS_BUSY) {
 | 
				
			||||||
    delay(AHT10_DEFAULT_DELAY);
 | 
					    delay(AHT10_DEFAULT_DELAY);
 | 
				
			||||||
    if (this->read(&data, 1) != i2c::ERROR_OK) {
 | 
					    if (this->read(&data, 1) != i2c::ERROR_OK) {
 | 
				
			||||||
      ESP_LOGE(TAG, "Communication with AHT10 failed!");
 | 
					      ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
 | 
				
			||||||
      this->mark_failed();
 | 
					      this->mark_failed();
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    ++cal_attempts;
 | 
					    ++cal_attempts;
 | 
				
			||||||
    if (cal_attempts > AHT10_INIT_ATTEMPTS) {
 | 
					    if (cal_attempts > AHT10_INIT_ATTEMPTS) {
 | 
				
			||||||
      ESP_LOGE(TAG, "AHT10 initialization timed out!");
 | 
					      ESP_LOGE(TAG, "Initialization timed out");
 | 
				
			||||||
      this->mark_failed();
 | 
					      this->mark_failed();
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if ((data & 0x68) != 0x08) {  // Bit[6:5] = 0b00, NORMAL mode and Bit[3] = 0b1, CALIBRATED
 | 
					  if ((data & 0x68) != 0x08) {  // Bit[6:5] = 0b00, NORMAL mode and Bit[3] = 0b1, CALIBRATED
 | 
				
			||||||
    ESP_LOGE(TAG, "AHT10 initialization failed!");
 | 
					    ESP_LOGE(TAG, "Initialization failed");
 | 
				
			||||||
    this->mark_failed();
 | 
					    this->mark_failed();
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ESP_LOGV(TAG, "AHT10 initialization");
 | 
					  ESP_LOGV(TAG, "Initialization complete");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void AHT10Component::restart_read_() {
 | 
					void AHT10Component::restart_read_() {
 | 
				
			||||||
  if (this->read_count_ == AHT10_ATTEMPTS) {
 | 
					  if (this->read_count_ == AHT10_ATTEMPTS) {
 | 
				
			||||||
    this->read_count_ = 0;
 | 
					    this->read_count_ = 0;
 | 
				
			||||||
    this->status_set_error("Measurements reading timed-out!");
 | 
					    this->status_set_error("Reading timed out");
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  this->read_count_++;
 | 
					  this->read_count_++;
 | 
				
			||||||
@@ -97,24 +100,24 @@ void AHT10Component::read_data_() {
 | 
				
			|||||||
    ESP_LOGD(TAG, "Read attempt %d at %ums", this->read_count_, (unsigned) (millis() - this->start_time_));
 | 
					    ESP_LOGD(TAG, "Read attempt %d at %ums", this->read_count_, (unsigned) (millis() - this->start_time_));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (this->read(data, 6) != i2c::ERROR_OK) {
 | 
					  if (this->read(data, 6) != i2c::ERROR_OK) {
 | 
				
			||||||
    this->status_set_warning("AHT10 read failed, retrying soon");
 | 
					    this->status_set_warning("Read failed, will retry");
 | 
				
			||||||
    this->restart_read_();
 | 
					    this->restart_read_();
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if ((data[0] & 0x80) == 0x80) {  // Bit[7] = 0b1, device is busy
 | 
					  if ((data[0] & 0x80) == 0x80) {  // Bit[7] = 0b1, device is busy
 | 
				
			||||||
    ESP_LOGD(TAG, "AHT10 is busy, waiting...");
 | 
					    ESP_LOGD(TAG, "Device busy, will retry");
 | 
				
			||||||
    this->restart_read_();
 | 
					    this->restart_read_();
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (data[1] == 0x0 && data[2] == 0x0 && (data[3] >> 4) == 0x0) {
 | 
					  if (data[1] == 0x0 && data[2] == 0x0 && (data[3] >> 4) == 0x0) {
 | 
				
			||||||
    // Unrealistic humidity (0x0)
 | 
					    // Invalid humidity (0x0)
 | 
				
			||||||
    if (this->humidity_sensor_ == nullptr) {
 | 
					    if (this->humidity_sensor_ == nullptr) {
 | 
				
			||||||
      ESP_LOGV(TAG, "ATH10 Unrealistic humidity (0x0), but humidity is not required");
 | 
					      ESP_LOGV(TAG, "Invalid humidity (reading not required)");
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      ESP_LOGD(TAG, "ATH10 Unrealistic humidity (0x0), retrying...");
 | 
					      ESP_LOGD(TAG, "Invalid humidity, retrying");
 | 
				
			||||||
      if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) {
 | 
					      if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) {
 | 
				
			||||||
        this->status_set_warning("Communication with AHT10 failed!");
 | 
					        this->status_set_warning(ESP_LOG_MSG_COMM_FAIL);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      this->restart_read_();
 | 
					      this->restart_read_();
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
@@ -123,22 +126,17 @@ void AHT10Component::read_data_() {
 | 
				
			|||||||
  if (this->read_count_ > 1) {
 | 
					  if (this->read_count_ > 1) {
 | 
				
			||||||
    ESP_LOGD(TAG, "Success at %ums", (unsigned) (millis() - this->start_time_));
 | 
					    ESP_LOGD(TAG, "Success at %ums", (unsigned) (millis() - this->start_time_));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  uint32_t raw_temperature = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5];
 | 
					  uint32_t raw_temperature = encode_uint24(data[3] & 0xF, data[4], data[5]);
 | 
				
			||||||
  uint32_t raw_humidity = ((data[1] << 16) | (data[2] << 8) | data[3]) >> 4;
 | 
					  uint32_t raw_humidity = encode_uint24(data[1], data[2], data[3]) >> 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (this->temperature_sensor_ != nullptr) {
 | 
					  if (this->temperature_sensor_ != nullptr) {
 | 
				
			||||||
    float temperature = ((200.0f * (float) raw_temperature) / 1048576.0f) - 50.0f;
 | 
					    float temperature = ((200.0f * static_cast<float>(raw_temperature)) / AHT10_DIVISOR) - 50.0f;
 | 
				
			||||||
    this->temperature_sensor_->publish_state(temperature);
 | 
					    this->temperature_sensor_->publish_state(temperature);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (this->humidity_sensor_ != nullptr) {
 | 
					  if (this->humidity_sensor_ != nullptr) {
 | 
				
			||||||
    float humidity;
 | 
					    float humidity = raw_humidity == 0 ? NAN : static_cast<float>(raw_humidity) * 100.0f / AHT10_DIVISOR;
 | 
				
			||||||
    if (raw_humidity == 0) {  // unrealistic value
 | 
					 | 
				
			||||||
      humidity = NAN;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      humidity = (float) raw_humidity * 100.0f / 1048576.0f;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (std::isnan(humidity)) {
 | 
					    if (std::isnan(humidity)) {
 | 
				
			||||||
      ESP_LOGW(TAG, "Invalid humidity! Sensor reported 0%% Hum");
 | 
					      ESP_LOGW(TAG, "Invalid humidity reading (0%%), ");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this->humidity_sensor_->publish_state(humidity);
 | 
					    this->humidity_sensor_->publish_state(humidity);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -150,7 +148,7 @@ void AHT10Component::update() {
 | 
				
			|||||||
    return;
 | 
					    return;
 | 
				
			||||||
  this->start_time_ = millis();
 | 
					  this->start_time_ = millis();
 | 
				
			||||||
  if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) {
 | 
					  if (this->write(AHT10_MEASURE_CMD, sizeof(AHT10_MEASURE_CMD)) != i2c::ERROR_OK) {
 | 
				
			||||||
    this->status_set_warning("Communication with AHT10 failed!");
 | 
					    this->status_set_warning(ESP_LOG_MSG_COMM_FAIL);
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  this->restart_read_();
 | 
					  this->restart_read_();
 | 
				
			||||||
@@ -162,7 +160,7 @@ void AHT10Component::dump_config() {
 | 
				
			|||||||
  ESP_LOGCONFIG(TAG, "AHT10:");
 | 
					  ESP_LOGCONFIG(TAG, "AHT10:");
 | 
				
			||||||
  LOG_I2C_DEVICE(this);
 | 
					  LOG_I2C_DEVICE(this);
 | 
				
			||||||
  if (this->is_failed()) {
 | 
					  if (this->is_failed()) {
 | 
				
			||||||
    ESP_LOGE(TAG, "Communication with AHT10 failed!");
 | 
					    ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  LOG_SENSOR("  ", "Temperature", this->temperature_sensor_);
 | 
					  LOG_SENSOR("  ", "Temperature", this->temperature_sensor_);
 | 
				
			||||||
  LOG_SENSOR("  ", "Humidity", this->humidity_sensor_);
 | 
					  LOG_SENSOR("  ", "Humidity", this->humidity_sensor_);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,16 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import i2c, sensor
 | 
					from esphome.components import i2c, sensor
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_HUMIDITY,
 | 
					    CONF_HUMIDITY,
 | 
				
			||||||
    CONF_ID,
 | 
					    CONF_ID,
 | 
				
			||||||
    CONF_TEMPERATURE,
 | 
					    CONF_TEMPERATURE,
 | 
				
			||||||
 | 
					    CONF_VARIANT,
 | 
				
			||||||
    DEVICE_CLASS_HUMIDITY,
 | 
					    DEVICE_CLASS_HUMIDITY,
 | 
				
			||||||
    DEVICE_CLASS_TEMPERATURE,
 | 
					    DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
    STATE_CLASS_MEASUREMENT,
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_CELSIUS,
 | 
					    UNIT_CELSIUS,
 | 
				
			||||||
    UNIT_PERCENT,
 | 
					    UNIT_PERCENT,
 | 
				
			||||||
    CONF_VARIANT,
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEPENDENCIES = ["i2c"]
 | 
					DEPENDENCIES = ["i2c"]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@ static const char *const TAG = "aic3204";
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void AIC3204::setup() {
 | 
					void AIC3204::setup() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up AIC3204...");
 | 
					  ESP_LOGCONFIG(TAG, "Running setup");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Set register page to 0
 | 
					  // Set register page to 0
 | 
				
			||||||
  ERROR_CHECK(this->write_byte(AIC3204_PAGE_CTRL, 0x00), "Set page 0 failed");
 | 
					  ERROR_CHECK(this->write_byte(AIC3204_PAGE_CTRL, 0x00), "Set page 0 failed");
 | 
				
			||||||
@@ -113,7 +113,7 @@ void AIC3204::dump_config() {
 | 
				
			|||||||
  LOG_I2C_DEVICE(this);
 | 
					  LOG_I2C_DEVICE(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (this->is_failed()) {
 | 
					  if (this->is_failed()) {
 | 
				
			||||||
    ESP_LOGE(TAG, "Communication with AIC3204 failed");
 | 
					    ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import esp32_ble_tracker
 | 
					from esphome.components import esp32_ble_tracker
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import CONF_ID
 | 
					from esphome.const import CONF_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEPENDENCIES = ["esp32_ble_tracker"]
 | 
					DEPENDENCIES = ["esp32_ble_tracker"]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,17 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					from esphome.components import ble_client, sensor
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.components import sensor, ble_client
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_BATTERY_VOLTAGE,
 | 
					    CONF_BATTERY_VOLTAGE,
 | 
				
			||||||
    CONF_HUMIDITY,
 | 
					    CONF_HUMIDITY,
 | 
				
			||||||
    CONF_PRESSURE,
 | 
					    CONF_PRESSURE,
 | 
				
			||||||
    CONF_TEMPERATURE,
 | 
					    CONF_TEMPERATURE,
 | 
				
			||||||
    CONF_TVOC,
 | 
					    CONF_TVOC,
 | 
				
			||||||
    DEVICE_CLASS_VOLTAGE,
 | 
					 | 
				
			||||||
    DEVICE_CLASS_HUMIDITY,
 | 
					    DEVICE_CLASS_HUMIDITY,
 | 
				
			||||||
    DEVICE_CLASS_PRESSURE,
 | 
					    DEVICE_CLASS_PRESSURE,
 | 
				
			||||||
    DEVICE_CLASS_TEMPERATURE,
 | 
					    DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
    DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
 | 
					    DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS_PARTS,
 | 
				
			||||||
 | 
					    DEVICE_CLASS_VOLTAGE,
 | 
				
			||||||
    ENTITY_CATEGORY_DIAGNOSTIC,
 | 
					    ENTITY_CATEGORY_DIAGNOSTIC,
 | 
				
			||||||
    STATE_CLASS_MEASUREMENT,
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_CELSIUS,
 | 
					    UNIT_CELSIUS,
 | 
				
			||||||
@@ -35,7 +34,7 @@ AirthingsWaveBase = airthings_wave_base_ns.class_(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BASE_SCHEMA = (
 | 
					BASE_SCHEMA = (
 | 
				
			||||||
    sensor.SENSOR_SCHEMA.extend(
 | 
					    cv.Schema(
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
 | 
				
			||||||
                unit_of_measurement=UNIT_PERCENT,
 | 
					                unit_of_measurement=UNIT_PERCENT,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,7 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import airthings_wave_base
 | 
					from esphome.components import airthings_wave_base
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import CONF_ID
 | 
				
			||||||
    CONF_ID,
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEPENDENCIES = airthings_wave_base.DEPENDENCIES
 | 
					DEPENDENCIES = airthings_wave_base.DEPENDENCIES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,20 +1,19 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					from esphome.components import airthings_wave_base, sensor
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.components import sensor, airthings_wave_base
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    DEVICE_CLASS_CARBON_DIOXIDE,
 | 
					    CONF_CO2,
 | 
				
			||||||
    STATE_CLASS_MEASUREMENT,
 | 
					 | 
				
			||||||
    ICON_RADIOACTIVE,
 | 
					 | 
				
			||||||
    CONF_ID,
 | 
					    CONF_ID,
 | 
				
			||||||
 | 
					    CONF_ILLUMINANCE,
 | 
				
			||||||
    CONF_RADON,
 | 
					    CONF_RADON,
 | 
				
			||||||
    CONF_RADON_LONG_TERM,
 | 
					    CONF_RADON_LONG_TERM,
 | 
				
			||||||
    CONF_CO2,
 | 
					    DEVICE_CLASS_CARBON_DIOXIDE,
 | 
				
			||||||
    UNIT_BECQUEREL_PER_CUBIC_METER,
 | 
					 | 
				
			||||||
    UNIT_PARTS_PER_MILLION,
 | 
					 | 
				
			||||||
    CONF_ILLUMINANCE,
 | 
					 | 
				
			||||||
    UNIT_LUX,
 | 
					 | 
				
			||||||
    DEVICE_CLASS_ILLUMINANCE,
 | 
					    DEVICE_CLASS_ILLUMINANCE,
 | 
				
			||||||
 | 
					    ICON_RADIOACTIVE,
 | 
				
			||||||
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					    UNIT_BECQUEREL_PER_CUBIC_METER,
 | 
				
			||||||
 | 
					    UNIT_LUX,
 | 
				
			||||||
 | 
					    UNIT_PARTS_PER_MILLION,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEPENDENCIES = airthings_wave_base.DEPENDENCIES
 | 
					DEPENDENCIES = airthings_wave_base.DEPENDENCIES
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,8 @@ from esphome.components import mqtt, web_server
 | 
				
			|||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_CODE,
 | 
					    CONF_CODE,
 | 
				
			||||||
 | 
					    CONF_ENTITY_CATEGORY,
 | 
				
			||||||
 | 
					    CONF_ICON,
 | 
				
			||||||
    CONF_ID,
 | 
					    CONF_ID,
 | 
				
			||||||
    CONF_MQTT_ID,
 | 
					    CONF_MQTT_ID,
 | 
				
			||||||
    CONF_ON_STATE,
 | 
					    CONF_ON_STATE,
 | 
				
			||||||
@@ -12,6 +14,7 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_WEB_SERVER,
 | 
					    CONF_WEB_SERVER,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from esphome.core import CORE, coroutine_with_priority
 | 
					from esphome.core import CORE, coroutine_with_priority
 | 
				
			||||||
 | 
					from esphome.cpp_generator import MockObjClass
 | 
				
			||||||
from esphome.cpp_helpers import setup_entity
 | 
					from esphome.cpp_helpers import setup_entity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CODEOWNERS = ["@grahambrown11", "@hwstar"]
 | 
					CODEOWNERS = ["@grahambrown11", "@hwstar"]
 | 
				
			||||||
@@ -78,12 +81,11 @@ AlarmControlPanelCondition = alarm_control_panel_ns.class_(
 | 
				
			|||||||
    "AlarmControlPanelCondition", automation.Condition
 | 
					    "AlarmControlPanelCondition", automation.Condition
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ALARM_CONTROL_PANEL_SCHEMA = (
 | 
					_ALARM_CONTROL_PANEL_SCHEMA = (
 | 
				
			||||||
    cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
 | 
					    cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
 | 
				
			||||||
    .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
 | 
					    .extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
 | 
				
			||||||
    .extend(
 | 
					    .extend(
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            cv.GenerateID(): cv.declare_id(AlarmControlPanel),
 | 
					 | 
				
			||||||
            cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(
 | 
					            cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(
 | 
				
			||||||
                mqtt.MQTTAlarmControlPanelComponent
 | 
					                mqtt.MQTTAlarmControlPanelComponent
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
@@ -146,6 +148,33 @@ ALARM_CONTROL_PANEL_SCHEMA = (
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def alarm_control_panel_schema(
 | 
				
			||||||
 | 
					    class_: MockObjClass,
 | 
				
			||||||
 | 
					    *,
 | 
				
			||||||
 | 
					    entity_category: str = cv.UNDEFINED,
 | 
				
			||||||
 | 
					    icon: str = cv.UNDEFINED,
 | 
				
			||||||
 | 
					) -> cv.Schema:
 | 
				
			||||||
 | 
					    schema = {
 | 
				
			||||||
 | 
					        cv.GenerateID(): cv.declare_id(class_),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for key, default, validator in [
 | 
				
			||||||
 | 
					        (CONF_ENTITY_CATEGORY, entity_category, cv.entity_category),
 | 
				
			||||||
 | 
					        (CONF_ICON, icon, cv.icon),
 | 
				
			||||||
 | 
					    ]:
 | 
				
			||||||
 | 
					        if default is not cv.UNDEFINED:
 | 
				
			||||||
 | 
					            schema[cv.Optional(key, default=default)] = validator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return _ALARM_CONTROL_PANEL_SCHEMA.extend(schema)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Remove before 2025.11.0
 | 
				
			||||||
 | 
					ALARM_CONTROL_PANEL_SCHEMA = alarm_control_panel_schema(AlarmControlPanel)
 | 
				
			||||||
 | 
					ALARM_CONTROL_PANEL_SCHEMA.add_extra(
 | 
				
			||||||
 | 
					    cv.deprecated_schema_constant("alarm_control_panel")
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ALARM_CONTROL_PANEL_ACTION_SCHEMA = maybe_simple_id(
 | 
					ALARM_CONTROL_PANEL_ACTION_SCHEMA = maybe_simple_id(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        cv.GenerateID(): cv.use_id(AlarmControlPanel),
 | 
					        cv.GenerateID(): cv.use_id(AlarmControlPanel),
 | 
				
			||||||
@@ -206,9 +235,16 @@ async def register_alarm_control_panel(var, config):
 | 
				
			|||||||
    if not CORE.has_id(config[CONF_ID]):
 | 
					    if not CORE.has_id(config[CONF_ID]):
 | 
				
			||||||
        var = cg.Pvariable(config[CONF_ID], var)
 | 
					        var = cg.Pvariable(config[CONF_ID], var)
 | 
				
			||||||
    cg.add(cg.App.register_alarm_control_panel(var))
 | 
					    cg.add(cg.App.register_alarm_control_panel(var))
 | 
				
			||||||
 | 
					    CORE.register_platform_component("alarm_control_panel", var)
 | 
				
			||||||
    await setup_alarm_control_panel_core_(var, config)
 | 
					    await setup_alarm_control_panel_core_(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def new_alarm_control_panel(config, *args):
 | 
				
			||||||
 | 
					    var = cg.new_Pvariable(config[CONF_ID], *args)
 | 
				
			||||||
 | 
					    await register_alarm_control_panel(var, config)
 | 
				
			||||||
 | 
					    return var
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@automation.register_action(
 | 
					@automation.register_action(
 | 
				
			||||||
    "alarm_control_panel.arm_away", ArmAwayAction, ALARM_CONTROL_PANEL_ACTION_SCHEMA
 | 
					    "alarm_control_panel.arm_away", ArmAwayAction, ALARM_CONTROL_PANEL_ACTION_SCHEMA
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -72,10 +72,9 @@ void AlarmControlPanelCall::validate_() {
 | 
				
			|||||||
      this->state_.reset();
 | 
					      this->state_.reset();
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (state == ACP_STATE_DISARMED &&
 | 
					    if (state == ACP_STATE_DISARMED && !this->parent_->is_state_armed(this->parent_->get_state()) &&
 | 
				
			||||||
        !(this->parent_->is_state_armed(this->parent_->get_state()) ||
 | 
					        this->parent_->get_state() != ACP_STATE_PENDING && this->parent_->get_state() != ACP_STATE_ARMING &&
 | 
				
			||||||
          this->parent_->get_state() == ACP_STATE_PENDING || this->parent_->get_state() == ACP_STATE_ARMING ||
 | 
					        this->parent_->get_state() != ACP_STATE_TRIGGERED) {
 | 
				
			||||||
          this->parent_->get_state() == ACP_STATE_TRIGGERED)) {
 | 
					 | 
				
			||||||
      ESP_LOGW(TAG, "Cannot disarm when not armed");
 | 
					      ESP_LOGW(TAG, "Cannot disarm when not armed");
 | 
				
			||||||
      this->state_.reset();
 | 
					      this->state_.reset();
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,20 +1,20 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					from esphome.components import ble_client, sensor
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.components import sensor, ble_client
 | 
					 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_ID,
 | 
					 | 
				
			||||||
    CONF_CURRENT,
 | 
					    CONF_CURRENT,
 | 
				
			||||||
    CONF_FLOW,
 | 
					    CONF_FLOW,
 | 
				
			||||||
    CONF_HEAD,
 | 
					    CONF_HEAD,
 | 
				
			||||||
 | 
					    CONF_ID,
 | 
				
			||||||
    CONF_POWER,
 | 
					    CONF_POWER,
 | 
				
			||||||
    CONF_SPEED,
 | 
					    CONF_SPEED,
 | 
				
			||||||
    CONF_VOLTAGE,
 | 
					    CONF_VOLTAGE,
 | 
				
			||||||
    UNIT_AMPERE,
 | 
					    UNIT_AMPERE,
 | 
				
			||||||
 | 
					    UNIT_CUBIC_METER_PER_HOUR,
 | 
				
			||||||
 | 
					    UNIT_METER,
 | 
				
			||||||
 | 
					    UNIT_REVOLUTIONS_PER_MINUTE,
 | 
				
			||||||
    UNIT_VOLT,
 | 
					    UNIT_VOLT,
 | 
				
			||||||
    UNIT_WATT,
 | 
					    UNIT_WATT,
 | 
				
			||||||
    UNIT_METER,
 | 
					 | 
				
			||||||
    UNIT_CUBIC_METER_PER_HOUR,
 | 
					 | 
				
			||||||
    UNIT_REVOLUTIONS_PER_MINUTE,
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
alpha3_ns = cg.esphome_ns.namespace("alpha3")
 | 
					alpha3_ns = cg.esphome_ns.namespace("alpha3")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -90,7 +90,7 @@ bool AM2315C::convert_(uint8_t *data, float &humidity, float &temperature) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void AM2315C::setup() {
 | 
					void AM2315C::setup() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up AM2315C...");
 | 
					  ESP_LOGCONFIG(TAG, "Running setup");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // get status
 | 
					  // get status
 | 
				
			||||||
  uint8_t status = 0;
 | 
					  uint8_t status = 0;
 | 
				
			||||||
@@ -128,7 +128,7 @@ void AM2315C::update() {
 | 
				
			|||||||
  data[2] = 0x00;
 | 
					  data[2] = 0x00;
 | 
				
			||||||
  if (this->write(data, 3) != i2c::ERROR_OK) {
 | 
					  if (this->write(data, 3) != i2c::ERROR_OK) {
 | 
				
			||||||
    ESP_LOGE(TAG, "Write failed!");
 | 
					    ESP_LOGE(TAG, "Write failed!");
 | 
				
			||||||
    this->mark_failed();
 | 
					    this->status_set_warning();
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -138,12 +138,12 @@ void AM2315C::update() {
 | 
				
			|||||||
    uint8_t status = 0;
 | 
					    uint8_t status = 0;
 | 
				
			||||||
    if (this->read(&status, 1) != i2c::ERROR_OK) {
 | 
					    if (this->read(&status, 1) != i2c::ERROR_OK) {
 | 
				
			||||||
      ESP_LOGE(TAG, "Read failed!");
 | 
					      ESP_LOGE(TAG, "Read failed!");
 | 
				
			||||||
      this->mark_failed();
 | 
					      this->status_set_warning();
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if ((status & 0x80) == 0x80) {
 | 
					    if ((status & 0x80) == 0x80) {
 | 
				
			||||||
      ESP_LOGE(TAG, "HW still busy!");
 | 
					      ESP_LOGE(TAG, "HW still busy!");
 | 
				
			||||||
      this->mark_failed();
 | 
					      this->status_set_warning();
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -151,7 +151,7 @@ void AM2315C::update() {
 | 
				
			|||||||
    uint8_t data[7];
 | 
					    uint8_t data[7];
 | 
				
			||||||
    if (this->read(data, 7) != i2c::ERROR_OK) {
 | 
					    if (this->read(data, 7) != i2c::ERROR_OK) {
 | 
				
			||||||
      ESP_LOGE(TAG, "Read failed!");
 | 
					      ESP_LOGE(TAG, "Read failed!");
 | 
				
			||||||
      this->mark_failed();
 | 
					      this->status_set_warning();
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -188,7 +188,7 @@ void AM2315C::dump_config() {
 | 
				
			|||||||
  ESP_LOGCONFIG(TAG, "AM2315C:");
 | 
					  ESP_LOGCONFIG(TAG, "AM2315C:");
 | 
				
			||||||
  LOG_I2C_DEVICE(this);
 | 
					  LOG_I2C_DEVICE(this);
 | 
				
			||||||
  if (this->is_failed()) {
 | 
					  if (this->is_failed()) {
 | 
				
			||||||
    ESP_LOGE(TAG, "Communication with AM2315C failed!");
 | 
					    ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  LOG_SENSOR("  ", "Temperature", this->temperature_sensor_);
 | 
					  LOG_SENSOR("  ", "Temperature", this->temperature_sensor_);
 | 
				
			||||||
  LOG_SENSOR("  ", "Humidity", this->humidity_sensor_);
 | 
					  LOG_SENSOR("  ", "Humidity", this->humidity_sensor_);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import i2c, sensor
 | 
					from esphome.components import i2c, sensor
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_HUMIDITY,
 | 
					    CONF_HUMIDITY,
 | 
				
			||||||
    CONF_ID,
 | 
					    CONF_ID,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,7 @@ void AM2320Component::update() {
 | 
				
			|||||||
  this->status_clear_warning();
 | 
					  this->status_clear_warning();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void AM2320Component::setup() {
 | 
					void AM2320Component::setup() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up AM2320...");
 | 
					  ESP_LOGCONFIG(TAG, "Running setup");
 | 
				
			||||||
  uint8_t data[8];
 | 
					  uint8_t data[8];
 | 
				
			||||||
  data[0] = 0;
 | 
					  data[0] = 0;
 | 
				
			||||||
  data[1] = 4;
 | 
					  data[1] = 4;
 | 
				
			||||||
@@ -47,7 +47,7 @@ void AM2320Component::dump_config() {
 | 
				
			|||||||
  ESP_LOGD(TAG, "AM2320:");
 | 
					  ESP_LOGD(TAG, "AM2320:");
 | 
				
			||||||
  LOG_I2C_DEVICE(this);
 | 
					  LOG_I2C_DEVICE(this);
 | 
				
			||||||
  if (this->is_failed()) {
 | 
					  if (this->is_failed()) {
 | 
				
			||||||
    ESP_LOGE(TAG, "Communication with AM2320 failed!");
 | 
					    ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  LOG_SENSOR("  ", "Temperature", this->temperature_sensor_);
 | 
					  LOG_SENSOR("  ", "Temperature", this->temperature_sensor_);
 | 
				
			||||||
  LOG_SENSOR("  ", "Humidity", this->humidity_sensor_);
 | 
					  LOG_SENSOR("  ", "Humidity", this->humidity_sensor_);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import i2c, sensor
 | 
					from esphome.components import i2c, sensor
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_HUMIDITY,
 | 
					    CONF_HUMIDITY,
 | 
				
			||||||
    CONF_ID,
 | 
					    CONF_ID,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "esphome/core/log.h"
 | 
					 | 
				
			||||||
#include "esphome/core/helpers.h"
 | 
					#include "esphome/core/helpers.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace am43 {
 | 
					namespace am43 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					from esphome.components import ble_client, cover
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.components import cover, ble_client
 | 
					from esphome.const import CONF_PIN
 | 
				
			||||||
from esphome.const import CONF_ID, CONF_PIN
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
CODEOWNERS = ["@buxtronix"]
 | 
					CODEOWNERS = ["@buxtronix"]
 | 
				
			||||||
DEPENDENCIES = ["ble_client"]
 | 
					DEPENDENCIES = ["ble_client"]
 | 
				
			||||||
@@ -15,9 +15,9 @@ Am43Component = am43_ns.class_(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONFIG_SCHEMA = (
 | 
					CONFIG_SCHEMA = (
 | 
				
			||||||
    cover.COVER_SCHEMA.extend(
 | 
					    cover.cover_schema(Am43Component)
 | 
				
			||||||
 | 
					    .extend(
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            cv.GenerateID(): cv.declare_id(Am43Component),
 | 
					 | 
				
			||||||
            cv.Optional(CONF_PIN, default=8888): cv.int_range(min=0, max=0xFFFF),
 | 
					            cv.Optional(CONF_PIN, default=8888): cv.int_range(min=0, max=0xFFFF),
 | 
				
			||||||
            cv.Optional(CONF_INVERT_POSITION, default=False): cv.boolean,
 | 
					            cv.Optional(CONF_INVERT_POSITION, default=False): cv.boolean,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -28,9 +28,8 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = await cover.new_cover(config)
 | 
				
			||||||
    cg.add(var.set_pin(config[CONF_PIN]))
 | 
					    cg.add(var.set_pin(config[CONF_PIN]))
 | 
				
			||||||
    cg.add(var.set_invert_position(config[CONF_INVERT_POSITION]))
 | 
					    cg.add(var.set_invert_position(config[CONF_INVERT_POSITION]))
 | 
				
			||||||
    await cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    await cover.register_cover(var, config)
 | 
					 | 
				
			||||||
    await ble_client.register_ble_node(var, config)
 | 
					    await ble_client.register_ble_node(var, config)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,8 +12,10 @@ using namespace esphome::cover;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void Am43Component::dump_config() {
 | 
					void Am43Component::dump_config() {
 | 
				
			||||||
  LOG_COVER("", "AM43 Cover", this);
 | 
					  LOG_COVER("", "AM43 Cover", this);
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  Device Pin: %d", this->pin_);
 | 
					  ESP_LOGCONFIG(TAG,
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  Invert Position: %d", (int) this->invert_position_);
 | 
					                "  Device Pin: %d\n"
 | 
				
			||||||
 | 
					                "  Invert Position: %d",
 | 
				
			||||||
 | 
					                this->pin_, (int) this->invert_position_);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Am43Component::setup() {
 | 
					void Am43Component::setup() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,12 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					from esphome.components import ble_client, sensor
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.components import sensor, ble_client
 | 
					 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_ID,
 | 
					 | 
				
			||||||
    CONF_BATTERY_LEVEL,
 | 
					    CONF_BATTERY_LEVEL,
 | 
				
			||||||
 | 
					    CONF_ID,
 | 
				
			||||||
 | 
					    CONF_ILLUMINANCE,
 | 
				
			||||||
    DEVICE_CLASS_BATTERY,
 | 
					    DEVICE_CLASS_BATTERY,
 | 
				
			||||||
    ENTITY_CATEGORY_DIAGNOSTIC,
 | 
					    ENTITY_CATEGORY_DIAGNOSTIC,
 | 
				
			||||||
    CONF_ILLUMINANCE,
 | 
					 | 
				
			||||||
    ICON_BRIGHTNESS_5,
 | 
					    ICON_BRIGHTNESS_5,
 | 
				
			||||||
    UNIT_PERCENT,
 | 
					    UNIT_PERCENT,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,8 @@ void AnalogThresholdBinarySensor::setup() {
 | 
				
			|||||||
  if (std::isnan(sensor_value)) {
 | 
					  if (std::isnan(sensor_value)) {
 | 
				
			||||||
    this->publish_initial_state(false);
 | 
					    this->publish_initial_state(false);
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    this->publish_initial_state(sensor_value >= (this->lower_threshold_ + this->upper_threshold_) / 2.0f);
 | 
					    this->publish_initial_state(sensor_value >=
 | 
				
			||||||
 | 
					                                (this->lower_threshold_.value() + this->upper_threshold_.value()) / 2.0f);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,7 +25,8 @@ void AnalogThresholdBinarySensor::set_sensor(sensor::Sensor *analog_sensor) {
 | 
				
			|||||||
  this->sensor_->add_on_state_callback([this](float sensor_value) {
 | 
					  this->sensor_->add_on_state_callback([this](float sensor_value) {
 | 
				
			||||||
    // if there is an invalid sensor reading, ignore the change and keep the current state
 | 
					    // if there is an invalid sensor reading, ignore the change and keep the current state
 | 
				
			||||||
    if (!std::isnan(sensor_value)) {
 | 
					    if (!std::isnan(sensor_value)) {
 | 
				
			||||||
      this->publish_state(sensor_value >= (this->state ? this->lower_threshold_ : this->upper_threshold_));
 | 
					      this->publish_state(sensor_value >=
 | 
				
			||||||
 | 
					                          (this->state ? this->lower_threshold_.value() : this->upper_threshold_.value()));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -32,8 +34,10 @@ void AnalogThresholdBinarySensor::set_sensor(sensor::Sensor *analog_sensor) {
 | 
				
			|||||||
void AnalogThresholdBinarySensor::dump_config() {
 | 
					void AnalogThresholdBinarySensor::dump_config() {
 | 
				
			||||||
  LOG_BINARY_SENSOR("", "Analog Threshold Binary Sensor", this);
 | 
					  LOG_BINARY_SENSOR("", "Analog Threshold Binary Sensor", this);
 | 
				
			||||||
  LOG_SENSOR("  ", "Sensor", this->sensor_);
 | 
					  LOG_SENSOR("  ", "Sensor", this->sensor_);
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  Upper threshold: %.11f", this->upper_threshold_);
 | 
					  ESP_LOGCONFIG(TAG,
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  Lower threshold: %.11f", this->lower_threshold_);
 | 
					                "  Upper threshold: %.11f\n"
 | 
				
			||||||
 | 
					                "  Lower threshold: %.11f",
 | 
				
			||||||
 | 
					                this->upper_threshold_.value(), this->lower_threshold_.value());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace analog_threshold
 | 
					}  // namespace analog_threshold
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,14 +15,13 @@ class AnalogThresholdBinarySensor : public Component, public binary_sensor::Bina
 | 
				
			|||||||
  float get_setup_priority() const override { return setup_priority::DATA; }
 | 
					  float get_setup_priority() const override { return setup_priority::DATA; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void set_sensor(sensor::Sensor *analog_sensor);
 | 
					  void set_sensor(sensor::Sensor *analog_sensor);
 | 
				
			||||||
  void set_upper_threshold(float threshold) { this->upper_threshold_ = threshold; }
 | 
					  template<typename T> void set_upper_threshold(T upper_threshold) { this->upper_threshold_ = upper_threshold; }
 | 
				
			||||||
  void set_lower_threshold(float threshold) { this->lower_threshold_ = threshold; }
 | 
					  template<typename T> void set_lower_threshold(T lower_threshold) { this->lower_threshold_ = lower_threshold; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
  sensor::Sensor *sensor_{nullptr};
 | 
					  sensor::Sensor *sensor_{nullptr};
 | 
				
			||||||
 | 
					  TemplatableValue<float> upper_threshold_{};
 | 
				
			||||||
  float upper_threshold_;
 | 
					  TemplatableValue<float> lower_threshold_{};
 | 
				
			||||||
  float lower_threshold_;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace analog_threshold
 | 
					}  // namespace analog_threshold
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,7 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import binary_sensor, sensor
 | 
					from esphome.components import binary_sensor, sensor
 | 
				
			||||||
from esphome.const import (
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
    CONF_SENSOR_ID,
 | 
					from esphome.const import CONF_SENSOR_ID, CONF_THRESHOLD
 | 
				
			||||||
    CONF_THRESHOLD,
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
analog_threshold_ns = cg.esphome_ns.namespace("analog_threshold")
 | 
					analog_threshold_ns = cg.esphome_ns.namespace("analog_threshold")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -21,11 +18,11 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            cv.Required(CONF_SENSOR_ID): cv.use_id(sensor.Sensor),
 | 
					            cv.Required(CONF_SENSOR_ID): cv.use_id(sensor.Sensor),
 | 
				
			||||||
            cv.Required(CONF_THRESHOLD): cv.Any(
 | 
					            cv.Required(CONF_THRESHOLD): cv.Any(
 | 
				
			||||||
                cv.float_,
 | 
					                cv.templatable(cv.float_),
 | 
				
			||||||
                cv.Schema(
 | 
					                cv.Schema(
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        cv.Required(CONF_UPPER): cv.float_,
 | 
					                        cv.Required(CONF_UPPER): cv.templatable(cv.float_),
 | 
				
			||||||
                        cv.Required(CONF_LOWER): cv.float_,
 | 
					                        cv.Required(CONF_LOWER): cv.templatable(cv.float_),
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
@@ -42,9 +39,11 @@ async def to_code(config):
 | 
				
			|||||||
    sens = await cg.get_variable(config[CONF_SENSOR_ID])
 | 
					    sens = await cg.get_variable(config[CONF_SENSOR_ID])
 | 
				
			||||||
    cg.add(var.set_sensor(sens))
 | 
					    cg.add(var.set_sensor(sens))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if isinstance(config[CONF_THRESHOLD], float):
 | 
					    if isinstance(config[CONF_THRESHOLD], dict):
 | 
				
			||||||
        cg.add(var.set_upper_threshold(config[CONF_THRESHOLD]))
 | 
					        lower = await cg.templatable(config[CONF_THRESHOLD][CONF_LOWER], [], float)
 | 
				
			||||||
        cg.add(var.set_lower_threshold(config[CONF_THRESHOLD]))
 | 
					        upper = await cg.templatable(config[CONF_THRESHOLD][CONF_UPPER], [], float)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        cg.add(var.set_upper_threshold(config[CONF_THRESHOLD][CONF_UPPER]))
 | 
					        lower = await cg.templatable(config[CONF_THRESHOLD], [], float)
 | 
				
			||||||
        cg.add(var.set_lower_threshold(config[CONF_THRESHOLD][CONF_LOWER]))
 | 
					        upper = lower
 | 
				
			||||||
 | 
					    cg.add(var.set_upper_threshold(upper))
 | 
				
			||||||
 | 
					    cg.add(var.set_lower_threshold(lower))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,29 +1,10 @@
 | 
				
			|||||||
import logging
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from esphome import automation, core
 | 
					from esphome import automation
 | 
				
			||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
from esphome.components import font
 | 
					 | 
				
			||||||
import esphome.components.image as espImage
 | 
					import esphome.components.image as espImage
 | 
				
			||||||
from esphome.components.image import (
 | 
					 | 
				
			||||||
    CONF_USE_TRANSPARENCY,
 | 
					 | 
				
			||||||
    LOCAL_SCHEMA,
 | 
					 | 
				
			||||||
    SOURCE_LOCAL,
 | 
					 | 
				
			||||||
    SOURCE_WEB,
 | 
					 | 
				
			||||||
    WEB_SCHEMA,
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import CONF_ID, CONF_REPEAT
 | 
				
			||||||
    CONF_FILE,
 | 
					 | 
				
			||||||
    CONF_ID,
 | 
					 | 
				
			||||||
    CONF_PATH,
 | 
					 | 
				
			||||||
    CONF_RAW_DATA_ID,
 | 
					 | 
				
			||||||
    CONF_REPEAT,
 | 
					 | 
				
			||||||
    CONF_RESIZE,
 | 
					 | 
				
			||||||
    CONF_SOURCE,
 | 
					 | 
				
			||||||
    CONF_TYPE,
 | 
					 | 
				
			||||||
    CONF_URL,
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
from esphome.core import CORE, HexInt
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
_LOGGER = logging.getLogger(__name__)
 | 
					_LOGGER = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,6 +12,7 @@ AUTO_LOAD = ["image"]
 | 
				
			|||||||
CODEOWNERS = ["@syndlex"]
 | 
					CODEOWNERS = ["@syndlex"]
 | 
				
			||||||
DEPENDENCIES = ["display"]
 | 
					DEPENDENCIES = ["display"]
 | 
				
			||||||
MULTI_CONF = True
 | 
					MULTI_CONF = True
 | 
				
			||||||
 | 
					MULTI_CONF_NO_DEFAULT = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONF_LOOP = "loop"
 | 
					CONF_LOOP = "loop"
 | 
				
			||||||
CONF_START_FRAME = "start_frame"
 | 
					CONF_START_FRAME = "start_frame"
 | 
				
			||||||
@@ -52,86 +34,19 @@ SetFrameAction = animation_ns.class_(
 | 
				
			|||||||
    "AnimationSetFrameAction", automation.Action, cg.Parented.template(Animation_)
 | 
					    "AnimationSetFrameAction", automation.Action, cg.Parented.template(Animation_)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TYPED_FILE_SCHEMA = cv.typed_schema(
 | 
					CONFIG_SCHEMA = espImage.IMAGE_SCHEMA.extend(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        SOURCE_LOCAL: LOCAL_SCHEMA,
 | 
					        cv.Required(CONF_ID): cv.declare_id(Animation_),
 | 
				
			||||||
        SOURCE_WEB: WEB_SCHEMA,
 | 
					        cv.Optional(CONF_LOOP): cv.All(
 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    key=CONF_SOURCE,
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def _file_schema(value):
 | 
					 | 
				
			||||||
    if isinstance(value, str):
 | 
					 | 
				
			||||||
        return validate_file_shorthand(value)
 | 
					 | 
				
			||||||
    return TYPED_FILE_SCHEMA(value)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FILE_SCHEMA = cv.Schema(_file_schema)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def validate_file_shorthand(value):
 | 
					 | 
				
			||||||
    value = cv.string_strict(value)
 | 
					 | 
				
			||||||
    if value.startswith("http://") or value.startswith("https://"):
 | 
					 | 
				
			||||||
        return FILE_SCHEMA(
 | 
					 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                CONF_SOURCE: SOURCE_WEB,
 | 
					                cv.Optional(CONF_START_FRAME, default=0): cv.positive_int,
 | 
				
			||||||
                CONF_URL: value,
 | 
					                cv.Optional(CONF_END_FRAME): cv.positive_int,
 | 
				
			||||||
 | 
					                cv.Optional(CONF_REPEAT): cv.positive_int,
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        )
 | 
					        ),
 | 
				
			||||||
    return FILE_SCHEMA(
 | 
					    },
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            CONF_SOURCE: SOURCE_LOCAL,
 | 
					 | 
				
			||||||
            CONF_PATH: value,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def validate_cross_dependencies(config):
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    Validate fields whose possible values depend on other fields.
 | 
					 | 
				
			||||||
    For example, validate that explicitly transparent image types
 | 
					 | 
				
			||||||
    have "use_transparency" set to True.
 | 
					 | 
				
			||||||
    Also set the default value for those kind of dependent fields.
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    image_type = config[CONF_TYPE]
 | 
					 | 
				
			||||||
    is_transparent_type = image_type in ["TRANSPARENT_BINARY", "RGBA"]
 | 
					 | 
				
			||||||
    # If the use_transparency option was not specified, set the default depending on the image type
 | 
					 | 
				
			||||||
    if CONF_USE_TRANSPARENCY not in config:
 | 
					 | 
				
			||||||
        config[CONF_USE_TRANSPARENCY] = is_transparent_type
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if is_transparent_type and not config[CONF_USE_TRANSPARENCY]:
 | 
					 | 
				
			||||||
        raise cv.Invalid(f"Image type {image_type} must always be transparent.")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return config
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ANIMATION_SCHEMA = cv.Schema(
 | 
					 | 
				
			||||||
    cv.All(
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            cv.Required(CONF_ID): cv.declare_id(Animation_),
 | 
					 | 
				
			||||||
            cv.Required(CONF_FILE): FILE_SCHEMA,
 | 
					 | 
				
			||||||
            cv.Optional(CONF_RESIZE): cv.dimensions,
 | 
					 | 
				
			||||||
            cv.Optional(CONF_TYPE, default="BINARY"): cv.enum(
 | 
					 | 
				
			||||||
                espImage.IMAGE_TYPE, upper=True
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            # Not setting default here on purpose; the default depends on the image type,
 | 
					 | 
				
			||||||
            # and thus will be set in the "validate_cross_dependencies" validator.
 | 
					 | 
				
			||||||
            cv.Optional(CONF_USE_TRANSPARENCY): cv.boolean,
 | 
					 | 
				
			||||||
            cv.Optional(CONF_LOOP): cv.All(
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    cv.Optional(CONF_START_FRAME, default=0): cv.positive_int,
 | 
					 | 
				
			||||||
                    cv.Optional(CONF_END_FRAME): cv.positive_int,
 | 
					 | 
				
			||||||
                    cv.Optional(CONF_REPEAT): cv.positive_int,
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        validate_cross_dependencies,
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, ANIMATION_SCHEMA)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
NEXT_FRAME_SCHEMA = automation.maybe_simple_id(
 | 
					NEXT_FRAME_SCHEMA = automation.maybe_simple_id(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -165,183 +80,26 @@ async def animation_action_to_code(config, action_id, template_arg, args):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    from PIL import Image
 | 
					    (
 | 
				
			||||||
 | 
					        prog_arr,
 | 
				
			||||||
 | 
					        width,
 | 
				
			||||||
 | 
					        height,
 | 
				
			||||||
 | 
					        image_type,
 | 
				
			||||||
 | 
					        trans_value,
 | 
				
			||||||
 | 
					        frame_count,
 | 
				
			||||||
 | 
					    ) = await espImage.write_image(config, all_frames=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    conf_file = config[CONF_FILE]
 | 
					 | 
				
			||||||
    if conf_file[CONF_SOURCE] == SOURCE_LOCAL:
 | 
					 | 
				
			||||||
        path = CORE.relative_config_path(conf_file[CONF_PATH])
 | 
					 | 
				
			||||||
    elif conf_file[CONF_SOURCE] == SOURCE_WEB:
 | 
					 | 
				
			||||||
        path = espImage.compute_local_image_path(conf_file).as_posix()
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        raise core.EsphomeError(f"Unknown animation source: {conf_file[CONF_SOURCE]}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        image = Image.open(path)
 | 
					 | 
				
			||||||
    except Exception as e:
 | 
					 | 
				
			||||||
        raise core.EsphomeError(f"Could not load image file {path}: {e}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    width, height = image.size
 | 
					 | 
				
			||||||
    frames = image.n_frames
 | 
					 | 
				
			||||||
    if CONF_RESIZE in config:
 | 
					 | 
				
			||||||
        new_width_max, new_height_max = config[CONF_RESIZE]
 | 
					 | 
				
			||||||
        ratio = min(new_width_max / width, new_height_max / height)
 | 
					 | 
				
			||||||
        width, height = int(width * ratio), int(height * ratio)
 | 
					 | 
				
			||||||
    elif width > 500 or height > 500:
 | 
					 | 
				
			||||||
        _LOGGER.warning(
 | 
					 | 
				
			||||||
            'The image "%s" you requested is very big. Please consider'
 | 
					 | 
				
			||||||
            " using the resize parameter.",
 | 
					 | 
				
			||||||
            path,
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    transparent = config[CONF_USE_TRANSPARENCY]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if config[CONF_TYPE] == "GRAYSCALE":
 | 
					 | 
				
			||||||
        data = [0 for _ in range(height * width * frames)]
 | 
					 | 
				
			||||||
        pos = 0
 | 
					 | 
				
			||||||
        for frameIndex in range(frames):
 | 
					 | 
				
			||||||
            image.seek(frameIndex)
 | 
					 | 
				
			||||||
            frame = image.convert("LA", dither=Image.Dither.NONE)
 | 
					 | 
				
			||||||
            if CONF_RESIZE in config:
 | 
					 | 
				
			||||||
                frame = frame.resize([width, height])
 | 
					 | 
				
			||||||
            pixels = list(frame.getdata())
 | 
					 | 
				
			||||||
            if len(pixels) != height * width:
 | 
					 | 
				
			||||||
                raise core.EsphomeError(
 | 
					 | 
				
			||||||
                    f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})"
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            for pix, a in pixels:
 | 
					 | 
				
			||||||
                if transparent:
 | 
					 | 
				
			||||||
                    if pix == 1:
 | 
					 | 
				
			||||||
                        pix = 0
 | 
					 | 
				
			||||||
                    if a < 0x80:
 | 
					 | 
				
			||||||
                        pix = 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                data[pos] = pix
 | 
					 | 
				
			||||||
                pos += 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    elif config[CONF_TYPE] == "RGBA":
 | 
					 | 
				
			||||||
        data = [0 for _ in range(height * width * 4 * frames)]
 | 
					 | 
				
			||||||
        pos = 0
 | 
					 | 
				
			||||||
        for frameIndex in range(frames):
 | 
					 | 
				
			||||||
            image.seek(frameIndex)
 | 
					 | 
				
			||||||
            frame = image.convert("RGBA")
 | 
					 | 
				
			||||||
            if CONF_RESIZE in config:
 | 
					 | 
				
			||||||
                frame = frame.resize([width, height])
 | 
					 | 
				
			||||||
            pixels = list(frame.getdata())
 | 
					 | 
				
			||||||
            if len(pixels) != height * width:
 | 
					 | 
				
			||||||
                raise core.EsphomeError(
 | 
					 | 
				
			||||||
                    f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})"
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            for pix in pixels:
 | 
					 | 
				
			||||||
                data[pos] = pix[0]
 | 
					 | 
				
			||||||
                pos += 1
 | 
					 | 
				
			||||||
                data[pos] = pix[1]
 | 
					 | 
				
			||||||
                pos += 1
 | 
					 | 
				
			||||||
                data[pos] = pix[2]
 | 
					 | 
				
			||||||
                pos += 1
 | 
					 | 
				
			||||||
                data[pos] = pix[3]
 | 
					 | 
				
			||||||
                pos += 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    elif config[CONF_TYPE] == "RGB24":
 | 
					 | 
				
			||||||
        data = [0 for _ in range(height * width * 3 * frames)]
 | 
					 | 
				
			||||||
        pos = 0
 | 
					 | 
				
			||||||
        for frameIndex in range(frames):
 | 
					 | 
				
			||||||
            image.seek(frameIndex)
 | 
					 | 
				
			||||||
            frame = image.convert("RGBA")
 | 
					 | 
				
			||||||
            if CONF_RESIZE in config:
 | 
					 | 
				
			||||||
                frame = frame.resize([width, height])
 | 
					 | 
				
			||||||
            pixels = list(frame.getdata())
 | 
					 | 
				
			||||||
            if len(pixels) != height * width:
 | 
					 | 
				
			||||||
                raise core.EsphomeError(
 | 
					 | 
				
			||||||
                    f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})"
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            for r, g, b, a in pixels:
 | 
					 | 
				
			||||||
                if transparent:
 | 
					 | 
				
			||||||
                    if r == 0 and g == 0 and b == 1:
 | 
					 | 
				
			||||||
                        b = 0
 | 
					 | 
				
			||||||
                    if a < 0x80:
 | 
					 | 
				
			||||||
                        r = 0
 | 
					 | 
				
			||||||
                        g = 0
 | 
					 | 
				
			||||||
                        b = 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                data[pos] = r
 | 
					 | 
				
			||||||
                pos += 1
 | 
					 | 
				
			||||||
                data[pos] = g
 | 
					 | 
				
			||||||
                pos += 1
 | 
					 | 
				
			||||||
                data[pos] = b
 | 
					 | 
				
			||||||
                pos += 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    elif config[CONF_TYPE] in ["RGB565", "TRANSPARENT_IMAGE"]:
 | 
					 | 
				
			||||||
        data = [0 for _ in range(height * width * 2 * frames)]
 | 
					 | 
				
			||||||
        pos = 0
 | 
					 | 
				
			||||||
        for frameIndex in range(frames):
 | 
					 | 
				
			||||||
            image.seek(frameIndex)
 | 
					 | 
				
			||||||
            frame = image.convert("RGBA")
 | 
					 | 
				
			||||||
            if CONF_RESIZE in config:
 | 
					 | 
				
			||||||
                frame = frame.resize([width, height])
 | 
					 | 
				
			||||||
            pixels = list(frame.getdata())
 | 
					 | 
				
			||||||
            if len(pixels) != height * width:
 | 
					 | 
				
			||||||
                raise core.EsphomeError(
 | 
					 | 
				
			||||||
                    f"Unexpected number of pixels in {path} frame {frameIndex}: ({len(pixels)} != {height * width})"
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            for r, g, b, a in pixels:
 | 
					 | 
				
			||||||
                R = r >> 3
 | 
					 | 
				
			||||||
                G = g >> 2
 | 
					 | 
				
			||||||
                B = b >> 3
 | 
					 | 
				
			||||||
                rgb = (R << 11) | (G << 5) | B
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if transparent:
 | 
					 | 
				
			||||||
                    if rgb == 0x0020:
 | 
					 | 
				
			||||||
                        rgb = 0
 | 
					 | 
				
			||||||
                    if a < 0x80:
 | 
					 | 
				
			||||||
                        rgb = 0x0020
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                data[pos] = rgb >> 8
 | 
					 | 
				
			||||||
                pos += 1
 | 
					 | 
				
			||||||
                data[pos] = rgb & 0xFF
 | 
					 | 
				
			||||||
                pos += 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    elif config[CONF_TYPE] in ["BINARY", "TRANSPARENT_BINARY"]:
 | 
					 | 
				
			||||||
        width8 = ((width + 7) // 8) * 8
 | 
					 | 
				
			||||||
        data = [0 for _ in range((height * width8 // 8) * frames)]
 | 
					 | 
				
			||||||
        for frameIndex in range(frames):
 | 
					 | 
				
			||||||
            image.seek(frameIndex)
 | 
					 | 
				
			||||||
            if transparent:
 | 
					 | 
				
			||||||
                alpha = image.split()[-1]
 | 
					 | 
				
			||||||
                has_alpha = alpha.getextrema()[0] < 0xFF
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                has_alpha = False
 | 
					 | 
				
			||||||
            frame = image.convert("1", dither=Image.Dither.NONE)
 | 
					 | 
				
			||||||
            if CONF_RESIZE in config:
 | 
					 | 
				
			||||||
                frame = frame.resize([width, height])
 | 
					 | 
				
			||||||
                if transparent:
 | 
					 | 
				
			||||||
                    alpha = alpha.resize([width, height])
 | 
					 | 
				
			||||||
            for x, y in [(i, j) for i in range(width) for j in range(height)]:
 | 
					 | 
				
			||||||
                if transparent and has_alpha:
 | 
					 | 
				
			||||||
                    if not alpha.getpixel((x, y)):
 | 
					 | 
				
			||||||
                        continue
 | 
					 | 
				
			||||||
                elif frame.getpixel((x, y)):
 | 
					 | 
				
			||||||
                    continue
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                pos = x + y * width8 + (height * width8 * frameIndex)
 | 
					 | 
				
			||||||
                data[pos // 8] |= 0x80 >> (pos % 8)
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        raise core.EsphomeError(
 | 
					 | 
				
			||||||
            f"Animation f{config[CONF_ID]} has not supported type {config[CONF_TYPE]}."
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    rhs = [HexInt(x) for x in data]
 | 
					 | 
				
			||||||
    prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
 | 
					 | 
				
			||||||
    var = cg.new_Pvariable(
 | 
					    var = cg.new_Pvariable(
 | 
				
			||||||
        config[CONF_ID],
 | 
					        config[CONF_ID],
 | 
				
			||||||
        prog_arr,
 | 
					        prog_arr,
 | 
				
			||||||
        width,
 | 
					        width,
 | 
				
			||||||
        height,
 | 
					        height,
 | 
				
			||||||
        frames,
 | 
					        frame_count,
 | 
				
			||||||
        espImage.IMAGE_TYPE[config[CONF_TYPE]],
 | 
					        image_type,
 | 
				
			||||||
 | 
					        trans_value,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    cg.add(var.set_transparency(transparent))
 | 
					 | 
				
			||||||
    if loop_config := config.get(CONF_LOOP):
 | 
					    if loop_config := config.get(CONF_LOOP):
 | 
				
			||||||
        start = loop_config[CONF_START_FRAME]
 | 
					        start = loop_config[CONF_START_FRAME]
 | 
				
			||||||
        end = loop_config.get(CONF_END_FRAME, frames)
 | 
					        end = loop_config.get(CONF_END_FRAME, frame_count)
 | 
				
			||||||
        count = loop_config.get(CONF_REPEAT, -1)
 | 
					        count = loop_config.get(CONF_REPEAT, -1)
 | 
				
			||||||
        cg.add(var.set_loop(start, end, count))
 | 
					        cg.add(var.set_loop(start, end, count))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,8 +6,8 @@ namespace esphome {
 | 
				
			|||||||
namespace animation {
 | 
					namespace animation {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Animation::Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count,
 | 
					Animation::Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count,
 | 
				
			||||||
                     image::ImageType type)
 | 
					                     image::ImageType type, image::Transparency transparent)
 | 
				
			||||||
    : Image(data_start, width, height, type),
 | 
					    : Image(data_start, width, height, type, transparent),
 | 
				
			||||||
      animation_data_start_(data_start),
 | 
					      animation_data_start_(data_start),
 | 
				
			||||||
      current_frame_(0),
 | 
					      current_frame_(0),
 | 
				
			||||||
      animation_frame_count_(animation_frame_count),
 | 
					      animation_frame_count_(animation_frame_count),
 | 
				
			||||||
@@ -62,7 +62,7 @@ void Animation::set_frame(int frame) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Animation::update_data_start_() {
 | 
					void Animation::update_data_start_() {
 | 
				
			||||||
  const uint32_t image_size = image_type_to_width_stride(this->width_, this->type_) * this->height_;
 | 
					  const uint32_t image_size = this->get_width_stride() * this->height_;
 | 
				
			||||||
  this->data_start_ = this->animation_data_start_ + image_size * this->current_frame_;
 | 
					  this->data_start_ = this->animation_data_start_ + image_size * this->current_frame_;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,8 @@ namespace animation {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class Animation : public image::Image {
 | 
					class Animation : public image::Image {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, image::ImageType type);
 | 
					  Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, image::ImageType type,
 | 
				
			||||||
 | 
					            image::Transparency transparent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  uint32_t get_animation_frame_count() const;
 | 
					  uint32_t get_animation_frame_count() const;
 | 
				
			||||||
  int get_current_frame() const;
 | 
					  int get_current_frame() const;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					from esphome.components import ble_client, climate
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.components import climate, ble_client
 | 
					from esphome.const import CONF_UNIT_OF_MEASUREMENT
 | 
				
			||||||
from esphome.const import CONF_ID, CONF_UNIT_OF_MEASUREMENT
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
UNITS = {
 | 
					UNITS = {
 | 
				
			||||||
    "f": "f",
 | 
					    "f": "f",
 | 
				
			||||||
@@ -17,9 +17,9 @@ Anova = anova_ns.class_(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONFIG_SCHEMA = (
 | 
					CONFIG_SCHEMA = (
 | 
				
			||||||
    climate.CLIMATE_SCHEMA.extend(
 | 
					    climate.climate_schema(Anova)
 | 
				
			||||||
 | 
					    .extend(
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            cv.GenerateID(): cv.declare_id(Anova),
 | 
					 | 
				
			||||||
            cv.Required(CONF_UNIT_OF_MEASUREMENT): cv.enum(UNITS),
 | 
					            cv.Required(CONF_UNIT_OF_MEASUREMENT): cv.enum(UNITS),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@@ -29,8 +29,7 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = await climate.new_climate(config)
 | 
				
			||||||
    await cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    await climate.register_climate(var, config)
 | 
					 | 
				
			||||||
    await ble_client.register_ble_node(var, config)
 | 
					    await ble_client.register_ble_node(var, config)
 | 
				
			||||||
    cg.add(var.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT]))
 | 
					    cg.add(var.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT]))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,7 +54,7 @@ enum {  // APDS9306 registers
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void APDS9306::setup() {
 | 
					void APDS9306::setup() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up APDS9306...");
 | 
					  ESP_LOGCONFIG(TAG, "Running setup");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  uint8_t id;
 | 
					  uint8_t id;
 | 
				
			||||||
  if (!this->read_byte(APDS9306_PART_ID, &id)) {  // Part ID register
 | 
					  if (!this->read_byte(APDS9306_PART_ID, &id)) {  // Part ID register
 | 
				
			||||||
@@ -97,7 +97,7 @@ void APDS9306::dump_config() {
 | 
				
			|||||||
  if (this->is_failed()) {
 | 
					  if (this->is_failed()) {
 | 
				
			||||||
    switch (this->error_code_) {
 | 
					    switch (this->error_code_) {
 | 
				
			||||||
      case COMMUNICATION_FAILED:
 | 
					      case COMMUNICATION_FAILED:
 | 
				
			||||||
        ESP_LOGE(TAG, "Communication with APDS9306 failed!");
 | 
					        ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      case WRONG_ID:
 | 
					      case WRONG_ID:
 | 
				
			||||||
        ESP_LOGE(TAG, "APDS9306 has invalid id!");
 | 
					        ESP_LOGE(TAG, "APDS9306 has invalid id!");
 | 
				
			||||||
@@ -108,9 +108,12 @@ void APDS9306::dump_config() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  Gain: %u", AMBIENT_LIGHT_GAIN_VALUES[this->gain_]);
 | 
					  ESP_LOGCONFIG(TAG,
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  Measurement rate: %u", MEASUREMENT_RATE_VALUES[this->measurement_rate_]);
 | 
					                "  Gain: %u\n"
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  Measurement Resolution/Bit width: %d", MEASUREMENT_BIT_WIDTH_VALUES[this->bit_width_]);
 | 
					                "  Measurement rate: %u\n"
 | 
				
			||||||
 | 
					                "  Measurement Resolution/Bit width: %d",
 | 
				
			||||||
 | 
					                AMBIENT_LIGHT_GAIN_VALUES[this->gain_], MEASUREMENT_RATE_VALUES[this->measurement_rate_],
 | 
				
			||||||
 | 
					                MEASUREMENT_BIT_WIDTH_VALUES[this->bit_width_]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  LOG_UPDATE_INTERVAL(this);
 | 
					  LOG_UPDATE_INTERVAL(this);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -122,7 +125,8 @@ void APDS9306::update() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  this->status_clear_warning();
 | 
					  this->status_clear_warning();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!(status &= 0b00001000)) {  // No new data
 | 
					  status &= 0b00001000;
 | 
				
			||||||
 | 
					  if (!status) {  // No new data
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,8 +2,8 @@
 | 
				
			|||||||
# https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf
 | 
					# https://www.mouser.ca/datasheet/2/678/AVGO_S_A0002854364_1-2574547.pdf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import i2c, sensor
 | 
					from esphome.components import i2c, sensor
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_GAIN,
 | 
					    CONF_GAIN,
 | 
				
			||||||
    DEVICE_CLASS_ILLUMINANCE,
 | 
					    DEVICE_CLASS_ILLUMINANCE,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					 | 
				
			||||||
from esphome.components import i2c
 | 
					from esphome.components import i2c
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.const import CONF_ID
 | 
					from esphome.const import CONF_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEPENDENCIES = ["i2c"]
 | 
					DEPENDENCIES = ["i2c"]
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user