Seria muito útil poder instalar o servidor de rede TTN, o servidor de aplicativos e o servidor de conexão separadamente. Atualmente, nos guias, encontrei apenas instruções para instalar o all-in-one ttn-lw-stack, mas nenhuma opção para instalar cada servidor separadamente se você quiser que eles trabalhem juntos em ambientes diferentes.
...
Este é um ótimo recurso para permitir métodos flexíveis de implantação. Você pode escolher instalar todos os 3 servidores (NS, AS e JS) no gateway ou pode optar por ter outro servidor com JS e manter apenas NS e AS no gateway para permitir o gerenciamento centralizado e remoto de vários gateways e assim sobre.
...
No momento, vejo apenas um método para instalar ttn-lw-stack que inclui todos os 3 servidores (NS, AS e JS).
...
Gostaria de ver instruções para instalar separadamente NS, AS e JS em vez de ter todos em uma instalação / pacote.
...
Adicione-o ao guia de primeiros passos.
...
Por enquanto, não tenho certeza se isso já está parcialmente implementado e provavelmente alguém sabe como fazer isso de forma mais eficiente do que eu.
...
Obrigado pela sugestão @zamashal
Na verdade, o Guia de Introdução é atualmente para a abordagem de processo único, mas como você deve ter visto, você pode iniciar os 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]
Não é muito difícil gerar serviços por componente quando esses serviços fazem parte do mesmo cluster e sub-rede.
Estou analisando este problema agora com instruções sobre como;
@johanstokking Muito obrigado pela sua resposta e adicionando o problema ao backlog. Nesse ínterim, gostaria de saber se você pode me ajudar com isso. Iniciei o servidor de junção sozinho com o seguinte comando:
ttn-lw-stack start js --cluster.network-server "ns_ip_address" --cluster.application-server "as_ip_address"
O que não consigo descobrir é em qual porta o Join Server receberá o Join_Req e enviará automaticamente o Join_Ans para o servidor de rede especificado?
Obrigado novamente!
@zamashal na verdade JS é o servidor e NS e AS são clientes. Portanto, configure o endereço do cluster JS em NS e AS. Isso os faz trabalhar no mesmo cluster, embora sejam componentes individuais. Observe que isso usa autenticação de cluster, que é projetada para componentes que confiam uns nos outros no mesmo cluster. Se você estiver implantando GS, NS e AS na borda e JS na nuvem, provavelmente não é o caso.
Nesse caso, você deve usar a interoperabilidade, por meio das interfaces de back-end LoRaWAN, que também são suportadas. Isso permite que o NS entre em contato com seu JS por meio da autenticação de cliente TLS.
Isso vem em duas partes: configurar o NS para usar seu JS e configurar seu JS com a configuração interop
(consulte --help
). Isso também não está totalmente documentado, infelizmente.
Obrigado novamente @johanstokking ! Tenho tentado fazer com que essa configuração funcione conforme você explicou. Há uma coisa que me confunde. No link que você forneceu, há um exemplo de como configurar a interoperabilidade com o Semtech Join Server . No entanto, estou tentando usar o Join Server do TTN Stack em si, e não algo externo como o da Semtech ou outros. Ainda preciso colocar na configuração configure.yml
e example/js.yml
? Se sim, como seria então?
Já configurei meu NS para trabalhar com um JS externo (também conhecido como JS de pilha TTN), mas usando a porta 8886
(Interop / tls) do servidor de junção para enviar o Join_Req, a conexão está sendo recusada, embora o JS parece estar escutando nessa porta.
Obrigado!
@zamashal Aqui estão aproximadamente as coisas que precisam ser feitas;
Veja as bandeiras:
--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
A Interop tem seu próprio ouvinte dedicado que usa autenticação de cliente TLS. Você pode usar o mesmo endereço IP público do gRPC e usar uma porta de interoperabilidade dedicada (padrão 8886).
Você precisa de uma CA privada que emita certificados de cliente. Eles são usados na borda por NS. Você pode configurar as CAs de clientes confiáveis no Join Server, e isso é feito por NetID. Você sempre pode usar NetIDs 000000
e 000001
em sua rede privada, ou aderir à LoRa Alliance e obter um você mesmo.
Defina interop.sender-client-ca.source
como directory
e coloque lá config.yml
com por exemplo:
# Experimentation
000000: ca-000000.pem
# The Things Network Foundation
#000013: ca-000013.pem
Sua CA privada vai em ca-000000.pem
. Você poderia adicionar o CA do TTN para o NetID do TTN como no exemplo, apenas para mostrar como isso funciona.
Isso é como documentado , mas na verdade o que você precisa é a configuração JS local. Isso seria o seguinte:
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'
Aqui, thethings.example
é o FQDN do seu Join Server e 8886 a porta daquele listen-tls
que você configurou na interoperabilidade JS.
Além disso, root-ca
é (ao contrário do que diz o exemplo) a CA raiz do _certificado do servidor_. Este pode ser o mesmo CA. Você também pode deixá-lo de fora se usar um certificado de servidor comercial (ou Let's Encrypt) que já seja confiável para NS.
Habilite os logs de depuração em qualquer um dos lados ( log.level=debug
) e você deverá ver as coisas funcionando ou rastros do porquê as coisas não funcionam. Boa sorte!
Além disso, se você fizer isso funcionar, sinta-se à vontade para registrar uma solicitação de pull para documentar isso. Provavelmente precisaria de um guia, mas a página de referência também precisa de um pouco de amor.
@johanstokking , estarei trabalhando nisso e, com sorte, assim que descobrir, farei uma solicitação de pull para atualizar o guia. Não posso agradecer o suficiente por toda a sua ajuda!
Ei, @johanstokking - Espero que esteja tudo bem com você. Eu gostaria de atualizá-lo sobre meu progresso. Infelizmente, tenho corrigido muitos erros para fazer isso funcionar e compartilharei com vocês aqui os erros mais recentes que estou enfrentando. Depois de definir a interoperabilidade e configurar meu servidor de rede para enviar solicitações de ingresso ao servidor de ingresso na porta padrão 8886, continuo recebendo o seguinte erro no log do meu servidor de rede:
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"
Se eu configurar meu servidor de rede para enviar as solicitações de ingresso para a porta 1884 do servidor gRPC, recebo o seguinte erro no log do servidor de rede:
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 com o seguinte erro do log da pilha 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 você ou qualquer outra pessoa possa me ajudar a entender como resolver esses erros e saber o que pode causar tais erros.
Agradecemos novamente pelo seu suporte contínuo!
O Join Server está disponível apenas em https.
Parece também que o NS não pode resolver js-server_ip
por meio do DNS.
Obrigado @johanstokking! Então, sim, descobri que não mapeei a porta 8886 para meu host no docker-compose.yml. Agora, o problema que tenho enfrentado é um erro de handshake de TLS:
tls: failed to verify client's certificate: x509: certificate signed by unknown authority
Por um lado, usei o sinalizador --tls.insecure-skip-verify
mas ele ainda insistiu em verificar o certificado e me deu o mesmo erro. Acho que o problema é que preciso confiar na autoridade de certificação em meu contêiner do docker. Eu abri um shell na pilha e ele me deu um erro Permission denied
sempre que tento copiar os certificados em /usr/local/share/ca-certificates/
para confiá-los pela máquina.
Acho que a sinalização --tls.insecure-skip-verify
deveria ter permitido, mas talvez sua implementação seja diferente. Meu problema agora é que o contêiner do docker não me dá a opção de confiar em meu certificado autoassinado. Há algo que estou perdendo aí?
O certificado do cliente é assinado por uma das CAs para SenderID
conforme definido na configuração da CA do
Isso é o que o Join Server usa para verificar o certificado do cliente; não a confiança do sistema ou qualquer coisa.
Tentei seguir isso, mas não está totalmente alinhado com as instruções do site .
O que eu tenho é o seguinte em meu config.yml:
000000: ca-000000.pem
join-servers:
- file: './example/js.yml'
join-euis:
- 'abcd000000000000/16'
e então coloco isso em meu 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'
As CAs do cliente remetente ainda não estão documentadas, faremos isso como parte do fechamento ou substituição deste problema. Consulte (aqui) [ https://github.com/TheThingsNetwork/lorawan-stack/issues/1818#issuecomment -575534345]. É um arquivo especial e tem sua própria configuração para referenciar o arquivo:
--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
Portanto, source
precisa ser definido como directory
e você coloca a configuração no formato mencionado em config.yml
nessa pasta. Esse é um diretório diferente da configuração de interoperabilidade.
Obrigado @johanstokking! Não percebi que deveria estar em um diretório diferente, finalmente superei o problema de certificados e agora estou lidando com este erro do log de depuração ttn-stack (intencionalmente encobri as chaves, mas elas estavam corretas):
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=/
Observe que gateway_ip também é onde o NS e o AS residem.
Isso também é o que estou vendo no log de depuração do 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)"
Pelo que pude ler, o erro parece estar reclamando de uma configuração incorreta do meu componente redis do docker-compose. Eu revisitei o tutorial de configuração para ter certeza de que tudo está combinando. O que eu tinha na minha configuração era o seguinte:
volumes:
- ${DEV_DATA_DIR:-.env/data}/redis:/data
Então eu fui em frente e mudei para isto:
volumes:
- './data/redis:/data'
Então, comecei a ver o seguinte erro, que nem mesmo me permite executar a pilha:
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
Eu não tinha certeza se essa mudança era necessária, em ./data/redis/
eu só vejo um arquivo `` appendonly.aof```, então parece que estou faltando alguma coisa ..
Eu não tinha certeza se essa mudança era necessária, em
./data/redis/
eu só vejo um arquivo `` appendonly.aof```, então parece que estou faltando alguma coisa ..
Não, isso é bom para Redis, na verdade.
Parece que o seu dispositivo não está registrado no Join Server?
Oh, provavelmente é por isso. Bem, tudo o que fiz foi usar a sinalização --js.join-eui-prefix
mas parece que não é suficiente. Estou preso em outro problema que venho tentando ignorar: o problema 1942
Posso registrar o dispositivo adicionando manualmente linhas ao banco de dados redis? Se sim, qual é o formato? Isso pode me ajudar a continuar a ignorar o outro problema enquanto isso.
Consegui acessar o painel do outro problema e registrar o dispositivo no painel. Agora estou vendo um erro que diz sender unknown
que acredito estar reclamando do gateway não ser reconhecido. Tentei adicionar o gateway do console, mas ainda diz Disconnected
. Tentei inserir o endereço do gateway_ip e do server_ip, mas ambos não pareciam fazer nenhuma diferença ainda.
Remetente desconhecido provavelmente significa que o NetID do dispositivo final não está definido para o NetID do seu servidor de rede. Ambos devem ser definidos como 000000
.
Você pode definir o NetID do dispositivo final via CLI com ttn-lw-cli end-device set <app-id> <dev-id> --net-id=000000
Meu ttn-lw-cli
está agindo de forma estranha, eu só posso executar o comando login com as opções padrão, e se eu especificar algo um arquivo de configuração ou autoridade de certificação, acabo de obter permission denied
. Tentei várias maneiras de contornar as permissões, alterando chmod e chown. Continuo recebendo permission denied
. Se eu executar as configurações padrão digitando apenas ttn-lw-cli login
, recebo:
Post https://localhost:8885/oauth/token: x509: certificate signed by unknown authority
Embora docker-compose up esteja funcionando bem, sem problemas de certificado ou quaisquer outros erros. Alguma ideia do que pode estar faltando, o que provavelmente está causando as permissões negadas?
Obrigado!
Você pode postar sua configuração de servidor e CLI e o que você tenta fazer exatamente?
Eu estava tentando fazer login primeiro com o comando sudo ttn-lw-cli login
, aqui está minha configuração:
# 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"
Portanto, executar o padrão me dá o erro certificate signed by unknown authority
que compartilhei anteriormente. Mas devido a problemas de certificado, tentei adicionar a seguinte opção: sudo ttn-lw-cli login --ca "path/to/ca.pem"
mas isso me deu um erro de permissão negada.
Tentei adicionar a seguinte opção:
sudo ttn-lw-cli login --ca "path/to/ca.pem"
Isso é bom. Você também pode colocar isso em um arquivo de configuração ou ambiente.
mas isso me deu um erro de permissão negada.
No CLI ou no servidor? Você tem logs?
erro do servidor eu acho? isso é tudo que posso 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
Também tentei dar a ele chmod 777
permissões e ainda obtive o mesmo erro.
Finalmente consegui contornar esse problema adicionando o arquivo de configuração a /root/snap/ttn-lw-stack/149/.ttn-lw-cli.yml
!
Agora estou recebendo um erro certificate signed by unknown authority
. Como a ferramenta ttn-lw-cli
confia em um certificado? Aqui está o 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
Estou usando o mesmo ca.pem que é confiável para ttn-stack
que executo com docker-compose.
Superei o problema de login / certificado novamente usando as portas http URI e http na configuração ttn-lw-cli
. Quando executo sudo ttn-lw-cli end-device set "mysensor1app" "mysensor1dev" --net-id=000000 --log.level="debug"
, vejo o seguinte:
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...
Aqui está minha configuração de ttn-lw-cli
:
--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"
Acho que isso pode estar relacionado à configuração do meu http, embora eu tenha recebido a mensagem INFO Got OAuth access token
após o login, que parece indicar uma autenticação bem-sucedida.
Também comecei a ver o seguinte erro nos meus docker-compose
logs:
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
Não consegui descobrir a que se refere, mas achei que pudesse estar reclamando do mesmo dispositivo e aplicativo que adicionei e ainda não juntei o sensor.
Agora estou recebendo um erro
certificate signed by unknown authority
. Como a ferramentattn-lw-cli
confia em um certificado?
Ele usa o arquivo CA que você passa com ca
. Esse arquivo deve apontar para o certificado do servidor (se for autoassinado) ou a CA que assinou o certificado do servidor.
Aqui está minha configuração de
ttn-lw-cli
:
Esta configuração parece boa se você não quiser usar TLS. Mas, o servidor está escutando nesses endereços, em sua configuração não-TLS?
Também comecei a ver o seguinte erro nos meus
docker-compose
logs:
Este é um cliente MQTT conectando-se a um nome de usuário que não é um ID de aplicativo válido.
Obrigado pelas dicas! Apontar para cert.pem
vez de ca.pem
resolveu o problema de certificate signed by unknown authority
. No entanto, ainda estou recebendo o outro erro de conexão. Definitivamente estou ouvindo na porta 1884
:
user<strong i="10">@localhost</strong>:/etc/ttn-stack$ sudo netstat -tulpn | grep LISTEN
tcp6 0 0 :::1884 :::* LISTEN 18793/docker-proxy
Também posso ver pacotes de dados chegando quando eu telnet para a porta 1884 e executo a ferramenta ttn-lw-cli
. Portanto, há definitivamente uma troca de pacotes acontecendo, mas o log de depuração ainda me dá o seguinte erro: "transport: authentication handshake failed: context deadline exceeded". Reconnecting...
Eu finalmente resolvido este problema adicionando o --insecure
bandeira para o end-device set
comando !! Parece que estou tendo problemas com o TLS, mas não estou preocupado com isso agora
Obrigado novamente!
Estou emocionado em informar que depois de definir --root-keys.app-key.key
além de --net-id
, o processo de junção para end-device
concluído com sucesso e comecei a obter os dados do dispositivo final no independente Servidor de aplicação! Obrigado novamente por sua grande ajuda em todos os problemas que enfrentei!
Isso é ótimo! Seria ótimo se você pudesse documentar seu cenário aqui, para que possamos incorporá-lo.
Obrigado também pela motivação e por ser a primeira panqueca.