-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.js
More file actions
373 lines (311 loc) · 11.8 KB
/
Copy pathapp.js
File metadata and controls
373 lines (311 loc) · 11.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
// ===== CONFIGURACIÓN - EDITA AQUÍ =====
const MQTT_CONFIG = {
broker: 'broker.hivemq.com', // Cambia aquí el broker
port: 8884, // Puerto WSS
topic: 'cfe/monitor/fuente', // Tópico MQTT (valores: CFE o GENERADOR)
path: '/mqtt' // Ruta del WebSocket
};
const DISPOSITIVO = {
id: 'DIS-2024-001', // ID del dispositivo
ubicacion: 'Edificio Principal' // Ubicación del dispositivo
};
const AUTH_CREDENTIALS = {
username: 'generac',
password: 'tymse-generac2025'
};
// ======================================
// Variables globales
let client = null;
let isConnected = false;
let deferredPrompt;
let isAuthenticated = false;
let messageReceivedTimeout = null;
let hasReceivedMessage = false;
// Elementos del DOM
const connectBtn = document.getElementById('connectBtn');
const statusDot = document.querySelector('.status-dot');
const statusText = document.getElementById('statusText');
const valueDisplay = document.getElementById('valueDisplay');
const timestamp = document.getElementById('timestamp');
const installPrompt = document.getElementById('installPrompt');
const installBtn = document.getElementById('installBtn');
const deviceInfo = document.getElementById('deviceInfo');
const authModal = document.getElementById('authModal');
const authForm = document.getElementById('authForm');
const authError = document.getElementById('authError');
const switchBtn = document.getElementById('switchBtn');
// Mostrar información del dispositivo
if (deviceInfo) {
deviceInfo.innerHTML = `
<div style="margin-bottom: 10px;">
<strong>ID Dispositivo:</strong> ${DISPOSITIVO.id}
</div>
<div>
<strong>Ubicación:</strong> ${DISPOSITIVO.ubicacion}
</div>
`;
}
// Actualizar estado de conexión
function updateStatus(connected, message) {
isConnected = connected;
statusText.textContent = message;
if (connected) {
statusDot.className = 'status-dot connected';
connectBtn.textContent = 'Desconectar';
connectBtn.classList.add('connected');
// No habilitar automáticamente el botón SWITCH, esperar a recibir un valor válido
} else {
statusDot.className = 'status-dot disconnected';
connectBtn.textContent = 'Conectar';
connectBtn.classList.remove('connected');
switchBtn.disabled = true; // Deshabilitar botón SWITCH cuando está desconectado
// Limpiar valor mostrado cuando no está conectado
valueDisplay.innerHTML = '<div class="no-data">Esperando datos...</div>';
timestamp.textContent = '';
}
}
// Mostrar valor recibido y cambiar color de fondo
function displayValue(value) {
const valorLimpio = value.trim().toUpperCase();
// Marcar que se ha recibido un mensaje
hasReceivedMessage = true;
// Limpiar el timeout si existe
if (messageReceivedTimeout) {
clearTimeout(messageReceivedTimeout);
messageReceivedTimeout = null;
}
// Si estamos conectados y no es el mensaje de "SIN INTERNET",
// reiniciar el timer de 3 minutos para el monitoreo continuo
if (isConnected && valorLimpio !== 'SIN INTERNET') {
messageReceivedTimeout = setTimeout(() => {
showNoInternet();
}, 180000); // 3 minutos (180,000 ms)
}
// Habilitar o deshabilitar botón SWITCH según el valor recibido
// Habilitar si hay cualquier valor válido excepto "SIN INTERNET"
if (isConnected && valorLimpio !== 'SIN INTERNET') {
switchBtn.disabled = false;
} else {
switchBtn.disabled = true;
}
// Determinar el color de fondo según la fuente
let backgroundColor;
if (valorLimpio === 'CFE') {
backgroundColor = 'linear-gradient(135deg, #1e3c72 0%, #2a5298 100%)'; // Azul
} else if (valorLimpio === 'GENERADOR') {
backgroundColor = 'linear-gradient(135deg, #c31432 0%, #e85d75 100%)'; // Rojo
} else if (valorLimpio === 'SIN INTERNET') {
backgroundColor = 'linear-gradient(135deg, #434343 0%, #000000 100%)'; // Negro/Gris
} else {
backgroundColor = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'; // Morado (default)
}
// Cambiar color de fondo del body
document.body.style.background = backgroundColor;
// Mostrar el valor
valueDisplay.innerHTML = `<div class="value">${valorLimpio}</div>`;
const now = new Date();
timestamp.textContent = `Última actualización: ${now.toLocaleString('es-ES')}`;
// Animación
valueDisplay.classList.add('pulse');
setTimeout(() => valueDisplay.classList.remove('pulse'), 500);
}
// Mostrar mensaje de sin internet
function showNoInternet() {
displayValue('SIN INTERNET');
console.log('Timeout: No se recibieron mensajes - Mostrando SIN INTERNET');
}
// Funciones de Autenticación
function checkAuthentication() {
const authStatus = localStorage.getItem('mqttMonitorAuth');
if (authStatus === 'authorized') {
isAuthenticated = true;
authModal.classList.remove('active');
} else {
isAuthenticated = false;
authModal.classList.add('active');
}
return isAuthenticated;
}
function handleLogin(e) {
e.preventDefault();
const username = document.getElementById('username').value.trim();
const password = document.getElementById('password').value;
if (username === AUTH_CREDENTIALS.username && password === AUTH_CREDENTIALS.password) {
// Autenticación exitosa
localStorage.setItem('mqttMonitorAuth', 'authorized');
isAuthenticated = true;
authModal.classList.remove('active');
authError.textContent = '';
// Limpiar formulario
authForm.reset();
console.log('Autenticación exitosa');
} else {
// Credenciales incorrectas
authError.textContent = 'Usuario o contraseña incorrectos';
document.getElementById('password').value = '';
document.getElementById('password').focus();
}
}
// Función para enviar mensaje STATUS
function sendStatus() {
if (!client) return;
const statusTopic = `${MQTT_CONFIG.topic}/${DISPOSITIVO.id}`;
client.publish(statusTopic, 'STATUS', { qos: 0, retain: false }, (err) => {
if (err) {
console.error('Error al enviar STATUS:', err);
} else {
console.log('Mensaje STATUS enviado a:', statusTopic);
}
});
}
// Conectar a MQTT
function connectMQTT() {
updateStatus(false, 'Conectando...');
// Detectar si estamos en HTTPS y usar wss:// en lugar de ws://
const protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
const url = `${protocol}${MQTT_CONFIG.broker}:${MQTT_CONFIG.port}/mqtt`;
console.log('Conectando a:', url);
try {
client = mqtt.connect(url, {
clientId: 'mqttjs_' + Math.random().toString(16).substr(2, 8),
clean: true,
reconnectPeriod: 5000,
connectTimeout: 10000,
keepalive: 60
});
client.on('connect', () => {
console.log('Conectado a MQTT');
updateStatus(true, 'Conectado');
// Reiniciar flag de mensaje recibido
hasReceivedMessage = false;
// Limpiar el valor mostrado al reconectar
valueDisplay.innerHTML = '<div class="no-data">Esperando datos...</div>';
timestamp.textContent = '';
client.subscribe(MQTT_CONFIG.topic, (err) => {
if (err) {
console.error('Error al suscribirse:', err);
updateStatus(true, 'Conectado (error suscripción)');
} else {
console.log('Suscrito a:', MQTT_CONFIG.topic);
updateStatus(true, `Conectado - Escuchando`);
// Enviar mensaje STATUS al conectarse o reconectarse
sendStatus();
// Iniciar timeout de 30 segundos para verificar si se reciben mensajes
messageReceivedTimeout = setTimeout(() => {
if (!hasReceivedMessage) {
showNoInternet();
}
}, 30000); // 30 segundos
}
});
});
client.on('message', (topic, message) => {
console.log('Mensaje recibido:', message.toString());
displayValue(message.toString());
});
client.on('error', (err) => {
console.error('Error MQTT:', err);
updateStatus(false, 'Error de conexión');
});
client.on('close', () => {
console.log('Conexión cerrada');
updateStatus(false, 'Desconectado');
});
client.on('offline', () => {
console.log('Cliente offline');
updateStatus(false, 'Sin conexión');
});
client.on('reconnect', () => {
console.log('Reconectando...');
updateStatus(false, 'Reconectando...');
});
} catch (err) {
console.error('Error al conectar:', err);
updateStatus(false, 'Error al conectar');
}
}
// Desconectar de MQTT
function disconnectMQTT() {
// Limpiar timeout si existe
if (messageReceivedTimeout) {
clearTimeout(messageReceivedTimeout);
messageReceivedTimeout = null;
}
if (client) {
client.end();
client = null;
}
hasReceivedMessage = false;
updateStatus(false, 'Desconectado');
}
// Enviar comando SWITCH
function sendSwitch() {
if (!isConnected || !client) {
console.error('No hay conexión MQTT activa');
return;
}
// Mostrar confirmación antes de enviar el comando
const confirmar = confirm('¿Está seguro que desea cambiar la fuente eléctrica?\n\nSe realizará el cambio de la fuente eléctrica.');
if (!confirmar) {
console.log('Cambio de fuente cancelado por el usuario');
return;
}
const switchTopic = `${MQTT_CONFIG.topic}/${DISPOSITIVO.id}`;
client.publish(switchTopic, 'SWITCH', { qos: 0, retain: false }, (err) => {
if (err) {
console.error('Error al enviar SWITCH:', err);
alert('Error al enviar el comando SWITCH. Por favor intente nuevamente.');
} else {
console.log('Comando SWITCH enviado a:', switchTopic);
}
});
}
// Event Listeners
authForm.addEventListener('submit', handleLogin);
connectBtn.addEventListener('click', () => {
if (!isAuthenticated) {
authModal.classList.add('active');
return;
}
if (isConnected) {
disconnectMQTT();
} else {
connectMQTT();
}
});
switchBtn.addEventListener('click', () => {
sendSwitch();
});
// PWA Installation
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
deferredPrompt = e;
// El botón ya es visible, solo habilitamos la funcionalidad
installBtn.disabled = false;
installBtn.style.opacity = '1';
});
installBtn.addEventListener('click', async () => {
if (!deferredPrompt) {
alert('Para instalar esta app:\n\n📱 Android: Usa el menú del navegador > "Agregar a pantalla de inicio"\n🍎 iOS: Usa el botón compartir > "Agregar a pantalla de inicio"');
return;
}
deferredPrompt.prompt();
const { outcome } = await deferredPrompt.userChoice;
console.log(`User response: ${outcome}`);
if (outcome === 'accepted') {
installPrompt.style.display = 'none';
}
deferredPrompt = null;
});
window.addEventListener('appinstalled', () => {
console.log('PWA instalada exitosamente');
installPrompt.style.display = 'none';
});
// Detectar cuando la app se vuelve visible
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
console.log('App visible');
}
});
// Verificar autenticación al cargar la página
checkAuthentication();