Un futbolí Córdoba restaurat
Barreres d'infrarojos als carrils de recollida i un ESP32 amb ESPHome que du la partida. El marcador és un dashboard a la tauleta, amb locutor i música, es controla per veu amb Assist i els gols se celebren amb WLED. Va amb bateria, amagat dins el moble, i la porteria no s'ha tocat.

01
Es juga amb 11 bolles i guanya qui arriba a 6. Amb 5-5, la darrera bolla es tira al centre: és «la bona». L'ESP32 coneix aquestes regles i publica la fase de la partida a sensor.futbolin_fase. Tota la resta (marcador, so i llums) reacciona a aquesta fase.
«Nova partida» per veu. Marcador a zero i el locutor presenta el clàssic.
normalSuma tot sol. Ona de llum del color de l'equip i una frase del locutor.
event.futbolin_golEn arribar a 5, les tires respiren del color de qui la té.
bola_partido_a5-5: duel d'ones, batec daurat i cartell al marcador.
la_buenaFesta de llums i pantalla del guanyador. Els gols que sobren ja no compten.
fin_a02
És un futbolí Córdoba antic, negre i restaurat. Això va fixar les regles del muntatge:
L'àbac de comptes vermells i blaus continua al seu lloc, per si de cas.




03
L'intuïtiu seria mirar a la porteria, però és millor mirar després. Quan la bolla entra, cau per una ranura a un carril de fusta que la du rodolant fins al calaix. Allà ja no va a cent per hora: rodola a poc a poc i sempre pel mateix camí.
A cada carril hi ha una barrera d'infrarojos, amb un emissor a un costat i un receptor al davant. Quan la bolla passa, talla el feix unes desenes de mil·lisegons, i això és un gol.
Dues falques de fusta aferrades amb cola dins el carril. No s'ha foradat ni la porteria ni el carril.
Les falques es desaferren i els sensors van amb connectors. El futbolí torna a estar com abans.
Cada sensor està a cobert darrere la seva falca. La bolla mai no el toca i la rampa la guia sense frenar-la.
El feix travessa el carril de paret a paret, així que la bolla el talla passi per on passi.
binary_sensor.futbolin_atasco_a).sensor.futbolin_ultimo_corte amb la seva durada i què se n'ha fet (gol, soroll o rebot). El registre d'HA guarda així el diari de la partida.
04
La decisió clau: la partida la du l'ESP32, no Home Assistant. Compta, calcula la fase i la desa a la flash (restore_value) per no perdre-la en un reinici o una actualització OTA.
Des d'allà avisa per dos camins. A HA, per l'API nativa d'ESPHome. A WLED, directament per l'API JSON ({"ps": 3}), sense passar per HA, perquè l'efecte surti a l'instant.
Si cau la WiFi o Home Assistant, l'ESP32 segueix comptant, i en tornar la tauleta mostra el marcador correcte. HA no du cap lògica de la partida: només mostra les entitats i prem els botons.
05
El dispositiu ESPHome es diu futbolin, així que totes les entitats queden com <domini>.futbolin_*. Els equips són A i B: a ca nostra, A és el Madrid i B el Barça.
| Entitat | Què és |
|---|---|
sensor.futbolin_goles_a / _b | Gols de cada equip, de 0 a 6 |
sensor.futbolin_fase | reposo, normal, bola_partido_a/_b, la_buena, fin_a/_b |
event.futbolin_gol | gol_a o gol_b, només amb els gols que veuen les barreres. És el disparador natural de les automatitzacions |
sensor.futbolin_bateria | % de bateria, calculat amb la tensió més alta dels darrers 10 min perquè els pics de les tires no el facin botar |
binary_sensor.futbolin_autotest | Resultat de l'autotest de les barreres |
| Entitat | Què fa |
|---|---|
button.futbolin_nueva_partida | 0-0 i a jugar |
button.futbolin_gol_a_mas / _menos | Corregeix el marcador. La fase es recalcula: un −1 des de 6-5 torna la bolla de partit |
button.futbolin_anular_partida | Torna a reposo |
switch.futbolin_efectos_luz | Activa o desactiva els efectes de les tires |
number.futbolin_luces_bateria_minima | % de bateria per davall del qual es tallen els llums |
switch.futbolin_modo_enchufado | Per jugar amb una font de 12 V en lloc de bateries: amaga la bateria i silencia els seus avisos |
06
El marcador és un dashboard d'HA fet amb una sola button-card amb HTML propi: dígits de matriu de punts, la columna de les 11 bolles amb l'ordre dels gols, l'animació de «GOL!», el cartell de «la bona» i la pantalla del guanyador. Mentre està obert, HA lleva l'estalvi de pantalla de la tauleta.
Cada gol el canta un locutor que segueix el partit: el primer gol, l'empat, la ratxa, la remuntada, la bolla de partit, el gol que salva el partit… Són 348 locucions generades per endavant amb una veu TTS d'OpenAI, en castellà. HA calcula el moment del partit com a atribut d'un sensor i el dashboard tria una frase a l'atzar, sense repetir l'anterior.

Amb música sonant a la tauleta, el locutor l'ha d'abaixar i no aturar-la. Android només abaixa la música si el so nou demana el focus d'àudio «temporal, es pot abaixar», i el WebView només el demana així per a mitjans de menys de 5 s. Amb una locució més llarga, la música es pausava i no tornava.
La solució: mentre parla el locutor, sona en bucle un <audio> amb 1 s de silenci, que demana el focus curt. La veu va a part per Web Audio, que no demana focus. En acabar, es buida el src del silenci i es crida load(): amb pause() tot sol, el focus no es deixa anar i la música es queda baixa.
07
El futbolí no té botons: tot es fa amb Assist des de la tauleta. Les frases són disparadors de conversa d'una automatització que premen els botons d'ESPHome. Es resolen en local abans d'arribar al LLM, així que no cal exposar el futbolí a Assist.
triggers: - trigger: conversation command: - "gol del Madrid" - "gol de los blancos" actions: - action: button.press target: entity_id: button.futbolin_gol_a_mas
| Frase | Acció |
|---|---|
| «Nueva partida», «echamos una» | Nova partida i marcador a la tauleta |
| «Gol del Barça» | +1 |
| «Ese no vale el del Madrid» | −1 |
| «¿Cómo vamos?» | Respon amb el marcador i la fase |
| «Anula la partida» | Tornada a repòs |
| «Pon la música» | Música a la tauleta |
Les frases són en castellà, l'idioma de l'Assist de casa.
08
Hi ha una tira LED a cada costat del camp (WS2811 de 12 V, 28 píxels cada una), mogudes per un controlador Gledopto amb WLED. Cada tira és un segment. Amb bateria gasten massa per anar enceses tota la partida, així que només fan efectes d'uns segons i tornen a apagar-se totes soles.
Cada moment és un preset (o una playlist de presets) que l'ESP32 llança per l'API JSON. Els presets surten d'un script generador, així que es versionen amb la resta del codi.
| Preset | Quan | Què fa |
|---|---|---|
gol_a / gol_b | Gol | Ona del color de l'equip cap a la porteria contrària i focs artificials, 3 s |
bola_partido_* | Un equip arriba a 5 | Les tires respiren del seu color 8 s |
la_buena | 5-5 | Duel d'ones, cada una des de la seva porteria, i batec daurat |
fin_a / fin_b | Gol que guanya | Festa del color del guanyador 10 s |
aviso | Embús o autotest fallit | Vermell fix fins que es resol |
Amb la bateria baixa, l'ESP32 talla els llums tot sol: si el % passa 60 s per davall de number.futbolin_luces_bateria_minima, els apaga, i no els torna a encendre fins que la bateria puja 10 punts per damunt del mínim. Aquest marge evita que el tall reboti, perquè els mateixos efectes fan baixar la tensió.
09
Tota l'electrònica va en un panell de contraxapat devora les bateries, a la part fixa del moble: l'ESP32, el buck que baixa de 12 a 5 V, una regleta que fa de bus de 12 V i la interfície de les barreres. Les tires prenen els 12 V directament.
A cada carril arriba un cable de 5 fils que acaba en dos connectors JST-SM, un per al receptor i un altre per a l'emissor. Les resistències de pull-up van soldades a l'extrem del cable, devora l'ESP32, i un divisor de 100k/20k du els 12 V al GPIO 34 per calcular el % de bateria.
Són dues bateries de plom de 12 V i 7 Ah en paral·lel, cada una amb el seu fusible de 5 A, i un interruptor general per davall del moble. Segons els comptes, donen per a unes 7 hores de joc (falta mesurar-ho). Per jugar endollat, es lleven les bateries i es connecta una font de 12 V al seu lloc.




Tot és a GitHub, amb codi obert: el firmware d'ESPHome, el paquet de Home Assistant amb el dashboard del marcador i les frases d'Assist, els presets de WLED amb el seu generador, el generador de les locucions i els diagrames.