The reader I am using uses a Wiegand interface. This uses 2 data lines - D0 and D1 along with a ground to transport the data. ESPHome does support the Wiegand interface. The YAML I posted above covers the Wiegand configuration for the ESP. Here is the full code, obfuscated as required of course.
esphome:
name: workshopaccesscontrol
friendly_name: WorkshopAccessControl
esp8266:
board: esp12e
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: <redacted>
ota:
- platform: esphome
password: <redacted>
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
manual_ip:
static_ip: A.B.C.D
subnet: A.B.C.D
gateway: A.B.C.D
dns1: A.B.C.D
# ShopDoor Reader
wiegand:
- id: ShopDoor
d0: GPIO5
d1: GPIO4
on_tag:
- lambda: ESP_LOGI("TAG", "received tag %s", x.c_str());
- homeassistant.tag_scanned: lambda 'return x.c_str();'
There is no I2C nor is there a binary output. The Wiegand code provides for an on_key, on_tag, and/or on_raw - on_key for keypad inputs (my device does not have a keypad), on_tag for a compatible tag read/decode (which applies to me) and on_raw which provide the bits exactly as sent from the device - no processing or decoding. The latter was immensely helpful in figuring out how to get the reader wired correctly. I now get a reliable 26-bit read, like I should. The log snippet I showed above is from the ESP device and shows a valid tag read and, what I presume, is a connection to the HA API following said read.
Here is the compile/install log, in all its glory:
Ensuring ESPHome 2026.4.5 is available...
ESPHome 2026.4.5 ready.
Invoking: /data/esphome-versions/2026.4.5/bin/esphome run /data/esphome-versions/slots/1/workshopaccesscontrol/workshopaccesscontrol.yaml --no-logs --device A.B.C.D
INFO ESPHome 2026.4.5
INFO Reading configuration /data/esphome-versions/slots/1/workshopaccesscontrol/workshopaccesscontrol.yaml...
WARNING The minimum WiFi authentication mode (wifi -> min_auth_mode) is not set. This controls the weakest encryption your device will accept when connecting to WiFi. Currently defaults to WPA (less secure), but will change to WPA2 (more secure
) in 2026.6.0. WPA uses TKIP encryption which has known security vulnerabilities and should be avoided. WPA2 uses AES encryption which is significantly more secure. To silence this warning, explicitly set min_auth_mode under 'wifi:'. If your ro
uter supports WPA2 or WPA3, set 'min_auth_mode: WPA2'. If your router only supports WPA, set 'min_auth_mode: WPA'.
INFO Generating C++ source...
INFO Compiling app... Build path: /data/esphome-versions/slots/1/workshopaccesscontrol/.esphome/build/workshopaccesscontrol
Processing workshopaccesscontrol (board: esp12e; framework: arduino; platform: platformio/[email protected])
--------------------------------------------------------------------------------
HARDWARE: ESP8266 80MHz, 80KB RAM, 4MB Flash
ESPHome: Excluding Updater.cpp from build (using native OTA backend)
ESPHome: Excluding core_esp8266_waveform_phase.cpp from build (waveform not required)
ESPHome: Excluding core_esp8266_waveform_pwm.cpp from build (waveform not required)
Dependency Graph
|-- ESP8266WiFi @ 1.0
|-- ESP8266mDNS @ 1.2
|-- noise-c @ 0.1.11
Compiling .pioenvs/workshopaccesscontrol/src/main.cpp.o
remove_scanf_float_flag([".pioenvs/workshopaccesscontrol/firmware.elf"], [".pioenvs/workshopaccesscontrol/src/esphome/components/api/api_buffer.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/api/api_connection.cpp.o", ".pioenvs/
workshopaccesscontrol/src/esphome/components/api/api_frame_helper.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/api/api_frame_helper_noise.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/api/api_overflow_buffer.c
pp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/api/api_pb2.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/api/api_pb2_service.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/api/api_server.cpp.o", "
.pioenvs/workshopaccesscontrol/src/esphome/components/api/list_entities.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/api/proto.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/api/subscribe_state.cpp.o", ".pioenv
s/workshopaccesscontrol/src/esphome/components/esp8266/core.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/esp8266/crash_handler.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/esp8266/gpio.cpp.o", ".pioenvs/works
hopaccesscontrol/src/esphome/components/esp8266/helpers.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/esp8266/preferences.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/esp8266/printf_stubs.cpp.o", ".pioenvs/wor
kshopaccesscontrol/src/esphome/components/esp8266/waveform_stubs.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/esphome/ota/ota_esphome.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/key_provider/key_provider.cpp
.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/logger/logger.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/logger/logger_esp8266.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/md5/md5.cpp.o", ".pioe
nvs/workshopaccesscontrol/src/esphome/components/mdns/mdns_component.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/mdns/mdns_esp8266.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/network/util.cpp.o", ".pioenvs/
workshopaccesscontrol/src/esphome/components/ota/ota_backend.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/ota/ota_backend_esp8266.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/ota/ota_backend_host.cpp.o", ".pi
oenvs/workshopaccesscontrol/src/esphome/components/safe_mode/safe_mode.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/sha256/sha256.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/socket/lwip_raw_tcp_impl.cpp.o",
".pioenvs/workshopaccesscontrol/src/esphome/components/socket/socket.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/wiegand/wiegand.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/components/wifi/wifi_component.cpp.o", ".pio
envs/workshopaccesscontrol/src/esphome/components/wifi/wifi_component_esp8266.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/core/application.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/core/color.cpp.o", ".pioenvs/workshopaccessco
ntrol/src/esphome/core/component.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/core/component_iterator.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/core/controller_registry.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/core/e
ntity_base.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/core/gpio.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/core/helpers.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/core/log.cpp.o", ".pioenvs/workshopaccesscontrol/src/e
sphome/core/scheduler.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/core/time.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/core/time_64.cpp.o", ".pioenvs/workshopaccesscontrol/src/esphome/core/util.cpp.o", ".pioenvs/workshopaccessc
ontrol/src/esphome/core/wake.cpp.o", ".pioenvs/workshopaccesscontrol/src/main.cpp.o"])
ESPHome: Removing _scanf_float (saves ~8KB flash)
Linking .pioenvs/workshopaccesscontrol/firmware.elf
RAM: [==== ] 37.9% (used 31036 bytes from 81920 bytes)
Flash: [==== ] 40.3% (used 420575 bytes from 1044464 bytes)
Building .pioenvs/workshopaccesscontrol/firmware.bin
esp8266_copy_factory_bin([".pioenvs/workshopaccesscontrol/firmware.bin"], [".pioenvs/workshopaccesscontrol/firmware.elf"])
esp8266_copy_ota_bin([".pioenvs/workshopaccesscontrol/firmware.bin"], [".pioenvs/workshopaccesscontrol/firmware.elf"])
========================= [SUCCESS] Took 5.29 seconds =========================
INFO Build Info: config_hash=0xe2dd9207 build_time_str=2026-05-09 19:31:47 -0400
INFO Successfully compiled program.
INFO Connecting to A.B.C.D port 8266...
INFO Connected to A.B.C.D
INFO Uploading /data/esphome-versions/slots/1/workshopaccesscontrol/.esphome/build/workshopaccesscontrol/.pioenvs/workshopaccesscontrol/firmware.bin (424720 bytes)
INFO Compressed to 304385 bytes
Uploading: [============================================================] 100% Done...
INFO Upload took 1.78 seconds, waiting for result...
INFO OTA successful
INFO Successfully uploaded program.
The big block in the middle is exactly what the compiler spit out - not sure where the breaks should be there to make it more readable.
After the compile/install (to get the above log), I monitored the log while scanning 3 different fobs. The log showed this:
[17:41:21.007][D][wiegand:075]: received 26-bit tag: 13235842
[17:41:21.007][I][TAG:036]: received tag 13235842
[17:41:37.430][D][wiegand:075]: received 26-bit tag: 13131891
[17:41:37.440][I][TAG:036]: received tag 13131891
[17:41:43.665][D][wiegand:075]: received 26-bit tag: 13131893
[17:41:43.665][I][TAG:036]: received tag 13131893
[17:41:44.756][D][wiegand:075]: received 26-bit tag: 13131893
[17:41:44.756][I][TAG:036]: received tag 13131893
[17:42:53.955][D][api:220]: Accept 192.168.6.110
[17:42:56.058][D][api.connection:2409]: aioesphomeapi (192.168.6.110): connected
[17:42:56.059][D][api.connection:2409]: aioesphomeapi (192.168.6.110): disconnected
Looking at those time stamps, there was over a minute from the time tag 3 was scanned until the API connection is shown - then 3 seconds from the Accept message to the connected message, and 1mS from connected to disconnected.
The reader I am using is for 125kHz RFID access tags. It takes a 12V power supply, and provides 5V TTL logic outputs for the D0 and D1 lines. Given the data I see in the log for the 'received tag' message and the data encoded in the tag I scanned matching, I feel fairly safe in assuming the reading of the tag is working as it should. Sending that data to HA, however, does not appear to be working.
The RDM6300 link is where I got the output format from for sending the tag data to HA, modified to fit the data returned by my specific reader. Specifically the second entry under this section.
rdm6300:
# ...
on_tag:
then:
- homeassistant.tag_scanned: !lambda 'return to_string(x);'
The UART settings do not apply, as this does not use a UART. The on_tag format I used is from the Wiegand instructions, I just added the tag_scanned action from the rdm6300 page.
The example from the ESPHome Wiegand page:
# Example configuration entry
wiegand:
- id: mykeypad
d0: GPIOXX
d1: GPIOXX
on_key:
- lambda: ESP_LOGI("KEY", "received key %d", x);
on_tag:
- lambda: ESP_LOGI("TAG", "received tag %s", x.c_str());
on_raw:
- lambda: ESP_LOGI("RAW", "received raw %d bits, value %llx", bits, value);
I dropped the key and raw sections, as they do not apply.
I am sure I am missing something simple here - which is usually the case when I get this far in. Been working on this for over a week now, so it is entirely possible (likely even!) I am now too close to see errors that a fresh set of eyes might catch.
This is the hardware setup:
The reader is the silver component on the left. The red/black wires on the reader (and going off to the right) are the 12V reader power. The white and green from the reader are the Wiegand D0 and D1, the brown and yellow from the reader are supposed to be for LED and buzzer, neither of which I plan to use. They are stuck in the breadboard to keep them from flopping about. The USB cable on the ESP D1 mini is for power for the ESP. I have all grounds tied together (brown Dupont wire).