Hi. I am trying to connect a simple esp-h2 (esp-h2-supermini - is that relevant?) to my new thread network. The thread network seems to be working fine, and the flashing of esp-h2 as well. But the esp-h2 doesn’t join the network nor I see anything like valid logs at it. I checked all of these:
- ESPHome 2025.6 adds OpenThread support | Matter Alpha
- esphome 2025.6.2 and openthread component · Issue #7200 · esphome/issues · GitHub
- Thread working on ESP32-H2 - Example Project - #11
- OpenThread Component — ESPHome
and seemingly I am doing exactly the same thing, but I don’t see the board cooperating.
My config is simply:
esphome:
name: h2alpha
friendly_name: h2alpha
esp32:
board: esp32-h2-devkitm-1 # maybe this is wrong, as I have supermini ?
variant: ESP32H2
framework:
type: esp-idf
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
- platform: esphome
network:
enable_ipv6: true
openthread:
# tlv: 0e08000000000001000000030000194a0300001935060004001fffe002085d6cb48f82003d94070...c0402a0f7f8 # used this one originally as it seems dead simple, but same result
# device_type: MTD # tried switching from FTD to MTD, no difference
channel: 25
network_name: openthread-iota
network_key: 0x35...aa605c9
pan_id: 0x4..8
ext_pan_id: 0x5d6c...3d94
pskc: "0x2fca54...e7a3c"
force_dataset: true
# found this on the github, it actually doesn't work though - the board doesn't output anything
text_sensor:
- platform: openthread_info
ip_address:
name: "Off-mesh routable IP Address"
channel:
name: "Channel"
role:
name: "Device Role"
rloc16:
name: "RLOC16"
ext_addr:
name: "Extended Address"
eui64:
name: "EUI64 Interface ID"
network_name:
name: "Network Name"
network_key:
name: "Network Key"
pan_id:
name: "PAN ID"
ext_pan_id:
name: "Extended PAN ID"
When I install the above and flash it to the board, I only get:
[22:34:24]ESP-ROM:esp32h2-20221101
[22:34:24]Build:Nov 1 2022
[22:34:24]rst:0xc (SW_CPU),boot:0x8 (SPI_FAST_FLASH_BOOT)
[22:34:24]Saved PC:0x400031b6
[22:34:24]SPIWP:0xee
[22:34:24]mode:DIO, clock div:1
[22:34:24]load:0x408460e0,len:0x1894
[22:34:24]load:0x4083cad0,len:0xf20
[22:34:24]load:0x4083efd0,len:0x2dc0
[22:34:24]entry 0x4083cad0
[22:34:24]I (22) boot: ESP-IDF 5.3.2 2nd stage bootloader
[22:34:24]I (22) boot: compile time Aug 7 2025 21:55:44
[22:34:24]I (24) boot: chip revision: v0.1
[22:34:24]I (25) boot: efuse block revision: v0.3
[22:34:24]I (29) boot.esp32h2: SPI Speed : 64MHz
[22:34:24]I (34) boot.esp32h2: SPI Mode : DIO
[22:34:24]I (39) boot.esp32h2: SPI Flash Size : 4MB
[22:34:24]I (43) boot: Enabling RNG early entropy source...
[22:34:24]I (49) boot: Partition Table:
[22:34:24]I (52) boot: ## Label Usage Type ST Offset Length
[22:34:24]I (60) boot: 0 otadata OTA data 01 00 00009000 00002000
[22:34:24]I (67) boot: 1 phy_init RF data 01 01 0000b000 00001000
[22:34:24]I (75) boot: 2 app0 OTA app 00 10 00010000 001c0000
[22:34:24]I (82) boot: 3 app1 OTA app 00 11 001d0000 001c0000
[22:34:24]I (89) boot: 4 nvs WiFi data 01 02 00390000 0006d000
[22:34:24]I (97) boot: End of partition table
[22:34:24]I (101) esp_image: segment 0: paddr=00010020 vaddr=420a0020 size=1dc9ch (122012) map
[22:34:24]I (160) esp_image: segment 1: paddr=0002dcc4 vaddr=40800000 size=02354h ( 9044) load
[22:34:24]I (166) esp_image: segment 2: paddr=00030020 vaddr=42000020 size=90e5ch (593500) map
[22:34:24]I (409) esp_image: segment 3: paddr=000c0e84 vaddr=40802354 size=0a498h ( 42136) load
[22:34:24]I (431) esp_image: segment 4: paddr=000cb324 vaddr=4080c7f0 size=01b44h ( 6980) load
[22:34:24]I (443) boot: Loaded app from partition at offset 0x10000
[22:34:24]I (444) boot: Disabling RNG early entropy source...
[22:34:24]I (456) cpu_start: Unicore app
[22:34:24]I (465) cpu_start: Pro cpu start user code
[22:34:24]I (465) cpu_start: cpu freq: 96000000 Hz
[22:34:24]I (466) app_init: Application information:
[22:34:24]I (468) app_init: Project name: h2alpha
[22:34:24]I (473) app_init: App version: 2025.7.5
[22:34:24]I (477) app_init: Compile time: Aug 7 2025 22:12:38
[22:34:24]I (483) app_init: ELF file SHA256: 3e28fb491...
[22:34:24]I (489) app_init: ESP-IDF: 5.3.2
[22:34:24]I (493) efuse_init: Min chip rev: v0.0
[22:34:24]I (498) efuse_init: Max chip rev: v0.99
[22:34:24]I (503) efuse_init: Chip rev: v0.1
[22:34:24]I (508) heap_init: Initializing. RAM available for dynamic allocation:
[22:34:24]I (515) heap_init: At 40815780 len 00037C00 (223 KiB): RAM
[22:34:24]I (521) heap_init: At 4084D380 len 00002B60 (10 KiB): RAM
[22:34:24]I (529) spi_flash: detected chip: generic
[22:34:24]I (532) spi_flash: flash io: dio
[22:34:24]I (537) sleep: Configure to isolate all GPIO pins in sleep state
[22:34:24]I (543) sleep: Enable automatic switching of GPIO sleep configuration
[22:34:24]I (550) main_task: Started on CPU0
[22:34:24]I (554) main_task: Calling app_main()
[22:34:24]I (714) main_task: Returned from app_main()
and then nothing.
I computed the pskc when trying to do it manually via this LLM written function based on the docs:
#!/usr/bin/env python3
"""
OpenThread PSKc Generator
Generates PSKc from Commissioner Credential/Passphrase
Compatible with OpenThread specification
"""
import hashlib
import binascii
from typing import Union
def generate_pskc(passphrase: str, ext_pan_id: Union[str, bytes], network_name: str) -> str:
"""
Generate PSKc using PBKDF2 as per Thread specification
Args:
passphrase: Commissioner Credential (e.g., "j01Nme")
ext_pan_id: Extended PAN ID in hex string or bytes
network_name: Network name string
Returns:
PSKc as hex string
"""
# Convert ext_pan_id to bytes if it's a string
if isinstance(ext_pan_id, str):
ext_pan_id = ext_pan_id.replace('0x', '').replace(':', '')
ext_pan_id_bytes = bytes.fromhex(ext_pan_id)
else:
ext_pan_id_bytes = ext_pan_id
# Create salt: Extended PAN ID + Network Name
salt = ext_pan_id_bytes + network_name.encode('utf-8')
# Generate PSKc using PBKDF2
# Thread uses 16384 iterations and generates 16 bytes
pskc_bytes = hashlib.pbkdf2_hmac(
'sha256', # Hash algorithm
passphrase.encode('utf-8'), # Password
salt, # Salt
16384, # Iterations (Thread specification)
16 # Key length in bytes
)
return binascii.hexlify(pskc_bytes).decode('ascii')
def main():
# Your network parameters
passphrase = "j01Nme"
ext_pan_id = "5d6cb48f82003d94"
network_name = "openthread-iota"
print("OpenThread PSKc Generator")
print("=" * 50)
print(f"Passphrase/Commissioner Credential: {passphrase}")
print(f"Extended PAN ID: {ext_pan_id}")
print(f"Network Name: {network_name}")
print("=" * 50)
# Generate PSKc
pskc = generate_pskc(passphrase, ext_pan_id, network_name)
print(f"\nGenerated PSKc: {pskc}")
print(f"PSKc (with 0x prefix): 0x{pskc}")
# Compare with the value from TLV
expected_pskc = "3b04ec0f77e42cfe2e7fc2b4ad094e49"
print(f"\nExpected PSKc from TLV: {expected_pskc}")
if pskc == expected_pskc:
print("✓ PSKc matches! The generation is correct.")
else:
print("✗ PSKc doesn't match. There might be a configuration issue.")
print("\n" + "=" * 50)
print("ESPHome Configuration:")
print("=" * 50)
print(f"""
openthread:
channel: 25
network_name: "{network_name}"
network_key: "0x35b078634e77cdea5ba51ee14aa605c9"
pan_id: 0x42a8
ext_pan_id: "0x{ext_pan_id}"
pskc: "0x{pskc}"
device_type: MTD # or FTD
""")
if __name__ == "__main__":
main()
My Passphrase/Commissioner Credential when forming the network via this guide is lowercased string of two words - does it have to be something else.
By the way essentially the same config with esp32-c6 supermini works just fine.
What am I doing wrong? Thanks!


