import fs from 'fs';
import path from 'path';
import axios from 'axios';
import xml2js from 'xml2js';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const CREDENTIALS_FILE = path.join(__dirname, 'credentials.json');
const HTML_OUTPUT_FILE = path.join(__dirname, 'status.html');
const API_URL = 'https://rs.alarmnet.com/TC2API/TC2.asmx';
const APPLICATION_ID = 14588; // App ID estándar de Total Connect 2.0
const APPLICATION_VERSION = '3.0.0';
// Parser de XML configurado para remover prefijos de namespaces (como soap:)
const xmlParser = new xml2js.Parser({
explicitArray: false,
ignoreAttrs: true,
tagNameProcessors: [xml2js.processors.stripPrefix]
});
// Función para parsear XML a objeto JS de manera segura
async function parseXml(xmlString) {
return await xmlParser.parseStringPromise(xmlString);
}
// Inicializar archivo de credenciales de ejemplo si no existe
function initCredentialsFile() {
if (!fs.existsSync(CREDENTIALS_FILE)) {
const template = [
{
label: "Cuenta Principal",
username: "tu_usuario_1",
password: "tu_password_1"
},
{
label: "Cuenta Secundaria",
username: "tu_usuario_2",
password: "tu_password_2"
}
];
fs.writeFileSync(CREDENTIALS_FILE, JSON.stringify(template, null, 2), 'utf8');
console.log(`⚠️ Se ha creado un archivo de plantilla en: ${CREDENTIALS_FILE}`);
console.log("Por favor edítalo con tus credenciales reales de TotalConnect 2.0 antes de ejecutar.");
process.exit(1);
}
}
// Traducir código de estado de alarma
function parseArmingState(stateCode) {
const code = parseInt(stateCode);
switch (code) {
// Códigos normales de desarmado
case 102:
case 10200:
case 10201: // Listo para armar
case 10203: // Alarma en memoria / aviso
return {
label: "Desarmado",
class: "state-disarmed",
icon: "🟢",
badge: "Listo"
};
case 10202: // No listo para armar (p.ej. sensor abierto)
return {
label: "Desarmado (No Listo / Zona Abierta)",
class: "state-fault",
icon: "🟡",
badge: "Revisar"
};
// Códigos de armado
case 101:
case 10100: // Armado fuera (Away)
return {
label: "Armado Fuera",
class: "state-armed-away",
icon: "🔴",
badge: "Armado (Away)"
};
case 103:
case 10300: // Armado casa (Stay)
return {
label: "Armado En Casa",
class: "state-armed-stay",
icon: "🟠",
badge: "Armado (Stay)"
};
case 104:
case 10400: // Armado noche (Night)
return {
label: "Armado Noche",
class: "state-armed-night",
icon: "🔵",
badge: "Armado (Night)"
};
default:
return {
label: `Estado Desconocido (${stateCode})`,
class: "state-unknown",
icon: "⚪",
badge: "Desconocido"
};
}
}
// 1. Realizar Login y obtener SessionID y lista de Sucursales (Locations)
async function loginAndGetLocations(username, password) {
const soapEnvelope = `
| Cuenta | Sucursal / Locación | Estatus Alarma |
|---|