fiberhome: add prelimunary add ONU support

Signed-off-by: Rodrigo Bertoldo de Sousa Martins <rodrigo.sousa.577@gmail.com>
This commit is contained in:
rodrigo committed 2026-02-10 19:41:29 -03:00
1 parent ee22ecf693
commit 94a3c6ab89
2 files changed
+180 -78

No files matched your search

+74 -67
View File
@@ -2,6 +2,7 @@ const NLPProcessor = require('../nlp/processor');
const SSHManager = require('../ssh/manager'); const SSHManager = require('../ssh/manager');
const { TopSappManager } = require('../topsapp'); const { TopSappManager } = require('../topsapp');
const FiberhomeManager = require('../fiberhome/manager'); const FiberhomeManager = require('../fiberhome/manager');
const FiberhomeTL1Manager = require('../fiberhome/manager_tl1');
const config = require('../config/config'); const config = require('../config/config');
const logger = require('../utils/logger'); const logger = require('../utils/logger');
const DateProcessor = require('../utils/dateProcessor'); const DateProcessor = require('../utils/dateProcessor');
@@ -13,6 +14,7 @@ class BotHandler {
this.ssh = new SSHManager(); this.ssh = new SSHManager();
this.topsapp = new TopSappManager(); this.topsapp = new TopSappManager();
this.fiberhome = new FiberhomeManager(); this.fiberhome = new FiberhomeManager();
this.fiberhomeTL1 = new FiberhomeTL1Manager();
this.dateProcessor = new DateProcessor(); this.dateProcessor = new DateProcessor();
this.userSessions = new Map(); // Armazena sessões de usuário this.userSessions = new Map(); // Armazena sessões de usuário
this.suporteSessions = new Map(); // Armazena sessões de suporte em andamento this.suporteSessions = new Map(); // Armazena sessões de suporte em andamento
@@ -1081,6 +1083,8 @@ Digite /help para ver todos os comandos disponíveis!
return; return;
} }
console.log(`📝 Criando sessão para usuário ${userId}, serial: ${serialNumber}`);
// Criar sessão para coletar informações // Criar sessão para coletar informações
this.userSessions.set(userId, { this.userSessions.set(userId, {
action: 'adicionar_onu_fiberhome_step1', action: 'adicionar_onu_fiberhome_step1',
@@ -1088,6 +1092,8 @@ Digite /help para ver todos os comandos disponíveis!
timestamp: Date.now() timestamp: Date.now()
}); });
console.log(`✅ Sessão criada. Sessões ativas:`, this.userSessions.size);
// Perguntar o alias/nome do usuário // Perguntar o alias/nome do usuário
await this.bot.sendMessage(chatId, await this.bot.sendMessage(chatId,
`➕ **Adicionar ONU Fiberhome**\n\n` + `➕ **Adicionar ONU Fiberhome**\n\n` +
@@ -1103,57 +1109,76 @@ Digite /help para ver todos os comandos disponíveis!
*/ */
async handleUserSessionInput(chatId, text, userId, session) { async handleUserSessionInput(chatId, text, userId, session) {
try { try {
switch (session.action) { console.log(`🔄 Processando input de sessão. Action: ${session.action}, Type: ${session.type}, Text: ${text}`);
case 'adicionar_onu_fiberhome_step1':
// Recebeu o nome do usuário, agora perguntar pelo tipo da ONU
session.usuario = text.trim();
session.action = 'adicionar_onu_fiberhome_step2';
this.userSessions.set(userId, session);
const keyboard = { // Verificar se é sessão baseada em action (Fiberhome ONU)
inline_keyboard: [ if (session.action) {
[{ text: '🔌 AN5506-02-B (2 portas)', callback_data: 'fh_onu_type_AN5506-02-B' }], switch (session.action) {
[{ text: '🔌 AN5506-01-A (1 porta)', callback_data: 'fh_onu_type_AN5506-01-A' }], case 'adicionar_onu_fiberhome_step1':
[{ text: '❌ Cancelar', callback_data: 'cancel_action' }] // Recebeu o nome do usuário, agora perguntar pelo tipo da ONU
] session.usuario = text.trim();
}; session.action = 'adicionar_onu_fiberhome_step2';
this.userSessions.set(userId, session);
await this.bot.sendMessage(chatId, const keyboard = {
`📡 **Porta PON:** ${session.portAlias}\n\n` + inline_keyboard: [
'🔌 Selecione o **tipo da ONU**:', [{ text: '🔌 AN5506-02-B (2 portas)', callback_data: 'fh_onu_type_AN5506-02-B' }],
{ reply_markup: keyboard, parse_mode: 'Markdown' } [{ text: '🔌 AN5506-01-A (1 porta)', callback_data: 'fh_onu_type_AN5506-01-A' }],
); [{ text: '❌ Cancelar', callback_data: 'cancel_action' }]
break; ]
};
case 'adicionar_onu_fiberhome_step5': await this.bot.sendMessage(chatId,
// Recebeu confirmação de VLAN customizada `👤 **Usuário:** ${session.usuario}\n\n` +
const vlanInput = text.trim(); '🔌 Selecione o **tipo da ONU**:',
{ reply_markup: keyboard, parse_mode: 'Markdown' }
);
return;
if (vlanInput && !isNaN(vlanInput)) { case 'adicionar_onu_fiberhome_step3':
const vlan = parseInt(vlanInput); // Recebeu confirmação de VLAN customizada
if (vlan >= 1 && vlan <= 4094) { const vlanInput = text.trim();
session.vlan = vlan;
if (vlanInput && !isNaN(vlanInput)) {
const vlan = parseInt(vlanInput);
if (vlan >= 1 && vlan <= 4094) {
session.vlan = vlan;
} else {
await this.bot.sendMessage(chatId, '❌ VLAN inválida. Usando VLAN padrão 1002.');
session.vlan = 1002;
}
} else { } else {
await this.bot.sendMessage(chatId, '❌ VLAN inválida. Usando VLAN padrão 1002.');
session.vlan = 1002; session.vlan = 1002;
} }
} else {
session.vlan = 1002;
}
// Limpar sessão // Limpar sessão
this.userSessions.delete(userId); this.userSessions.delete(userId);
// Executar adição da ONU // Executar adição da ONU
await this.executarAdicaoOnuFiberhome(chatId, session); await this.executarAdicaoOnuFiberhome(chatId, session);
break; return;
}
default:
// Sessão desconhecida, limpar
this.userSessions.delete(userId);
await this.bot.sendMessage(chatId, '❌ Sessão expirada. Por favor, comece novamente.');
break;
} }
// Verificar se é sessão baseada em type (outros fluxos)
if (session.type) {
switch (session.type) {
case 'waiting_custom_command':
await this.executeCustomCommand(chatId, session.connectionId, text);
this.userSessions.delete(userId);
return;
case 'waiting_username_disconnect':
await this.handleDisconnectUser(chatId, text.trim());
this.userSessions.delete(userId);
return;
}
}
// Estado desconhecido
console.log(`❓ Estado de sessão desconhecido: action=${session.action}, type=${session.type}`);
this.userSessions.delete(userId);
await this.bot.sendMessage(chatId, '❓ Estado de sessão desconhecido. Tente novamente.');
} catch (error) { } catch (error) {
console.error('❌ Erro ao processar input da sessão:', error); console.error('❌ Erro ao processar input da sessão:', error);
this.userSessions.delete(userId); this.userSessions.delete(userId);
@@ -1179,7 +1204,7 @@ Digite /help para ver todos os comandos disponíveis!
); );
// Executar comando TL1 via Fiberhome Manager // Executar comando TL1 via Fiberhome Manager
const resultado = await this.fiberhome.adicionarOnuFiberhome( const resultado = await this.fiberhomeTL1.adicionarOnuFiberhome(
serial, serial,
usuario, usuario,
vlan, vlan,
@@ -1196,7 +1221,7 @@ Digite /help para ver todos os comandos disponíveis!
`🔌 **Tipo:** ${onuType}\n` + `🔌 **Tipo:** ${onuType}\n` +
`🏷️ **VLAN:** ${vlan}\n` + `🏷️ **VLAN:** ${vlan}\n` +
`⚙️ **Portas configuradas:** ${resultado.details.portas}\n\n` + `⚙️ **Portas configuradas:** ${resultado.details.portas}\n\n` +
`🔐 **Login Web:** admin / clicknet10\n\n` + `🔐 **Login Web:** \`admin / clicknet10\`\n\n` +
`⚡ A ONU foi reiniciada e estará disponível em alguns instantes.`, `⚡ A ONU foi reiniciada e estará disponível em alguns instantes.`,
{ parse_mode: 'Markdown' } { parse_mode: 'Markdown' }
); );
@@ -1548,25 +1573,8 @@ Digite /help para ver todos os comandos disponíveis!
} }
/** /**
* Lida com input de usuário durante sessões específicas * MÉTODO REMOVIDO - handleUserSessionInput duplicado foi mesclado acima
*/ */
async handleUserSessionInput(chatId, text, userId, session) {
switch (session.type) {
case 'waiting_custom_command':
await this.executeCustomCommand(chatId, session.connectionId, text);
break;
case 'waiting_username_disconnect':
await this.handleDisconnectUser(chatId, text.trim());
break;
default:
await this.bot.sendMessage(chatId, '❓ Estado de sessão desconhecido. Tente novamente.');
}
// Limpar sessão
this.userSessions.delete(userId);
}
/** /**
* Executa comando personalizado em uma conexão SSH * Executa comando personalizado em uma conexão SSH
@@ -2639,7 +2647,7 @@ Digite /help para ver todos os comandos disponíveis!
// Recuperar sessão // Recuperar sessão
const session = this.userSessions.get(userId); const session = this.userSessions.get(userId);
if (!session || session.action !== 'adicionar_onu_fiberhome_step4') { if (!session || session.action !== 'adicionar_onu_fiberhome_step2') {
await this.bot.answerCallbackQuery(callbackQuery.id, '❌ Sessão expirada'); await this.bot.answerCallbackQuery(callbackQuery.id, '❌ Sessão expirada');
await this.bot.sendMessage(chatId, '❌ Sessão expirada. Por favor, comece novamente.'); await this.bot.sendMessage(chatId, '❌ Sessão expirada. Por favor, comece novamente.');
this.userSessions.delete(userId); this.userSessions.delete(userId);
@@ -2647,6 +2655,8 @@ Digite /help para ver todos os comandos disponíveis!
} }
session.onuType = onuType; session.onuType = onuType;
session.action = 'adicionar_onu_fiberhome_step3';
this.userSessions.set(userId, session);
await this.bot.answerCallbackQuery(callbackQuery.id); await this.bot.answerCallbackQuery(callbackQuery.id);
@@ -2681,7 +2691,7 @@ Digite /help para ver todos os comandos disponíveis!
// Recuperar sessão // Recuperar sessão
const session = this.userSessions.get(userId); const session = this.userSessions.get(userId);
if (!session || session.action !== 'adicionar_onu_fiberhome_step2') { if (!session || session.action !== 'adicionar_onu_fiberhome_step3') {
await this.bot.answerCallbackQuery(callbackQuery.id, '❌ Sessão expirada'); await this.bot.answerCallbackQuery(callbackQuery.id, '❌ Sessão expirada');
await this.bot.sendMessage(chatId, '❌ Sessão expirada. Por favor, comece novamente.'); await this.bot.sendMessage(chatId, '❌ Sessão expirada. Por favor, comece novamente.');
this.userSessions.delete(userId); this.userSessions.delete(userId);
@@ -2701,10 +2711,7 @@ Digite /help para ver todos os comandos disponíveis!
await this.executarAdicaoOnuFiberhome(chatId, session); await this.executarAdicaoOnuFiberhome(chatId, session);
} else if (data === 'fh_vlan_custom') { } else if (data === 'fh_vlan_custom') {
// Pedir VLAN customizada // Pedir VLAN customizada - manter sessão no step3 para receber input do usuário
session.action = 'adicionar_onu_fiberhome_step3';
this.userSessions.set(userId, session);
await this.bot.editMessageText( await this.bot.editMessageText(
`🏷️ **VLAN Customizada**\n\n` + `🏷️ **VLAN Customizada**\n\n` +
`Digite o número da VLAN que deseja usar (1-4094):`, `Digite o número da VLAN que deseja usar (1-4094):`,
+106 -11
View File
@@ -56,10 +56,12 @@ class FiberhomeManager {
async conectarUNM2000() { async conectarUNM2000() {
try { try {
if (this.tl1Connection && !this.tl1Connection.destroyed) { 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'); this.logger.debug('Conexão TL1 já existe e está ativa');
return true; return true;
} }
console.log('🔌 Conectando ao UNM2000 via TL1:', this.config.unm2000);
this.logger.debug('Conectando ao UNM2000 via TL1', this.config.unm2000); this.logger.debug('Conectando ao UNM2000 via TL1', this.config.unm2000);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@@ -72,43 +74,55 @@ class FiberhomeManager {
// Handler para dados recebidos // Handler para dados recebidos
this.tl1Connection.on('data', (data) => { this.tl1Connection.on('data', (data) => {
dataBuffer += data.toString(); dataBuffer += data.toString();
console.log('📥 TL1 dados recebidos:', dataBuffer);
this.logger.debug('TL1 dados recebidos:', dataBuffer); this.logger.debug('TL1 dados recebidos:', dataBuffer);
// Verificar se login foi bem-sucedido // Verificar se login foi bem-sucedido
if (!authenticated && dataBuffer.includes('COMPLD')) { if (!authenticated && dataBuffer.includes('COMPLD')) {
authenticated = true; authenticated = true;
console.log('✅ Login TL1 bem-sucedido!');
this.logger.info('Login TL1 bem-sucedido'); this.logger.info('Login TL1 bem-sucedido');
resolve(true); 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, () => { 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'); this.logger.debug('Socket TL1 conectado, enviando comando de login');
// Comando de login TL1 // Comando de login TL1 - formato correto: LOGIN:::CTAG::UN=username,PWD=password;
const loginCommand = `ACT-USER::${this.config.unm2000.username}:${this.commandId++}::${this.config.unm2000.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'); this.tl1Connection.write(loginCommand + '\r\n');
// Timeout para autenticação // Timeout para autenticação
setTimeout(() => { setTimeout(() => {
if (!authenticated) { if (!authenticated) {
this.logger.error('Timeout na autenticação TL1'); 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')); reject(new Error('Timeout na autenticação TL1'));
} }
}, 10000); }, 10000);
}); });
this.tl1Connection.on('error', (error) => { this.tl1Connection.on('error', (error) => {
console.log('❌ Erro na conexão TL1:', error.message);
this.logger.error('Erro na conexão TL1', error); this.logger.error('Erro na conexão TL1', error);
reject(error); reject(error);
}); });
this.tl1Connection.on('timeout', () => { this.tl1Connection.on('timeout', () => {
console.log('⏱️ Timeout do socket TL1');
this.logger.error('Timeout na conexão TL1'); this.logger.error('Timeout na conexão TL1');
reject(new Error('Timeout na conexão TL1')); reject(new Error('Timeout na conexão TL1'));
}); });
this.tl1Connection.on('close', () => { this.tl1Connection.on('close', () => {
console.log('🔌 Conexão TL1 fechada');
this.logger.debug('Conexão TL1 fechada'); this.logger.debug('Conexão TL1 fechada');
this.tl1Connection = null; this.tl1Connection = null;
}); });
@@ -386,6 +400,7 @@ class FiberhomeManager {
*/ */
async descobrirPortaPON(serial) { async descobrirPortaPON(serial) {
try { try {
console.log('🔍 Descobrindo porta PON para ONU:', serial);
this.logger.debug('Descobrindo porta PON para ONU', { serial }); this.logger.debug('Descobrindo porta PON para ONU', { serial });
// Conectar ao UNM2000 // Conectar ao UNM2000
@@ -394,18 +409,89 @@ class FiberhomeManager {
throw new Error('Não foi possível conectar ao UNM2000'); throw new Error('Não foi possível conectar ao UNM2000');
} }
// Buscar em todas as portas PON possíveis (slots 1-20, portas 1-16) let tentativas = 0;
for (let slot = 1; slot <= 20; slot++) { const maxTentativas = 320; // Máximo de tentativas (20 slots x 16 portas)
for (let porta = 1; porta <= 16; porta++) {
const ponId = `NA-NA-${slot}-${porta}`;
const comando = `LST-UNREGONU::OLTID=${this.config.olt.name},PONID=${ponId}:${this.commandId++}::;`;
this.logger.debug('Consultando porta PON', { ponId }); // 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); const resultado = await this.executarComandoTL1(comando);
if (resultado.success && resultado.data) { if (resultado.success && resultado.data) {
// Verificar se a ONU está na resposta // Verificar se a ONU está na resposta
if (resultado.data.toUpperCase().includes(serial.toUpperCase())) { if (resultado.data.toUpperCase().includes(serial.toUpperCase())) {
console.log(`✅ Porta PON descoberta: ${ponId}`);
this.logger.info('Porta PON descoberta', { serial, ponId }); this.logger.info('Porta PON descoberta', { serial, ponId });
return { return {
success: true, success: true,
@@ -414,21 +500,30 @@ class FiberhomeManager {
porta 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 // Pequeno delay entre consultas para não sobrecarregar
await new Promise(resolve => setTimeout(resolve, 100)); await new Promise(resolve => setTimeout(resolve, 200));
} }
} }
// ONU não encontrada // ONU não encontrada
this.logger.warn('ONU não encontrada em nenhuma porta PON', { serial }); 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 { return {
success: false, success: false,
error: 'ONU não encontrada em nenhuma porta PON. Verifique se a ONU está ligada e descoberta pela OLT.' error: 'ONU não encontrada em nenhuma porta PON. Verifique se a ONU está ligada e descoberta pela OLT.'
}; };
} catch (error) { } catch (error) {
console.log('❌ Erro ao descobrir porta PON:', error.message);
this.logger.error('Erro ao descobrir porta PON', { serial, error: error.message }); this.logger.error('Erro ao descobrir porta PON', { serial, error: error.message });
return { return {
success: false, success: false,