Integrando impressora térmica bluetooth portátil com aplicativos Delphi Multi-Device

impressora-termica-bolso-android-w8-bluetooth-recibos-taxi-849811-MLB20674273238_042016-F

Neste post iremos implementar um aplicativo mobile para efetuar a impressão diretamente em uma impressora térmica bluetooth sem utilização alguma de SDKs de terceiros, tudo 100% Delphi nativo. No exemplo iremos focar apenas nos métodos necessários para demonstrarmos a integração.

Postado a pouco tempo, foi visto como efetuar a integração de seu aplicativo mobile feito em Delphi com uma impressora bluetooth utilizando seu SDK feito em java. Esse modelo de integração é interessante quando precisamos utilizar alguma funcionalidade especifica do fabricante. http://community.embarcadero.com/blog-drafts?view=entry&id=8616

Em sua maioria estas impressoras trabalham da mesmo forma que a “moderníssima” Impressora Epson LX 300 (se você não conhece este modelo de impressora peça auxilio à um adulto).

Nesse passado não muito distante, a impressão poderia ser realizada através do envio de comandos ESC/POS para a porta paralela onde a impressora estava conectada. E é desta mesma forma que iremos proceder, mas ao invés de enviarmos comandos para a porta paralela iremos envia-los através de uma porta Bluetooth.

Como todo bom Delpheiro você deve estar pensando que o Delphi provavelmente já tenha um componente que fará a conexão Bluethooth para nós e depois só precisaremos enviar os comandos de impressão.
E como todo bom Delfeiro, você está certo!

O Delphi possui o componente TBluetooth, que encapsula todo o mecanismos de comunicação Bluetooth do seu dispositivo mobile. É ele por exemplo que é responsável por listar os dispositivos pareados em nosso mobile, alem de efetuar a conexão com os dispositivo bluetooth e enviar comandos para este dispositivo.

Então vamos por a mão massa:

Para nosso exemplo crie uma aplicação multi-device em branco. (File\New\Mult-Device Application\Bank Application).

Antes de tudo devemos configurar o projeto para que o aplicativo tenha permissão para acessar o Bluetooth do mobile, então no menu Project\Options\Uses Permissions, habilite as opções Bluetooth e Bluetooth admin.

Project Options

Coloque um componente TBluetooth no formulário e altere sua propriedade Enable para True. Em nosso exemplo deixaremos o componente sempre ativo.

Coloque um ComboBox, no qual iremos listar os dispositivos Bluetooth pareados em nosso mobile.

O comando é bem simples, o método PairedDevices do componente TBluetooth retorna a lista de dispositivos pareados, desta forma só precisamos percorrer a lista e popular o nosso ComboBox.

procedure TfrmImpressora.ListarDispositivosPareadosNoCombo;
var
  lDevice: TBluetoothDevice;
begin
  ComboBox1.Clear;
  for lDevice in Bluetooth1.PairedDevices do
  begin
    ComboBox1.Items.Add(lDevice.DeviceName);
  end;
end;

Coloque um botão para efetuar a chamada deste código.
Assim quando você clicar neste botão o ComboBox será atualizado com a lista de dispositivos pareados.

Vamos para nossa segunda funcionalidade, a conexão com o dispositivo.

Primeiramente é preciso selecionar o dispositivo que será conectado. Um dispositivo Bluetooth é encapsulado pela classe TBluetoothDevice. Criaremos uma função que nos retorne o dispositivo usando como parâmetro seu nome, que estará selecionado no ComboBox.

function TfrmImpressora.ObterDevicePeloNome(pNomeDevice: String): TBluetoothDevice;
var
  lDevice: TBluetoothDevice;
begin
  Result := nil;
  for lDevice in Bluetooth1.PairedDevices do
  begin
    if lDevice.DeviceName = pNomeDevice then
    begin
      Result := lDevice;
    end;
  end;
end;

As conexões Bluetooth são encapsuladas por uma classe Socket, a TBluetoothSocket. Esta classe é instanciada por um TBluetoothDevice. Executando o método ObterDevicePeloNome, teremos como retorno um TBluetoothDevice. E este objeto possui o método CreateClientSocket que irá criar nosso objeto Socket.

FSocket := lDevice.CreateClientSocket...

Cada tipo de dispositivo Bluetooth pode utilizar um tipo de Socket diferente. Por exemplo, um fone se comunica de uma forma diferente que uma impressora, mas ambos são Bluetooth, e estas configurações são dadas por um parâmetro UUID no método de criação do Socket.
O UUID é um identificador único universal, por exemplo, seja qual for o fabricante de fones Bluetooth eles irão utilizar o mesmo UUID para esta comunicação. (https://en.wikipedia.org/wiki/Universally_unique_identifier)

As Impressoras BT usam uma SerialPortServiceClass, que é definida pelo UUID 00001101-0000-1000-8000-00805F9B34FB.

const
UUID = '{00001101-0000-1000-8000-00805F9B34FB}';

Defina uma variável global FSocket: TBluetoothSocket para armazenar o objeto de conexão, e assim poder ser utilizados em outros métodos, como no de impressão.

function TfrmImpressora.ConectarImpressora(pNomeDevice: String): boolean;
var
  lDevice: TBluetoothDevice;
begin
  Result := False;
  lDevice := ObterDevicePeloNome(pNomeDevice);
  if lDevice <> nil then
  begin
    FSocket := lDevice.CreateClientSocket(StringToGUID(UUID), False);
    if FSocket <> nil then
    begin
      FSocket.Connect;
      Result := FSocket.Connected
    end;
  end;
end;

Em um TButton chame o método ConectarImpressora passando como parãmetro o dispositivo selecionado no ComboBox, como no exemplo abaixo:

procedure TfrmImpressora.btnConectarClick(Sender: TObject);
begin
  if (ComboBox1.Selected <> nil) and (ComboBox1.Selected.Text <> '') then
  begin
    if ConectarImpressora(ComboBox1.Selected.Text) then
    begin
      Label1.Text := 'Conectado';
    end
    else
    begin
      Label1.Text := 'Desconectado';
    end;
  end 
  else 
  begin
    ShowMessage('Selecione um dispositivo');
  end;
end;

Para finalizar basta enviarmos através do método SendData do Socket os comandos da impressora (A lista de comandos geralmente acompanham o manual do produto).

procedure TfrmImpressora.btnImprimirClick(Sender: TObject);
begin
  if (FSocket <> nil) and (FSocket.Connected) then
  begin
    FSocket.SendData(TEncoding.UTF8.GetBytes(chr(27) + chr(64)));
    FSocket.SendData(TEncoding.UTF8.GetBytes(chr(27) + chr(97) + chr(1)));
    FSocket.SendData(TEncoding.UTF8.GetBytes(chr(27) + chr(33) + chr(8)));
    FSocket.SendData(TEncoding.UTF8.GetBytes(chr(27) + chr(33) + chr(16)));
    FSocket.SendData(TEncoding.UTF8.GetBytes(chr(27) + chr(33) + chr(32)));

    FSocket.SendData(TEncoding.UTF8.GetBytes('Delphi Berlin' + chr(13)));
    FSocket.SendData(TEncoding.UTF8.GetBytes(chr(27) + chr(100) + chr(1)));
    FSocket.SendData(TEncoding.UTF8.GetBytes('Delphi Berlin' + chr(13)));
    FSocket.SendData(TEncoding.UTF8.GetBytes(chr(27) + chr(100) + chr(1)));
    FSocket.SendData(TEncoding.UTF8.GetBytes(chr(27) + chr(33) + chr(0)));

    FSocket.SendData(TEncoding.UTF8.GetBytes('Utilizando TBluetooth '));
    FSocket.SendData(TEncoding.UTF8.GetBytes(chr(27) + chr(100) + chr(1)));
    FSocket.SendData(TEncoding.UTF8.GetBytes('Utilizando TBluetooth '));
    FSocket.SendData(TEncoding.UTF8.GetBytes(chr(27) + chr(100) + chr(1)));

    FSocket.SendData(TEncoding.UTF8.GetBytes(chr(27) + chr(97) + chr(0)));
    FSocket.SendData(TEncoding.UTF8.GetBytes(chr(27) + chr(100) + chr(5)));
    FSocket.SendData(TEncoding.UTF8.GetBytes(chr(29) + chr(107) + chr(2) + '7896006259701' + chr(0)));
    FSocket.SendData(TEncoding.UTF8.GetBytes(chr(27) + chr(100) + chr(5)));
  end;
end;

Neste método fizemos o envio de diversos comandos de impressão como, quebra de linha, mudança de fontes e impressão de um código de barras.

A partir deste momento seu aplicativo já está integrado com nossa impressora Bluetooth, e sem utilizar qualquer outra biblioteca que não acompanhe a instalação básica do Delphi.

Segue abaixo uma lista de UUID de vários tipos de conexões bluetooth:

ServiceDiscoveryServerServiceClassID= ‘{00001000-0000-1000-8000-00805F9B34FB}’;
BrowseGroupDescriptorServiceClassID = ‘{00001001-0000-1000-8000-00805F9B34FB}’;
PublicBrowseGroupServiceClass = ‘{00001002-0000-1000-8000-00805F9B34FB}’;
SerialPortServiceClass = ‘{00001101-0000-1000-8000-00805F9B34FB}’;
LANAccessUsingPPPServiceClass = ‘{00001102-0000-1000-8000-00805F9B34FB}’;
DialupNetworkingServiceClas = ‘{00001103-0000-1000-8000-00805F9B34FB}’;
IrMCSyncServiceClass = ‘{00001104-0000-1000-8000-00805F9B34FB}’;
OBEXObjectPushServiceClass= ‘{00001105-0000-1000-8000-00805F9B34FB}’;
OBEXFileTransferServiceClass = ‘{00001106-0000-1000-8000-00805F9B34FB}’;
IrMCSyncCommandServiceClass= ‘{00001107-0000-1000-8000-00805F9B34FB}’;
HeadsetServiceClass = ‘{00001108-0000-1000-8000-00805F9B34FB}’;
CordlessTelephonyServiceClass = ‘{00001109-0000-1000-8000-00805F9B34FB}’;
AudioSourceServiceClass = ‘{0000110A-0000-1000-8000-00805F9B34FB}’;
AudioSinkServiceClass= ‘{0000110B-0000-1000-8000-00805F9B34FB}’;
AVRemoteControlTargetServiceClass = ‘{0000110C-0000-1000-8000-00805F9B34FB}’;
AdvancedAudioDistributionServiceClass = ‘{0000110D-0000-1000-8000-00805F9B34FB}’;
AVRemoteControlServiceClass= ‘{0000110E-0000-1000-8000-00805F9B34FB}’;
VideoConferencingServiceClass = ‘{0000110F-0000-1000-8000-00805F9B34FB}’;
IntercomServiceClass = ‘{00001110-0000-1000-8000-00805F9B34FB}’;
FaxServiceClass = ‘{00001111-0000-1000-8000-00805F9B34FB}’;
HeadsetAudioGatewayServiceClass= ‘{00001112-0000-1000-8000-00805F9B34FB}’;
WAPServiceClass = ‘{00001113-0000-1000-8000-00805F9B34FB}’;
WAPClientServiceClass = ‘{00001114-0000-1000-8000-00805F9B34FB}’;
PANUServiceClass = ‘{00001115-0000-1000-8000-00805F9B34FB}’;
NAPServiceClass = ‘{00001116-0000-1000-8000-00805F9B34FB}’;
GNServiceClass = ‘{00001117-0000-1000-8000-00805F9B34FB}’;
DirectPrintingServiceClass = ‘{00001118-0000-1000-8000-00805F9B34FB}’;
ReferencePrintingServiceClass = ‘{00001119-0000-1000-8000-00805F9B34FB}’;
ImagingServiceClass= ‘{0000111A-0000-1000-8000-00805F9B34FB}’;
ImagingResponderServiceClass = ‘{0000111B-0000-1000-8000-00805F9B34FB}’;
ImagingAutomaticArchiveServiceClass = ‘{0000111C-0000-1000-8000-00805F9B34FB}’;
ImagingReferenceObjectsServiceClass = ‘{0000111D-0000-1000-8000-00805F9B34FB}’;
HandsfreeServiceClass = ‘{0000111E-0000-1000-8000-00805F9B34FB}’;
HandsfreeAudioGatewayServiceClass = ‘{0000111F-0000-1000-8000-00805F9B34FB}’;
DirectPrintingReferenceObjectsServiceClass = ‘{00001120-0000-1000-8000-00805F9B34FB}’;
ReflectedUIServiceClass = ‘{00001121-0000-1000-8000-00805F9B34FB}’;
BasicPringingServiceClass = ‘{00001122-0000-1000-8000-00805F9B34FB}’;
PrintingStatusServiceClass= ‘{00001123-0000-1000-8000-00805F9B34FB}’;
HumanInterfaceDeviceServiceClass = ‘{00001124-0000-1000-8000-00805F9B34FB}’;
HardcopyCableReplacementServiceClass = ‘{00001125-0000-1000-8000-00805F9B34FB}’;
HCRPrintServiceClas = ‘{00001126-0000-1000-8000-00805F9B34FB}’;
HCRScanServiceClass= ‘{00001127-0000-1000-8000-00805F9B34FB}’;
CommonISDNAccessServiceClass = ‘{00001128-0000-1000-8000-00805F9B34FB}’;
VideoConferencingGWServiceClass = ‘{00001129-0000-1000-8000-00805F9B34FB}’;
UDIMTServiceClass = ‘{0000112A-0000-1000-8000-00805F9B34FB}’;
UDITAServiceClass = ‘{0000112B-0000-1000-8000-00805F9B34FB}’;
AudioVideoServiceClass = ‘{0000112C-0000-1000-8000-00805F9B34FB}’;
SIMAccessServiceClass = ‘{0000112D-0000-1000-8000-00805F9B34FB}’;
PnPInformationServiceClass= ‘{00001200-0000-1000-8000-00805F9B34FB}’;
GenericNetworkingServiceClass = ‘{00001201-0000-1000-8000-00805F9B34FB}’;
GenericFileTransferServiceClass = ‘{00001202-0000-1000-8000-00805F9B34FB}’;
GenericAudioServiceClass= ‘{00001203-0000-1000-8000-00805F9B34FB}’;
GenericTelephonyServiceClass = ‘{00001204-0000-1000-8000-00805F9B34FB}’;

 

44 thoughts on “Integrando impressora térmica bluetooth portátil com aplicativos Delphi Multi-Device

  1. O tutorial é bem bacana e dá um grande ponta-pé inicial, mas seria possível, colocar como comentário, na parte em que faz o envio dos dados para a impressora, o que faz cada conjunto de comandos que estão sendo utilizados?? Tentei isolar cada bloco, mas o resultado é um pouco confuso e não consegui decifrar… o manual da impressora então (Datec DPP-250) tem todos os códigos, mas entender como usá-los está bem complicado….
    Agradeço sua ajuda.

  2. Opa funcionou que é uma maravilha. Agora estou com problema na impressão de caracteres especiais, já tentei acho que todos os comandos esc, mas não consegui resolver. Teve esse problema?

  3. Não imprime nada, rodei tanto com o projeto para download quanto com meu próprio projeto, mesmo assim não imprime nada, pisca os leds azuis na impressora mas não sai impressão. Alguém pode me ajudar?

  4. Otimo artigo parabéns!
    Aqui na minha impressora não saiu o código de barras e após a impressão do texto eu preciso reiniciá-la para utilizá-la novamente!

    O que pode ser?
    Obrigado!

  5. Parabéns pelo artigo, muito didático e preciso. Fiz o teu exemplo, utilizei uma DPP250, pareou e conectou, porém não imprime nada. Falta alguma coisa?

  6. Alguem conseguiu fazer a comunicação coma impressora DPP 250, estou a dias tentando fazer essa comunicação mas nada…

    Está listando normal e conecnado com a impressora. mas, quando eu tento imprimir seguindo esses comandos esc pos aí. Nao imprime de jeito nenhum ,… nao sei nem mais o que faço …
    me ajudem aí pessoal !!

  7. Boa tarde, preciso que ela imprima direto de um site, como faço?
    Tem como? qual delphi utilizado no exemplo acima?

    Quanto cobraria para desenvolver o app pra mim que imprima do site que tenho? 99 991385001 whats

  8. Estou tentando imprimir seguindo este tutorial e a DPP-250 não imprime, conecta Bluetooth mas não imprime (fica piscando azul, marcando conexão).

    Alguém sabe o motivo?

  9. Alangei, vc salvou essa etapa do meu projeto! Muito obrigado.
    Tenho uma dica: coloque o link do vídeo e esse detalhe do Swicth no tutorial, será de grande ajuda para os futuros delpheiros.
    Muito obrigado

  10. Ola meu amigo, você teria um exemplo de como efetuar o ajuste do tamanho do código de barras e um exemplo de emissão de qrcode com esc/pos.

  11. Para enviar código de barras existe um código usado, como o código para trocar de fonte, vc sabe qual o método utilizado para enviar imagem para a impressora?

    1. Sim, para imprimir um código de barras deve usar comandos específicos para cada tipo de código… vou montar um exemplo simples de impressão de imagens e publicar ok!

  12. Parabéns pelo tutorial. Baita ajuda, dá um norte gigante. Já estava pensando em adicionar SDK da impressora e etc e assim funcionou direto. Existe uma forma de imprimir usando comando de linha coluna?

  13. Estou usando a impressora intermec pr2, ela conecta porém quando manda imprimir fica piscando a luz e não imprime nada. Já vi um vídeo que está no comentário porém não é o mesmo modelo da impressora que estou usando.

  14. Bom dia Alan!
    Muito bom o material. Estou tentando realizar a impressão na vertical(boleto bancário) e não estou conseguindo. Tentei utilizar os comandos, segundo o manual, e mesmo assim não estou conseguindo.
    Alguma dica?
    Obrigado.

Leave a Reply