@4demar/icard-electron-sdk
v0.1.1
Published
SDK TypeScript do leitor i-card (Chafon UHF RFID via BLE) para aplicações React + Electron usando Web Bluetooth.
Maintainers
Readme
@4demar/icard-electron-sdk
SDK TypeScript do leitor i-card (Chafon UHF RFID via BLE) para aplicações React + Electron.
Usa Web Bluetooth (navigator.bluetooth) no processo renderer do Electron, mantendo o mesmo
protocolo de bytes do reader Chafon (serviço BLE ffe0, característica ffe1, CRC-16 polinômio
0x8408).
Instalação
npm install @4demar/icard-electron-sdkPré-requisito obrigatório (Electron)
navigator.bluetooth roda no processo renderer, mas o Electron não abre o seletor de
dispositivos sozinho. É obrigatório tratar o evento select-bluetooth-device no processo main.
Sem isso, ICardReader.connect() nunca resolve.
No main.ts, após criar a BrowserWindow:
import { BrowserWindow } from 'electron';
const win = new BrowserWindow({ /* ... */ });
// Trata a seleção de dispositivo BLE.
win.webContents.on('select-bluetooth-device', (event, devices, callback) => {
event.preventDefault();
// Estratégia simples: conecta no primeiro reader com nome.
// Para uma UI de seleção, envie `devices` ao renderer via IPC.
const reader = devices.find((d) => d.deviceName && d.deviceName.length > 0);
if (reader) {
callback(reader.deviceId);
}
// Se a lista estiver incompleta, o evento é reemitido com novos devices.
});
// Concede permissões de Bluetooth.
win.webContents.session.setPermissionRequestHandler((_wc, _perm, cb) => cb(true));
win.webContents.session.setPermissionCheckHandler(() => true);No Windows, o rádio Bluetooth precisa estar ligado no SO.
Uso básico (React + TypeScript)
import { useRef, useState } from 'react';
import { ICardReader } from '@4demar/icard-electron-sdk';
export function LeituraRFID() {
const readerRef = useRef<ICardReader | null>(null);
const [tags, setTags] = useState<Set<string>>(new Set());
const [conectado, setConectado] = useState(false);
async function conectar() {
const reader = new ICardReader();
readerRef.current = reader;
// DEVE ser chamado a partir de um clique (gesto do usuário).
const nome = await reader.connect();
console.log('Conectado a', nome);
// Aplica a configuração padrão.
await reader.setPower(30);
await reader.setInventoryScanTime(50); // 50 * 100ms = 5s
await reader.setRegion(15, 0); // região Brasil
reader.onDisconnected(() => setConectado(false));
setConectado(true);
// Inventário contínuo.
await reader.scan((epcs) => {
setTags((prev) => {
const next = new Set(prev);
epcs.filter((e) => e.startsWith('30')).forEach((e) => next.add(e));
return next;
});
});
}
function parar() {
readerRef.current?.stopScan();
}
function desconectar() {
readerRef.current?.disconnect();
setConectado(false);
}
return (
<div>
<button onClick={conectar} disabled={conectado}>Conectar e ler</button>
<button onClick={parar} disabled={!conectado}>Parar</button>
<button onClick={desconectar} disabled={!conectado}>Desconectar</button>
<p>Tags lidas: {tags.size}</p>
<ul>
{[...tags].map((epc) => <li key={epc}>{epc}</li>)}
</ul>
</div>
);
}API — ICardReader
Conexão
| Método | Descrição |
|--------|-----------|
| connect(namePrefix?) | Abre o seletor BLE e conecta. Chamar em clique. Retorna o nome do device. |
| connectToDevice(device) | Conecta a um BluetoothDevice já obtido (reconexão). |
| disconnect() | Encerra a conexão BLE. |
| isConnected | boolean — se há conexão ativa. |
| onDisconnected(cb) | Registra callback de queda da conexão GATT. |
Inventário (scan)
| Método | Descrição |
|--------|-----------|
| scan(callback) | Inicia inventário contínuo. callback(epcs: string[]) é chamado a cada ciclo com os EPCs hex lidos. |
| stopScan() | Para o inventário. |
| isScanning | boolean — se há scan ativo. |
Configuração do reader
| Método | Descrição |
|--------|-----------|
| getReaderInfo() | Retorna { status, version, power, frequency }. |
| setPower(0..30) | Define a potência. Retorna 0 em sucesso. |
| setInventoryScanTime(3..255) | Tempo de scan (cada unidade = 100ms). |
| setRegion(max, min) | Frequência da região (Brasil: 15, 0). |
Memória da tag (EPC Gen2)
| Método | Descrição |
|--------|-----------|
| readDataG2(epc, mem, wordAddr, num, psd?) | Lê words da tag. Retorna Uint8Array ou null. |
| writeDataG2(epc, mem, wordAddr, data, psd?) | Escreve words na tag. Retorna 0 em sucesso. |
Exportações avançadas
Além da ICardReader, o pacote exporta utilitários de protocolo para uso em testes ou integrações de baixo nível:
import {
// Transporte BLE
BleTransport,
UUID_CHAFON_RFID_SERVICE,
UUID_CHAFON_RFID_CHARACTERISTIC,
// Códigos de comando
EpcC1G2Command,
ReaderDefinedCommand,
CommandResultStatus,
// Parsing
parseResponseBuffer,
getInventoryDataBuffer,
parseInventoryResult,
extractEpcs,
// Construtores de frames
createInventoryG2StartMessage,
createReadDataG2Message,
createWriteG2Message,
createSetPowerMessage,
createSetInventoryScanTimeMessage,
createSetRegionMessage,
createGetReaderInfoMessage,
// Utilitários de bytes
bytesToHex,
hexToBytes,
execCRC,
checkCRC,
} from '@4demar/icard-electron-sdk';Regras de uso
- Um scan por vez. Pare o scan (
stopScan()) antes de enviar comandos de configuração — o reader não processa ambos em paralelo. A SDK lança erro se tentar. - Gesto do usuário obrigatório.
connect()depende derequestDevice, que só funciona a partir de um clique. Não é possível conectar automaticamente no boot. - Reconexão limitada. Depende do Chromium/Electron reter permissão (
getDevices()quando disponível). UseconnectToDevice(device)se tiver a referência do device.
Publicação (mantenedores)
cd icard-electron-sdk
# Autenticação (uma vez):
npm login --scope=@4demar --registry=https://npm.pkg.github.com
# Publicar (roda build automaticamente via prepublishOnly):
npm publishPara atualizar a versão:
npm version patch # ou minor / major
npm publish