Documentation: https://esphome.io/
For issues, please go to the issue tracker.
For feature requests, please see feature requests.
Python Client for ESPHome native API. Used by Home Assistant.
Home Page: https://esphome.io/
License: MIT License
Documentation: https://esphome.io/
For issues, please go to the issue tracker.
For feature requests, please see feature requests.
both start and finish have an extra safety. I have audited the code and we aren’t missing any timeouts anymore. Since we control the code path end to end here we should remove the extra safeties when we have sufficient coverage
aioesphomeapi/aioesphomeapi/connection.py
Line 501 in cafdcca
Hi!
I'm looking for a way to normalize my assorted homebrew home automations (from mqtt to udp etc etc).
Since esphome/feature-requests#817 seems stuck, I'd like to try to flank the problem and to use this library to run a "pseudo-esphome" device (fed with those my automations) in native api mode.
How do I do that, if ever?
TIA,
--Vladimir
aioesphomeapi/aioesphomeapi/client.py
Line 508 in 14a2e30
We should instead check if debug is enabled when creating the connection
We need a .set_debug(default true) for ha to be able to change it at runtime though
The current design of bluetooth_gatt_start_notify
returns two callables:
We should only return one callable and handle cleaning up disconnecting the callback in _on_bluetooth_device_connection_response
so callers can't get it wrong and leak a callback
aioesphomeapi/aioesphomeapi/connection.py
Line 693 in 9439cc4
It doesn't matter which message type we get back. Any valid protobuf should cancel the disconnect timer.
From discussion in home-assistant/core#80432 we need this library to support newer versions of protocol buffer in order to move forward other packages.
I tried to upgrade this myself, but i'm having a hard time understanding the protoc workflow in this library.
______________________________ ERROR collecting tests/test_client.py _______________________________
tests/test_client.py:6: in <module>
from aioesphomeapi.api_pb2 import (
aioesphomeapi/__init__.py:3: in <module>
from .client import APIClient
aioesphomeapi/client.py:21: in <module>
from .api_pb2 import ( # type: ignore
aioesphomeapi/api_pb2.py:16: in <module>
from . import api_options_pb2 as api__options__pb2
aioesphomeapi/api_options_pb2.py:36: in <module>
_descriptor.EnumValueDescriptor(
venv/lib/python3.9/site-packages/google/protobuf/descriptor.py:755: in __new__
_message.Message._CheckCalledFromGeneratedFile()
E TypeError: Descriptors cannot not be created directly.
E If this call came from a _pb2.py file, your generated code is out of date and must be regenerated with protoc >= 3.19.0.
E If you cannot immediately regenerate your protos, some other possible workarounds are:
E 1. Downgrade the protobuf package to 3.20.x or lower.
E 2. Set PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python (but this will use pure-Python parsing and will be much slower).
E
E More information: https://developers.google.com/protocol-buffers/docs/news/2022-05-06#python-updates
2022-10-23 22:14:45.384 DEBUG (MainThread) [aiohomekit.controller.ble.pairing] Eve Motion 41A4 [CA:D5:1A:5B:E3:A9] (id=4B:10:3C:BB:EF:8E): Polling subscriptions for changes during disconnection; rssi=-65
2022-10-23 22:14:45.384 DEBUG (MainThread) [aiohomekit.controller.ble.pairing] Eve Motion 41A4 [CA:D5:1A:5B:E3:A9] (id=4B:10:3C:BB:EF:8E): Client not connected; rssi=-65
2022-10-23 22:14:45.384 WARNING (MainThread) [aiohomekit.controller.ble.pairing] Eve Motion 41A4 [CA:D5:1A:5B:E3:A9] (id=4B:10:3C:BB:EF:8E): Failed to fetch disconnected events: Eve Motion 41A4 [CA:D5:1A:5B:E3:A9] (id=4B:10:3C:BB:EF:8E) is not connected; rssi=-65
There is some type of race where we never get a disconnected callback but we are not actually connected anymore
If the first reconnect fails, keep the zeroconf listener running and cancel the connection attempt if we are not in phase 2 as soon as we see the device.
To make this cancel safe we need to split the connection logic into two phases
Phase 1: actual connection
Phase 2: setup connection
Phase 1 must be cancel safe
I got a level bolt for testing and found this
2023-07-19 12:56:48.780 ERROR (MainThread) [homeassistant.config_entries] Error setting up entry A13 for homekit_controller
Traceback (most recent call last):
File "/Users/bdraco/home-assistant/homeassistant/config_entries.py", line 391, in async_setup
result = await component.async_setup_entry(hass, self)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bdraco/home-assistant/homeassistant/components/homekit_controller/__init__.py", line 44, in async_setup_entry
await conn.async_setup()
File "/Users/bdraco/home-assistant/homeassistant/components/homekit_controller/connection.py", line 245, in async_setup
await self.pairing.async_populate_accessories_state(
File "/Users/bdraco/home-assistant/venv/lib/python3.11/site-packages/aiohomekit/controller/ble/pairing.py", line 1059, in async_populate_accessories_state
await self._async_populate_accessories_state(force_update, attempts)
File "/Users/bdraco/home-assistant/venv/lib/python3.11/site-packages/aiohomekit/controller/ble/pairing.py", line 189, in _async_operation_lock_wrap
return await func(self, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bdraco/home-assistant/venv/lib/python3.11/site-packages/bleak_retry_connector/__init__.py", line 454, in _async_wrap_bluetooth_connection_error_retry
return await func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bdraco/home-assistant/venv/lib/python3.11/site-packages/aiohomekit/controller/ble/pairing.py", line 205, in _async_disconnect_on_missing_services_wrap
return await func(self, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bdraco/home-assistant/venv/lib/python3.11/site-packages/aiohomekit/controller/ble/pairing.py", line 1072, in _async_populate_accessories_state
await self._populate_accessories_and_characteristics(force_update, attempts)
File "/Users/bdraco/home-assistant/venv/lib/python3.11/site-packages/aiohomekit/controller/ble/pairing.py", line 1117, in _populate_accessories_and_characteristics
accessories = await self._async_fetch_gatt_database()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bdraco/home-assistant/venv/lib/python3.11/site-packages/aiohomekit/controller/ble/pairing.py", line 872, in _async_fetch_gatt_database
decoded = await self._read_signature(
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bdraco/home-assistant/venv/lib/python3.11/site-packages/aiohomekit/controller/ble/pairing.py", line 810, in _read_signature
payload = await self.client.read_gatt_char(char)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bdraco/home-assistant/venv/lib/python3.11/site-packages/bleak/__init__.py", line 637, in read_gatt_char
return await self._backend.read_gatt_char(char_specifier, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bdraco/home-assistant/homeassistant/components/esphome/bluetooth/client.py", line 83, in _async_wrap_bluetooth_connected_operation
return await func(self, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bdraco/home-assistant/homeassistant/components/esphome/bluetooth/client.py", line 109, in _async_wrap_bluetooth_operation
return await func(self, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bdraco/home-assistant/homeassistant/components/esphome/bluetooth/client.py", line 596, in read_gatt_char
return await self._client.bluetooth_gatt_read(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bdraco/home-assistant/venv/lib/python3.11/site-packages/aioesphomeapi/client.py", line 862, in bluetooth_gatt_read
resp = await self._send_bluetooth_message_await_response(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bdraco/home-assistant/venv/lib/python3.11/site-packages/aioesphomeapi/client.py", line 507, in _send_bluetooth_message_await_response
resp = await self._connection.send_message_await_response_complex(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/bdraco/home-assistant/venv/lib/python3.11/site-packages/aioesphomeapi/connection.py", line 662, in send_message_await_response_complex
await fut
asyncio.exceptions.CancelledError
aioesphomeapi/aioesphomeapi/connection.py
Line 681 in 2df4eff
this check is impossible now since the function always returns on the first message that matches the type
we can use list unpack as well
Error while reading incoming messages: Invalid preamble 5e
2022-12-13 12:14:38.800 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
File "/usr/local/lib/python3.10/site-packages/aioesphomeapi/connection.py", line 137, in _do_cleanup
await self._process_task
File "/usr/local/lib/python3.10/site-packages/aioesphomeapi/connection.py", line 559, in _process_loop
msg.ParseFromString(pkt.data)
File "/usr/local/lib/python3.10/site-packages/google/protobuf/message.py", line 202, in ParseFromString
return self.MergeFromString(serialized)
File "/usr/local/lib/python3.10/site-packages/google/protobuf/internal/python_message.py", line 1128, in MergeFromString
if self._InternalParse(serialized, 0, length) != length:
File "/usr/local/lib/python3.10/site-packages/google/protobuf/internal/python_message.py", line 1178, in InternalParse
raise message_mod.DecodeError('Field number 0 is illegal.')
google.protobuf.message.DecodeError: Field number 0 is illegal.
When trying to connect to a device which is offline, the socket isn't closed and the file descriptor is leaked.
Running python with the -W default -X tracemalloc
options shows the following warning after each connection attempt.
/usr/lib/python3.7/traceback.py:357: ResourceWarning: unclosed <socket.socket fd=6, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.0.100', 43254)>
filename, lineno, name, lookup_line=False, locals=f_locals))
Object allocated at (most recent call last):
File "/home/pi/programs/influx_esphome/venv/lib/python3.7/site-packages/aioesphomeapi/connection.py", lineno 112
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Changing connection.py
as follows appears to fix the issue:
--- connection.py.orig 2020-02-05 14:17:04.468032907 +0000
+++ connection.py 2020-02-05 14:25:02.458536299 +0000
@@ -62,12 +62,11 @@
self._params.eventloop.create_task(func())
async def _close_socket(self) -> None:
- if not self._socket_connected:
- return
- async with self._write_lock:
- self._socket_writer.close()
- self._socket_writer = None
- self._socket_reader = None
+ if self._socket_connected:
+ async with self._write_lock:
+ self._socket_writer.close()
+ self._socket_writer = None
+ self._socket_reader = None
if self._socket is not None:
self._socket.close()
self._socket_connected = False
My ESPHome device publish some logs with log level DEBUG.
If I try to subscribe to the log with subscribe_logs(log_callback, LOG_LEVEL_DEBUG) I receive nothing.
Messages are received only with subscribe_logs(log_callback, LOG_LEVEL_VERBOSE) or subscribe_logs(log_callback, LOG_LEVEL_VERY_VERBOSE).
Output example:
level: LOG_LEVEL_VERBOSE
message: "\033[0;36m[D][AirCon:976]: 0001776712: [=>] [BB 00 01 80 01 00 08 00] 1C 27 00 00 00 00 00 00 [1E 58] \033[0m"
There is a string "[D]" in output. It means that message has LOG_LEVEL = DEBUG.
It looks like an incorrect comparison somewhere in the code. "<" instead of "<=" or something like that.
I was doing some testing on my program using the API and a found a problem with the read_loop/ping tasks left hanging when I try the following with an incorrect password:
...
try:
self._esphome = aioesphomeapi.APIClient(eventloop=asyncio.get_running_loop(), address=url, port=port, password=password)
await self._esphome.connect(login=True)
except InvalidAuthAPIError as e:
_LOGGER.error(f"ESPHome login failed: {e}")
return False
...
The InvalidAuthAPIError exception is caught but now when await self._esphome.disconnect()
is called during shutdown the disconnect code finds self._connection
is now None so there is no way to clean up the hanging tasks as it returns immediately,
async def disconnect(self, force: bool = False) -> None:
if self._connection is None:
return
if force:
resulting in the error message on exit:
Task was destroyed but it is pending!
task: <Task pending name='Task-5' coro=<APIConnection._connect_start_ping.<locals>.func() done, defined at ...
...
Task was destroyed but it is pending!
task: <Task pending name='Task-6' coro=<Event.wait() done, defined at ...
...
On PyPI is still 2.6.1 present. Looks like that the publishing didn't work.
There is Subscribe to state changes of an ESPHome device
example in the Readme.
This example generates an error:
Task exception was never retrieved
future: <Task finished name='Task-1' coro=<main() done, defined at test_from_github.py:4> exception=TypeError('__init__() takes 4 positional arguments but 5 were given')>
Traceback (most recent call last):
File "test_from_github.py", line 7, in main
cli = aioesphomeapi.APIClient(loop, "IP_ADDRESS", 6053, "API_PASSWORD")
TypeError: __init__() takes 4 positional arguments but 5 were given
Looks like loop
should be deleted from APIClient() call
2023-09-05 18:03:34.850 DEBUG (MainThread) [aioesphomeapi.reconnect_logic] disco @ 192.168.211.119: Triggering connect because of received mDNS record record[ptr,in,_esphomelib._tcp.local.]=4500.0/4500,disco._esphomelib._tcp.local.
2023-09-05 18:03:34.851 DEBUG (MainThread) [aioesphomeapi.reconnect_logic] Removing zeroconf listener for disco
2023-09-05 18:03:34.851 ERROR (MainThread) [homeassistant] Error doing job: Exception in callback _SelectorDatagramTransport._read_ready()
Traceback (most recent call last):
File "/opt/homebrew/Cellar/[email protected]/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/events.py", line 80, in _run
self._context.run(self._callback, *self._args)
File "/opt/homebrew/Cellar/[email protected]/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/selector_events.py", line 1169, in _read_ready
self._protocol.datagram_received(data, addr)
File "src/zeroconf/_listener.py", line 80, in zeroconf._listener.AsyncListener.datagram_received
File "src/zeroconf/_listener.py", line 161, in zeroconf._listener.AsyncListener.datagram_received
File "src/zeroconf/_handlers/record_manager.py", line 134, in zeroconf._handlers.record_manager.RecordManager.async_updates_from_response
File "src/zeroconf/_handlers/record_manager.py", line 58, in zeroconf._handlers.record_manager.RecordManager.async_updates
RuntimeError: set changed size during iteration
Background:
One of my devices is in an area with poor network connectivity and frequently disconnects and reconnects. Sometimes (time between 12 hours - 1 month), the device will disconnect and never reconnect even though it is connected to the wifi network.
Diagnosis:
After carefully monitoring the issue over a number of months and adding extra debug lines as necessary, it appears that this results from a perfectly timed disconnect during the handshake process.
Some extra logs were added and the relevant logs are displayed below.
2022-09-24 02:33:49.069 DEBUG (MainThread) [aioesphomeapi.connection] sonoff_switch_2 @ sonoff_switch_2.local: Got message of type <class 'api_pb2.ConnectResponse'>:
2022-09-24 02:33:49.070 INFO (MainThread) [aioesphomeapi.connection] sonoff_switch_2 @ sonoff_switch_2.local: Error while reading incoming messages: Error while reading data: 0 bytes read on a total of 1 expected bytes
<-- Report fatal is run here following the error in reading the message -->
2022-09-24 02:33:49.073 DEBUG (MainThread) [aioesphomeapi.connection] connection complete for sonoff_switch_2 @ sonoff_switch_2.local
From this, it seems that the connect
method is being run and login
is called successfully. However, a packet is received that is malformed and calls the _report_fatal_error
prior to the connect
method returning. This results in the connection being closed while it remains marked as connected in reconnect_logic
. Since the connection was closed and cleaned up, the disconnect callback is never called and thus a reconnect is never attempted again.
Solution:
I'm not sure if the malformed packet received during the connection phase should be ignored or passed along to reset the connection post initialization. Either
_report_fatal_error
to postphone it from excecuting during the connection phase.For completeness below are additional unmodified logs:
2022-09-24 02:33:41.434 DEBUG (MainThread) [aioesphomeapi.connection] Starting connection for sonoff @ sonoff.local
2022-09-24 02:33:41.443 DEBUG (MainThread) [aioesphomeapi.connection] sonoff @ sonoff.local: Connecting to sonoff.local:6053 (AddrInfo(family=<AddressFamily.AF_INET: 2>, type=<SocketKind.SOCK_STREAM: 1>, proto=6, sockaddr=IPv4Sockaddr(address='10.0.0.179', port=6053)))
2022-09-24 02:33:41.479 DEBUG (MainThread) [aioesphomeapi.connection] sonoff.local: Opened socket
2022-09-24 02:33:41.482 DEBUG (MainThread) [aioesphomeapi.connection] sonoff.local: Sending <class 'api_pb2.HelloRequest'>: client_info: "Home Assistant 2022.8.7"
2022-09-24 02:33:41.482 DEBUG (MainThread) [aioesphomeapi.connection] sonoff.local: finished sending
2022-09-24 02:33:41.510 DEBUG (MainThread) [aioesphomeapi.connection] sonoff @ sonoff.local: Got message of type <class 'api_pb2.HelloResponse'>: api_version_major: 1
api_version_minor: 3
server_info: "sonoff (esphome v1.15.3)"
2022-09-24 02:33:41.511 DEBUG (MainThread) [aioesphomeapi.connection] sonoff @ sonoff.local: Successfully connected ('sonoff (esphome v1.15.3)' API=1.3)
2022-09-24 02:33:41.512 DEBUG (MainThread) [aioesphomeapi.connection] sonoff.local: Sending <class 'api_pb2.ConnectRequest'>: password: "REDACTED"
2022-09-24 02:33:41.512 DEBUG (MainThread) [aioesphomeapi.connection] sonoff.local: finished sending
2022-09-24 02:33:49.068 DEBUG (MainThread) [aioesphomeapi.connection] sonoff @ sonoff.local: Got message of type <class 'api_pb2.GetTimeRequest'>:
2022-09-24 02:33:49.068 DEBUG (MainThread) [aioesphomeapi.connection] sonoff.local: Sending <class 'api_pb2.GetTimeResponse'>: epoch_seconds: 1664004829
2022-09-24 02:33:49.069 DEBUG (MainThread) [aioesphomeapi.connection] sonoff.local: finished sending
2022-09-24 02:33:49.069 DEBUG (MainThread) [aioesphomeapi.connection] sonoff @ sonoff.local: Got message of type <class 'api_pb2.ConnectResponse'>:
2022-09-24 02:33:49.070 INFO (MainThread) [aioesphomeapi.connection] sonoff @ sonoff.local: Error while reading incoming messages: Error while reading data: 0 bytes read on a total of 1 expected bytes
2022-09-24 02:33:49.070 DEBUG (MainThread) [aioesphomeapi.connection] report fatal: Before cleanup for sonoff @ sonoff.local
2022-09-24 02:33:49.070 DEBUG (MainThread) [aioesphomeapi.connection] _cleanup: before framehelper for sonoff @ sonoff.local
2022-09-24 02:33:49.070 DEBUG (MainThread) [aioesphomeapi.connection] _cleanup: before socket for sonoff @ sonoff.local
2022-09-24 02:33:49.071 DEBUG (MainThread) [aioesphomeapi.connection] _cleanup: before on stop for sonoff @ sonoff.local
2022-09-24 02:33:49.071 DEBUG (MainThread) [aioesphomeapi.connection] _cleanup: finished for sonoff @ sonoff.local
2022-09-24 02:33:49.072 DEBUG (MainThread) [aioesphomeapi.connection] report fatal: after cleanup for sonoff @ sonoff.local
2022-09-24 02:33:49.073 DEBUG (MainThread) [aioesphomeapi.connection] connection complete for sonoff @ sonoff.local
2022-09-24 02:33:49.073 DEBUG (MainThread) [aioesphomeapi.reconnect_logic] _try_connect: after connect sonoff @ sonoff.local
2022-09-24 02:33:49.073 INFO (MainThread) [aioesphomeapi.reconnect_logic] Successfully connected to sonoff @ sonoff.local
2022-09-24 02:33:49.073 DEBUG (MainThread) [aioesphomeapi.reconnect_logic] sonoff @ sonoff.local: aioesphome._try_connect setting connected to false
2022-09-24 02:33:49.073 DEBUG (MainThread) [custom_components.esphome] Starting on_connect for sonoff.local
2022-09-24 02:33:49.074 WARNING (MainThread) [custom_components.esphome] Error getting initial data for sonoff.local: Connection not done for sonoff @ sonoff.local!
Traceback (most recent call last):
File "/config/custom_components/esphome/__init__.py", line 272, in on_connect
entry_data.device_info = await cli.device_info()
File "/config/aioesphomeapi/client.py", line 244, in device_info
self._check_connected()
File "/config/aioesphomeapi/client.py", line 235, in _check_connected
raise APIConnectionError(f"Connection not done for {self._log_name}!")
aioesphomeapi.core.APIConnectionError: Connection not done for sonoff @ sonoff.local!
2022-09-24 02:33:49.076 DEBUG (MainThread) [aioesphomeapi.reconnect_logic] _reconnect_once: waiting for sonoff @ sonoff.local
Hi everybody,
not sure if it's ok to report this issue here, please check and add it:
* Package: dev-python/aioesphomeapi-2.6.3
* Repository: HomeAssistantRepository
* Maintainer: [email protected]
* Upstream: [email protected]
* USE: abi_x86_64 amd64 elibc_glibc kernel_linux python_targets_python3_7 test userland_GNU
* FEATURES: network-sandbox preserve-libs sandbox userpriv usersandbox
>>> Unpacking source...
>>> Unpacking aioesphomeapi-2.6.3.tar.gz to /var/tmp/portage/dev-python/aioesphomeapi-2.6.3/work
>>> Source unpacked in /var/tmp/portage/dev-python/aioesphomeapi-2.6.3/work
>>> Preparing source in /var/tmp/portage/dev-python/aioesphomeapi-2.6.3/work/aioesphomeapi-2.6.3 ...
>>> Source prepared.
>>> Configuring source in /var/tmp/portage/dev-python/aioesphomeapi-2.6.3/work/aioesphomeapi-2.6.3 ...
>>> Source configured.
>>> Compiling source in /var/tmp/portage/dev-python/aioesphomeapi-2.6.3/work/aioesphomeapi-2.6.3 ...
* python3_7: running distutils-r1_run_phase distutils-r1_python_compile
python3.7 setup.py build -j 10
Traceback (most recent call last):
File "setup.py", line 32, in <module>
with open(os.path.join(here, 'requirements.txt')) as requirements_txt:
FileNotFoundError: [Errno 2] No such file or directory: '/var/tmp/portage/dev-python/aioesphomeapi-2.6.3/work/aioesphomeapi-2.6.3/requirements.txt'
* ERROR: dev-python/aioesphomeapi-2.6.3::HomeAssistantRepository failed (compile phase):
* (no error message)
But works with the archive from Github.
Just re-checked, all the older versions compile with the SDIST source:
root@g18-hasstest:/usr/portage/homeassistant/dev-python/aioesphomeapi # l
insgesamt 84
drwxr-xr-x 2 b homeassistant 4096 5. Sep 13:39 ./
drwxr-xr-x 980 b homeassistant 36864 5. Sep 12:23 ../
-rw-r--r-- 1 b homeassistant 666 25. Aug 00:21 aioesphomeapi-2.4.0.ebuild
-rw-r--r-- 1 b homeassistant 666 25. Aug 00:21 aioesphomeapi-2.4.1.ebuild
-rw-r--r-- 1 b homeassistant 794 25. Aug 00:21 aioesphomeapi-2.4.2-r1.ebuild
-rw-r--r-- 1 b homeassistant 794 25. Aug 00:21 aioesphomeapi-2.5.0.ebuild
-rw-r--r-- 1 b homeassistant 794 25. Aug 00:21 aioesphomeapi-2.6.0.ebuild
-rw-r--r-- 1 b homeassistant 824 25. Aug 00:21 aioesphomeapi-2.6.1.ebuild
-rw-r--r-- 1 b homeassistant 949 5. Sep 13:36 aioesphomeapi-2.6.3.ebuild
-rw-r--r-- 1 b homeassistant 4652 5. Sep 13:39 Manifest
-rw-r--r-- 1 b homeassistant 460 5. Sep 13:27 metadata.xml
root@g18-hasstest:/usr/portage/homeassistant/dev-python/aioesphomeapi #
Please add git tags for the releases on https://pypi.org/project/aioesphomeapi/#history.
Hi!
Can interactions be done from outside the local area network?
I want to control an esp device that is not under the same LAN as my home assistant, not sure if this library might allow that.
Thanks
Edit: This description make me think is possible but I would appreciate an example/confirmation
Edit2: just found that on Oct 2019 was not possible, wondering if are there any updates.
esphome/feature-requests#441
there is only one consumer here so no need to wake multiple waiters
home assistant logs "Error doing job: Task was destroyed but it is pending!". also, HA fails to connect to some devices sometimes. after the failure, a few seconds later, it reconnects successfully. I'm not sure they are related. installed HA via pip + virtualenv.
homeassistant 2022.10.3
aioesphomeapi 11.1.0
2022-10-12 11:31:23.830 ERROR (MainThread) [homeassistant] Error doing job: Task was destroyed but it is pending!: File "/usr/home/hass/hass/.tox/python/bin/hass", line 10, in <module>
sys.exit(main())
File "/usr/home/hass/hass/.tox/python/lib/python3.9/site-packages/homeassistant/__main__.py", line 191, in main
exit_code = runner.run(runtime_conf)
File "/usr/home/hass/hass/.tox/python/lib/python3.9/site-packages/homeassistant/runner.py", line 119, in run
return loop.run_until_complete(setup_and_run_hass(runtime_config))
File "/usr/local/lib/python3.9/asyncio/base_events.py", line 634, in run_until_complete
self.run_forever()
File "/usr/local/lib/python3.9/asyncio/base_events.py", line 601, in run_forever
self._run_once()
File "/usr/local/lib/python3.9/asyncio/base_events.py", line 1897, in _run_once
handle._run()
File "/usr/local/lib/python3.9/asyncio/events.py", line 80, in _run
self._context.run(self._callback, *self._args)
File "/usr/home/hass/hass/.tox/python/lib/python3.9/site-packages/aioesphomeapi/reconnect_logic.py", line 171, in _reconnect_loop
await self._reconnect_once()
File "/usr/home/hass/hass/.tox/python/lib/python3.9/site-packages/aioesphomeapi/reconnect_logic.py", line 166, in _reconnect_once
await self._try_connect()
File "/usr/home/hass/hass/.tox/python/lib/python3.9/site-packages/aioesphomeapi/reconnect_logic.py", line 121, in _try_connect
await self._cli.connect(on_stop=self._on_disconnect, login=True)
File "/usr/home/hass/hass/.tox/python/lib/python3.9/site-packages/aioesphomeapi/client.py", line 240, in connect
await self._connection.connect(login=login)
File "/usr/home/hass/hass/.tox/python/lib/python3.9/site-packages/aioesphomeapi/connection.py", line 305, in connect
await _do_connect()
File "/usr/home/hass/hass/.tox/python/lib/python3.9/site-packages/aioesphomeapi/connection.py", line 294, in _do_connect
await self._connect_init_frame_helper()
File "/usr/home/hass/hass/.tox/python/lib/python3.9/site-packages/aioesphomeapi/connection.py", line 205, in _connect_init_frame_helper
asyncio.create_task(self._process_loop())
File "/usr/local/lib/python3.9/asyncio/tasks.py", line 361, in create_task
task = loop.create_task(coro)
It is not clear to me how to build code based on if the state gets disconnected, because i can't find any documentation on this topic. How can i retry a connection on disconnect, or build logic when the connection to the ESP device is lost?
I'm encountering this error enumerating the entities of my climate device.
This problem is occurring within Homeassistant as well (see logs).
asyncio
funkiness because I'm running in Jupyter.
Successfully installed aioesphomeapi-2.8.0
import nest_asyncio
nest_asyncio.apply()
import aioesphomeapi
import asyncio
async def main():
"""Connect to an ESPHome device and get details."""
loop = asyncio.get_running_loop()
# Establish connection
api = aioesphomeapi.APIClient(loop, "prusa_enclosure.local", 6053, "")
await api.connect(login=True)
# Get API version of the device's firmware
print(api.api_version)
# Show device details
device_info = await api.device_info()
# List all entities of the device
entities = await api.list_entities_services()
for entity in entities[0]:
print(entity)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
APIVersion(major=1, minor=4)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-2-764d321eea0b> in <module>
25
26 loop = asyncio.get_event_loop()
---> 27 loop.run_until_complete(main())
~/.venv3/lib/python3.9/site-packages/nest_asyncio.py in run_until_complete(self, future)
68 raise RuntimeError(
69 'Event loop stopped before Future completed.')
---> 70 return f.result()
71
72 def _run_once(self):
/usr/lib/python3.9/asyncio/futures.py in result(self)
199 self.__log_traceback = False
200 if self._exception is not None:
--> 201 raise self._exception
202 return self._result
203
/usr/lib/python3.9/asyncio/tasks.py in __step(***failed resolving arguments***)
254 # We use the `send` method directly, because coroutines
255 # don't have `__iter__` and `__next__` methods.
--> 256 result = coro.send(None)
257 else:
258 result = coro.throw(exc)
<ipython-input-2-764d321eea0b> in main()
19
20 # List all entities of the device
---> 21 entities = await api.list_entities_services()
22 for entity in entities[0]:
23 print(entity)
~/.venv3/lib/python3.9/site-packages/aioesphomeapi/client.py in list_entities_services(self)
135 for key, _ in attr.fields_dict(cls).items():
136 kwargs[key] = getattr(msg, key)
--> 137 entities.append(cls(**kwargs))
138 return entities, services
139
~/.venv3/lib/python3.9/site-packages/aioesphomeapi/model.py in __init__(self, object_id, key, name, unique_id, supports_current_temperature, supports_two_point_target_temperature, supported_modes, visual_min_temperature, visual_max_temperature, visual_temperature_step, supports_away, supports_action, supported_fan_modes, supported_swing_modes)
7 self.supports_two_point_target_temperature = supports_two_point_target_temperature
8 if supported_modes is not NOTHING:
----> 9 self.supported_modes = __attr_converter_supported_modes(supported_modes)
10 else:
11 self.supported_modes = __attr_converter_supported_modes(__attr_factory_supported_modes())
~/.venv3/lib/python3.9/site-packages/aioesphomeapi/model.py in _convert_climate_modes(value)
243
244 def _convert_climate_modes(value):
--> 245 return [ClimateMode(val) for val in value]
246
247
~/.venv3/lib/python3.9/site-packages/aioesphomeapi/model.py in <listcomp>(.0)
243
244 def _convert_climate_modes(value):
--> 245 return [ClimateMode(val) for val in value]
246
247
/usr/lib/python3.9/enum.py in __call__(cls, value, names, module, qualname, type, start)
358 """
359 if names is None: # simple value lookup
--> 360 return cls.__new__(cls, value)
361 # otherwise, functional API: we're creating a new Enum type
362 return cls._create_(
/usr/lib/python3.9/enum.py in __new__(cls, value)
675 ve_exc = ValueError("%r is not a valid %s" % (value, cls.__qualname__))
676 if result is None and exc is None:
--> 677 raise ve_exc
678 elif exc is None:
679 exc = TypeError(
ValueError: 6 is not a valid ClimateMode
esphome:
name: prusa_enclosure
platform: ESP32
board: esp32dev
wifi:
ssid: ""
password: ""
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Prusa Enclosure Fallback Hotspot"
password: ""
captive_portal:
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
output:
- platform: ledc
pin: GPIO32
id: fan_output
frequency: "25kHz"
- platform: template
id: fan_output_scaled
type: float
write_action:
- output.set_level:
id: fan_output
level: !lambda |-
return (state ? state*.55+.20 : 0);
light:
- platform: monochromatic
name: "Enclosure fan"
output: fan_output_scaled
gamma_correct: 1
default_transition_length: 0s
- platform: fastled_clockless
chipset: WS2812B
pin: GPIO26
num_leds: 68
rgb_order: GRB
name: "Enclosure light"
sensor:
- platform: pulse_counter
pin: GPIO33
name: 'Fan speed'
filters:
- multiply: 0.5
update_interval: 1s
- platform: dht
pin: 25
temperature:
name: "Enclosure temperature"
id: "enclosure_temp"
unit_of_measurement: "°C"
humidity:
name: "Enclosure humidity"
update_interval: 1s
model: DHT22
climate:
- platform: pid
name: "Enclosure PID controller"
id: pid_enclosure
sensor: enclosure_temp
default_target_temperature: 26.00C
cool_output: fan_output
control_parameters:
kp: 0.25000
ki: 0.00150
kd: 0.15000
switch:
- platform: template
name: "PID Autotune"
turn_on_action:
- climate.pid.autotune:
id: pid_enclosure
noiseband: 0.10
negative_output: -75%
2021-06-16 09:15:10 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/components/esphome/__init__.py", line 214, in on_login
entity_infos, services = await cli.list_entities_services()
File "/usr/local/lib/python3.8/site-packages/aioesphomeapi/client.py", line 137, in list_entities_services
entities.append(cls(**kwargs))
File "<attrs generated init aioesphomeapi.model.ClimateInfo>", line 9, in __init__
self.supported_modes = __attr_converter_supported_modes(supported_modes)
File "/usr/local/lib/python3.8/site-packages/aioesphomeapi/model.py", line 245, in _convert_climate_modes
return [ClimateMode(val) for val in value]
File "/usr/local/lib/python3.8/site-packages/aioesphomeapi/model.py", line 245, in <listcomp>
return [ClimateMode(val) for val in value]
File "/usr/local/lib/python3.8/enum.py", line 339, in __call__
return cls.__new__(cls, value)
File "/usr/local/lib/python3.8/enum.py", line 662, in __new__
raise ve_exc
ValueError: 6 is not a valid ClimateMode
I previously fixed on of the leaks on cancel but we have other places we add them. We should use a try/finally pattern to avoid leaking on cancelation
aioesphomeapi/aioesphomeapi/api_pb2.py
Line 202 in 9cfe819
I'm GitHub newbie and I don't know if anyone will see my message in the closed issue. So I made new one.
There is some discrepancy in the LOG_LEVEL constants of ESPHome and aioesphomeapi:
In ESPHome core/log.h
#define ESPHOME_LOG_LEVEL_NONE 0
#define ESPHOME_LOG_LEVEL_ERROR 1
#define ESPHOME_LOG_LEVEL_WARN 2
#define ESPHOME_LOG_LEVEL_INFO 3
#define ESPHOME_LOG_LEVEL_CONFIG 4
#define ESPHOME_LOG_LEVEL_DEBUG 5
#define ESPHOME_LOG_LEVEL_VERBOSE 6
#define ESPHOME_LOG_LEVEL_VERY_VERBOSE 7
In aioesphomeapi api_pb2.py
...
_descriptor.EnumValueDescriptor(
name='LOG_LEVEL_INFO', index=3, number=3,
serialized_options=None,
type=None),
_descriptor.EnumValueDescriptor(
name='LOG_LEVEL_DEBUG', index=4, number=4,
serialized_options=None,
type=None),
...
From LOG_LEVEL_NONE to LOG_LEVEL_INFO all constants are the same.
From LOG_LEVEL_DEBUG to LOG_LEVEL_VERY_VERBOSE all constants are reduced by 1.
There is no LOG_LEVEL_CONFIG in aioesphomeapi and this is the reason for shifting constants by one and the incorrect work of subscribe_logs(log_callback, LOG_LEVEL_DEBUG).
I'm trying to use aioesphomeapi from a Python program to drive some leds with fastled. The aim is to choose which color on which led i wanna to turn on. I was thinking of sending an array like this one : [ n_led, color_r, color_b, color_g , n_led_next, color_r, color_b, color_g ... ]
I'm confuse on how to do that, I try to read the documentation but i do not understand on how to add an argument on a call from aiesphomeapi and what to add on the YAML for my ESP.
Can somebody have an example or explain to me how to do it ?
Thanks
I have an ESP32 DevKit C board with an I2S microphone and speaker which I am trying to get to work using the ESPHome / Home Assistant voice_assistant
integration / pipeline. I have a binary_sensor
that triggers voice_assistant.start
on press and voice_assistant.end
on release, just as in the documentation. This seems to work well according to the logs:
[10:39:02][I][app:102]: ESPHome version 2023.4.4 compiled on May 10 2023, 15:09:22
[10:39:02][C][wifi:505]: WiFi:
[10:39:02][C][wifi:363]: Local MAC: C8:F0:9E:50:4C:48
[10:39:02][C][wifi:364]: SSID: [redacted]
[10:39:02][C][wifi:365]: IP Address: 192.168.30.131
[10:39:02][C][wifi:367]: BSSID: [redacted]
[10:39:02][C][wifi:368]: Hostname: 'kitchen-voice-assistant'
[10:39:02][C][wifi:370]: Signal strength: -50 dB ▂▄▆█
[10:39:02][C][wifi:374]: Channel: 10
[10:39:02][C][wifi:375]: Subnet: 255.255.255.0
[10:39:02][C][wifi:376]: Gateway: 192.168.30.1
[10:39:02][C][wifi:377]: DNS1: 192.168.30.1
[10:39:02][C][wifi:378]: DNS2: 0.0.0.0
[10:39:02][C][logger:294]: Logger:
[10:39:02][C][logger:295]: Level: DEBUG
[10:39:02][C][logger:296]: Log Baud Rate: 115200
[10:39:02][C][logger:297]: Hardware UART: UART0
[10:39:03][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'voice_button'
[10:39:03][C][gpio.binary_sensor:016]: Pin: GPIO13
[10:39:03][C][mdns:108]: mDNS:
[10:39:03][C][mdns:109]: Hostname: kitchen-voice-assistant
[10:39:03][C][ota:093]: Over-The-Air Updates:
[10:39:03][C][ota:094]: Address: kitchen-voice-assistant.local:3232
[10:39:03][C][ota:097]: Using Password.
[10:39:03][C][api:138]: API Server:
[10:39:03][C][api:139]: Address: kitchen-voice-assistant.local:6053
[10:39:03][C][api:141]: Using noise encryption: YES
[10:40:02][D][binary_sensor:036]: 'voice_button': Sending state ON
[10:40:02][D][voice_assistant:065]: Requesting start...
[10:40:02][D][voice_assistant:045]: Starting...
[10:40:02][D][voice_assistant:083]: Assist Pipeline running
[10:40:07][D][binary_sensor:036]: 'voice_button': Sending state OFF
[10:40:07][D][voice_assistant:073]: Signaling stop...
[10:40:15][D][binary_sensor:036]: 'voice_button': Sending state ON
[10:40:15][D][voice_assistant:065]: Requesting start...
[10:40:15][D][voice_assistant:045]: Starting...
[10:40:17][D][binary_sensor:036]: 'voice_button': Sending state OFF
[10:40:17][D][voice_assistant:073]: Signaling stop...
However, the HA voice assistant pipeline is never activated on the Home Assistant end, and aioesphomeapi.client
reports a "Server could not be started` error:
2023-05-16 10:38:59.321 INFO (MainThread) [aioesphomeapi.reconnect_logic] Successfully connected to kitchen-voice-assistant @ 192.168.30.131
2023-05-16 10:40:15.096 ERROR (MainThread) [aioesphomeapi.client] Server could not be started
2023-05-16 10:40:32.230 WARNING (MainThread) [homeassistant.components.esphome.voice_assistant] Pipeline timeout
This error happens on the second button press. I tried to understand the code paths involved but failed at that.
ESPHome version is 2023.4.4, Home Assistant is 2023.5.3 meaning aioesphomeapi is at version 3.7.4. I'm not running HASS, HA is running as a docker-compose
image but with network_mode: host
and privileged: true
so it should be fine for it to open UDP ports.
Here is the relevant part of my config YAML:
api:
encryption:
key: !secret api_key
binary_sensor:
- platform: gpio
pin:
number: GPIO13
inverted: true
mode:
pullup: true
input: true
id: voice_button
internal: true
filters:
- delayed_on: 10ms
- delayed_off: 10ms
on_press:
- voice_assistant.start:
on_release:
- voice_assistant.stop:
i2s_audio:
- id: i2smicrophone
i2s_lrclk_pin: GPIO27
i2s_bclk_pin: GPIO14
microphone:
- id: microphone_id
platform: i2s_audio
i2s_din_pin: GPIO26
i2s_audio_id: i2smicrophone
voice_assistant:
microphone: microphone_id
Since the error happens within aioesphomeapi.client
, I thought this would be the best venue for the bug report, but please do let me know if that should go in the HA core or ESPHome repos. Any advice would be appreciated!
This library gibes powerful access to esphome devices. Unfortunately it lacks documentation or at least some examples how to get started.
As a good start, I found: https://gist.github.com/fpletz/d071c72e45d17ba274fd61ca7a465033
Created one to fetch images from esp32cam: https://gist.github.com/micw/202f9dee5c990f0b0f7e7c36b567d92b
Was building a new version of my Docker container that is using the ESPHome API.
Upon building, the following error gets raised. This error wasn't there before, and the changes I made to my container are unrelated to the ESPHome part, so I believe something got broken recently in the API package
energy-meter-1.local: Connection error occurred: Invalid protobuf message: expected bytes, bytearray found
Fatal error: protocol.data_received() call failed.
protocol: <aioesphomeapi._frame_helper.APIPlaintextFrameHelper object at 0x7f6fedd8bb50>
transport: <_SelectorSocketTransport closing fd=6 read=idle write=<idle, bufsize=0>>
Traceback (most recent call last):
File "/usr/local/lib/python3.10/asyncio/selector_events.py", line 876, in _read_ready__data_received
self._protocol.data_received(data)
File "/usr/local/lib/python3.10/site-packages/aioesphomeapi/_frame_helper.py", line 195, in data_received
self._callback_packet(msg_type_int, packet_data)
File "/usr/local/lib/python3.10/site-packages/aioesphomeapi/_frame_helper.py", line 110, in _callback_packet
self._on_pkt(Packet(type_, data))
File "/usr/local/lib/python3.10/site-packages/aioesphomeapi/connection.py", line 581, in _process_packet
msg.ParseFromString(pkt.data)
TypeError: expected bytes, bytearray found
The ESPHome device is and ESP32 and is running on ESPHome 2022.12.3 FW
Let me know if you need any debugging or more information
My device is a bit unstable and subscribe_states() does not seem to reconnect automatically. Can I use ReconnectLogic or something?
I am using home assistant docker on a raspberry pi 4 (64bit os). HA can't connect to my esphome devices. I was able to pull this out of the logs and I am unsure how to further debug this at the moment. I will try and dig deeper in a bit, but wanted to see if anyone else had this issue. This is working just fine with home assistant docker on a x86 machine.
2022-01-26 22:11:34 DEBUG (MainThread) [aioesphomeapi.connection] 10.10.10.116: Connecting to 10.10.10.116:6053 (AddrInfo(family=<AddressFamily.AF_INET: 2>, type=<SocketKind.SOCK_STREAM: 1>, proto=6, sockaddr=IPv4S
ockaddr(address='10.10.10.116', port=6053)))
2022-01-26 22:11:34 DEBUG (MainThread) [aioesphomeapi.connection] 10.10.10.116: Opened socket for
2022-01-26 22:11:34 DEBUG (MainThread) [aioesphomeapi.connection] 10.10.10.116: Sending <class 'api_pb2.HelloRequest'>: client_info: "aioesphomeapi"
2022-01-26 22:11:34 DEBUG (MainThread) [aioesphomeapi._frame_helper] Sending plaintext frame 000f010a0d61696f657370686f6d65617069
2022-01-26 22:11:34 DEBUG (MainThread) [aioesphomeapi.connection] 10.10.10.116: Got message of type <class 'api_pb2.HelloResponse'>: api_version_major: 1
api_version_minor: 6
server_info: "sunroom-light (esphome v2022.1.1)"
2022-01-26 22:11:34 DEBUG (MainThread) [aioesphomeapi.connection] 10.10.10.116: Successfully connected ('sunroom-light (esphome v2022.1.1)' API=1.6)
2022-01-26 22:11:34 DEBUG (MainThread) [aioesphomeapi.connection] 10.10.10.116: Sending <class 'api_pb2.DeviceInfoRequest'>:
2022-01-26 22:11:34 DEBUG (MainThread) [aioesphomeapi._frame_helper] Sending plaintext frame 000009
2022-01-26 22:11:44 DEBUG (MainThread) [aioesphomeapi.connection] 10.10.10.116: Socket closed, stopping read loop
otherwise it cannot run tests in HA' environment, HA now pulls in pylint-2.6.0
During shutdown of HA I always get the following log line:
2021-06-27 18:02:31 INFO (MainThread) [aioesphomeapi.connection] 192.168.xxx.yyy: Error while reading incoming messages: Error while receiving data: 0 bytes read on a total of 1 expected bytes
Please notice that beside it should not be logged at all, it's has a Error description with INFO log level.
Simone
Traceback (most recent call last): File "C:\Users\Administrator\aio\aio\lib\site-packages\aioesphomeapi\client.py", line 176, in connect await self._connection.connect() File "C:\Users\Administrator\aio\aio\lib\site-packages\aioesphomeapi\connection.py", line 157, in connect self._socket_reader, self._socket_writer = await asyncio.open_connection( File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\asyncio\streams.py", line 52, in open_connection transport, _ = await loop.create_connection( File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py", line 1047, in create_connection raise ValueError( ValueError: A Stream Socket was expected, got <socket.socket fd=592, family=AddressFamily.AF_INET, type=0, proto=6, laddr=('192.168.2.4', 32149), raddr=('192.168.2.25', 6053)> The above exception was the direct cause of the following exception: Traceback (most recent call last): File "t.py", line 24, in <module> loop.run_until_complete(main()) File "C:\Users\Administrator\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py", line 616, in run_until_complete return future.result() File "t.py", line 10, in main await api.connect(login=True) File "C:\Users\Administrator\aio\aio\lib\site-packages\aioesphomeapi\client.py", line 184, in connect raise APIConnectionError( aioesphomeapi.core.APIConnectionError: Unexpected error while connecting to 192.168.2.25: A Stream Socket was expected, got <socket.socket fd=592, family=AddressFamily.AF_INET, type=0, proto=6, laddr=('192.168.2.4', 32149), raddr=('192.168.2.25', 6053)>
After replacing, in line 132 of connection.py
self._socket = socket.socket( family=addr.family, type=addr.type, proto=addr.proto )
with
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
The problem is fixed.
I have the native API enabled using encryption and key instead of password. The example shows connecting using password for aioesphomeapi. Do you have an example use encryption and key or can this not be done with aioesphomeapi?
It's hard to find examples online! :)
Anyone know how I'd turn an LED on? (Eventually one of a few relays)?
Here's my yaml and python code.
(With some stuff cut from the yaml, like time-server, for brevity):
---- sprinklers.yaml ------------------
esphome:
name: sprinklers
esp8266:
board: nodemcuv2
# Enable logging
logger:
api:
password: "meowmix"
reboot_timeout: 0s
services:
- service: yellow_on
then:
- switch.turn_on: yellow_pin
ota:
password: "meowmix"
captive_portal:
switch:
- platform: gpio
pin: D8
id: yellow_pin
# mode:
# input: false
# pullup: false
- platform: gpio
pin: D3
id: green_pin
- platform: gpio
id: red_pin
pin:
number: D4
mode: OUTPUT
restore_mode: ALWAYS_OFF
on_turn_on:
- logger.log: "RED On!"
on_turn_off:
- logger.log: "RED Off!"
- platform: template
name: "Yellow LED"
optimistic: yes
id: yellowled
turn_on_action:
- while:
condition:
lambda: 'return true;'
then:
- switch.turn_on: yellow_pin
- delay: 500ms
- switch.turn_off: yellow_pin
- delay: 500ms
turn_off_action:
- switch.turn_off: yellow_pin
# - platform: template
# name: "Red LED"
# optimistic: yes
# id: redled
# turn_on_action:
# - switch.turn_on: red_pin
# turn_off_action:
# - switch.turn_off: red_pin
- platform: template
name: "Green LED"
optimistic: yes
id: greenled
turn_on_action:
- switch.turn_on: green_pin
turn_off_action:
- switch.turn_off: green_pin
---------- sprinkler_led_on_test.py -------------------
#!/usr/bin/env python
import aioesphomeapi
from aioesphomeapi.model import (UserService)
import asyncio
import ipdb
async def main():
"""Connect to an ESPHome device and get details."""
# Establish connection
api = aioesphomeapi.APIClient("sprinklers.local", 6053, "meowmix")
await api.connect(login=True)
# List all entities of the device
entities = await api.list_entities_services()
print("\nEntities:")
for eli, entlist in enumerate(entities):
for ei, ent in enumerate(entlist):
print(f"[{eli}][{ei}] {ent}")
service = UserService(
name="yellow_on",
)
await api.execute_service(service, data={})
#ipdb.set_trace()
# print( [f" {i}\n" for i in entities])
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
I'm using device_class to find the device type associated to an Entity. For example, device_class=='power', it's a power-meter. This is for SensorInfo, but some component in ESPHome only support TextSensor. This is the case in example for the ble_scanner. This sounds good because it returns a JSON string, but as TextSensorInfo doesn't provide device_class, I'm unable to find if this is ble_scanner or any other TextSensor component.
Is there a way to fix this (without having to hardcode this information in another field like the name for example) ?
Best regards.
Could the timeout timeout: float = 10.0, in send_message_await_response_complex be the too short for ble response? Sometimes it takes a while to read the services and characteristics.
Thank you!
aioesphomeapi/aioesphomeapi/connection.py
Line 815 in 2df4eff
We need to log a warning here since it’s hard to track down why ble connections get left open for too long otherwise
aioesphomeapi/aioesphomeapi/connection.py
Line 154 in 284b767
It would be a safer design to set it to None after it’s called like the rest of cleanup
aioesphomeapi/aioesphomeapi/connection.py
Line 392 in 2df4eff
it’s hard to tell which one has the wrong name here when they get the ip address wrong due to a dhcp mixup
The current client needs to create two closures for each Bluetooth message.
Need to come up with a way to have a single place where futures are resolved to avoid creating the closures
DeprecationWarning: Call to deprecated create function EnumValueDescriptor(). Note: Create unlinked descriptors is going to go away. Please use get/find descriptors from generated code or query the descriptor_pool.
DeprecationWarning: Call to deprecated create function FileDescriptor(). Note: Create unlinked descriptors is going to go away. Please use get/find descriptors from generated code or query the descriptor_pool.
DeprecationWarning: Call to deprecated create function EnumDescriptor(). Note: Create unlinked descriptors is going to go away. Please use get/find descriptors from generated code or query the descriptor_pool.
DeprecationWarning: Call to deprecated create function Descriptor(). Note: Create unlinked descriptors is going to go away. Please use get/find descriptors from generated code or query the descriptor_pool.
The warning gets printed ~100 times while running the home-assistant test suite.
Just a heads up, not sure how much attention you pay to the home-assistant component tests.
Features such as on/off, selecting source, and all statuses aren't part of the esphome API.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.