1042 lines
43 KiB
JavaScript
1042 lines
43 KiB
JavaScript
const net = require('net');
|
|
|
|
class FiberhomeManager {
|
|
constructor() {
|
|
this.tl1Connection = null;
|
|
this.commandId = 1;
|
|
|
|
// Configuração apenas para UNM2000 via TL1
|
|
this.config = {
|
|
unm2000: {
|
|
host: '131.0.192.9',
|
|
port: 3337,
|
|
username: '1',
|
|
password: '1',
|
|
timeout: 15000
|
|
},
|
|
olt: {
|
|
name: '131.0.192.9' // OLT configurada no TL1
|
|
}
|
|
};
|
|
|
|
this.logger = require('../utils/logger');
|
|
}
|
|
|
|
/**
|
|
* Testar conectividade de rede com um host
|
|
*/
|
|
async testarConectividade(host, port, timeout = 5000) {
|
|
return new Promise((resolve) => {
|
|
const socket = new net.Socket();
|
|
|
|
socket.setTimeout(timeout);
|
|
|
|
socket.connect(port, host, () => {
|
|
this.logger.debug(`Conectividade OK: ${host}:${port}`);
|
|
socket.destroy();
|
|
resolve(true);
|
|
});
|
|
|
|
socket.on('error', (error) => {
|
|
this.logger.debug(`Erro de conectividade ${host}:${port}:`, error.message);
|
|
resolve(false);
|
|
});
|
|
|
|
socket.on('timeout', () => {
|
|
this.logger.debug(`Timeout de conectividade ${host}:${port}`);
|
|
socket.destroy();
|
|
resolve(false);
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Conectar ao UNM2000 via TL1
|
|
*/
|
|
async conectarUNM2000() {
|
|
try {
|
|
if (this.tl1Connection && !this.tl1Connection.destroyed) {
|
|
console.log('✅ Conexão TL1 já existe e está ativa');
|
|
this.logger.debug('Conexão TL1 já existe e está ativa');
|
|
return true;
|
|
}
|
|
|
|
console.log('🔌 Conectando ao UNM2000 via TL1:', this.config.unm2000);
|
|
this.logger.debug('Conectando ao UNM2000 via TL1', this.config.unm2000);
|
|
|
|
return new Promise((resolve, reject) => {
|
|
this.tl1Connection = new net.Socket();
|
|
let authenticated = false;
|
|
let dataBuffer = '';
|
|
|
|
this.tl1Connection.setTimeout(this.config.unm2000.timeout);
|
|
|
|
// Handler para dados recebidos
|
|
this.tl1Connection.on('data', (data) => {
|
|
dataBuffer += data.toString();
|
|
console.log('📥 TL1 dados recebidos:', dataBuffer);
|
|
this.logger.debug('TL1 dados recebidos:', dataBuffer);
|
|
|
|
// Verificar se login foi bem-sucedido
|
|
if (!authenticated && dataBuffer.includes('COMPLD')) {
|
|
authenticated = true;
|
|
console.log('✅ Login TL1 bem-sucedido!');
|
|
this.logger.info('Login TL1 bem-sucedido');
|
|
resolve(true);
|
|
} else if (!authenticated && dataBuffer.includes('DENY')) {
|
|
console.log('❌ Login TL1 negado!');
|
|
this.logger.error('Login TL1 negado');
|
|
reject(new Error('Login TL1 negado'));
|
|
}
|
|
});
|
|
|
|
this.tl1Connection.connect(this.config.unm2000.port, this.config.unm2000.host, () => {
|
|
console.log('🔗 Socket TL1 conectado, enviando comando de login');
|
|
this.logger.debug('Socket TL1 conectado, enviando comando de login');
|
|
|
|
// Comando de login TL1 - formato correto: LOGIN:::CTAG::UN=username,PWD=password;
|
|
const loginCommand = `LOGIN:::${this.commandId++}::UN=${this.config.unm2000.username},PWD=${this.config.unm2000.password};`;
|
|
console.log('📤 Enviando login:', loginCommand);
|
|
this.tl1Connection.write(loginCommand + '\r\n');
|
|
|
|
// Timeout para autenticação
|
|
setTimeout(() => {
|
|
if (!authenticated) {
|
|
console.log('⏱️ Timeout na autenticação TL1 (10s). DataBuffer:', dataBuffer);
|
|
this.logger.error('Timeout na autenticação TL1', { dataBuffer });
|
|
reject(new Error('Timeout na autenticação TL1'));
|
|
}
|
|
}, 10000);
|
|
});
|
|
|
|
this.tl1Connection.on('error', (error) => {
|
|
console.log('❌ Erro na conexão TL1:', error.message);
|
|
this.logger.error('Erro na conexão TL1', error);
|
|
reject(error);
|
|
});
|
|
|
|
this.tl1Connection.on('timeout', () => {
|
|
console.log('⏱️ Timeout do socket TL1');
|
|
this.logger.error('Timeout na conexão TL1');
|
|
reject(new Error('Timeout na conexão TL1'));
|
|
});
|
|
|
|
this.tl1Connection.on('close', () => {
|
|
console.log('🔌 Conexão TL1 fechada');
|
|
this.logger.debug('Conexão TL1 fechada');
|
|
this.tl1Connection = null;
|
|
});
|
|
});
|
|
|
|
} catch (error) {
|
|
this.logger.error('Erro ao conectar UNM2000', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Executar comando TL1
|
|
*/
|
|
async executarComandoTL1(comando) {
|
|
try {
|
|
this.logger.debug('Executando comando TL1', { comando });
|
|
|
|
if (!this.tl1Connection || this.tl1Connection.destroyed) {
|
|
const conectado = await this.conectarUNM2000();
|
|
if (!conectado) {
|
|
throw new Error('Não foi possível conectar ao UNM2000');
|
|
}
|
|
}
|
|
|
|
return new Promise((resolve, reject) => {
|
|
let dataBuffer = '';
|
|
let responseReceived = false;
|
|
|
|
// Handler temporário para esta consulta
|
|
const dataHandler = (data) => {
|
|
dataBuffer += data.toString();
|
|
this.logger.debug('Resposta TL1 recebida:', dataBuffer);
|
|
|
|
// Verificar se a resposta está completa (termina com ;)
|
|
if (dataBuffer.includes(';') && !responseReceived) {
|
|
responseReceived = true;
|
|
this.tl1Connection.removeListener('data', dataHandler);
|
|
|
|
if (dataBuffer.includes('COMPLD')) {
|
|
resolve({
|
|
success: true,
|
|
data: dataBuffer
|
|
});
|
|
} else if (dataBuffer.includes('DENY')) {
|
|
resolve({
|
|
success: false,
|
|
error: 'Comando negado pelo equipamento'
|
|
});
|
|
} else {
|
|
resolve({
|
|
success: false,
|
|
error: 'Resposta inválida do equipamento'
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
this.tl1Connection.on('data', dataHandler);
|
|
|
|
// Enviar comando TL1 com ID único
|
|
const comandoComId = comando.replace(':1;', `:${this.commandId++};`);
|
|
this.tl1Connection.write(comandoComId + '\r\n');
|
|
|
|
// Timeout para resposta
|
|
setTimeout(() => {
|
|
if (!responseReceived) {
|
|
this.tl1Connection.removeListener('data', dataHandler);
|
|
reject(new Error('Timeout aguardando resposta TL1'));
|
|
}
|
|
}, 10000);
|
|
});
|
|
|
|
} catch (error) {
|
|
this.logger.error('Erro ao executar comando TL1', { comando, error: error.message });
|
|
return {
|
|
success: false,
|
|
error: error.message
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Obter status de ONU via TL1
|
|
*/
|
|
async obterStatusONU(serial) {
|
|
try {
|
|
this.logger.debug('Obtendo status da ONU via TL1', { serial });
|
|
|
|
// Conectar ao UNM2000
|
|
const conectado = await this.conectarUNM2000();
|
|
if (!conectado) {
|
|
throw new Error('Não foi possível conectar ao UNM2000');
|
|
}
|
|
|
|
// Comando TL1 para buscar informações da ONU
|
|
const comando = `RTRV-ONU::${serial}:1;`;
|
|
this.logger.debug('Executando comando TL1', { comando });
|
|
|
|
const resultado = await this.executarComandoTL1(comando);
|
|
|
|
if (!resultado.success) {
|
|
throw new Error(resultado.error || 'Falha na consulta TL1');
|
|
}
|
|
|
|
// Processar resposta TL1 da ONU
|
|
const statusONU = this.processarStatusONUTL1(resultado.data, serial);
|
|
|
|
this.logger.debug('Status ONU processado via TL1', statusONU);
|
|
|
|
return {
|
|
success: true,
|
|
...statusONU
|
|
};
|
|
|
|
} catch (error) {
|
|
this.logger.error('Erro ao obter status da ONU via TL1', { serial, error: error.message });
|
|
return {
|
|
success: false,
|
|
error: error.message,
|
|
serial
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Obter status da ONU por device name via TL1
|
|
*/
|
|
async obterStatusONUPorNome(deviceName) {
|
|
try {
|
|
this.logger.debug('Obtendo status da ONU por nome via TL1', { deviceName });
|
|
|
|
// Conectar ao UNM2000
|
|
const conectado = await this.conectarUNM2000();
|
|
if (!conectado) {
|
|
throw new Error('Não foi possível conectar ao UNM2000');
|
|
}
|
|
|
|
// Comando TL1 para buscar ONU por nome
|
|
const comando = `RTRV-ONU::${deviceName}:1;`;
|
|
this.logger.debug('Executando comando TL1', { comando });
|
|
|
|
const resultado = await this.executarComandoTL1(comando);
|
|
|
|
if (!resultado.success) {
|
|
throw new Error(resultado.error || 'Falha na consulta TL1');
|
|
}
|
|
|
|
// Processar resposta TL1 da ONU
|
|
const statusONU = this.processarStatusONUTL1(resultado.data, deviceName);
|
|
|
|
this.logger.debug('Status ONU processado via TL1', statusONU);
|
|
|
|
return {
|
|
success: true,
|
|
...statusONU
|
|
};
|
|
|
|
} catch (error) {
|
|
this.logger.error('Erro ao obter status da ONU por nome via TL1', { deviceName, error: error.message });
|
|
return {
|
|
success: false,
|
|
error: error.message,
|
|
deviceName
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Processar resposta TL1 para status de ONU
|
|
*/
|
|
processarStatusONUTL1(dadosTL1, identificador) {
|
|
try {
|
|
// Processar dados TL1 - formato típico Fiberhome
|
|
// Exemplo de resposta TL1: "COMPLD RTRV-ONU:OLT:ONU-1:1:SERIAL=FHTT12345678,..."
|
|
|
|
const resultado = {
|
|
serial: identificador,
|
|
deviceName: identificador,
|
|
slot: 'N/A',
|
|
pon: 'N/A',
|
|
onuId: 'N/A',
|
|
online: false,
|
|
rxPower: 'N/A',
|
|
txPower: 'N/A',
|
|
distance: 'N/A',
|
|
portasEthernet: [],
|
|
servicosWAN: []
|
|
};
|
|
|
|
if (!dadosTL1 || typeof dadosTL1 !== 'string') {
|
|
return resultado;
|
|
}
|
|
|
|
// Extrair informações básicas da resposta TL1
|
|
if (dadosTL1.includes('COMPLD')) {
|
|
resultado.online = true;
|
|
|
|
// Extrair serial se disponível
|
|
const serialMatch = dadosTL1.match(/SERIAL=([A-Z0-9]+)/i);
|
|
if (serialMatch) {
|
|
resultado.serial = serialMatch[1];
|
|
}
|
|
|
|
// Extrair device name se disponível
|
|
const deviceMatch = dadosTL1.match(/DEVICENAME=([^,\s]+)/i);
|
|
if (deviceMatch) {
|
|
resultado.deviceName = deviceMatch[1];
|
|
}
|
|
|
|
// Extrair posição (slot/pon/onu)
|
|
const posicaoMatch = dadosTL1.match(/(\d+)-(\d+)-(\d+)/);
|
|
if (posicaoMatch) {
|
|
resultado.slot = posicaoMatch[1];
|
|
resultado.pon = posicaoMatch[2];
|
|
resultado.onuId = posicaoMatch[3];
|
|
}
|
|
|
|
// Extrair informações de sinal
|
|
const rxMatch = dadosTL1.match(/RXPOWER=([^,\s]+)/i);
|
|
if (rxMatch) {
|
|
resultado.rxPower = `${rxMatch[1]} dBm`;
|
|
}
|
|
|
|
const txMatch = dadosTL1.match(/TXPOWER=([^,\s]+)/i);
|
|
if (txMatch) {
|
|
resultado.txPower = `${txMatch[1]} dBm`;
|
|
}
|
|
|
|
const distMatch = dadosTL1.match(/DISTANCE=([^,\s]+)/i);
|
|
if (distMatch) {
|
|
resultado.distance = `${distMatch[1]} m`;
|
|
}
|
|
|
|
// Simular algumas portas Ethernet (dados típicos de ONU)
|
|
resultado.portasEthernet = [
|
|
{ porta: 1, status: 'up' },
|
|
{ porta: 2, status: 'down' },
|
|
{ porta: 3, status: 'down' },
|
|
{ porta: 4, status: 'down' }
|
|
];
|
|
|
|
// Simular serviço WAN
|
|
if (resultado.online) {
|
|
resultado.servicosWAN = [
|
|
{ id: 1, status: 'active', ip: '192.168.1.100' }
|
|
];
|
|
}
|
|
}
|
|
|
|
this.logger.debug('Dados TL1 processados', resultado);
|
|
return resultado;
|
|
|
|
} catch (error) {
|
|
this.logger.error('Erro ao processar dados TL1', { error: error.message });
|
|
return {
|
|
serial: identificador,
|
|
deviceName: identificador,
|
|
slot: 'N/A',
|
|
pon: 'N/A',
|
|
onuId: 'N/A',
|
|
online: false,
|
|
rxPower: 'N/A',
|
|
txPower: 'N/A',
|
|
distance: 'N/A',
|
|
portasEthernet: [],
|
|
servicosWAN: []
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Descobrir porta PON onde a ONU está descoberta
|
|
* @param {string} serial - Serial da ONU (MAC address)
|
|
*/
|
|
async descobrirPortaPON(serial) {
|
|
try {
|
|
console.log('🔍 Descobrindo porta PON para ONU:', serial);
|
|
this.logger.debug('Descobrindo porta PON para ONU', { serial });
|
|
|
|
// Conectar ao UNM2000
|
|
const conectado = await this.conectarUNM2000();
|
|
if (!conectado) {
|
|
throw new Error('Não foi possível conectar ao UNM2000');
|
|
}
|
|
|
|
let tentativas = 0;
|
|
const maxTentativas = 320; // Máximo de tentativas (20 slots x 16 portas)
|
|
|
|
// Primeiro, tentar listar dispositivos para descobrir o nome correto da OLT
|
|
console.log('📋 Listando dispositivos OLT...');
|
|
const listarCmd = `LST-DEVICE:::${this.commandId++}::;`;
|
|
const dispositivos = await this.executarComandoTL1(listarCmd);
|
|
|
|
let oltName = this.config.olt.name; // Fallback para o IP configurado
|
|
|
|
if (dispositivos.success && dispositivos.data) {
|
|
console.log('📋 Resposta LST-DEVICE:', dispositivos.data);
|
|
|
|
// Extrair DEVNAME da resposta (formato: AN5516-06_172.16.10.6)
|
|
const match = dispositivos.data.match(/^([^\s]+)\s+[\d\.]+\s+AN5516/m);
|
|
if (match && match[1]) {
|
|
oltName = match[1];
|
|
console.log(`✅ Nome da OLT descoberto: ${oltName}`);
|
|
// Atualizar configuração para uso futuro
|
|
this.config.olt.name = oltName;
|
|
} else {
|
|
console.log('⚠️ Não foi possível extrair DEVNAME, usando IP como fallback');
|
|
}
|
|
} else {
|
|
console.log('⚠️ Não foi possível listar dispositivos:', dispositivos.error);
|
|
}
|
|
|
|
// Listar placas PON instaladas para saber quais slots existem
|
|
console.log('📋 Listando placas PON instaladas...');
|
|
const listarBoardsCmd = `LST-BOARD::OLTID=${oltName}:${this.commandId++}::;`;
|
|
const boards = await this.executarComandoTL1(listarBoardsCmd);
|
|
|
|
let slotsDisponiveis = [];
|
|
if (boards.success && boards.data) {
|
|
console.log('📋 Placas encontradas:', boards.data);
|
|
|
|
// Extrair slots das placas GPON (formato BOARDID: 1-1-slot, tipo: GCOB ou GC8B)
|
|
// Exemplo: "1-1-12 GCOB GPON 16"
|
|
const ponLines = boards.data.split('\n');
|
|
for (const line of ponLines) {
|
|
// Verificar se a linha contém placa GPON
|
|
if (line.includes('GPON')) {
|
|
// Extrair BOARDID no formato rack-shelf-slot (ex: 1-1-12)
|
|
const boardMatch = line.match(/(\d+)-(\d+)-(\d+)\s+(GCOB|GC8B)\s+GPON/);
|
|
if (boardMatch) {
|
|
const slot = parseInt(boardMatch[3]); // Pegar o terceiro número (slot)
|
|
const numPortas = parseInt(line.match(/GPON\s+(\d+)/)[1]); // Número de portas
|
|
if (!slotsDisponiveis.find(s => s.slot === slot)) {
|
|
slotsDisponiveis.push({ slot, portas: numPortas });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
slotsDisponiveis.sort((a, b) => a.slot - b.slot);
|
|
console.log(`✅ Slots PON disponíveis:`, slotsDisponiveis.map(s => `${s.slot} (${s.portas} portas)`).join(', '));
|
|
}
|
|
|
|
if (slotsDisponiveis.length === 0) {
|
|
console.log('⚠️ Nenhuma placa GPON encontrada, tentando slots 1-20');
|
|
// Fallback: tentar todos os slots de 1 a 20 com 16 portas
|
|
slotsDisponiveis = Array.from({length: 20}, (_, i) => ({ slot: i + 1, portas: 16 }));
|
|
}
|
|
|
|
// Buscar em todas as portas PON dos slots disponíveis
|
|
for (const slotInfo of slotsDisponiveis) {
|
|
if (tentativas >= maxTentativas) break;
|
|
|
|
const { slot, portas } = slotInfo;
|
|
|
|
for (let porta = 1; porta <= portas && tentativas < maxTentativas; porta++) {
|
|
tentativas++;
|
|
const ponId = `NA-NA-${slot}-${porta}`;
|
|
const comando = `LST-UNREGONU::OLTID=${oltName},PONID=${ponId}:${this.commandId++}::;`;
|
|
|
|
console.log(`🔎 Consultando porta PON ${ponId} (slot ${slot}, porta ${porta}/${portas})`);
|
|
this.logger.debug('Consultando porta PON', { ponId, tentativa: tentativas, oltName });
|
|
const resultado = await this.executarComandoTL1(comando);
|
|
|
|
if (resultado.success && resultado.data) {
|
|
// Verificar se a ONU está na resposta
|
|
if (resultado.data.toUpperCase().includes(serial.toUpperCase())) {
|
|
console.log(`✅ Porta PON descoberta: ${ponId}`);
|
|
this.logger.info('Porta PON descoberta', { serial, ponId });
|
|
return {
|
|
success: true,
|
|
portAlias: `${slot}-${porta}`,
|
|
slot,
|
|
porta
|
|
};
|
|
}
|
|
} else if (!resultado.success) {
|
|
console.log(`⚠️ Erro ao consultar porta ${ponId}: ${resultado.error}`);
|
|
// Se o erro for de formato, provavelmente todas as portas vão falhar
|
|
if (resultado.error && resultado.error.includes('invalid parameter format')) {
|
|
console.log('❌ Formato de comando inválido, interrompendo busca');
|
|
throw new Error('Formato de comando LST-UNREGONU inválido. Verifique configuração da OLT.');
|
|
}
|
|
}
|
|
|
|
// Pequeno delay entre consultas para não sobrecarregar
|
|
await new Promise(resolve => setTimeout(resolve, 200));
|
|
}
|
|
}
|
|
|
|
// ONU não encontrada
|
|
console.log(`❌ ONU ${serial} não encontrada após ${tentativas} tentativas`);
|
|
this.logger.warn('ONU não encontrada em nenhuma porta PON', { serial, tentativas });
|
|
return {
|
|
success: false,
|
|
error: 'ONU não encontrada em nenhuma porta PON. Verifique se a ONU está ligada e descoberta pela OLT.'
|
|
};
|
|
|
|
} catch (error) {
|
|
console.log('❌ Erro ao descobrir porta PON:', error.message);
|
|
this.logger.error('Erro ao descobrir porta PON', { serial, error: error.message });
|
|
return {
|
|
success: false,
|
|
error: error.message
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adicionar ONU Fiberhome via TL1
|
|
* @param {string} serial - Serial da ONU (MAC address)
|
|
* @param {string} usuario - Nome/alias do usuário
|
|
* @param {number} vlan - VLAN ID (padrão: 1002)
|
|
* @param {string} onuType - Tipo da ONU (AN5506-02-B ou AN5506-01-A)
|
|
*/
|
|
async adicionarOnuFiberhome(serial, usuario, vlan = 1002, onuType = 'AN5506-02-B') {
|
|
try {
|
|
this.logger.info('Iniciando adição de ONU Fiberhome via TL1', {
|
|
serial, usuario, vlan, onuType
|
|
});
|
|
|
|
// Conectar ao UNM2000
|
|
const conectado = await this.conectarUNM2000();
|
|
if (!conectado) {
|
|
throw new Error('Não foi possível conectar ao UNM2000');
|
|
}
|
|
|
|
// Descobrir porta PON automaticamente
|
|
const descoberta = await this.descobrirPortaPON(serial);
|
|
if (!descoberta.success) {
|
|
throw new Error(descoberta.error);
|
|
}
|
|
|
|
const portAlias = descoberta.portAlias;
|
|
const nameOlt = this.config.olt.name;
|
|
|
|
this.logger.info('Porta PON descoberta', { portAlias, nameOlt });
|
|
|
|
// 1. ADD-ONU: Autenticar a ONU
|
|
const addOnuCmd = `ADD-ONU::OLTID=${nameOlt},PONID=NA-NA-${portAlias}:${this.commandId++}::AUTHTYPE=MAC,ONUTYPE=${onuType},NAME=${usuario},ONUID=${serial};`;
|
|
this.logger.debug('Executando ADD-ONU', { comando: addOnuCmd });
|
|
|
|
const resultadoAdd = await this.executarComandoTL1(addOnuCmd);
|
|
if (!resultadoAdd.success) {
|
|
throw new Error(`Falha ao adicionar ONU: ${resultadoAdd.error}`);
|
|
}
|
|
|
|
// Aguardar um pouco para a ONU ser registrada
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
// 2. SET-WANSERVICE: Configurar WAN services
|
|
// Determina quantas portas configurar baseado no tipo da ONU
|
|
const numPortas = onuType === 'AN5506-02-B' ? 2 : 1;
|
|
|
|
for (let porta = 1; porta <= numPortas; porta++) {
|
|
const setWanCmd = `SET-WANSERVICE::OLTID=${nameOlt},PONID=NA-NA-${portAlias},ONUIDTYPE=MAC,ONUID=${serial}:${this.commandId++}::STATUS=1,MODE=2,CONNTYPE=1,VLAN=${vlan},COS=0,QOS=2,UPORT=${porta};`;
|
|
this.logger.debug(`Configurando WAN Service porta ${porta}`, { comando: setWanCmd });
|
|
|
|
const resultadoWan = await this.executarComandoTL1(setWanCmd);
|
|
if (!resultadoWan.success) {
|
|
this.logger.warn(`Aviso ao configurar WAN porta ${porta}: ${resultadoWan.error}`);
|
|
// Não lança erro, apenas registra o aviso
|
|
}
|
|
|
|
// Pequeno delay entre comandos
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
}
|
|
|
|
// 3. CFG-WEBADMINISTRATOR: Configurar autenticação web
|
|
const cfgWebCmd = `CFG-WEBADMINISTRATOR::OLTID=${nameOlt},PONID=NA-NA-${portAlias},ONUIDTYPE=MAC,ONUID=${serial}:${this.commandId++}::WEBUSERNAME=admin,WEBPASSWORD=clicknet10;`;
|
|
this.logger.debug('Configurando autenticação web', { comando: cfgWebCmd });
|
|
|
|
const resultadoWeb = await this.executarComandoTL1(cfgWebCmd);
|
|
if (!resultadoWeb.success) {
|
|
this.logger.warn(`Aviso ao configurar autenticação web: ${resultadoWeb.error}`);
|
|
// Não lança erro, apenas registra o aviso
|
|
}
|
|
|
|
// Aguardar antes de reiniciar
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
|
|
// 4. RESET-ONU: Reiniciar a ONU
|
|
const resetCmd = `RESET-ONU::OLTID=${nameOlt},PONID=NA-NA-${portAlias},ONUIDTYPE=MAC,ONUID=${serial}:${this.commandId++}::;`;
|
|
this.logger.debug('Reiniciando ONU', { comando: resetCmd });
|
|
|
|
const resultadoReset = await this.executarComandoTL1(resetCmd);
|
|
if (!resultadoReset.success) {
|
|
this.logger.warn(`Aviso ao reiniciar ONU: ${resultadoReset.error}`);
|
|
// Não lança erro, apenas registra o aviso
|
|
}
|
|
|
|
this.logger.info('ONU Fiberhome adicionada com sucesso', {
|
|
nameOlt, portAlias, serial, usuario, vlan
|
|
});
|
|
|
|
return {
|
|
success: true,
|
|
message: 'ONU adicionada com sucesso',
|
|
details: {
|
|
olt: nameOlt,
|
|
porta: portAlias,
|
|
slot: descoberta.slot,
|
|
ponPort: descoberta.porta,
|
|
serial: serial,
|
|
usuario: usuario,
|
|
vlan: vlan,
|
|
tipo: onuType,
|
|
portas: numPortas
|
|
}
|
|
};
|
|
|
|
} catch (error) {
|
|
this.logger.error('Erro ao adicionar ONU Fiberhome', {
|
|
serial, error: error.message
|
|
});
|
|
return {
|
|
success: false,
|
|
error: error.message
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Buscar ONU registrada no sistema
|
|
*/
|
|
async buscarOnuRegistrada(serial) {
|
|
try {
|
|
this.logger.debug('Buscando ONU registrada no sistema', { serial });
|
|
|
|
// 1. Descobrir nome da OLT
|
|
const lstDeviceCmd = `LST-DEVICE:::${this.commandId++}::;`;
|
|
const deviceResult = await this.executarComandoTL1(lstDeviceCmd);
|
|
|
|
if (!deviceResult.success) {
|
|
throw new Error('Falha ao listar dispositivos OLT');
|
|
}
|
|
|
|
console.log('📋 Resposta LST-DEVICE:', deviceResult.data);
|
|
|
|
// Extrair nome da OLT da resposta
|
|
const deviceLines = deviceResult.data.split('\n');
|
|
let nameOlt = null;
|
|
|
|
for (const line of deviceLines) {
|
|
if (line.includes('AN5516') || line.includes('AN5116')) {
|
|
const parts = line.split(/\s+/).filter(p => p.trim());
|
|
if (parts.length > 0) {
|
|
nameOlt = parts[0]; // Primeiro campo é o DEVNAME
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!nameOlt) {
|
|
throw new Error('Nome da OLT não encontrado');
|
|
}
|
|
|
|
console.log(`✅ Nome da OLT descoberto: ${nameOlt}`);
|
|
|
|
// 2. Listar todas as ONUs registradas
|
|
const lstOnuCmd = `LST-ONU::OLTID=${nameOlt}:${this.commandId++}::;`;
|
|
console.log(`📋 Listando ONUs registradas...`);
|
|
|
|
const onuResult = await this.executarComandoTL1(lstOnuCmd);
|
|
|
|
if (!onuResult.success) {
|
|
throw new Error('Falha ao listar ONUs registradas');
|
|
}
|
|
|
|
console.log('📋 ONUs registradas:', onuResult.data);
|
|
|
|
// 3. Procurar a ONU pelo MAC/Serial
|
|
const onuLines = onuResult.data.split('\n');
|
|
let onuInfo = null;
|
|
|
|
for (const line of onuLines) {
|
|
// Procurar linha que contenha o serial (case-insensitive)
|
|
if (line.toUpperCase().includes(serial.toUpperCase())) {
|
|
console.log(`🔍 Linha encontrada: ${line}`);
|
|
|
|
// Extrair informações da linha
|
|
// Formato esperado: campos separados por tabs ou espaços
|
|
const parts = line.split(/\s+/).filter(p => p.trim() && p !== '--');
|
|
|
|
console.log(`📋 Parts extraídos:`, parts);
|
|
|
|
if (parts.length >= 4) {
|
|
// Tentar extrair PONID que pode estar em vários formatos:
|
|
// - 1-1-12-14 (frameId-slotId-portId-onuId)
|
|
// - NA-NA-12-14
|
|
// - 12-14
|
|
for (const part of parts) {
|
|
// Regex mais flexível: aceita N-N-N-N ou NA-NA-N-N
|
|
const ponidMatch = part.match(/^(?:\d+|\w+)-(?:\d+|\w+)-(\d+)-(\d+)$/);
|
|
if (ponidMatch) {
|
|
console.log(`✅ PONID identificado: ${part}`);
|
|
onuInfo = {
|
|
nameOlt: nameOlt,
|
|
portAlias: part,
|
|
slot: ponidMatch[1],
|
|
porta: ponidMatch[2]
|
|
};
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (onuInfo) {
|
|
console.log(`✅ ONU info completa:`, onuInfo);
|
|
break;
|
|
} else {
|
|
console.log(`❌ Não conseguiu extrair PONID da linha`);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!onuInfo) {
|
|
throw new Error('ONU não encontrada entre as ONUs registradas');
|
|
}
|
|
|
|
console.log(`✅ ONU encontrada:`, onuInfo);
|
|
return onuInfo;
|
|
|
|
} catch (error) {
|
|
this.logger.error('Erro ao buscar ONU registrada', { serial, error: error.message });
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remover ONU Fiberhome via TL1
|
|
*/
|
|
async removerOnuFiberhome(serial) {
|
|
try {
|
|
this.logger.debug('Removendo ONU Fiberhome via TL1', { serial });
|
|
|
|
// Conectar ao UNM2000
|
|
const conectado = await this.conectarUNM2000();
|
|
if (!conectado) {
|
|
throw new Error('Não foi possível conectar ao UNM2000');
|
|
}
|
|
|
|
// Normalizar serial para maiúsculas
|
|
serial = serial.toUpperCase();
|
|
|
|
// Buscar a ONU registrada no sistema
|
|
this.logger.debug('Buscando ONU registrada', { serial });
|
|
const onuInfo = await this.buscarOnuRegistrada(serial);
|
|
|
|
if (!onuInfo) {
|
|
throw new Error('ONU não encontrada no sistema');
|
|
}
|
|
|
|
const { nameOlt, portAlias } = onuInfo;
|
|
this.logger.debug('ONU encontrada', { nameOlt, portAlias });
|
|
|
|
// Executar comando DEL-ONU
|
|
const delOnuCmd = `DEL-ONU::OLTID=${nameOlt},PONID=${portAlias}:${this.commandId++}::ONUIDTYPE=MAC,ONUID=${serial};`;
|
|
|
|
this.logger.debug('Executando comando DEL-ONU', { comando: delOnuCmd });
|
|
const delResult = await this.executarComandoTL1(delOnuCmd);
|
|
|
|
if (!delResult.success) {
|
|
throw new Error(`Falha ao remover ONU: ${delResult.error}`);
|
|
}
|
|
|
|
this.logger.info('ONU Fiberhome removida com sucesso', {
|
|
serial,
|
|
olt: nameOlt,
|
|
porta: portAlias
|
|
});
|
|
|
|
return {
|
|
success: true,
|
|
message: 'ONU removida com sucesso',
|
|
details: {
|
|
olt: nameOlt,
|
|
porta: portAlias,
|
|
serial: serial,
|
|
slot: onuInfo.slot,
|
|
ponPort: onuInfo.porta
|
|
}
|
|
};
|
|
|
|
} catch (error) {
|
|
this.logger.error('Erro ao remover ONU Fiberhome', {
|
|
serial, error: error.message
|
|
});
|
|
return {
|
|
success: false,
|
|
error: error.message
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Desconectar TL1
|
|
*/
|
|
async desconectar() {
|
|
try {
|
|
if (this.tl1Connection && !this.tl1Connection.destroyed) {
|
|
this.logger.debug('Desconectando TL1');
|
|
this.tl1Connection.end();
|
|
this.tl1Connection = null;
|
|
}
|
|
} catch (error) {
|
|
this.logger.error('Erro ao desconectar TL1', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verificar se as conexões estão ativas
|
|
*/
|
|
verificarConexoes() {
|
|
return {
|
|
olt: false, // Não usamos mais OLT diretamente
|
|
unm2000: this.tl1Connection && !this.tl1Connection.destroyed
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Diagnóstico completo de conectividade
|
|
*/
|
|
async diagnosticarConectividade() {
|
|
const diagnostico = {
|
|
olt: {
|
|
host: 'N/A',
|
|
port: 'N/A',
|
|
conectividade: false,
|
|
telnet: false,
|
|
erro: 'Não utilizado - consultas via TL1'
|
|
},
|
|
unm2000: {
|
|
host: this.config.unm2000.host,
|
|
port: this.config.unm2000.port,
|
|
conectividade: false,
|
|
tl1: false,
|
|
erro: null
|
|
}
|
|
};
|
|
|
|
// Testar UNM2000
|
|
try {
|
|
this.logger.debug('Testando conectividade UNM2000...');
|
|
diagnostico.unm2000.conectividade = await this.testarConectividade(
|
|
this.config.unm2000.host,
|
|
this.config.unm2000.port
|
|
);
|
|
|
|
if (diagnostico.unm2000.conectividade) {
|
|
this.logger.debug('Testando login TL1 UNM2000...');
|
|
diagnostico.unm2000.tl1 = await this.conectarUNM2000();
|
|
}
|
|
} catch (error) {
|
|
diagnostico.unm2000.erro = error.message;
|
|
this.logger.error('Erro no diagnóstico UNM2000:', error);
|
|
}
|
|
|
|
return diagnostico;
|
|
}
|
|
|
|
/**
|
|
* Configura IPoE em ONU FiberHome: deleta WAN services existentes e recria com VLAN 977
|
|
* 1. Busca ONU registrada pelo serial
|
|
* 2. Consulta WAN services existentes (LST-ONUWANSERVICECFG)
|
|
* 3. Deleta cada WAN service (SET-WANSERVICE STATUS=2)
|
|
* 4. Recria com VLAN 977 (SET-WANSERVICE STATUS=1)
|
|
* 5. Reinicia ONU
|
|
* @param {string} serial - MAC/Serial da ONU
|
|
* @param {string} onuType - Tipo da ONU (para determinar número de portas)
|
|
* @returns {Promise} - Promise com resultado
|
|
*/
|
|
async configurarIPoEFiberhome(serial, onuType = 'AN5506-02-B') {
|
|
try {
|
|
const VLAN_IPOE = 977;
|
|
this.logger.info('Iniciando configuração IPoE FiberHome via TL1', { serial, vlan: VLAN_IPOE });
|
|
|
|
const conectado = await this.conectarUNM2000();
|
|
if (!conectado) {
|
|
throw new Error('Não foi possível conectar ao UNM2000');
|
|
}
|
|
|
|
// Buscar ONU registrada pelo serial
|
|
const onuInfo = await this.buscarOnuRegistrada(serial);
|
|
|
|
const nameOlt = onuInfo.nameOlt || this.config.olt.name;
|
|
const portAlias = onuInfo.portAlias;
|
|
|
|
this.logger.info('ONU encontrada, consultando WAN Services existentes', { nameOlt, portAlias, serial });
|
|
|
|
// 1. Consultar WAN services existentes
|
|
const lstCmd = `LST-ONUWANSERVICECFG::OLTID=${nameOlt},PONID=NA-NA-${portAlias},ONUIDTYPE=MAC,ONUID=${serial}:${this.commandId++}::;`;
|
|
this.logger.debug('Consultando WAN Services', { comando: lstCmd });
|
|
const lstResult = await this.executarComandoTL1(lstCmd);
|
|
|
|
let wanServices = [];
|
|
if (lstResult.success && lstResult.data) {
|
|
wanServices = this._parseWanServices(lstResult.data);
|
|
this.logger.info(`WAN Services encontrados: ${wanServices.length}`, { wanServices });
|
|
}
|
|
|
|
// 2. Deletar WAN services existentes
|
|
for (const ws of wanServices) {
|
|
const delCmd = `SET-WANSERVICE::OLTID=${nameOlt},PONID=NA-NA-${portAlias},ONUIDTYPE=MAC,ONUID=${serial}:${this.commandId++}::STATUS=2,MODE=${ws.mode},CONNTYPE=${ws.connType},VLAN=${ws.vlan},COS=${ws.cos},UPORT=${ws.uport};`;
|
|
this.logger.debug(`Deletando WAN Service porta ${ws.uport}`, { comando: delCmd });
|
|
|
|
const delResult = await this.executarComandoTL1(delCmd);
|
|
if (!delResult.success) {
|
|
this.logger.warn(`Aviso ao deletar WAN porta ${ws.uport}: ${delResult.error}`);
|
|
}
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
}
|
|
|
|
// 3. Recriar WAN services com VLAN 977
|
|
const numPortas = onuType === 'AN5506-02-B' ? 2 : 1;
|
|
// Usar as portas dos services existentes, ou fallback para 1..numPortas
|
|
const portas = wanServices.length > 0
|
|
? wanServices.map(ws => ws.uport)
|
|
: Array.from({ length: numPortas }, (_, i) => i + 1);
|
|
|
|
for (const porta of portas) {
|
|
const addCmd = `SET-WANSERVICE::OLTID=${nameOlt},PONID=NA-NA-${portAlias},ONUIDTYPE=MAC,ONUID=${serial}:${this.commandId++}::STATUS=1,MODE=2,CONNTYPE=1,VLAN=${VLAN_IPOE},COS=0,QOS=2,UPORT=${porta};`;
|
|
this.logger.debug(`Criando WAN Service IPoE porta ${porta}`, { comando: addCmd });
|
|
|
|
const addResult = await this.executarComandoTL1(addCmd);
|
|
if (!addResult.success) {
|
|
this.logger.warn(`Aviso ao criar WAN porta ${porta}: ${addResult.error}`);
|
|
}
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
}
|
|
|
|
// 4. Reiniciar ONU para aplicar
|
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
const resetCmd = `RESET-ONU::OLTID=${nameOlt},PONID=NA-NA-${portAlias},ONUIDTYPE=MAC,ONUID=${serial}:${this.commandId++}::;`;
|
|
this.logger.debug('Reiniciando ONU após IPoE', { comando: resetCmd });
|
|
const resultadoReset = await this.executarComandoTL1(resetCmd);
|
|
if (!resultadoReset.success) {
|
|
this.logger.warn(`Aviso ao reiniciar ONU: ${resultadoReset.error}`);
|
|
}
|
|
|
|
this.logger.info('IPoE FiberHome configurado com sucesso', { serial, vlan: VLAN_IPOE });
|
|
|
|
return {
|
|
success: true,
|
|
message: `VLAN alterada para ${VLAN_IPOE} (IPoE)`,
|
|
details: {
|
|
olt: nameOlt,
|
|
porta: portAlias,
|
|
serial,
|
|
vlan: VLAN_IPOE,
|
|
portasConfiguradas: portas,
|
|
wanServicesRemovidos: wanServices.length
|
|
}
|
|
};
|
|
|
|
} catch (error) {
|
|
this.logger.error('Erro ao configurar IPoE FiberHome', { serial, error: error.message });
|
|
return {
|
|
success: false,
|
|
error: error.message
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parseia a resposta do LST-ONUWANSERVICECFG para extrair WAN services
|
|
* Formato: SVCNAME CONNMODE CONNTYPE VLANID VLANCOS ... BINDPORTNO (tab-separated)
|
|
*/
|
|
_parseWanServices(data) {
|
|
const services = [];
|
|
const lines = data.split('\n');
|
|
|
|
// Encontrar a linha de cabeçalho e as linhas de dados
|
|
let headerFound = false;
|
|
let dashFound = false;
|
|
|
|
for (const line of lines) {
|
|
const trimmed = line.trim();
|
|
|
|
if (trimmed.startsWith('SVCNAME')) {
|
|
headerFound = true;
|
|
continue;
|
|
}
|
|
if (headerFound && trimmed.startsWith('---')) {
|
|
if (!dashFound) {
|
|
dashFound = true; // primeiro traço (após header)
|
|
continue;
|
|
} else {
|
|
break; // segundo traço = fim dos dados
|
|
}
|
|
}
|
|
|
|
if (dashFound && trimmed.length > 0 && !trimmed.startsWith('---')) {
|
|
// Linha de dados: campos separados por tab ou espaços
|
|
const parts = trimmed.split(/\t+|\s{2,}/).filter(p => p.trim());
|
|
// Formato: SVCNAME(0) CONNMODE(1) CONNTYPE(2) VLANID(3) VLANCOS(4) ... BINDPORTNO(18)
|
|
if (parts.length >= 5) {
|
|
const mode = parseInt(parts[1]) || 2;
|
|
const connType = parseInt(parts[2]) || 1;
|
|
const vlan = parseInt(parts[3]) || 0;
|
|
const cos = parseInt(parts[4]) || 0;
|
|
// BINDPORTNO é o último campo
|
|
const uport = parseInt(parts[parts.length - 1]) || 1;
|
|
|
|
services.push({ mode, connType, vlan, cos, uport, name: parts[0] });
|
|
console.log(`📋 [IPoE FH] WAN Service parseado: mode=${mode}, connType=${connType}, vlan=${vlan}, cos=${cos}, uport=${uport}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
return services;
|
|
}
|
|
}
|
|
|
|
module.exports = FiberhomeManager;
|