ESPHome Integration
This integration could allow ESPHome devices to connect directly to Gladys using the native ESPHome API.
There are solutions to connect your ESP via MQTT, but with the integration it would be direct.
ESPHome Integration
This integration could allow ESPHome devices to connect directly to Gladys using the native ESPHome API.
There are solutions to connect your ESP via MQTT, but with the integration it would be direct.
I’m sure we could make a super simple Matterbridge plugin for that ![]()
ESPHome plugin developed on Matterbridge!
Isn’t this unlocked by this?
Otherwise, we could do an external Gladys integration ![]()
Anyone doing an external ESPHome integration? ![]()
I ran Claude on it, it gave me something but I have no way to control it on my end.
Good evening @pierre-gilles and @Will_71
If I can be of any help with ESPHome, I’m at your disposal.
I would like to once again warmly thank @pierre-gilles for the lead on this subject, which seems very promising in my case!
Have a great end of the day,
Jean
Very interested too! I have several ESPHome modules at home. MQTT works, but the native API would bring mDNS discovery and automatic entity creation. With the arrival of external integrations, is this perhaps the right time? Volunteer to test.
Analyzed with the help of Claude (AI), reviewed and approved by me.
Here is the dev image for the esphome integration. I haven’t tested it because I don’t have the hardware. Thanks in advance for your tests.
Image pushed (linux/amd64 + linux/arm64):
ghcr.io/william-de71/gladys-esphome:dev
docker_image already points to this build):{
"manifest_version": 1,
"type": "device",
"name": "ESPHome",
"description": {
"en": "Control your ESPHome devices (ESP32/ESP8266) locally, over the native API.",
"fr": "Pilotez vos appareils ESPHome (ESP32/ESP8266) en local, via l'API native."
},
"version": "1.0.0",
"docker_image": "ghcr.io/william-de71/gladys-esphome:dev",
"gladys_version": ">=4.86.0",
"cover_image": "https://raw.githubusercontent.com/William-De71/gladys-esphome/master/cover.jpg",
"categories": [
"protocols",
"environment",
"lighting"
],
"transports": [
"local"
],
"network_discovery": [
{
"type": "mdns",
"service": "_esphomelib._tcp"
}
],
"config_schema": [
{
"key": "intro",
"type": "section",
"label": {
"en": "Getting started",
"fr": "Pour commencer"
},
"description": {
"en": "This integration talks to your ESPHome nodes on your local network, through their native API (port 6053). Paste your encryption key below, then go to the Discover screen and run a scan: the nodes found on your network appear there with all their entities, ready to be added. No IP address to type.",
"fr": "Cette intégration communique avec vos nœuds ESPHome sur votre réseau local, via leur API native (port 6053). Collez votre clé de chiffrement ci-dessous, puis allez dans l'écran Découverte et lancez un scan : les nœuds trouvés sur votre réseau y apparaissent avec toutes leurs entités, prêts à être ajoutés. Aucune adresse IP à saisir."
},
"links": [
{
"url": "https://esphome.io/components/api.html",
"label": {
"en": "ESPHome native API documentation",
"fr": "Documentation de l'API native ESPHome"
}
}
]
},
{
"key": "encryption_key",
"type": "secret",
"label": {
"en": "Encryption key",
"fr": "Clé de chiffrement"
},
"description": {
"en": "The base64 key declared under `api: encryption: key:` in your ESPHome YAML. Used for every node that has no specific key below. Leave empty only if your nodes have no encryption.",
"fr": "La clé base64 déclarée sous `api: encryption: key:` dans votre YAML ESPHome. Utilisée pour tous les nœuds n'ayant pas de clé spécifique ci-dessous. À laisser vide uniquement si vos nœuds n'ont pas de chiffrement."
},
"placeholder": {
"en": "kBv1s2f...=",
"fr": "kBv1s2f...="
},
"required": false
},
{
"key": "advanced",
"type": "section",
"label": {
"en": "Nodes with a different key",
"fr": "Nœuds avec une clé différente"
},
"description": {
"en": "Fill the two fields below only if some nodes do not share the key above, or if a node is not found by the network scan (another VLAN, mDNS filtered by your router).",
"fr": "Ne remplissez les deux champs ci-dessous que si certains nœuds ne partagent pas la clé ci-dessus, ou si un nœud n'est pas trouvé par le scan réseau (autre VLAN, mDNS filtré par votre routeur)."
}
},
{
"key": "encryption_keys",
"type": "secret",
"label": {
"en": "Keys per node",
"fr": "Clés par nœud"
},
"description": {
"en": "One node per line, in the form `node|key`. The node name is the one from your ESPHome YAML (`esphome: name:`), or its address. These keys take precedence over the key above.",
"fr": "Un nœud par ligne, sous la forme `nœud|clé`. Le nom du nœud est celui de votre YAML ESPHome (`esphome: name:`), ou son adresse. Ces clés sont prioritaires sur la clé ci-dessus."
},
"placeholder": {
"en": "salon|kBv1s2f...=\nkitchen|9xQm4Zt...=",
"fr": "salon|kBv1s2f...=\ncuisine|9xQm4Zt...="
},
"required": false
},
{
"key": "nodes",
"type": "string",
"label": {
"en": "Nodes added by hand",
"fr": "Nœuds ajoutés à la main"
},
"description": {
"en": "One address per line (`salon.local`, `192.168.1.42`, or `192.168.1.42:6053`), for the nodes the network scan does not find. Nodes found by the scan need nothing here.",
"fr": "Une adresse par ligne (`salon.local`, `192.168.1.42`, ou `192.168.1.42:6053`), pour les nœuds que le scan réseau ne trouve pas. Les nœuds trouvés par le scan n'ont rien à faire ici."
},
"placeholder": {
"en": "salon.local\n192.168.1.42:6053",
"fr": "salon.local\n192.168.1.42:6053"
},
"required": false
},
{
"key": "scan_duration",
"type": "number",
"label": {
"en": "Discovery duration (s)",
"fr": "Durée de la découverte (s)"
},
"description": {
"en": "How long the mDNS scan listens for ESPHome nodes on the network.",
"fr": "Durée pendant laquelle le scan mDNS écoute les nœuds ESPHome sur le réseau."
},
"required": false,
"default": 8,
"min": 3,
"max": 30
},
{
"key": "connection_timeout",
"type": "number",
"label": {
"en": "Connection timeout (s)",
"fr": "Délai d'attente de connexion (s)"
},
"description": {
"en": "How long to wait for a node to answer before giving up on it.",
"fr": "Temps d'attente pour qu'un nœud réponde avant de l'abandonner."
},
"required": false,
"default": 10,
"min": 5,
"max": 60
}
],
"actions": [
{
"key": "test_connection",
"label": {
"en": "Test the connection",
"fr": "Tester la connexion"
},
"timeout_seconds": 60
},
{
"key": "reconnect",
"label": {
"en": "Reconnect the nodes",
"fr": "Reconnecter les nœuds"
},
"timeout_seconds": 60
}
]
}
Hello @Will_71,
Thanks for this integration ![]()
Could you, however, provide more information about the configuration and usage of this integration, as it seems to only target WiFi devices (you specify port 6053).
In my specific case, I want to use ESPHome on Zigbee-only devices, so I fear there may be some confusion on my part…
Have a nice end of the day,
Jean
You need to give me all the use cases you have, because I don’t have devices of this type. So, I just ran Claude on it.
So, with your use cases, we can guide Claude.
In Zigbee? Can’t you integrate them into Zigbee2MQTT? What do you expect from the integration then?
I just found an old automatic cat food dispenser. The electronic board is probably dead, but the motor still works (as far as I remember, it runs on 9 V).
I would like to take this opportunity to put it back into service with a small ESP8266 + ESPHome, simply controlling the motor ON/OFF, and above all testing the ESPHome integration currently under development for Gladys.
I already have a few ESP8266s lying around, so I don’t need much to get started.
I also came across this project for an e-ink screen integrated into the decor: https://community.home-assistant.io/t/use-esphome-with-e-ink-displays-to-blend-in-with-your-home-decor/435428 — I think it’s really very cool!
Could this type of screen also be used with Gladys via ESPHome?
If anyone has already used ESPHome with Gladys or has tips for this kind of DIY, I’m all ears! ![]()
Hi @b3n.0
Your two topics have quite different answers, so I’m separating them.
The kibble dispenser: this is the nominal case, it already works. A switch: in your YAML, ESPHome directly sends an on/off switch to Gladys, without any configuration. For a 9 V motor, ESP8266 + a relay module (or a MOSFET if you want it quiet) and you declare:
switch:
- platform: gpio
pin: D1
name: "Kibble dispenser"
id: motor
A tip: rather add an on_turn_on with a delay then automatic shutdown, this avoids leaving the motor running if a Gladys scene crashes. And power the motor separately from the ESP8266 — a starting motor drops the voltage and the ESP reboots.
If you test this, your feedback interests me greatly: I don’t have any ESPHome hardware on my side, so I’m developing blind. Knowing that the basic path really works on real hardware would be the most useful feedback I could receive.
The e-ink screen: very good question, and the answer is less obvious than it seems.
The key point: in ESPHome, a screen is not an entity. The display: component is entirely local to the firmware - it’s your YAML that draws, via lambdas. Nothing is exposed on the native API, so there’s nothing that Gladys can « discover » or control directly.
The Home Assistant project you mention actually works by ricochet: the firmware declares input entities that HA feeds, and the display: lambda reads these values to draw. It’s not HA that controls the screen, it’s the ESP that reads the values and draws itself.
And that’s perfectly doable with Gladys. I just added support for the text entity in writing for this specific case (it was ignored until now). The principle:
text:
- platform: template
name: "Screen message"
optimistic: true
mode: text
id: screen_message
display:
- platform: waveshare_epaper
# ... lambda: |-
it.printf(0, 0, id(my_font), "%s", id(screen_message).state.c_str());
You get a text feature that can be modified in Gladys: you write « Yellow trash tomorrow », the ESP receives the string and redraws. Gladys scenes can therefore feed the screen.
Note: number: entities were already supported in writing. So if you want to display numerical values, you can start experimenting right away, without waiting for the next image.
Two warnings about e-ink, to avoid unpleasant surprises: these screens have a limited number of full refreshes and each refresh takes several seconds — so we update per minute or per event, never continuously. And check that your model is in the ESPHome waveshare_epaper list before buying, not all are supported.
If you get started, I’m interested in your feedback — it’s exactly the kind of concrete use case for integration.
The test image is the same, if already installed just force the update.
Hi @Will_71
Thanks for your two responses and for the work on the ESPHome integration! ![]()
While looking for ESP projects, I found the e-ink screen really cool. I don’t have one on hand right now to test this kind of thing, but I’m definitely keeping the idea in mind for later. ![]()
And thanks also for your advice regarding the pet feeder.
Since you indicated you weren’t equipped to test it, I used a small NodeMCU v2 ESP8266.
I installed ESPHome Device Builder, created a first device test-esphome with the standard configuration:
esphome:
name: test-esphome
friendly_name: test-esphome
esp8266:
board: nodemcuv2
logger:
api:
encryption:
key: "..."
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
ap:
ssid: test-esphome Fallback Hotspot
password: "..."
captive_portal:
I flashed the ESP via USB from ESPHome Device Builder.
It connects correctly to Wi-Fi and gets:
IP Address: 192.168.0.39
Hostname: test-esphome
Signal strength: -49 dBm
My Gladys is at 192.168.0.36.
I even tried later to manually add the node in the configuration:
192.168.0.39:6053
Other info, the ESP logs clearly show that Gladys is able to connect to its API:
Accept 192.168.0.36
esphome-client (192.168.0.36): connected
So the network and port 6053 seem OK.
On the other hand, then it gets quite strange:
Accept 192.168.0.36
esphome-client (192.168.0.36): connected
Accept 192.168.0.36
esphome-client (192.168.0.36): connected
...
Max connections (4), rejecting 192.168.0.36
Then several:
Reading failed CONNECTION_CLOSED errno=11
The ESP indicates:
API:
Address: test-esphome.local:6053
Max connections: 4
Noise encryption: YES
The final result on the Gladys side remains:
No device discovered yet.
While the ESP clearly sees Gladys connecting.
I don’t know if we can draw any conclusions…
Thanks again for developing this integration!
Okay, thank you for the test. As soon as a fix is ready, I’ll let you know.
Thank you very much!
Hi @b3n.0
Your feedback was extremely helpful — it contained exactly the right clues. I found the problem, and it wasn’t your hardware, your config, or your encryption key. Your installation was good from the start.
What was happening
Your test-esphome YAML doesn’t declare any entity: api, ota, wifi, logger, and that’s it. It’s the default YAML of ESPHome Device Builder, nothing to blame you for.
But my code was simply discarding any node that didn’t expose any usable functionality. The connection was successful — that’s what your ESP logs showed (esphome-client (192.168.0.36): connected), the encrypted handshake passed without issue — but the node was discarded right after, in silence. Result on Gladys side: « No device discovered », indistinguishable from a bad key or an unreachable ESP.
That’s also why manually adding 192.168.0.39:6053 didn’t change anything: the problem was downstream of the connection, not at the network discovery level.
The Max connections (4)
Your second symptom was a distinct bug, which your log helped identify. The client library I use retries a connection 3 times by default, i.e., 1 attempt + 3 retries = 4 sockets. And the ESPHome firmware accepts… exactly 4 API clients. A single failed scan thus saturated your ESP’s entire quota, hence the rejecting and then the CONNECTION_CLOSED errno=11. I reduced this to 1 retry (2 sockets max), which leaves room for the node while absorbing an ESP in the process of restarting.
Fixed
ESPHome node « test-esphome » (192.168.0.39:6053) is reachable but exposes no feature
Gladys can use (0 entity(ies) seen): declare an entity (switch, sensor…) in its YAML
I added a regression test that reproduces your specific case, and I verified that it failed on the old code — so that this scenario can’t slip through again.
For your next test
While waiting for the new image, you can already validate the complete path by adding an entity to your YAML. The simplest, and it’s perfect since it’s your cat feeder project:
switch:
- platform: gpio
pin: D1
name: "Cat feeder"
id: motor
You reflash, and the switch should appear directly in Gladys. That’s the feedback I’m most interested in now: knowing if the on/off command really works on real hardware. I always develop without an ESP at hand, so your tests are what’s moving this integration forward.
I’ll let you know as soon as the dev image is published.
The dev image is ready, you just need to force the update from Gladys.