V
Visla Hardware
Portal R&D
🔧 Bench tools & accessory ✓ Verified · 2026-07-16 🧪 Tested bench beacon nordic ble

Holyiot 25008 (nRF54L15)

Holyiot
📦 Dev board
€9.29
bench
🔓 SWD APERTO: core halted + firmware dumpato📡 Reflector Channel Sounding (ranging BLE 6.0)⭐ Stesso chip del Visla Tag (nRF54L15) a ~9€🔔 FIRMWARE VISLA: pulsante via BLE → campanello!🟢 Riflashato: iBeacon cinese → Matter → firmware nostro⚠️ Accel OK ma senza INT: no wake-on-motion (solo polling)
🛒 Ordine
Data ordine · 2026-06-21
Rif · AliExpress #3074783111333147
📑 Indice sezioni

Curiosity

Beacon BLE da ~9€ che è in realtà una dev board nRF54L15. Venduto come iBeacon per il posizionamento indoor (30 mm × 8.4 mm, 7 g, CR2032), monta il Nordic nRF54L15lo stesso chip scelto per il Visla Tag di produzione — con pulsante, LED RGB e accelerometro LIS2DH12.

Al banco (16/07/2026): SWD completamente aperto, core halted, firmware originale dumpato, chip riflashato. Cinque di questi beacon = cinque dev board nRF54L15 disponibili ORA (lo XIAO nRF54L15 arriva il 03/08/2026).

🛒 AliExpress — Holyiot Official Store · €9.29 · modello nRF54L15 25008

Specs

ParametroValore
SoCNordic nRF54L15 (N54L15 QFAAB0) — Cortex-M33 + TrustZone
BLE6.0 (+ Zigbee / Thread / Matter capable)
AccelerometroLIS2DH12 3 assi (I2C)
Pulsante1 (P1.13)
LEDRGB (P2.09 rosso / P1.10 verde / P2.07 blu)
AlimentazioneCR2032
DimensioniØ 30 mm × 8.4 mm · 7 g
Cristalli32 MHz (HFXO) + 32.768 kHz (LFXO)
ProgrammazioneSWD — 4 pad · ⚠️ nessun DFU sul firmware di serie
Consumo (firmware custom)~6 µA medi → ~4 anni su CR2032 (fonte: power profiling uAmpHome)

Varianti Holyiot nRF54L15 (⚠️ modelli diversi, hardware diverso — verificare sempre la serigrafia del PCB):

ModelloPulsanteBuzzerAccelAltro
25008✅ P1.13LIS2DH12 (tap rotto)“button only”
25015+ SHT40 temp/umidità
25027NOP1.06LIS2DH12serigrafia HOLYIOT-25027-V1.0

⚠️ Il buzzer P1.06 del 25027 non è documentato e non ha board Zephyr: trovato al banco con una web page che scriveva nella RAM via J-Link a chip acceso (firmware). 🚩 Compilare per holyiot_25008 una board 25027 funziona ma mente: sw0 esiste nel devicetree e il codice aspetta un pulsante inesistente.

🔓 SWD: il chip è APERTO

Quattro pad serigrafati sul PCB, dall’alto: VDD / GND / DIO / CLK.

J-Link (20 pin)Beacon
pin 1 VTrefVDD⚠️ solo lettura del livello → la CR2032 resta inserita
pin 4 GNDGND
pin 7 SWDIODIO
pin 9 SWCLKCLK

Esito con J-Link V9.8 PLUS + JLinkExe V9.24a (il device nRF54L15_M33 è nel DB dalla V9.24):

VTref = 3.300 V
Device "NRF54L15_M33" selected
Found SW-DP with ID 0x6BA02477
AP[0]: Core found              ← ✅ APPROTECT NON ATTIVO

Core halted, registri Cortex-M33 letti dal vivo (SP=0x20007DA8, TrustZone attivo).

💡 VTref non alimenta: dice solo al J-Link a che livello logico parlare.

💾 Backup del firmware stock — preso PRIMA di scrivere

printf "device nRF54L15_M33\nif SWD\nspeed 4000\nconnect\nhalt\n\
savebin holyiot_25008_stock.bin,0x00000000,0x17D000\nexit\n" | JLinkExe -nogui 1
1524 KB · 222 KB non vuoti (14.6%)
f0 7d 00 20 | f5 2d 00 00 | a1 3b 00 00 ...   ← vettore ARM Cortex-M corretto
stringhe: 'clock@10e000'                       ← nodo DEVICETREE

Il firmware Holyiot è già Zephyr. Dump in test-moduli/holyiot-beacon-zephyr/backup/ (repo). Ripristino con loadbin ...,0.

🟢 Riflashato: da iBeacon cinese a Matter

Binari precompilati di uAmpHome/micro_matter_button (video) — niente SDK da installare:

erase → loadfile micro_matter_button_h25008_om2.hex → r → g

Verifica in aria:

PRIMA:  5 iBeacon 'NexBeacon Pro' / 'Holy-IOT' / 'B2-S'
DOPO:   4 iBeacon  +  🟢 'MatterSwitch' RSSI -67, service 0xFFF6
                        0000fff6-...: 00 00 0f f1 ff 04 80 00

⚠️ verifybin vuole un .bin: su un .hex fallisce con Expected 3A read 20 (3A = : ASCII, prima lettera dell’Intel HEX). Usare loadfile, che verifica da sé (Contents already match).

Alternativa senza J-Link: XIAO RP2040/Pico con picoprobe + clip a molle 4P passo 1.5 mm (niente saldature) → pyocd load ... -t nrf54l. Cablaggio: GP2→SWCLK, GP3→SWDIO, GND→GND, 3V3→VCC (opzionale, o si usa la CR2032).

Le due modalità (si sceglie il binario, niente ricompilazione):

AccelerometroNote
om1 — Dimmable switchusato: double-click → sveglia l’accel → ruoti = regoli la lucerichiede binding Matter
om2 — Generic switchspento al boot✅ nessun binding: Apple/Google/Alexa/HA

⚠️ Al banco ho flashato la om2 → accelerometro spento. Per giocare col LIS2DH12 serve la om1.

Factory reset: pulsante premuto 12 s (LED bianco lampeggia) → rilascia prima di 15 s per annullare, oltre i 15 s torna in commissioning. Pairing code Matter: 34970112332.

Il repo contiene boards/ con le definizioni per holyiot_25008 e 25015 → per firmware custom non serve la board upstream (marcata “not actively maintained”):

west build -b holyiot_25008_nrf54l15_cpuapp -- -DCONFIG_MATTER_BUTTON_MODE_1=y

Costruito con nRF Connect SDK v3.2.4. La 25015 aggiunge SHT40 (temp/umidità, funzionante) e LPS22HB (pressione, non implementato: il driver NCS assume I²C ma la board usa SPI → spento al boot).

🔔 Firmware VISLA — il pulsante esce in BLE (16/07/2026)

Quello che né Holyiot né il progetto Matter fanno: mettere lo stato del pulsante nell’advertising. Gli eventi del MatterSwitch viaggiano su Thread (serve un hub); il firmware Holyiot il pulsante non lo espone affatto. Il nostro lo trasmette in broadcast: il tag lo sente senza connettersi, senza hub.

💻 Codice: test-moduli/holyiot-beacon-zephyr/visla-beacon/ · ricevitore: test-moduli/xiao-ble-doorbell/

124 KB di firmware (contro 1.6 MB del Matter button): niente stack Thread, solo BLE broadcast.

Payload (manufacturer data 0xFFFF)

[0..1] FF FF        company ID          [8]  flags        bit0 = premuto ORA
[2]    'V'          magic Visla         [9]  press_count  +1 a ogni pressione
[3]    01           versione            [10] batteria %
[4..7] device ID    ⭐ DAL SILICIO

Reale: 56 01 81 40 3c 51 01 07 64'V' v1 · devID 81403C51 · premuto · count 7 · batt 100%

⭐ Il problema dei cloni si risolve da solo

hwinfo_get_device_id() legge l’ID di fabbrica del silicio: ogni nRF54L15 ne ha uno diverso. Niente UUID da assegnare a mano, niente app cinese, nessuno può clonarlo.

press_count: l’advertising è inaffidabile per natura

Se il tag scansiona altrove nell’istante del click, quel pacchetto lo perde. Il contatore no: al pacchetto dopo vede 7 → 9 e recupera. Verificato al banco — un rilascio perso in aria, ma il conteggio 14 → 15 è arrivato lo stesso.

Advertising adattivo

1 Hz a riposo (batteria) → 100 ms per 2 s alla pressione: un campanello a 1 Hz avrebbe fino a 1 s di ritardo. bt_le_adv_update_data() aggiorna il payload senza fermare la radio.

🐛 Il bug più istruttivo: il DEBOUNCE

Prima versione senza debounceun click = 10 din-don. Un pulsante meccanico rimbalza: una pressione = 5-10 fronti = contatore +10 = dieci suonate. Avevo scritto il codice sul comportamento ideale del pulsante, non su quello reale.

Due difese complementari:

  • beacon: DEBOUNCE_MS 200 → ignora i fronti ravvicinati. Elimina la causa.
  • ricevitore: salto contatore > 3 → suona una volta sola. Anche col debounce, un riavvio del beacon fa balzare il contatore.

L’advertising è inaffidabile: il ricevitore dev’essere robusto per conto suo.

Build

west init -m https://github.com/zephyrproject-rtos/zephyr --mr main ws && cd ws && west update   # ⚠️ ~6.6 GB
west build -p -b holyiot_25008/nrf54l15/cpuapp visla-beacon

⚠️ prj.conf deve avere CONFIG_HWINFO=y → senza: undefined reference to z_impl_hwinfo_get_device_id.

⚠️ Gotcha ricevitore: Bluefruit NON toglie il company ID

parseReportByType(MANUFACTURER_SPECIFIC_DATA) restituisce anche i 2 byte di company ID → b[0..1] = FF FF, il magic 'V' sta in b[2], non in b[0]. Avendo assunto il contrario, il beacon veniva scartato e il display restava OFF.

⚠️ Gotchas

  • 🚩 Tap detection rotto da bug hardware — ma l’accelerometro FUNZIONA. Precisazione importante: il LIS2DH12 legge il movimento benissimo (il firmware uAmpHome fa rotational dimming: ruoti il beacon e regoli la luce). A essere rotto è l’interrupt, cioè la capacità del sensore di svegliare l’MCU da solo — infatti nella Mode 1 usano il doppio click del pulsante per attivare l’accelerometro, proprio perché non può auto-svegliarsi. → Conseguenza per Visla: niente wake-on-motion — l’accelerometro va interrogato a polling, che costa corrente (il video parla di “hidden accelerometer drawing 3× too much current”). Il pulsante invece funziona. → Al banco avevo dedotto “accelerometro presente ma firmware muto”: era l’hardware, non il firmware. Terzo annuncio AliExpress della giornata che promette una feature che l’hardware non regge (cfr. -LASE vs -FASE sull’A7672E, connettore BT/WiFi sul BG95-M3).
  • ⚠️ Il pulsante NON è visibile via BLE — verificato al banco su firmware stock e su MatterSwitch: l’advertising non cambia mai. Gli eventi del pulsante Matter viaggiano su Thread, non nell’advertising. → per un “pulsante → azione” fuori da Matter serve firmware custom.
  • 🔇 La 25008 non ha cicalino“button only”). Il buzzer è su un’altra variante Holyiot.
  • Nessun DFU sul firmware di serie → si passa per forza dai pad SWD (confermato dalle recensioni).
  • 🔁 Sono tutti CLONI: stesso UUID FDA50693-A4E2-4FB1-AFCF-C6EB07647825, Major 10011, Minor 19641 — l’UUID di default più diffuso tra i beacon cinesi. Per Visla vanno resi unici, altrimenti il tag non distingue il proprietario da chiunque altro.
  • 🇨🇳 App di configurazione NexBeacon Pro, in cinese e senza documentazione (una recensione: “3 scambi di email con Holyiot per farlo funzionare”). Il nome dell’advertising è il nome dell’app → è così che si riconoscono i 25008 tra i beacon.
  • 📱 iOS/macOS filtrano gli iBeacon: qui passano solo perché usano manufacturer ID FFFF invece di quello Apple (4C00). Con l’ID ufficiale, dal Mac non si vedrebbero.
  • ⏱️ Advertising ~1 Hz → la finestra di scan del tag deve essere ≥1 s: uno scan da 100 ms beccherebbe il beacon ~1 volta su 10.

🔬 Cosa trasmette (decodificato al banco)

Il service data contiene MAC + livello batteria, senza doversi connettere:

01 | f2 28 39 2b 62 c1 | 04 | 64      →  MAC F2:28:39:2B:62:C1 · batteria 0x64 = 100%
01 | e8 10 a5 83 56 6c | 04 | 61      →  MAC E8:10:A5:83:56:6C · batteria 0x61 = 97%

→ il tag saprebbe che il beacon del proprietario si sta scaricando a costo zero.

iBeacon: TxPower@1m = −55 dBm → distanza ≈ 10^((TxPower−RSSI)/20), ~1 m verificato. Affidabile da vicino, indicativa oltre.

Espone anche la Nordic UART Service (6e400001-...) → connettibile, ma protocollo binario proprietario (8 comandi AT provati → zero risposte).

🎯 Note per Visla

  • 5 dev board nRF54L15 a ~10€ con lo stesso chip del Tag di produzione, disponibili ora.
  • 📡 FATTO: reflector Channel Sounding (21/07/2026). Riflashato col ruolo RAS reflector del sample NCS e usato come partner di ranging BLE 6.0 con la XIAO nRF54LM20A initiator → distanza phase_slope ~2 m stabile. Firmware cs-reflector-holyiot. Gotcha J-Link: pad DIO↔CLK facilissimi da invertire (VTref 3.3 V presente ma “debug port unavailable” = linee dati scambiate, non approtect); reset pin non esposto → catturare il core al boot durante il power-cycle della CR2032.
  • Per l’arm/disarm NON serve riprogrammarli: il MAC pubblico (C0:9A:C2:7D:A0:68) è già un ID stabile, e l’RSSI basta per la soglia di prossimità.
  • FATTO: firmware Visla con UUID univoco dal silicio e pulsante in broadcast BLE → campanello funzionante al banco. Per il wake-on-motion a µA serve un’altra board: qui l’accelerometro c’è e legge, ma non ha l’interrupt per svegliare l’MCU → solo polling.
  • Board supportata in Zephyr: holyiot_25008 — LIS2DH12, pulsante e LED già nel devicetree. ⚠️ marcata “not actively maintained”.
    west build -b holyiot_25008/nrf54l15/cpuapp samples/basic/blinky
  • 🔓 La lezione del 16/07/2026: SimCom nega l’SDK (moduli canale cinese), Quectel lo pubblica ma il flash riscrive RF/NV senza backup possibile. Nordic: 4 fili → Core found → dump → flash. La toolchain aperta è un asset di business, non solo tecnico.

🔗 Risorse