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, defaultOLT: 'AN5516-06_172.16.10.6' // Nome correto da OLT no sistema } }; 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 { this.logger.debug('=== INICIO CONEXAO UNM2000 ==='); this.logger.debug('Configuração:', this.config.unm2000); if (this.tl1Connection && !this.tl1Connection.destroyed) { this.logger.debug('Conexão TL1 já existe e está ativa'); return true; } this.logger.debug('Conectando ao UNM2000 via TL1', this.config.unm2000); // Primeiro testar conectividade básica this.logger.debug('Testando conectividade básica...'); const conectividade = await this.testarConectividade( this.config.unm2000.host, this.config.unm2000.port, 5000 ); if (!conectividade) { this.logger.error(`Host ${this.config.unm2000.host}:${this.config.unm2000.port} não acessível`); throw new Error(`Host ${this.config.unm2000.host}:${this.config.unm2000.port} não acessível`); } this.logger.debug('Conectividade básica OK, iniciando conexão TL1...'); 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) => { const receivedData = data.toString(); dataBuffer += receivedData; this.logger.debug('TL1 dados recebidos:', { raw: receivedData, buffer: dataBuffer }); // Verificar padrões de sucesso no login TL1 Fiberhome if (!authenticated) { if (dataBuffer.includes('COMPLD') || dataBuffer.includes('M COMPLD') || dataBuffer.includes('IP') || dataBuffer.includes('>')) { authenticated = true; this.logger.info('Login TL1 Fiberhome bem-sucedido'); resolve(true); } // Padrões de erro else if (dataBuffer.includes('DENY') || dataBuffer.includes('FAIL') || dataBuffer.includes('ERROR')) { this.logger.error('Login TL1 negado:', dataBuffer); reject(new Error('Login TL1 negado pelo equipamento')); } } }); this.tl1Connection.connect(this.config.unm2000.port, this.config.unm2000.host, () => { this.logger.debug('Socket TL1 conectado, enviando login Fiberhome'); // Aguardar um pouco para receber prompt inicial setTimeout(() => { // Comando de login TL1 formato Fiberhome const loginCommand = `LOGIN:::CTAG::UN=${this.config.unm2000.username},PWD=${this.config.unm2000.password};`; this.logger.debug('Enviando comando login TL1 Fiberhome:', loginCommand); this.tl1Connection.write(loginCommand + '\r\n'); }, 1000); // Timeout para autenticação setTimeout(() => { if (!authenticated) { this.logger.error('Timeout na autenticação TL1 - dados recebidos:', dataBuffer); reject(new Error(`Timeout na autenticação TL1. Dados: ${dataBuffer.substring(0, 200)}`)); } }, 12000); }); this.tl1Connection.on('error', (error) => { this.logger.error('Erro na conexão TL1', error); reject(error); }); this.tl1Connection.on('timeout', () => { this.logger.error('Timeout na conexão TL1'); reject(new Error('Timeout na conexão TL1')); }); this.tl1Connection.on('close', () => { this.logger.debug('Conexão TL1 fechada'); this.tl1Connection = null; }); }); } catch (error) { this.logger.error('=== ERRO NA CONEXAO UNM2000 ==='); this.logger.error('Erro detalhado:', { message: error.message, code: error.code, errno: error.errno, syscall: error.syscall, address: error.address, port: error.port }); this.logger.error('Erro ao conectar UNM2000', error); return false; } } /** * Método de teste para verificar comandos TL1 básicos */ async testarComandoTL1(comando) { try { this.logger.debug('=== TESTE TL1 ==='); this.logger.debug('Comando:', comando); const conectado = await this.conectarUNM2000(); if (!conectado) { throw new Error('Não foi possível conectar ao UNM2000'); } const resultado = await this.executarComandoTL1(comando); this.logger.debug('=== RESULTADO TESTE TL1 ==='); this.logger.debug('Success:', resultado.success); this.logger.debug('Error:', resultado.error); this.logger.debug('Data length:', resultado.data ? resultado.data.length : 0); this.logger.debug('Data:', resultado.data); this.logger.debug('=== FIM TESTE TL1 ==='); return resultado; } catch (error) { this.logger.error('Erro no teste TL1:', error.message); return { success: false, error: error.message }; } } /** * 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 acumulada:', { comando, responseLength: dataBuffer.length, response: dataBuffer }); // Verificar se a resposta está completa (formato Fiberhome) if ((dataBuffer.includes('COMPLD') || dataBuffer.includes('M COMPLD') || dataBuffer.includes('DENY') || dataBuffer.includes(';')) && !responseReceived) { responseReceived = true; this.tl1Connection.removeListener('data', dataHandler); if (dataBuffer.includes('COMPLD') || dataBuffer.includes('M COMPLD')) { this.logger.debug('Comando TL1 executado com sucesso'); resolve({ success: true, data: dataBuffer }); } else if (dataBuffer.includes('DENY')) { this.logger.warn('Comando TL1 negado pelo equipamento'); resolve({ success: false, error: 'Comando negado pelo equipamento', data: dataBuffer }); } else { this.logger.debug('Resposta TL1 válida recebida'); resolve({ success: true, data: dataBuffer // Aceitar resposta válida }); } } }; this.tl1Connection.on('data', dataHandler); // Enviar comando TL1 formato Fiberhome this.tl1Connection.write(comando + '\r\n'); // Timeout para resposta setTimeout(() => { if (!responseReceived) { this.tl1Connection.removeListener('data', dataHandler); reject(new Error('Timeout aguardando resposta TL1')); } }, 15000); }); } 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'); } const oltId = this.config.unm2000.defaultOLT; // Nome correto da OLT // BUSCA AUTOMATIZADA: Estrutura correta da OLT this.logger.debug('=== INICIANDO BUSCA AUTOMATIZADA POR SLOT/PON ==='); this.logger.debug(`OLTID: ${oltId}, Serial: ${serial}`); // Definir estrutura correta da OLT const estruturaOLT = [ // Slots 12, 13, 14 com 16 PONs cada { slot: 12, maxPons: 16 }, { slot: 13, maxPons: 16 }, { slot: 14, maxPons: 16 }, // Slots 15, 16 com 8 PONs cada { slot: 15, maxPons: 8 }, { slot: 16, maxPons: 8 } ]; // Gerar lista de PONs para busca const listaPons = []; estruturaOLT.forEach(estrutura => { for (let pon = 1; pon <= estrutura.maxPons; pon++) { listaPons.push(`1-1-${estrutura.slot}-${pon}`); } }); this.logger.info(`📡 Iniciando busca em ${listaPons.length} PONs: slots 12-16`); let onuEncontrada = null; let ponEncontrada = null; // Buscar em cada PON até encontrar a ONU for (const ponid of listaPons) { try { this.logger.debug(`🔍 Verificando PON ${ponid}...`); // Listar ONUs desta PON específica const comandoListarPon = `LST-ONU::OLTID=${oltId},PONID=${ponid}:CTAG::;`; const resultadoPon = await this.executarComandoTL1(comandoListarPon); if (resultadoPon.success) { // Verificar se a ONU está nesta PON (busca case-insensitive) const serialUpperCase = serial.toUpperCase(); const dataUpperCase = resultadoPon.data ? resultadoPon.data.toUpperCase() : ''; if (resultadoPon.data && dataUpperCase.includes(serialUpperCase)) { // Extrair informações da ONU na listagem primeiro const posicaoONU = this.extrairPosicaoONU(resultadoPon.data, serial); if (posicaoONU) { // Usar o PONID correto extraído dos dados reais this.logger.info(`🎯 ONU ${serial} ENCONTRADA NA PON ${posicaoONU.ponid}!`); // Log dos dados da PON para debug this.logger.debug('Dados da PON onde ONU foi encontrada:', { ponidBuscada: ponid, ponidReal: posicaoONU.ponid, dataLength: resultadoPon.data.length, preview: resultadoPon.data.substring(0, 1000) }); onuEncontrada = { posicao: posicaoONU, listagem: resultadoPon.data, ponid: posicaoONU.ponid // Usar o PONID correto extraído dos dados }; ponEncontrada = posicaoONU.ponid; // Usar o PONID correto extraído dos dados // Extrair slot e PON do ponid encontrado const [, , slot, pon] = posicaoONU.ponid.split('-'); this.logger.info(`📍 Localização: Slot ${slot}, PON ${pon}`); break; // Encontrou, pode parar a busca } } } else { this.logger.debug(`❌ Erro na PON ${ponid}: ${resultadoPon.error}`); } } catch (error) { this.logger.debug(`⚠️ Erro ao verificar PON ${ponid}: ${error.message}`); // Continuar tentando outras PONs } } if (!onuEncontrada) { throw new Error(`ONU ${serial} não encontrada em nenhuma PON da OLT ${oltId}. Verifique se o serial está correto e se a ONU está cadastrada.`); } // Agora buscar informações detalhadas da ONU this.logger.info(`📊 Coletando informações detalhadas da ONU na PON ${ponEncontrada}...`); // Extrair número da ONU da posição encontrada const numeroONU = onuEncontrada.posicao.onuno; // Usar comandos TL1 que sabemos que funcionam baseados no manual const comandosDetalhados = [ // Para informações de distância e estado (comando válido do manual) `LST-ONUSTATE::OLTID=${oltId},PONID=${ponEncontrada},ONUNO=${numeroONU}:CTAG::;`, // Para informações DDM/potência ótica (comando válido do manual) `LST-OMDDM::OLTID=${oltId},PONID=${ponEncontrada},ONUNO=${numeroONU}:CTAG::;`, // Para informações das portas LAN (comando válido do manual) `LST-ONULANINFO::OLTID=${oltId},PONID=${ponEncontrada},ONUNO=${numeroONU}:CTAG::;` ]; this.logger.debug('Executando comandos TL1 detalhados:', comandosDetalhados); const [resultadoEstado, resultadoDDM, resultadoLAN] = await Promise.all([ this.executarComandoTL1(comandosDetalhados[0]), this.executarComandoTL1(comandosDetalhados[1]), this.executarComandoTL1(comandosDetalhados[2]) ]); // LOG COMPLETO DO LST-OMDDM PARA DEBUG - FORÇAR CONSOLE OUTPUT if (resultadoDDM.success && resultadoDDM.data) { const separador = '='.repeat(80); console.log('\n' + separador); console.log('LST-OMDDM RESPOSTA COMPLETA'); console.log(separador); console.log('Comando: ' + comandosDetalhados[1]); console.log('Resposta RAW:'); console.log(resultadoDDM.data); console.log(separador + '\n'); // Verificar se é resposta válida de DDM if (!resultadoDDM.data.includes('RxPower') && !resultadoDDM.data.includes('Optical Power')) { console.log('⚠️ ATENÇÃO: LST-OMDDM retornou formato inesperado!'); console.log('⚠️ Resposta parece ser lista de ONUs ao invés de dados DDM'); console.log('⚠️ Verifique se o comando está correto para esta versão do equipamento'); } } // Adicionar dados coletados onuEncontrada.estadoGeral = resultadoEstado.success ? resultadoEstado.data : null; onuEncontrada.detalhes = resultadoDDM.success ? resultadoDDM.data : null; onuEncontrada.lan = resultadoLAN.success ? resultadoLAN.data : null; // Adicionar respostas detalhadas para processamento onuEncontrada.detalhados = [ { comando: comandosDetalhados[0], response: resultadoEstado.data, success: resultadoEstado.success }, { comando: comandosDetalhados[1], response: resultadoDDM.data, success: resultadoDDM.success }, { comando: comandosDetalhados[2], response: resultadoLAN.data, success: resultadoLAN.success } ]; // Log dos resultados dos comandos detalhados this.logger.debug('📊 Resultados dos comandos detalhados:', { estado: { success: resultadoEstado.success, length: resultadoEstado.data?.length || 0 }, ddm: { success: resultadoDDM.success, length: resultadoDDM.data?.length || 0 }, lan: { success: resultadoLAN.success, length: resultadoLAN.data?.length || 0 } }); // Tentar extrair mais informações dos dados da listagem original this.logger.debug('📋 Processando dados da listagem original para extrair informações...'); onuEncontrada.dadosOriginais = onuEncontrada.listagem; // Processar todos os dados coletados const statusONU = this.processarStatusONUTL1(onuEncontrada, serial); this.logger.info('🎉 Status final da ONU processado:', { serial: statusONU.serial, slot: statusONU.slot, pon: statusONU.pon, online: statusONU.online, rxPower: statusONU.rxPower, txPower: statusONU.txPower }); 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 }; } } /** * Extrair posição da ONU da lista de ONUs */ extrairPosicaoONU(dadosLista, serial) { try { if (!dadosLista || typeof dadosLista !== 'string') { return null; } this.logger.debug('Extraindo posição da ONU da resposta TL1:', { serial, serialUpperCase: serial.toUpperCase(), responseLength: dadosLista.length, preview: dadosLista.substring(0, 500) }); // Dividir resposta em linhas para processamento const linhas = dadosLista.split('\n'); this.logger.debug('Total de linhas para processar:', linhas.length); for (const linha of linhas) { // Pular linhas de cabeçalho e vazias if (linha.includes('OLTID') || linha.includes('----') || linha.trim() === '') { continue; } // Log de cada linha processada (apenas as primeiras 3 para não poluir) if (linhas.indexOf(linha) < 3) { this.logger.debug('Processando linha:', linha.substring(0, 200)); } // Procurar linha que contém o serial na coluna MAC (busca case-insensitive) const serialUpperCase = serial.toUpperCase(); const linhaUpperCase = linha.toUpperCase(); if (linhaUpperCase.includes(serialUpperCase)) { this.logger.debug('Serial encontrado na linha:', linha); // Formato esperado baseado nos logs: // OLTID PONID ONUNO NAME DESC ONUTYPE IP AUTHTYPE MAC LOID PWD SWVER // 172.16.10.6 1-1-14-2 68 artenizamendes@clicknetguarai.com.br -- AN5506-02-B -- MAC FHTT92704618 -- -- RP2604 // Dividir por tabs const campos = linha.split('\t'); this.logger.debug('Campos extraídos por TAB:', campos); if (campos.length >= 9) { const oltid = campos[0]; const ponid = campos[1]; const onuno = campos[2]; const name = campos[3]; const mac = campos[8]; // Posição da coluna MAC // Verificar se o MAC corresponde ao serial procurado (case-insensitive) if (mac && mac.toUpperCase().includes(serialUpperCase)) { this.logger.debug('PONID encontrado:', ponid); return { ponid: ponid, encontrado: true, oltid: oltid, onuno: onuno, name: name, mac: mac, linhaOriginal: linha }; } } // Fallback: se não conseguiu dividir por TAB, tentar por espaços const camposEspaco = linha.trim().split(/\s+/); this.logger.debug('Campos extraídos por espaço:', camposEspaco); // Procurar o campo PONID (formato x-x-x-x) e verificar se serial está na linha for (let i = 0; i < camposEspaco.length; i++) { const campo = camposEspaco[i]; if (campo.match(/^\d+-\d+-\d+-\d+$/) && linhaUpperCase.includes(serialUpperCase)) { this.logger.debug('PONID encontrado por regex:', campo); return { ponid: campo, encontrado: true, linhaOriginal: linha }; } } } } this.logger.warn('ONU não encontrada na listagem TL1', { serial }); return null; } catch (error) { this.logger.error('Erro ao extrair posição da ONU', { error: error.message, serial }); return null; } } /** * Processar resposta TL1 para status de ONU */ processarStatusONUTL1(dadosONU, identificador) { try { 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 (!dadosONU || typeof dadosONU !== 'object') { return resultado; } this.logger.debug('Processando dados ONU TL1:', dadosONU); // Se encontramos a posição, a ONU existe if (dadosONU.posicao && dadosONU.posicao.encontrado) { resultado.online = true; // Extrair informações da posição (formato NA-NA-slot-pon ou NA-shelf-slot-pon) const ponid = dadosONU.posicao.ponid; const partesPonid = ponid.split('-'); this.logger.debug('Analisando PONID:', { ponid, partes: partesPonid }); if (partesPonid.length >= 4) { // Formato NA-NA-slot-pon ou NA-shelf-slot-pon resultado.slot = partesPonid[2]; resultado.pon = partesPonid[3]; // Incluir o número da ONU no ID (slot-pon-numeroONU) const numeroONU = dadosONU.posicao.onuno || '?'; resultado.onuId = `${partesPonid[2]}-${partesPonid[3]}-${numeroONU}`; } // Processar dados específicos dos comandos TL1 detalhados if (dadosONU.detalhados) { this.logger.debug('Processando respostas dos comandos TL1 detalhados'); for (const resposta of dadosONU.detalhados) { if (!resposta || !resposta.response) continue; const dados = resposta.response; // Processar LST-ONUSTATE (distância e estado) if (resposta.comando && resposta.comando.includes('LST-ONUSTATE')) { // Extrair distância const distMatch = dados.match(/DISTANCE\s*=\s*(\d+)/i) || dados.match(/RANGING\s*=\s*(\d+)/i); if (distMatch) { resultado.distance = `${distMatch[1]} m`; } // Verificar estado online/offline if (dados.includes('ONLINE') || dados.includes('ACTIVE')) { resultado.online = true; } else if (dados.includes('OFFLINE') || dados.includes('INACTIVE')) { resultado.online = false; } } // Processar LST-OMDDM (potência ótica) if (resposta.comando && resposta.comando.includes('LST-OMDDM')) { // Verificar se a resposta é válida (deve conter "Optical Power" ou campos de potência) if (!dados.includes('RxPower') && !dados.includes('Optical Power')) { this.logger.warn('⚠️ LST-OMDDM retornou formato inesperado, pulando...'); continue; } // Buscar pela tabela de potência ótica const linhasTabela = dados.split('\n').filter(linha => linha.includes('\t') && !linha.includes('ONUID') && !linha.includes('OLTID') && // Não é lista de ONUs !linha.includes('---') && linha.match(/[+-]?\d+[,.]?\d*/) ); this.logger.debug(`📋 LST-OMDDM: ${linhasTabela.length} linhas encontradas`); if (linhasTabela.length > 0) { const campos = linhasTabela[0].split('\t'); this.logger.debug(`📊 LST-OMDDM campos: [${campos.join('] [')}]`); // Formato: ONUID RxPower RxPowerR TxPower TxPowerR CurrTxBias CurrTxBiasR // Temperature TemperatureR Voltage VoltageR PTxPower PRxPower // Índices: 0 1 2 3 4 5 6 // 7 8 9 10 11 12 // RxPower = sinal que a OLT recebe da ONU (uplink) - campo 1 const rxPower = campos[1]?.replace(',', '.').trim(); // PTxPower = potência transmitida pela ONU - campo 11 const ptxPower = campos[11]?.replace(',', '.').trim(); if (rxPower && rxPower !== '--' && !isNaN(parseFloat(rxPower))) { resultado.rxPower = `${rxPower} dBm`; this.logger.info(`✅ RX Power extraído: ${rxPower} dBm`); } else { this.logger.warn(`⚠️ RxPower inválido: "${rxPower}"`); } if (ptxPower && ptxPower !== '--' && !isNaN(parseFloat(ptxPower))) { resultado.txPower = `${ptxPower} dBm`; this.logger.info(`✅ TX Power extraído (PTxPower): ${ptxPower} dBm`); } else { this.logger.warn(`⚠️ PTxPower inválido: "${ptxPower}"`); } } } // Processar LST-ONULANINFO (portas ethernet) if (resposta.comando && resposta.comando.includes('LST-ONULANINFO')) { // Extrair informações das portas const portMatches = dados.matchAll(/PORT\s*=\s*(\d+).*?STATUS\s*=\s*(\w+)/gi); for (const match of portMatches) { const portNum = parseInt(match[1]); const status = match[2].toLowerCase(); if (portNum >= 1 && portNum <= 4) { if (!resultado.portasEthernet[portNum-1]) { resultado.portasEthernet[portNum-1] = { porta: portNum, status: 'unknown' }; } resultado.portasEthernet[portNum-1].status = status === 'up' ? 'active' : status === 'down' ? 'inactive' : 'unknown'; } } } } } // Tentar extrair distância dos dados da listagem (onde já funcionou) if (dadosONU.listagem || dadosONU.dadosOriginais) { const dadosCompletos = dadosONU.listagem || dadosONU.dadosOriginais; // Análise específica do formato TL1 tabular const linhasTabela = dadosCompletos.split('\r\n').filter(linha => linha.includes('\t') && linha.includes(dadosONU.posicao.mac.toLowerCase()) && !linha.includes('OLTID\tPONID') ); if (linhasTabela.length > 0) { const campos = linhasTabela[0].split('\t'); // Último campo geralmente contém código de ranging (ex: RP2610) const ultimoCampo = campos[campos.length - 1]; // Extrair número do código RP (Ranging Profile) const rpMatch = ultimoCampo.match(/RP(\d{2})(\d{2})/); if (rpMatch) { // RP2610 = distância baseada no perfil // Converter baseado em padrões típicos dos equipamentos Fiberhome const codigoDistancia = parseInt(rpMatch[2]); if (codigoDistancia > 0) { // Estimativa baseada no código (cada unidade pode representar ~100m) const distanciaEstimada = codigoDistancia * 10; resultado.distance = `${distanciaEstimada} m`; } } } // Procurar por dados de distância explícitos na listagem const distanciaMatches = [ dadosCompletos.match(/DISTANCE[=\s:]+(\d+)/gi), dadosCompletos.match(/RANGING[=\s:]+(\d+)/gi), dadosCompletos.match(/RANGE[=\s:]+(\d+)/gi), // Buscar por padrões mais específicos de distância com metros (mínimo 3 dígitos) dadosCompletos.match(/\b(\d{3,4})\s*m(?:etros?)?\b/gi) ]; for (const matches of distanciaMatches) { if (matches && matches.length > 0) { // Pegar o primeiro match válido const match = matches[0].match(/(\d+)/); if (match) { resultado.distance = `${match[1]} m`; break; } } } // Extrair informações de potência se disponível na listagem const rxMatches = [ dadosCompletos.match(/RX[=\s:]+([+-]?\d+\.?\d*)/gi), dadosCompletos.match(/RXPOWER[=\s:]+([+-]?\d+\.?\d*)/gi) ]; for (const matches of rxMatches) { if (matches && matches.length > 0) { const match = matches[0].match(/([+-]?\d+\.?\d*)/); if (match) { resultado.rxPower = `${match[1]} dBm`; break; } } } const txMatches = [ dadosCompletos.match(/TX[=\s:]+([+-]?\d+\.?\d*)/gi), dadosCompletos.match(/TXPOWER[=\s:]+([+-]?\d+\.?\d*)/gi) ]; for (const matches of txMatches) { if (matches && matches.length > 0) { const match = matches[0].match(/([+-]?\d+\.?\d*)/); if (match) { resultado.txPower = `${match[1]} dBm`; break; } } } } // Processar dados detalhados se disponível if (dadosONU.detalhes) { this.logger.debug('Processando dados detalhados da ONU:', dadosONU.detalhes); // Extrair RX Power const rxMatches = [ dadosONU.detalhes.match(/RXPOWER[=\s:]+([+-]?\d+\.?\d*)/i), dadosONU.detalhes.match(/RX[=\s:]+([+-]?\d+\.?\d*)/i) ]; for (const match of rxMatches) { if (match) { resultado.rxPower = `${match[1]} dBm`; break; } } // Extrair TX Power const txMatches = [ dadosONU.detalhes.match(/TXPOWER[=\s:]+([+-]?\d+\.?\d*)/i), dadosONU.detalhes.match(/TX[=\s:]+([+-]?\d+\.?\d*)/i) ]; for (const match of txMatches) { if (match) { resultado.txPower = `${match[1]} dBm`; break; } } // Extrair distância const distMatches = [ dadosONU.detalhes.match(/DISTANCE[=\s:]+(\d+)/i), dadosONU.detalhes.match(/RANGINGTIME[=\s:]+(\d+)/i) ]; for (const match of distMatches) { if (match) { resultado.distance = `${match[1]} m`; break; } } } // Processar dados de estado geral se disponível if (dadosONU.estadoGeral) { this.logger.debug('Processando dados de estado geral:', dadosONU.estadoGeral); // Verificar se está online/offline if (dadosONU.estadoGeral.includes('ONLINE') || dadosONU.estadoGeral.includes('ACTIVE') || dadosONU.estadoGeral.includes('UP')) { resultado.online = true; } else if (dadosONU.estadoGeral.includes('OFFLINE') || dadosONU.estadoGeral.includes('INACTIVE') || dadosONU.estadoGeral.includes('DOWN')) { resultado.online = false; } } // Se não temos dados específicos das portas, usar padrão if (resultado.portasEthernet.length === 0) { resultado.portasEthernet = [ { porta: 1, status: 'unknown' }, { porta: 2, status: 'unknown' }, { porta: 3, status: 'unknown' }, { porta: 4, status: 'unknown' } ]; } // Se não temos dados WAN específicos, mas a ONU está online if (resultado.servicosWAN.length === 0 && resultado.online) { resultado.servicosWAN.push({ id: 1, status: 'active', ip: 'Configurado' }); } } 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: [] }; } } /** * 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; } } module.exports = FiberhomeManager;