Integração com sistemas de automação
Especificação do MTerminal para empresas que desenvolvem sistemas de automação comercial (PDV, restaurantes, padarias, bares) com suporte a microterminais VT100 via TCP/IP.
1.Visão geral
O MTerminal é um aplicativo Android que emula um microterminal de pedidos (visor LCD de caracteres + teclado numérico) conectado por TCP/IP ao servidor de microterminais do seu sistema. Ele se comporta como um terminal "burro": toda a lógica fica no servidor.
| Direção | Conteúdo |
|---|---|
| Servidor → app | Texto e sequências de controle VT100/ANSI (e, opcionalmente, quadros STX/ETX) que desenham o visor. |
| App → servidor | Um byte (ou poucos bytes) por tecla pressionada e o conteúdo lido pelo leitor de código de barras. |
Se o seu servidor já atende microterminais VT100 em rede (Ethernet/TCP), normalmente o MTerminal funciona sem nenhuma alteração: basta cadastrar o aparelho como mais um terminal.
2.Requisitos de rede
- O aparelho Android e o servidor na mesma rede local (Wi-Fi do estabelecimento), ou com rota IP entre eles.
- O servidor escutando numa porta TCP (qualquer porta; as mais comuns são
1001e23), com o firewall liberando conexões de entrada nela. - Recomendado: IP fixo para cada aparelho (reserva de DHCP no roteador), já que a maioria dos servidores identifica o terminal pelo IP.
- A comunicação é TCP puro, sem criptografia (como os microterminais físicos). Use apenas em redes confiáveis; o app não expõe portas nem aceita conexões de entrada.
3.Conexão TCP e sessão
| Item | Comportamento do MTerminal |
|---|---|
| Papel | Cliente TCP. O app conecta em IP:porta configurados; o servidor escuta. |
| Conexões por aparelho | Uma. Antes de abrir uma nova conexão, a anterior é sempre encerrada. |
| Tempo limite de conexão | 5 segundos. |
| Reconexão automática | Após falha ou queda: 2 s, 4 s, 8 s, 16 s e depois a cada 30 s, até conectar. Volta a 2 s depois de uma conexão bem-sucedida. |
| Retorno ao app | Ao voltar do segundo plano sem conexão, reconecta imediatamente (o Android pode derrubar o socket de apps em segundo plano). |
| Alteração de configurações | Ao salvar, encerra a conexão e abre uma nova. |
| Opções do socket | TCP_NODELAY ativado (cada tecla sai na hora). Sem keep-alive de aplicação. |
| Codificação | Latin-1 (ISO-8859-1), 1 byte por caractere, nos dois sentidos. Caracteres fora da faixa são enviados como ?. |
| Envio de teclas | Somente com a conexão estabelecida; teclas pressionadas sem conexão são descartadas. |
| Estado ao reconectar | O interpretador de sequências é reiniciado, mas o conteúdo do visor permanece até o servidor redesenhá-lo. |
4.Identificação do terminal
O MTerminal suporta as duas formas usuais:
4.1 Pelo IP de origem (padrão, recomendado)
O app não envia nada ao conectar. O servidor identifica o terminal pelo endereço IP remoto da conexão, como faz com microterminais físicos. O IP do aparelho aparece para o usuário em Configurações → IP deste aparelho, para ser cadastrado no seu sistema.
4.2 Por identificador enviado ao conectar (opcional)
Com a opção “Enviar identificador ao conectar” ligada, logo após o connect o app envia o campo Identificador do Terminal seguido de CR:
<identificador> 0x0D ex.: "01\r" → 30 31 0D
Se o seu servidor identifica por IP, deixe essa opção desligada: caso contrário o identificador chega ao servidor como se tivesse sido digitado (ex.: “01” + Enter no prompt de operador).
5.Modelo do visor
- Formatos: 2×16, 2×20 (padrão), 2×40 e 4×20 (linhas × colunas), escolhidos pelo usuário. Configure no app o mesmo formato do terminal cadastrado no seu sistema.
- Coordenadas das sequências VT100 são 1-based: linha 1 e coluna 1 são o canto superior esquerdo. Valores fora do visor são limitados à borda (ex.: coluna 30 num visor de 20 colunas vira coluna 20).
- Ao escrever na última coluna, o cursor vai para o início da linha seguinte.
- O visor não rola. Passando da última linha (por texto ou LF), o cursor volta para a linha 1. Posicione o cursor explicitamente e limpe as linhas em vez de depender de rolagem.
- O cursor é exibido como um bloco piscando na posição atual.
- Sem eco local: o app não escreve no visor o que é digitado. O servidor deve ecoar cada caractere que quiser mostrar (como nos microterminais físicos).
6.Sequências VT100/ANSI suportadas
O interpretador é contínuo: sequências divididas entre pacotes TCP são tratadas corretamente. Notação: ESC = 0x1B; CSI = ESC [; n omitido assume o padrão indicado.
| Sequência | Nome | Efeito no MTerminal |
|---|---|---|
CSI 2 J | Limpar tela | Limpa o visor inteiro, cursor na linha 1, coluna 1. |
CSI J / CSI 0 J | Limpar até o fim | Limpa do cursor até o fim do visor (cursor não se move). |
CSI 1 J | Limpar até o início | Limpa do início do visor até o cursor. |
CSI K / CSI 0 K | Limpar linha → fim | Limpa do cursor até o fim da linha. |
CSI 1 K | Limpar linha ← início | Limpa do início da linha até o cursor. |
CSI 2 K | Limpar linha | Limpa a linha inteira. |
CSI l ; c H / f | Posicionar cursor | Linha l, coluna c (padrão 1;1). Aceita zeros à esquerda (ESC[01;05H) e um só parâmetro (ESC[2H = linha 2, coluna 1). |
CSI H | Cursor no início | Linha 1, coluna 1. |
CSI n A/B/C/D | Mover cursor | Cima/baixo/direita/esquerda n posições (padrão 1), sem sair do visor. |
CSI s / CSI u | Salvar/restaurar cursor | Guarda e recupera a posição do cursor. |
ESC 7 / ESC 8 | Salvar/restaurar cursor | Idem (forma DEC). |
ESC c | Reset | Limpa o visor e posiciona o cursor em 1;1. |
ESC D / ESC M | Index / Reverse index | Cursor uma linha abaixo/acima (limitado ao visor). |
ESC E | Próxima linha | Início da linha seguinte. |
CSI 0 m, CSI 7 m, CSI 27 m, CSI 0;7 m | Atributos | Aceitos (vários parâmetros permitidos), sem efeito visual: o visor não exibe vídeo reverso. |
CSI 5 i … CSI 4 i | Media copy (impressora/porta auxiliar) | Tudo entre as duas sequências é descartado (não aparece no visor). |
CSI ? … h/l e outros modos privados | Modos DEC | Ignorados sem imprimir nada (ex.: ESC[?25l, ESC[?24h). |
ESC O x, ESC ( x, ESC ) x, ESC # x | SS3 / charset / DEC | Ignorados (consomem o próximo byte). |
Qualquer outro CSI … final | — | Ignorado sem imprimir nada. |
7.Caracteres de controle e texto
| Byte | Nome | Efeito |
|---|---|---|
0x07 | BEL | Emite o som de clique do sistema (se o bip estiver ativado no app). |
0x08 | BS | Cursor uma posição à esquerda e apaga o caractere (padrão dos microterminais). O usuário pode desligar o apagamento (VT100 estrito). BS espaço BS também funciona. |
0x09 | TAB | Avança até a próxima coluna múltipla de 8. |
0x0A, 0x0B, 0x0C | LF / VT / FF | Início da linha seguinte (sem rolagem: da última linha volta para a primeira). |
0x0D | CR | Cursor na coluna 1 da linha atual. |
0x02 / 0x03 | STX / ETX | Ver seção 8. |
0x20–0x7E | ASCII imprimível | Escrito na posição do cursor. |
0xA0–0xFF | Latin-1 | Escrito (acentos: Ã=0xC3, Ç=0xC7, É=0xC9…). |
Demais (0x00–0x1F, 0x7F–0x9F) | — | Ignorados. |
8.Enquadramento STX/ETX
Definido pelo usuário em Configurações → Protocolo:
8.1 “VT100 / ANSI” (padrão)
STX (0x02) e ETX (0x03) são apenas delimitadores e são descartados; o conteúdo segue como VT100. Um eventual byte de verificação (LRC) após o ETX seria tratado como texto, então não o envie nesse modo.
8.2 “STX/ETX com comandos”
Para sistemas que usam quadros STX <comando> <dados> ETX:
| Quadro | Efeito | Exemplo |
|---|---|---|
STX D <texto> ETX | Escreve o texto (pode conter sequências VT100). | 02 44 "MESA:" 03 |
STX L ETX | Limpa o visor e posiciona em 1;1. | 02 4C 03 |
STX C <l><cc> ETX | Posiciona o cursor com linha (1 dígito) e coluna (2 dígitos) a partir de 0. | STX C105 ETX = linha 2, coluna 6 |
STX P … ETX / STX S … ETX | Dados para impressora/serial do terminal: descartados. | — |
| Outro comando | O conteúdo do quadro é tratado como VT100. | — |
Sequências VT100 fora de quadros continuam funcionando nesse modo. Quadros com mais de 512 bytes sem ETX são exibidos como texto.
9.Teclado: bytes enviados
Cada toque envia imediatamente (sem buffer de linha) os bytes abaixo. Enter, Del e Bck são configuráveis pelo usuário; os valores padrão estão em destaque.
| Tecla | Envia | Opções |
|---|---|---|
| 0–9 | 0x30–0x39 | — |
| . | 0x2E | — |
| , | 0x2C | — |
| Enter | CR 0x0D | CR+LF 0D 0A · LF 0A |
| Del | ESC 0x1B | BS 08 · DEL 7F |
| Bck | BS 0x08 | DEL 7F |
Trate a entrada como um fluxo de bytes: vários toques (e a leitura do leitor de código de barras) podem chegar no mesmo segmento TCP.
10.Leitor de código de barras
A leitura pela câmera envia o conteúdo do código seguido da sequência configurada para Enter, como um leitor de teclado:
7891000012345 + CR → 37 38 39 31 30 30 30 30 31 32 33 34 35 0D
- Formatos: EAN-13, EAN-8, UPC-A/E, Code 128, Code 39, Code 93, ITF, Codabar, QR Code, Data Matrix, PDF417 e Aztec (Google ML Kit, processado no aparelho).
- Uma leitura por abertura do leitor; o conteúdo é enviado exatamente como lido (sem prefixo/sufixo além do Enter).
11.Exemplo de sessão
Login do operador “125” num visor 2×20, com eco feito pelo servidor:
# servidor → app: limpa e pede o operador
ESC[2J ESC[1;1H "OPERADOR:" 1B 5B 32 4A 1B 5B 31 3B 31 48 4F 50 45 ...
# usuário digita 1, 2, 5 (um byte por toque); o servidor ecoa cada um
app → servidor: 31 servidor → app: 31
app → servidor: 32 servidor → app: 32
app → servidor: 35 servidor → app: 35
# usuário corrige com Bck: o servidor ecoa BS (o app apaga o "5")
app → servidor: 08 servidor → app: 08
# Enter confirma; servidor responde na linha 2
app → servidor: 0D
servidor → app: ESC[2;1H ESC[K "BEM-VINDO JOAO"
12.Servidor de teste
Para testar sem o sistema completo, rode este servidor mínimo (Python 3) no computador e aponte o app para o IP dele, porta 1001. Ele desenha uma tela, ecoa os dígitos, trata Bck e responde ao Enter:
import socket, threading
ESC = "\x1b"
def atender(conn, addr):
print("terminal conectado:", addr[0])
def envia(texto):
conn.sendall(texto.encode("latin-1"))
envia(f"{ESC}[2J{ESC}[1;1HMTERMINAL TESTE{ESC}[2;1HDIGITE: ")
digitado = ""
while True:
dados = conn.recv(64)
if not dados:
break
for b in dados:
ch = chr(b)
if ch.isdigit():
digitado += ch
envia(ch) # eco
elif b == 0x08 and digitado: # Bck
digitado = digitado[:-1]
envia("\x08")
elif b == 0x0D: # Enter
envia(f"{ESC}[1;1H{ESC}[KRECEBIDO: {digitado}"
f"{ESC}[2;1H{ESC}[KDIGITE: ")
digitado = ""
elif b == 0x1B: # Del
digitado = ""
envia(f"{ESC}[2;1H{ESC}[KDIGITE: ")
conn.close()
srv = socket.socket()
srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
srv.bind(("0.0.0.0", 1001))
srv.listen()
while True:
threading.Thread(target=atender, args=srv.accept(), daemon=True).start()
Alternativa rápida para ver apenas a exibição: ncat -l 1001 (ou nc -l -p 1001 no Linux) e digite o texto a enviar.
13.Boas práticas do servidor
- Aceite várias conexões simultâneas, uma por aparelho.
- Reconexão do mesmo IP: ao receber uma nova conexão de um IP que já tem sessão, encerre a sessão antiga e continue na nova. O app nunca mantém duas conexões, então a antiga está morta.
- Redesenhe a tela inteira no início de cada conexão (
ESC[2J+ conteúdo), porque o visor mantém o conteúdo anterior. - Posicione o cursor explicitamente (
ESC[l;cH) e limpe comESC[K, em vez de depender de LF e rolagem. - Faça o eco dos caracteres digitados que devem aparecer no visor, e ecoe
BSao apagar. - Trate a entrada como fluxo: não assuma um toque por pacote.
- Não derrube conexões ociosas muito cedo: o operador pode passar vários minutos sem digitar. Detecte conexões mortas por falha de envio ou pela chegada de uma nova conexão do mesmo IP.
- Mantenha o texto dentro do formato configurado (ex.: 20 colunas no 2×20) e use Latin-1 para acentos.
14.Checklist de homologação
| # | Teste | Resultado esperado |
|---|---|---|
| 1 | Cadastrar o IP do aparelho e abrir o app | Status “CONECTADO” e tela inicial do sistema no visor. |
| 2 | Digitar números | Eco correto na posição esperada. |
| 3 | Bck, Del e Enter | Apagar, cancelar e confirmar funcionam no fluxo do sistema. |
| 4 | Ler um código de barras de produto | Produto lançado como se tivesse sido digitado + Enter. |
| 5 | Textos com acentos | Acentos exibidos corretamente (Latin-1). |
| 6 | Desligar o Wi-Fi do aparelho por 30 s e religar | O app reconecta sozinho; o servidor aceita a nova conexão e redesenha a tela. |
| 7 | Reiniciar o servidor de microterminais | O app reconecta em até 30 s. |
| 8 | Vários aparelhos ao mesmo tempo | Cada um com sua sessão, sem interferência. |
| 9 | Alterar e salvar as Configurações do app | Uma única nova conexão; nenhuma sessão duplicada no servidor. |
| 10 | Fluxo completo de venda (mesa/comanda, itens, fechamento) | Igual ao microterminal físico equivalente. |
15.Configurações do app (referência)
Para orientar o cliente final, estes são os campos em Configurações e os valores padrão:
| Campo | Padrão | Observação |
|---|---|---|
| IP do Servidor | — | IP ou nome do host do servidor de microterminais. |
| Porta TCP | 1001 | 1 a 65535. |
| Identificador do Terminal | — | Exibido no app; enviado apenas se a opção abaixo estiver ligada. |
| Enviar identificador ao conectar | Desligado | Seção 4.2. |
| Protocolo | VT100 / ANSI | Ou “STX/ETX com comandos” (seção 8). |
| Backspace do servidor apaga o caractere | Ligado | Desligue para VT100 estrito (BS só move o cursor). |
| Formato do visor | 2×20 | 2×16, 2×20, 2×40, 4×20. |
| Enter / Del / Bck | CR / ESC / BS | Seção 9. |
| Tema, bip, manter tela ligada | Verde, ligado, ligado | Apenas visuais/conforto. |
16.Limitações conhecidas
- Sem impressora, porta serial ou balança acopladas ao terminal: dados enviados a elas (media copy, quadros
P/S) são descartados. - Sem vídeo reverso, piscante ou sublinhado no visor.
- Sem rolagem de tela (seção 5).
- Sem teclas de função dedicadas (F1–F4) no teclado atual.
- Sem TLS; uso previsto em rede local.
- Com o app em segundo plano ou a tela desligada, o Android pode encerrar a conexão; o app reconecta ao voltar.
17.Contato técnico
Dúvidas de integração, relatos de incompatibilidade ou pedidos de novas sequências: suporte.dns.apps@gmail.com. Ajuda informar o sistema, a versão, o formato do visor e, se possível, uma captura dos bytes enviados pelo servidor.
Para orientar seus clientes no uso diário, indique o Manual do Usuário.