Sería muy útil poder instalar TTN Network Server, Application Server y Join Server por separado. Actualmente en las guías, solo encontré instrucciones para instalar ttn-lw-stack all-in-one, pero no hay opción para instalar cada servidor por separado si desea que funcionen juntos desde diferentes entornos.
...
Esta es una gran característica que permitiría métodos flexibles de implementación. Puede optar por instalar los 3 servidores (NS, AS y JS) en la puerta de enlace, o puede optar por tener otro servidor con JS y mantener solo NS y AS en la puerta de enlace para permitir la administración centralizada y remota de múltiples puertas de enlace, y así sobre.
...
En este momento solo veo un método para instalar ttn-lw-stack que incluye los 3 servidores (NS, AS y JS).
...
Me gustaría ver instrucciones para instalar NS, AS y JS por separado en lugar de tenerlos todos en una instalación / paquete.
...
Agréguelo a la guía de introducción.
...
No a partir de ahora, no estoy seguro de si esto ya se implementó parcialmente y probablemente alguien sepa cómo hacerlo de manera más eficiente que yo.
...
Gracias por la sugerencia @zamashal
De hecho, el Getting Started es actualmente para el enfoque de proceso único, pero como puede haber visto, puede iniciar los componentes individualmente. Ver;
$ ttn-lw-stack start --help
Start The Things Stack
Usage:
ttn-lw-stack start [is|gs|ns|as|js|console|gcs|dtc|qrg|all]... [flags]
No es muy difícil generar servicios por componente cuando estos servicios son parte del mismo clúster y subred.
Por ahora, estoy analizando este problema para obtener instrucciones sobre cómo hacerlo;
@johanstokking Muchas gracias por su respuesta y por agregar el problema a la lista de trabajos pendientes. Mientras tanto, me pregunto si me pueden ayudar con esto. Inicié el servidor de unión solo con el siguiente comando:
ttn-lw-stack start js --cluster.network-server "ns_ip_address" --cluster.application-server "as_ip_address"
Lo que no puedo averiguar es en qué puerto el servidor Join recibe el Join_Req y ¿va a enviar automáticamente el Join_Ans al servidor de red especificado?
¡Gracias de nuevo!
@zamashal de hecho JS es el servidor y NS y AS son clientes. Así que configure la dirección del clúster JS en NS y AS. Eso los hace trabajar en el mismo clúster, aunque son componentes individuales. Tenga en cuenta que esto utiliza la autenticación de clúster, que está diseñada para componentes que confían entre sí en el mismo clúster. Si está implementando GS, NS y AS en el borde y JS en la nube, probablemente este no sea el caso.
En ese caso, debe usar la interoperabilidad, a través de las interfaces de backend LoRaWAN, que también son compatibles. Esto permite que NS se comunique con su JS a través de la autenticación de cliente TLS.
Eso viene en dos partes: configurar el NS para usar su JS y configurar su JS con la configuración interop
(ver --help
). Desafortunadamente, esto tampoco está completamente documentado.
¡Gracias de nuevo @johanstokking ! He intentado que esta configuración funcione como me explicó. Hay una cosa que me confunde. En el enlace que proporcionó, hay un ejemplo sobre cómo configurar la interoperabilidad con Semtech Join Server . Sin embargo, estoy tratando de usar el servidor de unión de TTN Stack en sí, y no algo externo como el de Semtech u otros. ¿Todavía necesito poner la configuración para configure.yml
y example/js.yml
? Si es así, ¿cómo se vería eso entonces?
Ya configuré mi NS para que funcione con un JS externo (también conocido como JS de TTN Stack), pero usando el puerto 8886
(Interop / tls) del servidor de unión para enviar el Join_Req, la conexión se rechaza aunque el JS parece estar escuchando en ese puerto.
¡Gracias!
@zamashal Estas son aproximadamente las cosas que deben hacerse;
Ver banderas:
--interop.listen-tls string Address for the interop server to listen on (default ":8886")
--interop.sender-client-ca.blob.bucket string Bucket to use
--interop.sender-client-ca.blob.path string Path to use
--interop.sender-client-ca.directory string OS filesystem directory, which contains sender client CA configuration
--interop.sender-client-ca.source string Source of the sender client CA configuration (static, directory, url, blob)
--interop.sender-client-ca.url string URL, which contains sender client CA configuration
Interop tiene su propio oyente dedicado que utiliza la autenticación de cliente TLS. Puede usar la misma dirección IP pública que para gRPC y usar un puerto de interoperabilidad dedicado (predeterminado 8886).
Necesita una CA privada que emita certificados de cliente. Estos son utilizados en el borde por NS. Puede configurar las CA del cliente de confianza en el servidor de unión, y esto es por NetID. Siempre puede usar NetIDs 000000
y 000001
en su red privada, o unirse a LoRa Alliance y obtener uno usted mismo.
Establezca interop.sender-client-ca.source
en directory
y coloque allí un config.yml
con, por ejemplo:
# Experimentation
000000: ca-000000.pem
# The Things Network Foundation
#000013: ca-000013.pem
Su CA privada entra ca-000000.pem
. Puede agregar la CA de TTN para TTN NetID como en el ejemplo, solo para mostrarle cómo funciona.
Esto está documentado , pero de hecho lo que necesita es la configuración local de JS. Este sería el siguiente:
fqdn: 'thethings.example'
port: 8886
protocol: 'BI1.0'
tls:
root-ca: 'path/to/clientca.pem'
certificate: 'path/to/clientcert.pem'
key: 'path/to/clientkey.pem'
Aquí, thethings.example
es el FQDN de su servidor de unión y 8886 el puerto de ese listen-tls
que configuró en la interoperabilidad JS.
Además, root-ca
es (a diferencia de lo que dice el ejemplo) la CA raíz del _certificado de servidor_. Esta podría ser la misma CA. También puede omitirlo si utiliza un certificado de servidor comercial (o Let's Encrypt) en el que NS ya confía.
Habilite los registros de depuración en ambos lados ( log.level=debug
) y debería ver que las cosas funcionan o rastrear por qué las cosas no funcionan. ¡Buena suerte!
Además, si hace que esto funcione, no dude en presentar una solicitud de extracción para documentar esto. Probablemente necesitaría una guía, pero la página de referencia también necesita algo de amor.
@johanstokking , estaré trabajando en esto y, con suerte, tan pronto como lo
Hola @johanstokking , espero que todo te haya ido bien. Me gustaría informarles sobre mi progreso. Desafortunadamente, he estado abordando muchos errores para que esto funcione y compartiré con ustedes aquí los últimos errores que estoy enfrentando. Después de configurar la interoperabilidad y configurar mi servidor de red para enviar solicitudes de combinación al servidor de combinación en el puerto predeterminado 8886, sigo recibiendo el siguiente error en el registro de mi servidor de red:
error="join-request to join-server error: http post error: Post http://js-server_ip:8886: dial tcp js-server_ip:8886: connect: connection refused"
Si configuro mi servidor de red para enviar las solicitudes de unión al puerto 1884 del servidor gRPC, obtengo el siguiente error en el registro del servidor de red:
level=error msg="uplink: processing uplink frame error" ctx_id=f046310d-e528-4dd2-9dcb-6d5c8232a799 error="join-request to join-server error: http post error: Post http://js-server_ip:1884: net/http: HTTP/1.x transport connection broken: malformed HTTP response \"\\x00\\x00\\f\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x05\\x00\\x00@\\x00\\x00\\x03\\x00\\x00\\xff\\xff\""
combinado con el siguiente error del registro de pila ttn:
stack_1 | WARN grpc: Server.Serve failed to create ServerTransport: connection error: desc = "transport: http2Server.HandleStreams received bogus greeting from client: \"POST / HTTP/1.1\\r\\nHost: 1\"" namespace=grpc
Espero que usted o cualquier otra persona pueda ayudarme a comprender cómo resolver estos errores y saber qué puede causarlos.
¡Gracias nuevamente por su continuo apoyo!
El servidor de unión solo está disponible a través de https.
También parece que NS no puede resolver js-server_ip
través de DNS.
¡Gracias @johanstokking! Entonces sí, resulta que no asigné el puerto 8886 a mi host en el docker-compose.yml. Ahora, el problema al que me he enfrentado es un error de protocolo de enlace TLS:
tls: failed to verify client's certificate: x509: certificate signed by unknown authority
Por un lado, usé la bandera --tls.insecure-skip-verify
pero aún así insistió en verificar el certificado y me dio el mismo error. Creo que el problema es que necesito confiar en la autoridad de certificación en mi contenedor de la ventana acoplable. Abrí un shell en la pila y me dio un error Permission denied
cada vez que intento copiar los certificados en /usr/local/share/ca-certificates/
para que la máquina confíe en ellos.
Creo que la bandera --tls.insecure-skip-verify
debería haberlo permitido, pero tal vez su implementación sea diferente. Mi problema ahora es que el contenedor de la ventana acoplable no me da la opción de confiar en mi certificado autofirmado. ¿Hay algo que me falta allí?
¿El certificado del cliente está firmado por una de las CA para el SenderID
como se define en la configuración de la CA del
Eso es lo que usa Join Server para verificar el certificado del cliente; no la confianza del sistema ni nada.
Intenté seguir eso, pero no está completamente alineado con las instrucciones del sitio web .
Lo que tengo es lo siguiente en mi config.yml:
000000: ca-000000.pem
join-servers:
- file: './example/js.yml'
join-euis:
- 'abcd000000000000/16'
y luego puse esto en mi js.yml:
fqdn: 'thethings.example'
port: 8886
protocol: 'BI1.0'
tls:
root-ca: 'path/to/clientca.pem'
certificate: 'path/to/clientcert.pem'
key: 'path/to/clientkey.pem'
Las CA del cliente remitente aún no están documentadas, lo haremos como parte del cierre o reemplazo de este problema. Consulte (aquí) [ https://github.com/TheThingsNetwork/lorawan-stack/issues/1818#issuecomment -575534345]. Es un archivo especial y tiene su propia configuración para hacer referencia al archivo:
--interop.sender-client-ca.blob.bucket string Bucket to use
--interop.sender-client-ca.blob.path string Path to use
--interop.sender-client-ca.directory string OS filesystem directory, which contains sender client CA configuration
--interop.sender-client-ca.source string Source of the sender client CA configuration (static, directory, url, blob)
--interop.sender-client-ca.url string URL, which contains sender client CA configuration
Entonces source
debe establecerse en directory
y usted coloca la configuración en el formato mencionado anteriormente en config.yml
en esa carpeta. Ese es un directorio diferente al de la configuración de interoperabilidad.
¡Gracias @johanstokking! No me di cuenta de que debería estar en un directorio diferente, finalmente superé el problema de los certificados y ahora solucioné este error del registro de depuración ttn-stack (oculté intencionalmente las claves, pero eran correctas):
stack_1 | INFO Join not accepted dev_eui=0000000000000000 error=error:pkg/redis:not_found (entity not found) join_eui=0000000000000000 method=POST namespace=joinserver/interop remote_addr=gateway_ip:49426 request_id=01E1D3PZ63CQ7VNCE5JE8SDC3J url=/
stack_1 | INFO Request handled duration=2.948762ms error=error:pkg/interop:join_req (join-request failed) error_cause=error:pkg/redis:not_found (entity not found) method=POST namespace=interop remote_addr=gateway_ip:49426 request_id=01E1D3PZ63CQ7VNCE5JE8SDC3J status=400 url=/
Tenga en cuenta que gateway_ip también es donde residen NS y AS.
Esto también es lo que veo en el registro de depuración de NS:
time="2020-02-18T16:36:52-05:00" level=error msg="uplink: processing uplink frame error" ctx_id=ef20804f-13a8-4f7f-b90e-ce279c1e11ea error="join-request to join-server error: response error, code: JoinReqFailed, description: error:pkg/redis:not_found (entity not found)"
Por lo que puedo leer, el error parece estar quejándose de una mala configuración de mi componente redis del docker-compose. Revisé el tutorial de configuración para asegurarme de que todo coincide. Lo que tenía en mi configuración era esto:
volumes:
- ${DEV_DATA_DIR:-.env/data}/redis:/data
Así que seguí adelante y lo cambié a esto:
volumes:
- './data/redis:/data'
Luego, comencé a ver el siguiente error que ni siquiera me permite ejecutar la pila:
stack_1 | error:cmd/internal/shared:initialize_identity_server (could not initialize Identity Server)
stack_1 | --- error:pkg/identityserver:db_needs_migration (the database needs to be migrated)
stack_1 | --- pq: database "ttn_lorawan" does not exist
No estaba seguro de si este cambio era necesario en absoluto, en ./data/redis/
solo veo un archivo `` appendonly.aof ''`, por lo que parece que me falta algo ...
No estaba seguro de si este cambio era necesario en absoluto, en
./data/redis/
solo veo un archivo `` appendonly.aof ''`, por lo que parece que me falta algo ...
No, eso está bien para Redis de hecho.
¿Parece que su dispositivo no está registrado en el servidor de incorporación?
Oh, esa es probablemente la razón. Bueno, todo lo que hice fue usar la bandera --js.join-eui-prefix
pero parece que no es suficiente. Estoy atascado en otro problema que he estado tratando de ignorar: problema 1942
¿Puedo registrar el dispositivo agregando filas manualmente a la base de datos de redis? Si es así, ¿cuál es el formato? Eso podría ayudarme a seguir ignorando el otro problema mientras tanto ...
Pude acceder al tablero en el otro problema y registrar el dispositivo en el tablero. Ahora veo un error que dice sender unknown
y creo que se queja de que no se reconoce la puerta de enlace. Intenté agregar la puerta de enlace desde la consola pero todavía dice Disconnected
. Traté de ingresar la dirección de gateway_ip y server_ip pero ambos no parecían hacer ninguna diferencia todavía.
Remitente desconocido probablemente significa que la NetID del dispositivo final no está configurada como la NetID de su servidor de red. Ambos deben establecerse en 000000
.
Puede establecer la NetID del dispositivo final a través de CLI con ttn-lw-cli end-device set <app-id> <dev-id> --net-id=000000
Mi ttn-lw-cli
está actuando de manera extraña, solo puedo ejecutar el comando de inicio de sesión con las opciones predeterminadas, y si especifico algo, un archivo de configuración o una autoridad de certificación, solo obtengo permission denied
. Intenté varias formas de evitar los permisos cambiando chmod y chown. Continúo obteniendo permission denied
. Si ejecuto las configuraciones predeterminadas escribiendo solo ttn-lw-cli login
obtengo:
Post https://localhost:8885/oauth/token: x509: certificate signed by unknown authority
Aunque docker-compose up funciona bien sin problemas de certificados ni ningún otro error. ¿Alguna idea de lo que podría estar perdiendo y que probablemente esté causando los permisos denegados?
¡Gracias!
¿Puede publicar la configuración de su servidor y CLI y lo que intenta hacer exactamente?
Estaba intentando iniciar sesión primero con el comando sudo ttn-lw-cli login
, aquí está mi configuración:
# sudo ttn-lw-cli config
--allow-unknown-hosts="false"
--application-server-enabled="true"
--application-server-grpc-address="localhost:8884"
--ca=""
--config="/etc/ttn-cli/.ttn-lw-cli.yml,/root/snap/ttn-lw-stack/149/.ttn-lw-cli.yml,/root/snap/ttn-lw-stack/149/.config/.ttn-lw-cli.yml"
--credentials-id=""
--device-claiming-server-grpc-address="localhost:8884"
--device-template-converter-grpc-address="localhost:8884"
--gateway-server-enabled="true"
--gateway-server-grpc-address="localhost:8884"
--identity-server-grpc-address="localhost:8884"
--input-format="json"
--insecure="false"
--join-server-enabled="true"
--join-server-grpc-address="localhost:8884"
--log.level="info"
--network-server-enabled="true"
--network-server-grpc-address="localhost:8884"
--oauth-server-address="https://localhost:8885/oauth"
--output-format="json"
--qr-code-generator-grpc-address="localhost:8884"
Entonces, ejecutar el valor predeterminado me da el error certificate signed by unknown authority
que compartí anteriormente. Pero debido a los problemas del certificado, intenté agregar la siguiente opción: sudo ttn-lw-cli login --ca "path/to/ca.pem"
pero eso me dio un error de permiso denegado.
Intenté agregar la siguiente opción:
sudo ttn-lw-cli login --ca "path/to/ca.pem"
Esto es bueno. También puede poner esto en un archivo de configuración o en un entorno.
pero eso me dio un error de permiso denegado.
¿En la CLI o en el servidor? ¿Tienes registros?
error del servidor, creo? esto es todo lo que puedo ver:
root<strong i="6">@myserver</strong>:/etc/ttn-cli# sudo ttn-lw-cli login --ca="/etc/ttn-cli/ca.pem" --log.level="debug"
open /etc/ttn-cli/ca.pem: permission denied
También intenté darle permisos chmod 777
y sigo recibiendo el mismo error.
¡Finalmente pude solucionar este problema agregando el archivo de configuración a /root/snap/ttn-lw-stack/149/.ttn-lw-cli.yml
!
Ahora recibo un error certificate signed by unknown authority
. ¿Cómo confía la herramienta ttn-lw-cli
en un certificado? Aquí está el registro completo:
root<strong i="8">@localhost</strong>:/etc/ttn-stack# sudo ttn-lw-cli login --callback=false --config="/root/snap/ttn-lw-stack/149/.ttn-lw-cli.yml" --log.level="debug" --insecure="true" --allow-unknown-hosts="true" --ca="/root/snap/ttn-lw-stack/149/ca.pem"
WARN Access token expired at 5:17PM
ERROR Please login with the login command
DEBUG ccResolverWrapper: sending update to cc: {[{localhost:1884 <nil> 0 <nil>}] <nil> <nil>}
DEBUG pickfirstBalancer: HandleSubConnStateChange: 0xc00087caa0, {CONNECTING <nil>}
DEBUG pickfirstBalancer: HandleSubConnStateChange: 0xc00087caa0, {READY <nil>}
DEBUG Finished unary call duration=2.376756ms grpc_method=AuthInfo grpc_service=ttn.lorawan.v3.EntityAccess namespace=grpc
INFO Opening your browser on https://localhost/oauth/authorize?client_id=cli&redirect_uri=code&response_type=code
WARN Could not open your browser, you'll have to go there yourself error=fork/exec /usr/bin/xdg-open: permission denied
INFO After logging in and authorizing the CLI, we'll get an access token for future commands.
INFO Please paste the authorization code and press enter
> MF2XI.JX2QFUHNVVWMEYTTRQ3S4DTGPI5VXBYJWVJQ2ZI.OG5C4HQXGMRQ4LVW7ES4IZRNH2L5OJOING2SWOW74LFLQAYDH64Q
ERROR Could not exchange OAuth access token error=Post https://localhost/oauth/token: x509: certificate signed by unknown authority
Post https://localhost/oauth/token: x509: certificate signed by unknown authority
Estoy usando el mismo ca.pem en el que confían ttn-stack
que ejecuto con docker-compose.
Pasé el problema de inicio de sesión / certificado nuevamente usando http URI y puertos http en la configuración ttn-lw-cli
. Cuando ejecuto sudo ttn-lw-cli end-device set "mysensor1app" "mysensor1dev" --net-id=000000 --log.level="debug"
, veo lo siguiente:
root<strong i="8">@localhost</strong>:/etc/ttn-stack$ sudo ttn-lw-cli end-device set "mysensor1app" "mysensor1dev" --net-id=000000 --log.level="debug"
DEBUG Using access token (valid until 6:42PM)
DEBUG ccResolverWrapper: sending update to cc: {[{localhost:1884 <nil> 0 <nil>}] <nil> <nil>}
DEBUG pickfirstBalancer: HandleSubConnStateChange: 0xc000414730, {CONNECTING <nil>}
WARN grpc: addrConn.createTransport failed to connect to {localhost:1884 <nil> 0 <nil>}. Err :connection error: desc = "transport: authentication handshake failed: context deadline exceeded". Reconnecting...
DEBUG pickfirstBalancer: HandleSubConnStateChange: 0xc000414730, {TRANSIENT_FAILURE connection error: desc = "transport: authentication handshake failed: context deadline exceeded"}
DEBUG pickfirstBalancer: HandleSubConnStateChange: 0xc000414730, {CONNECTING <nil>}
WARN grpc: addrConn.createTransport failed to connect to {localhost:1884 <nil> 0 <nil>}. Err :connection error: desc = "transport: authentication handshake failed: context deadline exceeded". Reconnecting...
Aquí está mi ttn-lw-cli
config:
--allow-unknown-hosts="true"
--application-server-enabled="true"
--application-server-grpc-address="localhost:1884"
--ca="/root/snap/ttn-lw-stack/149/ca.pem"
--config="/etc/ttn-stack/.ttn-lw-cli.yml,/root/snap/ttn-lw-stack/149/.ttn-lw-cli.yml,/root/snap/ttn-lw-stack/149/.config/.ttn-lw-cli.yml"
--credentials-id=""
--device-claiming-server-grpc-address="localhost:1884"
--device-template-converter-grpc-address="localhost:1884"
--gateway-server-enabled="true"
--gateway-server-grpc-address="localhost:1884"
--identity-server-grpc-address="localhost:1884"
--input-format="json"
--insecure="true"
--join-server-enabled="true"
--join-server-grpc-address="localhost:1884"
--log.level="info"
--network-server-enabled="true"
--network-server-grpc-address="localhost:1884"
--oauth-server-address="http://localhost/oauth"
--output-format="json"
--qr-code-generator-grpc-address="localhost:1884"
Creo que esto podría estar relacionado con mi configuración de http, aunque tuve el mensaje INFO Got OAuth access token
después de iniciar sesión que parece indicar una autenticación exitosa.
También comencé a ver el siguiente error en mis registros de docker-compose
:
stack_1 | DEBUG Rejected authentication client_id=mqtt_5bc528ca.ae4ea8 error=error:pkg/ttnpb:identifiers (invalid identifiers) error_cause=error:pkg/errors:validation (invalid `application_id`: value does not match regex pattern "^[a-z0-9](?:[-]?[a-z0-9]){2,}$") field=application_id name=ApplicationIdentifiersValidationError namespace=applicationserver/io/mqtt reason=value does not match regex pattern "^[a-z0-9](?:[-]?[a-z0-9]){2,}$" username=
stack_1 | WARN Failed to setup connection error=error:pkg/ttnpb:identifiers (invalid identifiers) error_cause=error:pkg/errors:validation (invalid `application_id`: value does not match regex pattern "^[a-z0-9](?:[-]?[a-z0-9]){2,}$") field=application_id name=ApplicationIdentifiersValidationError namespace=applicationserver/io/mqtt reason=value does not match regex pattern "^[a-z0-9](?:[-]?[a-z0-9]){2,}$" remote_addr=172.18.0.1:57472
No pude entender a qué se refiere, pero pensé que podría estar quejándose del mismo dispositivo y aplicación que agregué y aún no tengo el sensor conectado.
Ahora recibo un error
certificate signed by unknown authority
. ¿Cómo confía la herramientattn-lw-cli
en un certificado?
Utiliza el archivo CA que pasa con ca
. Ese archivo debe apuntar al certificado del servidor (si es autofirmado) o la CA que firmó el certificado del servidor.
Aquí está mi
ttn-lw-cli
config:
Esta configuración se ve bien si no desea usar TLS. Pero, ¿el servidor está escuchando estas direcciones, en su configuración no TLS?
También comencé a ver el siguiente error en mis registros de
docker-compose
:
Este es un cliente MQTT que se conecta con un nombre de usuario que no es un ID de aplicación válido.
¡Gracias por las pistas! Apuntando a cert.pem
lugar de ca.pem
resolvió el problema certificate signed by unknown authority
. Sin embargo, sigo recibiendo el otro error de conexión. Definitivamente estoy escuchando en el puerto 1884
:
user<strong i="10">@localhost</strong>:/etc/ttn-stack$ sudo netstat -tulpn | grep LISTEN
tcp6 0 0 :::1884 :::* LISTEN 18793/docker-proxy
También puedo ver los paquetes de datos que llegan cuando hago telnet al puerto 1884 y ejecuto la herramienta ttn-lw-cli
. Así que definitivamente se está produciendo un intercambio de paquetes, pero el registro de depuración todavía me da el siguiente error: "transport: authentication handshake failed: context deadline exceeded". Reconnecting...
Finalmente resuelto este problema agregando el --insecure
bandera para el end-device set
comando !! Parece que estoy teniendo problemas con TLS, pero eso no me preocupa ahora de todos modos.
¡Gracias de nuevo!
Me complace informarle que después de configurar --root-keys.app-key.key
además de --net-id
, el proceso de unión para end-device
completó con éxito y comencé a obtener los datos del dispositivo final en el ¡Servidor de aplicaciones! ¡Gracias nuevamente por su gran ayuda a través de todos los problemas que he enfrentado!
¡Eso es genial! Sería fantástico si pudieras documentar tu escenario aquí, para que podamos incorporarlo.
Gracias también por la motivación y por ser el primer panqueque.