mirror of
				https://github.com/esphome/esphome.git
				synced 2025-11-04 09:01:49 +00:00 
			
		
		
		
	Compare commits
	
		
			224 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					c9d93ff685 | ||
| 
						 | 
					fa72990a63 | ||
| 
						 | 
					e5afb1c4ea | ||
| 
						 | 
					73ead5f328 | ||
| 
						 | 
					5c57b51378 | ||
| 
						 | 
					e25935ef21 | ||
| 
						 | 
					c7a52c3894 | ||
| 
						 | 
					53a4689ed1 | ||
| 
						 | 
					0a82e6e792 | ||
| 
						 | 
					98855e4123 | ||
| 
						 | 
					6a09d7c49b | ||
| 
						 | 
					46e50ba53f | ||
| 
						 | 
					f1e3ff2ed2 | ||
| 
						 | 
					7787fa8f29 | ||
| 
						 | 
					70902029f8 | ||
| 
						 | 
					4f9a56c884 | ||
| 
						 | 
					3715ba030b | ||
| 
						 | 
					0c93be97a9 | ||
| 
						 | 
					54eb6070fb | ||
| 
						 | 
					4dbf1c521e | ||
| 
						 | 
					f30b8f6b3c | ||
| 
						 | 
					18c08f24ad | ||
| 
						 | 
					a7f53aea0e | ||
| 
						 | 
					c399905675 | ||
| 
						 | 
					5cb0c11feb | ||
| 
						 | 
					08b67e7aea | ||
| 
						 | 
					07ae8ec553 | ||
| 
						 | 
					04c3a43c17 | ||
| 
						 | 
					b632344596 | ||
| 
						 | 
					fb8ec79a52 | ||
| 
						 | 
					7dd16df846 | ||
| 
						 | 
					551e9c6111 | ||
| 
						 | 
					cc9f0b3f47 | ||
| 
						 | 
					d77c3abdc0 | ||
| 
						 | 
					dd37a4e04c | ||
| 
						 | 
					1f5c79bd17 | ||
| 
						 | 
					623570a117 | ||
| 
						 | 
					cdbc146e5d | ||
| 
						 | 
					7ae611256a | ||
| 
						 | 
					b62c47fede | ||
| 
						 | 
					99f497c3b8 | ||
| 
						 | 
					4f88c2489b | ||
| 
						 | 
					294ba1fca7 | ||
| 
						 | 
					be61b38a2c | ||
| 
						 | 
					f9797825ad | ||
| 
						 | 
					fd4b7d4588 | ||
| 
						 | 
					062cedc200 | ||
| 
						 | 
					79b9d0579d | ||
| 
						 | 
					ab31117bf3 | ||
| 
						 | 
					d31040f5d8 | ||
| 
						 | 
					52d19fa43d | ||
| 
						 | 
					8ca34f7098 | ||
| 
						 | 
					4c4099966a | ||
| 
						 | 
					86ac7f3a59 | ||
| 
						 | 
					9e400a7857 | ||
| 
						 | 
					d5278351da | ||
| 
						 | 
					36861595f1 | ||
| 
						 | 
					d604321f37 | ||
| 
						 | 
					964ab65497 | ||
| 
						 | 
					3b940b1c04 | ||
| 
						 | 
					5fca480921 | ||
| 
						 | 
					7051f897bc | ||
| 
						 | 
					2cb3015a28 | ||
| 
						 | 
					d0859a7d33 | ||
| 
						 | 
					61ebc629f6 | ||
| 
						 | 
					32f2da77f8 | ||
| 
						 | 
					bfca3f242a | ||
| 
						 | 
					3dfff2930a | ||
| 
						 | 
					027e0de48e | ||
| 
						 | 
					c811141a4f | ||
| 
						 | 
					871c0ee2a5 | ||
| 
						 | 
					b8a7741c61 | ||
| 
						 | 
					b6011b9353 | ||
| 
						 | 
					40a5005d94 | ||
| 
						 | 
					c5eba21ff6 | ||
| 
						 | 
					4891cfef56 | ||
| 
						 | 
					4395664547 | ||
| 
						 | 
					04d926af39 | ||
| 
						 | 
					f9a31c1abb | ||
| 
						 | 
					dca1c0f160 | ||
| 
						 | 
					2419bc3678 | ||
| 
						 | 
					c19b3ecd43 | ||
| 
						 | 
					ef1e91d838 | ||
| 
						 | 
					e5929225eb | ||
| 
						 | 
					99d9ab4e40 | ||
| 
						 | 
					f310ca1b74 | ||
| 
						 | 
					f763daa577 | ||
| 
						 | 
					607c3ae651 | ||
| 
						 | 
					e006045f59 | ||
| 
						 | 
					fff3645901 | ||
| 
						 | 
					a5383fd208 | ||
| 
						 | 
					5591832b50 | ||
| 
						 | 
					9ce3a2059f | ||
| 
						 | 
					69e6cf2c0c | ||
| 
						 | 
					28635124f9 | ||
| 
						 | 
					25b116048c | ||
| 
						 | 
					035be87a83 | ||
| 
						 | 
					e8bdbc45a9 | ||
| 
						 | 
					429caccefa | ||
| 
						 | 
					744ca1af7c | ||
| 
						 | 
					106f0d611f | ||
| 
						 | 
					d826416684 | ||
| 
						 | 
					24ba9eba46 | ||
| 
						 | 
					424c34225f | ||
| 
						 | 
					d781f3a11b | ||
| 
						 | 
					a80f9ed336 | ||
| 
						 | 
					92bbedfa5a | ||
| 
						 | 
					86710ed483 | ||
| 
						 | 
					da7eb9ac90 | ||
| 
						 | 
					c411043681 | ||
| 
						 | 
					93f8ee7e60 | ||
| 
						 | 
					0efc1f06f2 | ||
| 
						 | 
					81959804df | ||
| 
						 | 
					75b524ddc4 | ||
| 
						 | 
					f599c36272 | ||
| 
						 | 
					9bb64315f3 | ||
| 
						 | 
					575badc690 | ||
| 
						 | 
					4b91cfb7f9 | ||
| 
						 | 
					9ad9d64ac7 | ||
| 
						 | 
					5a2cfa2798 | ||
| 
						 | 
					eb24da7c82 | ||
| 
						 | 
					f93e261d75 | ||
| 
						 | 
					501f88ca86 | ||
| 
						 | 
					360effcb72 | ||
| 
						 | 
					eb9bd69405 | ||
| 
						 | 
					11b8210e36 | ||
| 
						 | 
					a57a842f7b | ||
| 
						 | 
					a8c253a2a5 | ||
| 
						 | 
					8b737aabd9 | ||
| 
						 | 
					0db4815f3d | ||
| 
						 | 
					139db58a66 | ||
| 
						 | 
					d23376b81e | ||
| 
						 | 
					99d90845b5 | ||
| 
						 | 
					ea0127e42b | ||
| 
						 | 
					c32fec7432 | ||
| 
						 | 
					8bd23dd457 | ||
| 
						 | 
					97a12c0169 | ||
| 
						 | 
					635916737b | ||
| 
						 | 
					65c50e4f01 | ||
| 
						 | 
					5cf18235e3 | ||
| 
						 | 
					b80f3fdec9 | ||
| 
						 | 
					0426be9280 | ||
| 
						 | 
					7c678659d4 | ||
| 
						 | 
					13fe9e83fa | ||
| 
						 | 
					4711f36a1f | ||
| 
						 | 
					01e2a51132 | ||
| 
						 | 
					a70a205ace | ||
| 
						 | 
					33625e2dd3 | ||
| 
						 | 
					0277218319 | ||
| 
						 | 
					18a8c727fa | ||
| 
						 | 
					80ad784a4e | ||
| 
						 | 
					ebadaa9660 | ||
| 
						 | 
					7bc51582f0 | ||
| 
						 | 
					11fb54c74e | ||
| 
						 | 
					913ac8b7e8 | ||
| 
						 | 
					2b9350ce76 | ||
| 
						 | 
					3b18f1b87f | ||
| 
						 | 
					c5c24c1989 | ||
| 
						 | 
					c3938d04f3 | ||
| 
						 | 
					f968713be8 | ||
| 
						 | 
					7b11284008 | ||
| 
						 | 
					f39c0d52ee | ||
| 
						 | 
					a3756a9600 | ||
| 
						 | 
					afa436fe8f | ||
| 
						 | 
					48b5ea9e59 | ||
| 
						 | 
					56974153f1 | ||
| 
						 | 
					9a2cd71571 | ||
| 
						 | 
					d1c6368283 | ||
| 
						 | 
					5c3268b8d4 | ||
| 
						 | 
					25af5ab7c6 | ||
| 
						 | 
					4d586b1446 | ||
| 
						 | 
					bb759d52c8 | ||
| 
						 | 
					9a2cf05c5f | ||
| 
						 | 
					c79d700d03 | ||
| 
						 | 
					482a3aebc9 | ||
| 
						 | 
					387f249363 | ||
| 
						 | 
					3d917d0b7e | ||
| 
						 | 
					824f3187ac | ||
| 
						 | 
					e3c27a483c | ||
| 
						 | 
					a33bb32874 | ||
| 
						 | 
					93d9d4b50a | ||
| 
						 | 
					2376a2c941 | ||
| 
						 | 
					b92702a312 | ||
| 
						 | 
					b11d5f6799 | ||
| 
						 | 
					072dce340e | ||
| 
						 | 
					cccb1a2c9e | ||
| 
						 | 
					063d9c47a4 | ||
| 
						 | 
					8d8d421286 | ||
| 
						 | 
					0ce57e5a39 | ||
| 
						 | 
					aebad04c0b | ||
| 
						 | 
					514d11d46f | ||
| 
						 | 
					96e46db272 | ||
| 
						 | 
					76f78877f6 | ||
| 
						 | 
					4ffa68b773 | ||
| 
						 | 
					dce9d59dfe | ||
| 
						 | 
					d3e291b442 | ||
| 
						 | 
					d4686c0fb1 | ||
| 
						 | 
					95ed3e9d46 | ||
| 
						 | 
					d0eaebe19f | ||
| 
						 | 
					9ecead2645 | ||
| 
						 | 
					98166dfa66 | ||
| 
						 | 
					5645be4e0f | ||
| 
						 | 
					9a7a205510 | ||
| 
						 | 
					7e3b8fd346 | ||
| 
						 | 
					3d6dcc9eee | ||
| 
						 | 
					4f6982fbc5 | ||
| 
						 | 
					00c144daeb | ||
| 
						 | 
					54660300e9 | ||
| 
						 | 
					5dc40049be | ||
| 
						 | 
					1e46b4073f | ||
| 
						 | 
					29fc4af0fc | ||
| 
						 | 
					4030a2e253 | ||
| 
						 | 
					ea80cb751b | ||
| 
						 | 
					6aa61dbce7 | ||
| 
						 | 
					cdc9c99d40 | ||
| 
						 | 
					a546677b08 | ||
| 
						 | 
					5c3af1d3f6 | ||
| 
						 | 
					66b0b6feeb | ||
| 
						 | 
					7665a220a0 | ||
| 
						 | 
					4250af4dd9 | ||
| 
						 | 
					73252ccd25 | ||
| 
						 | 
					33bf78c369 | ||
| 
						 | 
					96ded4e402 | ||
| 
						 | 
					076124eb71 | 
@@ -49,7 +49,7 @@ ConstructorInitializerAllOnOneLineOrOnePerLine: true
 | 
				
			|||||||
ConstructorInitializerIndentWidth: 4
 | 
					ConstructorInitializerIndentWidth: 4
 | 
				
			||||||
ContinuationIndentWidth: 4
 | 
					ContinuationIndentWidth: 4
 | 
				
			||||||
Cpp11BracedListStyle: true
 | 
					Cpp11BracedListStyle: true
 | 
				
			||||||
DerivePointerAlignment: true
 | 
					DerivePointerAlignment: false
 | 
				
			||||||
DisableFormat:   false
 | 
					DisableFormat:   false
 | 
				
			||||||
ExperimentalAutoDetectBinPacking: false
 | 
					ExperimentalAutoDetectBinPacking: false
 | 
				
			||||||
FixNamespaceComments: true
 | 
					FixNamespaceComments: true
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										47
									
								
								.clang-tidy
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								.clang-tidy
									
									
									
									
									
								
							@@ -4,14 +4,24 @@ Checks: >-
 | 
				
			|||||||
  -abseil-*,
 | 
					  -abseil-*,
 | 
				
			||||||
  -android-*,
 | 
					  -android-*,
 | 
				
			||||||
  -boost-*,
 | 
					  -boost-*,
 | 
				
			||||||
  -bugprone-macro-parentheses,
 | 
					  -bugprone-branch-clone,
 | 
				
			||||||
 | 
					  -bugprone-narrowing-conversions,
 | 
				
			||||||
 | 
					  -bugprone-signed-char-misuse,
 | 
				
			||||||
 | 
					  -bugprone-too-small-loop-variable,
 | 
				
			||||||
  -cert-dcl50-cpp,
 | 
					  -cert-dcl50-cpp,
 | 
				
			||||||
  -cert-err58-cpp,
 | 
					  -cert-err58-cpp,
 | 
				
			||||||
  -clang-analyzer-core.CallAndMessage,
 | 
					  -cert-oop57-cpp,
 | 
				
			||||||
 | 
					  -cert-str34-c,
 | 
				
			||||||
 | 
					  -clang-analyzer-optin.cplusplus.UninitializedObject,
 | 
				
			||||||
  -clang-analyzer-osx.*,
 | 
					  -clang-analyzer-osx.*,
 | 
				
			||||||
  -clang-analyzer-security.*,
 | 
					  -clang-diagnostic-shadow-field,
 | 
				
			||||||
 | 
					  -cppcoreguidelines-avoid-c-arrays,
 | 
				
			||||||
  -cppcoreguidelines-avoid-goto,
 | 
					  -cppcoreguidelines-avoid-goto,
 | 
				
			||||||
  -cppcoreguidelines-c-copy-assignment-signature,
 | 
					  -cppcoreguidelines-avoid-magic-numbers,
 | 
				
			||||||
 | 
					  -cppcoreguidelines-init-variables,
 | 
				
			||||||
 | 
					  -cppcoreguidelines-macro-usage,
 | 
				
			||||||
 | 
					  -cppcoreguidelines-narrowing-conversions,
 | 
				
			||||||
 | 
					  -cppcoreguidelines-non-private-member-variables-in-classes,
 | 
				
			||||||
  -cppcoreguidelines-owning-memory,
 | 
					  -cppcoreguidelines-owning-memory,
 | 
				
			||||||
  -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,
 | 
				
			||||||
@@ -24,40 +34,51 @@ Checks: >-
 | 
				
			|||||||
  -cppcoreguidelines-pro-type-union-access,
 | 
					  -cppcoreguidelines-pro-type-union-access,
 | 
				
			||||||
  -cppcoreguidelines-pro-type-vararg,
 | 
					  -cppcoreguidelines-pro-type-vararg,
 | 
				
			||||||
  -cppcoreguidelines-special-member-functions,
 | 
					  -cppcoreguidelines-special-member-functions,
 | 
				
			||||||
  -fuchsia-*,
 | 
					 | 
				
			||||||
  -fuchsia-default-arguments,
 | 
					  -fuchsia-default-arguments,
 | 
				
			||||||
  -fuchsia-multiple-inheritance,
 | 
					  -fuchsia-multiple-inheritance,
 | 
				
			||||||
  -fuchsia-overloaded-operator,
 | 
					  -fuchsia-overloaded-operator,
 | 
				
			||||||
  -fuchsia-statically-constructed-objects,
 | 
					  -fuchsia-statically-constructed-objects,
 | 
				
			||||||
 | 
					  -fuchsia-default-arguments-declarations,
 | 
				
			||||||
 | 
					  -fuchsia-default-arguments-calls,
 | 
				
			||||||
  -google-build-using-namespace,
 | 
					  -google-build-using-namespace,
 | 
				
			||||||
  -google-explicit-constructor,
 | 
					  -google-explicit-constructor,
 | 
				
			||||||
  -google-readability-braces-around-statements,
 | 
					  -google-readability-braces-around-statements,
 | 
				
			||||||
  -google-readability-casting,
 | 
					  -google-readability-casting,
 | 
				
			||||||
  -google-readability-todo,
 | 
					  -google-readability-todo,
 | 
				
			||||||
  -google-runtime-int,
 | 
					 | 
				
			||||||
  -google-runtime-references,
 | 
					  -google-runtime-references,
 | 
				
			||||||
  -hicpp-*,
 | 
					  -hicpp-*,
 | 
				
			||||||
 | 
					  -llvm-else-after-return,
 | 
				
			||||||
  -llvm-header-guard,
 | 
					  -llvm-header-guard,
 | 
				
			||||||
  -llvm-include-order,
 | 
					  -llvm-include-order,
 | 
				
			||||||
  -misc-unconventional-assign-operator,
 | 
					  -llvm-qualified-auto,
 | 
				
			||||||
 | 
					  -llvmlibc-*,
 | 
				
			||||||
 | 
					  -misc-non-private-member-variables-in-classes,
 | 
				
			||||||
 | 
					  -misc-no-recursion,
 | 
				
			||||||
  -misc-unused-parameters,
 | 
					  -misc-unused-parameters,
 | 
				
			||||||
  -modernize-deprecated-headers,
 | 
					  -modernize-avoid-c-arrays,
 | 
				
			||||||
  -modernize-pass-by-value,
 | 
					 | 
				
			||||||
  -modernize-pass-by-value,
 | 
					 | 
				
			||||||
  -modernize-return-braced-init-list,
 | 
					  -modernize-return-braced-init-list,
 | 
				
			||||||
  -modernize-use-auto,
 | 
					  -modernize-use-auto,
 | 
				
			||||||
  -modernize-use-default-member-init,
 | 
					  -modernize-use-default-member-init,
 | 
				
			||||||
  -modernize-use-equals-default,
 | 
					  -modernize-use-equals-default,
 | 
				
			||||||
 | 
					  -modernize-use-trailing-return-type,
 | 
				
			||||||
  -mpi-*,
 | 
					  -mpi-*,
 | 
				
			||||||
  -objc-*,
 | 
					  -objc-*,
 | 
				
			||||||
  -performance-unnecessary-value-param,
 | 
					 | 
				
			||||||
  -readability-braces-around-statements,
 | 
					  -readability-braces-around-statements,
 | 
				
			||||||
 | 
					  -readability-const-return-type,
 | 
				
			||||||
 | 
					  -readability-convert-member-functions-to-static,
 | 
				
			||||||
  -readability-else-after-return,
 | 
					  -readability-else-after-return,
 | 
				
			||||||
  -readability-implicit-bool-conversion,
 | 
					  -readability-implicit-bool-conversion,
 | 
				
			||||||
 | 
					  -readability-isolate-declaration,
 | 
				
			||||||
 | 
					  -readability-magic-numbers,
 | 
				
			||||||
 | 
					  -readability-make-member-function-const,
 | 
				
			||||||
  -readability-named-parameter,
 | 
					  -readability-named-parameter,
 | 
				
			||||||
 | 
					  -readability-qualified-auto,
 | 
				
			||||||
 | 
					  -readability-redundant-access-specifiers,
 | 
				
			||||||
  -readability-redundant-member-init,
 | 
					  -readability-redundant-member-init,
 | 
				
			||||||
  -warnings-as-errors,
 | 
					  -readability-redundant-string-init,
 | 
				
			||||||
  -zircon-*
 | 
					  -readability-uppercase-literal-suffix,
 | 
				
			||||||
 | 
					  -readability-use-anyofallof,
 | 
				
			||||||
 | 
					  -warnings-as-errors
 | 
				
			||||||
WarningsAsErrors: '*'
 | 
					WarningsAsErrors: '*'
 | 
				
			||||||
HeaderFilterRegex: '^.*/src/esphome/.*'
 | 
					HeaderFilterRegex: '^.*/src/esphome/.*'
 | 
				
			||||||
AnalyzeTemporaryDtors: false
 | 
					AnalyzeTemporaryDtors: false
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,16 +2,29 @@
 | 
				
			|||||||
  "name": "ESPHome Dev",
 | 
					  "name": "ESPHome Dev",
 | 
				
			||||||
  "context": "..",
 | 
					  "context": "..",
 | 
				
			||||||
  "dockerFile": "../docker/Dockerfile.dev",
 | 
					  "dockerFile": "../docker/Dockerfile.dev",
 | 
				
			||||||
  "postCreateCommand": "mkdir -p config && pip3 install -e .",
 | 
					  "postCreateCommand": [
 | 
				
			||||||
  "runArgs": ["--privileged", "-e", "ESPHOME_DASHBOARD_USE_PING=1"],
 | 
					    "script/devcontainer-post-create"
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  "runArgs": [
 | 
				
			||||||
 | 
					    "--privileged",
 | 
				
			||||||
 | 
					    "-e",
 | 
				
			||||||
 | 
					    "ESPHOME_DASHBOARD_USE_PING=1"
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
  "appPort": 6052,
 | 
					  "appPort": 6052,
 | 
				
			||||||
  "extensions": [
 | 
					  "extensions": [
 | 
				
			||||||
 | 
					    // python
 | 
				
			||||||
    "ms-python.python",
 | 
					    "ms-python.python",
 | 
				
			||||||
    "visualstudioexptteam.vscodeintellicode",
 | 
					    "visualstudioexptteam.vscodeintellicode",
 | 
				
			||||||
    "redhat.vscode-yaml"
 | 
					    // yaml
 | 
				
			||||||
 | 
					    "redhat.vscode-yaml",
 | 
				
			||||||
 | 
					    // cpp
 | 
				
			||||||
 | 
					    "ms-vscode.cpptools",
 | 
				
			||||||
 | 
					    // editorconfig
 | 
				
			||||||
 | 
					    "editorconfig.editorconfig",
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  "settings": {
 | 
					  "settings": {
 | 
				
			||||||
    "python.pythonPath": "/usr/local/bin/python",
 | 
					    "python.languageServer": "Pylance",
 | 
				
			||||||
 | 
					    "python.pythonPath": "/usr/bin/python3",
 | 
				
			||||||
    "python.linting.pylintEnabled": true,
 | 
					    "python.linting.pylintEnabled": true,
 | 
				
			||||||
    "python.linting.enabled": true,
 | 
					    "python.linting.enabled": true,
 | 
				
			||||||
    "python.formatting.provider": "black",
 | 
					    "python.formatting.provider": "black",
 | 
				
			||||||
@@ -19,7 +32,7 @@
 | 
				
			|||||||
    "editor.formatOnSave": true,
 | 
					    "editor.formatOnSave": true,
 | 
				
			||||||
    "editor.formatOnType": true,
 | 
					    "editor.formatOnType": true,
 | 
				
			||||||
    "files.trimTrailingWhitespace": true,
 | 
					    "files.trimTrailingWhitespace": true,
 | 
				
			||||||
    "terminal.integrated.shell.linux": "/bin/bash",
 | 
					    "terminal.integrated.defaultProfile.linux": "bash",
 | 
				
			||||||
    "yaml.customTags": [
 | 
					    "yaml.customTags": [
 | 
				
			||||||
      "!secret scalar",
 | 
					      "!secret scalar",
 | 
				
			||||||
      "!lambda scalar",
 | 
					      "!lambda scalar",
 | 
				
			||||||
@@ -27,6 +40,18 @@
 | 
				
			|||||||
      "!include_dir_list scalar",
 | 
					      "!include_dir_list scalar",
 | 
				
			||||||
      "!include_dir_merge_list scalar",
 | 
					      "!include_dir_merge_list scalar",
 | 
				
			||||||
      "!include_dir_merge_named scalar"
 | 
					      "!include_dir_merge_named scalar"
 | 
				
			||||||
    ]
 | 
					    ],
 | 
				
			||||||
 | 
					    "files.exclude": {
 | 
				
			||||||
 | 
					      "**/.git": true,
 | 
				
			||||||
 | 
					      "**/.DS_Store": true,
 | 
				
			||||||
 | 
					      "**/*.pyc": {
 | 
				
			||||||
 | 
					        "when": "$(basename).py"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "**/__pycache__": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "files.associations": {
 | 
				
			||||||
 | 
					      "**/.vscode/*.json": "jsonc"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "C_Cpp.clang_format_path": "/usr/bin/clang-format-11",
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -103,6 +103,10 @@ venv.bak/
 | 
				
			|||||||
# mypy
 | 
					# mypy
 | 
				
			||||||
.mypy_cache/
 | 
					.mypy_cache/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# PlatformIO
 | 
				
			||||||
 | 
					.pio/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ESPHome
 | 
				
			||||||
config/
 | 
					config/
 | 
				
			||||||
examples/
 | 
					examples/
 | 
				
			||||||
Dockerfile
 | 
					Dockerfile
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ insert_final_newline = true
 | 
				
			|||||||
charset = utf-8
 | 
					charset = utf-8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# python
 | 
					# python
 | 
				
			||||||
[*.{py}]
 | 
					[*.py]
 | 
				
			||||||
indent_style = space
 | 
					indent_style = space
 | 
				
			||||||
indent_size = 4
 | 
					indent_size = 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,4 +25,10 @@ indent_size = 2
 | 
				
			|||||||
[*.{yaml,yml}]
 | 
					[*.{yaml,yml}]
 | 
				
			||||||
indent_style = space
 | 
					indent_style = space
 | 
				
			||||||
indent_size = 2
 | 
					indent_size = 2
 | 
				
			||||||
quote_type = single
 | 
					quote_type = single
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# JSON
 | 
				
			||||||
 | 
					[*.json]
 | 
				
			||||||
 | 
					indent_style = space
 | 
				
			||||||
 | 
					indent_size = 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								.github/PULL_REQUEST_TEMPLATE.md
									
									
									
									
										vendored
									
									
								
							@@ -1,25 +1,22 @@
 | 
				
			|||||||
# What does this implement/fix? 
 | 
					# What does this implement/fix? 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Quick description 
 | 
					Quick description and explanation of changes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Types of changes
 | 
					## Types of changes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- [ ] 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)
 | 
				
			||||||
- [ ] Configuration change (this will require users to update their yaml configuration files to keep working)
 | 
					- [ ] Other
 | 
				
			||||||
 | 
					
 | 
				
			||||||
**Related issue or feature (if applicable):** fixes <link to issue>
 | 
					**Related issue or feature (if applicable):** 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>
 | 
					**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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- [ ] ESP32
 | 
					- [ ] ESP32
 | 
				
			||||||
- [ ] ESP8266
 | 
					- [ ] ESP8266
 | 
				
			||||||
- [ ] Windows
 | 
					 | 
				
			||||||
- [ ] Mac OS
 | 
					 | 
				
			||||||
- [ ] Linux
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Example entry for `config.yaml`:
 | 
					## Example entry for `config.yaml`:
 | 
				
			||||||
<!--
 | 
					<!--
 | 
				
			||||||
@@ -34,11 +31,6 @@ Quick description
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Explain your changes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Describe your changes here to communicate to the maintainers **why we should accept this pull request**.
 | 
					 | 
				
			||||||
Very important to fill if no issue linked
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Checklist:
 | 
					## Checklist:
 | 
				
			||||||
  - [ ] The code change is tested and works locally.
 | 
					  - [ ] The code change is tested and works locally.
 | 
				
			||||||
  - [ ] Tests have been added to verify that the new code works (under `tests/` folder).
 | 
					  - [ ] Tests have been added to verify that the new code works (under `tests/` folder).
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										49
									
								
								.github/workflows/ci-docker.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										49
									
								
								.github/workflows/ci-docker.yml
									
									
									
									
										vendored
									
									
								
							@@ -3,7 +3,7 @@ name: CI for docker images
 | 
				
			|||||||
# Only run when docker paths change
 | 
					# Only run when docker paths change
 | 
				
			||||||
on:
 | 
					on:
 | 
				
			||||||
  push:
 | 
					  push:
 | 
				
			||||||
    branches: [dev, beta, master]
 | 
					    branches: [dev, beta, release]
 | 
				
			||||||
    paths:
 | 
					    paths:
 | 
				
			||||||
      - 'docker/**'
 | 
					      - 'docker/**'
 | 
				
			||||||
      - '.github/workflows/**'
 | 
					      - '.github/workflows/**'
 | 
				
			||||||
@@ -18,38 +18,23 @@ jobs:
 | 
				
			|||||||
    name: Build docker containers
 | 
					    name: Build docker containers
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    strategy:
 | 
					    strategy:
 | 
				
			||||||
      fail-fast: false
 | 
					 | 
				
			||||||
      matrix:
 | 
					      matrix:
 | 
				
			||||||
        arch: [amd64, armv7, aarch64]
 | 
					        arch: [amd64, armv7, aarch64]
 | 
				
			||||||
        build_type: ["hassio", "docker"]
 | 
					        build_type: ["ha-addon", "docker", "lint"]
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					    - uses: actions/checkout@v2
 | 
				
			||||||
      - name: Set up env variables
 | 
					    - name: Set up Python
 | 
				
			||||||
        run: |
 | 
					      uses: actions/setup-python@v2
 | 
				
			||||||
          base_version="3.0.0"
 | 
					      with:
 | 
				
			||||||
 | 
					        python-version: '3.9'
 | 
				
			||||||
 | 
					    - name: Set TAG
 | 
				
			||||||
 | 
					      run: |
 | 
				
			||||||
 | 
					        echo "TAG=check" >> $GITHUB_ENV
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if [[ "${{ matrix.build_type }}" == "hassio" ]]; then
 | 
					    - name: Run build
 | 
				
			||||||
            build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}"
 | 
					      run: |
 | 
				
			||||||
            build_to="esphome/esphome-hassio-${{ matrix.arch }}"
 | 
					        docker/build.py \
 | 
				
			||||||
            dockerfile="docker/Dockerfile.hassio"
 | 
					          --tag "${TAG}" \
 | 
				
			||||||
          else
 | 
					          --arch "${{ matrix.arch }}" \
 | 
				
			||||||
            build_from="esphome/esphome-base-${{ matrix.arch }}:${base_version}"
 | 
					          --build-type "${{ matrix.build_type }}" \
 | 
				
			||||||
            build_to="esphome/esphome-${{ matrix.arch }}"
 | 
					          build
 | 
				
			||||||
            dockerfile="docker/Dockerfile"
 | 
					 | 
				
			||||||
          fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          echo "BUILD_FROM=${build_from}" >> $GITHUB_ENV
 | 
					 | 
				
			||||||
          echo "BUILD_TO=${build_to}" >> $GITHUB_ENV
 | 
					 | 
				
			||||||
          echo "DOCKERFILE=${dockerfile}" >> $GITHUB_ENV
 | 
					 | 
				
			||||||
      - name: Pull for cache
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          docker pull "${BUILD_TO}:dev" || true
 | 
					 | 
				
			||||||
      - name: Register QEMU binfmt
 | 
					 | 
				
			||||||
        run: docker run --rm --privileged multiarch/qemu-user-static:5.2.0-2 --reset -p yes
 | 
					 | 
				
			||||||
      - run: |
 | 
					 | 
				
			||||||
          docker build \
 | 
					 | 
				
			||||||
            --build-arg "BUILD_FROM=${BUILD_FROM}" \
 | 
					 | 
				
			||||||
            --build-arg "BUILD_VERSION=ci" \
 | 
					 | 
				
			||||||
            --cache-from "${BUILD_TO}:dev" \
 | 
					 | 
				
			||||||
            --file "${DOCKERFILE}" \
 | 
					 | 
				
			||||||
            .
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										177
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										177
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							@@ -4,40 +4,36 @@ name: CI
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
on:
 | 
					on:
 | 
				
			||||||
  push:
 | 
					  push:
 | 
				
			||||||
    # On dev branch release-dev already performs CI checks
 | 
					    branches: [dev, beta, release]
 | 
				
			||||||
    # On other branches the `pull_request` trigger will be used
 | 
					 | 
				
			||||||
    branches: [beta, master]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pull_request:
 | 
					  pull_request:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  lint-clang-format:
 | 
					  ci-with-container:
 | 
				
			||||||
 | 
					    name: ${{ matrix.name }}
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    # cpp lint job runs with esphome-lint docker image so that clang-format-*
 | 
					 | 
				
			||||||
    # doesn't have to be installed
 | 
					 | 
				
			||||||
    container: esphome/esphome-lint:latest
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					 | 
				
			||||||
      # Set up the pio project so that the cpp checks know how files are compiled
 | 
					 | 
				
			||||||
      # (build flags, libraries etc)
 | 
					 | 
				
			||||||
      - name: Set up platformio environment
 | 
					 | 
				
			||||||
        run: pio init --ide atom
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Run clang-format
 | 
					 | 
				
			||||||
        run: script/clang-format -i
 | 
					 | 
				
			||||||
      - name: Suggest changes
 | 
					 | 
				
			||||||
        run: script/ci-suggest-changes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  lint-clang-tidy:
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    # cpp lint job runs with esphome-lint docker image so that clang-format-*
 | 
					 | 
				
			||||||
    # doesn't have to be installed
 | 
					 | 
				
			||||||
    container: esphome/esphome-lint:latest
 | 
					 | 
				
			||||||
    # Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files
 | 
					 | 
				
			||||||
    strategy:
 | 
					    strategy:
 | 
				
			||||||
      fail-fast: false
 | 
					      fail-fast: false
 | 
				
			||||||
      matrix:
 | 
					      matrix:
 | 
				
			||||||
        split: [1, 2, 3, 4]
 | 
					        include:
 | 
				
			||||||
 | 
					          - id: clang-format
 | 
				
			||||||
 | 
					            name: Run script/clang-format
 | 
				
			||||||
 | 
					          - id: clang-tidy
 | 
				
			||||||
 | 
					            name: Run script/clang-tidy 1/4
 | 
				
			||||||
 | 
					            split: 1
 | 
				
			||||||
 | 
					          - id: clang-tidy
 | 
				
			||||||
 | 
					            name: Run script/clang-tidy 2/4
 | 
				
			||||||
 | 
					            split: 2
 | 
				
			||||||
 | 
					          - id: clang-tidy
 | 
				
			||||||
 | 
					            name: Run script/clang-tidy 3/4
 | 
				
			||||||
 | 
					            split: 3
 | 
				
			||||||
 | 
					          - id: clang-tidy
 | 
				
			||||||
 | 
					            name: Run script/clang-tidy 4/4
 | 
				
			||||||
 | 
					            split: 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # cpp lint job runs with esphome-lint docker image so that clang-format-*
 | 
				
			||||||
 | 
					    # doesn't have to be installed
 | 
				
			||||||
 | 
					    container: ghcr.io/esphome/esphome-lint:1.1
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					      - uses: actions/checkout@v2
 | 
				
			||||||
      # Set up the pio project so that the cpp checks know how files are compiled
 | 
					      # Set up the pio project so that the cpp checks know how files are compiled
 | 
				
			||||||
@@ -45,26 +41,57 @@ jobs:
 | 
				
			|||||||
      - name: Set up platformio environment
 | 
					      - name: Set up platformio environment
 | 
				
			||||||
        run: pio init --ide atom
 | 
					        run: pio init --ide atom
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Register problem matchers
 | 
					      - name: Register problem matchers
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/clang-tidy.json"
 | 
					          echo "::add-matcher::.github/workflows/matchers/clang-tidy.json"
 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/gcc.json"
 | 
					          echo "::add-matcher::.github/workflows/matchers/gcc.json"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Run clang-format
 | 
				
			||||||
 | 
					        run: script/clang-format -i
 | 
				
			||||||
 | 
					        if: ${{ matrix.id == 'clang-format' }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Run clang-tidy
 | 
					      - name: Run clang-tidy
 | 
				
			||||||
        run: script/clang-tidy --all-headers --fix --split-num 4 --split-at ${{ matrix.split }}
 | 
					        run: script/clang-tidy --all-headers --fix --split-num 4 --split-at ${{ matrix.split }}
 | 
				
			||||||
 | 
					        if: ${{ matrix.id == 'clang-tidy' }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Suggest changes
 | 
					      - name: Suggest changes
 | 
				
			||||||
        run: script/ci-suggest-changes
 | 
					        run: script/ci-suggest-changes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  lint-python:
 | 
					  ci:
 | 
				
			||||||
    # Don't use the esphome-lint docker image because it may contain outdated requirements.
 | 
					    # Don't use the esphome-lint docker image because it may contain outdated requirements.
 | 
				
			||||||
    # This way, all dependencies are cached via the cache action.
 | 
					    # This way, all dependencies are cached via the cache action.
 | 
				
			||||||
 | 
					    name: ${{ matrix.name }}
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    strategy:
 | 
				
			||||||
 | 
					      fail-fast: false
 | 
				
			||||||
 | 
					      matrix:
 | 
				
			||||||
 | 
					        include:
 | 
				
			||||||
 | 
					          - id: ci-custom
 | 
				
			||||||
 | 
					            name: Run script/ci-custom
 | 
				
			||||||
 | 
					          - id: lint-python
 | 
				
			||||||
 | 
					            name: Run script/lint-python
 | 
				
			||||||
 | 
					          - id: test
 | 
				
			||||||
 | 
					            file: tests/test1.yaml
 | 
				
			||||||
 | 
					            name: Test tests/test1.yaml
 | 
				
			||||||
 | 
					          - id: test
 | 
				
			||||||
 | 
					            file: tests/test2.yaml
 | 
				
			||||||
 | 
					            name: Test tests/test2.yaml
 | 
				
			||||||
 | 
					          - id: test
 | 
				
			||||||
 | 
					            file: tests/test3.yaml
 | 
				
			||||||
 | 
					            name: Test tests/test3.yaml
 | 
				
			||||||
 | 
					          - id: test
 | 
				
			||||||
 | 
					            file: tests/test4.yaml
 | 
				
			||||||
 | 
					            name: Test tests/test4.yaml
 | 
				
			||||||
 | 
					          - id: pytest
 | 
				
			||||||
 | 
					            name: Run pytest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					      - uses: actions/checkout@v2
 | 
				
			||||||
      - name: Set up Python
 | 
					      - name: Set up Python
 | 
				
			||||||
        uses: actions/setup-python@v2
 | 
					        uses: actions/setup-python@v2
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          python-version: '3.7'
 | 
					          python-version: '3.7'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Cache pip modules
 | 
					      - name: Cache pip modules
 | 
				
			||||||
        uses: actions/cache@v1
 | 
					        uses: actions/cache@v1
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
@@ -72,6 +99,17 @@ jobs:
 | 
				
			|||||||
          key: esphome-pip-3.7-${{ hashFiles('setup.py') }}
 | 
					          key: esphome-pip-3.7-${{ hashFiles('setup.py') }}
 | 
				
			||||||
          restore-keys: |
 | 
					          restore-keys: |
 | 
				
			||||||
            esphome-pip-3.7-
 | 
					            esphome-pip-3.7-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # Use per test platformio cache because tests have different platform versions
 | 
				
			||||||
 | 
					      - name: Cache ~/.platformio
 | 
				
			||||||
 | 
					        uses: actions/cache@v1
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          path: ~/.platformio
 | 
				
			||||||
 | 
					          key: test-home-platformio-${{ matrix.file }}-${{ hashFiles('esphome/core/config.py') }}
 | 
				
			||||||
 | 
					          restore-keys: |
 | 
				
			||||||
 | 
					            test-home-platformio-${{ matrix.file }}-
 | 
				
			||||||
 | 
					        if: ${{ matrix.id == 'test' }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Set up python environment
 | 
					      - name: Set up python environment
 | 
				
			||||||
        run: script/setup
 | 
					        run: script/setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -80,81 +118,22 @@ jobs:
 | 
				
			|||||||
          echo "::add-matcher::.github/workflows/matchers/ci-custom.json"
 | 
					          echo "::add-matcher::.github/workflows/matchers/ci-custom.json"
 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/lint-python.json"
 | 
					          echo "::add-matcher::.github/workflows/matchers/lint-python.json"
 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/python.json"
 | 
					          echo "::add-matcher::.github/workflows/matchers/python.json"
 | 
				
			||||||
 | 
					          echo "::add-matcher::.github/workflows/matchers/pytest.json"
 | 
				
			||||||
 | 
					          echo "::add-matcher::.github/workflows/matchers/gcc.json"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Lint Custom
 | 
					      - name: Lint Custom
 | 
				
			||||||
        run: script/ci-custom.py
 | 
					        run: |
 | 
				
			||||||
 | 
					          script/ci-custom.py
 | 
				
			||||||
 | 
					          script/build_codeowners.py --check
 | 
				
			||||||
 | 
					        if: ${{ matrix.id == 'ci-custom' }}
 | 
				
			||||||
      - name: Lint Python
 | 
					      - name: Lint Python
 | 
				
			||||||
        run: script/lint-python
 | 
					        run: script/lint-python
 | 
				
			||||||
      - name: Lint CODEOWNERS
 | 
					        if: ${{ matrix.id == 'lint-python' }}
 | 
				
			||||||
        run: script/build_codeowners.py --check
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  test:
 | 
					      - run: esphome compile ${{ matrix.file }}
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					        if: ${{ matrix.id == 'test' }}
 | 
				
			||||||
    strategy:
 | 
					 | 
				
			||||||
      fail-fast: false
 | 
					 | 
				
			||||||
      matrix:
 | 
					 | 
				
			||||||
          test:
 | 
					 | 
				
			||||||
          - test1
 | 
					 | 
				
			||||||
          - test2
 | 
					 | 
				
			||||||
          - test3
 | 
					 | 
				
			||||||
          - test4
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					 | 
				
			||||||
      - name: Set up Python
 | 
					 | 
				
			||||||
        uses: actions/setup-python@v2
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          python-version: '3.7'
 | 
					 | 
				
			||||||
      - name: Cache pip modules
 | 
					 | 
				
			||||||
        uses: actions/cache@v1
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          path: ~/.cache/pip
 | 
					 | 
				
			||||||
          key: esphome-pip-3.7-${{ hashFiles('setup.py') }}
 | 
					 | 
				
			||||||
          restore-keys: |
 | 
					 | 
				
			||||||
            esphome-pip-3.7-
 | 
					 | 
				
			||||||
      # Use per test platformio cache because tests have different platform versions
 | 
					 | 
				
			||||||
      - name: Cache ~/.platformio
 | 
					 | 
				
			||||||
        uses: actions/cache@v1
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          path: ~/.platformio
 | 
					 | 
				
			||||||
          key: test-home-platformio-${{ matrix.test }}-${{ hashFiles('esphome/core/config.py') }}
 | 
					 | 
				
			||||||
          restore-keys: |
 | 
					 | 
				
			||||||
            test-home-platformio-${{ matrix.test }}-
 | 
					 | 
				
			||||||
      - name: Set up environment
 | 
					 | 
				
			||||||
        run: script/setup
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Register problem matchers
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/gcc.json"
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/python.json"
 | 
					 | 
				
			||||||
      - run: esphome tests/${{ matrix.test }}.yaml compile
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pytest:
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					 | 
				
			||||||
      - name: Set up Python
 | 
					 | 
				
			||||||
        uses: actions/setup-python@v2
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          python-version: '3.7'
 | 
					 | 
				
			||||||
      - name: Cache pip modules
 | 
					 | 
				
			||||||
        uses: actions/cache@v1
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          path: ~/.cache/pip
 | 
					 | 
				
			||||||
          key: esphome-pip-3.7-${{ hashFiles('setup.py') }}
 | 
					 | 
				
			||||||
          restore-keys: |
 | 
					 | 
				
			||||||
            esphome-pip-3.7-
 | 
					 | 
				
			||||||
      - name: Set up environment
 | 
					 | 
				
			||||||
        run: script/setup
 | 
					 | 
				
			||||||
      - name: Install Github Actions annotator
 | 
					 | 
				
			||||||
        run: pip install pytest-github-actions-annotate-failures
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Register problem matchers
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/python.json"
 | 
					 | 
				
			||||||
      - name: Run pytest
 | 
					      - name: Run pytest
 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
          pytest \
 | 
					          pytest -vv --tb=native tests
 | 
				
			||||||
            -qq \
 | 
					        if: ${{ matrix.id == 'pytest' }}
 | 
				
			||||||
            --durations=10 \
 | 
					 | 
				
			||||||
            -o console_output_style=count \
 | 
					 | 
				
			||||||
            tests
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										104
									
								
								.github/workflows/docker-lint-build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										104
									
								
								.github/workflows/docker-lint-build.yml
									
									
									
									
										vendored
									
									
								
							@@ -7,30 +7,94 @@ on:
 | 
				
			|||||||
    paths:
 | 
					    paths:
 | 
				
			||||||
      - 'docker/Dockerfile.lint'
 | 
					      - 'docker/Dockerfile.lint'
 | 
				
			||||||
      - 'requirements.txt'
 | 
					      - 'requirements.txt'
 | 
				
			||||||
 | 
					      - 'requirements_optional.txt'
 | 
				
			||||||
      - 'requirements_test.txt'
 | 
					      - 'requirements_test.txt'
 | 
				
			||||||
      - 'platformio.ini'
 | 
					      - 'platformio.ini'
 | 
				
			||||||
      - '.github/workflows/docker-lint-build.yml'
 | 
					      - '.github/workflows/docker-lint-build.yml'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  publish-docker-lint-iage:
 | 
					  deploy-docker:
 | 
				
			||||||
    name: Build docker containers
 | 
					    name: Build and publish docker containers
 | 
				
			||||||
 | 
					    if: github.repository == 'esphome/esphome'
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    strategy:
 | 
				
			||||||
 | 
					      matrix:
 | 
				
			||||||
 | 
					        arch: [amd64, armv7, aarch64]
 | 
				
			||||||
 | 
					        build_type: ["lint"]
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					    - uses: actions/checkout@v2
 | 
				
			||||||
      - name: Pull for cache
 | 
					    - name: Set up Python
 | 
				
			||||||
        run: |
 | 
					      uses: actions/setup-python@v2
 | 
				
			||||||
          docker pull "esphome/esphome-lint:latest" || true
 | 
					      with:
 | 
				
			||||||
      - name: Build
 | 
					        python-version: '3.9'
 | 
				
			||||||
        run: |
 | 
					    - name: Set TAG
 | 
				
			||||||
          docker build \
 | 
					      run: |
 | 
				
			||||||
            --cache-from "esphome/esphome-lint:latest" \
 | 
					        echo "TAG=1.1" >> $GITHUB_ENV
 | 
				
			||||||
            --file "docker/Dockerfile.lint" \
 | 
					
 | 
				
			||||||
            --tag "esphome/esphome-lint:latest" \
 | 
					    - name: Run build
 | 
				
			||||||
            .
 | 
					      run: |
 | 
				
			||||||
      - name: Log in to docker hub
 | 
					        docker/build.py \
 | 
				
			||||||
        env:
 | 
					          --tag "${TAG}" \
 | 
				
			||||||
          DOCKER_USER: ${{ secrets.DOCKER_USER }}
 | 
					          --arch "${{ matrix.arch }}" \
 | 
				
			||||||
          DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
 | 
					          --build-type "${{ matrix.build_type }}" \
 | 
				
			||||||
        run: docker login -u "${DOCKER_USER}" -p "${DOCKER_PASSWORD}"
 | 
					          build
 | 
				
			||||||
      - run: |
 | 
					
 | 
				
			||||||
          docker push "esphome/esphome-lint:latest"
 | 
					    - name: Log in to docker hub
 | 
				
			||||||
 | 
					      uses: docker/login-action@v1
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        username: ${{ secrets.DOCKER_USER }}
 | 
				
			||||||
 | 
					        password: ${{ secrets.DOCKER_PASSWORD }}
 | 
				
			||||||
 | 
					    - name: Log in to the GitHub container registry
 | 
				
			||||||
 | 
					      uses: docker/login-action@v1
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					          registry: ghcr.io
 | 
				
			||||||
 | 
					          username: ${{ github.actor }}
 | 
				
			||||||
 | 
					          password: ${{ secrets.GITHUB_TOKEN }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: Run push
 | 
				
			||||||
 | 
					      run: |
 | 
				
			||||||
 | 
					        docker/build.py \
 | 
				
			||||||
 | 
					          --tag "${TAG}" \
 | 
				
			||||||
 | 
					          --arch "${{ matrix.arch }}" \
 | 
				
			||||||
 | 
					          --build-type "${{ matrix.build_type }}" \
 | 
				
			||||||
 | 
					          push
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  deploy-docker-manifest:
 | 
				
			||||||
 | 
					    if: github.repository == 'esphome/esphome'
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					    needs: [deploy-docker]
 | 
				
			||||||
 | 
					    strategy:
 | 
				
			||||||
 | 
					      matrix:
 | 
				
			||||||
 | 
					        build_type: ["lint"]
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					    - uses: actions/checkout@v2
 | 
				
			||||||
 | 
					    - name: Set up Python
 | 
				
			||||||
 | 
					      uses: actions/setup-python@v2
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        python-version: '3.9'
 | 
				
			||||||
 | 
					    - name: Set TAG
 | 
				
			||||||
 | 
					      run: |
 | 
				
			||||||
 | 
					        echo "TAG=1.1" >> $GITHUB_ENV
 | 
				
			||||||
 | 
					    - name: Enable experimental manifest support
 | 
				
			||||||
 | 
					      run: |
 | 
				
			||||||
 | 
					        mkdir -p ~/.docker
 | 
				
			||||||
 | 
					        echo "{\"experimental\": \"enabled\"}" > ~/.docker/config.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: Log in to docker hub
 | 
				
			||||||
 | 
					      uses: docker/login-action@v1
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        username: ${{ secrets.DOCKER_USER }}
 | 
				
			||||||
 | 
					        password: ${{ secrets.DOCKER_PASSWORD }}
 | 
				
			||||||
 | 
					    - name: Log in to the GitHub container registry
 | 
				
			||||||
 | 
					      uses: docker/login-action@v1
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					          registry: ghcr.io
 | 
				
			||||||
 | 
					          username: ${{ github.actor }}
 | 
				
			||||||
 | 
					          password: ${{ secrets.GITHUB_TOKEN }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: Run manifest
 | 
				
			||||||
 | 
					      run: |
 | 
				
			||||||
 | 
					        docker/build.py \
 | 
				
			||||||
 | 
					          --tag "${TAG}" \
 | 
				
			||||||
 | 
					          --build-type "${{ matrix.build_type }}" \
 | 
				
			||||||
 | 
					          manifest
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								.github/workflows/matchers/pytest.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								.github/workflows/matchers/pytest.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "problemMatcher": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "owner": "pytest",
 | 
				
			||||||
 | 
					      "fileLocation": "absolute",
 | 
				
			||||||
 | 
					      "pattern": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "regexp": "^\\s+File \"(.*)\", line (\\d+), in (.*)$",
 | 
				
			||||||
 | 
					          "file": 1,
 | 
				
			||||||
 | 
					          "line": 2
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "regexp": "^\\s+(.*)$",
 | 
				
			||||||
 | 
					          "message": 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										246
									
								
								.github/workflows/release-dev.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										246
									
								
								.github/workflows/release-dev.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,246 +0,0 @@
 | 
				
			|||||||
name: Publish dev releases to docker hub
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
on:
 | 
					 | 
				
			||||||
  push:
 | 
					 | 
				
			||||||
    branches:
 | 
					 | 
				
			||||||
    - dev
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
jobs:
 | 
					 | 
				
			||||||
  # THE LINT/TEST JOBS ARE COPIED FROM ci.yaml
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  lint-clang-format:
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    # cpp lint job runs with esphome-lint docker image so that clang-format-*
 | 
					 | 
				
			||||||
    # doesn't have to be installed
 | 
					 | 
				
			||||||
    container: esphome/esphome-lint:latest
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					 | 
				
			||||||
      # Set up the pio project so that the cpp checks know how files are compiled
 | 
					 | 
				
			||||||
      # (build flags, libraries etc)
 | 
					 | 
				
			||||||
      - name: Set up platformio environment
 | 
					 | 
				
			||||||
        run: pio init --ide atom
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Run clang-format
 | 
					 | 
				
			||||||
        run: script/clang-format -i
 | 
					 | 
				
			||||||
      - name: Suggest changes
 | 
					 | 
				
			||||||
        run: script/ci-suggest-changes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  lint-clang-tidy:
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    # cpp lint job runs with esphome-lint docker image so that clang-format-*
 | 
					 | 
				
			||||||
    # doesn't have to be installed
 | 
					 | 
				
			||||||
    container: esphome/esphome-lint:latest
 | 
					 | 
				
			||||||
    # Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files
 | 
					 | 
				
			||||||
    strategy:
 | 
					 | 
				
			||||||
      fail-fast: false
 | 
					 | 
				
			||||||
      matrix:
 | 
					 | 
				
			||||||
        split: [1, 2, 3, 4]
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					 | 
				
			||||||
      # Set up the pio project so that the cpp checks know how files are compiled
 | 
					 | 
				
			||||||
      # (build flags, libraries etc)
 | 
					 | 
				
			||||||
      - name: Set up platformio environment
 | 
					 | 
				
			||||||
        run: pio init --ide atom
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Register problem matchers
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/clang-tidy.json"
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/gcc.json"
 | 
					 | 
				
			||||||
      - name: Run clang-tidy
 | 
					 | 
				
			||||||
        run: script/clang-tidy --all-headers --fix --split-num 4 --split-at ${{ matrix.split }}
 | 
					 | 
				
			||||||
      - name: Suggest changes
 | 
					 | 
				
			||||||
        run: script/ci-suggest-changes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  lint-python:
 | 
					 | 
				
			||||||
    # Don't use the esphome-lint docker image because it may contain outdated requirements.
 | 
					 | 
				
			||||||
    # This way, all dependencies are cached via the cache action.
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					 | 
				
			||||||
      - name: Set up Python
 | 
					 | 
				
			||||||
        uses: actions/setup-python@v2
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          python-version: '3.7'
 | 
					 | 
				
			||||||
      - name: Cache pip modules
 | 
					 | 
				
			||||||
        uses: actions/cache@v1
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          path: ~/.cache/pip
 | 
					 | 
				
			||||||
          key: esphome-pip-3.7-${{ hashFiles('setup.py') }}
 | 
					 | 
				
			||||||
          restore-keys: |
 | 
					 | 
				
			||||||
            esphome-pip-3.7-
 | 
					 | 
				
			||||||
      - name: Set up python environment
 | 
					 | 
				
			||||||
        run: script/setup
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Register problem matchers
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/ci-custom.json"
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/lint-python.json"
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/python.json"
 | 
					 | 
				
			||||||
      - name: Lint Custom
 | 
					 | 
				
			||||||
        run: script/ci-custom.py
 | 
					 | 
				
			||||||
      - name: Lint Python
 | 
					 | 
				
			||||||
        run: script/lint-python
 | 
					 | 
				
			||||||
      - name: Lint CODEOWNERS
 | 
					 | 
				
			||||||
        run: script/build_codeowners.py --check
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  test:
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    strategy:
 | 
					 | 
				
			||||||
      fail-fast: false
 | 
					 | 
				
			||||||
      matrix:
 | 
					 | 
				
			||||||
          test:
 | 
					 | 
				
			||||||
          - test1
 | 
					 | 
				
			||||||
          - test2
 | 
					 | 
				
			||||||
          - test3
 | 
					 | 
				
			||||||
          - test4
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					 | 
				
			||||||
      - name: Set up Python
 | 
					 | 
				
			||||||
        uses: actions/setup-python@v2
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          python-version: '3.7'
 | 
					 | 
				
			||||||
      - name: Cache pip modules
 | 
					 | 
				
			||||||
        uses: actions/cache@v1
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          path: ~/.cache/pip
 | 
					 | 
				
			||||||
          key: esphome-pip-3.7-${{ hashFiles('setup.py') }}
 | 
					 | 
				
			||||||
          restore-keys: |
 | 
					 | 
				
			||||||
            esphome-pip-3.7-
 | 
					 | 
				
			||||||
      # Use per test platformio cache because tests have different platform versions
 | 
					 | 
				
			||||||
      - name: Cache ~/.platformio
 | 
					 | 
				
			||||||
        uses: actions/cache@v1
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          path: ~/.platformio
 | 
					 | 
				
			||||||
          key: test-home-platformio-${{ matrix.test }}-${{ hashFiles('esphome/core/config.py') }}
 | 
					 | 
				
			||||||
          restore-keys: |
 | 
					 | 
				
			||||||
            test-home-platformio-${{ matrix.test }}-
 | 
					 | 
				
			||||||
      - name: Set up environment
 | 
					 | 
				
			||||||
        run: script/setup
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Register problem matchers
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/gcc.json"
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/python.json"
 | 
					 | 
				
			||||||
      - run: esphome tests/${{ matrix.test }}.yaml compile
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pytest:
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					 | 
				
			||||||
      - name: Set up Python
 | 
					 | 
				
			||||||
        uses: actions/setup-python@v2
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          python-version: '3.7'
 | 
					 | 
				
			||||||
      - name: Cache pip modules
 | 
					 | 
				
			||||||
        uses: actions/cache@v1
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          path: ~/.cache/pip
 | 
					 | 
				
			||||||
          key: esphome-pip-3.7-${{ hashFiles('setup.py') }}
 | 
					 | 
				
			||||||
          restore-keys: |
 | 
					 | 
				
			||||||
            esphome-pip-3.7-
 | 
					 | 
				
			||||||
      - name: Set up environment
 | 
					 | 
				
			||||||
        run: script/setup
 | 
					 | 
				
			||||||
      - name: Install Github Actions annotator
 | 
					 | 
				
			||||||
        run: pip install pytest-github-actions-annotate-failures
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Register problem matchers
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/python.json"
 | 
					 | 
				
			||||||
      - name: Run pytest
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          pytest \
 | 
					 | 
				
			||||||
            -qq \
 | 
					 | 
				
			||||||
            --durations=10 \
 | 
					 | 
				
			||||||
            -o console_output_style=count \
 | 
					 | 
				
			||||||
            tests
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  deploy-docker:
 | 
					 | 
				
			||||||
    name: Build and publish docker containers
 | 
					 | 
				
			||||||
    if: github.repository == 'esphome/esphome'
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    needs: [lint-clang-format, lint-clang-tidy, lint-python, test, pytest]
 | 
					 | 
				
			||||||
    strategy:
 | 
					 | 
				
			||||||
      matrix:
 | 
					 | 
				
			||||||
        arch: [amd64, armv7, aarch64]
 | 
					 | 
				
			||||||
        # Hassio dev image doesn't use esphome/esphome-hassio-$arch and uses base directly
 | 
					 | 
				
			||||||
        build_type: ["docker"]
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					 | 
				
			||||||
      - name: Set TAG
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          TAG="${GITHUB_SHA:0:7}"
 | 
					 | 
				
			||||||
          echo "TAG=${TAG}" >> $GITHUB_ENV
 | 
					 | 
				
			||||||
      - name: Set up env variables
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          base_version="3.0.0"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          if [[ "${{ matrix.build_type }}" == "hassio" ]]; then
 | 
					 | 
				
			||||||
            build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}"
 | 
					 | 
				
			||||||
            build_to="esphome/esphome-hassio-${{ matrix.arch }}"
 | 
					 | 
				
			||||||
            dockerfile="docker/Dockerfile.hassio"
 | 
					 | 
				
			||||||
          else
 | 
					 | 
				
			||||||
            build_from="esphome/esphome-base-${{ matrix.arch }}:${base_version}"
 | 
					 | 
				
			||||||
            build_to="esphome/esphome-${{ matrix.arch }}"
 | 
					 | 
				
			||||||
            dockerfile="docker/Dockerfile"
 | 
					 | 
				
			||||||
          fi
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          echo "BUILD_FROM=${build_from}" >> $GITHUB_ENV
 | 
					 | 
				
			||||||
          echo "BUILD_TO=${build_to}" >> $GITHUB_ENV
 | 
					 | 
				
			||||||
          echo "DOCKERFILE=${dockerfile}" >> $GITHUB_ENV
 | 
					 | 
				
			||||||
      - name: Pull for cache
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          docker pull "${BUILD_TO}:dev" || true
 | 
					 | 
				
			||||||
      - name: Register QEMU binfmt
 | 
					 | 
				
			||||||
        run: docker run --rm --privileged multiarch/qemu-user-static:5.2.0-2 --reset -p yes
 | 
					 | 
				
			||||||
      - run: |
 | 
					 | 
				
			||||||
          docker build \
 | 
					 | 
				
			||||||
            --build-arg "BUILD_FROM=${BUILD_FROM}" \
 | 
					 | 
				
			||||||
            --build-arg "BUILD_VERSION=${TAG}" \
 | 
					 | 
				
			||||||
            --tag "${BUILD_TO}:${TAG}" \
 | 
					 | 
				
			||||||
            --tag "${BUILD_TO}:dev" \
 | 
					 | 
				
			||||||
            --cache-from "${BUILD_TO}:dev" \
 | 
					 | 
				
			||||||
            --file "${DOCKERFILE}" \
 | 
					 | 
				
			||||||
            .
 | 
					 | 
				
			||||||
      - name: Log in to docker hub
 | 
					 | 
				
			||||||
        env:
 | 
					 | 
				
			||||||
          DOCKER_USER: ${{ secrets.DOCKER_USER }}
 | 
					 | 
				
			||||||
          DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
 | 
					 | 
				
			||||||
        run: docker login -u "${DOCKER_USER}" -p "${DOCKER_PASSWORD}"
 | 
					 | 
				
			||||||
      - run: |
 | 
					 | 
				
			||||||
          docker push "${BUILD_TO}:${TAG}"
 | 
					 | 
				
			||||||
          docker push "${BUILD_TO}:dev"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  deploy-docker-manifest:
 | 
					 | 
				
			||||||
    if: github.repository == 'esphome/esphome'
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    needs: [deploy-docker]
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
    - name: Enable experimental manifest support
 | 
					 | 
				
			||||||
      run: |
 | 
					 | 
				
			||||||
        mkdir -p ~/.docker
 | 
					 | 
				
			||||||
        echo "{\"experimental\": \"enabled\"}" > ~/.docker/config.json
 | 
					 | 
				
			||||||
    - name: Set TAG
 | 
					 | 
				
			||||||
      run: |
 | 
					 | 
				
			||||||
        TAG="${GITHUB_SHA:0:7}"
 | 
					 | 
				
			||||||
        echo "TAG=${TAG}" >> $GITHUB_ENV
 | 
					 | 
				
			||||||
    - name: Log in to docker hub
 | 
					 | 
				
			||||||
      env:
 | 
					 | 
				
			||||||
        DOCKER_USER: ${{ secrets.DOCKER_USER }}
 | 
					 | 
				
			||||||
        DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
 | 
					 | 
				
			||||||
      run: docker login -u "${DOCKER_USER}" -p "${DOCKER_PASSWORD}"
 | 
					 | 
				
			||||||
    - name: "Create the manifest"
 | 
					 | 
				
			||||||
      run: |
 | 
					 | 
				
			||||||
        docker manifest create esphome/esphome:${TAG} \
 | 
					 | 
				
			||||||
          esphome/esphome-aarch64:${TAG} \
 | 
					 | 
				
			||||||
          esphome/esphome-amd64:${TAG} \
 | 
					 | 
				
			||||||
          esphome/esphome-armv7:${TAG}
 | 
					 | 
				
			||||||
        docker manifest push esphome/esphome:${TAG}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        docker manifest create esphome/esphome:dev \
 | 
					 | 
				
			||||||
          esphome/esphome-aarch64:${TAG} \
 | 
					 | 
				
			||||||
          esphome/esphome-amd64:${TAG} \
 | 
					 | 
				
			||||||
          esphome/esphome-armv7:${TAG}
 | 
					 | 
				
			||||||
        docker manifest push esphome/esphome:dev
 | 
					 | 
				
			||||||
							
								
								
									
										316
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										316
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@@ -1,163 +1,35 @@
 | 
				
			|||||||
name: Publish Release
 | 
					name: Publish Release
 | 
				
			||||||
 | 
					
 | 
				
			||||||
on:
 | 
					on:
 | 
				
			||||||
 | 
					  workflow_dispatch:
 | 
				
			||||||
  release:
 | 
					  release:
 | 
				
			||||||
    types: [published]
 | 
					    types: [published]
 | 
				
			||||||
 | 
					  schedule:
 | 
				
			||||||
 | 
					    - cron: "0 2 * * *"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  # THE LINT/TEST JOBS ARE COPIED FROM ci.yaml
 | 
					  init:
 | 
				
			||||||
 | 
					    name: Initialize build
 | 
				
			||||||
  lint-clang-format:
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    # cpp lint job runs with esphome-lint docker image so that clang-format-*
 | 
					    outputs:
 | 
				
			||||||
    # doesn't have to be installed
 | 
					      tag: ${{ steps.tag.outputs.tag }}
 | 
				
			||||||
    container: esphome/esphome-lint:latest
 | 
					 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					      - uses: actions/checkout@v2
 | 
				
			||||||
      # Set up the pio project so that the cpp checks know how files are compiled
 | 
					      - name: Get tag
 | 
				
			||||||
      # (build flags, libraries etc)
 | 
					        id: tag
 | 
				
			||||||
      - name: Set up platformio environment
 | 
					 | 
				
			||||||
        run: pio init --ide atom
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Run clang-format
 | 
					 | 
				
			||||||
        run: script/clang-format -i
 | 
					 | 
				
			||||||
      - name: Suggest changes
 | 
					 | 
				
			||||||
        run: script/ci-suggest-changes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  lint-clang-tidy:
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    # cpp lint job runs with esphome-lint docker image so that clang-format-*
 | 
					 | 
				
			||||||
    # doesn't have to be installed
 | 
					 | 
				
			||||||
    container: esphome/esphome-lint:latest
 | 
					 | 
				
			||||||
    # Split clang-tidy check into 4 jobs. Each one will check 1/4th of the .cpp files
 | 
					 | 
				
			||||||
    strategy:
 | 
					 | 
				
			||||||
      fail-fast: false
 | 
					 | 
				
			||||||
      matrix:
 | 
					 | 
				
			||||||
        split: [1, 2, 3, 4]
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					 | 
				
			||||||
      # Set up the pio project so that the cpp checks know how files are compiled
 | 
					 | 
				
			||||||
      # (build flags, libraries etc)
 | 
					 | 
				
			||||||
      - name: Set up platformio environment
 | 
					 | 
				
			||||||
        run: pio init --ide atom
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Register problem matchers
 | 
					 | 
				
			||||||
        run: |
 | 
					        run: |
 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/clang-tidy.json"
 | 
					          if [[ "$GITHUB_EVENT_NAME" = "release" ]]; then
 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/gcc.json"
 | 
					            TAG="${GITHUB_REF#refs/tags/v}"
 | 
				
			||||||
      - name: Run clang-tidy
 | 
					          else
 | 
				
			||||||
        run: script/clang-tidy --all-headers --fix --split-num 4 --split-at ${{ matrix.split }}
 | 
					            TAG=$(cat esphome/const.py | sed -n -E "s/^__version__\s+=\s+\"(.+)\"$/\1/p")
 | 
				
			||||||
      - name: Suggest changes
 | 
					            today="$(date --utc '+%Y%m%d')"
 | 
				
			||||||
        run: script/ci-suggest-changes
 | 
					            TAG="${TAG}${today}"
 | 
				
			||||||
 | 
					          fi
 | 
				
			||||||
  lint-python:
 | 
					          echo "::set-output name=tag::${TAG}"
 | 
				
			||||||
    # Don't use the esphome-lint docker image because it may contain outdated requirements.
 | 
					 | 
				
			||||||
    # This way, all dependencies are cached via the cache action.
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					 | 
				
			||||||
      - name: Set up Python
 | 
					 | 
				
			||||||
        uses: actions/setup-python@v2
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          python-version: '3.7'
 | 
					 | 
				
			||||||
      - name: Cache pip modules
 | 
					 | 
				
			||||||
        uses: actions/cache@v1
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          path: ~/.cache/pip
 | 
					 | 
				
			||||||
          key: esphome-pip-3.7-${{ hashFiles('setup.py') }}
 | 
					 | 
				
			||||||
          restore-keys: |
 | 
					 | 
				
			||||||
            esphome-pip-3.7-
 | 
					 | 
				
			||||||
      - name: Set up python environment
 | 
					 | 
				
			||||||
        run: script/setup
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Register problem matchers
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/ci-custom.json"
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/lint-python.json"
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/python.json"
 | 
					 | 
				
			||||||
      - name: Lint Custom
 | 
					 | 
				
			||||||
        run: script/ci-custom.py
 | 
					 | 
				
			||||||
      - name: Lint Python
 | 
					 | 
				
			||||||
        run: script/lint-python
 | 
					 | 
				
			||||||
      - name: Lint CODEOWNERS
 | 
					 | 
				
			||||||
        run: script/build_codeowners.py --check
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  test:
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    strategy:
 | 
					 | 
				
			||||||
      fail-fast: false
 | 
					 | 
				
			||||||
      matrix:
 | 
					 | 
				
			||||||
          test:
 | 
					 | 
				
			||||||
          - test1
 | 
					 | 
				
			||||||
          - test2
 | 
					 | 
				
			||||||
          - test3
 | 
					 | 
				
			||||||
          - test4
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					 | 
				
			||||||
      - name: Set up Python
 | 
					 | 
				
			||||||
        uses: actions/setup-python@v2
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          python-version: '3.7'
 | 
					 | 
				
			||||||
      - name: Cache pip modules
 | 
					 | 
				
			||||||
        uses: actions/cache@v1
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          path: ~/.cache/pip
 | 
					 | 
				
			||||||
          key: esphome-pip-3.7-${{ hashFiles('setup.py') }}
 | 
					 | 
				
			||||||
          restore-keys: |
 | 
					 | 
				
			||||||
            esphome-pip-3.7-
 | 
					 | 
				
			||||||
      # Use per test platformio cache because tests have different platform versions
 | 
					 | 
				
			||||||
      - name: Cache ~/.platformio
 | 
					 | 
				
			||||||
        uses: actions/cache@v1
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          path: ~/.platformio
 | 
					 | 
				
			||||||
          key: test-home-platformio-${{ matrix.test }}-${{ hashFiles('esphome/core/config.py') }}
 | 
					 | 
				
			||||||
          restore-keys: |
 | 
					 | 
				
			||||||
            test-home-platformio-${{ matrix.test }}-
 | 
					 | 
				
			||||||
      - name: Set up environment
 | 
					 | 
				
			||||||
        run: script/setup
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Register problem matchers
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/gcc.json"
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/python.json"
 | 
					 | 
				
			||||||
      - run: esphome tests/${{ matrix.test }}.yaml compile
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  pytest:
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					 | 
				
			||||||
      - name: Set up Python
 | 
					 | 
				
			||||||
        uses: actions/setup-python@v2
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          python-version: '3.7'
 | 
					 | 
				
			||||||
      - name: Cache pip modules
 | 
					 | 
				
			||||||
        uses: actions/cache@v1
 | 
					 | 
				
			||||||
        with:
 | 
					 | 
				
			||||||
          path: ~/.cache/pip
 | 
					 | 
				
			||||||
          key: esphome-pip-3.7-${{ hashFiles('setup.py') }}
 | 
					 | 
				
			||||||
          restore-keys: |
 | 
					 | 
				
			||||||
            esphome-pip-3.7-
 | 
					 | 
				
			||||||
      - name: Set up environment
 | 
					 | 
				
			||||||
        run: script/setup
 | 
					 | 
				
			||||||
      - name: Install Github Actions annotator
 | 
					 | 
				
			||||||
        run: pip install pytest-github-actions-annotate-failures
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - name: Register problem matchers
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          echo "::add-matcher::.github/workflows/matchers/python.json"
 | 
					 | 
				
			||||||
      - name: Run pytest
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          pytest \
 | 
					 | 
				
			||||||
            -qq \
 | 
					 | 
				
			||||||
            --durations=10 \
 | 
					 | 
				
			||||||
            -o console_output_style=count \
 | 
					 | 
				
			||||||
            tests
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  deploy-pypi:
 | 
					  deploy-pypi:
 | 
				
			||||||
    name: Build and publish to PyPi
 | 
					    name: Build and publish to PyPi
 | 
				
			||||||
    if: github.repository == 'esphome/esphome'
 | 
					    if: github.repository == 'esphome/esphome' && github.event_name == 'release'
 | 
				
			||||||
    needs: [lint-clang-format, lint-clang-tidy, lint-python, test, pytest]
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					      - uses: actions/checkout@v2
 | 
				
			||||||
@@ -181,119 +53,85 @@ jobs:
 | 
				
			|||||||
    name: Build and publish docker containers
 | 
					    name: Build and publish docker containers
 | 
				
			||||||
    if: github.repository == 'esphome/esphome'
 | 
					    if: github.repository == 'esphome/esphome'
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    needs: [lint-clang-format, lint-clang-tidy, lint-python, test, pytest]
 | 
					    needs: [init]
 | 
				
			||||||
    strategy:
 | 
					    strategy:
 | 
				
			||||||
      matrix:
 | 
					      matrix:
 | 
				
			||||||
        arch: [amd64, armv7, aarch64]
 | 
					        arch: [amd64, armv7, aarch64]
 | 
				
			||||||
        build_type: ["hassio", "docker"]
 | 
					        build_type: ["ha-addon", "docker"]
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
      - uses: actions/checkout@v2
 | 
					    - uses: actions/checkout@v2
 | 
				
			||||||
      - name: Set TAG
 | 
					    - name: Set up Python
 | 
				
			||||||
        run: |
 | 
					      uses: actions/setup-python@v2
 | 
				
			||||||
          TAG="${GITHUB_REF#refs/tags/v}"
 | 
					      with:
 | 
				
			||||||
          echo "TAG=${TAG}" >> $GITHUB_ENV
 | 
					        python-version: '3.9'
 | 
				
			||||||
      - name: Set up env variables
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          base_version="3.0.0"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if [[ "${{ matrix.build_type }}" == "hassio" ]]; then
 | 
					    - name: Run build
 | 
				
			||||||
            build_from="esphome/esphome-hassio-base-${{ matrix.arch }}:${base_version}"
 | 
					      run: |
 | 
				
			||||||
            build_to="esphome/esphome-hassio-${{ matrix.arch }}"
 | 
					        docker/build.py \
 | 
				
			||||||
            dockerfile="docker/Dockerfile.hassio"
 | 
					          --tag "${{ needs.init.outputs.tag }}" \
 | 
				
			||||||
          else
 | 
					          --arch "${{ matrix.arch }}" \
 | 
				
			||||||
            build_from="esphome/esphome-base-${{ matrix.arch }}:${base_version}"
 | 
					          --build-type "${{ matrix.build_type }}" \
 | 
				
			||||||
            build_to="esphome/esphome-${{ matrix.arch }}"
 | 
					          build
 | 
				
			||||||
            dockerfile="docker/Dockerfile"
 | 
					 | 
				
			||||||
          fi
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if [[ "${{ github.event.release.prerelease }}" == "true" ]]; then
 | 
					    - name: Log in to docker hub
 | 
				
			||||||
            cache_tag="beta"
 | 
					      uses: docker/login-action@v1
 | 
				
			||||||
          else
 | 
					      with:
 | 
				
			||||||
            cache_tag="latest"
 | 
					        username: ${{ secrets.DOCKER_USER }}
 | 
				
			||||||
          fi
 | 
					        password: ${{ secrets.DOCKER_PASSWORD }}
 | 
				
			||||||
 | 
					    - name: Log in to the GitHub container registry
 | 
				
			||||||
 | 
					      uses: docker/login-action@v1
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					          registry: ghcr.io
 | 
				
			||||||
 | 
					          username: ${{ github.actor }}
 | 
				
			||||||
 | 
					          password: ${{ secrets.GITHUB_TOKEN }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          # Set env variables so these values don't need to be calculated again
 | 
					    - name: Run push
 | 
				
			||||||
          echo "BUILD_FROM=${build_from}" >> $GITHUB_ENV
 | 
					      run: |
 | 
				
			||||||
          echo "BUILD_TO=${build_to}" >> $GITHUB_ENV
 | 
					        docker/build.py \
 | 
				
			||||||
          echo "DOCKERFILE=${dockerfile}" >> $GITHUB_ENV
 | 
					          --tag "${{ needs.init.outputs.tag }}" \
 | 
				
			||||||
          echo "CACHE_TAG=${cache_tag}" >> $GITHUB_ENV
 | 
					          --arch "${{ matrix.arch }}" \
 | 
				
			||||||
      - name: Pull for cache
 | 
					          --build-type "${{ matrix.build_type }}" \
 | 
				
			||||||
        run: |
 | 
					          push
 | 
				
			||||||
          docker pull "${BUILD_TO}:${CACHE_TAG}" || true
 | 
					 | 
				
			||||||
      - name: Register QEMU binfmt
 | 
					 | 
				
			||||||
        run: docker run --rm --privileged multiarch/qemu-user-static:5.2.0-2 --reset -p yes
 | 
					 | 
				
			||||||
      - run: |
 | 
					 | 
				
			||||||
          docker build \
 | 
					 | 
				
			||||||
            --build-arg "BUILD_FROM=${BUILD_FROM}" \
 | 
					 | 
				
			||||||
            --build-arg "BUILD_VERSION=${TAG}" \
 | 
					 | 
				
			||||||
            --tag "${BUILD_TO}:${TAG}" \
 | 
					 | 
				
			||||||
            --cache-from "${BUILD_TO}:${CACHE_TAG}" \
 | 
					 | 
				
			||||||
            --file "${DOCKERFILE}" \
 | 
					 | 
				
			||||||
            .
 | 
					 | 
				
			||||||
      - name: Log in to docker hub
 | 
					 | 
				
			||||||
        env:
 | 
					 | 
				
			||||||
          DOCKER_USER: ${{ secrets.DOCKER_USER }}
 | 
					 | 
				
			||||||
          DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
 | 
					 | 
				
			||||||
        run: docker login -u "${DOCKER_USER}" -p "${DOCKER_PASSWORD}"
 | 
					 | 
				
			||||||
      - run: docker push "${BUILD_TO}:${TAG}"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      # Always publish to beta tag (also full releases)
 | 
					 | 
				
			||||||
      - name: Publish docker beta tag
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          docker tag "${BUILD_TO}:${TAG}" "${BUILD_TO}:beta"
 | 
					 | 
				
			||||||
          docker push "${BUILD_TO}:beta"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      - if: ${{ !github.event.release.prerelease }}
 | 
					 | 
				
			||||||
        name: Publish docker latest tag
 | 
					 | 
				
			||||||
        run: |
 | 
					 | 
				
			||||||
          docker tag "${BUILD_TO}:${TAG}" "${BUILD_TO}:latest"
 | 
					 | 
				
			||||||
          docker push "${BUILD_TO}:latest"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  deploy-docker-manifest:
 | 
					  deploy-docker-manifest:
 | 
				
			||||||
    if: github.repository == 'esphome/esphome'
 | 
					    if: github.repository == 'esphome/esphome'
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    needs: [deploy-docker]
 | 
					    needs: [init, deploy-docker]
 | 
				
			||||||
 | 
					    strategy:
 | 
				
			||||||
 | 
					      matrix:
 | 
				
			||||||
 | 
					        build_type: ["ha-addon", "docker"]
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
 | 
					    - uses: actions/checkout@v2
 | 
				
			||||||
 | 
					    - name: Set up Python
 | 
				
			||||||
 | 
					      uses: actions/setup-python@v2
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        python-version: '3.9'
 | 
				
			||||||
    - name: Enable experimental manifest support
 | 
					    - name: Enable experimental manifest support
 | 
				
			||||||
      run: |
 | 
					      run: |
 | 
				
			||||||
        mkdir -p ~/.docker
 | 
					        mkdir -p ~/.docker
 | 
				
			||||||
        echo "{\"experimental\": \"enabled\"}" > ~/.docker/config.json
 | 
					        echo "{\"experimental\": \"enabled\"}" > ~/.docker/config.json
 | 
				
			||||||
    - name: Set TAG
 | 
					
 | 
				
			||||||
      run: |
 | 
					 | 
				
			||||||
        TAG="${GITHUB_REF#refs/tags/v}"
 | 
					 | 
				
			||||||
        echo "TAG=${TAG}" >> $GITHUB_ENV
 | 
					 | 
				
			||||||
    - name: Log in to docker hub
 | 
					    - name: Log in to docker hub
 | 
				
			||||||
      env:
 | 
					      uses: docker/login-action@v1
 | 
				
			||||||
        DOCKER_USER: ${{ secrets.DOCKER_USER }}
 | 
					      with:
 | 
				
			||||||
        DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
 | 
					        username: ${{ secrets.DOCKER_USER }}
 | 
				
			||||||
      run: docker login -u "${DOCKER_USER}" -p "${DOCKER_PASSWORD}"
 | 
					        password: ${{ secrets.DOCKER_PASSWORD }}
 | 
				
			||||||
    - name: "Create the manifest"
 | 
					    - name: Log in to the GitHub container registry
 | 
				
			||||||
      run: |
 | 
					      uses: docker/login-action@v1
 | 
				
			||||||
        docker manifest create esphome/esphome:${TAG} \
 | 
					      with:
 | 
				
			||||||
          esphome/esphome-aarch64:${TAG} \
 | 
					          registry: ghcr.io
 | 
				
			||||||
          esphome/esphome-amd64:${TAG} \
 | 
					          username: ${{ github.actor }}
 | 
				
			||||||
          esphome/esphome-armv7:${TAG}
 | 
					          password: ${{ secrets.GITHUB_TOKEN }}
 | 
				
			||||||
        docker manifest push esphome/esphome:${TAG}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - name: Publish docker beta tag
 | 
					    - name: Run manifest
 | 
				
			||||||
      run: |
 | 
					      run: |
 | 
				
			||||||
        docker manifest create esphome/esphome:beta \
 | 
					        docker/build.py \
 | 
				
			||||||
          esphome/esphome-aarch64:${TAG} \
 | 
					          --tag "${{ needs.init.outputs.tag }}" \
 | 
				
			||||||
          esphome/esphome-amd64:${TAG} \
 | 
					          --build-type "${{ matrix.build_type }}" \
 | 
				
			||||||
          esphome/esphome-armv7:${TAG}
 | 
					          manifest
 | 
				
			||||||
        docker manifest push esphome/esphome:beta
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    - name: Publish docker latest tag
 | 
					 | 
				
			||||||
      if: ${{ !github.event.release.prerelease }}
 | 
					 | 
				
			||||||
      run: |
 | 
					 | 
				
			||||||
        docker manifest create esphome/esphome:latest \
 | 
					 | 
				
			||||||
          esphome/esphome-aarch64:${TAG} \
 | 
					 | 
				
			||||||
          esphome/esphome-amd64:${TAG} \
 | 
					 | 
				
			||||||
          esphome/esphome-armv7:${TAG}
 | 
					 | 
				
			||||||
        docker manifest push esphome/esphome:latest
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  deploy-hassio-repo:
 | 
					  deploy-hassio-repo:
 | 
				
			||||||
    if: github.repository == 'esphome/esphome'
 | 
					    if: github.repository == 'esphome/esphome' && github.event_name == 'release'
 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
    needs: [deploy-docker]
 | 
					    needs: [deploy-docker]
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
@@ -306,4 +144,4 @@ jobs:
 | 
				
			|||||||
            -X POST \
 | 
					            -X POST \
 | 
				
			||||||
            -H "Accept: application/vnd.github.v3+json" \
 | 
					            -H "Accept: application/vnd.github.v3+json" \
 | 
				
			||||||
            https://api.github.com/repos/esphome/hassio/actions/workflows/bump-version.yml/dispatches \
 | 
					            https://api.github.com/repos/esphome/hassio/actions/workflows/bump-version.yml/dispatches \
 | 
				
			||||||
            -d "{\"ref\":\"master\",\"inputs\":{\"version\":\"$TAG\"}}"
 | 
					            -d "{\"ref\":\"main\",\"inputs\":{\"version\":\"$TAG\"}}"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -13,6 +13,9 @@ __pycache__/
 | 
				
			|||||||
# Intellij Idea
 | 
					# Intellij Idea
 | 
				
			||||||
.idea
 | 
					.idea
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Vim
 | 
				
			||||||
 | 
					*.swp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Hide some OS X stuff
 | 
					# Hide some OS X stuff
 | 
				
			||||||
.DS_Store
 | 
					.DS_Store
 | 
				
			||||||
.AppleDouble
 | 
					.AppleDouble
 | 
				
			||||||
@@ -100,6 +103,8 @@ CMakeLists.txt
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# CMake
 | 
					# CMake
 | 
				
			||||||
cmake-build-debug/
 | 
					cmake-build-debug/
 | 
				
			||||||
 | 
					cmake-build-livingroom8266/
 | 
				
			||||||
 | 
					cmake-build-livingroom32/
 | 
				
			||||||
cmake-build-release/
 | 
					cmake-build-release/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CMakeCache.txt
 | 
					CMakeCache.txt
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,5 +23,5 @@ repos:
 | 
				
			|||||||
      - id: no-commit-to-branch
 | 
					      - id: no-commit-to-branch
 | 
				
			||||||
        args:
 | 
					        args:
 | 
				
			||||||
          - --branch=dev
 | 
					          - --branch=dev
 | 
				
			||||||
          - --branch=master
 | 
					          - --branch=release
 | 
				
			||||||
          - --branch=beta
 | 
					          - --branch=beta
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										35
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										35
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							@@ -1,11 +1,32 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "version": "2.0.0",
 | 
					  "version": "2.0.0",
 | 
				
			||||||
    "tasks": [
 | 
					  "tasks": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "label": "run",
 | 
				
			||||||
 | 
					      "type": "shell",
 | 
				
			||||||
 | 
					      "command": "python3 -m esphome dashboard config/",
 | 
				
			||||||
 | 
					      "problemMatcher": []
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      "label": "clang-tidy",
 | 
				
			||||||
 | 
					      "type": "shell",
 | 
				
			||||||
 | 
					      "command": "test -f .gcc-flags.json || pio init --silent --ide atom; ./script/clang-tidy",
 | 
				
			||||||
 | 
					      "problemMatcher": [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            "label": "run",
 | 
					          "owner": "clang-tidy",
 | 
				
			||||||
            "type": "shell",
 | 
					          "fileLocation": "absolute",
 | 
				
			||||||
            "command": "python3 -m esphome config dashboard",
 | 
					          "pattern": [
 | 
				
			||||||
            "problemMatcher": []
 | 
					            {
 | 
				
			||||||
 | 
					              "regexp": "^(.*):(\\d+):(\\d+):\\s+(error):\\s+(.*) \\[([a-z0-9,\\-]+)\\]\\s*$",
 | 
				
			||||||
 | 
					              "file": 1,
 | 
				
			||||||
 | 
					              "line": 2,
 | 
				
			||||||
 | 
					              "column": 3,
 | 
				
			||||||
 | 
					              "severity": 4,
 | 
				
			||||||
 | 
					              "message": 5
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          ]
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    ]
 | 
					      ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										17
									
								
								CODEOWNERS
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								CODEOWNERS
									
									
									
									
									
								
							@@ -15,10 +15,12 @@ esphome/components/ac_dimmer/* @glmnet
 | 
				
			|||||||
esphome/components/adc/* @esphome/core
 | 
					esphome/components/adc/* @esphome/core
 | 
				
			||||||
esphome/components/addressable_light/* @justfalter
 | 
					esphome/components/addressable_light/* @justfalter
 | 
				
			||||||
esphome/components/animation/* @syndlex
 | 
					esphome/components/animation/* @syndlex
 | 
				
			||||||
 | 
					esphome/components/anova/* @buxtronix
 | 
				
			||||||
esphome/components/api/* @OttoWinter
 | 
					esphome/components/api/* @OttoWinter
 | 
				
			||||||
esphome/components/async_tcp/* @OttoWinter
 | 
					esphome/components/async_tcp/* @OttoWinter
 | 
				
			||||||
esphome/components/atc_mithermometer/* @ahpohl
 | 
					esphome/components/atc_mithermometer/* @ahpohl
 | 
				
			||||||
esphome/components/b_parasite/* @rbaron
 | 
					esphome/components/b_parasite/* @rbaron
 | 
				
			||||||
 | 
					esphome/components/ballu/* @bazuchan
 | 
				
			||||||
esphome/components/bang_bang/* @OttoWinter
 | 
					esphome/components/bang_bang/* @OttoWinter
 | 
				
			||||||
esphome/components/binary_sensor/* @esphome/core
 | 
					esphome/components/binary_sensor/* @esphome/core
 | 
				
			||||||
esphome/components/ble_client/* @buxtronix
 | 
					esphome/components/ble_client/* @buxtronix
 | 
				
			||||||
@@ -29,11 +31,15 @@ esphome/components/climate/* @esphome/core
 | 
				
			|||||||
esphome/components/climate_ir/* @glmnet
 | 
					esphome/components/climate_ir/* @glmnet
 | 
				
			||||||
esphome/components/coolix/* @glmnet
 | 
					esphome/components/coolix/* @glmnet
 | 
				
			||||||
esphome/components/cover/* @esphome/core
 | 
					esphome/components/cover/* @esphome/core
 | 
				
			||||||
 | 
					esphome/components/cs5460a/* @balrog-kun
 | 
				
			||||||
esphome/components/ct_clamp/* @jesserockz
 | 
					esphome/components/ct_clamp/* @jesserockz
 | 
				
			||||||
esphome/components/debug/* @OttoWinter
 | 
					esphome/components/debug/* @OttoWinter
 | 
				
			||||||
esphome/components/dfplayer/* @glmnet
 | 
					esphome/components/dfplayer/* @glmnet
 | 
				
			||||||
esphome/components/dht/* @OttoWinter
 | 
					esphome/components/dht/* @OttoWinter
 | 
				
			||||||
esphome/components/ds1307/* @badbadc0ffee
 | 
					esphome/components/ds1307/* @badbadc0ffee
 | 
				
			||||||
 | 
					esphome/components/esp32_ble/* @jesserockz
 | 
				
			||||||
 | 
					esphome/components/esp32_ble_server/* @jesserockz
 | 
				
			||||||
 | 
					esphome/components/esp32_improv/* @jesserockz
 | 
				
			||||||
esphome/components/exposure_notifications/* @OttoWinter
 | 
					esphome/components/exposure_notifications/* @OttoWinter
 | 
				
			||||||
esphome/components/ezo/* @ssieb
 | 
					esphome/components/ezo/* @ssieb
 | 
				
			||||||
esphome/components/fastled_base/* @OttoWinter
 | 
					esphome/components/fastled_base/* @OttoWinter
 | 
				
			||||||
@@ -41,8 +47,10 @@ esphome/components/fingerprint_grow/* @OnFreund @loongyh
 | 
				
			|||||||
esphome/components/globals/* @esphome/core
 | 
					esphome/components/globals/* @esphome/core
 | 
				
			||||||
esphome/components/gpio/* @esphome/core
 | 
					esphome/components/gpio/* @esphome/core
 | 
				
			||||||
esphome/components/gps/* @coogle
 | 
					esphome/components/gps/* @coogle
 | 
				
			||||||
 | 
					esphome/components/havells_solar/* @sourabhjaiswal
 | 
				
			||||||
esphome/components/homeassistant/* @OttoWinter
 | 
					esphome/components/homeassistant/* @OttoWinter
 | 
				
			||||||
esphome/components/i2c/* @esphome/core
 | 
					esphome/components/i2c/* @esphome/core
 | 
				
			||||||
 | 
					esphome/components/improv/* @jesserockz
 | 
				
			||||||
esphome/components/inkbird_ibsth1_mini/* @fkirill
 | 
					esphome/components/inkbird_ibsth1_mini/* @fkirill
 | 
				
			||||||
esphome/components/inkplate6/* @jesserockz
 | 
					esphome/components/inkplate6/* @jesserockz
 | 
				
			||||||
esphome/components/integration/* @OttoWinter
 | 
					esphome/components/integration/* @OttoWinter
 | 
				
			||||||
@@ -63,8 +71,15 @@ esphome/components/mcp2515/* @danielschramm @mvturnho
 | 
				
			|||||||
esphome/components/mcp9808/* @k7hpn
 | 
					esphome/components/mcp9808/* @k7hpn
 | 
				
			||||||
esphome/components/midea_ac/* @dudanov
 | 
					esphome/components/midea_ac/* @dudanov
 | 
				
			||||||
esphome/components/midea_dongle/* @dudanov
 | 
					esphome/components/midea_dongle/* @dudanov
 | 
				
			||||||
 | 
					esphome/components/mitsubishi/* @RubyBailey
 | 
				
			||||||
esphome/components/network/* @esphome/core
 | 
					esphome/components/network/* @esphome/core
 | 
				
			||||||
 | 
					esphome/components/nextion/* @senexcrenshaw
 | 
				
			||||||
 | 
					esphome/components/nextion/binary_sensor/* @senexcrenshaw
 | 
				
			||||||
 | 
					esphome/components/nextion/sensor/* @senexcrenshaw
 | 
				
			||||||
 | 
					esphome/components/nextion/switch/* @senexcrenshaw
 | 
				
			||||||
 | 
					esphome/components/nextion/text_sensor/* @senexcrenshaw
 | 
				
			||||||
esphome/components/nfc/* @jesserockz
 | 
					esphome/components/nfc/* @jesserockz
 | 
				
			||||||
 | 
					esphome/components/number/* @esphome/core
 | 
				
			||||||
esphome/components/ota/* @esphome/core
 | 
					esphome/components/ota/* @esphome/core
 | 
				
			||||||
esphome/components/output/* @esphome/core
 | 
					esphome/components/output/* @esphome/core
 | 
				
			||||||
esphome/components/pid/* @OttoWinter
 | 
					esphome/components/pid/* @OttoWinter
 | 
				
			||||||
@@ -80,6 +95,7 @@ esphome/components/restart/* @esphome/core
 | 
				
			|||||||
esphome/components/rf_bridge/* @jesserockz
 | 
					esphome/components/rf_bridge/* @jesserockz
 | 
				
			||||||
esphome/components/rtttl/* @glmnet
 | 
					esphome/components/rtttl/* @glmnet
 | 
				
			||||||
esphome/components/script/* @esphome/core
 | 
					esphome/components/script/* @esphome/core
 | 
				
			||||||
 | 
					esphome/components/sdm_meter/* @jesserockz @polyfaces
 | 
				
			||||||
esphome/components/sensor/* @esphome/core
 | 
					esphome/components/sensor/* @esphome/core
 | 
				
			||||||
esphome/components/sgp40/* @SenexCrenshaw
 | 
					esphome/components/sgp40/* @SenexCrenshaw
 | 
				
			||||||
esphome/components/sht4x/* @sjtrny
 | 
					esphome/components/sht4x/* @sjtrny
 | 
				
			||||||
@@ -122,3 +138,4 @@ esphome/components/web_server_base/* @OttoWinter
 | 
				
			|||||||
esphome/components/whirlpool/* @glmnet
 | 
					esphome/components/whirlpool/* @glmnet
 | 
				
			||||||
esphome/components/xiaomi_lywsd03mmc/* @ahpohl
 | 
					esphome/components/xiaomi_lywsd03mmc/* @ahpohl
 | 
				
			||||||
esphome/components/xiaomi_mhoc401/* @vevsvevs
 | 
					esphome/components/xiaomi_mhoc401/* @vevsvevs
 | 
				
			||||||
 | 
					esphome/components/xpt2046/* @numo68
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
# ESPHome [](https://travis-ci.org/esphome/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/)
 | 
					[](https://esphome.io/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
ARG BUILD_FROM=esphome/esphome-base-amd64:3.0.0
 | 
					ARG BUILD_FROM=esphome/esphome-base:latest
 | 
				
			||||||
FROM ${BUILD_FROM}
 | 
					FROM ${BUILD_FROM}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# First install requirements to leverage caching when requirements don't change
 | 
					# First install requirements to leverage caching when requirements don't change
 | 
				
			||||||
COPY requirements.txt docker/platformio_install_deps.py platformio.ini /
 | 
					COPY requirements.txt requirements_optional.txt docker/platformio_install_deps.py platformio.ini /
 | 
				
			||||||
RUN \
 | 
					RUN \
 | 
				
			||||||
    pip3 install --no-cache-dir -r /requirements.txt \
 | 
					    pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
 | 
				
			||||||
    && /platformio_install_deps.py /platformio.ini
 | 
					    && /platformio_install_deps.py /platformio.ini
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Then copy esphome and install
 | 
					# Then copy esphome and install
 | 
				
			||||||
@@ -27,4 +27,4 @@ WORKDIR /config
 | 
				
			|||||||
# in every docker command twice
 | 
					# in every docker command twice
 | 
				
			||||||
ENTRYPOINT ["esphome"]
 | 
					ENTRYPOINT ["esphome"]
 | 
				
			||||||
# When no arguments given, start the dashboard in the workdir
 | 
					# When no arguments given, start the dashboard in the workdir
 | 
				
			||||||
CMD ["/config", "dashboard"]
 | 
					CMD ["dashboard", "/config"]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1 @@
 | 
				
			|||||||
FROM esphome/esphome-base-amd64:3.0.0
 | 
					FROM esphome/esphome-lint:1.1
 | 
				
			||||||
 | 
					 | 
				
			||||||
COPY . .
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RUN apt-get update \
 | 
					 | 
				
			||||||
    && apt-get install -y --no-install-recommends \
 | 
					 | 
				
			||||||
        python3-wheel \
 | 
					 | 
				
			||||||
        net-tools \
 | 
					 | 
				
			||||||
    && apt-get clean \
 | 
					 | 
				
			||||||
    && rm -rf /var/lib/apt/lists/*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
WORKDIR /workspaces
 | 
					 | 
				
			||||||
ENV SHELL /bin/bash
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
ARG BUILD_FROM
 | 
					ARG BUILD_FROM=esphome/esphome-hassio-base:latest
 | 
				
			||||||
FROM ${BUILD_FROM}
 | 
					FROM ${BUILD_FROM}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# First install requirements to leverage caching when requirements don't change
 | 
					# First install requirements to leverage caching when requirements don't change
 | 
				
			||||||
COPY requirements.txt docker/platformio_install_deps.py platformio.ini /
 | 
					COPY requirements.txt requirements_optional.txt docker/platformio_install_deps.py platformio.ini /
 | 
				
			||||||
RUN \
 | 
					RUN \
 | 
				
			||||||
    pip3 install --no-cache-dir -r /requirements.txt \
 | 
					    pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt \
 | 
				
			||||||
    && /platformio_install_deps.py /platformio.ini
 | 
					    && /platformio_install_deps.py /platformio.ini
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Copy root filesystem
 | 
					# Copy root filesystem
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,9 @@
 | 
				
			|||||||
FROM esphome/esphome-lint-base:3.0.0
 | 
					ARG BUILD_FROM=esphome/esphome-lint-base:latest
 | 
				
			||||||
 | 
					FROM ${BUILD_FROM}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
COPY requirements.txt requirements_test.txt docker/platformio_install_deps.py  platformio.ini /
 | 
					COPY requirements.txt requirements_optional.txt requirements_test.txt docker/platformio_install_deps.py  platformio.ini /
 | 
				
			||||||
RUN \
 | 
					RUN \
 | 
				
			||||||
    pip3 install --no-cache-dir -r /requirements.txt -r /requirements_test.txt \
 | 
					    pip3 install --no-cache-dir -r /requirements.txt -r /requirements_optional.txt -r /requirements_test.txt \
 | 
				
			||||||
    && /platformio_install_deps.py /platformio.ini
 | 
					    && /platformio_install_deps.py /platformio.ini
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VOLUME ["/esphome"]
 | 
					VOLUME ["/esphome"]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										177
									
								
								docker/build.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										177
									
								
								docker/build.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,177 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
 | 
					from dataclasses import dataclass
 | 
				
			||||||
 | 
					import subprocess
 | 
				
			||||||
 | 
					import argparse
 | 
				
			||||||
 | 
					import platform
 | 
				
			||||||
 | 
					import shlex
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CHANNEL_DEV = 'dev'
 | 
				
			||||||
 | 
					CHANNEL_BETA = 'beta'
 | 
				
			||||||
 | 
					CHANNEL_RELEASE = 'release'
 | 
				
			||||||
 | 
					CHANNELS = [CHANNEL_DEV, CHANNEL_BETA, CHANNEL_RELEASE]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ARCH_AMD64 = 'amd64'
 | 
				
			||||||
 | 
					ARCH_ARMV7 = 'armv7'
 | 
				
			||||||
 | 
					ARCH_AARCH64 = 'aarch64'
 | 
				
			||||||
 | 
					ARCHS = [ARCH_AMD64, ARCH_ARMV7, ARCH_AARCH64]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TYPE_DOCKER = 'docker'
 | 
				
			||||||
 | 
					TYPE_HA_ADDON = 'ha-addon'
 | 
				
			||||||
 | 
					TYPE_LINT = 'lint'
 | 
				
			||||||
 | 
					TYPES = [TYPE_DOCKER, TYPE_HA_ADDON, TYPE_LINT]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BASE_VERSION = "3.6.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					parser = argparse.ArgumentParser()
 | 
				
			||||||
 | 
					parser.add_argument("--tag", type=str, required=True, help="The main docker tag to push to. If a version number also adds latest and/or beta tag")
 | 
				
			||||||
 | 
					parser.add_argument("--arch", choices=ARCHS, required=False, help="The architecture to build for")
 | 
				
			||||||
 | 
					parser.add_argument("--build-type", choices=TYPES, required=True, help="The type of build to run")
 | 
				
			||||||
 | 
					parser.add_argument("--dry-run", action="store_true", help="Don't run any commands, just print them")
 | 
				
			||||||
 | 
					subparsers = parser.add_subparsers(help="Action to perform", dest="command", required=True)
 | 
				
			||||||
 | 
					build_parser = subparsers.add_parser("build", help="Build the image")
 | 
				
			||||||
 | 
					push_parser = subparsers.add_parser("push", help="Tag the already built image and push it to docker hub")
 | 
				
			||||||
 | 
					manifest_parser = subparsers.add_parser("manifest", help="Create a manifest from already pushed images")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# only lists some possibilities, doesn't have to be perfect
 | 
				
			||||||
 | 
					# https://stackoverflow.com/a/45125525
 | 
				
			||||||
 | 
					UNAME_TO_ARCH = {
 | 
				
			||||||
 | 
					    "x86_64": ARCH_AMD64,
 | 
				
			||||||
 | 
					    "aarch64": ARCH_AARCH64,
 | 
				
			||||||
 | 
					    "aarch64_be": ARCH_AARCH64,
 | 
				
			||||||
 | 
					    "arm": ARCH_ARMV7,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@dataclass(frozen=True)
 | 
				
			||||||
 | 
					class DockerParams:
 | 
				
			||||||
 | 
					    build_from: str
 | 
				
			||||||
 | 
					    build_to: str
 | 
				
			||||||
 | 
					    manifest_to: str
 | 
				
			||||||
 | 
					    dockerfile: str
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def for_type_arch(cls, build_type, arch):
 | 
				
			||||||
 | 
					        prefix = {
 | 
				
			||||||
 | 
					            TYPE_DOCKER: "esphome/esphome",
 | 
				
			||||||
 | 
					            TYPE_HA_ADDON: "esphome/esphome-hassio",
 | 
				
			||||||
 | 
					            TYPE_LINT: "esphome/esphome-lint"
 | 
				
			||||||
 | 
					        }[build_type]
 | 
				
			||||||
 | 
					        build_from = f"ghcr.io/{prefix}-base-{arch}:{BASE_VERSION}"
 | 
				
			||||||
 | 
					        build_to = f"{prefix}-{arch}"
 | 
				
			||||||
 | 
					        dockerfile = {
 | 
				
			||||||
 | 
					            TYPE_DOCKER: "docker/Dockerfile",
 | 
				
			||||||
 | 
					            TYPE_HA_ADDON: "docker/Dockerfile.hassio",
 | 
				
			||||||
 | 
					            TYPE_LINT: "docker/Dockerfile.lint",
 | 
				
			||||||
 | 
					        }[build_type]
 | 
				
			||||||
 | 
					        return cls(
 | 
				
			||||||
 | 
					            build_from=build_from,
 | 
				
			||||||
 | 
					            build_to=build_to,
 | 
				
			||||||
 | 
					            manifest_to=prefix,
 | 
				
			||||||
 | 
					            dockerfile=dockerfile
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    args = parser.parse_args()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run_command(*cmd, ignore_error: bool = False):
 | 
				
			||||||
 | 
					        print(f"$ {shlex.join(list(cmd))}")
 | 
				
			||||||
 | 
					        if not args.dry_run:
 | 
				
			||||||
 | 
					            rc = subprocess.call(list(cmd))
 | 
				
			||||||
 | 
					            if rc != 0 and not ignore_error:
 | 
				
			||||||
 | 
					                print("Command failed")
 | 
				
			||||||
 | 
					                sys.exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # detect channel from tag
 | 
				
			||||||
 | 
					    match = re.match(r'^\d+\.\d+(?:\.\d+)?(b\d+)?$', args.tag)
 | 
				
			||||||
 | 
					    if match is None:
 | 
				
			||||||
 | 
					        channel = CHANNEL_DEV
 | 
				
			||||||
 | 
					    elif match.group(1) is None:
 | 
				
			||||||
 | 
					        channel = CHANNEL_RELEASE
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        channel = CHANNEL_BETA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tags_to_push = [args.tag]
 | 
				
			||||||
 | 
					    if channel == CHANNEL_DEV:
 | 
				
			||||||
 | 
					        tags_to_push.append("dev")
 | 
				
			||||||
 | 
					    elif channel == CHANNEL_BETA:
 | 
				
			||||||
 | 
					        tags_to_push.append("beta")
 | 
				
			||||||
 | 
					    elif channel == CHANNEL_RELEASE:
 | 
				
			||||||
 | 
					        # Additionally push to beta
 | 
				
			||||||
 | 
					        tags_to_push.append("beta")
 | 
				
			||||||
 | 
					        tags_to_push.append("latest")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if args.command == "build":
 | 
				
			||||||
 | 
					        # 1. pull cache image
 | 
				
			||||||
 | 
					        params = DockerParams.for_type_arch(args.build_type, args.arch)
 | 
				
			||||||
 | 
					        cache_tag = {
 | 
				
			||||||
 | 
					            CHANNEL_DEV: "dev",
 | 
				
			||||||
 | 
					            CHANNEL_BETA: "beta",
 | 
				
			||||||
 | 
					            CHANNEL_RELEASE: "latest",
 | 
				
			||||||
 | 
					        }[channel]
 | 
				
			||||||
 | 
					        cache_img = f"ghcr.io/{params.build_to}:{cache_tag}"
 | 
				
			||||||
 | 
					        run_command("docker", "pull", cache_img, ignore_error=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # 2. register QEMU binfmt (if not host arch)
 | 
				
			||||||
 | 
					        is_native = UNAME_TO_ARCH.get(platform.machine()) == args.arch
 | 
				
			||||||
 | 
					        if not is_native:
 | 
				
			||||||
 | 
					            run_command(
 | 
				
			||||||
 | 
					                "docker", "run", "--rm", "--privileged", "multiarch/qemu-user-static:5.2.0-2",
 | 
				
			||||||
 | 
					                "--reset", "-p", "yes"
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # 3. build
 | 
				
			||||||
 | 
					        run_command(
 | 
				
			||||||
 | 
					            "docker", "build",
 | 
				
			||||||
 | 
					            "--build-arg", f"BUILD_FROM={params.build_from}",
 | 
				
			||||||
 | 
					            "--build-arg", f"BUILD_VERSION={args.tag}",
 | 
				
			||||||
 | 
					            "--tag", f"{params.build_to}:{args.tag}",
 | 
				
			||||||
 | 
					            "--cache-from", cache_img,
 | 
				
			||||||
 | 
					            "--file", params.dockerfile,
 | 
				
			||||||
 | 
					            "."
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    elif args.command == "push":
 | 
				
			||||||
 | 
					        params = DockerParams.for_type_arch(args.build_type, args.arch)
 | 
				
			||||||
 | 
					        imgs = [f"{params.build_to}:{tag}" for tag in tags_to_push]
 | 
				
			||||||
 | 
					        imgs += [f"ghcr.io/{params.build_to}:{tag}" for tag in tags_to_push]
 | 
				
			||||||
 | 
					        src = imgs[0]
 | 
				
			||||||
 | 
					        # 1. tag images
 | 
				
			||||||
 | 
					        for img in imgs[1:]:
 | 
				
			||||||
 | 
					            run_command(
 | 
				
			||||||
 | 
					                "docker", "tag", src, img
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        # 2. push images
 | 
				
			||||||
 | 
					        for img in imgs:
 | 
				
			||||||
 | 
					            run_command(
 | 
				
			||||||
 | 
					                "docker", "push", img
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					    elif args.command == "manifest":
 | 
				
			||||||
 | 
					        manifest = DockerParams.for_type_arch(args.build_type, ARCH_AMD64).manifest_to
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        targets = [f"{manifest}:{tag}" for tag in tags_to_push]
 | 
				
			||||||
 | 
					        targets += [f"ghcr.io/{manifest}:{tag}" for tag in tags_to_push]
 | 
				
			||||||
 | 
					        # 1. Create manifests
 | 
				
			||||||
 | 
					        for target in targets:
 | 
				
			||||||
 | 
					            cmd = ["docker", "manifest", "create", target]
 | 
				
			||||||
 | 
					            for arch in ARCHS:
 | 
				
			||||||
 | 
					                src = f"{DockerParams.for_type_arch(args.build_type, arch).build_to}:{args.tag}"
 | 
				
			||||||
 | 
					                if target.startswith("ghcr.io"):
 | 
				
			||||||
 | 
					                    src = f"ghcr.io/{src}"
 | 
				
			||||||
 | 
					                cmd.append(src)
 | 
				
			||||||
 | 
					            run_command(*cmd)
 | 
				
			||||||
 | 
					        # 2. Push manifests
 | 
				
			||||||
 | 
					        for target in targets:
 | 
				
			||||||
 | 
					            run_command(
 | 
				
			||||||
 | 
					                "docker", "manifest", "push", target
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
@@ -23,4 +23,4 @@ if bashio::config.has_value 'relative_url'; then
 | 
				
			|||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bashio::log.info "Starting ESPHome dashboard..."
 | 
					bashio::log.info "Starting ESPHome dashboard..."
 | 
				
			||||||
exec esphome /config/esphome dashboard --socket /var/run/esphome.sock --hassio
 | 
					exec esphome dashboard /config/esphome --socket /var/run/esphome.sock --hassio
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,7 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_ESPHOME,
 | 
					    CONF_ESPHOME,
 | 
				
			||||||
    CONF_PLATFORMIO_OPTIONS,
 | 
					    CONF_PLATFORMIO_OPTIONS,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from esphome.core import CORE, EsphomeError, coroutine, coroutine_with_priority
 | 
					from esphome.core import CORE, EsphomeError, coroutine
 | 
				
			||||||
from esphome.helpers import indent
 | 
					from esphome.helpers import indent
 | 
				
			||||||
from esphome.util import (
 | 
					from esphome.util import (
 | 
				
			||||||
    run_external_command,
 | 
					    run_external_command,
 | 
				
			||||||
@@ -127,15 +127,16 @@ def wrap_to_code(name, comp):
 | 
				
			|||||||
    coro = coroutine(comp.to_code)
 | 
					    coro = coroutine(comp.to_code)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @functools.wraps(comp.to_code)
 | 
					    @functools.wraps(comp.to_code)
 | 
				
			||||||
    @coroutine_with_priority(coro.priority)
 | 
					    async def wrapped(conf):
 | 
				
			||||||
    def wrapped(conf):
 | 
					 | 
				
			||||||
        cg.add(cg.LineComment(f"{name}:"))
 | 
					        cg.add(cg.LineComment(f"{name}:"))
 | 
				
			||||||
        if comp.config_schema is not None:
 | 
					        if comp.config_schema is not None:
 | 
				
			||||||
            conf_str = yaml_util.dump(conf)
 | 
					            conf_str = yaml_util.dump(conf)
 | 
				
			||||||
            conf_str = conf_str.replace("//", "")
 | 
					            conf_str = conf_str.replace("//", "")
 | 
				
			||||||
            cg.add(cg.LineComment(indent(conf_str)))
 | 
					            cg.add(cg.LineComment(indent(conf_str)))
 | 
				
			||||||
        yield coro(conf)
 | 
					        await coro(conf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if hasattr(coro, "priority"):
 | 
				
			||||||
 | 
					        wrapped.priority = coro.priority
 | 
				
			||||||
    return wrapped
 | 
					    return wrapped
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -267,7 +268,7 @@ def clean_mqtt(config, args):
 | 
				
			|||||||
def command_wizard(args):
 | 
					def command_wizard(args):
 | 
				
			||||||
    from esphome import wizard
 | 
					    from esphome import wizard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return wizard.wizard(args.configuration[0])
 | 
					    return wizard.wizard(args.configuration)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def command_config(args, config):
 | 
					def command_config(args, config):
 | 
				
			||||||
@@ -283,7 +284,7 @@ def command_vscode(args):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    logging.disable(logging.INFO)
 | 
					    logging.disable(logging.INFO)
 | 
				
			||||||
    logging.disable(logging.WARNING)
 | 
					    logging.disable(logging.WARNING)
 | 
				
			||||||
    CORE.config_path = args.configuration[0]
 | 
					    CORE.config_path = args.configuration
 | 
				
			||||||
    vscode.read_config(args)
 | 
					    vscode.read_config(args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -303,7 +304,7 @@ def command_compile(args, config):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def command_upload(args, config):
 | 
					def command_upload(args, config):
 | 
				
			||||||
    port = choose_upload_log_host(
 | 
					    port = choose_upload_log_host(
 | 
				
			||||||
        default=args.upload_port,
 | 
					        default=args.device,
 | 
				
			||||||
        check_default=None,
 | 
					        check_default=None,
 | 
				
			||||||
        show_ota=True,
 | 
					        show_ota=True,
 | 
				
			||||||
        show_mqtt=False,
 | 
					        show_mqtt=False,
 | 
				
			||||||
@@ -318,7 +319,7 @@ def command_upload(args, config):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
def command_logs(args, config):
 | 
					def command_logs(args, config):
 | 
				
			||||||
    port = choose_upload_log_host(
 | 
					    port = choose_upload_log_host(
 | 
				
			||||||
        default=args.serial_port,
 | 
					        default=args.device,
 | 
				
			||||||
        check_default=None,
 | 
					        check_default=None,
 | 
				
			||||||
        show_ota=False,
 | 
					        show_ota=False,
 | 
				
			||||||
        show_mqtt=True,
 | 
					        show_mqtt=True,
 | 
				
			||||||
@@ -336,7 +337,7 @@ def command_run(args, config):
 | 
				
			|||||||
        return exit_code
 | 
					        return exit_code
 | 
				
			||||||
    _LOGGER.info("Successfully compiled program.")
 | 
					    _LOGGER.info("Successfully compiled program.")
 | 
				
			||||||
    port = choose_upload_log_host(
 | 
					    port = choose_upload_log_host(
 | 
				
			||||||
        default=args.upload_port,
 | 
					        default=args.device,
 | 
				
			||||||
        check_default=None,
 | 
					        check_default=None,
 | 
				
			||||||
        show_ota=True,
 | 
					        show_ota=True,
 | 
				
			||||||
        show_mqtt=False,
 | 
					        show_mqtt=False,
 | 
				
			||||||
@@ -349,7 +350,7 @@ def command_run(args, config):
 | 
				
			|||||||
    if args.no_logs:
 | 
					    if args.no_logs:
 | 
				
			||||||
        return 0
 | 
					        return 0
 | 
				
			||||||
    port = choose_upload_log_host(
 | 
					    port = choose_upload_log_host(
 | 
				
			||||||
        default=args.upload_port,
 | 
					        default=args.device,
 | 
				
			||||||
        check_default=port,
 | 
					        check_default=port,
 | 
				
			||||||
        show_ota=False,
 | 
					        show_ota=False,
 | 
				
			||||||
        show_mqtt=True,
 | 
					        show_mqtt=True,
 | 
				
			||||||
@@ -407,7 +408,7 @@ def command_update_all(args):
 | 
				
			|||||||
        print("-" * twidth)
 | 
					        print("-" * twidth)
 | 
				
			||||||
        print()
 | 
					        print()
 | 
				
			||||||
        rc = run_external_process(
 | 
					        rc = run_external_process(
 | 
				
			||||||
            "esphome", "--dashboard", f, "run", "--no-logs", "--upload-port", "OTA"
 | 
					            "esphome", "--dashboard", "run", "--no-logs", "--device", "OTA", f
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        if rc == 0:
 | 
					        if rc == 0:
 | 
				
			||||||
            print_bar("[{}] {}".format(color(Fore.BOLD_GREEN, "SUCCESS"), f))
 | 
					            print_bar("[{}] {}".format(color(Fore.BOLD_GREEN, "SUCCESS"), f))
 | 
				
			||||||
@@ -452,15 +453,17 @@ POST_CONFIG_ACTIONS = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def parse_args(argv):
 | 
					def parse_args(argv):
 | 
				
			||||||
    parser = argparse.ArgumentParser(description=f"ESPHome v{const.__version__}")
 | 
					    options_parser = argparse.ArgumentParser(add_help=False)
 | 
				
			||||||
    parser.add_argument(
 | 
					    options_parser.add_argument(
 | 
				
			||||||
        "-v", "--verbose", help="Enable verbose esphome logs.", action="store_true"
 | 
					        "-v", "--verbose", help="Enable verbose ESPHome logs.", action="store_true"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    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"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    parser.add_argument("--dashboard", help=argparse.SUPPRESS, action="store_true")
 | 
					    options_parser.add_argument(
 | 
				
			||||||
    parser.add_argument(
 | 
					        "--dashboard", help=argparse.SUPPRESS, action="store_true"
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    options_parser.add_argument(
 | 
				
			||||||
        "-s",
 | 
					        "-s",
 | 
				
			||||||
        "--substitution",
 | 
					        "--substitution",
 | 
				
			||||||
        nargs=2,
 | 
					        nargs=2,
 | 
				
			||||||
@@ -468,17 +471,100 @@ def parse_args(argv):
 | 
				
			|||||||
        help="Add a substitution",
 | 
					        help="Add a substitution",
 | 
				
			||||||
        metavar=("key", "value"),
 | 
					        metavar=("key", "value"),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    parser.add_argument(
 | 
					
 | 
				
			||||||
        "configuration", help="Your YAML configuration file.", nargs="*"
 | 
					    # Keep backward compatibility with the old command line format of
 | 
				
			||||||
 | 
					    # esphome <config> <command>.
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    # Unfortunately this can't be done by adding another configuration argument to the
 | 
				
			||||||
 | 
					    # main config parser, as argparse is greedy when parsing arguments, so in regular
 | 
				
			||||||
 | 
					    # usage it'll eat the command as the configuration argument and error out out
 | 
				
			||||||
 | 
					    # because it can't parse the configuration as a command.
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    # Instead, construct an ad-hoc parser for the old format that doesn't actually
 | 
				
			||||||
 | 
					    # process the arguments, but parses them enough to let us figure out if the old
 | 
				
			||||||
 | 
					    # format is used. In that case, swap the command and configuration in the arguments
 | 
				
			||||||
 | 
					    # and continue on with the normal parser (after raising a deprecation warning).
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    # Disable argparse's built-in help option and add it manually to prevent this
 | 
				
			||||||
 | 
					    # parser from printing the help messagefor the old format when invoked with -h.
 | 
				
			||||||
 | 
					    compat_parser = argparse.ArgumentParser(parents=[options_parser], add_help=False)
 | 
				
			||||||
 | 
					    compat_parser.add_argument("-h", "--help")
 | 
				
			||||||
 | 
					    compat_parser.add_argument("configuration", nargs="*")
 | 
				
			||||||
 | 
					    compat_parser.add_argument(
 | 
				
			||||||
 | 
					        "command",
 | 
				
			||||||
 | 
					        choices=[
 | 
				
			||||||
 | 
					            "config",
 | 
				
			||||||
 | 
					            "compile",
 | 
				
			||||||
 | 
					            "upload",
 | 
				
			||||||
 | 
					            "logs",
 | 
				
			||||||
 | 
					            "run",
 | 
				
			||||||
 | 
					            "clean-mqtt",
 | 
				
			||||||
 | 
					            "wizard",
 | 
				
			||||||
 | 
					            "mqtt-fingerprint",
 | 
				
			||||||
 | 
					            "version",
 | 
				
			||||||
 | 
					            "clean",
 | 
				
			||||||
 | 
					            "dashboard",
 | 
				
			||||||
 | 
					            "vscode",
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    subparsers = parser.add_subparsers(help="Commands", dest="command")
 | 
					    # on Python 3.9+ we can simply set exit_on_error=False in the constructor
 | 
				
			||||||
 | 
					    def _raise(x):
 | 
				
			||||||
 | 
					        raise argparse.ArgumentError(None, x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    compat_parser.error = _raise
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    deprecated_argv_suggestion = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ["dashboard", "config"] == argv[1:3] or ["version"] == argv[1:2]:
 | 
				
			||||||
 | 
					        # this is most likely meant in new-style arg format. do not try compat parsing
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            result, unparsed = compat_parser.parse_known_args(argv[1:])
 | 
				
			||||||
 | 
					            last_option = len(argv) - len(unparsed) - 1 - len(result.configuration)
 | 
				
			||||||
 | 
					            unparsed = [
 | 
				
			||||||
 | 
					                "--device" if arg in ("--upload-port", "--serial-port") else arg
 | 
				
			||||||
 | 
					                for arg in unparsed
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					            argv = (
 | 
				
			||||||
 | 
					                argv[0:last_option] + [result.command] + result.configuration + unparsed
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            deprecated_argv_suggestion = argv
 | 
				
			||||||
 | 
					        except argparse.ArgumentError:
 | 
				
			||||||
 | 
					            # This is not an old-style command line, so we don't have to do anything.
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # And continue on with regular parsing
 | 
				
			||||||
 | 
					    parser = argparse.ArgumentParser(
 | 
				
			||||||
 | 
					        description=f"ESPHome v{const.__version__}", parents=[options_parser]
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    parser.set_defaults(deprecated_argv_suggestion=deprecated_argv_suggestion)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mqtt_options = argparse.ArgumentParser(add_help=False)
 | 
				
			||||||
 | 
					    mqtt_options.add_argument("--topic", help="Manually set the MQTT topic.")
 | 
				
			||||||
 | 
					    mqtt_options.add_argument("--username", help="Manually set the MQTT username.")
 | 
				
			||||||
 | 
					    mqtt_options.add_argument("--password", help="Manually set the MQTT password.")
 | 
				
			||||||
 | 
					    mqtt_options.add_argument("--client-id", help="Manually set the MQTT client id.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    subparsers = parser.add_subparsers(
 | 
				
			||||||
 | 
					        help="Command to run:", dest="command", metavar="command"
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    subparsers.required = True
 | 
					    subparsers.required = True
 | 
				
			||||||
    subparsers.add_parser("config", help="Validate the configuration and spit it out.")
 | 
					
 | 
				
			||||||
 | 
					    parser_config = subparsers.add_parser(
 | 
				
			||||||
 | 
					        "config", help="Validate the configuration and spit it out."
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    parser_config.add_argument(
 | 
				
			||||||
 | 
					        "configuration", help="Your YAML configuration file(s).", nargs="+"
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    parser_compile = subparsers.add_parser(
 | 
					    parser_compile = subparsers.add_parser(
 | 
				
			||||||
        "compile", help="Read the configuration and compile a program."
 | 
					        "compile", help="Read the configuration and compile a program."
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					    parser_compile.add_argument(
 | 
				
			||||||
 | 
					        "configuration", help="Your YAML configuration file(s).", nargs="+"
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    parser_compile.add_argument(
 | 
					    parser_compile.add_argument(
 | 
				
			||||||
        "--only-generate",
 | 
					        "--only-generate",
 | 
				
			||||||
        help="Only generate source code, do not compile.",
 | 
					        help="Only generate source code, do not compile.",
 | 
				
			||||||
@@ -486,106 +572,124 @@ def parse_args(argv):
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    parser_upload = subparsers.add_parser(
 | 
					    parser_upload = subparsers.add_parser(
 | 
				
			||||||
        "upload", help="Validate the configuration " "and upload the latest binary."
 | 
					        "upload", help="Validate the configuration and upload the latest binary."
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    parser_upload.add_argument(
 | 
					    parser_upload.add_argument(
 | 
				
			||||||
        "--upload-port",
 | 
					        "configuration", help="Your YAML configuration file(s).", nargs="+"
 | 
				
			||||||
        help="Manually specify the upload port to use. "
 | 
					    )
 | 
				
			||||||
        "For example /dev/cu.SLAB_USBtoUART.",
 | 
					    parser_upload.add_argument(
 | 
				
			||||||
 | 
					        "--device",
 | 
				
			||||||
 | 
					        help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    parser_logs = subparsers.add_parser(
 | 
					    parser_logs = subparsers.add_parser(
 | 
				
			||||||
        "logs", help="Validate the configuration " "and show all MQTT logs."
 | 
					        "logs",
 | 
				
			||||||
 | 
					        help="Validate the configuration and show all logs.",
 | 
				
			||||||
 | 
					        parents=[mqtt_options],
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    parser_logs.add_argument("--topic", help="Manually set the topic to subscribe to.")
 | 
					 | 
				
			||||||
    parser_logs.add_argument("--username", help="Manually set the username.")
 | 
					 | 
				
			||||||
    parser_logs.add_argument("--password", help="Manually set the password.")
 | 
					 | 
				
			||||||
    parser_logs.add_argument("--client-id", help="Manually set the client id.")
 | 
					 | 
				
			||||||
    parser_logs.add_argument(
 | 
					    parser_logs.add_argument(
 | 
				
			||||||
        "--serial-port",
 | 
					        "configuration", help="Your YAML configuration file.", nargs=1
 | 
				
			||||||
        help="Manually specify a serial port to use"
 | 
					    )
 | 
				
			||||||
        "For example /dev/cu.SLAB_USBtoUART.",
 | 
					    parser_logs.add_argument(
 | 
				
			||||||
 | 
					        "--device",
 | 
				
			||||||
 | 
					        help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    parser_run = subparsers.add_parser(
 | 
					    parser_run = subparsers.add_parser(
 | 
				
			||||||
        "run",
 | 
					        "run",
 | 
				
			||||||
        help="Validate the configuration, create a binary, "
 | 
					        help="Validate the configuration, create a binary, upload it, and start logs.",
 | 
				
			||||||
        "upload it, and start MQTT logs.",
 | 
					        parents=[mqtt_options],
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    parser_run.add_argument(
 | 
					    parser_run.add_argument(
 | 
				
			||||||
        "--upload-port",
 | 
					        "configuration", help="Your YAML configuration file(s).", nargs="+"
 | 
				
			||||||
        help="Manually specify the upload port/ip to use. "
 | 
					 | 
				
			||||||
        "For example /dev/cu.SLAB_USBtoUART.",
 | 
					 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    parser_run.add_argument(
 | 
					    parser_run.add_argument(
 | 
				
			||||||
        "--no-logs", help="Disable starting MQTT logs.", action="store_true"
 | 
					        "--device",
 | 
				
			||||||
 | 
					        help="Manually specify the serial port/address to use, for example /dev/ttyUSB0.",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    parser_run.add_argument(
 | 
					    parser_run.add_argument(
 | 
				
			||||||
        "--topic", help="Manually set the topic to subscribe to for logs."
 | 
					        "--no-logs", help="Disable starting logs.", action="store_true"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    parser_run.add_argument(
 | 
					 | 
				
			||||||
        "--username", help="Manually set the MQTT username for logs."
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    parser_run.add_argument(
 | 
					 | 
				
			||||||
        "--password", help="Manually set the MQTT password for logs."
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    parser_run.add_argument("--client-id", help="Manually set the client id for logs.")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    parser_clean = subparsers.add_parser(
 | 
					    parser_clean = subparsers.add_parser(
 | 
				
			||||||
        "clean-mqtt", help="Helper to clear an MQTT topic from " "retain messages."
 | 
					        "clean-mqtt",
 | 
				
			||||||
 | 
					        help="Helper to clear retained messages from an MQTT topic.",
 | 
				
			||||||
 | 
					        parents=[mqtt_options],
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    parser_clean.add_argument(
 | 
				
			||||||
 | 
					        "configuration", help="Your YAML configuration file(s).", nargs="+"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    parser_clean.add_argument("--topic", help="Manually set the topic to subscribe to.")
 | 
					 | 
				
			||||||
    parser_clean.add_argument("--username", help="Manually set the username.")
 | 
					 | 
				
			||||||
    parser_clean.add_argument("--password", help="Manually set the password.")
 | 
					 | 
				
			||||||
    parser_clean.add_argument("--client-id", help="Manually set the client id.")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    subparsers.add_parser(
 | 
					    parser_wizard = subparsers.add_parser(
 | 
				
			||||||
        "wizard",
 | 
					        "wizard",
 | 
				
			||||||
        help="A helpful setup wizard that will guide "
 | 
					        help="A helpful setup wizard that will guide you through setting up ESPHome.",
 | 
				
			||||||
        "you through setting up esphome.",
 | 
					    )
 | 
				
			||||||
 | 
					    parser_wizard.add_argument(
 | 
				
			||||||
 | 
					        "configuration",
 | 
				
			||||||
 | 
					        help="Your YAML configuration file.",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    subparsers.add_parser(
 | 
					    parser_fingerprint = subparsers.add_parser(
 | 
				
			||||||
        "mqtt-fingerprint", help="Get the SSL fingerprint from a MQTT broker."
 | 
					        "mqtt-fingerprint", help="Get the SSL fingerprint from a MQTT broker."
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					    parser_fingerprint.add_argument(
 | 
				
			||||||
 | 
					        "configuration", help="Your YAML configuration file(s).", nargs="+"
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    subparsers.add_parser("version", help="Print the esphome version and exit.")
 | 
					    subparsers.add_parser("version", help="Print the ESPHome version and exit.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    subparsers.add_parser("clean", help="Delete all temporary build files.")
 | 
					    parser_clean = subparsers.add_parser(
 | 
				
			||||||
 | 
					        "clean", help="Delete all temporary build files."
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    parser_clean.add_argument(
 | 
				
			||||||
 | 
					        "configuration", help="Your YAML configuration file(s).", nargs="+"
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dashboard = subparsers.add_parser(
 | 
					    parser_dashboard = subparsers.add_parser(
 | 
				
			||||||
        "dashboard", help="Create a simple web server for a dashboard."
 | 
					        "dashboard", help="Create a simple web server for a dashboard."
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    dashboard.add_argument(
 | 
					    parser_dashboard.add_argument(
 | 
				
			||||||
 | 
					        "configuration",
 | 
				
			||||||
 | 
					        help="Your YAML configuration file directory.",
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    parser_dashboard.add_argument(
 | 
				
			||||||
        "--port",
 | 
					        "--port",
 | 
				
			||||||
        help="The HTTP port to open connections on. Defaults to 6052.",
 | 
					        help="The HTTP port to open connections on. Defaults to 6052.",
 | 
				
			||||||
        type=int,
 | 
					        type=int,
 | 
				
			||||||
        default=6052,
 | 
					        default=6052,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    dashboard.add_argument(
 | 
					    parser_dashboard.add_argument(
 | 
				
			||||||
        "--username",
 | 
					        "--username",
 | 
				
			||||||
        help="The optional username to require " "for authentication.",
 | 
					        help="The optional username to require for authentication.",
 | 
				
			||||||
        type=str,
 | 
					        type=str,
 | 
				
			||||||
        default="",
 | 
					        default="",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    dashboard.add_argument(
 | 
					    parser_dashboard.add_argument(
 | 
				
			||||||
        "--password",
 | 
					        "--password",
 | 
				
			||||||
        help="The optional password to require " "for authentication.",
 | 
					        help="The optional password to require for authentication.",
 | 
				
			||||||
        type=str,
 | 
					        type=str,
 | 
				
			||||||
        default="",
 | 
					        default="",
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    dashboard.add_argument(
 | 
					    parser_dashboard.add_argument(
 | 
				
			||||||
        "--open-ui", help="Open the dashboard UI in a browser.", action="store_true"
 | 
					        "--open-ui", help="Open the dashboard UI in a browser.", action="store_true"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    dashboard.add_argument("--hassio", help=argparse.SUPPRESS, action="store_true")
 | 
					    parser_dashboard.add_argument(
 | 
				
			||||||
    dashboard.add_argument(
 | 
					        "--hassio", help=argparse.SUPPRESS, action="store_true"
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    parser_dashboard.add_argument(
 | 
				
			||||||
        "--socket", help="Make the dashboard serve under a unix socket", type=str
 | 
					        "--socket", help="Make the dashboard serve under a unix socket", type=str
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vscode = subparsers.add_parser("vscode", help=argparse.SUPPRESS)
 | 
					    parser_vscode = subparsers.add_parser("vscode")
 | 
				
			||||||
    vscode.add_argument("--ace", action="store_true")
 | 
					    parser_vscode.add_argument(
 | 
				
			||||||
 | 
					        "configuration", help="Your YAML configuration file.", nargs=1
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    parser_vscode.add_argument("--ace", action="store_true")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    subparsers.add_parser("update-all", help=argparse.SUPPRESS)
 | 
					    parser_update = subparsers.add_parser("update-all")
 | 
				
			||||||
 | 
					    parser_update.add_argument(
 | 
				
			||||||
 | 
					        "configuration", help="Your YAML configuration file directory.", nargs=1
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return parser.parse_args(argv[1:])
 | 
					    return parser.parse_args(argv[1:])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -595,9 +699,13 @@ def run_esphome(argv):
 | 
				
			|||||||
    CORE.dashboard = args.dashboard
 | 
					    CORE.dashboard = args.dashboard
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setup_log(args.verbose, args.quiet)
 | 
					    setup_log(args.verbose, args.quiet)
 | 
				
			||||||
    if args.command != "version" and not args.configuration:
 | 
					    if args.deprecated_argv_suggestion is not None and args.command != "vscode":
 | 
				
			||||||
        _LOGGER.error("Missing configuration parameter, see esphome --help.")
 | 
					        _LOGGER.warning(
 | 
				
			||||||
        return 1
 | 
					            "Calling ESPHome with the configuration before the command is deprecated "
 | 
				
			||||||
 | 
					            "and will be removed in the future. "
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        _LOGGER.warning("Please instead use:")
 | 
				
			||||||
 | 
					        _LOGGER.warning("   esphome %s", " ".join(args.deprecated_argv_suggestion[1:]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if sys.version_info < (3, 7, 0):
 | 
					    if sys.version_info < (3, 7, 0):
 | 
				
			||||||
        _LOGGER.error(
 | 
					        _LOGGER.error(
 | 
				
			||||||
@@ -610,7 +718,7 @@ def run_esphome(argv):
 | 
				
			|||||||
        try:
 | 
					        try:
 | 
				
			||||||
            return PRE_CONFIG_ACTIONS[args.command](args)
 | 
					            return PRE_CONFIG_ACTIONS[args.command](args)
 | 
				
			||||||
        except EsphomeError as e:
 | 
					        except EsphomeError as e:
 | 
				
			||||||
            _LOGGER.error(e)
 | 
					            _LOGGER.error(e, exc_info=args.verbose)
 | 
				
			||||||
            return 1
 | 
					            return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for conf_path in args.configuration:
 | 
					    for conf_path in args.configuration:
 | 
				
			||||||
@@ -628,7 +736,7 @@ def run_esphome(argv):
 | 
				
			|||||||
        try:
 | 
					        try:
 | 
				
			||||||
            rc = POST_CONFIG_ACTIONS[args.command](args, config)
 | 
					            rc = POST_CONFIG_ACTIONS[args.command](args, config)
 | 
				
			||||||
        except EsphomeError as e:
 | 
					        except EsphomeError as e:
 | 
				
			||||||
            _LOGGER.error(e)
 | 
					            _LOGGER.error(e, exc_info=args.verbose)
 | 
				
			||||||
            return 1
 | 
					            return 1
 | 
				
			||||||
        if rc != 0:
 | 
					        if rc != 0:
 | 
				
			||||||
            return rc
 | 
					            return rc
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,6 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_TYPE_ID,
 | 
					    CONF_TYPE_ID,
 | 
				
			||||||
    CONF_TIME,
 | 
					    CONF_TIME,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from esphome.core import coroutine
 | 
					 | 
				
			||||||
from esphome.jsonschema import jschema_extractor
 | 
					from esphome.jsonschema import jschema_extractor
 | 
				
			||||||
from esphome.util import Registry
 | 
					from esphome.util import Registry
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -142,27 +141,27 @@ NotCondition = cg.esphome_ns.class_("NotCondition", Condition)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@register_condition("and", AndCondition, validate_condition_list)
 | 
					@register_condition("and", AndCondition, validate_condition_list)
 | 
				
			||||||
def and_condition_to_code(config, condition_id, template_arg, args):
 | 
					async def and_condition_to_code(config, condition_id, template_arg, args):
 | 
				
			||||||
    conditions = yield build_condition_list(config, template_arg, args)
 | 
					    conditions = await build_condition_list(config, template_arg, args)
 | 
				
			||||||
    yield cg.new_Pvariable(condition_id, template_arg, conditions)
 | 
					    return cg.new_Pvariable(condition_id, template_arg, conditions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@register_condition("or", OrCondition, validate_condition_list)
 | 
					@register_condition("or", OrCondition, validate_condition_list)
 | 
				
			||||||
def or_condition_to_code(config, condition_id, template_arg, args):
 | 
					async def or_condition_to_code(config, condition_id, template_arg, args):
 | 
				
			||||||
    conditions = yield build_condition_list(config, template_arg, args)
 | 
					    conditions = await build_condition_list(config, template_arg, args)
 | 
				
			||||||
    yield cg.new_Pvariable(condition_id, template_arg, conditions)
 | 
					    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)
 | 
				
			||||||
def not_condition_to_code(config, condition_id, template_arg, args):
 | 
					async def not_condition_to_code(config, condition_id, template_arg, args):
 | 
				
			||||||
    condition = yield build_condition(config, template_arg, args)
 | 
					    condition = await build_condition(config, template_arg, args)
 | 
				
			||||||
    yield cg.new_Pvariable(condition_id, template_arg, condition)
 | 
					    return cg.new_Pvariable(condition_id, template_arg, condition)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@register_condition("lambda", LambdaCondition, cv.lambda_)
 | 
					@register_condition("lambda", LambdaCondition, cv.returning_lambda)
 | 
				
			||||||
def lambda_condition_to_code(config, condition_id, template_arg, args):
 | 
					async def lambda_condition_to_code(config, condition_id, template_arg, args):
 | 
				
			||||||
    lambda_ = yield cg.process_lambda(config, args, return_type=bool)
 | 
					    lambda_ = await cg.process_lambda(config, args, return_type=bool)
 | 
				
			||||||
    yield cg.new_Pvariable(condition_id, template_arg, lambda_)
 | 
					    return cg.new_Pvariable(condition_id, template_arg, lambda_)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@register_condition(
 | 
					@register_condition(
 | 
				
			||||||
@@ -177,26 +176,26 @@ def lambda_condition_to_code(config, condition_id, template_arg, args):
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    ).extend(cv.COMPONENT_SCHEMA),
 | 
					    ).extend(cv.COMPONENT_SCHEMA),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
def for_condition_to_code(config, condition_id, template_arg, args):
 | 
					async def for_condition_to_code(config, condition_id, template_arg, args):
 | 
				
			||||||
    condition = yield build_condition(
 | 
					    condition = await build_condition(
 | 
				
			||||||
        config[CONF_CONDITION], cg.TemplateArguments(), []
 | 
					        config[CONF_CONDITION], cg.TemplateArguments(), []
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    var = cg.new_Pvariable(condition_id, template_arg, condition)
 | 
					    var = cg.new_Pvariable(condition_id, template_arg, condition)
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    templ = yield cg.templatable(config[CONF_TIME], args, cg.uint32)
 | 
					    templ = await cg.templatable(config[CONF_TIME], args, cg.uint32)
 | 
				
			||||||
    cg.add(var.set_time(templ))
 | 
					    cg.add(var.set_time(templ))
 | 
				
			||||||
    yield var
 | 
					    return var
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@register_action(
 | 
					@register_action(
 | 
				
			||||||
    "delay", DelayAction, cv.templatable(cv.positive_time_period_milliseconds)
 | 
					    "delay", DelayAction, cv.templatable(cv.positive_time_period_milliseconds)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
def delay_action_to_code(config, action_id, template_arg, args):
 | 
					async def delay_action_to_code(config, action_id, template_arg, args):
 | 
				
			||||||
    var = cg.new_Pvariable(action_id, template_arg)
 | 
					    var = cg.new_Pvariable(action_id, template_arg)
 | 
				
			||||||
    yield cg.register_component(var, {})
 | 
					    await cg.register_component(var, {})
 | 
				
			||||||
    template_ = yield cg.templatable(config, args, cg.uint32)
 | 
					    template_ = await cg.templatable(config, args, cg.uint32)
 | 
				
			||||||
    cg.add(var.set_delay(template_))
 | 
					    cg.add(var.set_delay(template_))
 | 
				
			||||||
    yield var
 | 
					    return var
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@register_action(
 | 
					@register_action(
 | 
				
			||||||
@@ -211,16 +210,16 @@ def delay_action_to_code(config, action_id, template_arg, args):
 | 
				
			|||||||
        cv.has_at_least_one_key(CONF_THEN, CONF_ELSE),
 | 
					        cv.has_at_least_one_key(CONF_THEN, CONF_ELSE),
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
def if_action_to_code(config, action_id, template_arg, args):
 | 
					async def if_action_to_code(config, action_id, template_arg, args):
 | 
				
			||||||
    conditions = yield build_condition(config[CONF_CONDITION], template_arg, args)
 | 
					    conditions = await build_condition(config[CONF_CONDITION], 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 = yield build_action_list(config[CONF_THEN], template_arg, args)
 | 
					        actions = await build_action_list(config[CONF_THEN], template_arg, args)
 | 
				
			||||||
        cg.add(var.add_then(actions))
 | 
					        cg.add(var.add_then(actions))
 | 
				
			||||||
    if CONF_ELSE in config:
 | 
					    if CONF_ELSE in config:
 | 
				
			||||||
        actions = yield build_action_list(config[CONF_ELSE], template_arg, args)
 | 
					        actions = await build_action_list(config[CONF_ELSE], template_arg, args)
 | 
				
			||||||
        cg.add(var.add_else(actions))
 | 
					        cg.add(var.add_else(actions))
 | 
				
			||||||
    yield var
 | 
					    return var
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@register_action(
 | 
					@register_action(
 | 
				
			||||||
@@ -233,12 +232,12 @@ def if_action_to_code(config, action_id, template_arg, args):
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
def while_action_to_code(config, action_id, template_arg, args):
 | 
					async def while_action_to_code(config, action_id, template_arg, args):
 | 
				
			||||||
    conditions = yield build_condition(config[CONF_CONDITION], template_arg, args)
 | 
					    conditions = await build_condition(config[CONF_CONDITION], template_arg, args)
 | 
				
			||||||
    var = cg.new_Pvariable(action_id, template_arg, conditions)
 | 
					    var = cg.new_Pvariable(action_id, template_arg, conditions)
 | 
				
			||||||
    actions = yield build_action_list(config[CONF_THEN], template_arg, args)
 | 
					    actions = await build_action_list(config[CONF_THEN], template_arg, args)
 | 
				
			||||||
    cg.add(var.add_then(actions))
 | 
					    cg.add(var.add_then(actions))
 | 
				
			||||||
    yield var
 | 
					    return var
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def validate_wait_until(value):
 | 
					def validate_wait_until(value):
 | 
				
			||||||
@@ -253,17 +252,17 @@ def validate_wait_until(value):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@register_action("wait_until", WaitUntilAction, validate_wait_until)
 | 
					@register_action("wait_until", WaitUntilAction, validate_wait_until)
 | 
				
			||||||
def wait_until_action_to_code(config, action_id, template_arg, args):
 | 
					async def wait_until_action_to_code(config, action_id, template_arg, args):
 | 
				
			||||||
    conditions = yield build_condition(config[CONF_CONDITION], template_arg, args)
 | 
					    conditions = await build_condition(config[CONF_CONDITION], template_arg, args)
 | 
				
			||||||
    var = cg.new_Pvariable(action_id, template_arg, conditions)
 | 
					    var = cg.new_Pvariable(action_id, template_arg, conditions)
 | 
				
			||||||
    yield cg.register_component(var, {})
 | 
					    await cg.register_component(var, {})
 | 
				
			||||||
    yield var
 | 
					    return var
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@register_action("lambda", LambdaAction, cv.lambda_)
 | 
					@register_action("lambda", LambdaAction, cv.lambda_)
 | 
				
			||||||
def lambda_action_to_code(config, action_id, template_arg, args):
 | 
					async def lambda_action_to_code(config, action_id, template_arg, args):
 | 
				
			||||||
    lambda_ = yield cg.process_lambda(config, args, return_type=cg.void)
 | 
					    lambda_ = await cg.process_lambda(config, args, return_type=cg.void)
 | 
				
			||||||
    yield cg.new_Pvariable(action_id, template_arg, lambda_)
 | 
					    return cg.new_Pvariable(action_id, template_arg, lambda_)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@register_action(
 | 
					@register_action(
 | 
				
			||||||
@@ -275,54 +274,51 @@ def lambda_action_to_code(config, action_id, template_arg, args):
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
def component_update_action_to_code(config, action_id, template_arg, args):
 | 
					async def component_update_action_to_code(config, action_id, template_arg, args):
 | 
				
			||||||
    comp = yield cg.get_variable(config[CONF_ID])
 | 
					    comp = await cg.get_variable(config[CONF_ID])
 | 
				
			||||||
    yield cg.new_Pvariable(action_id, template_arg, comp)
 | 
					    return cg.new_Pvariable(action_id, template_arg, comp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@coroutine
 | 
					async def build_action(full_config, template_arg, args):
 | 
				
			||||||
def build_action(full_config, template_arg, args):
 | 
					 | 
				
			||||||
    registry_entry, config = cg.extract_registry_entry_config(
 | 
					    registry_entry, config = cg.extract_registry_entry_config(
 | 
				
			||||||
        ACTION_REGISTRY, full_config
 | 
					        ACTION_REGISTRY, full_config
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    action_id = full_config[CONF_TYPE_ID]
 | 
					    action_id = full_config[CONF_TYPE_ID]
 | 
				
			||||||
    builder = registry_entry.coroutine_fun
 | 
					    builder = registry_entry.coroutine_fun
 | 
				
			||||||
    yield builder(config, action_id, template_arg, args)
 | 
					    ret = await builder(config, action_id, template_arg, args)
 | 
				
			||||||
 | 
					    return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@coroutine
 | 
					async def build_action_list(config, templ, arg_type):
 | 
				
			||||||
def build_action_list(config, templ, arg_type):
 | 
					 | 
				
			||||||
    actions = []
 | 
					    actions = []
 | 
				
			||||||
    for conf in config:
 | 
					    for conf in config:
 | 
				
			||||||
        action = yield build_action(conf, templ, arg_type)
 | 
					        action = await build_action(conf, templ, arg_type)
 | 
				
			||||||
        actions.append(action)
 | 
					        actions.append(action)
 | 
				
			||||||
    yield actions
 | 
					    return actions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@coroutine
 | 
					async def build_condition(full_config, template_arg, args):
 | 
				
			||||||
def build_condition(full_config, template_arg, args):
 | 
					 | 
				
			||||||
    registry_entry, config = cg.extract_registry_entry_config(
 | 
					    registry_entry, config = cg.extract_registry_entry_config(
 | 
				
			||||||
        CONDITION_REGISTRY, full_config
 | 
					        CONDITION_REGISTRY, full_config
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    action_id = full_config[CONF_TYPE_ID]
 | 
					    action_id = full_config[CONF_TYPE_ID]
 | 
				
			||||||
    builder = registry_entry.coroutine_fun
 | 
					    builder = registry_entry.coroutine_fun
 | 
				
			||||||
    yield builder(config, action_id, template_arg, args)
 | 
					    ret = await builder(config, action_id, template_arg, args)
 | 
				
			||||||
 | 
					    return ret
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@coroutine
 | 
					async def build_condition_list(config, templ, args):
 | 
				
			||||||
def build_condition_list(config, templ, args):
 | 
					 | 
				
			||||||
    conditions = []
 | 
					    conditions = []
 | 
				
			||||||
    for conf in config:
 | 
					    for conf in config:
 | 
				
			||||||
        condition = yield build_condition(conf, templ, args)
 | 
					        condition = await build_condition(conf, templ, args)
 | 
				
			||||||
        conditions.append(condition)
 | 
					        conditions.append(condition)
 | 
				
			||||||
    yield conditions
 | 
					    return conditions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@coroutine
 | 
					async def build_automation(trigger, args, config):
 | 
				
			||||||
def build_automation(trigger, args, config):
 | 
					 | 
				
			||||||
    arg_types = [arg[0] for arg in args]
 | 
					    arg_types = [arg[0] for arg in args]
 | 
				
			||||||
    templ = cg.TemplateArguments(*arg_types)
 | 
					    templ = cg.TemplateArguments(*arg_types)
 | 
				
			||||||
    obj = cg.new_Pvariable(config[CONF_AUTOMATION_ID], templ, trigger)
 | 
					    obj = cg.new_Pvariable(config[CONF_AUTOMATION_ID], templ, trigger)
 | 
				
			||||||
    actions = yield build_action_list(config[CONF_THEN], templ, args)
 | 
					    actions = await build_action_list(config[CONF_THEN], templ, args)
 | 
				
			||||||
    cg.add(obj.add_actions(actions))
 | 
					    cg.add(obj.add_actions(actions))
 | 
				
			||||||
    yield obj
 | 
					    return obj
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@ from esphome.cpp_generator import (  # noqa
 | 
				
			|||||||
    Statement,
 | 
					    Statement,
 | 
				
			||||||
    LineComment,
 | 
					    LineComment,
 | 
				
			||||||
    progmem_array,
 | 
					    progmem_array,
 | 
				
			||||||
 | 
					    static_const_array,
 | 
				
			||||||
    statement,
 | 
					    statement,
 | 
				
			||||||
    variable,
 | 
					    variable,
 | 
				
			||||||
    new_variable,
 | 
					    new_variable,
 | 
				
			||||||
@@ -59,6 +60,7 @@ from esphome.cpp_types import (  # noqa
 | 
				
			|||||||
    uint8,
 | 
					    uint8,
 | 
				
			||||||
    uint16,
 | 
					    uint16,
 | 
				
			||||||
    uint32,
 | 
					    uint32,
 | 
				
			||||||
 | 
					    uint64,
 | 
				
			||||||
    int32,
 | 
					    int32,
 | 
				
			||||||
    const_char_ptr,
 | 
					    const_char_ptr,
 | 
				
			||||||
    NAN,
 | 
					    NAN,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace a4988 {
 | 
					namespace a4988 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *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, "Setting up A4988...");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,16 +18,16 @@ CONFIG_SCHEMA = stepper.STEPPER_SCHEMA.extend(
 | 
				
			|||||||
).extend(cv.COMPONENT_SCHEMA)
 | 
					).extend(cv.COMPONENT_SCHEMA)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    yield stepper.register_stepper(var, config)
 | 
					    await stepper.register_stepper(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    step_pin = yield cg.gpio_pin_expression(config[CONF_STEP_PIN])
 | 
					    step_pin = await cg.gpio_pin_expression(config[CONF_STEP_PIN])
 | 
				
			||||||
    cg.add(var.set_step_pin(step_pin))
 | 
					    cg.add(var.set_step_pin(step_pin))
 | 
				
			||||||
    dir_pin = yield cg.gpio_pin_expression(config[CONF_DIR_PIN])
 | 
					    dir_pin = await cg.gpio_pin_expression(config[CONF_DIR_PIN])
 | 
				
			||||||
    cg.add(var.set_dir_pin(dir_pin))
 | 
					    cg.add(var.set_dir_pin(dir_pin))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if CONF_SLEEP_PIN in config:
 | 
					    if CONF_SLEEP_PIN in config:
 | 
				
			||||||
        sleep_pin = yield cg.gpio_pin_expression(config[CONF_SLEEP_PIN])
 | 
					        sleep_pin = await cg.gpio_pin_expression(config[CONF_SLEEP_PIN])
 | 
				
			||||||
        cg.add(var.set_sleep_pin(sleep_pin))
 | 
					        cg.add(var.set_sleep_pin(sleep_pin))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,15 +9,15 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace ac_dimmer {
 | 
					namespace ac_dimmer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "ac_dimmer";
 | 
					static const char *const TAG = "ac_dimmer";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Global array to store dimmer objects
 | 
					// Global array to store dimmer objects
 | 
				
			||||||
static AcDimmerDataStore *all_dimmers[32];
 | 
					static AcDimmerDataStore *all_dimmers[32];  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Time in microseconds the gate should be held high
 | 
					/// Time in microseconds the gate should be held high
 | 
				
			||||||
/// 10µs should be long enough for most triacs
 | 
					/// 10µs should be long enough for most triacs
 | 
				
			||||||
/// For reference: BT136 datasheet says 2µs nominal (page 7)
 | 
					/// For reference: BT136 datasheet says 2µs nominal (page 7)
 | 
				
			||||||
static uint32_t GATE_ENABLE_TIME = 10;
 | 
					static const uint32_t GATE_ENABLE_TIME = 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Function called from timer interrupt
 | 
					/// Function called from timer interrupt
 | 
				
			||||||
/// Input is current time in microseconds (micros())
 | 
					/// Input is current time in microseconds (micros())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,18 +32,18 @@ CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend(
 | 
				
			|||||||
).extend(cv.COMPONENT_SCHEMA)
 | 
					).extend(cv.COMPONENT_SCHEMA)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # override default min power to 10%
 | 
					    # override default min power to 10%
 | 
				
			||||||
    if CONF_MIN_POWER not in config:
 | 
					    if CONF_MIN_POWER not in config:
 | 
				
			||||||
        config[CONF_MIN_POWER] = 0.1
 | 
					        config[CONF_MIN_POWER] = 0.1
 | 
				
			||||||
    yield output.register_output(var, config)
 | 
					    await output.register_output(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pin = yield cg.gpio_pin_expression(config[CONF_GATE_PIN])
 | 
					    pin = await cg.gpio_pin_expression(config[CONF_GATE_PIN])
 | 
				
			||||||
    cg.add(var.set_gate_pin(pin))
 | 
					    cg.add(var.set_gate_pin(pin))
 | 
				
			||||||
    pin = yield cg.gpio_pin_expression(config[CONF_ZERO_CROSS_PIN])
 | 
					    pin = await cg.gpio_pin_expression(config[CONF_ZERO_CROSS_PIN])
 | 
				
			||||||
    cg.add(var.set_zero_cross_pin(pin))
 | 
					    cg.add(var.set_zero_cross_pin(pin))
 | 
				
			||||||
    cg.add(var.set_init_with_half_cycle(config[CONF_INIT_WITH_HALF_CYCLE]))
 | 
					    cg.add(var.set_init_with_half_cycle(config[CONF_INIT_WITH_HALF_CYCLE]))
 | 
				
			||||||
    cg.add(var.set_method(config[CONF_METHOD]))
 | 
					    cg.add(var.set_method(config[CONF_METHOD]))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,8 +21,7 @@ CONFIG_SCHEMA = cv.Schema({})
 | 
				
			|||||||
    "Adalight",
 | 
					    "Adalight",
 | 
				
			||||||
    {cv.GenerateID(CONF_UART_ID): cv.use_id(uart.UARTComponent)},
 | 
					    {cv.GenerateID(CONF_UART_ID): cv.use_id(uart.UARTComponent)},
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
def adalight_light_effect_to_code(config, effect_id):
 | 
					async def adalight_light_effect_to_code(config, effect_id):
 | 
				
			||||||
    effect = cg.new_Pvariable(effect_id, config[CONF_NAME])
 | 
					    effect = cg.new_Pvariable(effect_id, config[CONF_NAME])
 | 
				
			||||||
    yield uart.register_uart_device(effect, config)
 | 
					    await uart.register_uart_device(effect, config)
 | 
				
			||||||
 | 
					    return effect
 | 
				
			||||||
    yield effect
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace adalight {
 | 
					namespace adalight {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "adalight_light_effect";
 | 
					static const char *const TAG = "adalight_light_effect";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const uint32_t ADALIGHT_ACK_INTERVAL = 1000;
 | 
					static const uint32_t ADALIGHT_ACK_INTERVAL = 1000;
 | 
				
			||||||
static const uint32_t ADALIGHT_RECEIVE_TIMEOUT = 1000;
 | 
					static const uint32_t ADALIGHT_RECEIVE_TIMEOUT = 1000;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,10 +8,33 @@ ADC_MODE(ADC_VCC)
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace adc {
 | 
					namespace adc {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "adc";
 | 
					static const char *const TAG = "adc";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef ARDUINO_ARCH_ESP32
 | 
					#ifdef ARDUINO_ARCH_ESP32
 | 
				
			||||||
void ADCSensor::set_attenuation(adc_attenuation_t attenuation) { this->attenuation_ = attenuation; }
 | 
					void ADCSensor::set_attenuation(adc_atten_t attenuation) { this->attenuation_ = attenuation; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline adc1_channel_t gpio_to_adc1(uint8_t pin) {
 | 
				
			||||||
 | 
					  switch (pin) {
 | 
				
			||||||
 | 
					    case 36:
 | 
				
			||||||
 | 
					      return ADC1_CHANNEL_0;
 | 
				
			||||||
 | 
					    case 37:
 | 
				
			||||||
 | 
					      return ADC1_CHANNEL_1;
 | 
				
			||||||
 | 
					    case 38:
 | 
				
			||||||
 | 
					      return ADC1_CHANNEL_2;
 | 
				
			||||||
 | 
					    case 39:
 | 
				
			||||||
 | 
					      return ADC1_CHANNEL_3;
 | 
				
			||||||
 | 
					    case 32:
 | 
				
			||||||
 | 
					      return ADC1_CHANNEL_4;
 | 
				
			||||||
 | 
					    case 33:
 | 
				
			||||||
 | 
					      return ADC1_CHANNEL_5;
 | 
				
			||||||
 | 
					    case 34:
 | 
				
			||||||
 | 
					      return ADC1_CHANNEL_6;
 | 
				
			||||||
 | 
					    case 35:
 | 
				
			||||||
 | 
					      return ADC1_CHANNEL_7;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      return ADC1_CHANNEL_MAX;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ADCSensor::setup() {
 | 
					void ADCSensor::setup() {
 | 
				
			||||||
@@ -21,7 +44,9 @@ void ADCSensor::setup() {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef ARDUINO_ARCH_ESP32
 | 
					#ifdef ARDUINO_ARCH_ESP32
 | 
				
			||||||
  analogSetPinAttenuation(this->pin_, this->attenuation_);
 | 
					  adc1_config_channel_atten(gpio_to_adc1(pin_), attenuation_);
 | 
				
			||||||
 | 
					  adc1_config_width(ADC_WIDTH_BIT_12);
 | 
				
			||||||
 | 
					  adc_gpio_init(ADC_UNIT_1, (adc_channel_t) gpio_to_adc1(pin_));
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void ADCSensor::dump_config() {
 | 
					void ADCSensor::dump_config() {
 | 
				
			||||||
@@ -36,18 +61,20 @@ void ADCSensor::dump_config() {
 | 
				
			|||||||
#ifdef ARDUINO_ARCH_ESP32
 | 
					#ifdef ARDUINO_ARCH_ESP32
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "  Pin: %u", this->pin_);
 | 
					  ESP_LOGCONFIG(TAG, "  Pin: %u", this->pin_);
 | 
				
			||||||
  switch (this->attenuation_) {
 | 
					  switch (this->attenuation_) {
 | 
				
			||||||
    case ADC_0db:
 | 
					    case ADC_ATTEN_DB_0:
 | 
				
			||||||
      ESP_LOGCONFIG(TAG, " Attenuation: 0db (max 1.1V)");
 | 
					      ESP_LOGCONFIG(TAG, " Attenuation: 0db (max 1.1V)");
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case ADC_2_5db:
 | 
					    case ADC_ATTEN_DB_2_5:
 | 
				
			||||||
      ESP_LOGCONFIG(TAG, " Attenuation: 2.5db (max 1.5V)");
 | 
					      ESP_LOGCONFIG(TAG, " Attenuation: 2.5db (max 1.5V)");
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case ADC_6db:
 | 
					    case ADC_ATTEN_DB_6:
 | 
				
			||||||
      ESP_LOGCONFIG(TAG, " Attenuation: 6db (max 2.2V)");
 | 
					      ESP_LOGCONFIG(TAG, " Attenuation: 6db (max 2.2V)");
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case ADC_11db:
 | 
					    case ADC_ATTEN_DB_11:
 | 
				
			||||||
      ESP_LOGCONFIG(TAG, " Attenuation: 11db (max 3.9V)");
 | 
					      ESP_LOGCONFIG(TAG, " Attenuation: 11db (max 3.9V)");
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					    default:  // This is to satisfy the unused ADC_ATTEN_MAX
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  LOG_UPDATE_INTERVAL(this);
 | 
					  LOG_UPDATE_INTERVAL(this);
 | 
				
			||||||
@@ -60,20 +87,23 @@ void ADCSensor::update() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
float ADCSensor::sample() {
 | 
					float ADCSensor::sample() {
 | 
				
			||||||
#ifdef ARDUINO_ARCH_ESP32
 | 
					#ifdef ARDUINO_ARCH_ESP32
 | 
				
			||||||
  float value_v = analogRead(this->pin_) / 4095.0f;  // NOLINT
 | 
					  int raw = adc1_get_raw(gpio_to_adc1(pin_));
 | 
				
			||||||
 | 
					  float value_v = raw / 4095.0f;
 | 
				
			||||||
  switch (this->attenuation_) {
 | 
					  switch (this->attenuation_) {
 | 
				
			||||||
    case ADC_0db:
 | 
					    case ADC_ATTEN_DB_0:
 | 
				
			||||||
      value_v *= 1.1;
 | 
					      value_v *= 1.1;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case ADC_2_5db:
 | 
					    case ADC_ATTEN_DB_2_5:
 | 
				
			||||||
      value_v *= 1.5;
 | 
					      value_v *= 1.5;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case ADC_6db:
 | 
					    case ADC_ATTEN_DB_6:
 | 
				
			||||||
      value_v *= 2.2;
 | 
					      value_v *= 2.2;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case ADC_11db:
 | 
					    case ADC_ATTEN_DB_11:
 | 
				
			||||||
      value_v *= 3.9;
 | 
					      value_v *= 3.9;
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					    default:  // This is to satisfy the unused ADC_ATTEN_MAX
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return value_v;
 | 
					  return value_v;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,10 @@
 | 
				
			|||||||
#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"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef ARDUINO_ARCH_ESP32
 | 
				
			||||||
 | 
					#include "driver/adc.h"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace adc {
 | 
					namespace adc {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -13,7 +17,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
 | 
				
			|||||||
 public:
 | 
					 public:
 | 
				
			||||||
#ifdef ARDUINO_ARCH_ESP32
 | 
					#ifdef ARDUINO_ARCH_ESP32
 | 
				
			||||||
  /// Set the attenuation for this pin. Only available on the ESP32.
 | 
					  /// Set the attenuation for this pin. Only available on the ESP32.
 | 
				
			||||||
  void set_attenuation(adc_attenuation_t attenuation);
 | 
					  void set_attenuation(adc_atten_t attenuation);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Update adc values.
 | 
					  /// Update adc values.
 | 
				
			||||||
@@ -34,7 +38,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
 | 
				
			|||||||
  uint8_t pin_;
 | 
					  uint8_t pin_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef ARDUINO_ARCH_ESP32
 | 
					#ifdef ARDUINO_ARCH_ESP32
 | 
				
			||||||
  adc_attenuation_t attenuation_{ADC_0db};
 | 
					  adc_atten_t attenuation_{ADC_ATTEN_DB_0};
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_PIN,
 | 
					    CONF_PIN,
 | 
				
			||||||
    DEVICE_CLASS_VOLTAGE,
 | 
					    DEVICE_CLASS_VOLTAGE,
 | 
				
			||||||
    ICON_EMPTY,
 | 
					    ICON_EMPTY,
 | 
				
			||||||
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_VOLT,
 | 
					    UNIT_VOLT,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -15,10 +16,10 @@ from esphome.const import (
 | 
				
			|||||||
AUTO_LOAD = ["voltage_sampler"]
 | 
					AUTO_LOAD = ["voltage_sampler"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ATTENUATION_MODES = {
 | 
					ATTENUATION_MODES = {
 | 
				
			||||||
    "0db": cg.global_ns.ADC_0db,
 | 
					    "0db": cg.global_ns.ADC_ATTEN_DB_0,
 | 
				
			||||||
    "2.5db": cg.global_ns.ADC_2_5db,
 | 
					    "2.5db": cg.global_ns.ADC_ATTEN_DB_2_5,
 | 
				
			||||||
    "6db": cg.global_ns.ADC_6db,
 | 
					    "6db": cg.global_ns.ADC_ATTEN_DB_6,
 | 
				
			||||||
    "11db": cg.global_ns.ADC_11db,
 | 
					    "11db": cg.global_ns.ADC_ATTEN_DB_11,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -35,7 +36,9 @@ ADCSensor = adc_ns.class_(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONFIG_SCHEMA = (
 | 
					CONFIG_SCHEMA = (
 | 
				
			||||||
    sensor.sensor_schema(UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE)
 | 
					    sensor.sensor_schema(
 | 
				
			||||||
 | 
					        UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    .extend(
 | 
					    .extend(
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            cv.GenerateID(): cv.declare_id(ADCSensor),
 | 
					            cv.GenerateID(): cv.declare_id(ADCSensor),
 | 
				
			||||||
@@ -49,10 +52,10 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    yield sensor.register_sensor(var, config)
 | 
					    await sensor.register_sensor(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if config[CONF_PIN] == "VCC":
 | 
					    if config[CONF_PIN] == "VCC":
 | 
				
			||||||
        cg.add_define("USE_ADC_SENSOR_VCC")
 | 
					        cg.add_define("USE_ADC_SENSOR_VCC")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace addressable_light {
 | 
					namespace addressable_light {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char* TAG = "addressable_light.display";
 | 
					static const char *const TAG = "addressable_light.display";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int AddressableLightDisplay::get_width_internal() { return this->width_; }
 | 
					int AddressableLightDisplay::get_width_internal() { return this->width_; }
 | 
				
			||||||
int AddressableLightDisplay::get_height_internal() { return this->height_; }
 | 
					int AddressableLightDisplay::get_height_internal() { return this->height_; }
 | 
				
			||||||
@@ -24,7 +24,7 @@ void AddressableLightDisplay::update() {
 | 
				
			|||||||
void AddressableLightDisplay::display() {
 | 
					void AddressableLightDisplay::display() {
 | 
				
			||||||
  bool dirty = false;
 | 
					  bool dirty = false;
 | 
				
			||||||
  uint8_t old_r, old_g, old_b, old_w;
 | 
					  uint8_t old_r, old_g, old_b, old_w;
 | 
				
			||||||
  Color* c;
 | 
					  Color *c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (uint32_t offset = 0; offset < this->addressable_light_buffer_.size(); offset++) {
 | 
					  for (uint32_t offset = 0; offset < this->addressable_light_buffer_.size(); offset++) {
 | 
				
			||||||
    c = &(this->addressable_light_buffer_[offset]);
 | 
					    c = &(this->addressable_light_buffer_[offset]);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,18 +38,18 @@ CONFIG_SCHEMA = cv.All(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    wrapped_light = yield cg.get_variable(config[CONF_ADDRESSABLE_LIGHT_ID])
 | 
					    wrapped_light = await cg.get_variable(config[CONF_ADDRESSABLE_LIGHT_ID])
 | 
				
			||||||
    cg.add(var.set_width(config[CONF_WIDTH]))
 | 
					    cg.add(var.set_width(config[CONF_WIDTH]))
 | 
				
			||||||
    cg.add(var.set_height(config[CONF_HEIGHT]))
 | 
					    cg.add(var.set_height(config[CONF_HEIGHT]))
 | 
				
			||||||
    cg.add(var.set_light(wrapped_light))
 | 
					    cg.add(var.set_light(wrapped_light))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    yield display.register_display(var, config)
 | 
					    await display.register_display(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if CONF_PIXEL_MAPPER in config:
 | 
					    if CONF_PIXEL_MAPPER in config:
 | 
				
			||||||
        pixel_mapper_template_ = yield cg.process_lambda(
 | 
					        pixel_mapper_template_ = await cg.process_lambda(
 | 
				
			||||||
            config[CONF_PIXEL_MAPPER],
 | 
					            config[CONF_PIXEL_MAPPER],
 | 
				
			||||||
            [(int, "x"), (int, "y")],
 | 
					            [(int, "x"), (int, "y")],
 | 
				
			||||||
            return_type=cg.int_,
 | 
					            return_type=cg.int_,
 | 
				
			||||||
@@ -57,7 +57,7 @@ def to_code(config):
 | 
				
			|||||||
        cg.add(var.set_pixel_mapper(pixel_mapper_template_))
 | 
					        cg.add(var.set_pixel_mapper(pixel_mapper_template_))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if CONF_LAMBDA in config:
 | 
					    if CONF_LAMBDA in config:
 | 
				
			||||||
        lambda_ = yield cg.process_lambda(
 | 
					        lambda_ = await cg.process_lambda(
 | 
				
			||||||
            config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void
 | 
					            config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        cg.add(var.set_writer(lambda_))
 | 
					        cg.add(var.set_writer(lambda_))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace ade7953 {
 | 
					namespace ade7953 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "ade7953";
 | 
					static const char *const TAG = "ade7953";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ADE7953::dump_config() {
 | 
					void ADE7953::dump_config() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "ADE7953:");
 | 
					  ESP_LOGCONFIG(TAG, "ADE7953:");
 | 
				
			||||||
@@ -21,8 +21,8 @@ void ADE7953::dump_config() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ADE_PUBLISH_(name, factor) \
 | 
					#define ADE_PUBLISH_(name, factor) \
 | 
				
			||||||
  if (name && this->name##_sensor_) { \
 | 
					  if ((name) && this->name##_sensor_) { \
 | 
				
			||||||
    float value = *name / factor; \
 | 
					    float value = *(name) / (factor); \
 | 
				
			||||||
    this->name##_sensor_->publish_state(value); \
 | 
					    this->name##_sensor_->publish_state(value); \
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#define ADE_PUBLISH(name, factor) ADE_PUBLISH_(name, factor)
 | 
					#define ADE_PUBLISH(name, factor) ADE_PUBLISH_(name, factor)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ from esphome.const import (
 | 
				
			|||||||
    DEVICE_CLASS_POWER,
 | 
					    DEVICE_CLASS_POWER,
 | 
				
			||||||
    DEVICE_CLASS_VOLTAGE,
 | 
					    DEVICE_CLASS_VOLTAGE,
 | 
				
			||||||
    ICON_EMPTY,
 | 
					    ICON_EMPTY,
 | 
				
			||||||
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_VOLT,
 | 
					    UNIT_VOLT,
 | 
				
			||||||
    UNIT_AMPERE,
 | 
					    UNIT_AMPERE,
 | 
				
			||||||
    UNIT_WATT,
 | 
					    UNIT_WATT,
 | 
				
			||||||
@@ -31,19 +32,27 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
            cv.GenerateID(): cv.declare_id(ADE7953),
 | 
					            cv.GenerateID(): cv.declare_id(ADE7953),
 | 
				
			||||||
            cv.Optional(CONF_IRQ_PIN): pins.input_pin,
 | 
					            cv.Optional(CONF_IRQ_PIN): pins.input_pin,
 | 
				
			||||||
            cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE
 | 
					                UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cv.Optional(CONF_CURRENT_A): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_CURRENT_A): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT
 | 
					                UNIT_AMPERE,
 | 
				
			||||||
 | 
					                ICON_EMPTY,
 | 
				
			||||||
 | 
					                2,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_CURRENT,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cv.Optional(CONF_CURRENT_B): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_CURRENT_B): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT
 | 
					                UNIT_AMPERE,
 | 
				
			||||||
 | 
					                ICON_EMPTY,
 | 
				
			||||||
 | 
					                2,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_CURRENT,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cv.Optional(CONF_ACTIVE_POWER_A): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_ACTIVE_POWER_A): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER
 | 
					                UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cv.Optional(CONF_ACTIVE_POWER_B): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_ACTIVE_POWER_B): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER
 | 
					                UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@@ -52,10 +61,10 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    yield i2c.register_i2c_device(var, config)
 | 
					    await i2c.register_i2c_device(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if CONF_IRQ_PIN in config:
 | 
					    if CONF_IRQ_PIN in config:
 | 
				
			||||||
        cg.add(var.set_irq_pin(config[CONF_IRQ_PIN]))
 | 
					        cg.add(var.set_irq_pin(config[CONF_IRQ_PIN]))
 | 
				
			||||||
@@ -70,5 +79,5 @@ def to_code(config):
 | 
				
			|||||||
        if key not in config:
 | 
					        if key not in config:
 | 
				
			||||||
            continue
 | 
					            continue
 | 
				
			||||||
        conf = config[key]
 | 
					        conf = config[key]
 | 
				
			||||||
        sens = yield sensor.new_sensor(conf)
 | 
					        sens = await sensor.new_sensor(conf)
 | 
				
			||||||
        cg.add(getattr(var, f"set_{key}_sensor")(sens))
 | 
					        cg.add(getattr(var, f"set_{key}_sensor")(sens))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,9 +23,9 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    yield i2c.register_i2c_device(var, config)
 | 
					    await i2c.register_i2c_device(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cg.add(var.set_continuous_mode(config[CONF_CONTINUOUS_MODE]))
 | 
					    cg.add(var.set_continuous_mode(config[CONF_CONTINUOUS_MODE]))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace ads1115 {
 | 
					namespace ads1115 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "ads1115";
 | 
					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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -107,17 +107,22 @@ float ADS1115Component::request_measurement(ADS1115Sensor *sensor) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    this->prev_config_ = config;
 | 
					    this->prev_config_ = config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // about 1.6 ms with 860 samples per second
 | 
					    // about 1.2 ms with 860 samples per second
 | 
				
			||||||
    delay(2);
 | 
					    delay(2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t start = millis();
 | 
					    // in continuous mode, conversion will always be running, rely on the delay
 | 
				
			||||||
    while (this->read_byte_16(ADS1115_REGISTER_CONFIG, &config) && (config >> 15) == 0) {
 | 
					    // to ensure conversion is taking place with the correct settings
 | 
				
			||||||
      if (millis() - start > 100) {
 | 
					    // can we use the rdy pin to trigger when a conversion is done?
 | 
				
			||||||
        ESP_LOGW(TAG, "Reading ADS1115 timed out");
 | 
					    if (!this->continuous_mode_) {
 | 
				
			||||||
        this->status_set_warning();
 | 
					      uint32_t start = millis();
 | 
				
			||||||
        return NAN;
 | 
					      while (this->read_byte_16(ADS1115_REGISTER_CONFIG, &config) && (config >> 15) == 0) {
 | 
				
			||||||
 | 
					        if (millis() - start > 100) {
 | 
				
			||||||
 | 
					          ESP_LOGW(TAG, "Reading ADS1115 timed out");
 | 
				
			||||||
 | 
					          this->status_set_warning();
 | 
				
			||||||
 | 
					          return NAN;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        yield();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      yield();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_MULTIPLEXER,
 | 
					    CONF_MULTIPLEXER,
 | 
				
			||||||
    DEVICE_CLASS_VOLTAGE,
 | 
					    DEVICE_CLASS_VOLTAGE,
 | 
				
			||||||
    ICON_EMPTY,
 | 
					    ICON_EMPTY,
 | 
				
			||||||
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_VOLT,
 | 
					    UNIT_VOLT,
 | 
				
			||||||
    CONF_ID,
 | 
					    CONF_ID,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -51,7 +52,9 @@ ADS1115Sensor = ads1115_ns.class_(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
CONF_ADS1115_ID = "ads1115_id"
 | 
					CONF_ADS1115_ID = "ads1115_id"
 | 
				
			||||||
CONFIG_SCHEMA = (
 | 
					CONFIG_SCHEMA = (
 | 
				
			||||||
    sensor.sensor_schema(UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE)
 | 
					    sensor.sensor_schema(
 | 
				
			||||||
 | 
					        UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    .extend(
 | 
					    .extend(
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            cv.GenerateID(): cv.declare_id(ADS1115Sensor),
 | 
					            cv.GenerateID(): cv.declare_id(ADS1115Sensor),
 | 
				
			||||||
@@ -64,11 +67,11 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    paren = yield cg.get_variable(config[CONF_ADS1115_ID])
 | 
					    paren = await cg.get_variable(config[CONF_ADS1115_ID])
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID], paren)
 | 
					    var = cg.new_Pvariable(config[CONF_ID], paren)
 | 
				
			||||||
    yield sensor.register_sensor(var, config)
 | 
					    await sensor.register_sensor(var, config)
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, 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]))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace aht10 {
 | 
					namespace aht10 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "aht10";
 | 
					static const char *const TAG = "aht10";
 | 
				
			||||||
static const uint8_t AHT10_CALIBRATE_CMD[] = {0xE1};
 | 
					static const uint8_t AHT10_CALIBRATE_CMD[] = {0xE1};
 | 
				
			||||||
static const uint8_t AHT10_MEASURE_CMD[] = {0xAC, 0x33, 0x00};
 | 
					static const uint8_t AHT10_MEASURE_CMD[] = {0xAC, 0x33, 0x00};
 | 
				
			||||||
static const uint8_t AHT10_DEFAULT_DELAY = 5;    // ms, for calibration and temperature measurement
 | 
					static const uint8_t AHT10_DEFAULT_DELAY = 5;    // ms, for calibration and temperature measurement
 | 
				
			||||||
@@ -60,6 +60,7 @@ void AHT10Component::update() {
 | 
				
			|||||||
    delay = AHT10_HUMIDITY_DELAY;
 | 
					    delay = AHT10_HUMIDITY_DELAY;
 | 
				
			||||||
  for (int i = 0; i < AHT10_ATTEMPS; ++i) {
 | 
					  for (int i = 0; i < AHT10_ATTEMPS; ++i) {
 | 
				
			||||||
    ESP_LOGVV(TAG, "Attemps %u at %6ld", i, millis());
 | 
					    ESP_LOGVV(TAG, "Attemps %u at %6ld", i, millis());
 | 
				
			||||||
 | 
					    delay_microseconds_accurate(4);
 | 
				
			||||||
    if (!this->read_bytes(0, data, 6, delay)) {
 | 
					    if (!this->read_bytes(0, data, 6, delay)) {
 | 
				
			||||||
      ESP_LOGD(TAG, "Communication with AHT10 failed, waiting...");
 | 
					      ESP_LOGD(TAG, "Communication with AHT10 failed, waiting...");
 | 
				
			||||||
    } else if ((data[0] & 0x80) == 0x80) {  // Bit[7] = 0b1, device is busy
 | 
					    } else if ((data[0] & 0x80) == 0x80) {  // Bit[7] = 0b1, device is busy
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ from esphome.const import (
 | 
				
			|||||||
    DEVICE_CLASS_HUMIDITY,
 | 
					    DEVICE_CLASS_HUMIDITY,
 | 
				
			||||||
    DEVICE_CLASS_TEMPERATURE,
 | 
					    DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
    ICON_EMPTY,
 | 
					    ICON_EMPTY,
 | 
				
			||||||
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_CELSIUS,
 | 
					    UNIT_CELSIUS,
 | 
				
			||||||
    UNIT_PERCENT,
 | 
					    UNIT_PERCENT,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -22,10 +23,18 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            cv.GenerateID(): cv.declare_id(AHT10Component),
 | 
					            cv.GenerateID(): cv.declare_id(AHT10Component),
 | 
				
			||||||
            cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_CELSIUS, ICON_EMPTY, 2, DEVICE_CLASS_TEMPERATURE
 | 
					                UNIT_CELSIUS,
 | 
				
			||||||
 | 
					                ICON_EMPTY,
 | 
				
			||||||
 | 
					                2,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_PERCENT, ICON_EMPTY, 2, DEVICE_CLASS_HUMIDITY
 | 
					                UNIT_PERCENT,
 | 
				
			||||||
 | 
					                ICON_EMPTY,
 | 
				
			||||||
 | 
					                2,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_HUMIDITY,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@@ -34,15 +43,15 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    yield i2c.register_i2c_device(var, config)
 | 
					    await i2c.register_i2c_device(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if CONF_TEMPERATURE in config:
 | 
					    if CONF_TEMPERATURE in config:
 | 
				
			||||||
        sens = yield sensor.new_sensor(config[CONF_TEMPERATURE])
 | 
					        sens = await sensor.new_sensor(config[CONF_TEMPERATURE])
 | 
				
			||||||
        cg.add(var.set_temperature_sensor(sens))
 | 
					        cg.add(var.set_temperature_sensor(sens))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if CONF_HUMIDITY in config:
 | 
					    if CONF_HUMIDITY in config:
 | 
				
			||||||
        sens = yield sensor.new_sensor(config[CONF_HUMIDITY])
 | 
					        sens = await sensor.new_sensor(config[CONF_HUMIDITY])
 | 
				
			||||||
        cg.add(var.set_humidity_sensor(sens))
 | 
					        cg.add(var.set_humidity_sensor(sens))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace am2320 {
 | 
					namespace am2320 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "am2320";
 | 
					static const char *const TAG = "am2320";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ---=== Calc CRC16 ===---
 | 
					// ---=== Calc CRC16 ===---
 | 
				
			||||||
uint16_t crc_16(uint8_t *ptr, uint8_t length) {
 | 
					uint16_t crc_16(uint8_t *ptr, uint8_t length) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_TEMPERATURE,
 | 
					    CONF_TEMPERATURE,
 | 
				
			||||||
    DEVICE_CLASS_HUMIDITY,
 | 
					    DEVICE_CLASS_HUMIDITY,
 | 
				
			||||||
    DEVICE_CLASS_TEMPERATURE,
 | 
					    DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_CELSIUS,
 | 
					    UNIT_CELSIUS,
 | 
				
			||||||
    ICON_EMPTY,
 | 
					    ICON_EMPTY,
 | 
				
			||||||
    UNIT_PERCENT,
 | 
					    UNIT_PERCENT,
 | 
				
			||||||
@@ -24,10 +25,18 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            cv.GenerateID(): cv.declare_id(AM2320Component),
 | 
					            cv.GenerateID(): cv.declare_id(AM2320Component),
 | 
				
			||||||
            cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE
 | 
					                UNIT_CELSIUS,
 | 
				
			||||||
 | 
					                ICON_EMPTY,
 | 
				
			||||||
 | 
					                1,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY
 | 
					                UNIT_PERCENT,
 | 
				
			||||||
 | 
					                ICON_EMPTY,
 | 
				
			||||||
 | 
					                1,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_HUMIDITY,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@@ -36,15 +45,15 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    yield i2c.register_i2c_device(var, config)
 | 
					    await i2c.register_i2c_device(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if CONF_TEMPERATURE in config:
 | 
					    if CONF_TEMPERATURE in config:
 | 
				
			||||||
        sens = yield sensor.new_sensor(config[CONF_TEMPERATURE])
 | 
					        sens = await sensor.new_sensor(config[CONF_TEMPERATURE])
 | 
				
			||||||
        cg.add(var.set_temperature_sensor(sens))
 | 
					        cg.add(var.set_temperature_sensor(sens))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if CONF_HUMIDITY in config:
 | 
					    if CONF_HUMIDITY in config:
 | 
				
			||||||
        sens = yield sensor.new_sensor(config[CONF_HUMIDITY])
 | 
					        sens = await sensor.new_sensor(config[CONF_HUMIDITY])
 | 
				
			||||||
        cg.add(var.set_humidity_sensor(sens))
 | 
					        cg.add(var.set_humidity_sensor(sens))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,7 @@ CONFIG_SCHEMA = cv.All(font.validate_pillow_installed, ANIMATION_SCHEMA)
 | 
				
			|||||||
CODEOWNERS = ["@syndlex"]
 | 
					CODEOWNERS = ["@syndlex"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    from PIL import Image
 | 
					    from PIL import Image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    path = CORE.relative_config_path(config[CONF_FILE])
 | 
					    path = CORE.relative_config_path(config[CONF_FILE])
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										140
									
								
								esphome/components/anova/anova.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								esphome/components/anova/anova.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,140 @@
 | 
				
			|||||||
 | 
					#include "anova.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef ARDUINO_ARCH_ESP32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace anova {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *TAG = "anova";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using namespace esphome::climate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Anova::dump_config() { LOG_CLIMATE("", "Anova BLE Cooker", this); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Anova::setup() {
 | 
				
			||||||
 | 
					  this->codec_ = new AnovaCodec();
 | 
				
			||||||
 | 
					  this->current_request_ = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Anova::loop() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Anova::control(const ClimateCall &call) {
 | 
				
			||||||
 | 
					  if (call.get_mode().has_value()) {
 | 
				
			||||||
 | 
					    ClimateMode mode = *call.get_mode();
 | 
				
			||||||
 | 
					    AnovaPacket *pkt;
 | 
				
			||||||
 | 
					    switch (mode) {
 | 
				
			||||||
 | 
					      case climate::CLIMATE_MODE_OFF:
 | 
				
			||||||
 | 
					        pkt = this->codec_->get_stop_request();
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case climate::CLIMATE_MODE_HEAT:
 | 
				
			||||||
 | 
					        pkt = this->codec_->get_start_request();
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      default:
 | 
				
			||||||
 | 
					        ESP_LOGW(TAG, "Unsupported mode: %d", mode);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,
 | 
				
			||||||
 | 
					                                           pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
				
			||||||
 | 
					    if (status)
 | 
				
			||||||
 | 
					      ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (call.get_target_temperature().has_value()) {
 | 
				
			||||||
 | 
					    auto pkt = this->codec_->get_set_target_temp_request(*call.get_target_temperature());
 | 
				
			||||||
 | 
					    auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,
 | 
				
			||||||
 | 
					                                           pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
				
			||||||
 | 
					    if (status)
 | 
				
			||||||
 | 
					      ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) {
 | 
				
			||||||
 | 
					  switch (event) {
 | 
				
			||||||
 | 
					    case ESP_GATTC_DISCONNECT_EVT: {
 | 
				
			||||||
 | 
					      this->current_temperature = NAN;
 | 
				
			||||||
 | 
					      this->target_temperature = NAN;
 | 
				
			||||||
 | 
					      this->publish_state();
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case ESP_GATTC_SEARCH_CMPL_EVT: {
 | 
				
			||||||
 | 
					      auto chr = this->parent_->get_characteristic(ANOVA_SERVICE_UUID, ANOVA_CHARACTERISTIC_UUID);
 | 
				
			||||||
 | 
					      if (chr == nullptr) {
 | 
				
			||||||
 | 
					        ESP_LOGW(TAG, "[%s] No control service found at device, not an Anova..?", this->get_name().c_str());
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this->char_handle_ = chr->handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      auto status = esp_ble_gattc_register_for_notify(this->parent_->gattc_if, this->parent_->remote_bda, chr->handle);
 | 
				
			||||||
 | 
					      if (status) {
 | 
				
			||||||
 | 
					        ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", this->get_name().c_str(), status);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
 | 
				
			||||||
 | 
					      this->node_state = espbt::ClientState::Established;
 | 
				
			||||||
 | 
					      this->current_request_ = 0;
 | 
				
			||||||
 | 
					      this->update();
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case ESP_GATTC_NOTIFY_EVT: {
 | 
				
			||||||
 | 
					      if (param->notify.handle != this->char_handle_)
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      this->codec_->decode(param->notify.value, param->notify.value_len);
 | 
				
			||||||
 | 
					      if (this->codec_->has_target_temp()) {
 | 
				
			||||||
 | 
					        this->target_temperature = this->codec_->target_temp_;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (this->codec_->has_current_temp()) {
 | 
				
			||||||
 | 
					        this->current_temperature = this->codec_->current_temp_;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (this->codec_->has_running()) {
 | 
				
			||||||
 | 
					        this->mode = this->codec_->running_ ? climate::CLIMATE_MODE_HEAT : climate::CLIMATE_MODE_OFF;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this->publish_state();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (this->current_request_ > 0) {
 | 
				
			||||||
 | 
					        AnovaPacket *pkt = nullptr;
 | 
				
			||||||
 | 
					        switch (this->current_request_++) {
 | 
				
			||||||
 | 
					          case 1:
 | 
				
			||||||
 | 
					            pkt = this->codec_->get_read_target_temp_request();
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 2:
 | 
				
			||||||
 | 
					            pkt = this->codec_->get_read_current_temp_request();
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          default:
 | 
				
			||||||
 | 
					            this->current_request_ = 0;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (pkt != nullptr) {
 | 
				
			||||||
 | 
					          auto status =
 | 
				
			||||||
 | 
					              esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_, pkt->length,
 | 
				
			||||||
 | 
					                                       pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
				
			||||||
 | 
					          if (status)
 | 
				
			||||||
 | 
					            ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(),
 | 
				
			||||||
 | 
					                     status);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Anova::update() {
 | 
				
			||||||
 | 
					  if (this->node_state != espbt::ClientState::Established)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (this->current_request_ == 0) {
 | 
				
			||||||
 | 
					    auto pkt = this->codec_->get_read_device_status_request();
 | 
				
			||||||
 | 
					    auto status = esp_ble_gattc_write_char(this->parent_->gattc_if, this->parent_->conn_id, this->char_handle_,
 | 
				
			||||||
 | 
					                                           pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
 | 
				
			||||||
 | 
					    if (status)
 | 
				
			||||||
 | 
					      ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
 | 
				
			||||||
 | 
					    this->current_request_++;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace anova
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										50
									
								
								esphome/components/anova/anova.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								esphome/components/anova/anova.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "esphome/core/component.h"
 | 
				
			||||||
 | 
					#include "esphome/components/ble_client/ble_client.h"
 | 
				
			||||||
 | 
					#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
 | 
				
			||||||
 | 
					#include "esphome/components/climate/climate.h"
 | 
				
			||||||
 | 
					#include "anova_base.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef ARDUINO_ARCH_ESP32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <esp_gattc_api.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace anova {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace espbt = esphome::esp32_ble_tracker;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const uint16_t ANOVA_SERVICE_UUID = 0xFFE0;
 | 
				
			||||||
 | 
					static const uint16_t ANOVA_CHARACTERISTIC_UUID = 0xFFE1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Anova : public climate::Climate, public esphome::ble_client::BLEClientNode, public PollingComponent {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  void setup() override;
 | 
				
			||||||
 | 
					  void loop() override;
 | 
				
			||||||
 | 
					  void update() override;
 | 
				
			||||||
 | 
					  void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
 | 
				
			||||||
 | 
					                           esp_ble_gattc_cb_param_t *param) override;
 | 
				
			||||||
 | 
					  void dump_config() override;
 | 
				
			||||||
 | 
					  float get_setup_priority() const override { return setup_priority::DATA; }
 | 
				
			||||||
 | 
					  climate::ClimateTraits traits() {
 | 
				
			||||||
 | 
					    auto traits = climate::ClimateTraits();
 | 
				
			||||||
 | 
					    traits.set_supports_current_temperature(true);
 | 
				
			||||||
 | 
					    traits.set_supports_heat_mode(true);
 | 
				
			||||||
 | 
					    traits.set_visual_min_temperature(25.0);
 | 
				
			||||||
 | 
					    traits.set_visual_max_temperature(100.0);
 | 
				
			||||||
 | 
					    traits.set_visual_temperature_step(0.1);
 | 
				
			||||||
 | 
					    return traits;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 protected:
 | 
				
			||||||
 | 
					  AnovaCodec *codec_;
 | 
				
			||||||
 | 
					  void control(const climate::ClimateCall &call) override;
 | 
				
			||||||
 | 
					  uint16_t char_handle_;
 | 
				
			||||||
 | 
					  uint8_t current_request_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace anova
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										119
									
								
								esphome/components/anova/anova_base.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								esphome/components/anova/anova_base.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
				
			|||||||
 | 
					#include "anova_base.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace anova {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AnovaPacket *AnovaCodec::clean_packet_() {
 | 
				
			||||||
 | 
					  this->packet_.length = strlen((char *) this->packet_.data);
 | 
				
			||||||
 | 
					  this->packet_.data[this->packet_.length] = '\0';
 | 
				
			||||||
 | 
					  ESP_LOGV("anova", "SendPkt: %s\n", this->packet_.data);
 | 
				
			||||||
 | 
					  return &this->packet_;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AnovaPacket *AnovaCodec::get_read_device_status_request() {
 | 
				
			||||||
 | 
					  this->current_query_ = READ_DEVICE_STATUS;
 | 
				
			||||||
 | 
					  sprintf((char *) this->packet_.data, "%s", CMD_READ_DEVICE_STATUS);
 | 
				
			||||||
 | 
					  return this->clean_packet_();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AnovaPacket *AnovaCodec::get_read_target_temp_request() {
 | 
				
			||||||
 | 
					  this->current_query_ = READ_TARGET_TEMPERATURE;
 | 
				
			||||||
 | 
					  sprintf((char *) this->packet_.data, "%s", CMD_READ_TARGET_TEMP);
 | 
				
			||||||
 | 
					  return this->clean_packet_();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AnovaPacket *AnovaCodec::get_read_current_temp_request() {
 | 
				
			||||||
 | 
					  this->current_query_ = READ_CURRENT_TEMPERATURE;
 | 
				
			||||||
 | 
					  sprintf((char *) this->packet_.data, "%s", CMD_READ_CURRENT_TEMP);
 | 
				
			||||||
 | 
					  return this->clean_packet_();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AnovaPacket *AnovaCodec::get_read_unit_request() {
 | 
				
			||||||
 | 
					  this->current_query_ = READ_UNIT;
 | 
				
			||||||
 | 
					  sprintf((char *) this->packet_.data, "%s", CMD_READ_UNIT);
 | 
				
			||||||
 | 
					  return this->clean_packet_();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AnovaPacket *AnovaCodec::get_read_data_request() {
 | 
				
			||||||
 | 
					  this->current_query_ = READ_DATA;
 | 
				
			||||||
 | 
					  sprintf((char *) this->packet_.data, "%s", CMD_READ_DATA);
 | 
				
			||||||
 | 
					  return this->clean_packet_();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AnovaPacket *AnovaCodec::get_set_target_temp_request(float temperature) {
 | 
				
			||||||
 | 
					  this->current_query_ = SET_TARGET_TEMPERATURE;
 | 
				
			||||||
 | 
					  sprintf((char *) this->packet_.data, CMD_SET_TARGET_TEMP, temperature);
 | 
				
			||||||
 | 
					  return this->clean_packet_();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AnovaPacket *AnovaCodec::get_set_unit_request(char unit) {
 | 
				
			||||||
 | 
					  this->current_query_ = SET_UNIT;
 | 
				
			||||||
 | 
					  sprintf((char *) this->packet_.data, CMD_SET_TEMP_UNIT, unit);
 | 
				
			||||||
 | 
					  return this->clean_packet_();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AnovaPacket *AnovaCodec::get_start_request() {
 | 
				
			||||||
 | 
					  this->current_query_ = START;
 | 
				
			||||||
 | 
					  sprintf((char *) this->packet_.data, CMD_START);
 | 
				
			||||||
 | 
					  return this->clean_packet_();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AnovaPacket *AnovaCodec::get_stop_request() {
 | 
				
			||||||
 | 
					  this->current_query_ = STOP;
 | 
				
			||||||
 | 
					  sprintf((char *) this->packet_.data, CMD_STOP);
 | 
				
			||||||
 | 
					  return this->clean_packet_();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AnovaCodec::decode(const uint8_t *data, uint16_t length) {
 | 
				
			||||||
 | 
					  memset(this->buf_, 0, 32);
 | 
				
			||||||
 | 
					  strncpy(this->buf_, (char *) data, length);
 | 
				
			||||||
 | 
					  ESP_LOGV("anova", "Received: %s\n", this->buf_);
 | 
				
			||||||
 | 
					  this->has_target_temp_ = this->has_current_temp_ = this->has_unit_ = this->has_running_ = false;
 | 
				
			||||||
 | 
					  switch (this->current_query_) {
 | 
				
			||||||
 | 
					    case READ_DEVICE_STATUS: {
 | 
				
			||||||
 | 
					      if (!strncmp(this->buf_, "stopped", 7)) {
 | 
				
			||||||
 | 
					        this->has_running_ = true;
 | 
				
			||||||
 | 
					        this->running_ = false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (!strncmp(this->buf_, "running", 7)) {
 | 
				
			||||||
 | 
					        this->has_running_ = true;
 | 
				
			||||||
 | 
					        this->running_ = true;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case START: {
 | 
				
			||||||
 | 
					      if (!strncmp(this->buf_, "start", 5)) {
 | 
				
			||||||
 | 
					        this->has_running_ = true;
 | 
				
			||||||
 | 
					        this->running_ = true;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case STOP: {
 | 
				
			||||||
 | 
					      if (!strncmp(this->buf_, "stop", 4)) {
 | 
				
			||||||
 | 
					        this->has_running_ = true;
 | 
				
			||||||
 | 
					        this->running_ = false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case READ_TARGET_TEMPERATURE: {
 | 
				
			||||||
 | 
					      this->target_temp_ = strtof(this->buf_, nullptr);
 | 
				
			||||||
 | 
					      this->has_target_temp_ = true;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case SET_TARGET_TEMPERATURE: {
 | 
				
			||||||
 | 
					      this->target_temp_ = strtof(this->buf_, nullptr);
 | 
				
			||||||
 | 
					      this->has_target_temp_ = true;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case READ_CURRENT_TEMPERATURE: {
 | 
				
			||||||
 | 
					      this->current_temp_ = strtof(this->buf_, nullptr);
 | 
				
			||||||
 | 
					      this->has_current_temp_ = true;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace anova
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										79
									
								
								esphome/components/anova/anova_base.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								esphome/components/anova/anova_base.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "esphome/core/helpers.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace anova {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum CurrentQuery {
 | 
				
			||||||
 | 
					  NONE,
 | 
				
			||||||
 | 
					  READ_DEVICE_STATUS,
 | 
				
			||||||
 | 
					  READ_TARGET_TEMPERATURE,
 | 
				
			||||||
 | 
					  READ_CURRENT_TEMPERATURE,
 | 
				
			||||||
 | 
					  READ_DATA,
 | 
				
			||||||
 | 
					  READ_UNIT,
 | 
				
			||||||
 | 
					  SET_TARGET_TEMPERATURE,
 | 
				
			||||||
 | 
					  SET_UNIT,
 | 
				
			||||||
 | 
					  START,
 | 
				
			||||||
 | 
					  STOP,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct AnovaPacket {
 | 
				
			||||||
 | 
					  uint16_t length;
 | 
				
			||||||
 | 
					  uint8_t data[24];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CMD_READ_DEVICE_STATUS "status\r"
 | 
				
			||||||
 | 
					#define CMD_READ_TARGET_TEMP "read set temp\r"
 | 
				
			||||||
 | 
					#define CMD_READ_CURRENT_TEMP "read temp\r"
 | 
				
			||||||
 | 
					#define CMD_READ_UNIT "read unit\r"
 | 
				
			||||||
 | 
					#define CMD_READ_DATA "read data\r"
 | 
				
			||||||
 | 
					#define CMD_SET_TARGET_TEMP "set temp %.1f\r"
 | 
				
			||||||
 | 
					#define CMD_SET_TEMP_UNIT "set unit %c\r"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CMD_START "start\r"
 | 
				
			||||||
 | 
					#define CMD_STOP "stop\r"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AnovaCodec {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  AnovaPacket *get_read_device_status_request();
 | 
				
			||||||
 | 
					  AnovaPacket *get_read_target_temp_request();
 | 
				
			||||||
 | 
					  AnovaPacket *get_read_current_temp_request();
 | 
				
			||||||
 | 
					  AnovaPacket *get_read_data_request();
 | 
				
			||||||
 | 
					  AnovaPacket *get_read_unit_request();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AnovaPacket *get_set_target_temp_request(float temperature);
 | 
				
			||||||
 | 
					  AnovaPacket *get_set_unit_request(char unit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AnovaPacket *get_start_request();
 | 
				
			||||||
 | 
					  AnovaPacket *get_stop_request();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void decode(const uint8_t *data, uint16_t length);
 | 
				
			||||||
 | 
					  bool has_target_temp() { return this->has_target_temp_; }
 | 
				
			||||||
 | 
					  bool has_current_temp() { return this->has_current_temp_; }
 | 
				
			||||||
 | 
					  bool has_unit() { return this->has_unit_; }
 | 
				
			||||||
 | 
					  bool has_running() { return this->has_running_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  union {
 | 
				
			||||||
 | 
					    float target_temp_;
 | 
				
			||||||
 | 
					    float current_temp_;
 | 
				
			||||||
 | 
					    char unit_;
 | 
				
			||||||
 | 
					    bool running_;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 protected:
 | 
				
			||||||
 | 
					  AnovaPacket *clean_packet_();
 | 
				
			||||||
 | 
					  AnovaPacket packet_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool has_target_temp_;
 | 
				
			||||||
 | 
					  bool has_current_temp_;
 | 
				
			||||||
 | 
					  bool has_unit_;
 | 
				
			||||||
 | 
					  bool has_running_;
 | 
				
			||||||
 | 
					  char buf_[32];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  CurrentQuery current_query_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace anova
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										25
									
								
								esphome/components/anova/climate.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								esphome/components/anova/climate.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome.components import climate, ble_client
 | 
				
			||||||
 | 
					from esphome.const import CONF_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CODEOWNERS = ["@buxtronix"]
 | 
				
			||||||
 | 
					DEPENDENCIES = ["ble_client"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					anova_ns = cg.esphome_ns.namespace("anova")
 | 
				
			||||||
 | 
					Anova = anova_ns.class_(
 | 
				
			||||||
 | 
					    "Anova", climate.Climate, ble_client.BLEClientNode, cg.PollingComponent
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONFIG_SCHEMA = (
 | 
				
			||||||
 | 
					    climate.CLIMATE_SCHEMA.extend({cv.GenerateID(): cv.declare_id(Anova)})
 | 
				
			||||||
 | 
					    .extend(ble_client.BLE_CLIENT_SCHEMA)
 | 
				
			||||||
 | 
					    .extend(cv.polling_component_schema("60s"))
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def to_code(config):
 | 
				
			||||||
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
 | 
					    yield cg.register_component(var, config)
 | 
				
			||||||
 | 
					    yield climate.register_climate(var, config)
 | 
				
			||||||
 | 
					    yield ble_client.register_ble_node(var, config)
 | 
				
			||||||
@@ -23,7 +23,7 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    yield i2c.register_i2c_device(var, config)
 | 
					    await i2c.register_i2c_device(var, config)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,10 +4,10 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace apds9960 {
 | 
					namespace apds9960 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "apds9960";
 | 
					static const char *const TAG = "apds9960";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define APDS9960_ERROR_CHECK(func) \
 | 
					#define APDS9960_ERROR_CHECK(func) \
 | 
				
			||||||
  if (!func) { \
 | 
					  if (!(func)) { \
 | 
				
			||||||
    this->mark_failed(); \
 | 
					    this->mark_failed(); \
 | 
				
			||||||
    return; \
 | 
					    return; \
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,8 +24,8 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    hub = yield cg.get_variable(config[CONF_APDS9960_ID])
 | 
					    hub = await cg.get_variable(config[CONF_APDS9960_ID])
 | 
				
			||||||
    var = yield binary_sensor.new_binary_sensor(config)
 | 
					    var = await binary_sensor.new_binary_sensor(config)
 | 
				
			||||||
    func = getattr(hub, DIRECTIONS[config[CONF_DIRECTION]])
 | 
					    func = getattr(hub, DIRECTIONS[config[CONF_DIRECTION]])
 | 
				
			||||||
    cg.add(func(var))
 | 
					    cg.add(func(var))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,13 @@
 | 
				
			|||||||
import esphome.codegen as cg
 | 
					import esphome.codegen as cg
 | 
				
			||||||
import esphome.config_validation as cv
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
from esphome.components import sensor
 | 
					from esphome.components import sensor
 | 
				
			||||||
from esphome.const import CONF_TYPE, DEVICE_CLASS_EMPTY, UNIT_PERCENT, ICON_LIGHTBULB
 | 
					from esphome.const import (
 | 
				
			||||||
 | 
					    CONF_TYPE,
 | 
				
			||||||
 | 
					    DEVICE_CLASS_EMPTY,
 | 
				
			||||||
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
 | 
					    UNIT_PERCENT,
 | 
				
			||||||
 | 
					    ICON_LIGHTBULB,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
from . import APDS9960, CONF_APDS9960_ID
 | 
					from . import APDS9960, CONF_APDS9960_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEPENDENCIES = ["apds9960"]
 | 
					DEPENDENCIES = ["apds9960"]
 | 
				
			||||||
@@ -15,7 +21,7 @@ TYPES = {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONFIG_SCHEMA = sensor.sensor_schema(
 | 
					CONFIG_SCHEMA = sensor.sensor_schema(
 | 
				
			||||||
    UNIT_PERCENT, ICON_LIGHTBULB, 1, DEVICE_CLASS_EMPTY
 | 
					    UNIT_PERCENT, ICON_LIGHTBULB, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_MEASUREMENT
 | 
				
			||||||
).extend(
 | 
					).extend(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        cv.Required(CONF_TYPE): cv.one_of(*TYPES, upper=True),
 | 
					        cv.Required(CONF_TYPE): cv.one_of(*TYPES, upper=True),
 | 
				
			||||||
@@ -24,8 +30,8 @@ CONFIG_SCHEMA = sensor.sensor_schema(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    hub = yield cg.get_variable(config[CONF_APDS9960_ID])
 | 
					    hub = await cg.get_variable(config[CONF_APDS9960_ID])
 | 
				
			||||||
    var = yield sensor.new_sensor(config)
 | 
					    var = await sensor.new_sensor(config)
 | 
				
			||||||
    func = getattr(hub, TYPES[config[CONF_TYPE]])
 | 
					    func = getattr(hub, TYPES[config[CONF_TYPE]])
 | 
				
			||||||
    cg.add(func(var))
 | 
					    cg.add(func(var))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -68,9 +68,9 @@ CONFIG_SCHEMA = cv.Schema(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@coroutine_with_priority(40.0)
 | 
					@coroutine_with_priority(40.0)
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cg.add(var.set_port(config[CONF_PORT]))
 | 
					    cg.add(var.set_port(config[CONF_PORT]))
 | 
				
			||||||
    cg.add(var.set_password(config[CONF_PASSWORD]))
 | 
					    cg.add(var.set_password(config[CONF_PASSWORD]))
 | 
				
			||||||
@@ -90,7 +90,7 @@ def to_code(config):
 | 
				
			|||||||
            conf[CONF_TRIGGER_ID], templ, conf[CONF_SERVICE], service_arg_names
 | 
					            conf[CONF_TRIGGER_ID], templ, conf[CONF_SERVICE], service_arg_names
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        cg.add(var.register_user_service(trigger))
 | 
					        cg.add(var.register_user_service(trigger))
 | 
				
			||||||
        yield automation.build_automation(trigger, func_args, conf)
 | 
					        await automation.build_automation(trigger, func_args, conf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cg.add_define("USE_API")
 | 
					    cg.add_define("USE_API")
 | 
				
			||||||
    cg.add_global(api_ns.using)
 | 
					    cg.add_global(api_ns.using)
 | 
				
			||||||
@@ -116,21 +116,21 @@ HOMEASSISTANT_SERVICE_ACTION_SCHEMA = cv.Schema(
 | 
				
			|||||||
    HomeAssistantServiceCallAction,
 | 
					    HomeAssistantServiceCallAction,
 | 
				
			||||||
    HOMEASSISTANT_SERVICE_ACTION_SCHEMA,
 | 
					    HOMEASSISTANT_SERVICE_ACTION_SCHEMA,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
def homeassistant_service_to_code(config, action_id, template_arg, args):
 | 
					async def homeassistant_service_to_code(config, action_id, template_arg, args):
 | 
				
			||||||
    serv = yield cg.get_variable(config[CONF_ID])
 | 
					    serv = await cg.get_variable(config[CONF_ID])
 | 
				
			||||||
    var = cg.new_Pvariable(action_id, template_arg, serv, False)
 | 
					    var = cg.new_Pvariable(action_id, template_arg, serv, False)
 | 
				
			||||||
    templ = yield cg.templatable(config[CONF_SERVICE], args, None)
 | 
					    templ = await cg.templatable(config[CONF_SERVICE], args, None)
 | 
				
			||||||
    cg.add(var.set_service(templ))
 | 
					    cg.add(var.set_service(templ))
 | 
				
			||||||
    for key, value in config[CONF_DATA].items():
 | 
					    for key, value in config[CONF_DATA].items():
 | 
				
			||||||
        templ = yield cg.templatable(value, args, None)
 | 
					        templ = await cg.templatable(value, args, None)
 | 
				
			||||||
        cg.add(var.add_data(key, templ))
 | 
					        cg.add(var.add_data(key, templ))
 | 
				
			||||||
    for key, value in config[CONF_DATA_TEMPLATE].items():
 | 
					    for key, value in config[CONF_DATA_TEMPLATE].items():
 | 
				
			||||||
        templ = yield cg.templatable(value, args, None)
 | 
					        templ = await cg.templatable(value, args, None)
 | 
				
			||||||
        cg.add(var.add_data_template(key, templ))
 | 
					        cg.add(var.add_data_template(key, templ))
 | 
				
			||||||
    for key, value in config[CONF_VARIABLES].items():
 | 
					    for key, value in config[CONF_VARIABLES].items():
 | 
				
			||||||
        templ = yield cg.templatable(value, args, None)
 | 
					        templ = await cg.templatable(value, args, None)
 | 
				
			||||||
        cg.add(var.add_variable(key, templ))
 | 
					        cg.add(var.add_variable(key, templ))
 | 
				
			||||||
    yield var
 | 
					    return var
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def validate_homeassistant_event(value):
 | 
					def validate_homeassistant_event(value):
 | 
				
			||||||
@@ -159,21 +159,21 @@ HOMEASSISTANT_EVENT_ACTION_SCHEMA = cv.Schema(
 | 
				
			|||||||
    HomeAssistantServiceCallAction,
 | 
					    HomeAssistantServiceCallAction,
 | 
				
			||||||
    HOMEASSISTANT_EVENT_ACTION_SCHEMA,
 | 
					    HOMEASSISTANT_EVENT_ACTION_SCHEMA,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
def homeassistant_event_to_code(config, action_id, template_arg, args):
 | 
					async def homeassistant_event_to_code(config, action_id, template_arg, args):
 | 
				
			||||||
    serv = yield cg.get_variable(config[CONF_ID])
 | 
					    serv = await cg.get_variable(config[CONF_ID])
 | 
				
			||||||
    var = cg.new_Pvariable(action_id, template_arg, serv, True)
 | 
					    var = cg.new_Pvariable(action_id, template_arg, serv, True)
 | 
				
			||||||
    templ = yield cg.templatable(config[CONF_EVENT], args, None)
 | 
					    templ = await cg.templatable(config[CONF_EVENT], args, None)
 | 
				
			||||||
    cg.add(var.set_service(templ))
 | 
					    cg.add(var.set_service(templ))
 | 
				
			||||||
    for key, value in config[CONF_DATA].items():
 | 
					    for key, value in config[CONF_DATA].items():
 | 
				
			||||||
        templ = yield cg.templatable(value, args, None)
 | 
					        templ = await cg.templatable(value, args, None)
 | 
				
			||||||
        cg.add(var.add_data(key, templ))
 | 
					        cg.add(var.add_data(key, templ))
 | 
				
			||||||
    for key, value in config[CONF_DATA_TEMPLATE].items():
 | 
					    for key, value in config[CONF_DATA_TEMPLATE].items():
 | 
				
			||||||
        templ = yield cg.templatable(value, args, None)
 | 
					        templ = await cg.templatable(value, args, None)
 | 
				
			||||||
        cg.add(var.add_data_template(key, templ))
 | 
					        cg.add(var.add_data_template(key, templ))
 | 
				
			||||||
    for key, value in config[CONF_VARIABLES].items():
 | 
					    for key, value in config[CONF_VARIABLES].items():
 | 
				
			||||||
        templ = yield cg.templatable(value, args, None)
 | 
					        templ = await cg.templatable(value, args, None)
 | 
				
			||||||
        cg.add(var.add_variable(key, templ))
 | 
					        cg.add(var.add_variable(key, templ))
 | 
				
			||||||
    yield var
 | 
					    return var
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA = cv.maybe_simple_value(
 | 
					HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA = cv.maybe_simple_value(
 | 
				
			||||||
@@ -190,15 +190,15 @@ HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA = cv.maybe_simple_value(
 | 
				
			|||||||
    HomeAssistantServiceCallAction,
 | 
					    HomeAssistantServiceCallAction,
 | 
				
			||||||
    HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA,
 | 
					    HOMEASSISTANT_TAG_SCANNED_ACTION_SCHEMA,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
def homeassistant_tag_scanned_to_code(config, action_id, template_arg, args):
 | 
					async def homeassistant_tag_scanned_to_code(config, action_id, template_arg, args):
 | 
				
			||||||
    serv = yield cg.get_variable(config[CONF_ID])
 | 
					    serv = await cg.get_variable(config[CONF_ID])
 | 
				
			||||||
    var = cg.new_Pvariable(action_id, template_arg, serv, True)
 | 
					    var = cg.new_Pvariable(action_id, template_arg, serv, True)
 | 
				
			||||||
    cg.add(var.set_service("esphome.tag_scanned"))
 | 
					    cg.add(var.set_service("esphome.tag_scanned"))
 | 
				
			||||||
    templ = yield cg.templatable(config[CONF_TAG], args, cg.std_string)
 | 
					    templ = await cg.templatable(config[CONF_TAG], args, cg.std_string)
 | 
				
			||||||
    cg.add(var.add_data("tag_id", templ))
 | 
					    cg.add(var.add_data("tag_id", templ))
 | 
				
			||||||
    yield var
 | 
					    return var
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@automation.register_condition("api.connected", APIConnectedCondition, {})
 | 
					@automation.register_condition("api.connected", APIConnectedCondition, {})
 | 
				
			||||||
def api_connected_to_code(config, condition_id, template_arg, args):
 | 
					async def api_connected_to_code(config, condition_id, template_arg, args):
 | 
				
			||||||
    yield cg.new_Pvariable(condition_id, template_arg)
 | 
					    return cg.new_Pvariable(condition_id, template_arg)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,6 +38,7 @@ service APIConnection {
 | 
				
			|||||||
  rpc switch_command (SwitchCommandRequest) returns (void) {}
 | 
					  rpc switch_command (SwitchCommandRequest) returns (void) {}
 | 
				
			||||||
  rpc camera_image (CameraImageRequest) returns (void) {}
 | 
					  rpc camera_image (CameraImageRequest) returns (void) {}
 | 
				
			||||||
  rpc climate_command (ClimateCommandRequest) returns (void) {}
 | 
					  rpc climate_command (ClimateCommandRequest) returns (void) {}
 | 
				
			||||||
 | 
					  rpc number_command (NumberCommandRequest) returns (void) {}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -176,6 +177,10 @@ message DeviceInfoResponse {
 | 
				
			|||||||
  string model = 6;
 | 
					  string model = 6;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool has_deep_sleep = 7;
 | 
					  bool has_deep_sleep = 7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // The esphome project details if set
 | 
				
			||||||
 | 
					  string project_name = 8;
 | 
				
			||||||
 | 
					  string project_version = 9;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
message ListEntitiesRequest {
 | 
					message ListEntitiesRequest {
 | 
				
			||||||
@@ -374,6 +379,7 @@ message LightStateResponse {
 | 
				
			|||||||
  fixed32 key = 1;
 | 
					  fixed32 key = 1;
 | 
				
			||||||
  bool state = 2;
 | 
					  bool state = 2;
 | 
				
			||||||
  float brightness = 3;
 | 
					  float brightness = 3;
 | 
				
			||||||
 | 
					  float color_brightness = 10;
 | 
				
			||||||
  float red = 4;
 | 
					  float red = 4;
 | 
				
			||||||
  float green = 5;
 | 
					  float green = 5;
 | 
				
			||||||
  float blue = 6;
 | 
					  float blue = 6;
 | 
				
			||||||
@@ -392,6 +398,8 @@ message LightCommandRequest {
 | 
				
			|||||||
  bool state = 3;
 | 
					  bool state = 3;
 | 
				
			||||||
  bool has_brightness = 4;
 | 
					  bool has_brightness = 4;
 | 
				
			||||||
  float brightness = 5;
 | 
					  float brightness = 5;
 | 
				
			||||||
 | 
					  bool has_color_brightness = 20;
 | 
				
			||||||
 | 
					  float color_brightness = 21;
 | 
				
			||||||
  bool has_rgb = 6;
 | 
					  bool has_rgb = 6;
 | 
				
			||||||
  float red = 7;
 | 
					  float red = 7;
 | 
				
			||||||
  float green = 8;
 | 
					  float green = 8;
 | 
				
			||||||
@@ -409,6 +417,11 @@ message LightCommandRequest {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ==================== SENSOR ====================
 | 
					// ==================== SENSOR ====================
 | 
				
			||||||
 | 
					enum SensorStateClass {
 | 
				
			||||||
 | 
					  STATE_CLASS_NONE = 0;
 | 
				
			||||||
 | 
					  STATE_CLASS_MEASUREMENT = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
message ListEntitiesSensorResponse {
 | 
					message ListEntitiesSensorResponse {
 | 
				
			||||||
  option (id) = 16;
 | 
					  option (id) = 16;
 | 
				
			||||||
  option (source) = SOURCE_SERVER;
 | 
					  option (source) = SOURCE_SERVER;
 | 
				
			||||||
@@ -424,6 +437,7 @@ message ListEntitiesSensorResponse {
 | 
				
			|||||||
  int32 accuracy_decimals = 7;
 | 
					  int32 accuracy_decimals = 7;
 | 
				
			||||||
  bool force_update = 8;
 | 
					  bool force_update = 8;
 | 
				
			||||||
  string device_class = 9;
 | 
					  string device_class = 9;
 | 
				
			||||||
 | 
					  SensorStateClass state_class = 10;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
message SensorStateResponse {
 | 
					message SensorStateResponse {
 | 
				
			||||||
  option (id) = 25;
 | 
					  option (id) = 25;
 | 
				
			||||||
@@ -561,6 +575,7 @@ message SubscribeHomeAssistantStateResponse {
 | 
				
			|||||||
  option (id) = 39;
 | 
					  option (id) = 39;
 | 
				
			||||||
  option (source) = SOURCE_SERVER;
 | 
					  option (source) = SOURCE_SERVER;
 | 
				
			||||||
  string entity_id = 1;
 | 
					  string entity_id = 1;
 | 
				
			||||||
 | 
					  string attribute = 2;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
message HomeAssistantStateResponse {
 | 
					message HomeAssistantStateResponse {
 | 
				
			||||||
@@ -570,6 +585,7 @@ message HomeAssistantStateResponse {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  string entity_id = 1;
 | 
					  string entity_id = 1;
 | 
				
			||||||
  string state = 2;
 | 
					  string state = 2;
 | 
				
			||||||
 | 
					  string attribute = 3;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ==================== IMPORT TIME ====================
 | 
					// ==================== IMPORT TIME ====================
 | 
				
			||||||
@@ -664,11 +680,12 @@ message CameraImageRequest {
 | 
				
			|||||||
// ==================== CLIMATE ====================
 | 
					// ==================== CLIMATE ====================
 | 
				
			||||||
enum ClimateMode {
 | 
					enum ClimateMode {
 | 
				
			||||||
  CLIMATE_MODE_OFF = 0;
 | 
					  CLIMATE_MODE_OFF = 0;
 | 
				
			||||||
  CLIMATE_MODE_AUTO = 1;
 | 
					  CLIMATE_MODE_HEAT_COOL = 1;
 | 
				
			||||||
  CLIMATE_MODE_COOL = 2;
 | 
					  CLIMATE_MODE_COOL = 2;
 | 
				
			||||||
  CLIMATE_MODE_HEAT = 3;
 | 
					  CLIMATE_MODE_HEAT = 3;
 | 
				
			||||||
  CLIMATE_MODE_FAN_ONLY = 4;
 | 
					  CLIMATE_MODE_FAN_ONLY = 4;
 | 
				
			||||||
  CLIMATE_MODE_DRY = 5;
 | 
					  CLIMATE_MODE_DRY = 5;
 | 
				
			||||||
 | 
					  CLIMATE_MODE_AUTO = 6;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
enum ClimateFanMode {
 | 
					enum ClimateFanMode {
 | 
				
			||||||
  CLIMATE_FAN_ON = 0;
 | 
					  CLIMATE_FAN_ON = 0;
 | 
				
			||||||
@@ -696,6 +713,16 @@ enum ClimateAction {
 | 
				
			|||||||
  CLIMATE_ACTION_DRYING = 5;
 | 
					  CLIMATE_ACTION_DRYING = 5;
 | 
				
			||||||
  CLIMATE_ACTION_FAN = 6;
 | 
					  CLIMATE_ACTION_FAN = 6;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					enum ClimatePreset {
 | 
				
			||||||
 | 
					  CLIMATE_PRESET_NONE = 0;
 | 
				
			||||||
 | 
					  CLIMATE_PRESET_HOME = 1;
 | 
				
			||||||
 | 
					  CLIMATE_PRESET_AWAY = 2;
 | 
				
			||||||
 | 
					  CLIMATE_PRESET_BOOST = 3;
 | 
				
			||||||
 | 
					  CLIMATE_PRESET_COMFORT = 4;
 | 
				
			||||||
 | 
					  CLIMATE_PRESET_ECO = 5;
 | 
				
			||||||
 | 
					  CLIMATE_PRESET_SLEEP = 6;
 | 
				
			||||||
 | 
					  CLIMATE_PRESET_ACTIVITY = 7;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
message ListEntitiesClimateResponse {
 | 
					message ListEntitiesClimateResponse {
 | 
				
			||||||
  option (id) = 46;
 | 
					  option (id) = 46;
 | 
				
			||||||
  option (source) = SOURCE_SERVER;
 | 
					  option (source) = SOURCE_SERVER;
 | 
				
			||||||
@@ -712,10 +739,15 @@ message ListEntitiesClimateResponse {
 | 
				
			|||||||
  float visual_min_temperature = 8;
 | 
					  float visual_min_temperature = 8;
 | 
				
			||||||
  float visual_max_temperature = 9;
 | 
					  float visual_max_temperature = 9;
 | 
				
			||||||
  float visual_temperature_step = 10;
 | 
					  float visual_temperature_step = 10;
 | 
				
			||||||
  bool supports_away = 11;
 | 
					  // for older peer versions - in new system this
 | 
				
			||||||
 | 
					  // is if CLIMATE_PRESET_AWAY exists is supported_presets
 | 
				
			||||||
 | 
					  bool legacy_supports_away = 11;
 | 
				
			||||||
  bool supports_action = 12;
 | 
					  bool supports_action = 12;
 | 
				
			||||||
  repeated ClimateFanMode supported_fan_modes = 13;
 | 
					  repeated ClimateFanMode supported_fan_modes = 13;
 | 
				
			||||||
  repeated ClimateSwingMode supported_swing_modes = 14;
 | 
					  repeated ClimateSwingMode supported_swing_modes = 14;
 | 
				
			||||||
 | 
					  repeated string supported_custom_fan_modes = 15;
 | 
				
			||||||
 | 
					  repeated ClimatePreset supported_presets = 16;
 | 
				
			||||||
 | 
					  repeated string supported_custom_presets = 17;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
message ClimateStateResponse {
 | 
					message ClimateStateResponse {
 | 
				
			||||||
  option (id) = 47;
 | 
					  option (id) = 47;
 | 
				
			||||||
@@ -729,10 +761,14 @@ message ClimateStateResponse {
 | 
				
			|||||||
  float target_temperature = 4;
 | 
					  float target_temperature = 4;
 | 
				
			||||||
  float target_temperature_low = 5;
 | 
					  float target_temperature_low = 5;
 | 
				
			||||||
  float target_temperature_high = 6;
 | 
					  float target_temperature_high = 6;
 | 
				
			||||||
  bool away = 7;
 | 
					  // For older peers, equal to preset == CLIMATE_PRESET_AWAY
 | 
				
			||||||
 | 
					  bool legacy_away = 7;
 | 
				
			||||||
  ClimateAction action = 8;
 | 
					  ClimateAction action = 8;
 | 
				
			||||||
  ClimateFanMode fan_mode = 9;
 | 
					  ClimateFanMode fan_mode = 9;
 | 
				
			||||||
  ClimateSwingMode swing_mode = 10;
 | 
					  ClimateSwingMode swing_mode = 10;
 | 
				
			||||||
 | 
					  string custom_fan_mode = 11;
 | 
				
			||||||
 | 
					  ClimatePreset preset = 12;
 | 
				
			||||||
 | 
					  string custom_preset = 13;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
message ClimateCommandRequest {
 | 
					message ClimateCommandRequest {
 | 
				
			||||||
  option (id) = 48;
 | 
					  option (id) = 48;
 | 
				
			||||||
@@ -749,10 +785,55 @@ message ClimateCommandRequest {
 | 
				
			|||||||
  float target_temperature_low = 7;
 | 
					  float target_temperature_low = 7;
 | 
				
			||||||
  bool has_target_temperature_high = 8;
 | 
					  bool has_target_temperature_high = 8;
 | 
				
			||||||
  float target_temperature_high = 9;
 | 
					  float target_temperature_high = 9;
 | 
				
			||||||
  bool has_away = 10;
 | 
					  // legacy, for older peers, newer ones should use CLIMATE_PRESET_AWAY in preset
 | 
				
			||||||
  bool away = 11;
 | 
					  bool has_legacy_away = 10;
 | 
				
			||||||
 | 
					  bool legacy_away = 11;
 | 
				
			||||||
  bool has_fan_mode = 12;
 | 
					  bool has_fan_mode = 12;
 | 
				
			||||||
  ClimateFanMode fan_mode = 13;
 | 
					  ClimateFanMode fan_mode = 13;
 | 
				
			||||||
  bool has_swing_mode = 14;
 | 
					  bool has_swing_mode = 14;
 | 
				
			||||||
  ClimateSwingMode swing_mode = 15;
 | 
					  ClimateSwingMode swing_mode = 15;
 | 
				
			||||||
 | 
					  bool has_custom_fan_mode = 16;
 | 
				
			||||||
 | 
					  string custom_fan_mode = 17;
 | 
				
			||||||
 | 
					  bool has_preset = 18;
 | 
				
			||||||
 | 
					  ClimatePreset preset = 19;
 | 
				
			||||||
 | 
					  bool has_custom_preset = 20;
 | 
				
			||||||
 | 
					  string custom_preset = 21;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ==================== NUMBER ====================
 | 
				
			||||||
 | 
					message ListEntitiesNumberResponse {
 | 
				
			||||||
 | 
					  option (id) = 49;
 | 
				
			||||||
 | 
					  option (source) = SOURCE_SERVER;
 | 
				
			||||||
 | 
					  option (ifdef) = "USE_NUMBER";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  string object_id = 1;
 | 
				
			||||||
 | 
					  fixed32 key = 2;
 | 
				
			||||||
 | 
					  string name = 3;
 | 
				
			||||||
 | 
					  string unique_id = 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  string icon = 5;
 | 
				
			||||||
 | 
					  float min_value = 6;
 | 
				
			||||||
 | 
					  float max_value = 7;
 | 
				
			||||||
 | 
					  float step = 8;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					message NumberStateResponse {
 | 
				
			||||||
 | 
					  option (id) = 50;
 | 
				
			||||||
 | 
					  option (source) = SOURCE_SERVER;
 | 
				
			||||||
 | 
					  option (ifdef) = "USE_NUMBER";
 | 
				
			||||||
 | 
					  option (no_delay) = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fixed32 key = 1;
 | 
				
			||||||
 | 
					  float state = 2;
 | 
				
			||||||
 | 
					  // If the number does not have a valid state yet.
 | 
				
			||||||
 | 
					  // Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
 | 
				
			||||||
 | 
					  bool missing_state = 3;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					message NumberCommandRequest {
 | 
				
			||||||
 | 
					  option (id) = 51;
 | 
				
			||||||
 | 
					  option (source) = SOURCE_CLIENT;
 | 
				
			||||||
 | 
					  option (ifdef) = "USE_NUMBER";
 | 
				
			||||||
 | 
					  option (no_delay) = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  fixed32 key = 1;
 | 
				
			||||||
 | 
					  float state = 2;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace api {
 | 
					namespace api {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "api.connection";
 | 
					static const char *const TAG = "api.connection";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
APIConnection::APIConnection(AsyncClient *client, APIServer *parent)
 | 
					APIConnection::APIConnection(AsyncClient *client, APIServer *parent)
 | 
				
			||||||
    : client_(client), parent_(parent), initial_state_iterator_(parent, this), list_entities_iterator_(parent, this) {
 | 
					    : client_(client), parent_(parent), initial_state_iterator_(parent, this), list_entities_iterator_(parent, this) {
 | 
				
			||||||
@@ -308,6 +308,7 @@ bool APIConnection::send_light_state(light::LightState *light) {
 | 
				
			|||||||
  if (traits.get_supports_brightness())
 | 
					  if (traits.get_supports_brightness())
 | 
				
			||||||
    resp.brightness = values.get_brightness();
 | 
					    resp.brightness = values.get_brightness();
 | 
				
			||||||
  if (traits.get_supports_rgb()) {
 | 
					  if (traits.get_supports_rgb()) {
 | 
				
			||||||
 | 
					    resp.color_brightness = values.get_color_brightness();
 | 
				
			||||||
    resp.red = values.get_red();
 | 
					    resp.red = values.get_red();
 | 
				
			||||||
    resp.green = values.get_green();
 | 
					    resp.green = values.get_green();
 | 
				
			||||||
    resp.blue = values.get_blue();
 | 
					    resp.blue = values.get_blue();
 | 
				
			||||||
@@ -352,6 +353,8 @@ void APIConnection::light_command(const LightCommandRequest &msg) {
 | 
				
			|||||||
    call.set_state(msg.state);
 | 
					    call.set_state(msg.state);
 | 
				
			||||||
  if (msg.has_brightness)
 | 
					  if (msg.has_brightness)
 | 
				
			||||||
    call.set_brightness(msg.brightness);
 | 
					    call.set_brightness(msg.brightness);
 | 
				
			||||||
 | 
					  if (msg.has_color_brightness)
 | 
				
			||||||
 | 
					    call.set_color_brightness(msg.color_brightness);
 | 
				
			||||||
  if (msg.has_rgb) {
 | 
					  if (msg.has_rgb) {
 | 
				
			||||||
    call.set_red(msg.red);
 | 
					    call.set_red(msg.red);
 | 
				
			||||||
    call.set_green(msg.green);
 | 
					    call.set_green(msg.green);
 | 
				
			||||||
@@ -395,6 +398,8 @@ bool APIConnection::send_sensor_info(sensor::Sensor *sensor) {
 | 
				
			|||||||
  msg.accuracy_decimals = sensor->get_accuracy_decimals();
 | 
					  msg.accuracy_decimals = sensor->get_accuracy_decimals();
 | 
				
			||||||
  msg.force_update = sensor->get_force_update();
 | 
					  msg.force_update = sensor->get_force_update();
 | 
				
			||||||
  msg.device_class = sensor->get_device_class();
 | 
					  msg.device_class = sensor->get_device_class();
 | 
				
			||||||
 | 
					  msg.state_class = static_cast<enums::SensorStateClass>(sensor->state_class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return this->send_list_entities_sensor_response(msg);
 | 
					  return this->send_list_entities_sensor_response(msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -473,10 +478,16 @@ bool APIConnection::send_climate_state(climate::Climate *climate) {
 | 
				
			|||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    resp.target_temperature = climate->target_temperature;
 | 
					    resp.target_temperature = climate->target_temperature;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (traits.get_supports_away())
 | 
					  if (traits.get_supports_fan_modes() && climate->fan_mode.has_value())
 | 
				
			||||||
    resp.away = climate->away;
 | 
					    resp.fan_mode = static_cast<enums::ClimateFanMode>(climate->fan_mode.value());
 | 
				
			||||||
  if (traits.get_supports_fan_modes())
 | 
					  if (!traits.get_supported_custom_fan_modes().empty() && climate->custom_fan_mode.has_value())
 | 
				
			||||||
    resp.fan_mode = static_cast<enums::ClimateFanMode>(climate->fan_mode);
 | 
					    resp.custom_fan_mode = climate->custom_fan_mode.value();
 | 
				
			||||||
 | 
					  if (traits.get_supports_presets() && climate->preset.has_value()) {
 | 
				
			||||||
 | 
					    resp.preset = static_cast<enums::ClimatePreset>(climate->preset.value());
 | 
				
			||||||
 | 
					    resp.legacy_away = resp.preset == enums::CLIMATE_PRESET_AWAY;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (!traits.get_supported_custom_presets().empty() && climate->custom_preset.has_value())
 | 
				
			||||||
 | 
					    resp.custom_preset = climate->custom_preset.value();
 | 
				
			||||||
  if (traits.get_supports_swing_modes())
 | 
					  if (traits.get_supports_swing_modes())
 | 
				
			||||||
    resp.swing_mode = static_cast<enums::ClimateSwingMode>(climate->swing_mode);
 | 
					    resp.swing_mode = static_cast<enums::ClimateSwingMode>(climate->swing_mode);
 | 
				
			||||||
  return this->send_climate_state_response(resp);
 | 
					  return this->send_climate_state_response(resp);
 | 
				
			||||||
@@ -490,27 +501,26 @@ bool APIConnection::send_climate_info(climate::Climate *climate) {
 | 
				
			|||||||
  msg.unique_id = get_default_unique_id("climate", climate);
 | 
					  msg.unique_id = get_default_unique_id("climate", climate);
 | 
				
			||||||
  msg.supports_current_temperature = traits.get_supports_current_temperature();
 | 
					  msg.supports_current_temperature = traits.get_supports_current_temperature();
 | 
				
			||||||
  msg.supports_two_point_target_temperature = traits.get_supports_two_point_target_temperature();
 | 
					  msg.supports_two_point_target_temperature = traits.get_supports_two_point_target_temperature();
 | 
				
			||||||
  for (auto mode : {climate::CLIMATE_MODE_AUTO, climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_COOL,
 | 
					
 | 
				
			||||||
                    climate::CLIMATE_MODE_HEAT, climate::CLIMATE_MODE_DRY, climate::CLIMATE_MODE_FAN_ONLY}) {
 | 
					  for (auto mode : traits.get_supported_modes())
 | 
				
			||||||
    if (traits.supports_mode(mode))
 | 
					    msg.supported_modes.push_back(static_cast<enums::ClimateMode>(mode));
 | 
				
			||||||
      msg.supported_modes.push_back(static_cast<enums::ClimateMode>(mode));
 | 
					
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  msg.visual_min_temperature = traits.get_visual_min_temperature();
 | 
					  msg.visual_min_temperature = traits.get_visual_min_temperature();
 | 
				
			||||||
  msg.visual_max_temperature = traits.get_visual_max_temperature();
 | 
					  msg.visual_max_temperature = traits.get_visual_max_temperature();
 | 
				
			||||||
  msg.visual_temperature_step = traits.get_visual_temperature_step();
 | 
					  msg.visual_temperature_step = traits.get_visual_temperature_step();
 | 
				
			||||||
  msg.supports_away = traits.get_supports_away();
 | 
					  msg.legacy_supports_away = traits.supports_preset(climate::CLIMATE_PRESET_AWAY);
 | 
				
			||||||
  msg.supports_action = traits.get_supports_action();
 | 
					  msg.supports_action = traits.get_supports_action();
 | 
				
			||||||
  for (auto fan_mode : {climate::CLIMATE_FAN_ON, climate::CLIMATE_FAN_OFF, climate::CLIMATE_FAN_AUTO,
 | 
					
 | 
				
			||||||
                        climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, climate::CLIMATE_FAN_HIGH,
 | 
					  for (auto fan_mode : traits.get_supported_fan_modes())
 | 
				
			||||||
                        climate::CLIMATE_FAN_MIDDLE, climate::CLIMATE_FAN_FOCUS, climate::CLIMATE_FAN_DIFFUSE}) {
 | 
					    msg.supported_fan_modes.push_back(static_cast<enums::ClimateFanMode>(fan_mode));
 | 
				
			||||||
    if (traits.supports_fan_mode(fan_mode))
 | 
					  for (auto const &custom_fan_mode : traits.get_supported_custom_fan_modes())
 | 
				
			||||||
      msg.supported_fan_modes.push_back(static_cast<enums::ClimateFanMode>(fan_mode));
 | 
					    msg.supported_custom_fan_modes.push_back(custom_fan_mode);
 | 
				
			||||||
  }
 | 
					  for (auto preset : traits.get_supported_presets())
 | 
				
			||||||
  for (auto swing_mode : {climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_BOTH, climate::CLIMATE_SWING_VERTICAL,
 | 
					    msg.supported_presets.push_back(static_cast<enums::ClimatePreset>(preset));
 | 
				
			||||||
                          climate::CLIMATE_SWING_HORIZONTAL}) {
 | 
					  for (auto const &custom_preset : traits.get_supported_custom_presets())
 | 
				
			||||||
    if (traits.supports_swing_mode(swing_mode))
 | 
					    msg.supported_custom_presets.push_back(custom_preset);
 | 
				
			||||||
      msg.supported_swing_modes.push_back(static_cast<enums::ClimateSwingMode>(swing_mode));
 | 
					  for (auto swing_mode : traits.get_supported_swing_modes())
 | 
				
			||||||
  }
 | 
					    msg.supported_swing_modes.push_back(static_cast<enums::ClimateSwingMode>(swing_mode));
 | 
				
			||||||
  return this->send_list_entities_climate_response(msg);
 | 
					  return this->send_list_entities_climate_response(msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void APIConnection::climate_command(const ClimateCommandRequest &msg) {
 | 
					void APIConnection::climate_command(const ClimateCommandRequest &msg) {
 | 
				
			||||||
@@ -527,16 +537,58 @@ void APIConnection::climate_command(const ClimateCommandRequest &msg) {
 | 
				
			|||||||
    call.set_target_temperature_low(msg.target_temperature_low);
 | 
					    call.set_target_temperature_low(msg.target_temperature_low);
 | 
				
			||||||
  if (msg.has_target_temperature_high)
 | 
					  if (msg.has_target_temperature_high)
 | 
				
			||||||
    call.set_target_temperature_high(msg.target_temperature_high);
 | 
					    call.set_target_temperature_high(msg.target_temperature_high);
 | 
				
			||||||
  if (msg.has_away)
 | 
					  if (msg.has_legacy_away)
 | 
				
			||||||
    call.set_away(msg.away);
 | 
					    call.set_preset(msg.legacy_away ? climate::CLIMATE_PRESET_AWAY : climate::CLIMATE_PRESET_HOME);
 | 
				
			||||||
  if (msg.has_fan_mode)
 | 
					  if (msg.has_fan_mode)
 | 
				
			||||||
    call.set_fan_mode(static_cast<climate::ClimateFanMode>(msg.fan_mode));
 | 
					    call.set_fan_mode(static_cast<climate::ClimateFanMode>(msg.fan_mode));
 | 
				
			||||||
 | 
					  if (msg.has_custom_fan_mode)
 | 
				
			||||||
 | 
					    call.set_fan_mode(msg.custom_fan_mode);
 | 
				
			||||||
 | 
					  if (msg.has_preset)
 | 
				
			||||||
 | 
					    call.set_preset(static_cast<climate::ClimatePreset>(msg.preset));
 | 
				
			||||||
 | 
					  if (msg.has_custom_preset)
 | 
				
			||||||
 | 
					    call.set_preset(msg.custom_preset);
 | 
				
			||||||
  if (msg.has_swing_mode)
 | 
					  if (msg.has_swing_mode)
 | 
				
			||||||
    call.set_swing_mode(static_cast<climate::ClimateSwingMode>(msg.swing_mode));
 | 
					    call.set_swing_mode(static_cast<climate::ClimateSwingMode>(msg.swing_mode));
 | 
				
			||||||
  call.perform();
 | 
					  call.perform();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					bool APIConnection::send_number_state(number::Number *number, float state) {
 | 
				
			||||||
 | 
					  if (!this->state_subscription_)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  NumberStateResponse resp{};
 | 
				
			||||||
 | 
					  resp.key = number->get_object_id_hash();
 | 
				
			||||||
 | 
					  resp.state = state;
 | 
				
			||||||
 | 
					  resp.missing_state = !number->has_state();
 | 
				
			||||||
 | 
					  return this->send_number_state_response(resp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bool APIConnection::send_number_info(number::Number *number) {
 | 
				
			||||||
 | 
					  ListEntitiesNumberResponse msg;
 | 
				
			||||||
 | 
					  msg.key = number->get_object_id_hash();
 | 
				
			||||||
 | 
					  msg.object_id = number->get_object_id();
 | 
				
			||||||
 | 
					  msg.name = number->get_name();
 | 
				
			||||||
 | 
					  msg.unique_id = get_default_unique_id("number", number);
 | 
				
			||||||
 | 
					  msg.icon = number->traits.get_icon();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  msg.min_value = number->traits.get_min_value();
 | 
				
			||||||
 | 
					  msg.max_value = number->traits.get_max_value();
 | 
				
			||||||
 | 
					  msg.step = number->traits.get_step();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return this->send_list_entities_number_response(msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void APIConnection::number_command(const NumberCommandRequest &msg) {
 | 
				
			||||||
 | 
					  number::Number *number = App.get_number_by_key(msg.key);
 | 
				
			||||||
 | 
					  if (number == nullptr)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto call = number->make_call();
 | 
				
			||||||
 | 
					  call.set_value(msg.state);
 | 
				
			||||||
 | 
					  call.perform();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_ESP32_CAMERA
 | 
					#ifdef USE_ESP32_CAMERA
 | 
				
			||||||
void APIConnection::send_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) {
 | 
					void APIConnection::send_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) {
 | 
				
			||||||
  if (!this->state_subscription_)
 | 
					  if (!this->state_subscription_)
 | 
				
			||||||
@@ -602,7 +654,7 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  HelloResponse resp;
 | 
					  HelloResponse resp;
 | 
				
			||||||
  resp.api_version_major = 1;
 | 
					  resp.api_version_major = 1;
 | 
				
			||||||
  resp.api_version_minor = 4;
 | 
					  resp.api_version_minor = 5;
 | 
				
			||||||
  resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
 | 
					  resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
 | 
				
			||||||
  this->connection_state_ = ConnectionState::CONNECTED;
 | 
					  this->connection_state_ = ConnectionState::CONNECTED;
 | 
				
			||||||
  return resp;
 | 
					  return resp;
 | 
				
			||||||
@@ -637,13 +689,18 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef USE_DEEP_SLEEP
 | 
					#ifdef USE_DEEP_SLEEP
 | 
				
			||||||
  resp.has_deep_sleep = deep_sleep::global_has_deep_sleep;
 | 
					  resp.has_deep_sleep = deep_sleep::global_has_deep_sleep;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef ESPHOME_PROJECT_NAME
 | 
				
			||||||
 | 
					  resp.project_name = ESPHOME_PROJECT_NAME;
 | 
				
			||||||
 | 
					  resp.project_version = ESPHOME_PROJECT_VERSION;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  return resp;
 | 
					  return resp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void APIConnection::on_home_assistant_state_response(const HomeAssistantStateResponse &msg) {
 | 
					void APIConnection::on_home_assistant_state_response(const HomeAssistantStateResponse &msg) {
 | 
				
			||||||
  for (auto &it : this->parent_->get_state_subs())
 | 
					  for (auto &it : this->parent_->get_state_subs())
 | 
				
			||||||
    if (it.entity_id == msg.entity_id)
 | 
					    if (it.entity_id == msg.entity_id && it.attribute.value() == msg.attribute) {
 | 
				
			||||||
      it.callback(msg.state);
 | 
					      it.callback(msg.state);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void APIConnection::execute_service(const ExecuteServiceRequest &msg) {
 | 
					void APIConnection::execute_service(const ExecuteServiceRequest &msg) {
 | 
				
			||||||
  bool found = false;
 | 
					  bool found = false;
 | 
				
			||||||
@@ -660,6 +717,7 @@ void APIConnection::subscribe_home_assistant_states(const SubscribeHomeAssistant
 | 
				
			|||||||
  for (auto &it : this->parent_->get_state_subs()) {
 | 
					  for (auto &it : this->parent_->get_state_subs()) {
 | 
				
			||||||
    SubscribeHomeAssistantStateResponse resp;
 | 
					    SubscribeHomeAssistantStateResponse resp;
 | 
				
			||||||
    resp.entity_id = it.entity_id;
 | 
					    resp.entity_id = it.entity_id;
 | 
				
			||||||
 | 
					    resp.attribute = it.attribute.value();
 | 
				
			||||||
    if (!this->send_subscribe_home_assistant_state_response(resp)) {
 | 
					    if (!this->send_subscribe_home_assistant_state_response(resp)) {
 | 
				
			||||||
      this->on_fatal_error();
 | 
					      this->on_fatal_error();
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,6 +62,11 @@ class APIConnection : public APIServerConnection {
 | 
				
			|||||||
  bool send_climate_state(climate::Climate *climate);
 | 
					  bool send_climate_state(climate::Climate *climate);
 | 
				
			||||||
  bool send_climate_info(climate::Climate *climate);
 | 
					  bool send_climate_info(climate::Climate *climate);
 | 
				
			||||||
  void climate_command(const ClimateCommandRequest &msg) override;
 | 
					  void climate_command(const ClimateCommandRequest &msg) override;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					  bool send_number_state(number::Number *number, float state);
 | 
				
			||||||
 | 
					  bool send_number_info(number::Number *number);
 | 
				
			||||||
 | 
					  void number_command(const NumberCommandRequest &msg) override;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  bool send_log_message(int level, const char *tag, const char *line);
 | 
					  bool send_log_message(int level, const char *tag, const char *line);
 | 
				
			||||||
  void send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
 | 
					  void send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,6 +62,16 @@ template<> const char *proto_enum_to_string<enums::FanDirection>(enums::FanDirec
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					template<> const char *proto_enum_to_string<enums::SensorStateClass>(enums::SensorStateClass value) {
 | 
				
			||||||
 | 
					  switch (value) {
 | 
				
			||||||
 | 
					    case enums::STATE_CLASS_NONE:
 | 
				
			||||||
 | 
					      return "STATE_CLASS_NONE";
 | 
				
			||||||
 | 
					    case enums::STATE_CLASS_MEASUREMENT:
 | 
				
			||||||
 | 
					      return "STATE_CLASS_MEASUREMENT";
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      return "UNKNOWN";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
template<> const char *proto_enum_to_string<enums::LogLevel>(enums::LogLevel value) {
 | 
					template<> const char *proto_enum_to_string<enums::LogLevel>(enums::LogLevel value) {
 | 
				
			||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::LOG_LEVEL_NONE:
 | 
					    case enums::LOG_LEVEL_NONE:
 | 
				
			||||||
@@ -108,8 +118,8 @@ template<> const char *proto_enum_to_string<enums::ClimateMode>(enums::ClimateMo
 | 
				
			|||||||
  switch (value) {
 | 
					  switch (value) {
 | 
				
			||||||
    case enums::CLIMATE_MODE_OFF:
 | 
					    case enums::CLIMATE_MODE_OFF:
 | 
				
			||||||
      return "CLIMATE_MODE_OFF";
 | 
					      return "CLIMATE_MODE_OFF";
 | 
				
			||||||
    case enums::CLIMATE_MODE_AUTO:
 | 
					    case enums::CLIMATE_MODE_HEAT_COOL:
 | 
				
			||||||
      return "CLIMATE_MODE_AUTO";
 | 
					      return "CLIMATE_MODE_HEAT_COOL";
 | 
				
			||||||
    case enums::CLIMATE_MODE_COOL:
 | 
					    case enums::CLIMATE_MODE_COOL:
 | 
				
			||||||
      return "CLIMATE_MODE_COOL";
 | 
					      return "CLIMATE_MODE_COOL";
 | 
				
			||||||
    case enums::CLIMATE_MODE_HEAT:
 | 
					    case enums::CLIMATE_MODE_HEAT:
 | 
				
			||||||
@@ -118,6 +128,8 @@ template<> const char *proto_enum_to_string<enums::ClimateMode>(enums::ClimateMo
 | 
				
			|||||||
      return "CLIMATE_MODE_FAN_ONLY";
 | 
					      return "CLIMATE_MODE_FAN_ONLY";
 | 
				
			||||||
    case enums::CLIMATE_MODE_DRY:
 | 
					    case enums::CLIMATE_MODE_DRY:
 | 
				
			||||||
      return "CLIMATE_MODE_DRY";
 | 
					      return "CLIMATE_MODE_DRY";
 | 
				
			||||||
 | 
					    case enums::CLIMATE_MODE_AUTO:
 | 
				
			||||||
 | 
					      return "CLIMATE_MODE_AUTO";
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -178,6 +190,28 @@ template<> const char *proto_enum_to_string<enums::ClimateAction>(enums::Climate
 | 
				
			|||||||
      return "UNKNOWN";
 | 
					      return "UNKNOWN";
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					template<> const char *proto_enum_to_string<enums::ClimatePreset>(enums::ClimatePreset value) {
 | 
				
			||||||
 | 
					  switch (value) {
 | 
				
			||||||
 | 
					    case enums::CLIMATE_PRESET_NONE:
 | 
				
			||||||
 | 
					      return "CLIMATE_PRESET_NONE";
 | 
				
			||||||
 | 
					    case enums::CLIMATE_PRESET_HOME:
 | 
				
			||||||
 | 
					      return "CLIMATE_PRESET_HOME";
 | 
				
			||||||
 | 
					    case enums::CLIMATE_PRESET_AWAY:
 | 
				
			||||||
 | 
					      return "CLIMATE_PRESET_AWAY";
 | 
				
			||||||
 | 
					    case enums::CLIMATE_PRESET_BOOST:
 | 
				
			||||||
 | 
					      return "CLIMATE_PRESET_BOOST";
 | 
				
			||||||
 | 
					    case enums::CLIMATE_PRESET_COMFORT:
 | 
				
			||||||
 | 
					      return "CLIMATE_PRESET_COMFORT";
 | 
				
			||||||
 | 
					    case enums::CLIMATE_PRESET_ECO:
 | 
				
			||||||
 | 
					      return "CLIMATE_PRESET_ECO";
 | 
				
			||||||
 | 
					    case enums::CLIMATE_PRESET_SLEEP:
 | 
				
			||||||
 | 
					      return "CLIMATE_PRESET_SLEEP";
 | 
				
			||||||
 | 
					    case enums::CLIMATE_PRESET_ACTIVITY:
 | 
				
			||||||
 | 
					      return "CLIMATE_PRESET_ACTIVITY";
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      return "UNKNOWN";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
 | 
					bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
 | 
				
			||||||
  switch (field_id) {
 | 
					  switch (field_id) {
 | 
				
			||||||
    case 1: {
 | 
					    case 1: {
 | 
				
			||||||
@@ -328,6 +362,14 @@ bool DeviceInfoResponse::decode_length(uint32_t field_id, ProtoLengthDelimited v
 | 
				
			|||||||
      this->model = value.as_string();
 | 
					      this->model = value.as_string();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case 8: {
 | 
				
			||||||
 | 
					      this->project_name = value.as_string();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 9: {
 | 
				
			||||||
 | 
					      this->project_version = value.as_string();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -340,6 +382,8 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
 | 
				
			|||||||
  buffer.encode_string(5, this->compilation_time);
 | 
					  buffer.encode_string(5, this->compilation_time);
 | 
				
			||||||
  buffer.encode_string(6, this->model);
 | 
					  buffer.encode_string(6, this->model);
 | 
				
			||||||
  buffer.encode_bool(7, this->has_deep_sleep);
 | 
					  buffer.encode_bool(7, this->has_deep_sleep);
 | 
				
			||||||
 | 
					  buffer.encode_string(8, this->project_name);
 | 
				
			||||||
 | 
					  buffer.encode_string(9, this->project_version);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void DeviceInfoResponse::dump_to(std::string &out) const {
 | 
					void DeviceInfoResponse::dump_to(std::string &out) const {
 | 
				
			||||||
  char buffer[64];
 | 
					  char buffer[64];
 | 
				
			||||||
@@ -371,6 +415,14 @@ void DeviceInfoResponse::dump_to(std::string &out) const {
 | 
				
			|||||||
  out.append("  has_deep_sleep: ");
 | 
					  out.append("  has_deep_sleep: ");
 | 
				
			||||||
  out.append(YESNO(this->has_deep_sleep));
 | 
					  out.append(YESNO(this->has_deep_sleep));
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  project_name: ");
 | 
				
			||||||
 | 
					  out.append("'").append(this->project_name).append("'");
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  project_version: ");
 | 
				
			||||||
 | 
					  out.append("'").append(this->project_version).append("'");
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
  out.append("}");
 | 
					  out.append("}");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void ListEntitiesRequest::encode(ProtoWriteBuffer buffer) const {}
 | 
					void ListEntitiesRequest::encode(ProtoWriteBuffer buffer) const {}
 | 
				
			||||||
@@ -1211,6 +1263,10 @@ bool LightStateResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
 | 
				
			|||||||
      this->brightness = value.as_float();
 | 
					      this->brightness = value.as_float();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case 10: {
 | 
				
			||||||
 | 
					      this->color_brightness = value.as_float();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    case 4: {
 | 
					    case 4: {
 | 
				
			||||||
      this->red = value.as_float();
 | 
					      this->red = value.as_float();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
@@ -1239,6 +1295,7 @@ void LightStateResponse::encode(ProtoWriteBuffer buffer) const {
 | 
				
			|||||||
  buffer.encode_fixed32(1, this->key);
 | 
					  buffer.encode_fixed32(1, this->key);
 | 
				
			||||||
  buffer.encode_bool(2, this->state);
 | 
					  buffer.encode_bool(2, this->state);
 | 
				
			||||||
  buffer.encode_float(3, this->brightness);
 | 
					  buffer.encode_float(3, this->brightness);
 | 
				
			||||||
 | 
					  buffer.encode_float(10, this->color_brightness);
 | 
				
			||||||
  buffer.encode_float(4, this->red);
 | 
					  buffer.encode_float(4, this->red);
 | 
				
			||||||
  buffer.encode_float(5, this->green);
 | 
					  buffer.encode_float(5, this->green);
 | 
				
			||||||
  buffer.encode_float(6, this->blue);
 | 
					  buffer.encode_float(6, this->blue);
 | 
				
			||||||
@@ -1263,6 +1320,11 @@ void LightStateResponse::dump_to(std::string &out) const {
 | 
				
			|||||||
  out.append(buffer);
 | 
					  out.append(buffer);
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  color_brightness: ");
 | 
				
			||||||
 | 
					  sprintf(buffer, "%g", this->color_brightness);
 | 
				
			||||||
 | 
					  out.append(buffer);
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  out.append("  red: ");
 | 
					  out.append("  red: ");
 | 
				
			||||||
  sprintf(buffer, "%g", this->red);
 | 
					  sprintf(buffer, "%g", this->red);
 | 
				
			||||||
  out.append(buffer);
 | 
					  out.append(buffer);
 | 
				
			||||||
@@ -1307,6 +1369,10 @@ bool LightCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
 | 
				
			|||||||
      this->has_brightness = value.as_bool();
 | 
					      this->has_brightness = value.as_bool();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case 20: {
 | 
				
			||||||
 | 
					      this->has_color_brightness = value.as_bool();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    case 6: {
 | 
					    case 6: {
 | 
				
			||||||
      this->has_rgb = value.as_bool();
 | 
					      this->has_rgb = value.as_bool();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
@@ -1363,6 +1429,10 @@ bool LightCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
 | 
				
			|||||||
      this->brightness = value.as_float();
 | 
					      this->brightness = value.as_float();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case 21: {
 | 
				
			||||||
 | 
					      this->color_brightness = value.as_float();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    case 7: {
 | 
					    case 7: {
 | 
				
			||||||
      this->red = value.as_float();
 | 
					      this->red = value.as_float();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
@@ -1393,6 +1463,8 @@ void LightCommandRequest::encode(ProtoWriteBuffer buffer) const {
 | 
				
			|||||||
  buffer.encode_bool(3, this->state);
 | 
					  buffer.encode_bool(3, this->state);
 | 
				
			||||||
  buffer.encode_bool(4, this->has_brightness);
 | 
					  buffer.encode_bool(4, this->has_brightness);
 | 
				
			||||||
  buffer.encode_float(5, this->brightness);
 | 
					  buffer.encode_float(5, this->brightness);
 | 
				
			||||||
 | 
					  buffer.encode_bool(20, this->has_color_brightness);
 | 
				
			||||||
 | 
					  buffer.encode_float(21, this->color_brightness);
 | 
				
			||||||
  buffer.encode_bool(6, this->has_rgb);
 | 
					  buffer.encode_bool(6, this->has_rgb);
 | 
				
			||||||
  buffer.encode_float(7, this->red);
 | 
					  buffer.encode_float(7, this->red);
 | 
				
			||||||
  buffer.encode_float(8, this->green);
 | 
					  buffer.encode_float(8, this->green);
 | 
				
			||||||
@@ -1433,6 +1505,15 @@ void LightCommandRequest::dump_to(std::string &out) const {
 | 
				
			|||||||
  out.append(buffer);
 | 
					  out.append(buffer);
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  has_color_brightness: ");
 | 
				
			||||||
 | 
					  out.append(YESNO(this->has_color_brightness));
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  color_brightness: ");
 | 
				
			||||||
 | 
					  sprintf(buffer, "%g", this->color_brightness);
 | 
				
			||||||
 | 
					  out.append(buffer);
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  out.append("  has_rgb: ");
 | 
					  out.append("  has_rgb: ");
 | 
				
			||||||
  out.append(YESNO(this->has_rgb));
 | 
					  out.append(YESNO(this->has_rgb));
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
@@ -1507,6 +1588,10 @@ bool ListEntitiesSensorResponse::decode_varint(uint32_t field_id, ProtoVarInt va
 | 
				
			|||||||
      this->force_update = value.as_bool();
 | 
					      this->force_update = value.as_bool();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case 10: {
 | 
				
			||||||
 | 
					      this->state_class = value.as_enum<enums::SensorStateClass>();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -1561,6 +1646,7 @@ void ListEntitiesSensorResponse::encode(ProtoWriteBuffer buffer) const {
 | 
				
			|||||||
  buffer.encode_int32(7, this->accuracy_decimals);
 | 
					  buffer.encode_int32(7, this->accuracy_decimals);
 | 
				
			||||||
  buffer.encode_bool(8, this->force_update);
 | 
					  buffer.encode_bool(8, this->force_update);
 | 
				
			||||||
  buffer.encode_string(9, this->device_class);
 | 
					  buffer.encode_string(9, this->device_class);
 | 
				
			||||||
 | 
					  buffer.encode_enum<enums::SensorStateClass>(10, this->state_class);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void ListEntitiesSensorResponse::dump_to(std::string &out) const {
 | 
					void ListEntitiesSensorResponse::dump_to(std::string &out) const {
 | 
				
			||||||
  char buffer[64];
 | 
					  char buffer[64];
 | 
				
			||||||
@@ -1602,6 +1688,10 @@ void ListEntitiesSensorResponse::dump_to(std::string &out) const {
 | 
				
			|||||||
  out.append("  device_class: ");
 | 
					  out.append("  device_class: ");
 | 
				
			||||||
  out.append("'").append(this->device_class).append("'");
 | 
					  out.append("'").append(this->device_class).append("'");
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  state_class: ");
 | 
				
			||||||
 | 
					  out.append(proto_enum_to_string<enums::SensorStateClass>(this->state_class));
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
  out.append("}");
 | 
					  out.append("}");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
bool SensorStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
 | 
					bool SensorStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
 | 
				
			||||||
@@ -2123,12 +2213,17 @@ bool SubscribeHomeAssistantStateResponse::decode_length(uint32_t field_id, Proto
 | 
				
			|||||||
      this->entity_id = value.as_string();
 | 
					      this->entity_id = value.as_string();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case 2: {
 | 
				
			||||||
 | 
					      this->attribute = value.as_string();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void SubscribeHomeAssistantStateResponse::encode(ProtoWriteBuffer buffer) const {
 | 
					void SubscribeHomeAssistantStateResponse::encode(ProtoWriteBuffer buffer) const {
 | 
				
			||||||
  buffer.encode_string(1, this->entity_id);
 | 
					  buffer.encode_string(1, this->entity_id);
 | 
				
			||||||
 | 
					  buffer.encode_string(2, this->attribute);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const {
 | 
					void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const {
 | 
				
			||||||
  char buffer[64];
 | 
					  char buffer[64];
 | 
				
			||||||
@@ -2136,6 +2231,10 @@ void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const {
 | 
				
			|||||||
  out.append("  entity_id: ");
 | 
					  out.append("  entity_id: ");
 | 
				
			||||||
  out.append("'").append(this->entity_id).append("'");
 | 
					  out.append("'").append(this->entity_id).append("'");
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  attribute: ");
 | 
				
			||||||
 | 
					  out.append("'").append(this->attribute).append("'");
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
  out.append("}");
 | 
					  out.append("}");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
 | 
					bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
 | 
				
			||||||
@@ -2148,6 +2247,10 @@ bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDel
 | 
				
			|||||||
      this->state = value.as_string();
 | 
					      this->state = value.as_string();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case 3: {
 | 
				
			||||||
 | 
					      this->attribute = value.as_string();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -2155,6 +2258,7 @@ bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDel
 | 
				
			|||||||
void HomeAssistantStateResponse::encode(ProtoWriteBuffer buffer) const {
 | 
					void HomeAssistantStateResponse::encode(ProtoWriteBuffer buffer) const {
 | 
				
			||||||
  buffer.encode_string(1, this->entity_id);
 | 
					  buffer.encode_string(1, this->entity_id);
 | 
				
			||||||
  buffer.encode_string(2, this->state);
 | 
					  buffer.encode_string(2, this->state);
 | 
				
			||||||
 | 
					  buffer.encode_string(3, this->attribute);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void HomeAssistantStateResponse::dump_to(std::string &out) const {
 | 
					void HomeAssistantStateResponse::dump_to(std::string &out) const {
 | 
				
			||||||
  char buffer[64];
 | 
					  char buffer[64];
 | 
				
			||||||
@@ -2166,6 +2270,10 @@ void HomeAssistantStateResponse::dump_to(std::string &out) const {
 | 
				
			|||||||
  out.append("  state: ");
 | 
					  out.append("  state: ");
 | 
				
			||||||
  out.append("'").append(this->state).append("'");
 | 
					  out.append("'").append(this->state).append("'");
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  attribute: ");
 | 
				
			||||||
 | 
					  out.append("'").append(this->attribute).append("'");
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
  out.append("}");
 | 
					  out.append("}");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void GetTimeRequest::encode(ProtoWriteBuffer buffer) const {}
 | 
					void GetTimeRequest::encode(ProtoWriteBuffer buffer) const {}
 | 
				
			||||||
@@ -2595,7 +2703,7 @@ bool ListEntitiesClimateResponse::decode_varint(uint32_t field_id, ProtoVarInt v
 | 
				
			|||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case 11: {
 | 
					    case 11: {
 | 
				
			||||||
      this->supports_away = value.as_bool();
 | 
					      this->legacy_supports_away = value.as_bool();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case 12: {
 | 
					    case 12: {
 | 
				
			||||||
@@ -2610,6 +2718,10 @@ bool ListEntitiesClimateResponse::decode_varint(uint32_t field_id, ProtoVarInt v
 | 
				
			|||||||
      this->supported_swing_modes.push_back(value.as_enum<enums::ClimateSwingMode>());
 | 
					      this->supported_swing_modes.push_back(value.as_enum<enums::ClimateSwingMode>());
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case 16: {
 | 
				
			||||||
 | 
					      this->supported_presets.push_back(value.as_enum<enums::ClimatePreset>());
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -2628,6 +2740,14 @@ bool ListEntitiesClimateResponse::decode_length(uint32_t field_id, ProtoLengthDe
 | 
				
			|||||||
      this->unique_id = value.as_string();
 | 
					      this->unique_id = value.as_string();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case 15: {
 | 
				
			||||||
 | 
					      this->supported_custom_fan_modes.push_back(value.as_string());
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 17: {
 | 
				
			||||||
 | 
					      this->supported_custom_presets.push_back(value.as_string());
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -2667,7 +2787,7 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer buffer) const {
 | 
				
			|||||||
  buffer.encode_float(8, this->visual_min_temperature);
 | 
					  buffer.encode_float(8, this->visual_min_temperature);
 | 
				
			||||||
  buffer.encode_float(9, this->visual_max_temperature);
 | 
					  buffer.encode_float(9, this->visual_max_temperature);
 | 
				
			||||||
  buffer.encode_float(10, this->visual_temperature_step);
 | 
					  buffer.encode_float(10, this->visual_temperature_step);
 | 
				
			||||||
  buffer.encode_bool(11, this->supports_away);
 | 
					  buffer.encode_bool(11, this->legacy_supports_away);
 | 
				
			||||||
  buffer.encode_bool(12, this->supports_action);
 | 
					  buffer.encode_bool(12, this->supports_action);
 | 
				
			||||||
  for (auto &it : this->supported_fan_modes) {
 | 
					  for (auto &it : this->supported_fan_modes) {
 | 
				
			||||||
    buffer.encode_enum<enums::ClimateFanMode>(13, it, true);
 | 
					    buffer.encode_enum<enums::ClimateFanMode>(13, it, true);
 | 
				
			||||||
@@ -2675,6 +2795,15 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer buffer) const {
 | 
				
			|||||||
  for (auto &it : this->supported_swing_modes) {
 | 
					  for (auto &it : this->supported_swing_modes) {
 | 
				
			||||||
    buffer.encode_enum<enums::ClimateSwingMode>(14, it, true);
 | 
					    buffer.encode_enum<enums::ClimateSwingMode>(14, it, true);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  for (auto &it : this->supported_custom_fan_modes) {
 | 
				
			||||||
 | 
					    buffer.encode_string(15, it, true);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  for (auto &it : this->supported_presets) {
 | 
				
			||||||
 | 
					    buffer.encode_enum<enums::ClimatePreset>(16, it, true);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  for (auto &it : this->supported_custom_presets) {
 | 
				
			||||||
 | 
					    buffer.encode_string(17, it, true);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void ListEntitiesClimateResponse::dump_to(std::string &out) const {
 | 
					void ListEntitiesClimateResponse::dump_to(std::string &out) const {
 | 
				
			||||||
  char buffer[64];
 | 
					  char buffer[64];
 | 
				
			||||||
@@ -2725,8 +2854,8 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const {
 | 
				
			|||||||
  out.append(buffer);
 | 
					  out.append(buffer);
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  out.append("  supports_away: ");
 | 
					  out.append("  legacy_supports_away: ");
 | 
				
			||||||
  out.append(YESNO(this->supports_away));
 | 
					  out.append(YESNO(this->legacy_supports_away));
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  out.append("  supports_action: ");
 | 
					  out.append("  supports_action: ");
 | 
				
			||||||
@@ -2744,6 +2873,24 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const {
 | 
				
			|||||||
    out.append(proto_enum_to_string<enums::ClimateSwingMode>(it));
 | 
					    out.append(proto_enum_to_string<enums::ClimateSwingMode>(it));
 | 
				
			||||||
    out.append("\n");
 | 
					    out.append("\n");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (const auto &it : this->supported_custom_fan_modes) {
 | 
				
			||||||
 | 
					    out.append("  supported_custom_fan_modes: ");
 | 
				
			||||||
 | 
					    out.append("'").append(it).append("'");
 | 
				
			||||||
 | 
					    out.append("\n");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (const auto &it : this->supported_presets) {
 | 
				
			||||||
 | 
					    out.append("  supported_presets: ");
 | 
				
			||||||
 | 
					    out.append(proto_enum_to_string<enums::ClimatePreset>(it));
 | 
				
			||||||
 | 
					    out.append("\n");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (const auto &it : this->supported_custom_presets) {
 | 
				
			||||||
 | 
					    out.append("  supported_custom_presets: ");
 | 
				
			||||||
 | 
					    out.append("'").append(it).append("'");
 | 
				
			||||||
 | 
					    out.append("\n");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  out.append("}");
 | 
					  out.append("}");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
bool ClimateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
 | 
					bool ClimateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
 | 
				
			||||||
@@ -2753,7 +2900,7 @@ bool ClimateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
 | 
				
			|||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case 7: {
 | 
					    case 7: {
 | 
				
			||||||
      this->away = value.as_bool();
 | 
					      this->legacy_away = value.as_bool();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case 8: {
 | 
					    case 8: {
 | 
				
			||||||
@@ -2768,6 +2915,24 @@ bool ClimateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
 | 
				
			|||||||
      this->swing_mode = value.as_enum<enums::ClimateSwingMode>();
 | 
					      this->swing_mode = value.as_enum<enums::ClimateSwingMode>();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case 12: {
 | 
				
			||||||
 | 
					      this->preset = value.as_enum<enums::ClimatePreset>();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bool ClimateStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
 | 
				
			||||||
 | 
					  switch (field_id) {
 | 
				
			||||||
 | 
					    case 11: {
 | 
				
			||||||
 | 
					      this->custom_fan_mode = value.as_string();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 13: {
 | 
				
			||||||
 | 
					      this->custom_preset = value.as_string();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -2805,10 +2970,13 @@ void ClimateStateResponse::encode(ProtoWriteBuffer buffer) const {
 | 
				
			|||||||
  buffer.encode_float(4, this->target_temperature);
 | 
					  buffer.encode_float(4, this->target_temperature);
 | 
				
			||||||
  buffer.encode_float(5, this->target_temperature_low);
 | 
					  buffer.encode_float(5, this->target_temperature_low);
 | 
				
			||||||
  buffer.encode_float(6, this->target_temperature_high);
 | 
					  buffer.encode_float(6, this->target_temperature_high);
 | 
				
			||||||
  buffer.encode_bool(7, this->away);
 | 
					  buffer.encode_bool(7, this->legacy_away);
 | 
				
			||||||
  buffer.encode_enum<enums::ClimateAction>(8, this->action);
 | 
					  buffer.encode_enum<enums::ClimateAction>(8, this->action);
 | 
				
			||||||
  buffer.encode_enum<enums::ClimateFanMode>(9, this->fan_mode);
 | 
					  buffer.encode_enum<enums::ClimateFanMode>(9, this->fan_mode);
 | 
				
			||||||
  buffer.encode_enum<enums::ClimateSwingMode>(10, this->swing_mode);
 | 
					  buffer.encode_enum<enums::ClimateSwingMode>(10, this->swing_mode);
 | 
				
			||||||
 | 
					  buffer.encode_string(11, this->custom_fan_mode);
 | 
				
			||||||
 | 
					  buffer.encode_enum<enums::ClimatePreset>(12, this->preset);
 | 
				
			||||||
 | 
					  buffer.encode_string(13, this->custom_preset);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void ClimateStateResponse::dump_to(std::string &out) const {
 | 
					void ClimateStateResponse::dump_to(std::string &out) const {
 | 
				
			||||||
  char buffer[64];
 | 
					  char buffer[64];
 | 
				
			||||||
@@ -2842,8 +3010,8 @@ void ClimateStateResponse::dump_to(std::string &out) const {
 | 
				
			|||||||
  out.append(buffer);
 | 
					  out.append(buffer);
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  out.append("  away: ");
 | 
					  out.append("  legacy_away: ");
 | 
				
			||||||
  out.append(YESNO(this->away));
 | 
					  out.append(YESNO(this->legacy_away));
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  out.append("  action: ");
 | 
					  out.append("  action: ");
 | 
				
			||||||
@@ -2857,6 +3025,18 @@ void ClimateStateResponse::dump_to(std::string &out) const {
 | 
				
			|||||||
  out.append("  swing_mode: ");
 | 
					  out.append("  swing_mode: ");
 | 
				
			||||||
  out.append(proto_enum_to_string<enums::ClimateSwingMode>(this->swing_mode));
 | 
					  out.append(proto_enum_to_string<enums::ClimateSwingMode>(this->swing_mode));
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  custom_fan_mode: ");
 | 
				
			||||||
 | 
					  out.append("'").append(this->custom_fan_mode).append("'");
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  preset: ");
 | 
				
			||||||
 | 
					  out.append(proto_enum_to_string<enums::ClimatePreset>(this->preset));
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  custom_preset: ");
 | 
				
			||||||
 | 
					  out.append("'").append(this->custom_preset).append("'");
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
  out.append("}");
 | 
					  out.append("}");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
 | 
					bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
 | 
				
			||||||
@@ -2882,11 +3062,11 @@ bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value)
 | 
				
			|||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case 10: {
 | 
					    case 10: {
 | 
				
			||||||
      this->has_away = value.as_bool();
 | 
					      this->has_legacy_away = value.as_bool();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case 11: {
 | 
					    case 11: {
 | 
				
			||||||
      this->away = value.as_bool();
 | 
					      this->legacy_away = value.as_bool();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case 12: {
 | 
					    case 12: {
 | 
				
			||||||
@@ -2905,6 +3085,36 @@ bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value)
 | 
				
			|||||||
      this->swing_mode = value.as_enum<enums::ClimateSwingMode>();
 | 
					      this->swing_mode = value.as_enum<enums::ClimateSwingMode>();
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    case 16: {
 | 
				
			||||||
 | 
					      this->has_custom_fan_mode = value.as_bool();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 18: {
 | 
				
			||||||
 | 
					      this->has_preset = value.as_bool();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 19: {
 | 
				
			||||||
 | 
					      this->preset = value.as_enum<enums::ClimatePreset>();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 20: {
 | 
				
			||||||
 | 
					      this->has_custom_preset = value.as_bool();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bool ClimateCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
 | 
				
			||||||
 | 
					  switch (field_id) {
 | 
				
			||||||
 | 
					    case 17: {
 | 
				
			||||||
 | 
					      this->custom_fan_mode = value.as_string();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 21: {
 | 
				
			||||||
 | 
					      this->custom_preset = value.as_string();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -2941,12 +3151,18 @@ void ClimateCommandRequest::encode(ProtoWriteBuffer buffer) const {
 | 
				
			|||||||
  buffer.encode_float(7, this->target_temperature_low);
 | 
					  buffer.encode_float(7, this->target_temperature_low);
 | 
				
			||||||
  buffer.encode_bool(8, this->has_target_temperature_high);
 | 
					  buffer.encode_bool(8, this->has_target_temperature_high);
 | 
				
			||||||
  buffer.encode_float(9, this->target_temperature_high);
 | 
					  buffer.encode_float(9, this->target_temperature_high);
 | 
				
			||||||
  buffer.encode_bool(10, this->has_away);
 | 
					  buffer.encode_bool(10, this->has_legacy_away);
 | 
				
			||||||
  buffer.encode_bool(11, this->away);
 | 
					  buffer.encode_bool(11, this->legacy_away);
 | 
				
			||||||
  buffer.encode_bool(12, this->has_fan_mode);
 | 
					  buffer.encode_bool(12, this->has_fan_mode);
 | 
				
			||||||
  buffer.encode_enum<enums::ClimateFanMode>(13, this->fan_mode);
 | 
					  buffer.encode_enum<enums::ClimateFanMode>(13, this->fan_mode);
 | 
				
			||||||
  buffer.encode_bool(14, this->has_swing_mode);
 | 
					  buffer.encode_bool(14, this->has_swing_mode);
 | 
				
			||||||
  buffer.encode_enum<enums::ClimateSwingMode>(15, this->swing_mode);
 | 
					  buffer.encode_enum<enums::ClimateSwingMode>(15, this->swing_mode);
 | 
				
			||||||
 | 
					  buffer.encode_bool(16, this->has_custom_fan_mode);
 | 
				
			||||||
 | 
					  buffer.encode_string(17, this->custom_fan_mode);
 | 
				
			||||||
 | 
					  buffer.encode_bool(18, this->has_preset);
 | 
				
			||||||
 | 
					  buffer.encode_enum<enums::ClimatePreset>(19, this->preset);
 | 
				
			||||||
 | 
					  buffer.encode_bool(20, this->has_custom_preset);
 | 
				
			||||||
 | 
					  buffer.encode_string(21, this->custom_preset);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void ClimateCommandRequest::dump_to(std::string &out) const {
 | 
					void ClimateCommandRequest::dump_to(std::string &out) const {
 | 
				
			||||||
  char buffer[64];
 | 
					  char buffer[64];
 | 
				
			||||||
@@ -2991,12 +3207,12 @@ void ClimateCommandRequest::dump_to(std::string &out) const {
 | 
				
			|||||||
  out.append(buffer);
 | 
					  out.append(buffer);
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  out.append("  has_away: ");
 | 
					  out.append("  has_legacy_away: ");
 | 
				
			||||||
  out.append(YESNO(this->has_away));
 | 
					  out.append(YESNO(this->has_legacy_away));
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  out.append("  away: ");
 | 
					  out.append("  legacy_away: ");
 | 
				
			||||||
  out.append(YESNO(this->away));
 | 
					  out.append(YESNO(this->legacy_away));
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  out.append("  has_fan_mode: ");
 | 
					  out.append("  has_fan_mode: ");
 | 
				
			||||||
@@ -3014,6 +3230,203 @@ void ClimateCommandRequest::dump_to(std::string &out) const {
 | 
				
			|||||||
  out.append("  swing_mode: ");
 | 
					  out.append("  swing_mode: ");
 | 
				
			||||||
  out.append(proto_enum_to_string<enums::ClimateSwingMode>(this->swing_mode));
 | 
					  out.append(proto_enum_to_string<enums::ClimateSwingMode>(this->swing_mode));
 | 
				
			||||||
  out.append("\n");
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  has_custom_fan_mode: ");
 | 
				
			||||||
 | 
					  out.append(YESNO(this->has_custom_fan_mode));
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  custom_fan_mode: ");
 | 
				
			||||||
 | 
					  out.append("'").append(this->custom_fan_mode).append("'");
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  has_preset: ");
 | 
				
			||||||
 | 
					  out.append(YESNO(this->has_preset));
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  preset: ");
 | 
				
			||||||
 | 
					  out.append(proto_enum_to_string<enums::ClimatePreset>(this->preset));
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  has_custom_preset: ");
 | 
				
			||||||
 | 
					  out.append(YESNO(this->has_custom_preset));
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  custom_preset: ");
 | 
				
			||||||
 | 
					  out.append("'").append(this->custom_preset).append("'");
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					  out.append("}");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bool ListEntitiesNumberResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
 | 
				
			||||||
 | 
					  switch (field_id) {
 | 
				
			||||||
 | 
					    case 1: {
 | 
				
			||||||
 | 
					      this->object_id = value.as_string();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 3: {
 | 
				
			||||||
 | 
					      this->name = value.as_string();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 4: {
 | 
				
			||||||
 | 
					      this->unique_id = value.as_string();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 5: {
 | 
				
			||||||
 | 
					      this->icon = value.as_string();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bool ListEntitiesNumberResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
 | 
				
			||||||
 | 
					  switch (field_id) {
 | 
				
			||||||
 | 
					    case 2: {
 | 
				
			||||||
 | 
					      this->key = value.as_fixed32();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 6: {
 | 
				
			||||||
 | 
					      this->min_value = value.as_float();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 7: {
 | 
				
			||||||
 | 
					      this->max_value = value.as_float();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 8: {
 | 
				
			||||||
 | 
					      this->step = value.as_float();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void ListEntitiesNumberResponse::encode(ProtoWriteBuffer buffer) const {
 | 
				
			||||||
 | 
					  buffer.encode_string(1, this->object_id);
 | 
				
			||||||
 | 
					  buffer.encode_fixed32(2, this->key);
 | 
				
			||||||
 | 
					  buffer.encode_string(3, this->name);
 | 
				
			||||||
 | 
					  buffer.encode_string(4, this->unique_id);
 | 
				
			||||||
 | 
					  buffer.encode_string(5, this->icon);
 | 
				
			||||||
 | 
					  buffer.encode_float(6, this->min_value);
 | 
				
			||||||
 | 
					  buffer.encode_float(7, this->max_value);
 | 
				
			||||||
 | 
					  buffer.encode_float(8, this->step);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void ListEntitiesNumberResponse::dump_to(std::string &out) const {
 | 
				
			||||||
 | 
					  char buffer[64];
 | 
				
			||||||
 | 
					  out.append("ListEntitiesNumberResponse {\n");
 | 
				
			||||||
 | 
					  out.append("  object_id: ");
 | 
				
			||||||
 | 
					  out.append("'").append(this->object_id).append("'");
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  key: ");
 | 
				
			||||||
 | 
					  sprintf(buffer, "%u", this->key);
 | 
				
			||||||
 | 
					  out.append(buffer);
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  name: ");
 | 
				
			||||||
 | 
					  out.append("'").append(this->name).append("'");
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  unique_id: ");
 | 
				
			||||||
 | 
					  out.append("'").append(this->unique_id).append("'");
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  icon: ");
 | 
				
			||||||
 | 
					  out.append("'").append(this->icon).append("'");
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  min_value: ");
 | 
				
			||||||
 | 
					  sprintf(buffer, "%g", this->min_value);
 | 
				
			||||||
 | 
					  out.append(buffer);
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  max_value: ");
 | 
				
			||||||
 | 
					  sprintf(buffer, "%g", this->max_value);
 | 
				
			||||||
 | 
					  out.append(buffer);
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  step: ");
 | 
				
			||||||
 | 
					  sprintf(buffer, "%g", this->step);
 | 
				
			||||||
 | 
					  out.append(buffer);
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					  out.append("}");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bool NumberStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
 | 
				
			||||||
 | 
					  switch (field_id) {
 | 
				
			||||||
 | 
					    case 3: {
 | 
				
			||||||
 | 
					      this->missing_state = value.as_bool();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bool NumberStateResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
 | 
				
			||||||
 | 
					  switch (field_id) {
 | 
				
			||||||
 | 
					    case 1: {
 | 
				
			||||||
 | 
					      this->key = value.as_fixed32();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 2: {
 | 
				
			||||||
 | 
					      this->state = value.as_float();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void NumberStateResponse::encode(ProtoWriteBuffer buffer) const {
 | 
				
			||||||
 | 
					  buffer.encode_fixed32(1, this->key);
 | 
				
			||||||
 | 
					  buffer.encode_float(2, this->state);
 | 
				
			||||||
 | 
					  buffer.encode_bool(3, this->missing_state);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void NumberStateResponse::dump_to(std::string &out) const {
 | 
				
			||||||
 | 
					  char buffer[64];
 | 
				
			||||||
 | 
					  out.append("NumberStateResponse {\n");
 | 
				
			||||||
 | 
					  out.append("  key: ");
 | 
				
			||||||
 | 
					  sprintf(buffer, "%u", this->key);
 | 
				
			||||||
 | 
					  out.append(buffer);
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  state: ");
 | 
				
			||||||
 | 
					  sprintf(buffer, "%g", this->state);
 | 
				
			||||||
 | 
					  out.append(buffer);
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  missing_state: ");
 | 
				
			||||||
 | 
					  out.append(YESNO(this->missing_state));
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					  out.append("}");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					bool NumberCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
 | 
				
			||||||
 | 
					  switch (field_id) {
 | 
				
			||||||
 | 
					    case 1: {
 | 
				
			||||||
 | 
					      this->key = value.as_fixed32();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 2: {
 | 
				
			||||||
 | 
					      this->state = value.as_float();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void NumberCommandRequest::encode(ProtoWriteBuffer buffer) const {
 | 
				
			||||||
 | 
					  buffer.encode_fixed32(1, this->key);
 | 
				
			||||||
 | 
					  buffer.encode_float(2, this->state);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					void NumberCommandRequest::dump_to(std::string &out) const {
 | 
				
			||||||
 | 
					  char buffer[64];
 | 
				
			||||||
 | 
					  out.append("NumberCommandRequest {\n");
 | 
				
			||||||
 | 
					  out.append("  key: ");
 | 
				
			||||||
 | 
					  sprintf(buffer, "%u", this->key);
 | 
				
			||||||
 | 
					  out.append(buffer);
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  out.append("  state: ");
 | 
				
			||||||
 | 
					  sprintf(buffer, "%g", this->state);
 | 
				
			||||||
 | 
					  out.append(buffer);
 | 
				
			||||||
 | 
					  out.append("\n");
 | 
				
			||||||
  out.append("}");
 | 
					  out.append("}");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,6 +32,10 @@ enum FanDirection : uint32_t {
 | 
				
			|||||||
  FAN_DIRECTION_FORWARD = 0,
 | 
					  FAN_DIRECTION_FORWARD = 0,
 | 
				
			||||||
  FAN_DIRECTION_REVERSE = 1,
 | 
					  FAN_DIRECTION_REVERSE = 1,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					enum SensorStateClass : uint32_t {
 | 
				
			||||||
 | 
					  STATE_CLASS_NONE = 0,
 | 
				
			||||||
 | 
					  STATE_CLASS_MEASUREMENT = 1,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
enum LogLevel : uint32_t {
 | 
					enum LogLevel : uint32_t {
 | 
				
			||||||
  LOG_LEVEL_NONE = 0,
 | 
					  LOG_LEVEL_NONE = 0,
 | 
				
			||||||
  LOG_LEVEL_ERROR = 1,
 | 
					  LOG_LEVEL_ERROR = 1,
 | 
				
			||||||
@@ -53,11 +57,12 @@ enum ServiceArgType : uint32_t {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
enum ClimateMode : uint32_t {
 | 
					enum ClimateMode : uint32_t {
 | 
				
			||||||
  CLIMATE_MODE_OFF = 0,
 | 
					  CLIMATE_MODE_OFF = 0,
 | 
				
			||||||
  CLIMATE_MODE_AUTO = 1,
 | 
					  CLIMATE_MODE_HEAT_COOL = 1,
 | 
				
			||||||
  CLIMATE_MODE_COOL = 2,
 | 
					  CLIMATE_MODE_COOL = 2,
 | 
				
			||||||
  CLIMATE_MODE_HEAT = 3,
 | 
					  CLIMATE_MODE_HEAT = 3,
 | 
				
			||||||
  CLIMATE_MODE_FAN_ONLY = 4,
 | 
					  CLIMATE_MODE_FAN_ONLY = 4,
 | 
				
			||||||
  CLIMATE_MODE_DRY = 5,
 | 
					  CLIMATE_MODE_DRY = 5,
 | 
				
			||||||
 | 
					  CLIMATE_MODE_AUTO = 6,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
enum ClimateFanMode : uint32_t {
 | 
					enum ClimateFanMode : uint32_t {
 | 
				
			||||||
  CLIMATE_FAN_ON = 0,
 | 
					  CLIMATE_FAN_ON = 0,
 | 
				
			||||||
@@ -84,12 +89,22 @@ enum ClimateAction : uint32_t {
 | 
				
			|||||||
  CLIMATE_ACTION_DRYING = 5,
 | 
					  CLIMATE_ACTION_DRYING = 5,
 | 
				
			||||||
  CLIMATE_ACTION_FAN = 6,
 | 
					  CLIMATE_ACTION_FAN = 6,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					enum ClimatePreset : uint32_t {
 | 
				
			||||||
 | 
					  CLIMATE_PRESET_NONE = 0,
 | 
				
			||||||
 | 
					  CLIMATE_PRESET_HOME = 1,
 | 
				
			||||||
 | 
					  CLIMATE_PRESET_AWAY = 2,
 | 
				
			||||||
 | 
					  CLIMATE_PRESET_BOOST = 3,
 | 
				
			||||||
 | 
					  CLIMATE_PRESET_COMFORT = 4,
 | 
				
			||||||
 | 
					  CLIMATE_PRESET_ECO = 5,
 | 
				
			||||||
 | 
					  CLIMATE_PRESET_SLEEP = 6,
 | 
				
			||||||
 | 
					  CLIMATE_PRESET_ACTIVITY = 7,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace enums
 | 
					}  // namespace enums
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class HelloRequest : public ProtoMessage {
 | 
					class HelloRequest : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string client_info{};  // NOLINT
 | 
					  std::string client_info{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -98,9 +113,9 @@ class HelloRequest : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class HelloResponse : public ProtoMessage {
 | 
					class HelloResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t api_version_major{0};  // NOLINT
 | 
					  uint32_t api_version_major{0};
 | 
				
			||||||
  uint32_t api_version_minor{0};  // NOLINT
 | 
					  uint32_t api_version_minor{0};
 | 
				
			||||||
  std::string server_info{};      // NOLINT
 | 
					  std::string server_info{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -110,7 +125,7 @@ class HelloResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class ConnectRequest : public ProtoMessage {
 | 
					class ConnectRequest : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string password{};  // NOLINT
 | 
					  std::string password{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -119,7 +134,7 @@ class ConnectRequest : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class ConnectResponse : public ProtoMessage {
 | 
					class ConnectResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  bool invalid_password{false};  // NOLINT
 | 
					  bool invalid_password{false};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -163,13 +178,15 @@ class DeviceInfoRequest : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class DeviceInfoResponse : public ProtoMessage {
 | 
					class DeviceInfoResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  bool uses_password{false};       // NOLINT
 | 
					  bool uses_password{false};
 | 
				
			||||||
  std::string name{};              // NOLINT
 | 
					  std::string name{};
 | 
				
			||||||
  std::string mac_address{};       // NOLINT
 | 
					  std::string mac_address{};
 | 
				
			||||||
  std::string esphome_version{};   // NOLINT
 | 
					  std::string esphome_version{};
 | 
				
			||||||
  std::string compilation_time{};  // NOLINT
 | 
					  std::string compilation_time{};
 | 
				
			||||||
  std::string model{};             // NOLINT
 | 
					  std::string model{};
 | 
				
			||||||
  bool has_deep_sleep{false};      // NOLINT
 | 
					  bool has_deep_sleep{false};
 | 
				
			||||||
 | 
					  std::string project_name{};
 | 
				
			||||||
 | 
					  std::string project_version{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -200,12 +217,12 @@ class SubscribeStatesRequest : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class ListEntitiesBinarySensorResponse : public ProtoMessage {
 | 
					class ListEntitiesBinarySensorResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string object_id{};              // NOLINT
 | 
					  std::string object_id{};
 | 
				
			||||||
  uint32_t key{0};                      // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  std::string name{};                   // NOLINT
 | 
					  std::string name{};
 | 
				
			||||||
  std::string unique_id{};              // NOLINT
 | 
					  std::string unique_id{};
 | 
				
			||||||
  std::string device_class{};           // NOLINT
 | 
					  std::string device_class{};
 | 
				
			||||||
  bool is_status_binary_sensor{false};  // NOLINT
 | 
					  bool is_status_binary_sensor{false};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -216,9 +233,9 @@ class ListEntitiesBinarySensorResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class BinarySensorStateResponse : public ProtoMessage {
 | 
					class BinarySensorStateResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t key{0};            // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  bool state{false};          // NOLINT
 | 
					  bool state{false};
 | 
				
			||||||
  bool missing_state{false};  // NOLINT
 | 
					  bool missing_state{false};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -228,14 +245,14 @@ class BinarySensorStateResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class ListEntitiesCoverResponse : public ProtoMessage {
 | 
					class ListEntitiesCoverResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string object_id{};        // NOLINT
 | 
					  std::string object_id{};
 | 
				
			||||||
  uint32_t key{0};                // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  std::string name{};             // NOLINT
 | 
					  std::string name{};
 | 
				
			||||||
  std::string unique_id{};        // NOLINT
 | 
					  std::string unique_id{};
 | 
				
			||||||
  bool assumed_state{false};      // NOLINT
 | 
					  bool assumed_state{false};
 | 
				
			||||||
  bool supports_position{false};  // NOLINT
 | 
					  bool supports_position{false};
 | 
				
			||||||
  bool supports_tilt{false};      // NOLINT
 | 
					  bool supports_tilt{false};
 | 
				
			||||||
  std::string device_class{};     // NOLINT
 | 
					  std::string device_class{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -246,11 +263,11 @@ class ListEntitiesCoverResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class CoverStateResponse : public ProtoMessage {
 | 
					class CoverStateResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t key{0};                            // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  enums::LegacyCoverState legacy_state{};     // NOLINT
 | 
					  enums::LegacyCoverState legacy_state{};
 | 
				
			||||||
  float position{0.0f};                       // NOLINT
 | 
					  float position{0.0f};
 | 
				
			||||||
  float tilt{0.0f};                           // NOLINT
 | 
					  float tilt{0.0f};
 | 
				
			||||||
  enums::CoverOperation current_operation{};  // NOLINT
 | 
					  enums::CoverOperation current_operation{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -260,14 +277,14 @@ class CoverStateResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class CoverCommandRequest : public ProtoMessage {
 | 
					class CoverCommandRequest : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t key{0};                             // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  bool has_legacy_command{false};              // NOLINT
 | 
					  bool has_legacy_command{false};
 | 
				
			||||||
  enums::LegacyCoverCommand legacy_command{};  // NOLINT
 | 
					  enums::LegacyCoverCommand legacy_command{};
 | 
				
			||||||
  bool has_position{false};                    // NOLINT
 | 
					  bool has_position{false};
 | 
				
			||||||
  float position{0.0f};                        // NOLINT
 | 
					  float position{0.0f};
 | 
				
			||||||
  bool has_tilt{false};                        // NOLINT
 | 
					  bool has_tilt{false};
 | 
				
			||||||
  float tilt{0.0f};                            // NOLINT
 | 
					  float tilt{0.0f};
 | 
				
			||||||
  bool stop{false};                            // NOLINT
 | 
					  bool stop{false};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -277,14 +294,14 @@ class CoverCommandRequest : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class ListEntitiesFanResponse : public ProtoMessage {
 | 
					class ListEntitiesFanResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string object_id{};           // NOLINT
 | 
					  std::string object_id{};
 | 
				
			||||||
  uint32_t key{0};                   // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  std::string name{};                // NOLINT
 | 
					  std::string name{};
 | 
				
			||||||
  std::string unique_id{};           // NOLINT
 | 
					  std::string unique_id{};
 | 
				
			||||||
  bool supports_oscillation{false};  // NOLINT
 | 
					  bool supports_oscillation{false};
 | 
				
			||||||
  bool supports_speed{false};        // NOLINT
 | 
					  bool supports_speed{false};
 | 
				
			||||||
  bool supports_direction{false};    // NOLINT
 | 
					  bool supports_direction{false};
 | 
				
			||||||
  int32_t supported_speed_count{0};  // NOLINT
 | 
					  int32_t supported_speed_count{0};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -295,12 +312,12 @@ class ListEntitiesFanResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class FanStateResponse : public ProtoMessage {
 | 
					class FanStateResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t key{0};                  // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  bool state{false};                // NOLINT
 | 
					  bool state{false};
 | 
				
			||||||
  bool oscillating{false};          // NOLINT
 | 
					  bool oscillating{false};
 | 
				
			||||||
  enums::FanSpeed speed{};          // NOLINT
 | 
					  enums::FanSpeed speed{};
 | 
				
			||||||
  enums::FanDirection direction{};  // NOLINT
 | 
					  enums::FanDirection direction{};
 | 
				
			||||||
  int32_t speed_level{0};           // NOLINT
 | 
					  int32_t speed_level{0};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -310,17 +327,17 @@ class FanStateResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class FanCommandRequest : public ProtoMessage {
 | 
					class FanCommandRequest : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t key{0};                  // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  bool has_state{false};            // NOLINT
 | 
					  bool has_state{false};
 | 
				
			||||||
  bool state{false};                // NOLINT
 | 
					  bool state{false};
 | 
				
			||||||
  bool has_speed{false};            // NOLINT
 | 
					  bool has_speed{false};
 | 
				
			||||||
  enums::FanSpeed speed{};          // NOLINT
 | 
					  enums::FanSpeed speed{};
 | 
				
			||||||
  bool has_oscillating{false};      // NOLINT
 | 
					  bool has_oscillating{false};
 | 
				
			||||||
  bool oscillating{false};          // NOLINT
 | 
					  bool oscillating{false};
 | 
				
			||||||
  bool has_direction{false};        // NOLINT
 | 
					  bool has_direction{false};
 | 
				
			||||||
  enums::FanDirection direction{};  // NOLINT
 | 
					  enums::FanDirection direction{};
 | 
				
			||||||
  bool has_speed_level{false};      // NOLINT
 | 
					  bool has_speed_level{false};
 | 
				
			||||||
  int32_t speed_level{0};           // NOLINT
 | 
					  int32_t speed_level{0};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -330,17 +347,17 @@ class FanCommandRequest : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class ListEntitiesLightResponse : public ProtoMessage {
 | 
					class ListEntitiesLightResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string object_id{};                 // NOLINT
 | 
					  std::string object_id{};
 | 
				
			||||||
  uint32_t key{0};                         // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  std::string name{};                      // NOLINT
 | 
					  std::string name{};
 | 
				
			||||||
  std::string unique_id{};                 // NOLINT
 | 
					  std::string unique_id{};
 | 
				
			||||||
  bool supports_brightness{false};         // NOLINT
 | 
					  bool supports_brightness{false};
 | 
				
			||||||
  bool supports_rgb{false};                // NOLINT
 | 
					  bool supports_rgb{false};
 | 
				
			||||||
  bool supports_white_value{false};        // NOLINT
 | 
					  bool supports_white_value{false};
 | 
				
			||||||
  bool supports_color_temperature{false};  // NOLINT
 | 
					  bool supports_color_temperature{false};
 | 
				
			||||||
  float min_mireds{0.0f};                  // NOLINT
 | 
					  float min_mireds{0.0f};
 | 
				
			||||||
  float max_mireds{0.0f};                  // NOLINT
 | 
					  float max_mireds{0.0f};
 | 
				
			||||||
  std::vector<std::string> effects{};      // NOLINT
 | 
					  std::vector<std::string> effects{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -351,15 +368,16 @@ class ListEntitiesLightResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class LightStateResponse : public ProtoMessage {
 | 
					class LightStateResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t key{0};                // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  bool state{false};              // NOLINT
 | 
					  bool state{false};
 | 
				
			||||||
  float brightness{0.0f};         // NOLINT
 | 
					  float brightness{0.0f};
 | 
				
			||||||
  float red{0.0f};                // NOLINT
 | 
					  float color_brightness{0.0f};
 | 
				
			||||||
  float green{0.0f};              // NOLINT
 | 
					  float red{0.0f};
 | 
				
			||||||
  float blue{0.0f};               // NOLINT
 | 
					  float green{0.0f};
 | 
				
			||||||
  float white{0.0f};              // NOLINT
 | 
					  float blue{0.0f};
 | 
				
			||||||
  float color_temperature{0.0f};  // NOLINT
 | 
					  float white{0.0f};
 | 
				
			||||||
  std::string effect{};           // NOLINT
 | 
					  float color_temperature{0.0f};
 | 
				
			||||||
 | 
					  std::string effect{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -370,25 +388,27 @@ class LightStateResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class LightCommandRequest : public ProtoMessage {
 | 
					class LightCommandRequest : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t key{0};                    // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  bool has_state{false};              // NOLINT
 | 
					  bool has_state{false};
 | 
				
			||||||
  bool state{false};                  // NOLINT
 | 
					  bool state{false};
 | 
				
			||||||
  bool has_brightness{false};         // NOLINT
 | 
					  bool has_brightness{false};
 | 
				
			||||||
  float brightness{0.0f};             // NOLINT
 | 
					  float brightness{0.0f};
 | 
				
			||||||
  bool has_rgb{false};                // NOLINT
 | 
					  bool has_color_brightness{false};
 | 
				
			||||||
  float red{0.0f};                    // NOLINT
 | 
					  float color_brightness{0.0f};
 | 
				
			||||||
  float green{0.0f};                  // NOLINT
 | 
					  bool has_rgb{false};
 | 
				
			||||||
  float blue{0.0f};                   // NOLINT
 | 
					  float red{0.0f};
 | 
				
			||||||
  bool has_white{false};              // NOLINT
 | 
					  float green{0.0f};
 | 
				
			||||||
  float white{0.0f};                  // NOLINT
 | 
					  float blue{0.0f};
 | 
				
			||||||
  bool has_color_temperature{false};  // NOLINT
 | 
					  bool has_white{false};
 | 
				
			||||||
  float color_temperature{0.0f};      // NOLINT
 | 
					  float white{0.0f};
 | 
				
			||||||
  bool has_transition_length{false};  // NOLINT
 | 
					  bool has_color_temperature{false};
 | 
				
			||||||
  uint32_t transition_length{0};      // NOLINT
 | 
					  float color_temperature{0.0f};
 | 
				
			||||||
  bool has_flash_length{false};       // NOLINT
 | 
					  bool has_transition_length{false};
 | 
				
			||||||
  uint32_t flash_length{0};           // NOLINT
 | 
					  uint32_t transition_length{0};
 | 
				
			||||||
  bool has_effect{false};             // NOLINT
 | 
					  bool has_flash_length{false};
 | 
				
			||||||
  std::string effect{};               // NOLINT
 | 
					  uint32_t flash_length{0};
 | 
				
			||||||
 | 
					  bool has_effect{false};
 | 
				
			||||||
 | 
					  std::string effect{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -399,15 +419,16 @@ class LightCommandRequest : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class ListEntitiesSensorResponse : public ProtoMessage {
 | 
					class ListEntitiesSensorResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string object_id{};            // NOLINT
 | 
					  std::string object_id{};
 | 
				
			||||||
  uint32_t key{0};                    // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  std::string name{};                 // NOLINT
 | 
					  std::string name{};
 | 
				
			||||||
  std::string unique_id{};            // NOLINT
 | 
					  std::string unique_id{};
 | 
				
			||||||
  std::string icon{};                 // NOLINT
 | 
					  std::string icon{};
 | 
				
			||||||
  std::string unit_of_measurement{};  // NOLINT
 | 
					  std::string unit_of_measurement{};
 | 
				
			||||||
  int32_t accuracy_decimals{0};       // NOLINT
 | 
					  int32_t accuracy_decimals{0};
 | 
				
			||||||
  bool force_update{false};           // NOLINT
 | 
					  bool force_update{false};
 | 
				
			||||||
  std::string device_class{};         // NOLINT
 | 
					  std::string device_class{};
 | 
				
			||||||
 | 
					  enums::SensorStateClass state_class{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -418,9 +439,9 @@ class ListEntitiesSensorResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class SensorStateResponse : public ProtoMessage {
 | 
					class SensorStateResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t key{0};            // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  float state{0.0f};          // NOLINT
 | 
					  float state{0.0f};
 | 
				
			||||||
  bool missing_state{false};  // NOLINT
 | 
					  bool missing_state{false};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -430,12 +451,12 @@ class SensorStateResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class ListEntitiesSwitchResponse : public ProtoMessage {
 | 
					class ListEntitiesSwitchResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string object_id{};    // NOLINT
 | 
					  std::string object_id{};
 | 
				
			||||||
  uint32_t key{0};            // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  std::string name{};         // NOLINT
 | 
					  std::string name{};
 | 
				
			||||||
  std::string unique_id{};    // NOLINT
 | 
					  std::string unique_id{};
 | 
				
			||||||
  std::string icon{};         // NOLINT
 | 
					  std::string icon{};
 | 
				
			||||||
  bool assumed_state{false};  // NOLINT
 | 
					  bool assumed_state{false};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -446,8 +467,8 @@ class ListEntitiesSwitchResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class SwitchStateResponse : public ProtoMessage {
 | 
					class SwitchStateResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t key{0};    // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  bool state{false};  // NOLINT
 | 
					  bool state{false};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -457,8 +478,8 @@ class SwitchStateResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class SwitchCommandRequest : public ProtoMessage {
 | 
					class SwitchCommandRequest : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t key{0};    // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  bool state{false};  // NOLINT
 | 
					  bool state{false};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -468,11 +489,11 @@ class SwitchCommandRequest : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class ListEntitiesTextSensorResponse : public ProtoMessage {
 | 
					class ListEntitiesTextSensorResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string object_id{};  // NOLINT
 | 
					  std::string object_id{};
 | 
				
			||||||
  uint32_t key{0};          // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  std::string name{};       // NOLINT
 | 
					  std::string name{};
 | 
				
			||||||
  std::string unique_id{};  // NOLINT
 | 
					  std::string unique_id{};
 | 
				
			||||||
  std::string icon{};       // NOLINT
 | 
					  std::string icon{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -482,9 +503,9 @@ class ListEntitiesTextSensorResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class TextSensorStateResponse : public ProtoMessage {
 | 
					class TextSensorStateResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t key{0};            // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  std::string state{};        // NOLINT
 | 
					  std::string state{};
 | 
				
			||||||
  bool missing_state{false};  // NOLINT
 | 
					  bool missing_state{false};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -495,8 +516,8 @@ class TextSensorStateResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class SubscribeLogsRequest : public ProtoMessage {
 | 
					class SubscribeLogsRequest : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  enums::LogLevel level{};  // NOLINT
 | 
					  enums::LogLevel level{};
 | 
				
			||||||
  bool dump_config{false};  // NOLINT
 | 
					  bool dump_config{false};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -505,10 +526,10 @@ class SubscribeLogsRequest : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class SubscribeLogsResponse : public ProtoMessage {
 | 
					class SubscribeLogsResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  enums::LogLevel level{};  // NOLINT
 | 
					  enums::LogLevel level{};
 | 
				
			||||||
  std::string tag{};        // NOLINT
 | 
					  std::string tag{};
 | 
				
			||||||
  std::string message{};    // NOLINT
 | 
					  std::string message{};
 | 
				
			||||||
  bool send_failed{false};  // NOLINT
 | 
					  bool send_failed{false};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -525,8 +546,8 @@ class SubscribeHomeassistantServicesRequest : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class HomeassistantServiceMap : public ProtoMessage {
 | 
					class HomeassistantServiceMap : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string key{};    // NOLINT
 | 
					  std::string key{};
 | 
				
			||||||
  std::string value{};  // NOLINT
 | 
					  std::string value{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -535,11 +556,11 @@ class HomeassistantServiceMap : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class HomeassistantServiceResponse : public ProtoMessage {
 | 
					class HomeassistantServiceResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string service{};                                 // NOLINT
 | 
					  std::string service{};
 | 
				
			||||||
  std::vector<HomeassistantServiceMap> data{};           // NOLINT
 | 
					  std::vector<HomeassistantServiceMap> data{};
 | 
				
			||||||
  std::vector<HomeassistantServiceMap> data_template{};  // NOLINT
 | 
					  std::vector<HomeassistantServiceMap> data_template{};
 | 
				
			||||||
  std::vector<HomeassistantServiceMap> variables{};      // NOLINT
 | 
					  std::vector<HomeassistantServiceMap> variables{};
 | 
				
			||||||
  bool is_event{false};                                  // NOLINT
 | 
					  bool is_event{false};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -556,7 +577,8 @@ class SubscribeHomeAssistantStatesRequest : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class SubscribeHomeAssistantStateResponse : public ProtoMessage {
 | 
					class SubscribeHomeAssistantStateResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string entity_id{};  // NOLINT
 | 
					  std::string entity_id{};
 | 
				
			||||||
 | 
					  std::string attribute{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -565,8 +587,9 @@ class SubscribeHomeAssistantStateResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class HomeAssistantStateResponse : public ProtoMessage {
 | 
					class HomeAssistantStateResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string entity_id{};  // NOLINT
 | 
					  std::string entity_id{};
 | 
				
			||||||
  std::string state{};      // NOLINT
 | 
					  std::string state{};
 | 
				
			||||||
 | 
					  std::string attribute{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -582,7 +605,7 @@ class GetTimeRequest : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class GetTimeResponse : public ProtoMessage {
 | 
					class GetTimeResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t epoch_seconds{0};  // NOLINT
 | 
					  uint32_t epoch_seconds{0};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -591,8 +614,8 @@ class GetTimeResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class ListEntitiesServicesArgument : public ProtoMessage {
 | 
					class ListEntitiesServicesArgument : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string name{};            // NOLINT
 | 
					  std::string name{};
 | 
				
			||||||
  enums::ServiceArgType type{};  // NOLINT
 | 
					  enums::ServiceArgType type{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -602,9 +625,9 @@ class ListEntitiesServicesArgument : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class ListEntitiesServicesResponse : public ProtoMessage {
 | 
					class ListEntitiesServicesResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string name{};                                // NOLINT
 | 
					  std::string name{};
 | 
				
			||||||
  uint32_t key{0};                                   // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  std::vector<ListEntitiesServicesArgument> args{};  // NOLINT
 | 
					  std::vector<ListEntitiesServicesArgument> args{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -614,15 +637,15 @@ class ListEntitiesServicesResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class ExecuteServiceArgument : public ProtoMessage {
 | 
					class ExecuteServiceArgument : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  bool bool_{false};                        // NOLINT
 | 
					  bool bool_{false};
 | 
				
			||||||
  int32_t legacy_int{0};                    // NOLINT
 | 
					  int32_t legacy_int{0};
 | 
				
			||||||
  float float_{0.0f};                       // NOLINT
 | 
					  float float_{0.0f};
 | 
				
			||||||
  std::string string_{};                    // NOLINT
 | 
					  std::string string_{};
 | 
				
			||||||
  int32_t int_{0};                          // NOLINT
 | 
					  int32_t int_{0};
 | 
				
			||||||
  std::vector<bool> bool_array{};           // NOLINT
 | 
					  std::vector<bool> bool_array{};
 | 
				
			||||||
  std::vector<int32_t> int_array{};         // NOLINT
 | 
					  std::vector<int32_t> int_array{};
 | 
				
			||||||
  std::vector<float> float_array{};         // NOLINT
 | 
					  std::vector<float> float_array{};
 | 
				
			||||||
  std::vector<std::string> string_array{};  // NOLINT
 | 
					  std::vector<std::string> string_array{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -633,8 +656,8 @@ class ExecuteServiceArgument : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class ExecuteServiceRequest : public ProtoMessage {
 | 
					class ExecuteServiceRequest : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t key{0};                             // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  std::vector<ExecuteServiceArgument> args{};  // NOLINT
 | 
					  std::vector<ExecuteServiceArgument> args{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -644,10 +667,10 @@ class ExecuteServiceRequest : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class ListEntitiesCameraResponse : public ProtoMessage {
 | 
					class ListEntitiesCameraResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string object_id{};  // NOLINT
 | 
					  std::string object_id{};
 | 
				
			||||||
  uint32_t key{0};          // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  std::string name{};       // NOLINT
 | 
					  std::string name{};
 | 
				
			||||||
  std::string unique_id{};  // NOLINT
 | 
					  std::string unique_id{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -657,9 +680,9 @@ class ListEntitiesCameraResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class CameraImageResponse : public ProtoMessage {
 | 
					class CameraImageResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t key{0};     // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  std::string data{};  // NOLINT
 | 
					  std::string data{};
 | 
				
			||||||
  bool done{false};    // NOLINT
 | 
					  bool done{false};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -670,8 +693,8 @@ class CameraImageResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class CameraImageRequest : public ProtoMessage {
 | 
					class CameraImageRequest : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  bool single{false};  // NOLINT
 | 
					  bool single{false};
 | 
				
			||||||
  bool stream{false};  // NOLINT
 | 
					  bool stream{false};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -680,20 +703,23 @@ class CameraImageRequest : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class ListEntitiesClimateResponse : public ProtoMessage {
 | 
					class ListEntitiesClimateResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  std::string object_id{};                                       // NOLINT
 | 
					  std::string object_id{};
 | 
				
			||||||
  uint32_t key{0};                                               // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  std::string name{};                                            // NOLINT
 | 
					  std::string name{};
 | 
				
			||||||
  std::string unique_id{};                                       // NOLINT
 | 
					  std::string unique_id{};
 | 
				
			||||||
  bool supports_current_temperature{false};                      // NOLINT
 | 
					  bool supports_current_temperature{false};
 | 
				
			||||||
  bool supports_two_point_target_temperature{false};             // NOLINT
 | 
					  bool supports_two_point_target_temperature{false};
 | 
				
			||||||
  std::vector<enums::ClimateMode> supported_modes{};             // NOLINT
 | 
					  std::vector<enums::ClimateMode> supported_modes{};
 | 
				
			||||||
  float visual_min_temperature{0.0f};                            // NOLINT
 | 
					  float visual_min_temperature{0.0f};
 | 
				
			||||||
  float visual_max_temperature{0.0f};                            // NOLINT
 | 
					  float visual_max_temperature{0.0f};
 | 
				
			||||||
  float visual_temperature_step{0.0f};                           // NOLINT
 | 
					  float visual_temperature_step{0.0f};
 | 
				
			||||||
  bool supports_away{false};                                     // NOLINT
 | 
					  bool legacy_supports_away{false};
 | 
				
			||||||
  bool supports_action{false};                                   // NOLINT
 | 
					  bool supports_action{false};
 | 
				
			||||||
  std::vector<enums::ClimateFanMode> supported_fan_modes{};      // NOLINT
 | 
					  std::vector<enums::ClimateFanMode> supported_fan_modes{};
 | 
				
			||||||
  std::vector<enums::ClimateSwingMode> supported_swing_modes{};  // NOLINT
 | 
					  std::vector<enums::ClimateSwingMode> supported_swing_modes{};
 | 
				
			||||||
 | 
					  std::vector<std::string> supported_custom_fan_modes{};
 | 
				
			||||||
 | 
					  std::vector<enums::ClimatePreset> supported_presets{};
 | 
				
			||||||
 | 
					  std::vector<std::string> supported_custom_presets{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -704,40 +730,80 @@ class ListEntitiesClimateResponse : public ProtoMessage {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
class ClimateStateResponse : public ProtoMessage {
 | 
					class ClimateStateResponse : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t key{0};                       // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  enums::ClimateMode mode{};             // NOLINT
 | 
					  enums::ClimateMode mode{};
 | 
				
			||||||
  float current_temperature{0.0f};       // NOLINT
 | 
					  float current_temperature{0.0f};
 | 
				
			||||||
  float target_temperature{0.0f};        // NOLINT
 | 
					  float target_temperature{0.0f};
 | 
				
			||||||
  float target_temperature_low{0.0f};    // NOLINT
 | 
					  float target_temperature_low{0.0f};
 | 
				
			||||||
  float target_temperature_high{0.0f};   // NOLINT
 | 
					  float target_temperature_high{0.0f};
 | 
				
			||||||
  bool away{false};                      // NOLINT
 | 
					  bool legacy_away{false};
 | 
				
			||||||
  enums::ClimateAction action{};         // NOLINT
 | 
					  enums::ClimateAction action{};
 | 
				
			||||||
  enums::ClimateFanMode fan_mode{};      // NOLINT
 | 
					  enums::ClimateFanMode fan_mode{};
 | 
				
			||||||
  enums::ClimateSwingMode swing_mode{};  // NOLINT
 | 
					  enums::ClimateSwingMode swing_mode{};
 | 
				
			||||||
 | 
					  std::string custom_fan_mode{};
 | 
				
			||||||
 | 
					  enums::ClimatePreset preset{};
 | 
				
			||||||
 | 
					  std::string custom_preset{};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
  bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
 | 
					  bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
 | 
				
			||||||
 | 
					  bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
 | 
				
			||||||
  bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
 | 
					  bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
class ClimateCommandRequest : public ProtoMessage {
 | 
					class ClimateCommandRequest : public ProtoMessage {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  uint32_t key{0};                          // NOLINT
 | 
					  uint32_t key{0};
 | 
				
			||||||
  bool has_mode{false};                     // NOLINT
 | 
					  bool has_mode{false};
 | 
				
			||||||
  enums::ClimateMode mode{};                // NOLINT
 | 
					  enums::ClimateMode mode{};
 | 
				
			||||||
  bool has_target_temperature{false};       // NOLINT
 | 
					  bool has_target_temperature{false};
 | 
				
			||||||
  float target_temperature{0.0f};           // NOLINT
 | 
					  float target_temperature{0.0f};
 | 
				
			||||||
  bool has_target_temperature_low{false};   // NOLINT
 | 
					  bool has_target_temperature_low{false};
 | 
				
			||||||
  float target_temperature_low{0.0f};       // NOLINT
 | 
					  float target_temperature_low{0.0f};
 | 
				
			||||||
  bool has_target_temperature_high{false};  // NOLINT
 | 
					  bool has_target_temperature_high{false};
 | 
				
			||||||
  float target_temperature_high{0.0f};      // NOLINT
 | 
					  float target_temperature_high{0.0f};
 | 
				
			||||||
  bool has_away{false};                     // NOLINT
 | 
					  bool has_legacy_away{false};
 | 
				
			||||||
  bool away{false};                         // NOLINT
 | 
					  bool legacy_away{false};
 | 
				
			||||||
  bool has_fan_mode{false};                 // NOLINT
 | 
					  bool has_fan_mode{false};
 | 
				
			||||||
  enums::ClimateFanMode fan_mode{};         // NOLINT
 | 
					  enums::ClimateFanMode fan_mode{};
 | 
				
			||||||
  bool has_swing_mode{false};               // NOLINT
 | 
					  bool has_swing_mode{false};
 | 
				
			||||||
  enums::ClimateSwingMode swing_mode{};     // NOLINT
 | 
					  enums::ClimateSwingMode swing_mode{};
 | 
				
			||||||
 | 
					  bool has_custom_fan_mode{false};
 | 
				
			||||||
 | 
					  std::string custom_fan_mode{};
 | 
				
			||||||
 | 
					  bool has_preset{false};
 | 
				
			||||||
 | 
					  enums::ClimatePreset preset{};
 | 
				
			||||||
 | 
					  bool has_custom_preset{false};
 | 
				
			||||||
 | 
					  std::string custom_preset{};
 | 
				
			||||||
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 protected:
 | 
				
			||||||
 | 
					  bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
 | 
				
			||||||
 | 
					  bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
 | 
				
			||||||
 | 
					  bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					class ListEntitiesNumberResponse : public ProtoMessage {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  std::string object_id{};
 | 
				
			||||||
 | 
					  uint32_t key{0};
 | 
				
			||||||
 | 
					  std::string name{};
 | 
				
			||||||
 | 
					  std::string unique_id{};
 | 
				
			||||||
 | 
					  std::string icon{};
 | 
				
			||||||
 | 
					  float min_value{0.0f};
 | 
				
			||||||
 | 
					  float max_value{0.0f};
 | 
				
			||||||
 | 
					  float step{0.0f};
 | 
				
			||||||
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 protected:
 | 
				
			||||||
 | 
					  bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
 | 
				
			||||||
 | 
					  bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					class NumberStateResponse : public ProtoMessage {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  uint32_t key{0};
 | 
				
			||||||
 | 
					  float state{0.0f};
 | 
				
			||||||
 | 
					  bool missing_state{false};
 | 
				
			||||||
  void encode(ProtoWriteBuffer buffer) const override;
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
  void dump_to(std::string &out) const override;
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -745,6 +811,16 @@ class ClimateCommandRequest : public ProtoMessage {
 | 
				
			|||||||
  bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
 | 
					  bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
 | 
				
			||||||
  bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
 | 
					  bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					class NumberCommandRequest : public ProtoMessage {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  uint32_t key{0};
 | 
				
			||||||
 | 
					  float state{0.0f};
 | 
				
			||||||
 | 
					  void encode(ProtoWriteBuffer buffer) const override;
 | 
				
			||||||
 | 
					  void dump_to(std::string &out) const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 protected:
 | 
				
			||||||
 | 
					  bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace api
 | 
					}  // namespace api
 | 
				
			||||||
}  // namespace esphome
 | 
					}  // namespace esphome
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace api {
 | 
					namespace api {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "api.service";
 | 
					static const char *const TAG = "api.service";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool APIServerConnectionBase::send_hello_response(const HelloResponse &msg) {
 | 
					bool APIServerConnectionBase::send_hello_response(const HelloResponse &msg) {
 | 
				
			||||||
  ESP_LOGVV(TAG, "send_hello_response: %s", msg.dump().c_str());
 | 
					  ESP_LOGVV(TAG, "send_hello_response: %s", msg.dump().c_str());
 | 
				
			||||||
@@ -184,6 +184,20 @@ bool APIServerConnectionBase::send_climate_state_response(const ClimateStateResp
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef USE_CLIMATE
 | 
					#ifdef USE_CLIMATE
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					bool APIServerConnectionBase::send_list_entities_number_response(const ListEntitiesNumberResponse &msg) {
 | 
				
			||||||
 | 
					  ESP_LOGVV(TAG, "send_list_entities_number_response: %s", msg.dump().c_str());
 | 
				
			||||||
 | 
					  return this->send_message_<ListEntitiesNumberResponse>(msg, 49);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					bool APIServerConnectionBase::send_number_state_response(const NumberStateResponse &msg) {
 | 
				
			||||||
 | 
					  ESP_LOGVV(TAG, "send_number_state_response: %s", msg.dump().c_str());
 | 
				
			||||||
 | 
					  return this->send_message_<NumberStateResponse>(msg, 50);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) {
 | 
					bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) {
 | 
				
			||||||
  switch (msg_type) {
 | 
					  switch (msg_type) {
 | 
				
			||||||
    case 1: {
 | 
					    case 1: {
 | 
				
			||||||
@@ -349,6 +363,15 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
 | 
				
			|||||||
      msg.decode(msg_data, msg_size);
 | 
					      msg.decode(msg_data, msg_size);
 | 
				
			||||||
      ESP_LOGVV(TAG, "on_climate_command_request: %s", msg.dump().c_str());
 | 
					      ESP_LOGVV(TAG, "on_climate_command_request: %s", msg.dump().c_str());
 | 
				
			||||||
      this->on_climate_command_request(msg);
 | 
					      this->on_climate_command_request(msg);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    case 51: {
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					      NumberCommandRequest msg;
 | 
				
			||||||
 | 
					      msg.decode(msg_data, msg_size);
 | 
				
			||||||
 | 
					      ESP_LOGVV(TAG, "on_number_command_request: %s", msg.dump().c_str());
 | 
				
			||||||
 | 
					      this->on_number_command_request(msg);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -547,6 +570,19 @@ void APIServerConnection::on_climate_command_request(const ClimateCommandRequest
 | 
				
			|||||||
  this->climate_command(msg);
 | 
					  this->climate_command(msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					void APIServerConnection::on_number_command_request(const NumberCommandRequest &msg) {
 | 
				
			||||||
 | 
					  if (!this->is_connection_setup()) {
 | 
				
			||||||
 | 
					    this->on_no_setup_connection();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (!this->is_authenticated()) {
 | 
				
			||||||
 | 
					    this->on_unauthenticated_access();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  this->number_command(msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace api
 | 
					}  // namespace api
 | 
				
			||||||
}  // namespace esphome
 | 
					}  // namespace esphome
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -111,6 +111,15 @@ class APIServerConnectionBase : public ProtoService {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef USE_CLIMATE
 | 
					#ifdef USE_CLIMATE
 | 
				
			||||||
  virtual void on_climate_command_request(const ClimateCommandRequest &value){};
 | 
					  virtual void on_climate_command_request(const ClimateCommandRequest &value){};
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					  bool send_list_entities_number_response(const ListEntitiesNumberResponse &msg);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					  bool send_number_state_response(const NumberStateResponse &msg);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					  virtual void on_number_command_request(const NumberCommandRequest &value){};
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
  bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;
 | 
					  bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;
 | 
				
			||||||
@@ -147,6 +156,9 @@ class APIServerConnection : public APIServerConnectionBase {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef USE_CLIMATE
 | 
					#ifdef USE_CLIMATE
 | 
				
			||||||
  virtual void climate_command(const ClimateCommandRequest &msg) = 0;
 | 
					  virtual void climate_command(const ClimateCommandRequest &msg) = 0;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					  virtual void number_command(const NumberCommandRequest &msg) = 0;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
  void on_hello_request(const HelloRequest &msg) override;
 | 
					  void on_hello_request(const HelloRequest &msg) override;
 | 
				
			||||||
@@ -179,6 +191,9 @@ class APIServerConnection : public APIServerConnectionBase {
 | 
				
			|||||||
#ifdef USE_CLIMATE
 | 
					#ifdef USE_CLIMATE
 | 
				
			||||||
  void on_climate_command_request(const ClimateCommandRequest &msg) override;
 | 
					  void on_climate_command_request(const ClimateCommandRequest &msg) override;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					  void on_number_command_request(const NumberCommandRequest &msg) override;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace api
 | 
					}  // namespace api
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace api {
 | 
					namespace api {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "api";
 | 
					static const char *const TAG = "api";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// APIServer
 | 
					// APIServer
 | 
				
			||||||
void APIServer::setup() {
 | 
					void APIServer::setup() {
 | 
				
			||||||
@@ -180,7 +180,7 @@ void APIServer::on_switch_update(switch_::Switch *obj, bool state) {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_TEXT_SENSOR
 | 
					#ifdef USE_TEXT_SENSOR
 | 
				
			||||||
void APIServer::on_text_sensor_update(text_sensor::TextSensor *obj, std::string state) {
 | 
					void APIServer::on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state) {
 | 
				
			||||||
  if (obj->is_internal())
 | 
					  if (obj->is_internal())
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  for (auto *c : this->clients_)
 | 
					  for (auto *c : this->clients_)
 | 
				
			||||||
@@ -197,9 +197,18 @@ void APIServer::on_climate_update(climate::Climate *obj) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					void APIServer::on_number_update(number::Number *obj, float state) {
 | 
				
			||||||
 | 
					  if (obj->is_internal())
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  for (auto *c : this->clients_)
 | 
				
			||||||
 | 
					    c->send_number_state(obj, state);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
 | 
					float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
 | 
				
			||||||
void APIServer::set_port(uint16_t port) { this->port_ = port; }
 | 
					void APIServer::set_port(uint16_t port) { this->port_ = port; }
 | 
				
			||||||
APIServer *global_api_server = nullptr;
 | 
					APIServer *global_api_server = nullptr;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void APIServer::set_password(const std::string &password) { this->password_ = password; }
 | 
					void APIServer::set_password(const std::string &password) { this->password_ = password; }
 | 
				
			||||||
void APIServer::send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
 | 
					void APIServer::send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
 | 
				
			||||||
@@ -208,9 +217,11 @@ void APIServer::send_homeassistant_service_call(const HomeassistantServiceRespon
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
APIServer::APIServer() { global_api_server = this; }
 | 
					APIServer::APIServer() { global_api_server = this; }
 | 
				
			||||||
void APIServer::subscribe_home_assistant_state(std::string entity_id, std::function<void(std::string)> f) {
 | 
					void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
 | 
				
			||||||
 | 
					                                               std::function<void(std::string)> f) {
 | 
				
			||||||
  this->state_subs_.push_back(HomeAssistantStateSubscription{
 | 
					  this->state_subs_.push_back(HomeAssistantStateSubscription{
 | 
				
			||||||
      .entity_id = std::move(entity_id),
 | 
					      .entity_id = std::move(entity_id),
 | 
				
			||||||
 | 
					      .attribute = std::move(attribute),
 | 
				
			||||||
      .callback = std::move(f),
 | 
					      .callback = std::move(f),
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,10 +56,13 @@ class APIServer : public Component, public Controller {
 | 
				
			|||||||
  void on_switch_update(switch_::Switch *obj, bool state) override;
 | 
					  void on_switch_update(switch_::Switch *obj, bool state) override;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef USE_TEXT_SENSOR
 | 
					#ifdef USE_TEXT_SENSOR
 | 
				
			||||||
  void on_text_sensor_update(text_sensor::TextSensor *obj, std::string state) override;
 | 
					  void on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state) override;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef USE_CLIMATE
 | 
					#ifdef USE_CLIMATE
 | 
				
			||||||
  void on_climate_update(climate::Climate *obj) override;
 | 
					  void on_climate_update(climate::Climate *obj) override;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					  void on_number_update(number::Number *obj, float state) override;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  void send_homeassistant_service_call(const HomeassistantServiceResponse &call);
 | 
					  void send_homeassistant_service_call(const HomeassistantServiceResponse &call);
 | 
				
			||||||
  void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); }
 | 
					  void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); }
 | 
				
			||||||
@@ -71,10 +74,12 @@ class APIServer : public Component, public Controller {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  struct HomeAssistantStateSubscription {
 | 
					  struct HomeAssistantStateSubscription {
 | 
				
			||||||
    std::string entity_id;
 | 
					    std::string entity_id;
 | 
				
			||||||
 | 
					    optional<std::string> attribute;
 | 
				
			||||||
    std::function<void(std::string)> callback;
 | 
					    std::function<void(std::string)> callback;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void subscribe_home_assistant_state(std::string entity_id, std::function<void(std::string)> f);
 | 
					  void subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
 | 
				
			||||||
 | 
					                                      std::function<void(std::string)> f);
 | 
				
			||||||
  const std::vector<HomeAssistantStateSubscription> &get_state_subs() const;
 | 
					  const std::vector<HomeAssistantStateSubscription> &get_state_subs() const;
 | 
				
			||||||
  const std::vector<UserServiceDescriptor *> &get_user_services() const { return this->user_services_; }
 | 
					  const std::vector<UserServiceDescriptor *> &get_user_services() const { return this->user_services_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -89,7 +94,7 @@ class APIServer : public Component, public Controller {
 | 
				
			|||||||
  std::vector<UserServiceDescriptor *> user_services_;
 | 
					  std::vector<UserServiceDescriptor *> user_services_;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern APIServer *global_api_server;
 | 
					extern APIServer *global_api_server;  // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename... Ts> class APIConnectedCondition : public Condition<Ts...> {
 | 
					template<typename... Ts> class APIConnectedCondition : public Condition<Ts...> {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -76,13 +76,13 @@ class CustomAPIDevice {
 | 
				
			|||||||
    global_api_server->register_user_service(service);
 | 
					    global_api_server->register_user_service(service);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Subscribe to the state of an entity from Home Assistant.
 | 
					  /** Subscribe to the state (or attribute state) of an entity from Home Assistant.
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
   * Usage:
 | 
					   * Usage:
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
   * ```cpp
 | 
					   * ```cpp
 | 
				
			||||||
   * void setup() override {
 | 
					   * void setup() override {
 | 
				
			||||||
   *   subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "sensor.weather_forecast");
 | 
					   *   subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "climate.kitchen", "current_temperature");
 | 
				
			||||||
   * }
 | 
					   * }
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
   * void on_state_changed(std::string state) {
 | 
					   * void on_state_changed(std::string state) {
 | 
				
			||||||
@@ -93,17 +93,19 @@ class CustomAPIDevice {
 | 
				
			|||||||
   * @tparam T The class type creating the service, automatically deduced from the function pointer.
 | 
					   * @tparam T The class type creating the service, automatically deduced from the function pointer.
 | 
				
			||||||
   * @param callback The member function to call when the entity state changes.
 | 
					   * @param callback The member function to call when the entity state changes.
 | 
				
			||||||
   * @param entity_id The entity_id to track.
 | 
					   * @param entity_id The entity_id to track.
 | 
				
			||||||
 | 
					   * @param attribute The entity state attribute to track.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  template<typename T>
 | 
					  template<typename T>
 | 
				
			||||||
  void subscribe_homeassistant_state(void (T::*callback)(std::string), const std::string &entity_id) {
 | 
					  void subscribe_homeassistant_state(void (T::*callback)(std::string), const std::string &entity_id,
 | 
				
			||||||
 | 
					                                     const std::string &attribute = "") {
 | 
				
			||||||
    auto f = std::bind(callback, (T *) this, std::placeholders::_1);
 | 
					    auto f = std::bind(callback, (T *) this, std::placeholders::_1);
 | 
				
			||||||
    global_api_server->subscribe_home_assistant_state(entity_id, f);
 | 
					    global_api_server->subscribe_home_assistant_state(entity_id, optional<std::string>(attribute), f);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Subscribe to the state of an entity from Home Assistant.
 | 
					  /** Subscribe to the state (or attribute state) of an entity from Home Assistant.
 | 
				
			||||||
   *
 | 
					   *
 | 
				
			||||||
   * Usage:
 | 
					   * Usage:
 | 
				
			||||||
   *
 | 
					   *å
 | 
				
			||||||
   * ```cpp
 | 
					   * ```cpp
 | 
				
			||||||
   * void setup() override {
 | 
					   * void setup() override {
 | 
				
			||||||
   *   subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "sensor.weather_forecast");
 | 
					   *   subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "sensor.weather_forecast");
 | 
				
			||||||
@@ -117,11 +119,13 @@ class CustomAPIDevice {
 | 
				
			|||||||
   * @tparam T The class type creating the service, automatically deduced from the function pointer.
 | 
					   * @tparam T The class type creating the service, automatically deduced from the function pointer.
 | 
				
			||||||
   * @param callback The member function to call when the entity state changes.
 | 
					   * @param callback The member function to call when the entity state changes.
 | 
				
			||||||
   * @param entity_id The entity_id to track.
 | 
					   * @param entity_id The entity_id to track.
 | 
				
			||||||
 | 
					   * @param attribute The entity state attribute to track.
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  template<typename T>
 | 
					  template<typename T>
 | 
				
			||||||
  void subscribe_homeassistant_state(void (T::*callback)(std::string, std::string), const std::string &entity_id) {
 | 
					  void subscribe_homeassistant_state(void (T::*callback)(std::string, std::string), const std::string &entity_id,
 | 
				
			||||||
 | 
					                                     const std::string &attribute = "") {
 | 
				
			||||||
    auto f = std::bind(callback, (T *) this, entity_id, std::placeholders::_1);
 | 
					    auto f = std::bind(callback, (T *) this, entity_id, std::placeholders::_1);
 | 
				
			||||||
    global_api_server->subscribe_home_assistant_state(entity_id, f);
 | 
					    global_api_server->subscribe_home_assistant_state(entity_id, optional<std::string>(attribute), f);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Call a Home Assistant service from ESPHome.
 | 
					  /** Call a Home Assistant service from ESPHome.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -51,5 +51,9 @@ bool ListEntitiesIterator::on_camera(esp32_camera::ESP32Camera *camera) {
 | 
				
			|||||||
bool ListEntitiesIterator::on_climate(climate::Climate *climate) { return this->client_->send_climate_info(climate); }
 | 
					bool ListEntitiesIterator::on_climate(climate::Climate *climate) { return this->client_->send_climate_info(climate); }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					bool ListEntitiesIterator::on_number(number::Number *number) { return this->client_->send_number_info(number); }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace api
 | 
					}  // namespace api
 | 
				
			||||||
}  // namespace esphome
 | 
					}  // namespace esphome
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,6 +39,9 @@ class ListEntitiesIterator : public ComponentIterator {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef USE_CLIMATE
 | 
					#ifdef USE_CLIMATE
 | 
				
			||||||
  bool on_climate(climate::Climate *climate) override;
 | 
					  bool on_climate(climate::Climate *climate) override;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					  bool on_number(number::Number *number) override;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  bool on_end() override;
 | 
					  bool on_end() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace api {
 | 
					namespace api {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "api.proto";
 | 
					static const char *const TAG = "api.proto";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProtoMessage::decode(const uint8_t *buffer, size_t length) {
 | 
					void ProtoMessage::decode(const uint8_t *buffer, size_t length) {
 | 
				
			||||||
  uint32_t i = 0;
 | 
					  uint32_t i = 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,6 +37,11 @@ bool InitialStateIterator::on_text_sensor(text_sensor::TextSensor *text_sensor)
 | 
				
			|||||||
#ifdef USE_CLIMATE
 | 
					#ifdef USE_CLIMATE
 | 
				
			||||||
bool InitialStateIterator::on_climate(climate::Climate *climate) { return this->client_->send_climate_state(climate); }
 | 
					bool InitialStateIterator::on_climate(climate::Climate *climate) { return this->client_->send_climate_state(climate); }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					bool InitialStateIterator::on_number(number::Number *number) {
 | 
				
			||||||
 | 
					  return this->client_->send_number_state(number, number->state);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
InitialStateIterator::InitialStateIterator(APIServer *server, APIConnection *client)
 | 
					InitialStateIterator::InitialStateIterator(APIServer *server, APIConnection *client)
 | 
				
			||||||
    : ComponentIterator(server), client_(client) {}
 | 
					    : ComponentIterator(server), client_(client) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,9 @@ class InitialStateIterator : public ComponentIterator {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef USE_CLIMATE
 | 
					#ifdef USE_CLIMATE
 | 
				
			||||||
  bool on_climate(climate::Climate *climate) override;
 | 
					  bool on_climate(climate::Climate *climate) override;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					  bool on_number(number::Number *number) override;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
  APIConnection *client_;
 | 
					  APIConnection *client_;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <utility>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "esphome/core/component.h"
 | 
					#include "esphome/core/component.h"
 | 
				
			||||||
#include "esphome/core/automation.h"
 | 
					#include "esphome/core/automation.h"
 | 
				
			||||||
#include "api_pb2.h"
 | 
					#include "api_pb2.h"
 | 
				
			||||||
@@ -20,8 +22,8 @@ template<typename T> enums::ServiceArgType to_service_arg_type();
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template<typename... Ts> class UserServiceBase : public UserServiceDescriptor {
 | 
					template<typename... Ts> class UserServiceBase : public UserServiceDescriptor {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  UserServiceBase(const std::string &name, const std::array<std::string, sizeof...(Ts)> &arg_names)
 | 
					  UserServiceBase(std::string name, const std::array<std::string, sizeof...(Ts)> &arg_names)
 | 
				
			||||||
      : name_(name), arg_names_(arg_names) {
 | 
					      : name_(std::move(name)), arg_names_(arg_names) {
 | 
				
			||||||
    this->key_ = fnv1_hash(this->name_);
 | 
					    this->key_ = fnv1_hash(this->name_);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -167,6 +167,21 @@ void ComponentIterator::advance() {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					    case IteratorState::NUMBER:
 | 
				
			||||||
 | 
					      if (this->at_ >= App.get_numbers().size()) {
 | 
				
			||||||
 | 
					        advance_platform = true;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        auto *number = App.get_numbers()[this->at_];
 | 
				
			||||||
 | 
					        if (number->is_internal()) {
 | 
				
			||||||
 | 
					          success = true;
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          success = this->on_number(number);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    case IteratorState::MAX:
 | 
					    case IteratorState::MAX:
 | 
				
			||||||
      if (this->on_end()) {
 | 
					      if (this->on_end()) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,6 +47,9 @@ class ComponentIterator {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef USE_CLIMATE
 | 
					#ifdef USE_CLIMATE
 | 
				
			||||||
  virtual bool on_climate(climate::Climate *climate) = 0;
 | 
					  virtual bool on_climate(climate::Climate *climate) = 0;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					  virtual bool on_number(number::Number *number) = 0;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
  virtual bool on_end();
 | 
					  virtual bool on_end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -81,6 +84,9 @@ class ComponentIterator {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef USE_CLIMATE
 | 
					#ifdef USE_CLIMATE
 | 
				
			||||||
    CLIMATE,
 | 
					    CLIMATE,
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef USE_NUMBER
 | 
				
			||||||
 | 
					    NUMBER,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    MAX,
 | 
					    MAX,
 | 
				
			||||||
  } state_{IteratorState::NONE};
 | 
					  } state_{IteratorState::NONE};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,6 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_DIV_RATIO,
 | 
					    CONF_DIV_RATIO,
 | 
				
			||||||
    CONF_CAPACITANCE,
 | 
					    CONF_CAPACITANCE,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
from esphome.core import coroutine
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
AUTO_LOAD = ["sensor", "binary_sensor"]
 | 
					AUTO_LOAD = ["sensor", "binary_sensor"]
 | 
				
			||||||
MULTI_CONF = True
 | 
					MULTI_CONF = True
 | 
				
			||||||
@@ -40,11 +39,10 @@ AS3935_SCHEMA = cv.Schema(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@coroutine
 | 
					async def setup_as3935(var, config):
 | 
				
			||||||
def setup_as3935(var, config):
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    irq_pin = yield cg.gpio_pin_expression(config[CONF_IRQ_PIN])
 | 
					    irq_pin = await cg.gpio_pin_expression(config[CONF_IRQ_PIN])
 | 
				
			||||||
    cg.add(var.set_irq_pin(irq_pin))
 | 
					    cg.add(var.set_irq_pin(irq_pin))
 | 
				
			||||||
    cg.add(var.set_indoor(config[CONF_INDOOR]))
 | 
					    cg.add(var.set_indoor(config[CONF_INDOOR]))
 | 
				
			||||||
    cg.add(var.set_noise_level(config[CONF_NOISE_LEVEL]))
 | 
					    cg.add(var.set_noise_level(config[CONF_NOISE_LEVEL]))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace as3935 {
 | 
					namespace as3935 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "as3935";
 | 
					static const char *const TAG = "as3935";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void AS3935Component::setup() {
 | 
					void AS3935Component::setup() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "Setting up AS3935...");
 | 
					  ESP_LOGCONFIG(TAG, "Setting up AS3935...");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@ CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    hub = yield cg.get_variable(config[CONF_AS3935_ID])
 | 
					    hub = await cg.get_variable(config[CONF_AS3935_ID])
 | 
				
			||||||
    var = yield binary_sensor.new_binary_sensor(config)
 | 
					    var = await binary_sensor.new_binary_sensor(config)
 | 
				
			||||||
    cg.add(hub.set_thunder_alert_binary_sensor(var))
 | 
					    cg.add(hub.set_thunder_alert_binary_sensor(var))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_DISTANCE,
 | 
					    CONF_DISTANCE,
 | 
				
			||||||
    CONF_LIGHTNING_ENERGY,
 | 
					    CONF_LIGHTNING_ENERGY,
 | 
				
			||||||
    DEVICE_CLASS_EMPTY,
 | 
					    DEVICE_CLASS_EMPTY,
 | 
				
			||||||
 | 
					    STATE_CLASS_NONE,
 | 
				
			||||||
    UNIT_KILOMETER,
 | 
					    UNIT_KILOMETER,
 | 
				
			||||||
    UNIT_EMPTY,
 | 
					    UNIT_EMPTY,
 | 
				
			||||||
    ICON_SIGNAL_DISTANCE_VARIANT,
 | 
					    ICON_SIGNAL_DISTANCE_VARIANT,
 | 
				
			||||||
@@ -18,24 +19,28 @@ CONFIG_SCHEMA = cv.Schema(
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        cv.GenerateID(CONF_AS3935_ID): cv.use_id(AS3935),
 | 
					        cv.GenerateID(CONF_AS3935_ID): cv.use_id(AS3935),
 | 
				
			||||||
        cv.Optional(CONF_DISTANCE): sensor.sensor_schema(
 | 
					        cv.Optional(CONF_DISTANCE): sensor.sensor_schema(
 | 
				
			||||||
            UNIT_KILOMETER, ICON_SIGNAL_DISTANCE_VARIANT, 1, DEVICE_CLASS_EMPTY
 | 
					            UNIT_KILOMETER,
 | 
				
			||||||
 | 
					            ICON_SIGNAL_DISTANCE_VARIANT,
 | 
				
			||||||
 | 
					            1,
 | 
				
			||||||
 | 
					            DEVICE_CLASS_EMPTY,
 | 
				
			||||||
 | 
					            STATE_CLASS_NONE,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        cv.Optional(CONF_LIGHTNING_ENERGY): sensor.sensor_schema(
 | 
					        cv.Optional(CONF_LIGHTNING_ENERGY): sensor.sensor_schema(
 | 
				
			||||||
            UNIT_EMPTY, ICON_FLASH, 1, DEVICE_CLASS_EMPTY
 | 
					            UNIT_EMPTY, ICON_FLASH, 1, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
).extend(cv.COMPONENT_SCHEMA)
 | 
					).extend(cv.COMPONENT_SCHEMA)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    hub = yield cg.get_variable(config[CONF_AS3935_ID])
 | 
					    hub = await cg.get_variable(config[CONF_AS3935_ID])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if CONF_DISTANCE in config:
 | 
					    if CONF_DISTANCE in config:
 | 
				
			||||||
        conf = config[CONF_DISTANCE]
 | 
					        conf = config[CONF_DISTANCE]
 | 
				
			||||||
        distance_sensor = yield sensor.new_sensor(conf)
 | 
					        distance_sensor = await sensor.new_sensor(conf)
 | 
				
			||||||
        cg.add(hub.set_distance_sensor(distance_sensor))
 | 
					        cg.add(hub.set_distance_sensor(distance_sensor))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if CONF_LIGHTNING_ENERGY in config:
 | 
					    if CONF_LIGHTNING_ENERGY in config:
 | 
				
			||||||
        conf = config[CONF_LIGHTNING_ENERGY]
 | 
					        conf = config[CONF_LIGHTNING_ENERGY]
 | 
				
			||||||
        lightning_energy_sensor = yield sensor.new_sensor(conf)
 | 
					        lightning_energy_sensor = await sensor.new_sensor(conf)
 | 
				
			||||||
        cg.add(hub.set_energy_sensor(lightning_energy_sensor))
 | 
					        cg.add(hub.set_energy_sensor(lightning_energy_sensor))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@ CONFIG_SCHEMA = cv.All(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    yield as3935.setup_as3935(var, config)
 | 
					    await as3935.setup_as3935(var, config)
 | 
				
			||||||
    yield i2c.register_i2c_device(var, config)
 | 
					    await i2c.register_i2c_device(var, config)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace as3935_i2c {
 | 
					namespace as3935_i2c {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "as3935_i2c";
 | 
					static const char *const TAG = "as3935_i2c";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void I2CAS3935Component::write_register(uint8_t reg, uint8_t mask, uint8_t bits, uint8_t start_pos) {
 | 
					void I2CAS3935Component::write_register(uint8_t reg, uint8_t mask, uint8_t bits, uint8_t start_pos) {
 | 
				
			||||||
  uint8_t write_reg;
 | 
					  uint8_t write_reg;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@ CONFIG_SCHEMA = cv.All(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    yield as3935.setup_as3935(var, config)
 | 
					    await as3935.setup_as3935(var, config)
 | 
				
			||||||
    yield spi.register_spi_device(var, config)
 | 
					    await spi.register_spi_device(var, config)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace as3935_spi {
 | 
					namespace as3935_spi {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "as3935_spi";
 | 
					static const char *const TAG = "as3935_spi";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SPIAS3935Component::setup() {
 | 
					void SPIAS3935Component::setup() {
 | 
				
			||||||
  ESP_LOGI(TAG, "SPIAS3935Component setup started!");
 | 
					  ESP_LOGI(TAG, "SPIAS3935Component setup started!");
 | 
				
			||||||
@@ -33,7 +33,7 @@ void SPIAS3935Component::write_register(uint8_t reg, uint8_t mask, uint8_t bits,
 | 
				
			|||||||
uint8_t SPIAS3935Component::read_register(uint8_t reg) {
 | 
					uint8_t SPIAS3935Component::read_register(uint8_t reg) {
 | 
				
			||||||
  uint8_t value = 0;
 | 
					  uint8_t value = 0;
 | 
				
			||||||
  this->enable();
 | 
					  this->enable();
 | 
				
			||||||
  this->write_byte(reg |= SPI_READ_M);
 | 
					  this->write_byte(reg | SPI_READ_M);
 | 
				
			||||||
  value = this->read_byte();
 | 
					  value = this->read_byte();
 | 
				
			||||||
  // According to datsheet, the chip select must be written HIGH, LOW, HIGH
 | 
					  // According to datsheet, the chip select must be written HIGH, LOW, HIGH
 | 
				
			||||||
  // to correctly end the READ command.
 | 
					  // to correctly end the READ command.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@ CODEOWNERS = ["@OttoWinter"]
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@coroutine_with_priority(200.0)
 | 
					@coroutine_with_priority(200.0)
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    if CORE.is_esp32:
 | 
					    if CORE.is_esp32:
 | 
				
			||||||
        # https://github.com/esphome/AsyncTCP/blob/master/library.json
 | 
					        # https://github.com/esphome/AsyncTCP/blob/master/library.json
 | 
				
			||||||
        cg.add_library("esphome/AsyncTCP-esphome", "1.2.2")
 | 
					        cg.add_library("esphome/AsyncTCP-esphome", "1.2.2")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace atc_mithermometer {
 | 
					namespace atc_mithermometer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "atc_mithermometer";
 | 
					static const char *const TAG = "atc_mithermometer";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ATCMiThermometer::dump_config() {
 | 
					void ATCMiThermometer::dump_config() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "ATC MiThermometer");
 | 
					  ESP_LOGCONFIG(TAG, "ATC MiThermometer");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,7 @@ from esphome.const import (
 | 
				
			|||||||
    DEVICE_CLASS_TEMPERATURE,
 | 
					    DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
    DEVICE_CLASS_VOLTAGE,
 | 
					    DEVICE_CLASS_VOLTAGE,
 | 
				
			||||||
    ICON_EMPTY,
 | 
					    ICON_EMPTY,
 | 
				
			||||||
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_CELSIUS,
 | 
					    UNIT_CELSIUS,
 | 
				
			||||||
    UNIT_PERCENT,
 | 
					    UNIT_PERCENT,
 | 
				
			||||||
    UNIT_VOLT,
 | 
					    UNIT_VOLT,
 | 
				
			||||||
@@ -33,16 +34,28 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
            cv.GenerateID(): cv.declare_id(ATCMiThermometer),
 | 
					            cv.GenerateID(): cv.declare_id(ATCMiThermometer),
 | 
				
			||||||
            cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
 | 
					            cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
 | 
				
			||||||
            cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE
 | 
					                UNIT_CELSIUS,
 | 
				
			||||||
 | 
					                ICON_EMPTY,
 | 
				
			||||||
 | 
					                1,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_HUMIDITY
 | 
					                UNIT_PERCENT,
 | 
				
			||||||
 | 
					                ICON_EMPTY,
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_HUMIDITY,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_PERCENT, ICON_EMPTY, 0, DEVICE_CLASS_BATTERY
 | 
					                UNIT_PERCENT,
 | 
				
			||||||
 | 
					                ICON_EMPTY,
 | 
				
			||||||
 | 
					                0,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_BATTERY,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE
 | 
					                UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@@ -51,22 +64,22 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    yield esp32_ble_tracker.register_ble_device(var, config)
 | 
					    await esp32_ble_tracker.register_ble_device(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
 | 
					    cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if CONF_TEMPERATURE in config:
 | 
					    if CONF_TEMPERATURE in config:
 | 
				
			||||||
        sens = yield sensor.new_sensor(config[CONF_TEMPERATURE])
 | 
					        sens = await sensor.new_sensor(config[CONF_TEMPERATURE])
 | 
				
			||||||
        cg.add(var.set_temperature(sens))
 | 
					        cg.add(var.set_temperature(sens))
 | 
				
			||||||
    if CONF_HUMIDITY in config:
 | 
					    if CONF_HUMIDITY in config:
 | 
				
			||||||
        sens = yield sensor.new_sensor(config[CONF_HUMIDITY])
 | 
					        sens = await sensor.new_sensor(config[CONF_HUMIDITY])
 | 
				
			||||||
        cg.add(var.set_humidity(sens))
 | 
					        cg.add(var.set_humidity(sens))
 | 
				
			||||||
    if CONF_BATTERY_LEVEL in config:
 | 
					    if CONF_BATTERY_LEVEL in config:
 | 
				
			||||||
        sens = yield sensor.new_sensor(config[CONF_BATTERY_LEVEL])
 | 
					        sens = await sensor.new_sensor(config[CONF_BATTERY_LEVEL])
 | 
				
			||||||
        cg.add(var.set_battery_level(sens))
 | 
					        cg.add(var.set_battery_level(sens))
 | 
				
			||||||
    if CONF_BATTERY_VOLTAGE in config:
 | 
					    if CONF_BATTERY_VOLTAGE in config:
 | 
				
			||||||
        sens = yield sensor.new_sensor(config[CONF_BATTERY_VOLTAGE])
 | 
					        sens = await sensor.new_sensor(config[CONF_BATTERY_VOLTAGE])
 | 
				
			||||||
        cg.add(var.set_battery_voltage(sens))
 | 
					        cg.add(var.set_battery_voltage(sens))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace atm90e32 {
 | 
					namespace atm90e32 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "atm90e32";
 | 
					static const char *const TAG = "atm90e32";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ATM90E32Component::update() {
 | 
					void ATM90E32Component::update() {
 | 
				
			||||||
  if (this->read16_(ATM90E32_REGISTER_METEREN) != 1) {
 | 
					  if (this->read16_(ATM90E32_REGISTER_METEREN) != 1) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ import esphome.config_validation as cv
 | 
				
			|||||||
from esphome.components import sensor, spi
 | 
					from esphome.components import sensor, spi
 | 
				
			||||||
from esphome.const import (
 | 
					from esphome.const import (
 | 
				
			||||||
    CONF_ID,
 | 
					    CONF_ID,
 | 
				
			||||||
 | 
					    CONF_REACTIVE_POWER,
 | 
				
			||||||
    CONF_VOLTAGE,
 | 
					    CONF_VOLTAGE,
 | 
				
			||||||
    CONF_CURRENT,
 | 
					    CONF_CURRENT,
 | 
				
			||||||
    CONF_POWER,
 | 
					    CONF_POWER,
 | 
				
			||||||
@@ -20,6 +21,7 @@ from esphome.const import (
 | 
				
			|||||||
    ICON_EMPTY,
 | 
					    ICON_EMPTY,
 | 
				
			||||||
    ICON_LIGHTBULB,
 | 
					    ICON_LIGHTBULB,
 | 
				
			||||||
    ICON_CURRENT_AC,
 | 
					    ICON_CURRENT_AC,
 | 
				
			||||||
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_HERTZ,
 | 
					    UNIT_HERTZ,
 | 
				
			||||||
    UNIT_VOLT,
 | 
					    UNIT_VOLT,
 | 
				
			||||||
    UNIT_AMPERE,
 | 
					    UNIT_AMPERE,
 | 
				
			||||||
@@ -34,7 +36,6 @@ CONF_PHASE_A = "phase_a"
 | 
				
			|||||||
CONF_PHASE_B = "phase_b"
 | 
					CONF_PHASE_B = "phase_b"
 | 
				
			||||||
CONF_PHASE_C = "phase_c"
 | 
					CONF_PHASE_C = "phase_c"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONF_REACTIVE_POWER = "reactive_power"
 | 
					 | 
				
			||||||
CONF_LINE_FREQUENCY = "line_frequency"
 | 
					CONF_LINE_FREQUENCY = "line_frequency"
 | 
				
			||||||
CONF_CHIP_TEMPERATURE = "chip_temperature"
 | 
					CONF_CHIP_TEMPERATURE = "chip_temperature"
 | 
				
			||||||
CONF_GAIN_PGA = "gain_pga"
 | 
					CONF_GAIN_PGA = "gain_pga"
 | 
				
			||||||
@@ -63,25 +64,37 @@ ATM90E32Component = atm90e32_ns.class_(
 | 
				
			|||||||
ATM90E32_PHASE_SCHEMA = cv.Schema(
 | 
					ATM90E32_PHASE_SCHEMA = cv.Schema(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
 | 
					        cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
 | 
				
			||||||
            UNIT_VOLT, ICON_EMPTY, 2, DEVICE_CLASS_VOLTAGE
 | 
					            UNIT_VOLT,
 | 
				
			||||||
 | 
					            ICON_EMPTY,
 | 
				
			||||||
 | 
					            2,
 | 
				
			||||||
 | 
					            DEVICE_CLASS_VOLTAGE,
 | 
				
			||||||
 | 
					            STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        cv.Optional(CONF_CURRENT): sensor.sensor_schema(
 | 
					        cv.Optional(CONF_CURRENT): sensor.sensor_schema(
 | 
				
			||||||
            UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT
 | 
					            UNIT_AMPERE, ICON_EMPTY, 2, DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        cv.Optional(CONF_POWER): sensor.sensor_schema(
 | 
					        cv.Optional(CONF_POWER): sensor.sensor_schema(
 | 
				
			||||||
            UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER
 | 
					            UNIT_WATT, ICON_EMPTY, 2, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        cv.Optional(CONF_REACTIVE_POWER): sensor.sensor_schema(
 | 
					        cv.Optional(CONF_REACTIVE_POWER): sensor.sensor_schema(
 | 
				
			||||||
            UNIT_VOLT_AMPS_REACTIVE, ICON_LIGHTBULB, 2, DEVICE_CLASS_EMPTY
 | 
					            UNIT_VOLT_AMPS_REACTIVE,
 | 
				
			||||||
 | 
					            ICON_LIGHTBULB,
 | 
				
			||||||
 | 
					            2,
 | 
				
			||||||
 | 
					            DEVICE_CLASS_EMPTY,
 | 
				
			||||||
 | 
					            STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        cv.Optional(CONF_POWER_FACTOR): sensor.sensor_schema(
 | 
					        cv.Optional(CONF_POWER_FACTOR): sensor.sensor_schema(
 | 
				
			||||||
            UNIT_EMPTY, ICON_EMPTY, 2, DEVICE_CLASS_POWER_FACTOR
 | 
					            UNIT_EMPTY,
 | 
				
			||||||
 | 
					            ICON_EMPTY,
 | 
				
			||||||
 | 
					            2,
 | 
				
			||||||
 | 
					            DEVICE_CLASS_POWER_FACTOR,
 | 
				
			||||||
 | 
					            STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        cv.Optional(CONF_FORWARD_ACTIVE_ENERGY): sensor.sensor_schema(
 | 
					        cv.Optional(CONF_FORWARD_ACTIVE_ENERGY): sensor.sensor_schema(
 | 
				
			||||||
            UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY
 | 
					            UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY, STATE_CLASS_MEASUREMENT
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        cv.Optional(CONF_REVERSE_ACTIVE_ENERGY): sensor.sensor_schema(
 | 
					        cv.Optional(CONF_REVERSE_ACTIVE_ENERGY): sensor.sensor_schema(
 | 
				
			||||||
            UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY
 | 
					            UNIT_WATT_HOURS, ICON_EMPTY, 2, DEVICE_CLASS_ENERGY, STATE_CLASS_MEASUREMENT
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        cv.Optional(CONF_GAIN_VOLTAGE, default=7305): cv.uint16_t,
 | 
					        cv.Optional(CONF_GAIN_VOLTAGE, default=7305): cv.uint16_t,
 | 
				
			||||||
        cv.Optional(CONF_GAIN_CT, default=27961): cv.uint16_t,
 | 
					        cv.Optional(CONF_GAIN_CT, default=27961): cv.uint16_t,
 | 
				
			||||||
@@ -96,10 +109,18 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
            cv.Optional(CONF_PHASE_B): ATM90E32_PHASE_SCHEMA,
 | 
					            cv.Optional(CONF_PHASE_B): ATM90E32_PHASE_SCHEMA,
 | 
				
			||||||
            cv.Optional(CONF_PHASE_C): ATM90E32_PHASE_SCHEMA,
 | 
					            cv.Optional(CONF_PHASE_C): ATM90E32_PHASE_SCHEMA,
 | 
				
			||||||
            cv.Optional(CONF_FREQUENCY): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_FREQUENCY): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_HERTZ, ICON_CURRENT_AC, 1, DEVICE_CLASS_EMPTY
 | 
					                UNIT_HERTZ,
 | 
				
			||||||
 | 
					                ICON_CURRENT_AC,
 | 
				
			||||||
 | 
					                1,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_EMPTY,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cv.Optional(CONF_CHIP_TEMPERATURE): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_CHIP_TEMPERATURE): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE
 | 
					                UNIT_CELSIUS,
 | 
				
			||||||
 | 
					                ICON_EMPTY,
 | 
				
			||||||
 | 
					                1,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cv.Required(CONF_LINE_FREQUENCY): cv.enum(LINE_FREQS, upper=True),
 | 
					            cv.Required(CONF_LINE_FREQUENCY): cv.enum(LINE_FREQS, upper=True),
 | 
				
			||||||
            cv.Optional(CONF_CURRENT_PHASES, default="3"): cv.enum(
 | 
					            cv.Optional(CONF_CURRENT_PHASES, default="3"): cv.enum(
 | 
				
			||||||
@@ -113,10 +134,10 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    yield spi.register_spi_device(var, config)
 | 
					    await spi.register_spi_device(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for i, phase in enumerate([CONF_PHASE_A, CONF_PHASE_B, CONF_PHASE_C]):
 | 
					    for i, phase in enumerate([CONF_PHASE_A, CONF_PHASE_B, CONF_PHASE_C]):
 | 
				
			||||||
        if phase not in config:
 | 
					        if phase not in config:
 | 
				
			||||||
@@ -125,31 +146,31 @@ def to_code(config):
 | 
				
			|||||||
        cg.add(var.set_volt_gain(i, conf[CONF_GAIN_VOLTAGE]))
 | 
					        cg.add(var.set_volt_gain(i, conf[CONF_GAIN_VOLTAGE]))
 | 
				
			||||||
        cg.add(var.set_ct_gain(i, conf[CONF_GAIN_CT]))
 | 
					        cg.add(var.set_ct_gain(i, conf[CONF_GAIN_CT]))
 | 
				
			||||||
        if CONF_VOLTAGE in conf:
 | 
					        if CONF_VOLTAGE in conf:
 | 
				
			||||||
            sens = yield sensor.new_sensor(conf[CONF_VOLTAGE])
 | 
					            sens = await sensor.new_sensor(conf[CONF_VOLTAGE])
 | 
				
			||||||
            cg.add(var.set_voltage_sensor(i, sens))
 | 
					            cg.add(var.set_voltage_sensor(i, sens))
 | 
				
			||||||
        if CONF_CURRENT in conf:
 | 
					        if CONF_CURRENT in conf:
 | 
				
			||||||
            sens = yield sensor.new_sensor(conf[CONF_CURRENT])
 | 
					            sens = await sensor.new_sensor(conf[CONF_CURRENT])
 | 
				
			||||||
            cg.add(var.set_current_sensor(i, sens))
 | 
					            cg.add(var.set_current_sensor(i, sens))
 | 
				
			||||||
        if CONF_POWER in conf:
 | 
					        if CONF_POWER in conf:
 | 
				
			||||||
            sens = yield sensor.new_sensor(conf[CONF_POWER])
 | 
					            sens = await sensor.new_sensor(conf[CONF_POWER])
 | 
				
			||||||
            cg.add(var.set_power_sensor(i, sens))
 | 
					            cg.add(var.set_power_sensor(i, sens))
 | 
				
			||||||
        if CONF_REACTIVE_POWER in conf:
 | 
					        if CONF_REACTIVE_POWER in conf:
 | 
				
			||||||
            sens = yield sensor.new_sensor(conf[CONF_REACTIVE_POWER])
 | 
					            sens = await sensor.new_sensor(conf[CONF_REACTIVE_POWER])
 | 
				
			||||||
            cg.add(var.set_reactive_power_sensor(i, sens))
 | 
					            cg.add(var.set_reactive_power_sensor(i, sens))
 | 
				
			||||||
        if CONF_POWER_FACTOR in conf:
 | 
					        if CONF_POWER_FACTOR in conf:
 | 
				
			||||||
            sens = yield sensor.new_sensor(conf[CONF_POWER_FACTOR])
 | 
					            sens = await sensor.new_sensor(conf[CONF_POWER_FACTOR])
 | 
				
			||||||
            cg.add(var.set_power_factor_sensor(i, sens))
 | 
					            cg.add(var.set_power_factor_sensor(i, sens))
 | 
				
			||||||
        if CONF_FORWARD_ACTIVE_ENERGY in conf:
 | 
					        if CONF_FORWARD_ACTIVE_ENERGY in conf:
 | 
				
			||||||
            sens = yield sensor.new_sensor(conf[CONF_FORWARD_ACTIVE_ENERGY])
 | 
					            sens = await sensor.new_sensor(conf[CONF_FORWARD_ACTIVE_ENERGY])
 | 
				
			||||||
            cg.add(var.set_forward_active_energy_sensor(i, sens))
 | 
					            cg.add(var.set_forward_active_energy_sensor(i, sens))
 | 
				
			||||||
        if CONF_REVERSE_ACTIVE_ENERGY in conf:
 | 
					        if CONF_REVERSE_ACTIVE_ENERGY in conf:
 | 
				
			||||||
            sens = yield sensor.new_sensor(conf[CONF_REVERSE_ACTIVE_ENERGY])
 | 
					            sens = await sensor.new_sensor(conf[CONF_REVERSE_ACTIVE_ENERGY])
 | 
				
			||||||
            cg.add(var.set_reverse_active_energy_sensor(i, sens))
 | 
					            cg.add(var.set_reverse_active_energy_sensor(i, sens))
 | 
				
			||||||
    if CONF_FREQUENCY in config:
 | 
					    if CONF_FREQUENCY in config:
 | 
				
			||||||
        sens = yield sensor.new_sensor(config[CONF_FREQUENCY])
 | 
					        sens = await sensor.new_sensor(config[CONF_FREQUENCY])
 | 
				
			||||||
        cg.add(var.set_freq_sensor(sens))
 | 
					        cg.add(var.set_freq_sensor(sens))
 | 
				
			||||||
    if CONF_CHIP_TEMPERATURE in config:
 | 
					    if CONF_CHIP_TEMPERATURE in config:
 | 
				
			||||||
        sens = yield sensor.new_sensor(config[CONF_CHIP_TEMPERATURE])
 | 
					        sens = await sensor.new_sensor(config[CONF_CHIP_TEMPERATURE])
 | 
				
			||||||
        cg.add(var.set_chip_temperature_sensor(sens))
 | 
					        cg.add(var.set_chip_temperature_sensor(sens))
 | 
				
			||||||
    cg.add(var.set_line_freq(config[CONF_LINE_FREQUENCY]))
 | 
					    cg.add(var.set_line_freq(config[CONF_LINE_FREQUENCY]))
 | 
				
			||||||
    cg.add(var.set_current_phases(config[CONF_CURRENT_PHASES]))
 | 
					    cg.add(var.set_current_phases(config[CONF_CURRENT_PHASES]))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace b_parasite {
 | 
					namespace b_parasite {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char* TAG = "b_parasite";
 | 
					static const char *const TAG = "b_parasite";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void BParasite::dump_config() {
 | 
					void BParasite::dump_config() {
 | 
				
			||||||
  ESP_LOGCONFIG(TAG, "b_parasite");
 | 
					  ESP_LOGCONFIG(TAG, "b_parasite");
 | 
				
			||||||
@@ -16,25 +16,25 @@ void BParasite::dump_config() {
 | 
				
			|||||||
  LOG_SENSOR("  ", "Soil Moisture", this->soil_moisture_);
 | 
					  LOG_SENSOR("  ", "Soil Moisture", this->soil_moisture_);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool BParasite::parse_device(const esp32_ble_tracker::ESPBTDevice& device) {
 | 
					bool BParasite::parse_device(const esp32_ble_tracker::ESPBTDevice &device) {
 | 
				
			||||||
  if (device.address_uint64() != address_) {
 | 
					  if (device.address_uint64() != address_) {
 | 
				
			||||||
    ESP_LOGVV(TAG, "parse_device(): unknown MAC address.");
 | 
					    ESP_LOGVV(TAG, "parse_device(): unknown MAC address.");
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  ESP_LOGVV(TAG, "parse_device(): MAC address %s found.", device.address_str().c_str());
 | 
					  ESP_LOGVV(TAG, "parse_device(): MAC address %s found.", device.address_str().c_str());
 | 
				
			||||||
  const auto& service_datas = device.get_service_datas();
 | 
					  const auto &service_datas = device.get_service_datas();
 | 
				
			||||||
  if (service_datas.size() != 1) {
 | 
					  if (service_datas.size() != 1) {
 | 
				
			||||||
    ESP_LOGE(TAG, "Unexpected service_datas size (%d)", service_datas.size());
 | 
					    ESP_LOGE(TAG, "Unexpected service_datas size (%d)", service_datas.size());
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  const auto& service_data = service_datas[0];
 | 
					  const auto &service_data = service_datas[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ESP_LOGVV(TAG, "Service data:");
 | 
					  ESP_LOGVV(TAG, "Service data:");
 | 
				
			||||||
  for (const uint8_t byte : service_data.data) {
 | 
					  for (const uint8_t byte : service_data.data) {
 | 
				
			||||||
    ESP_LOGVV(TAG, "0x%02x", byte);
 | 
					    ESP_LOGVV(TAG, "0x%02x", byte);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const auto& data = service_data.data;
 | 
					  const auto &data = service_data.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Counter for deduplicating messages.
 | 
					  // Counter for deduplicating messages.
 | 
				
			||||||
  uint8_t counter = data[1] & 0x0f;
 | 
					  uint8_t counter = data[1] & 0x0f;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ from esphome.const import (
 | 
				
			|||||||
    DEVICE_CLASS_TEMPERATURE,
 | 
					    DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
    DEVICE_CLASS_VOLTAGE,
 | 
					    DEVICE_CLASS_VOLTAGE,
 | 
				
			||||||
    ICON_EMPTY,
 | 
					    ICON_EMPTY,
 | 
				
			||||||
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_CELSIUS,
 | 
					    UNIT_CELSIUS,
 | 
				
			||||||
    UNIT_PERCENT,
 | 
					    UNIT_PERCENT,
 | 
				
			||||||
    UNIT_VOLT,
 | 
					    UNIT_VOLT,
 | 
				
			||||||
@@ -32,16 +33,28 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
            cv.GenerateID(): cv.declare_id(BParasite),
 | 
					            cv.GenerateID(): cv.declare_id(BParasite),
 | 
				
			||||||
            cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
 | 
					            cv.Required(CONF_MAC_ADDRESS): cv.mac_address,
 | 
				
			||||||
            cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE
 | 
					                UNIT_CELSIUS,
 | 
				
			||||||
 | 
					                ICON_EMPTY,
 | 
				
			||||||
 | 
					                1,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_TEMPERATURE,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY
 | 
					                UNIT_PERCENT,
 | 
				
			||||||
 | 
					                ICON_EMPTY,
 | 
				
			||||||
 | 
					                1,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_HUMIDITY,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_BATTERY_VOLTAGE): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE
 | 
					                UNIT_VOLT, ICON_EMPTY, 3, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cv.Optional(CONF_MOISTURE): sensor.sensor_schema(
 | 
					            cv.Optional(CONF_MOISTURE): sensor.sensor_schema(
 | 
				
			||||||
                UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_HUMIDITY
 | 
					                UNIT_PERCENT,
 | 
				
			||||||
 | 
					                ICON_EMPTY,
 | 
				
			||||||
 | 
					                1,
 | 
				
			||||||
 | 
					                DEVICE_CLASS_HUMIDITY,
 | 
				
			||||||
 | 
					                STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
@@ -50,10 +63,10 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    yield esp32_ble_tracker.register_ble_device(var, config)
 | 
					    await esp32_ble_tracker.register_ble_device(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
 | 
					    cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -64,5 +77,5 @@ def to_code(config):
 | 
				
			|||||||
        (CONF_MOISTURE, var.set_soil_moisture),
 | 
					        (CONF_MOISTURE, var.set_soil_moisture),
 | 
				
			||||||
    ]:
 | 
					    ]:
 | 
				
			||||||
        if config_key in config:
 | 
					        if config_key in config:
 | 
				
			||||||
            sens = yield sensor.new_sensor(config[config_key])
 | 
					            sens = await sensor.new_sensor(config[config_key])
 | 
				
			||||||
            cg.add(setter(sens))
 | 
					            cg.add(setter(sens))
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										239
									
								
								esphome/components/ballu/ballu.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								esphome/components/ballu/ballu.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,239 @@
 | 
				
			|||||||
 | 
					#include "ballu.h"
 | 
				
			||||||
 | 
					#include "esphome/core/log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace ballu {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *const TAG = "ballu.climate";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const uint16_t BALLU_HEADER_MARK = 9000;
 | 
				
			||||||
 | 
					const uint16_t BALLU_HEADER_SPACE = 4500;
 | 
				
			||||||
 | 
					const uint16_t BALLU_BIT_MARK = 575;
 | 
				
			||||||
 | 
					const uint16_t BALLU_ONE_SPACE = 1675;
 | 
				
			||||||
 | 
					const uint16_t BALLU_ZERO_SPACE = 550;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const uint32_t BALLU_CARRIER_FREQUENCY = 38000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const uint8_t BALLU_STATE_LENGTH = 13;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const uint8_t BALLU_AUTO = 0;
 | 
				
			||||||
 | 
					const uint8_t BALLU_COOL = 0x20;
 | 
				
			||||||
 | 
					const uint8_t BALLU_DRY = 0x40;
 | 
				
			||||||
 | 
					const uint8_t BALLU_HEAT = 0x80;
 | 
				
			||||||
 | 
					const uint8_t BALLU_FAN = 0xc0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const uint8_t BALLU_FAN_AUTO = 0xa0;
 | 
				
			||||||
 | 
					const uint8_t BALLU_FAN_HIGH = 0x20;
 | 
				
			||||||
 | 
					const uint8_t BALLU_FAN_MED = 0x40;
 | 
				
			||||||
 | 
					const uint8_t BALLU_FAN_LOW = 0x60;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const uint8_t BALLU_SWING_VER = 0x07;
 | 
				
			||||||
 | 
					const uint8_t BALLU_SWING_HOR = 0xe0;
 | 
				
			||||||
 | 
					const uint8_t BALLU_POWER = 0x20;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void BalluClimate::transmit_state() {
 | 
				
			||||||
 | 
					  uint8_t remote_state[BALLU_STATE_LENGTH] = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto temp = (uint8_t) roundf(clamp(this->target_temperature, YKR_K_002E_TEMP_MIN, YKR_K_002E_TEMP_MAX));
 | 
				
			||||||
 | 
					  auto swing_ver =
 | 
				
			||||||
 | 
					      ((this->swing_mode == climate::CLIMATE_SWING_VERTICAL) || (this->swing_mode == climate::CLIMATE_SWING_BOTH));
 | 
				
			||||||
 | 
					  auto swing_hor =
 | 
				
			||||||
 | 
					      ((this->swing_mode == climate::CLIMATE_SWING_HORIZONTAL) || (this->swing_mode == climate::CLIMATE_SWING_BOTH));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  remote_state[0] = 0xc3;
 | 
				
			||||||
 | 
					  remote_state[1] = ((temp - 8) << 3) | (swing_ver ? 0 : BALLU_SWING_VER);
 | 
				
			||||||
 | 
					  remote_state[2] = swing_hor ? 0 : BALLU_SWING_HOR;
 | 
				
			||||||
 | 
					  remote_state[9] = (this->mode == climate::CLIMATE_MODE_OFF) ? 0 : BALLU_POWER;
 | 
				
			||||||
 | 
					  remote_state[11] = 0x1e;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Fan speed
 | 
				
			||||||
 | 
					  switch (this->fan_mode.value()) {
 | 
				
			||||||
 | 
					    case climate::CLIMATE_FAN_HIGH:
 | 
				
			||||||
 | 
					      remote_state[4] |= BALLU_FAN_HIGH;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case climate::CLIMATE_FAN_MEDIUM:
 | 
				
			||||||
 | 
					      remote_state[4] |= BALLU_FAN_MED;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case climate::CLIMATE_FAN_LOW:
 | 
				
			||||||
 | 
					      remote_state[4] |= BALLU_FAN_LOW;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case climate::CLIMATE_FAN_AUTO:
 | 
				
			||||||
 | 
					      remote_state[4] |= BALLU_FAN_AUTO;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Mode
 | 
				
			||||||
 | 
					  switch (this->mode) {
 | 
				
			||||||
 | 
					    case climate::CLIMATE_MODE_AUTO:
 | 
				
			||||||
 | 
					      remote_state[6] |= BALLU_AUTO;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case climate::CLIMATE_MODE_HEAT:
 | 
				
			||||||
 | 
					      remote_state[6] |= BALLU_HEAT;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case climate::CLIMATE_MODE_COOL:
 | 
				
			||||||
 | 
					      remote_state[6] |= BALLU_COOL;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case climate::CLIMATE_MODE_DRY:
 | 
				
			||||||
 | 
					      remote_state[6] |= BALLU_DRY;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case climate::CLIMATE_MODE_FAN_ONLY:
 | 
				
			||||||
 | 
					      remote_state[6] |= BALLU_FAN;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case climate::CLIMATE_MODE_OFF:
 | 
				
			||||||
 | 
					      remote_state[6] |= BALLU_AUTO;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Checksum
 | 
				
			||||||
 | 
					  for (uint8_t i = 0; i < BALLU_STATE_LENGTH - 1; i++)
 | 
				
			||||||
 | 
					    remote_state[12] += remote_state[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ESP_LOGV(TAG, "Sending: %02X %02X %02X %02X   %02X %02X %02X %02X   %02X %02X %02X %02X   %02X", remote_state[0],
 | 
				
			||||||
 | 
					           remote_state[1], remote_state[2], remote_state[3], remote_state[4], remote_state[5], remote_state[6],
 | 
				
			||||||
 | 
					           remote_state[7], remote_state[8], remote_state[9], remote_state[10], remote_state[11], remote_state[12]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Send code
 | 
				
			||||||
 | 
					  auto transmit = this->transmitter_->transmit();
 | 
				
			||||||
 | 
					  auto data = transmit.get_data();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  data->set_carrier_frequency(38000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Header
 | 
				
			||||||
 | 
					  data->mark(BALLU_HEADER_MARK);
 | 
				
			||||||
 | 
					  data->space(BALLU_HEADER_SPACE);
 | 
				
			||||||
 | 
					  // Data
 | 
				
			||||||
 | 
					  for (uint8_t i : remote_state) {
 | 
				
			||||||
 | 
					    for (uint8_t j = 0; j < 8; j++) {
 | 
				
			||||||
 | 
					      data->mark(BALLU_BIT_MARK);
 | 
				
			||||||
 | 
					      bool bit = i & (1 << j);
 | 
				
			||||||
 | 
					      data->space(bit ? BALLU_ONE_SPACE : BALLU_ZERO_SPACE);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Footer
 | 
				
			||||||
 | 
					  data->mark(BALLU_BIT_MARK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  transmit.perform();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool BalluClimate::on_receive(remote_base::RemoteReceiveData data) {
 | 
				
			||||||
 | 
					  // Validate header
 | 
				
			||||||
 | 
					  if (!data.expect_item(BALLU_HEADER_MARK, BALLU_HEADER_SPACE)) {
 | 
				
			||||||
 | 
					    ESP_LOGV(TAG, "Header fail");
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint8_t remote_state[BALLU_STATE_LENGTH] = {0};
 | 
				
			||||||
 | 
					  // Read all bytes.
 | 
				
			||||||
 | 
					  for (int i = 0; i < BALLU_STATE_LENGTH; i++) {
 | 
				
			||||||
 | 
					    // Read bit
 | 
				
			||||||
 | 
					    for (int j = 0; j < 8; j++) {
 | 
				
			||||||
 | 
					      if (data.expect_item(BALLU_BIT_MARK, BALLU_ONE_SPACE))
 | 
				
			||||||
 | 
					        remote_state[i] |= 1 << j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      else if (!data.expect_item(BALLU_BIT_MARK, BALLU_ZERO_SPACE)) {
 | 
				
			||||||
 | 
					        ESP_LOGV(TAG, "Byte %d bit %d fail", i, j);
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ESP_LOGVV(TAG, "Byte %d %02X", i, remote_state[i]);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // Validate footer
 | 
				
			||||||
 | 
					  if (!data.expect_mark(BALLU_BIT_MARK)) {
 | 
				
			||||||
 | 
					    ESP_LOGV(TAG, "Footer fail");
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint8_t checksum = 0;
 | 
				
			||||||
 | 
					  // Calculate  checksum and compare with signal value.
 | 
				
			||||||
 | 
					  for (uint8_t i = 0; i < BALLU_STATE_LENGTH - 1; i++)
 | 
				
			||||||
 | 
					    checksum += remote_state[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (checksum != remote_state[BALLU_STATE_LENGTH - 1]) {
 | 
				
			||||||
 | 
					    ESP_LOGVV(TAG, "Checksum fail");
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ESP_LOGV(TAG, "Received: %02X %02X %02X %02X   %02X %02X %02X %02X   %02X %02X %02X %02X   %02X", remote_state[0],
 | 
				
			||||||
 | 
					           remote_state[1], remote_state[2], remote_state[3], remote_state[4], remote_state[5], remote_state[6],
 | 
				
			||||||
 | 
					           remote_state[7], remote_state[8], remote_state[9], remote_state[10], remote_state[11], remote_state[12]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // verify header remote code
 | 
				
			||||||
 | 
					  if (remote_state[0] != 0xc3)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // powr on/off button
 | 
				
			||||||
 | 
					  ESP_LOGV(TAG, "Power: %02X", (remote_state[9] & BALLU_POWER));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if ((remote_state[9] & BALLU_POWER) != BALLU_POWER) {
 | 
				
			||||||
 | 
					    this->mode = climate::CLIMATE_MODE_OFF;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    auto mode = remote_state[6] & 0xe0;
 | 
				
			||||||
 | 
					    ESP_LOGV(TAG, "Mode: %02X", mode);
 | 
				
			||||||
 | 
					    switch (mode) {
 | 
				
			||||||
 | 
					      case BALLU_HEAT:
 | 
				
			||||||
 | 
					        this->mode = climate::CLIMATE_MODE_HEAT;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case BALLU_COOL:
 | 
				
			||||||
 | 
					        this->mode = climate::CLIMATE_MODE_COOL;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case BALLU_DRY:
 | 
				
			||||||
 | 
					        this->mode = climate::CLIMATE_MODE_DRY;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case BALLU_FAN:
 | 
				
			||||||
 | 
					        this->mode = climate::CLIMATE_MODE_FAN_ONLY;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case BALLU_AUTO:
 | 
				
			||||||
 | 
					        this->mode = climate::CLIMATE_MODE_AUTO;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Set received temp
 | 
				
			||||||
 | 
					  int temp = remote_state[1] & 0xf8;
 | 
				
			||||||
 | 
					  ESP_LOGVV(TAG, "Temperature Raw: %02X", temp);
 | 
				
			||||||
 | 
					  temp = ((uint8_t) temp >> 3) + 8;
 | 
				
			||||||
 | 
					  ESP_LOGVV(TAG, "Temperature Climate: %u", temp);
 | 
				
			||||||
 | 
					  this->target_temperature = temp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Set received fan speed
 | 
				
			||||||
 | 
					  auto fan = remote_state[4] & 0xe0;
 | 
				
			||||||
 | 
					  ESP_LOGVV(TAG, "Fan: %02X", fan);
 | 
				
			||||||
 | 
					  switch (fan) {
 | 
				
			||||||
 | 
					    case BALLU_FAN_HIGH:
 | 
				
			||||||
 | 
					      this->fan_mode = climate::CLIMATE_FAN_HIGH;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case BALLU_FAN_MED:
 | 
				
			||||||
 | 
					      this->fan_mode = climate::CLIMATE_FAN_MEDIUM;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case BALLU_FAN_LOW:
 | 
				
			||||||
 | 
					      this->fan_mode = climate::CLIMATE_FAN_LOW;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case BALLU_FAN_AUTO:
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      this->fan_mode = climate::CLIMATE_FAN_AUTO;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Set received swing status
 | 
				
			||||||
 | 
					  ESP_LOGVV(TAG, "Swing status: %02X %02X", remote_state[1] & BALLU_SWING_VER, remote_state[2] & BALLU_SWING_HOR);
 | 
				
			||||||
 | 
					  if (((remote_state[1] & BALLU_SWING_VER) != BALLU_SWING_VER) &&
 | 
				
			||||||
 | 
					      ((remote_state[2] & BALLU_SWING_HOR) != BALLU_SWING_HOR)) {
 | 
				
			||||||
 | 
					    this->swing_mode = climate::CLIMATE_SWING_BOTH;
 | 
				
			||||||
 | 
					  } else if ((remote_state[1] & BALLU_SWING_VER) != BALLU_SWING_VER) {
 | 
				
			||||||
 | 
					    this->swing_mode = climate::CLIMATE_SWING_VERTICAL;
 | 
				
			||||||
 | 
					  } else if ((remote_state[2] & BALLU_SWING_HOR) != BALLU_SWING_HOR) {
 | 
				
			||||||
 | 
					    this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL;
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    this->swing_mode = climate::CLIMATE_SWING_OFF;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  this->publish_state();
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace ballu
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										31
									
								
								esphome/components/ballu/ballu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								esphome/components/ballu/ballu.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "esphome/components/climate_ir/climate_ir.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace esphome {
 | 
				
			||||||
 | 
					namespace ballu {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Support for Ballu air conditioners with YKR-K/002E remote
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Temperature
 | 
				
			||||||
 | 
					const float YKR_K_002E_TEMP_MIN = 16.0;
 | 
				
			||||||
 | 
					const float YKR_K_002E_TEMP_MAX = 32.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BalluClimate : public climate_ir::ClimateIR {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  BalluClimate()
 | 
				
			||||||
 | 
					      : climate_ir::ClimateIR(YKR_K_002E_TEMP_MIN, YKR_K_002E_TEMP_MAX, 1.0f, true, true,
 | 
				
			||||||
 | 
					                              {climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM,
 | 
				
			||||||
 | 
					                               climate::CLIMATE_FAN_HIGH},
 | 
				
			||||||
 | 
					                              {climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL,
 | 
				
			||||||
 | 
					                               climate::CLIMATE_SWING_HORIZONTAL, climate::CLIMATE_SWING_BOTH}) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 protected:
 | 
				
			||||||
 | 
					  /// Transmit via IR the state of this climate controller.
 | 
				
			||||||
 | 
					  void transmit_state() override;
 | 
				
			||||||
 | 
					  /// Handle received IR Buffer
 | 
				
			||||||
 | 
					  bool on_receive(remote_base::RemoteReceiveData data) override;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace ballu
 | 
				
			||||||
 | 
					}  // namespace esphome
 | 
				
			||||||
							
								
								
									
										21
									
								
								esphome/components/ballu/climate.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								esphome/components/ballu/climate.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					import esphome.codegen as cg
 | 
				
			||||||
 | 
					import esphome.config_validation as cv
 | 
				
			||||||
 | 
					from esphome.components import climate_ir
 | 
				
			||||||
 | 
					from esphome.const import CONF_ID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AUTO_LOAD = ["climate_ir"]
 | 
				
			||||||
 | 
					CODEOWNERS = ["@bazuchan"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ballu_ns = cg.esphome_ns.namespace("ballu")
 | 
				
			||||||
 | 
					BalluClimate = ballu_ns.class_("BalluClimate", climate_ir.ClimateIR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend(
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        cv.GenerateID(): cv.declare_id(BalluClimate),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def to_code(config):
 | 
				
			||||||
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
 | 
					    await climate_ir.register_climate_ir(var, config)
 | 
				
			||||||
@@ -4,7 +4,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace bang_bang {
 | 
					namespace bang_bang {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "bang_bang.climate";
 | 
					static const char *const TAG = "bang_bang.climate";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void BangBangClimate::setup() {
 | 
					void BangBangClimate::setup() {
 | 
				
			||||||
  this->sensor_->add_on_state_callback([this](float state) {
 | 
					  this->sensor_->add_on_state_callback([this](float state) {
 | 
				
			||||||
@@ -21,7 +21,12 @@ void BangBangClimate::setup() {
 | 
				
			|||||||
    restore->to_call(this).perform();
 | 
					    restore->to_call(this).perform();
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    // restore from defaults, change_away handles those for us
 | 
					    // restore from defaults, change_away handles those for us
 | 
				
			||||||
    this->mode = climate::CLIMATE_MODE_AUTO;
 | 
					    if (supports_cool_ && supports_heat_)
 | 
				
			||||||
 | 
					      this->mode = climate::CLIMATE_MODE_HEAT_COOL;
 | 
				
			||||||
 | 
					    else if (supports_cool_)
 | 
				
			||||||
 | 
					      this->mode = climate::CLIMATE_MODE_COOL;
 | 
				
			||||||
 | 
					    else if (supports_heat_)
 | 
				
			||||||
 | 
					      this->mode = climate::CLIMATE_MODE_HEAT;
 | 
				
			||||||
    this->change_away_(false);
 | 
					    this->change_away_(false);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -32,8 +37,8 @@ void BangBangClimate::control(const climate::ClimateCall &call) {
 | 
				
			|||||||
    this->target_temperature_low = *call.get_target_temperature_low();
 | 
					    this->target_temperature_low = *call.get_target_temperature_low();
 | 
				
			||||||
  if (call.get_target_temperature_high().has_value())
 | 
					  if (call.get_target_temperature_high().has_value())
 | 
				
			||||||
    this->target_temperature_high = *call.get_target_temperature_high();
 | 
					    this->target_temperature_high = *call.get_target_temperature_high();
 | 
				
			||||||
  if (call.get_away().has_value())
 | 
					  if (call.get_preset().has_value())
 | 
				
			||||||
    this->change_away_(*call.get_away());
 | 
					    this->change_away_(*call.get_preset() == climate::CLIMATE_PRESET_AWAY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  this->compute_state_();
 | 
					  this->compute_state_();
 | 
				
			||||||
  this->publish_state();
 | 
					  this->publish_state();
 | 
				
			||||||
@@ -41,21 +46,27 @@ void BangBangClimate::control(const climate::ClimateCall &call) {
 | 
				
			|||||||
climate::ClimateTraits BangBangClimate::traits() {
 | 
					climate::ClimateTraits BangBangClimate::traits() {
 | 
				
			||||||
  auto traits = climate::ClimateTraits();
 | 
					  auto traits = climate::ClimateTraits();
 | 
				
			||||||
  traits.set_supports_current_temperature(true);
 | 
					  traits.set_supports_current_temperature(true);
 | 
				
			||||||
  traits.set_supports_auto_mode(true);
 | 
					  traits.set_supported_modes({
 | 
				
			||||||
  traits.set_supports_cool_mode(this->supports_cool_);
 | 
					      climate::CLIMATE_MODE_OFF,
 | 
				
			||||||
  traits.set_supports_heat_mode(this->supports_heat_);
 | 
					  });
 | 
				
			||||||
 | 
					  if (supports_cool_)
 | 
				
			||||||
 | 
					    traits.add_supported_mode(climate::CLIMATE_MODE_COOL);
 | 
				
			||||||
 | 
					  if (supports_heat_)
 | 
				
			||||||
 | 
					    traits.add_supported_mode(climate::CLIMATE_MODE_HEAT);
 | 
				
			||||||
 | 
					  if (supports_cool_ && supports_heat_)
 | 
				
			||||||
 | 
					    traits.add_supported_mode(climate::CLIMATE_MODE_HEAT_COOL);
 | 
				
			||||||
  traits.set_supports_two_point_target_temperature(true);
 | 
					  traits.set_supports_two_point_target_temperature(true);
 | 
				
			||||||
  traits.set_supports_away(this->supports_away_);
 | 
					  if (supports_away_)
 | 
				
			||||||
 | 
					    traits.set_supported_presets({
 | 
				
			||||||
 | 
					        climate::CLIMATE_PRESET_HOME,
 | 
				
			||||||
 | 
					        climate::CLIMATE_PRESET_AWAY,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  traits.set_supports_action(true);
 | 
					  traits.set_supports_action(true);
 | 
				
			||||||
  return traits;
 | 
					  return traits;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void BangBangClimate::compute_state_() {
 | 
					void BangBangClimate::compute_state_() {
 | 
				
			||||||
  if (this->mode != climate::CLIMATE_MODE_AUTO) {
 | 
					  if (this->mode == climate::CLIMATE_MODE_OFF) {
 | 
				
			||||||
    // in non-auto mode, switch directly to appropriate action
 | 
					    this->switch_to_action_(climate::CLIMATE_ACTION_OFF);
 | 
				
			||||||
    //  - HEAT mode -> HEATING action
 | 
					 | 
				
			||||||
    //  - COOL mode -> COOLING action
 | 
					 | 
				
			||||||
    //  - OFF mode -> OFF action (not IDLE!)
 | 
					 | 
				
			||||||
    this->switch_to_action_(static_cast<climate::ClimateAction>(this->mode));
 | 
					 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (isnan(this->current_temperature) || isnan(this->target_temperature_low) || isnan(this->target_temperature_high)) {
 | 
					  if (isnan(this->current_temperature) || isnan(this->target_temperature_low) || isnan(this->target_temperature_high)) {
 | 
				
			||||||
@@ -140,7 +151,7 @@ void BangBangClimate::change_away_(bool away) {
 | 
				
			|||||||
    this->target_temperature_low = this->away_config_.default_temperature_low;
 | 
					    this->target_temperature_low = this->away_config_.default_temperature_low;
 | 
				
			||||||
    this->target_temperature_high = this->away_config_.default_temperature_high;
 | 
					    this->target_temperature_high = this->away_config_.default_temperature_high;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  this->away = away;
 | 
					  this->preset = away ? climate::CLIMATE_PRESET_AWAY : climate::CLIMATE_PRESET_HOME;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
void BangBangClimate::set_normal_config(const BangBangClimateTargetTempConfig &normal_config) {
 | 
					void BangBangClimate::set_normal_config(const BangBangClimateTargetTempConfig &normal_config) {
 | 
				
			||||||
  this->normal_config_ = normal_config;
 | 
					  this->normal_config_ = normal_config;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,12 +39,12 @@ CONFIG_SCHEMA = cv.All(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    yield climate.register_climate(var, config)
 | 
					    await climate.register_climate(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sens = yield cg.get_variable(config[CONF_SENSOR])
 | 
					    sens = await cg.get_variable(config[CONF_SENSOR])
 | 
				
			||||||
    cg.add(var.set_sensor(sens))
 | 
					    cg.add(var.set_sensor(sens))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    normal_config = BangBangClimateTargetTempConfig(
 | 
					    normal_config = BangBangClimateTargetTempConfig(
 | 
				
			||||||
@@ -53,17 +53,17 @@ def to_code(config):
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
    cg.add(var.set_normal_config(normal_config))
 | 
					    cg.add(var.set_normal_config(normal_config))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    yield automation.build_automation(
 | 
					    await automation.build_automation(
 | 
				
			||||||
        var.get_idle_trigger(), [], config[CONF_IDLE_ACTION]
 | 
					        var.get_idle_trigger(), [], config[CONF_IDLE_ACTION]
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if CONF_COOL_ACTION in config:
 | 
					    if CONF_COOL_ACTION in config:
 | 
				
			||||||
        yield automation.build_automation(
 | 
					        await automation.build_automation(
 | 
				
			||||||
            var.get_cool_trigger(), [], config[CONF_COOL_ACTION]
 | 
					            var.get_cool_trigger(), [], config[CONF_COOL_ACTION]
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        cg.add(var.set_supports_cool(True))
 | 
					        cg.add(var.set_supports_cool(True))
 | 
				
			||||||
    if CONF_HEAT_ACTION in config:
 | 
					    if CONF_HEAT_ACTION in config:
 | 
				
			||||||
        yield automation.build_automation(
 | 
					        await automation.build_automation(
 | 
				
			||||||
            var.get_heat_trigger(), [], config[CONF_HEAT_ACTION]
 | 
					            var.get_heat_trigger(), [], config[CONF_HEAT_ACTION]
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        cg.add(var.set_supports_heat(True))
 | 
					        cg.add(var.set_supports_heat(True))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@
 | 
				
			|||||||
namespace esphome {
 | 
					namespace esphome {
 | 
				
			||||||
namespace bh1750 {
 | 
					namespace bh1750 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char *TAG = "bh1750.sensor";
 | 
					static const char *const TAG = "bh1750.sensor";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const uint8_t BH1750_COMMAND_POWER_ON = 0b00000001;
 | 
					static const uint8_t BH1750_COMMAND_POWER_ON = 0b00000001;
 | 
				
			||||||
static const uint8_t BH1750_COMMAND_MT_REG_HI = 0b01000000;  // last 3 bits
 | 
					static const uint8_t BH1750_COMMAND_MT_REG_HI = 0b01000000;  // last 3 bits
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ from esphome.const import (
 | 
				
			|||||||
    CONF_RESOLUTION,
 | 
					    CONF_RESOLUTION,
 | 
				
			||||||
    DEVICE_CLASS_ILLUMINANCE,
 | 
					    DEVICE_CLASS_ILLUMINANCE,
 | 
				
			||||||
    ICON_EMPTY,
 | 
					    ICON_EMPTY,
 | 
				
			||||||
 | 
					    STATE_CLASS_MEASUREMENT,
 | 
				
			||||||
    UNIT_LUX,
 | 
					    UNIT_LUX,
 | 
				
			||||||
    CONF_MEASUREMENT_DURATION,
 | 
					    CONF_MEASUREMENT_DURATION,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -26,7 +27,9 @@ BH1750Sensor = bh1750_ns.class_(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
CONF_MEASUREMENT_TIME = "measurement_time"
 | 
					CONF_MEASUREMENT_TIME = "measurement_time"
 | 
				
			||||||
CONFIG_SCHEMA = (
 | 
					CONFIG_SCHEMA = (
 | 
				
			||||||
    sensor.sensor_schema(UNIT_LUX, ICON_EMPTY, 1, DEVICE_CLASS_ILLUMINANCE)
 | 
					    sensor.sensor_schema(
 | 
				
			||||||
 | 
					        UNIT_LUX, ICON_EMPTY, 1, DEVICE_CLASS_ILLUMINANCE, STATE_CLASS_MEASUREMENT
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
    .extend(
 | 
					    .extend(
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            cv.GenerateID(): cv.declare_id(BH1750Sensor),
 | 
					            cv.GenerateID(): cv.declare_id(BH1750Sensor),
 | 
				
			||||||
@@ -46,11 +49,11 @@ CONFIG_SCHEMA = (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_ID])
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
    yield sensor.register_sensor(var, config)
 | 
					    await sensor.register_sensor(var, config)
 | 
				
			||||||
    yield i2c.register_i2c_device(var, config)
 | 
					    await i2c.register_i2c_device(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cg.add(var.set_resolution(config[CONF_RESOLUTION]))
 | 
					    cg.add(var.set_resolution(config[CONF_RESOLUTION]))
 | 
				
			||||||
    cg.add(var.set_measurement_duration(config[CONF_MEASUREMENT_DURATION]))
 | 
					    cg.add(var.set_measurement_duration(config[CONF_MEASUREMENT_DURATION]))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,19 +21,19 @@ CONFIG_SCHEMA = fan.FAN_SCHEMA.extend(
 | 
				
			|||||||
).extend(cv.COMPONENT_SCHEMA)
 | 
					).extend(cv.COMPONENT_SCHEMA)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def to_code(config):
 | 
					async def to_code(config):
 | 
				
			||||||
    var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
 | 
					    var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
 | 
				
			||||||
    yield cg.register_component(var, config)
 | 
					    await cg.register_component(var, config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fan_ = yield fan.create_fan_state(config)
 | 
					    fan_ = await fan.create_fan_state(config)
 | 
				
			||||||
    cg.add(var.set_fan(fan_))
 | 
					    cg.add(var.set_fan(fan_))
 | 
				
			||||||
    output_ = yield cg.get_variable(config[CONF_OUTPUT])
 | 
					    output_ = await cg.get_variable(config[CONF_OUTPUT])
 | 
				
			||||||
    cg.add(var.set_output(output_))
 | 
					    cg.add(var.set_output(output_))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if CONF_OSCILLATION_OUTPUT in config:
 | 
					    if CONF_OSCILLATION_OUTPUT in config:
 | 
				
			||||||
        oscillation_output = yield cg.get_variable(config[CONF_OSCILLATION_OUTPUT])
 | 
					        oscillation_output = await cg.get_variable(config[CONF_OSCILLATION_OUTPUT])
 | 
				
			||||||
        cg.add(var.set_oscillating(oscillation_output))
 | 
					        cg.add(var.set_oscillating(oscillation_output))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if CONF_DIRECTION_OUTPUT in config:
 | 
					    if CONF_DIRECTION_OUTPUT in config:
 | 
				
			||||||
        direction_output = yield cg.get_variable(config[CONF_DIRECTION_OUTPUT])
 | 
					        direction_output = await cg.get_variable(config[CONF_DIRECTION_OUTPUT])
 | 
				
			||||||
        cg.add(var.set_direction(direction_output))
 | 
					        cg.add(var.set_direction(direction_output))
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user