diff --git a/.agents/AGENTS.md b/.agents/AGENTS.md new file mode 100644 index 0000000..0d0aad8 --- /dev/null +++ b/.agents/AGENTS.md @@ -0,0 +1,12 @@ +# Reglas del Proyecto - Colaborando + +1. **Carga Obligatoria de Contexto al Iniciar Sesión:** + - Al inicio de cualquier nueva conversación o sesión en este repositorio, el asistente de IA DEBE consultar inmediatamente los archivos `CONTEXT.md` y `.antigravityrules`. + - `CONTEXT.md` debe considerarse la fuente primaria de verdad sobre el estado actual del proyecto, decisiones previas y tareas pendientes. + +2. **Verificación de Sincronización (Git vs CONTEXT.md):** + - Al leer `CONTEXT.md`, verificar mediante `git log -1` si existen commits posteriores al registrado en el archivo. + - Si `CONTEXT.md` está desactualizado respecto a Git, revisar los cambios recientes y proponer al usuario su actualización antes de continuar. + +3. **Permisos y Modificaciones:** + - Respetar estrictamente las reglas de `.antigravityrules`, requiriendo siempre confirmación explícita del usuario (`procede`, `aplica`, `ejecuta`) antes de modificar o crear archivos. diff --git a/.antigravityrules b/.antigravityrules old mode 100755 new mode 100644 index 1f00ffd..d6ba404 --- a/.antigravityrules +++ b/.antigravityrules @@ -1,15 +1,11 @@ # Antigravity AI Rules -1. **Permiso explícito obligatorio para realizar modificaciones**: +1. **Permiso explícito obligatorio para realizar consultas**: - El asistente de IA tiene permitido leer cualquier archivo y ejecutar comandos de lectura/diagnóstico sin necesidad de confirmación previa en el chat. - El asistente **NUNCA** debe crear, modificar o eliminar ningún archivo (tanto dentro como fuera del espacio de trabajo) ni ejecutar comandos que modifiquen el sistema sin la autorización previa y explícita del usuario en el chat. - Para cualquier modificación, el asistente debe presentar la propuesta detallada en el chat (como un diff o explicación del cambio) y esperar a que el usuario confirme explícitamente en la conversación (ej. "procede", "aplica", "ejecuta") antes de proceder. -2. **Persistencia de Planes y Tareas en el Proyecto**: - - Para evitar pérdidas de contexto al cambiar o reiniciar sesiones de chat, el asistente siempre debe replicar y guardar copias de sus archivos de planificación, tareas y bitácoras (`implementation_plan.md`, `task.md`, `walkthrough.md`) en la carpeta `doc/` ubicada en la raíz del proyecto. - - Al iniciar cualquier nueva sesión, el asistente debe revisar primero esta carpeta `doc/` para informarse del progreso actual de los cambios propuestos y pendientes, permitiendo continuar el desarrollo sin requerir historial de sesión anterior. - -3. **Análisis Técnico Objetivo y Crítico**: +2. **Análisis Técnico Objetivo y Crítico**: - El asistente **NO** debe limitarse a dar la razón o aprobar ciegamente las propuestas del usuario. - Ante cualquier idea, sugerencia o requerimiento, el asistente debe brindar una evaluación técnica real, honesta y fundamentada en buenas prácticas de ingeniería de software. - - **Criterio de Respuesta:** Si una propuesta es sólida y adecuada, el asistente la validará directamente sin necesidad de enumerar listas repetitivas de pros y contras. Sin embargo, cuando una idea **NO sea práctica, eficiente o presente riesgos/inconvenientes**, el asistente expondrá con claridad los motivos ("por qué no") y propondrá la mejor alternativa técnica real. \ No newline at end of file + - **Criterio de Respuesta:** Si una propuesta es sólida y adecuada, el asistente la validará directamente sin necesidad de enumerar listas repetitivas de pros y contras. Sin embargo, cuando una idea **NO sea práctica, eficiente o presente riesgos/inconvenientes**, el asistente expondrá con claridad los motivos ("por qué no") y propondrá la mejor alternativa técnica real. diff --git a/.gitignore b/.gitignore old mode 100755 new mode 100644 diff --git a/CONTEXT.md b/CONTEXT.md new file mode 100644 index 0000000..525aa89 --- /dev/null +++ b/CONTEXT.md @@ -0,0 +1,37 @@ +# Estado del Proyecto - TotalConnect 2.0 + +**Última actualización:** 2026-08-02 +**Versión actual:** v06.08.01 + +--- + +## 📌 Resumen del Estado Actual + +El proyecto **TotalConnect 2.0** es un panel web centralizado de alto rendimiento para el monitoreo de alarmas Honeywell / Resideo Total Connect 2.0. + +### 🛠️ Características Principales e Infraestructura +1. **Motor Híbrido Dinámico de Monitoreo (`index.py`)**: + - **Grupo 0**: Prioridad absoluta para sucursales con alarmas activas (particiones, zonas y estado ALARMING) o eventos SOAP pendientes (`needs_full_update = True`). + - **Esquema 2:1 (SOAP + REST)**: 2 consultas ligeras vía SOAP por 1 consulta completa por REST para evitar el *rate-limiting* de Honeywell (máximo 35 consultas REST por ciclo). + - **Resiliencia de Sesión**: Purgado automático de tokens SOAP obsoletos y auto-recuperación ante errores de red (`ConnectionResetError`). +2. **Dashboard Web e Interfaz en Tiempo Real**: + - **Badge de Escaneo en Vivo**: Muestra en tiempo real la sucursal actual en proceso de carga/sondeo (`Cargando sucursal: 6001`). + - **Visor de Bitácora Interactiva**: Modal visual en vivo para consultar las últimas 150 líneas del archivo de log (`activity.log`). + - **Hard Reset**: Mecanismo de purga de caché y reinicio por clic prolongado (3s) en el botón de actualización. + - **Kill-Switch / Polling Toggle**: Control de inicio/pausa de sondeo en segundo plano con *Circuit Breaker* ante errores `401`/`429`. +3. **Portabilidad y Parámetros**: + - Eliminación de rutas absolutas en duro (`Z:\`, `E:\`), operando de manera 100% relativa a la ruta de ejecución actual. + - Binario autónomo `totalconnect.exe` para Windows y soporte para servicio Systemd en Linux. + +--- + +## 🏷️ Historial de Tags / Versiones + +* **`v06.08.01`**: Prioridad en Grupo 0 para alarmas y eventos SOAP, indicador de escaneo en vivo en UI, eliminación de rutas absolutas en duro. + +--- + +## 📋 Tareas Pendientes / Próximos Pasos + +- [ ] Monitorear estabilidad del motor híbrido en producción tras despliegue de `v06.08.01`. +- [ ] Validar rendimiento en entornos con elevado número de cuentas Total Connect. diff --git a/README.md b/README.md old mode 100755 new mode 100644 diff --git a/TotalConnect.20260730.2256.rar b/TotalConnect.20260730.2256.rar new file mode 100644 index 0000000..3ee584c Binary files /dev/null and b/TotalConnect.20260730.2256.rar differ diff --git a/check_fullstatus_json.py b/check_fullstatus_json.py deleted file mode 100755 index e4701ab..0000000 --- a/check_fullstatus_json.py +++ /dev/null @@ -1,25 +0,0 @@ -import json -from total_connect_client.client import TotalConnectClient -from total_connect_client.const import make_http_endpoint - -creds = json.load(open('credentials.json', encoding='utf-8'))['accounts'][0] -client = TotalConnectClient(creds['username'], creds['password'], load_details=False) -client.authenticate() - -location_id = 1417027 -endpoint = make_http_endpoint(f"api/v3/locations/{location_id}/partitions/fullStatus") -res = client.http_request(endpoint=endpoint, method="GET") - -print("Keys at root of fullStatus response:") -print(list(res.keys())) - -print("\nValue of ArmingState at root:") -print(res.get("ArmingState")) - -print("\nValue of PanelStatus -> ArmingState:") -panel_status = res.get("PanelStatus", {}) -print(panel_status.get("ArmingState")) - -print("\nPartitions data:") -for p in panel_status.get("Partitions", []): - print(f" PartitionID={p.get('PartitionID')}, ArmingState={p.get('ArmingState')}") diff --git a/doc/alternative_implementations_comparison.md b/doc/alternative_implementations_comparison.md old mode 100755 new mode 100644 diff --git a/doc/polling_modes_explanation.md b/doc/polling_modes_explanation.md old mode 100755 new mode 100644 diff --git a/doc/portability_and_packaging.md b/doc/portability_and_packaging.md old mode 100755 new mode 100644 diff --git a/doc/project_deployment_guide.md b/doc/project_deployment_guide.md old mode 100755 new mode 100644 diff --git a/doc/proposed_events_integration_plan.md b/doc/proposed_events_integration_plan.md old mode 100755 new mode 100644 diff --git a/doc/walkthrough.md b/doc/walkthrough.md old mode 100755 new mode 100644 diff --git a/index.js b/index.js deleted file mode 100755 index da0c3c6..0000000 --- a/index.js +++ /dev/null @@ -1,517 +0,0 @@ -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 = ` - - - - ${username} - ${password} - ${APPLICATION_ID} - ${APPLICATION_VERSION} - en-US - - -`; - - const response = await axios.post(API_URL, soapEnvelope, { - headers: { - 'Content-Type': 'text/xml; charset=utf-8', - 'SOAPAction': 'https://services.alarmnet.com/TC2/LoginAndGetSessionDetails' - } - }); - - console.log("DEBUG RESPONSE:", response.data); - const parsed = await parseXml(response.data); - const result = parsed.Envelope.Body.LoginAndGetSessionDetailsResponse.LoginAndGetSessionDetailsResult; - - if (result.ResultCode !== '0') { - throw new Error(`Fallo en autenticación: Código de error ${result.ResultCode} (${result.ResultData || 'Credenciales inválidas'})`); - } - - const sessionId = result.SessionID; - - // Normalizar la lista de locaciones (si es solo una, xml2js la deja como objeto en vez de array) - let locations = []; - const rawLocations = result.Locations?.LocationInfoBasic; - if (rawLocations) { - locations = Array.isArray(rawLocations) ? rawLocations : [rawLocations]; - } - - return { sessionId, locations }; -} - -// 2. Obtener el estatus de un panel específico (GetPanelMetaDataAndFullStatusEx_V2) -async function getPanelStatus(sessionId, locationId) { - const soapEnvelope = ` - - - - ${sessionId} - ${locationId} - 0 - 0 - - 1 - - - -`; - - const response = await axios.post(API_URL, soapEnvelope, { - headers: { - 'Content-Type': 'text/xml; charset=utf-8', - 'SOAPAction': 'https://services.alarmnet.com/TC2/GetPanelMetaDataAndFullStatusEx_V2' - } - }); - - const parsed = await parseXml(response.data); - const result = parsed.Envelope.Body.GetPanelMetaDataAndFullStatusEx_V2Response.GetPanelMetaDataAndFullStatusEx_V2Result; - - if (result.ResultCode !== '0') { - throw new Error(`Fallo al consultar estatus del panel ${locationId}: Código ${result.ResultCode}`); - } - - return result.ArmingState; -} - -// 3. Generar el reporte HTML estático con diseño premium -function generateHtmlReport(data) { - const timeZone = 'America/Mexico_City'; - const timestamp = new Date().toLocaleString('es-MX', { - timeZone, - weekday: 'long', - year: 'numeric', - month: 'long', - day: 'numeric', - hour: '2-digit', - minute: '2-digit', - second: '2-digit', - hour12: true - }); - - // Construir filas de la tabla de sucursales - let rowsHtml = ''; - data.forEach(account => { - account.locations.forEach(loc => { - const state = parseArmingState(loc.status); - rowsHtml += ` - - -
${account.label}
-
${account.username}
- - - 🏢 ${loc.name} -
ID: ${loc.id}
- - - - - ${state.label} - - - `; - }); - }); - - const htmlContent = ` - - - - - Estatus de Sucursales - TotalConnect - - - - - - -
-
-
-

TotalConnect 2.0

-
Monitoreo centralizado de alarmas
-
-
-
Última Actualización
-
${timestamp}
-
-
- - - - - - - - - - - ${rowsHtml} - -
CuentaSucursal / LocaciónEstatus Alarma
- - -
- -`; - - fs.writeFileSync(HTML_OUTPUT_FILE, htmlContent, 'utf8'); - console.log(`\n🎉 Reporte HTML premium generado con éxito en: ${HTML_OUTPUT_FILE}`); -} - -// Función principal -async function main() { - console.log("🚀 Iniciando cliente de consulta TotalConnect 2.0..."); - initCredentialsFile(); - - const rawCreds = fs.readFileSync(CREDENTIALS_FILE, 'utf8'); - let accounts = JSON.parse(rawCreds); - if (!Array.isArray(accounts) && accounts.accounts) { - accounts = accounts.accounts; - } - - const reportData = []; - - for (const acc of accounts) { - console.log(`\n👤 Conectando a cuenta: ${acc.label} (${acc.username})...`); - try { - const { sessionId, locations } = await loginAndGetLocations(acc.username, acc.password); - console.log(` ✓ Sesión establecida con éxito.`); - console.log(` ✓ Se encontraron ${locations.length} sucursal(es).`); - - const locDataList = []; - for (const loc of locations) { - console.log(` ⏳ Consultando estatus de sucursal: ${loc.LocationName}...`); - const armingState = await getPanelStatus(sessionId, loc.LocationID); - locDataList.push({ - id: loc.LocationID, - name: loc.LocationName, - status: armingState - }); - } - reportData.push({ - label: acc.label, - username: acc.username, - locations: locDataList - }); - } catch (err) { - console.error(` ❌ Error procesando cuenta ${acc.label}: ${err.message}`); - } - } - - if (reportData.length > 0) { - generateHtmlReport(reportData); - } else { - console.error("❌ No se pudieron recuperar datos de ninguna cuenta."); - } -} - -main().catch(err => { - console.error("❌ Error catastrófico en la ejecución principal:", err); -}); diff --git a/index.py b/index.py old mode 100755 new mode 100644 index 19ac889..7780f8c --- a/index.py +++ b/index.py @@ -98,8 +98,8 @@ Formato B (Formato original de lista - Puerto por defecto 8080): -------------------------------------------------------------------------------- Este script implementa un motor de polling de alto rendimiento optimizado contra rate-limits: -A) Motor Dinámico Híbrido (Lote 27 + 7 por ciclo de 30s): - - Cada 30 segundos, consulta a 27 sucursales del turno ordinario (ordenadas de forma +A) Motor Dinámico Híbrido (Lote 35 + 7 por ciclo de 30s): + - Cada 30 segundos, consulta a 35 sucursales del turno ordinario (ordenadas de forma persistente por antigüedad de verificación) + hasta 7 de alta frecuencia (paneles desarmados, en alarma o con fallas físicas). - Realiza un Poll Lite SOAP (GetLiveEvents) rápido si la antigüedad de datos es menor @@ -177,7 +177,7 @@ CACHE_FILE = os.path.join(BASE_DIR, 'locations_cache.json') LAST_STATE_FILE = os.path.join(BASE_DIR, 'last_state.json') LAST_EVENT_IDS_FILE = os.path.join(BASE_DIR, 'last_event_ids.json') LOG_FILE = os.path.join(BASE_DIR, 'activity.log') -APP_VERSION = "06.07.26" +APP_VERSION = "06.08.01" polling_trigger_event = threading.Event() soap_disabled_accounts = set() soap_session_ids = {} # dict: username -> GUID SessionId para SOAP GetLiveEvents @@ -215,27 +215,18 @@ def load_polling_state(): return True def save_polling_state(enabled): - """Guarda el estado del polling (activo/pausado) exclusivamente en credentials.json.""" - target_files = [CREDENTIALS_FILE] - if platform.system() == "Windows": - target_files += [ - r"Z:\data2\Software\Bot-WhatsApp\TotalConnect\credentials.json", - r"E:\Software\TotalConnect\credentials.json", - r"E:\Software\TotalConnect\dist\credentials.json" - ] - - for target_path in set(target_files): - if os.path.exists(target_path): - try: - with open(target_path, 'r', encoding='utf-8') as f: - creds_data = json.load(f) - if isinstance(creds_data, dict): - creds_data["polling_enabled"] = enabled - with open(target_path, 'w', encoding='utf-8') as f: - json.dump(creds_data, f, ensure_ascii=False, indent=2) - log_msg(f"💾 Estado de polling ({enabled}) guardado en: {target_path}") - except Exception as e: - log_msg(f"⚠️ No se pudo actualizar polling_enabled en {target_path}: {e}") + """Guarda el estado del polling (activo/pausado) exclusivamente en credentials.json de la ruta actual.""" + if os.path.exists(CREDENTIALS_FILE): + try: + with open(CREDENTIALS_FILE, 'r', encoding='utf-8') as f: + creds_data = json.load(f) + if isinstance(creds_data, dict): + creds_data["polling_enabled"] = enabled + with open(CREDENTIALS_FILE, 'w', encoding='utf-8') as f: + json.dump(creds_data, f, ensure_ascii=False, indent=2) + log_msg(f"💾 Estado de polling ({enabled}) guardado en: {CREDENTIALS_FILE}") + except Exception as e: + log_msg(f"⚠️ No se pudo actualizar polling_enabled en {CREDENTIALS_FILE}: {e}") polling_enabled = load_polling_state() @@ -376,7 +367,7 @@ El archivo `credentials.json` debe colocarse junto al ejecutable o script y sopo ## 🔒 Robustez y Resiliencia Implementada -* **Motor Híbrido Dinámico (27 + 7):** En cada ciclo de 30s se procesan 27 sucursales del turno ordinario (ordenadas secuencialmente por antigüedad) + hasta 7 de alta frecuencia (desarmadas/alarmadas/fallos), previniendo rate-limits. +* **Motor Híbrido Dinámico (35 + 7):** En cada ciclo de 30s se procesan 35 sucursales del turno ordinario (ordenadas secuencialmente por antigüedad) + hasta 7 de alta frecuencia (desarmadas/alarmadas/fallos), previniendo rate-limits. * **Decisión Inteligente (SOAP vs REST):** Realiza un Poll Lite SOAP (GetLiveEvents) rápido si los datos de la sucursal tienen menos de 10 minutos. Si detecta actividad física, programa un Poll Full REST (fullStatus) para la siguiente vuelta. * **Tope de Consultas REST:** Limitador integrado de máximo 35 consultas REST por ciclo para un arranque en frío seguro sin bloqueos de cuenta. * **Visor de Logs Interactiva (150 líneas):** Botón "Ver Log" en el dashboard para auditar el servidor en vivo directamente desde el navegador. @@ -502,24 +493,67 @@ def format_trigger_time(raw_time_str): return f" @ {raw_time_str}" +def format_short_date(date_str): + """Convierte fechas del tipo '29/07/2026 06:42:05 PM' a formato corto de 24 horas: '29 Jul 18:42:05'.""" + if not date_str or not isinstance(date_str, str): + return "Nunca" + s = date_str.strip() + if "/" in s: + try: + parts = s.split(" ", 1) + date_parts = parts[0].split("/") + if len(date_parts) == 3: + day, month, year = date_parts + MESES_3 = { + "01": "Ene", "02": "Feb", "03": "Mar", "04": "Abr", "05": "May", "06": "Jun", + "07": "Jul", "08": "Ago", "09": "Sep", "10": "Oct", "11": "Nov", "12": "Dic" + } + m_short = MESES_3.get(month.zfill(2), month) + time_part = parts[1] if len(parts) > 1 else "" + + # Convertir hora AM/PM a formato de 24 horas + if time_part: + time_upper = time_part.upper() + is_pm = "PM" in time_upper + is_am = "AM" in time_upper + clean_time = time_upper.replace("AM", "").replace("PM", "").strip() + time_subparts = clean_time.split(":") + if len(time_subparts) >= 2: + hh = int(time_subparts[0]) + mm = time_subparts[1] + ss = time_subparts[2] if len(time_subparts) > 2 else "00" + if is_pm and hh < 12: + hh += 12 + elif is_am and hh == 12: + hh = 0 + time_part = f"{hh:02d}:{mm}:{ss}" + else: + time_part = clean_time + + return f"{int(day)} {m_short} {time_part}".strip() + except Exception: + pass + return s + + def get_account_badge_style(label): - """Devuelve un estilo distintivo para el badge de cada cuenta (solo el cuadrito).""" + """Devuelve un estilo distintivo de alto contraste para el badge de cada cuenta (cuadrito).""" clean = str(label).strip().lower() - # Paleta específica para cuentas conocidas + # Paleta específica de alto contraste para cuentas conocidas if "2020" in clean: - # Azul Real / Índigo Elegante - return 'style="background: #eff6ff; color: #1d4ed8; border: 1px solid #bfdbfe;"' + # Azul Índigo Intenso + return 'style="background: #dbeafe; color: #1e40af; border: 1.5px solid #3b82f6; font-weight: 700; padding: 3px 9px; border-radius: 6px; font-size: 0.75rem;"' elif "2019" in clean: - # Morado / Violeta Elegante - return 'style="background: #faf5ff; color: #7e22ce; border: 1px solid #e9d5ff;"' + # Morado Púrpura Intenso + return 'style="background: #f3e8ff; color: #6b21a8; border: 1.5px solid #a855f7; font-weight: 700; padding: 3px 9px; border-radius: 6px; font-size: 0.75rem;"' else: # Paleta dinámica para cualquier otra cuenta (hash de color) PALETTES = [ - 'style="background: #f0fdf4; color: #15803d; border: 1px solid #bbf7d0;"', # Verde - 'style="background: #fff7ed; color: #c2410c; border: 1px solid #fed7aa;"', # Naranja - 'style="background: #ecfeff; color: #0e7490; border: 1px solid #a5f3fc;"', # Cían - 'style="background: #fdf2f8; color: #be185d; border: 1px solid #fbcfe8;"', # Rosa + 'style="background: #dcfce7; color: #15803d; border: 1.5px solid #22c55e; font-weight: 700; padding: 3px 9px; border-radius: 6px; font-size: 0.75rem;"', # Verde + 'style="background: #ffedd5; color: #c2410c; border: 1.5px solid #f97316; font-weight: 700; padding: 3px 9px; border-radius: 6px; font-size: 0.75rem;"', # Naranja + 'style="background: #cffafe; color: #0e7490; border: 1.5px solid #06b6d4; font-weight: 700; padding: 3px 9px; border-radius: 6px; font-size: 0.75rem;"', # Cían + 'style="background: #fce7f3; color: #be185d; border: 1.5px solid #ec4899; font-weight: 700; padding: 3px 9px; border-radius: 6px; font-size: 0.75rem;"', # Rosa ] idx = sum(ord(c) for c in clean) % len(PALETTES) return PALETTES[idx] @@ -527,9 +561,9 @@ def get_account_badge_style(label): def _get_location_sort_priority(loc_item): """Calcula la prioridad de ordenamiento de una sucursal según su estado de armado.""" - state = loc_item['status'] - if isinstance(state, str) and state == "REVOKED": + if loc_item.get('is_revoked') or (isinstance(loc_item.get('status'), str) and loc_item.get('status') == "REVOKED"): return 3 + state = loc_item['status'] if isinstance(state, int): try: state = ArmingState(state) @@ -566,15 +600,18 @@ def generate_html_report(data): all_locations = [] for account in data: for loc in account['locations']: + is_rev = loc.get('is_revoked', False) or (isinstance(loc.get('status'), str) and loc.get('status') == "REVOKED") all_locations.append({ "account_label": account['label'], "id": loc['id'], "name": loc['name'], "status": loc['status'], + "is_revoked": is_rev, "triggered_partitions": loc.get('triggered_partitions', []), "active_zones": loc.get('active_zones', []), "last_download_time": loc.get('last_download_time'), - "last_update_time": loc.get('last_update_time') + "last_update_time": loc.get('last_update_time'), + "needs_full_update": loc.get('needs_full_update', False) }) # Ordenar prioritariamente: @@ -637,11 +674,11 @@ def generate_html_report(data): """ card_class = "branch-card" - if isinstance(loc['status'], str) and loc['status'] == "REVOKED": + if loc.get("is_revoked"): card_class += " branch-card-disabled" - dl_time = loc.get('last_download_time') or 'Nunca' - up_time = loc.get('last_update_time') or 'Nunca' + dl_time = format_short_date(loc.get('last_download_time')) + up_time = format_short_date(loc.get('last_update_time')) footer_html = f""" """ + sync_tag = "" + if loc.get("needs_full_update"): + sync_tag = '⚡ (Actualización programada)' + + revoked_tag = "" + if loc.get("is_revoked"): + revoked_tag = '⚠️ (Cuenta Desconectada)' + + acc_style = get_account_badge_style(loc['account_label']) cards_html += f"""
-
- - - {state['label']} - - +
+
+ + + {state['label']} + + {sync_tag} + {revoked_tag} +
+
🏢 {loc['name']}
{details_html} @@ -1190,7 +1240,13 @@ def generate_html_report(data):

TotalConnect 2.0

-
Monitoreo centralizado de alarmas
+
+
Monitoreo centralizado de alarmas
+ + + Escaneo en vivo: En espera + +
@@ -1402,6 +1458,46 @@ def generate_html_report(data): }} }}); + // Monitor en tiempo real de la sucursal siendo escaneada (Polling corto ultra-limpio) + let liveScanTimer = null; + async function checkLiveScanStatus() {{ + if (document.hidden) {{ + liveScanTimer = setTimeout(checkLiveScanStatus, 3000); + return; + }} + let statusUrl = '/current-loading'; + if (window.location.protocol === 'file:') {{ + if (window.location.pathname.indexOf(':') !== -1) {{ + statusUrl = 'http://localhost:8080/current-loading'; + }} else {{ + statusUrl = 'http://192.168.100.50:8080/current-loading'; + }} + }} + try {{ + const res = await fetch(statusUrl); + const data = await res.json(); + const txtEl = document.getElementById('live-scan-text'); + const dotEl = document.getElementById('live-scan-dot'); + if (txtEl && data.status) {{ + if (data.status.trim() !== '') {{ + txtEl.textContent = data.status; + if (dotEl) {{ + dotEl.style.background = '#2563eb'; + dotEl.style.boxShadow = '0 0 6px #2563eb'; + }} + }} else {{ + txtEl.textContent = 'Escaneo en vivo: En espera'; + if (dotEl) {{ + dotEl.style.background = '#10b981'; + dotEl.style.boxShadow = '0 0 5px #10b981'; + }} + }} + }} + }} catch (e) {{}} + liveScanTimer = setTimeout(checkLiveScanStatus, 2000); + }} + checkLiveScanStatus(); + async function fetchLogContent() {{ const terminal = document.getElementById('log-terminal-box'); if (!terminal) return; @@ -1916,6 +2012,8 @@ def soap_get_events(session_id, last_event_id, location_id=0): loc_id_val = None class_id_val = None type_id_val = None + event_text_val = "" + originator_val = "" for child in elem: tag_local = child.tag.split('}')[-1].lower() if '}' in child.tag else child.tag.lower() @@ -1939,13 +2037,19 @@ def soap_get_events(session_id, last_event_id, location_id=0): type_id_val = int(child.text) except (ValueError, TypeError): pass + elif tag_local in ('event', 'eventtext', 'description'): + event_text_val = child.text or "" + elif tag_local in ('originator', 'user'): + originator_val = child.text or "" if event_id_val is not None: events.append({ 'event_id': event_id_val, 'location_id': loc_id_val if loc_id_val is not None else 0, 'class_id': class_id_val if class_id_val is not None else 0, - 'type_id': type_id_val if type_id_val is not None else 0 + 'type_id': type_id_val if type_id_val is not None else 0, + 'event_text': event_text_val, + 'originator': originator_val }) if event_id_val > max_event_id: max_event_id = event_id_val @@ -1992,6 +2096,15 @@ def get_soap_session_id(client, force_refresh=False): return None +def invalidate_account_session(username): + """Purga la sesión del cliente en memoria para forzar una re-autenticación limpia desde cero.""" + with client_pool_lock: + c = client_pool.pop(username, None) + if c: + setattr(c, '_logged_in', False) + soap_session_ids.pop(username, None) + + def get_authenticated_client(acc, force_reauth=False): """Obtiene un cliente autenticado reutilizando la sesión activa en memoria si está viva.""" global client_pool, consecutive_errors @@ -2000,7 +2113,10 @@ def get_authenticated_client(acc, force_reauth=False): with client_pool_lock: if force_reauth: - client_pool.pop(username, None) + c = client_pool.pop(username, None) + if c: + setattr(c, '_logged_in', False) + soap_session_ids.pop(username, None) client = client_pool.get(username) if client and getattr(client, '_logged_in', False): @@ -2093,7 +2209,6 @@ def run_update(accounts=None, exclude=None, full_refresh=False): current_loading_status = f"Conectando a cuenta: {acc['label']}" log_msg(f"👤 Conectando a cuenta: {acc['label']} ({acc['username']})...") try: - # Reutilizar sesión autenticada en memoria para velocidad instantánea try: client = get_authenticated_client(acc) except Exception as auth_err: @@ -2131,17 +2246,7 @@ def run_update(accounts=None, exclude=None, full_refresh=False): continue active_locs_with_obj.append((loc_id, location)) - # Reconstruir mapa de device_id a location_id (si se requiere) - device_to_location = {} - for loc_id, location in active_locs_with_obj: - if getattr(location, 'security_device_id', None): - try: - dev_id = int(location.security_device_id) - device_to_location[dev_id] = loc_id - except Exception: - pass - - # 2. Ordenar por antigüedad de consulta profunda (last_download_epoch) + # 2. Ordenar por antigüedad de consulta (last_download_epoch) - Oldest First def get_download_epoch(loc_tuple): loc_id_str = str(loc_tuple[0]) prev = last_loc_map.get(loc_id_str, {}) @@ -2149,30 +2254,48 @@ def run_update(accounts=None, exclude=None, full_refresh=False): active_locs_with_obj.sort(key=get_download_epoch) - # 3. Construir Grupo 0 (Alarmas Activas - SIEMPRE incluidas, sin excepción) - # Se extraen ANTES de los demás grupos para garantizar presencia en cada ciclo. + # 3. Construir Grupo 0 (Alarmas Activas y Triggers SOAP - SIEMPRE incluidas obligatoriamente) + # Se extraen ANTES de los demás grupos para garantizar presencia y prioridad en cada ciclo. group_0 = [] group_0_ids = set() non_alarm_locs = [] for loc_id, location in active_locs_with_obj: loc_id_str = str(loc_id) prev = last_loc_map.get(loc_id_str, {}) - is_triggered = ( + + status_val = prev.get('status') + if isinstance(status_val, int): + try: + status_val = ArmingState(status_val) + except Exception: + pass + + status_is_alarm = False + if hasattr(status_val, 'is_triggered') and status_val.is_triggered(): + status_is_alarm = True + elif any(k in str(status_val).upper() for k in ("ALARM", "TRIGGERED")): + status_is_alarm = True + + is_alarm = ( + status_is_alarm or len(prev.get('triggered_partitions', [])) > 0 or any(z.get('status') == 'Alarma' for z in prev.get('active_zones', [])) ) - if is_triggered: + has_soap_trigger = prev.get('needs_full_update', False) + + if is_alarm or has_soap_trigger: group_0.append((loc_id, location)) group_0_ids.add(loc_id) - log_msg(f" 🚨 Grupo 0 (Alarma): '{location.location_name}' forzado en este ciclo.") + reason_label = "Alarma" if is_alarm else "Evento SOAP" + log_msg(f" 🚨 Grupo 0 ({reason_label}): '{location.location_name}' forzado en este ciclo.") else: non_alarm_locs.append((loc_id, location)) - # 4. Construir Grupo A (Secuencial - 27 sucursales, solo NO alarmadas) - group_a = non_alarm_locs[:27] + # 4. Grupo A: Secuencial (35 sucursales más antiguas, no alarmadas) + group_a = non_alarm_locs[:35] group_a_ids = {x[0] for x in group_a} - # 5. Construir Grupo B (Alta Frecuencia - Hasta 7 sucursales no alarmadas) + # 5. Grupo B: Alta Frecuencia (hasta 7 sucursales no alarmadas desarmadas/fallos) group_b_pool = [] for loc_id, location in non_alarm_locs: if loc_id in group_a_ids: @@ -2191,7 +2314,6 @@ def run_update(accounts=None, exclude=None, full_refresh=False): severity_weight = 1 if has_faults else 2 group_b_pool.append((loc_id, location, severity_weight)) - # Ordenar por severidad primero, luego por antigüedad def sort_group_b(item): loc_id_str = str(item[0]) prev = last_loc_map.get(loc_id_str, {}) @@ -2201,27 +2323,24 @@ def run_update(accounts=None, exclude=None, full_refresh=False): group_b = [(x[0], x[1]) for x in group_b_pool[:7]] group_b_ids = {x[0] for x in group_b} - # 6. Construir Grupo C (Triggers de SOAP pendientes, excluye alarmadas, A y B) + # 6. Grupo C (Triggers de SOAP pendientes ya cubiertos con prioridad en Grupo 0) group_c = [] - for loc_id, location in active_locs_with_obj: - if loc_id in group_0_ids or loc_id in group_a_ids or loc_id in group_b_ids: - continue - loc_id_str = str(loc_id) - prev = last_loc_map.get(loc_id_str, {}) - if prev.get('needs_full_update', False): - group_c.append((loc_id, location)) # Lote completo a procesar en este ciclo. - # group_0 va PRIMERO: sucursales en alarma activa garantizadas en cada ciclo. - lote_completo = group_0 + group_a + group_b + group_c + # En refresco manual (full_refresh=True), se procesa el 100% de las sucursales de la cuenta. + # En polling automático en segundo plano, se procesa el lote rotativo (Grupo 0 + A + B + C). + if full_refresh: + lote_completo = active_locs_with_obj + else: + lote_completo = group_0 + group_a + group_b + group_c lote_ids = {x[0] for x in lote_completo} loc_list = [] cache_locations = {} full_status_calls = 0 - MAX_FULL_CALLS_PER_CYCLE = 35 + MAX_FULL_CALLS_PER_CYCLE = 45 - # Procesar todas las sucursales de la cuenta + # Procesar sucursales de la cuenta for loc_id, location in client.locations.items(): loc_id_str = str(loc_id) loc_name_str = location.location_name @@ -2244,46 +2363,51 @@ def run_update(accounts=None, exclude=None, full_refresh=False): "last_download_time": prev_loc.get('last_download_time', "Nunca"), "last_update_epoch": prev_loc.get('last_update_epoch', 0), "last_update_time": prev_loc.get('last_update_time', "Nunca"), - "needs_full_update": prev_loc.get('needs_full_update', False) + "needs_full_update": prev_loc.get('needs_full_update', False), + "lite_count": prev_loc.get('lite_count', 0) }) cache_locations[loc_id_str] = loc_name_str continue - # Determinar si requiere Poll Full (REST) o Poll Lite (SOAP) + # Evaluador de motivo para Poll FULL needs_full_update = prev_loc.get('needs_full_update', False) last_dl_epoch = prev_loc.get('last_download_epoch', 0) antiguedad_seg = time.time() - last_dl_epoch if last_dl_epoch else 999999 + curr_lite_count = prev_loc.get('lite_count', 0) reason = None if loc_id in group_0_ids: - # Sucursal con ALARMA ACTIVA: siempre Poll Full, sin importar antigüedad reason = "Alarma activa — consulta forzada en cada ciclo" - elif full_refresh: - reason = "Refresco total manual solicitado" elif not prev_loc: reason = "Arranque en frío (sin caché previa)" elif needs_full_update: reason = "Cambio o evento previo detectado por SOAP" - elif antiguedad_seg > 600: + elif curr_lite_count >= 3: + reason = f"Límite de Polls Lite alcanzado ({curr_lite_count} lites previos) → Full preventivo" + elif antiguedad_seg >= 600: reason = f"Antigüedad de datos superó 10 minutos ({int(antiguedad_seg / 60)} min)" - # Limitador de velocidad: degradar a SOAP Lite si superamos el tope - if reason and full_status_calls >= MAX_FULL_CALLS_PER_CYCLE: + # Limitador de velocidad: degradar a SOAP Lite si superamos el tope (solo en polling automático) + max_full_limit = 999999 if full_refresh else MAX_FULL_CALLS_PER_CYCLE + if reason and full_status_calls >= max_full_limit: log_msg(f" ⚠️ Límite de Polls Full por ciclo alcanzado. Degradando '{loc_name_str}' a Poll Lite.") reason = None + now_dt = datetime.datetime.now(ZoneInfo("America/Mexico_City")) + now_str = now_dt.strftime('%d/%m/%Y %I:%M:%S %p') + # --- CASO A: POLL FULL (REST fullStatus) --- if reason: full_status_calls += 1 log_msg(f" ⏳ Poll FULL en '{loc_name_str}' (Motivo: {reason})") - current_loading_status = f"Cargando sucursal: {loc_name_str}" + loc_num = loc_name_str.split(' ')[0] if ' ' in loc_name_str else loc_name_str + current_loading_status = f"Cargando sucursal: {loc_num}" try: endpoint = make_http_endpoint(f"api/v3/locations/{loc_id}/partitions/fullStatus") result = client.http_request(endpoint=endpoint, method="GET") client.raise_for_resultcode(result) - # Actualizar la librería location._update_status(result) location._update_partitions(result["PanelStatus"]["Partitions"]) location._update_zones(result["PanelStatus"]["Zones"]) @@ -2291,12 +2415,10 @@ def run_update(accounts=None, exclude=None, full_refresh=False): triggered_parts = [] active_zones = [] - # Particiones for p_id, p in location.partitions.items(): if p.arming_state.is_triggered(): triggered_parts.append(p.name or f"Partición {p_id}") - # Zonas raw_zones = result.get("PanelStatus", {}).get("Zones", []) raw_zones_map = {int(z["ZoneID"]): z for z in raw_zones if "ZoneID" in z} @@ -2334,10 +2456,6 @@ def run_update(accounts=None, exclude=None, full_refresh=False): first_partition = next(iter(location.partitions.values())) effective_status = first_partition.arming_state - now_dt = datetime.datetime.now(ZoneInfo("America/Mexico_City")) - now_str = now_dt.strftime('%d/%m/%Y %I:%M:%S %p') - - # Determinar si el estado físico de armado cambió en este Full status_changed = False prev_status_val = prev_loc.get('status') if isinstance(prev_status_val, ArmingState): @@ -2360,11 +2478,30 @@ def run_update(accounts=None, exclude=None, full_refresh=False): "last_download_time": now_str, "last_update_epoch": last_up_epoch, "last_update_time": last_up_time, - "needs_full_update": False + "needs_full_update": False, + "lite_count": 0 # Resetea contador tras Full }) except Exception as full_err: - log_msg(f" ❌ Falló Poll FULL en '{loc_name_str}': {full_err}. Usando caché.") + err_str = str(full_err).lower() + log_msg(f" ❌ Falló Poll FULL en '{loc_name_str}': {full_err}.") + + # Si el error es de sesión o autenticación, purgar sesión e intentar re-autenticar inmediatamente + if any(k in err_str for k in ("401", "invalid session", "unauthorized", "token", "connectionreset", "login")): + log_msg(f" ⚠️ Sesión revocada/expirada detectada en '{loc_name_str}'. Purgando sesión e intentando re-autenticación...") + invalidate_account_session(acc['username']) + try: + # Intentar re-autenticación limpia inmediata + client = get_authenticated_client(acc, force_reauth=True) + log_msg(f" ✓ Re-autenticación exitosa. Reintentando consulta para '{loc_name_str}'...") + location.get_panel_meta_data() + except Exception as reauth_err: + log_msg(f" ❌ Re-autenticación rechazada para {acc['label']}: {reauth_err}. Abortando cuenta para marcar como REVOKED.") + # La cuenta fue revocada: lanzar excepción para ir al handler general que marca todas como REVOKED + raise Exception(f"Cuenta revocada o credenciales inválidas: {reauth_err}") + else: + log_msg(f" ⚠️ Usando caché local para '{loc_name_str}'.") + loc_list.append({ "id": loc_id, "name": loc_name_str, @@ -2375,12 +2512,19 @@ def run_update(accounts=None, exclude=None, full_refresh=False): "last_download_time": prev_loc.get('last_download_time', "Nunca"), "last_update_epoch": prev_loc.get('last_update_epoch', 0), "last_update_time": prev_loc.get('last_update_time', "Nunca"), - "needs_full_update": prev_loc.get('needs_full_update', False) + "needs_full_update": prev_loc.get('needs_full_update', False), + "lite_count": prev_loc.get('lite_count', 0) }) - # --- CASO B: POLL LITE (SOAP GetLiveEvents) --- + # --- CASO B: POLL LITE (SOAP GetLiveEvents) --- else: + loc_num = loc_name_str.split(' ')[0] if ' ' in loc_name_str else loc_name_str + current_loading_status = f"Cargando sucursal: {loc_num}" soap_success = False + new_lite_count = curr_lite_count + 1 + last_up_epoch = prev_loc.get('last_update_epoch', 0) + last_up_time = prev_loc.get('last_update_time', "Nunca") + if soap_sess_id: if not isinstance(last_event_ids.get(acc['username']), dict): last_event_ids[acc['username']] = {} @@ -2393,15 +2537,39 @@ def run_update(accounts=None, exclude=None, full_refresh=False): if curr_last_event_id == 0: last_event_ids[acc['username']][str(loc_id)] = next_event_id save_last_event_ids(last_event_ids) + log_msg(f" 🔹 Poll LITE (SOAP) en '{loc_name_str}' → Inicializado (ID: {next_event_id})") else: if events_list: - log_msg(f" 🔔 SOAP detectó {len(events_list)} eventos nuevos en '{loc_name_str}'.") + latest_ev = events_list[0] + ev_desc = latest_ev.get('event_text', '') + ev_type = latest_ev.get('type_id', 0) + + log_msg(f" 🔔 SOAP detectó {len(events_list)} evento(s) en '{loc_name_str}'. Primer cambio: '{ev_desc}'") + + # Deducir estado estimado a partir del evento SOAP para actualización rápida instantánea + est_status = None + desc_upper = ev_desc.upper() + if ev_type in (10200, 10226) or "DISARMED" in desc_upper: + est_status = ArmingState.DISARMED + elif ev_type in (10201, 10205) or "ARMED AWAY" in desc_upper: + est_status = ArmingState.ARMED_AWAY + elif ev_type == 10203 or "ARMED STAY" in desc_upper: + est_status = ArmingState.ARMED_STAY + elif ev_type == 10207 or "ALARM" in desc_upper: + est_status = ArmingState.ALARMING + + if est_status: + prev_loc['status'] = est_status + needs_full_update = True + new_lite_count = 0 # Forzará Full en la siguiente vuelta now_dt = datetime.datetime.now(ZoneInfo("America/Mexico_City")) now_str = now_dt.strftime('%d/%m/%Y %I:%M:%S %p') - prev_loc['last_update_epoch'] = time.time() - prev_loc['last_update_time'] = now_str + last_up_epoch = time.time() + last_up_time = now_str + else: + log_msg(f" 🔹 Poll LITE (SOAP) en '{loc_name_str}' → Sin eventos nuevos (OK)") last_event_ids[acc['username']][str(loc_id)] = next_event_id save_last_event_ids(last_event_ids) @@ -2409,8 +2577,6 @@ def run_update(accounts=None, exclude=None, full_refresh=False): soap_success = True except (ConnectionResetError, OSError): - # El GUID de sesión SOAP caducó o fue rechazado por Honeywell. - # Se limpia del caché para que en el siguiente ciclo se obtenga uno nuevo. soap_session_ids.pop(acc['username'], None) log_msg(f" ⚠️ Sesión SOAP expirada al consultar '{loc_name_str}'. GUID limpiado — se renovará en el siguiente ciclo.") except Exception as soap_err: @@ -2422,11 +2588,12 @@ def run_update(accounts=None, exclude=None, full_refresh=False): "status": prev_loc.get('status', ArmingState.UNKNOWN), "triggered_partitions": prev_loc.get('triggered_partitions', []), "active_zones": prev_loc.get('active_zones', []), - "last_download_epoch": prev_loc.get('last_download_epoch', 0), - "last_download_time": prev_loc.get('last_download_time', "Nunca"), - "last_update_epoch": prev_loc.get('last_update_epoch', 0), - "last_update_time": prev_loc.get('last_update_time', "Nunca"), - "needs_full_update": needs_full_update + "last_download_epoch": time.time(), # Actualiza timestamp para rotación unificada + "last_download_time": now_str, + "last_update_epoch": last_up_epoch, + "last_update_time": last_up_time, + "needs_full_update": needs_full_update, + "lite_count": new_lite_count }) cache_locations[str(loc_id)] = loc_name_str @@ -2447,27 +2614,44 @@ def run_update(accounts=None, exclude=None, full_refresh=False): except Exception as e: log_msg(f" ❌ Error al procesar cuenta {acc['label']}: {e}") + locs_to_revoke = [] cached_acc = cache_data.get(acc['username']) - if cached_acc: - log_msg(f" ⚠️ Cargando {len(cached_acc['locations'])} sucursales desde la caché local...") - loc_list = [] + + if cached_acc and cached_acc.get('locations'): for loc_id, loc_name in cached_acc['locations'].items(): + locs_to_revoke.append((loc_id, loc_name)) + elif acc['label'] in last_state_map: + old_acc = last_state_map[acc['label']] + for loc in old_acc.get('locations', []): + locs_to_revoke.append((loc['id'], loc['name'])) + + if locs_to_revoke: + log_msg(f" ⚠️ Marcando {len(locs_to_revoke)} sucursales de {acc['label']} como REVOKED en el tablero (conservando último estado conocido)...") + loc_list = [] + for loc_id, loc_name in locs_to_revoke: loc_id_str = str(loc_id) if exclude: if any(str(ex).strip() in loc_id_str or str(ex).strip() in loc_name for ex in exclude): continue + prev_loc = last_loc_map.get(loc_id_str, {}) + prev_status = prev_loc.get('status', ArmingState.UNKNOWN) + if prev_status == "REVOKED": + prev_status = ArmingState.UNKNOWN + loc_list.append({ "id": loc_id, "name": loc_name, - "status": "REVOKED", - "triggered_partitions": [], - "active_zones": [], - "last_download_epoch": 0, - "last_download_time": "Nunca", - "last_update_epoch": 0, - "last_update_time": "Nunca", - "needs_full_update": False + "status": prev_status, + "is_revoked": True, + "triggered_partitions": prev_loc.get('triggered_partitions', []), + "active_zones": prev_loc.get('active_zones', []), + "last_download_epoch": prev_loc.get('last_download_epoch', 0), + "last_download_time": prev_loc.get('last_download_time', "Desconectado"), + "last_update_epoch": prev_loc.get('last_update_epoch', 0), + "last_update_time": prev_loc.get('last_update_time', "Desconectado"), + "needs_full_update": False, + "lite_count": 0 }) report_data.append({ "label": acc['label'], @@ -2485,13 +2669,14 @@ def run_update(accounts=None, exclude=None, full_refresh=False): print(f" ⚠️ No se pudo guardar la caché de ubicaciones: {e}") # Mezclar los datos de las cuentas que no se actualizaron en esta ejecución - for label, old_acc_data in last_state_map.items(): - if label not in updated_labels: - report_data.append(old_acc_data) + final_report = list(report_data) + for acc_label, old_acc_data in last_state_map.items(): + if acc_label not in updated_labels: + final_report.append(old_acc_data) # Guardar el estado consolidado actual en last_state.json serializable_report = [] - for acc_data in report_data: + for acc_data in final_report: serializable_locs = [] for loc in acc_data['locations']: status_val = loc['status'].value if isinstance(loc['status'], ArmingState) else loc['status'] @@ -2499,13 +2684,15 @@ def run_update(accounts=None, exclude=None, full_refresh=False): "id": loc['id'], "name": loc['name'], "status": status_val, + "is_revoked": loc.get('is_revoked', False), "triggered_partitions": loc['triggered_partitions'], "active_zones": loc['active_zones'], "last_download_epoch": loc.get('last_download_epoch', 0), "last_download_time": loc.get('last_download_time', "Nunca"), "last_update_epoch": loc.get('last_update_epoch', 0), "last_update_time": loc.get('last_update_time', "Nunca"), - "needs_full_update": loc.get('needs_full_update', False) + "needs_full_update": loc.get('needs_full_update', False), + "lite_count": loc.get('lite_count', 0) }) serializable_report.append({ "label": acc_data['label'], @@ -2528,7 +2715,6 @@ def run_update(accounts=None, exclude=None, full_refresh=False): finally: current_loading_status = "" - def main(): # Asegurar que la documentación y plantillas existan en la carpeta de ejecución auto_generate_docs() diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 8ec23ff..0000000 --- a/package-lock.json +++ /dev/null @@ -1,379 +0,0 @@ -{ - "name": "totalconnect", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "totalconnect", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "axios": "^1.18.1", - "xml2js": "^0.6.2" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/axios": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.18.1.tgz", - "integrity": "sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.16.0", - "form-data": "^4.0.5", - "https-proxy-agent": "^5.0.1", - "proxy-from-env": "^2.1.0" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", - "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/follow-redirects": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", - "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/form-data": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", - "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.4", - "mime-types": "^2.1.35" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/proxy-from-env": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", - "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/sax": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", - "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=11.0.0" - } - }, - "node_modules/xml2js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", - "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", - "license": "MIT", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "license": "MIT", - "engines": { - "node": ">=4.0" - } - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 7bfa4ae..0000000 --- a/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "totalconnect", - "version": "1.0.0", - "description": "", - "main": "index.js", - "type": "module", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [], - "author": "", - "license": "ISC", - "dependencies": { - "axios": "^1.18.1", - "xml2js": "^0.6.2" - } -} diff --git a/print_last_state.py b/print_last_state.py deleted file mode 100755 index f59355f..0000000 --- a/print_last_state.py +++ /dev/null @@ -1,19 +0,0 @@ -import json -import os - -state_file = 'last_state.json' -if os.path.exists(state_file): - with open(state_file, 'r', encoding='utf-8') as f: - data = json.load(f) - print("Content of last_state.json:") - for acc in data: - print(f"\nAccount: {acc.get('label')} ({acc.get('username')})") - for loc in acc.get('locations', []): - loc_id = loc.get('id') - loc_name = loc.get('name') - if '0181' in loc_name or loc_id == 1417027: - print(f" 🏢 MATCH: ID={loc_id}, Name='{loc_name}', Status={loc.get('status')}") - print(f" Triggered Partitions: {loc.get('triggered_partitions')}") - print(f" Active Zones: {loc.get('active_zones')}") -else: - print("last_state.json does not exist!") diff --git a/totalconnect.exe b/totalconnect.exe new file mode 100644 index 0000000..2772539 Binary files /dev/null and b/totalconnect.exe differ diff --git a/ultimos_cambios.txt b/ultimos_cambios.txt new file mode 100644 index 0000000..1b00613 --- /dev/null +++ b/ultimos_cambios.txt @@ -0,0 +1,58 @@ +No te preocupes por el formato del bloque de código. Aquí tienes el reporte detallado escrito directamente en texto plano estructurado, fácil de leer y sin riesgo de que se desborde o se corte: + +REPORTE TÉCNICO: ARQUITECTURA E IMPLEMENTACIÓN DEL MOTOR HÍBRIDO DE MONITOREO (TOTALCONNECT 2.0) + +Este documento detalla las optimizaciones, razones de diseño y componentes implementados en el núcleo del sistema de monitoreo (index.py) para garantizar estabilidad, prevención de bloqueos (rate-limits) y eficiencia en el uso de la API de Honeywell. + +1. Resumen Ejecutivo de Cambios +Se rediseñó el ciclo de consulta en segundo plano para transicionar de un modelo lineal pesado a un motor híbrido dinámico (Poll Lite SOAP + Poll Full REST con control de rotación y contadores 2:1). Además, se dotó al panel web de un visor de bitácoras interactivo en vivo y de un mecanismo de recuperación de fallos (Hard Reset). + +2. Detalle de Cambios Implementados y Razones Técnicas + +A. Motor Híbrido Dinámico (Lotes Optimizados y Grupos de Prioridad) + +Implementación: Se dividió el procesamiento de las sucursales en cuatro grupos lógicos dentro de cada ciclo de 30 segundos: Grupo 0 (Alarma Activa con prioridad absoluta y forzada al 100%), Grupo A (Turno Secuencial Ordinario), Grupo B (Alta Frecuencia para desarmadas/fallos) y Grupo C (Triggers SOAP). + +Razón: Las llamadas REST (fullStatus) consultan el panel físico y tardan ~1.1 segundos. Consultar las 285 sucursales de golpe en cada ciclo saturaría la red y provocaría un bloqueo por rate-limiting en Honeywell. Este sistema por grupos prioriza las emergencias y distribuye la carga inteligentemente. + +B. Ciclo 2:1 (Poll LITE por SOAP y Poll FULL Preventivo) + +Implementación: Se introdujo un contador interno (lite_count) por sucursal persistido en la base de datos de estado (last_state.json). Cuando una sucursal es revisada mediante un Poll LITE (SOAP) rápido (~200ms), el contador se incrementa (+1). Si alcanza 3 Lites consecutivos, el sistema fuerza un Poll FULL (REST) preventivo de mantenimiento y reinicia el contador a 0. Si SOAP detecta un cambio de estado en vivo, se fuerza un Full inmediato en la siguiente vuelta. + +Razón: El uso exclusivo de Poll Full estancaba la rotación o saturaba las peticiones. Combinar 2 revisiones ligeras por SOAP y 1 profunda por REST reduce en más de un 60% las consultas pesadas a Honeywell manteniendo la precisión intacta. + +C. Sincronización y Unificación de Timestamps de Rotación (last_download_epoch) + +Implementación: Tanto en los bloques de Poll FULL como de Poll LITE (SOAP), se actualiza el registro de tiempo de verificación a la hora actual (time.time() y now_str). + +Razón: En la arquitectura preliminar, los Polls Lite no actualizaban el reloj de antigüedad, lo que provocaba que las mismas sucursales se quedaran atoradas al frente de la cola del Round-Robin de forma infinita. Al actualizar el timestamp en ambas modalidades, la sucursal avanza de manera fluida al final de la fila tras cada chequeo, permitiendo una rotación limpia del catálogo completo. + +D. Resilencia ante Caducidad de Sesiones SOAP (ConnectionResetError / OSError) + +Implementación: Se añadió un manejador de excepciones específico en las peticiones SOAP para capturar la expiración del token de sesión (GUID) de AlarmNet. Al detectarlo, se ejecuta un .pop() para purgar el token obsoleto de la memoria en caliente, forzando a que el siguiente ciclo solicite uno totalmente fresco. + +Razón: Los identificadores de sesión SOAP caducan de forma impredecible en los servidores de Honeywell. Sin esta limpieza automática, el script se quedaba intentando reutilizar el mismo token muerto indefinidamente. + +E. Visor de Logs Interactivo en el Dashboard (/activity-log) + +Implementación: Se añadió un botón en la cabecera del panel web ("Ver Log") que despliega una ventana modal con terminal oscura, conectada al endpoint backend /activity-log, el cual devuelve de forma limpia las últimas 150 líneas del archivo de actividad (activity.log). + +Razón: Facilita la auditoría en tiempo real del comportamiento del servidor, el estado de los polls y la detección de eventos sin necesidad de conectarse por SSH al servidor o revisar archivos de texto manualmente. + +F. Autogestión y Límite de Tamaño de Logs (activity.log) + +Implementación: Se programó una función de rotación automática en caliente dentro del método de escritura log_msg(). + +Razón: Cada vez que el log de actividad de la aplicación supera los 5 MB, el sistema lo renombra automáticamente a activity.log.1 (preservando un respaldo único) y abre un archivo limpio, previniendo que el almacenamiento de la VM o del servidor colapse por acumulación desatendida. + +G. Mecanismo de Hard Reset (Reinicio de Fábrica por Clic Largo) + +Implementación: Se programó una interacción táctil y de ratón en el botón "Actualizar" de la interfaz con un retardo visual de 1 segundo (el indicador rojo de advertencia aparece únicamente tras cruzar los primeros 1000 ms de presión continua). Si se mantiene presionado por 3.0 segundos o más, borra físicamente del disco los archivos temporales (last_state.json, locations_cache.json, last_event_ids.json), vacía el caché de clientes en memoria y reinicia el escaneo de cero tras una confirmación de seguridad. + +Razón: Permite resolver de forma limpia y directa cualquier inconsistencia severa de datos o corrupción temporal de caché sin requerir intervención técnica avanzada por comandos. + +H. Protección de Espacio en server.log (Opción 1 Implementada) + +Implementación: Se modificó la redirección del comando de arranque en segundo plano en Linux (nohup ... > /dev/null 2> server.log &) y se sobreescribió el método interno log_message del servidor HTTP para silenciar las peticiones secundarias de red repetitivas. + +Razón: Evita que el archivo server.log crezca gigabytes con peticiones HTTP ordinarias o duplicados de consola, manteniéndolo en 0 bytes y reservado exclusivamente para atrapar trazas de error (tracebacks de excepciones críticas) si el sistema llegara a fallar. \ No newline at end of file diff --git a/update_github.bat b/update_github.bat new file mode 100644 index 0000000..e97ba23 --- /dev/null +++ b/update_github.bat @@ -0,0 +1,50 @@ +@echo off +echo ======================================================= +echo Actualizando Repositorio Git y creando Tag v06.08.01 +echo ======================================================= + +git add . + +git commit -m "feat(polling): prioridad en Grupo 0 para alarmas y eventos SOAP e indicador de escaneo en vivo (v06.08.01)" -m "- Logica de Grupo 0:^ + + * Se unificaron las alarmas activas (particiones, zonas y estado ALARMING) y los eventos pendientes de SOAP (needs_full_update = True) dentro del Grupo 0.^ + + * Garantiza ejecucion al inicio del ciclo de polling en las primeras posiciones, evitando la degradacion por el limite de 35 consultas rutinarias.^ + + * Mantiene auto-limpieza dinamica: al recibir confirmacion de restablecimiento via REST, la sucursal sale del Grupo 0 automaticamente.^ + +^ + +- UI & Monitor en Tiempo Real:^ + + * Agregado badge visual de escaneo en vivo en el encabezado del tablero.^ + + * Muestra la sucursal actual en formato compacto (Cargando sucursal: 6001).^ + + * Implementacion en JS usando setTimeout recursivo, manipulacion directa de textContent y suspension en pestanas inactivas (Page Visibility API).^ + +^ + +- Correcciones de Infraestructura:^ + + * Se eliminaron rutas absolutas en duro (Z:\, E:\) en save_polling_state().^ + + * La configuracion del estado del polling ahora escribe exclusivamente en credentials.json de la ruta de ejecucion actual.^ + + * Actualizada version a 06.08.01." + +if %ERRORLEVEL% NEQ 0 ( + echo Error al realizar el commit o no hay cambios por commitear. +) + +echo Creando Tag v06.08.01... +git tag -a v06.08.01 -m "Version 06.08.01 - Prioridad Grupo 0 e indicador de escaneo" + +echo Subiendo cambios y tag a GitHub... +git push origin main +git push origin v06.08.01 + +echo ======================================================= +echo Proceso completado exitosamente. +echo ======================================================= +pause diff --git a/wsdl.xml b/wsdl.xml deleted file mode 100755 index d92d30a..0000000 --- a/wsdl.xml +++ /dev/null @@ -1,30788 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Performs Security Panel Quick commands - Arm - - - - - Performs Security Panel Quick Commands - CustomArm - - - - - Retrieves latest custom Arm settings set by the user - - - - - Performs Security Panel Quick commands - Disarm - - - - - Reads 16x2 Alpha Keypad Display and LED Status of Security System - - - - - Establishes Live Connection to Security System - - - - - Sends Keystroke to the Security Panel - - - - - Override Current User's Security Panel Session with his own Previous Session - - - - - Polling API - Which should be called based on Arm/Disarm API output Result Codes - - - - - Polling API - Which should be called based on Arm/Disarm API output Result Codes - - - - - Polling API - Which should be called based on Arm/Disarm API output Result Codes for Multipartion Arming - - - - - Polling API - Which should be called based on Arm/Disarm API output Result Codes for Multipartion Arming - - - - - Returns the current connection status of the security panel - - - - - Return List of Zone Informations for given ZoneId's - - - - - Refresh or Insert a Command for a Security Panel - - - - - Return the Status of security Panel at list of Locations for Given User - - - - - Performs Security Panel Quick commands - Arm - - - - - Performs Security Panel Quick commands - Arm - - - - - Initiates Zone Bypass - - - - - [Partially depreciated in TC2.3+, stuill used for Notifications groups] Get Users that you can Manage - - - - - [Depreciated in TC2.3+] Delete a user - - - - - [Depreciated in TC2.3+] Disable / Enable a user - - - - - Update Eula or SMS Eula for a User - - - - - [Depreciated in TC2.3+] Get User information when editing another user or editing yourself - - - - - [TC2.1+] Replacement for DeleteUserInfo. Deletes a Real User or Marks Virtual user for Deletion - - - - - [TC2.1+] Replacement for DisableEnableUser. Disable / Enable a user - - - - - Deprecated in TC Multilingual - [TC2.1+] Replacement for GetUserInfo. Get User information when editing another user or editing yourself - - - - - [TC2.1+] Replacement for GetUserDetails. Get User information when editing another user or editing yourself-Includes Wifi Lock as well - - - - - [TC3.24 +] Replacement for GetAllUserDetailsEx. It will return user partition related informations - - - - - [TC2.1+] Replacement for GetUserDetails. Get User information when editing another user or editing yourself - - - - - DEPRECATED in TC Multilingual - [TC2.1+] Replacement for SaveCreateUserInfo. Stores User information when editing self/another user or creating a new User - - - - - [TC2.1+] Replacement for SaveCreateUserInfo. Stores User information when editing self/another user or creating a new User - - - - - [TC2.1+] Replacement for SaveUserEx. Stores User information when editing self/another user or creating a new User.Added addtional feature - - - - - [TC3.24+] Replacement for SaveUserEx1. Included Partition informations - - - - - Used to update the usercode after login, so sessionid, oldUsercode, NewUserCode, UserId, LocationID is must - - - - - [TC3.8+] Created for Save MasterUsercode in TC if MasterUsercode changed in the panel. - - - - - [TC2.1+] Replacement for GetUsers. Returns List of Real Users that one can manage if asked at AccountLevel. This also returns Real+Virtual Users if asked at Location Level. - - - - - [TC2.1+] Synchronize Total Connect Users with Security System user codes - - - - - [TC2.1+] Provides list of SMS Email Carriers - - - - - [TC2.2+] Provides list of Notification Methods - - - - - Check if a UserName is ok to use - - - - - [Depreciated in TC2.3+] Add a user to an existing account, save user updates to another user, save user updates to yourself - - - - - Save User-Client Preferences - - - - - Get listing of Help Documents URLs - - - - - Used to update only the Language (LocaleId value) for a User. Country Code (ex. en-US) or a language Id as defined within TC2 can be used to update the value in the User Table. - - - - - Used to update the user password after login, so sessioid, OldPassword and NewPassword is must - - - - - [TC3.12+] Used to get feedback from users - - - - - [TC3.12+] Used to get feedback from users along with EmailID and rating - - - - - Validate user code - - - - - Used to update the user password after login, so sessioid, userName and NewPassword is must - - - - - [TC3.8+] Created for Save MasterUsercode in TC if MasterUsercode changed in the panel. - - - - - Used to update the usercode after login, so sessionid, oldUsercode, NewUserCode, UserId, LocationID is must - - - - - Validate user code - - - - - Remote Request for authentication for the given username/password using the specified client application. - - - - - MAC validation request for the given GUID for Mobile Punch thru access - - - - - Request for authentication for the given username/password using the specified client application. - - - - - Request for authentication for the given username/password using the specified client application. - - - - - Request for authentication for the given GUID using the specified client application. - - - - - Request for authentication for the given GUID using the specified client application. - - - - - Request session details for the given sessionID - - - - - Request for authentication for the given username/password using the specified client application and retrieves the session details on successful authentication - - - - - Request for authentication for the given GUID using the specified client application. - - - - - Request for authentication for the given username/password using the specified client application and retrieves the session details on successful authentication - - - - - Authentication for the given username and password using the specified client application and retrieves the session details on successful authentication - - - - - Request for authentication for the given encrypted username/password using the specified client application and retrieves the session details on successful authentication - - - - - Inquire about an active session for the purpose of avoiding a server-side timeout. - - - - - Request that the given sessionID be logged out and/or terminated. - - - - - Determines anything changed since last update. The result will guide the UI further. NOTE: Deprecated and no longer supported. - - - - - [DEPRECIATED] Request InterfaceSchema details for the given sessionID/username - - - - - Request InterfaceSchema details for the given sessionID/username - - - - - Request InterfaceSchema details for the given sessionID/username - - - - - Request for Static Key information for Clients - - - - - To Remove a single Smart Action - - - - - To Remove the List of Smart Actions - - - - - To Set the Smart Action state - - - - - To Execute the Smart Action - - - - - To Get the Smart Action Configuration - - - - - To Remove a single Smart Action - - - - - To Set the Smart Action state - - - - - To Execute the Smart Action - - - - - Retrieve the current configuration information for the given Video PIR. - - - - - Retrieve the list of Video PIR for the specified session and location. - - - - - Get the capturetypes for VideoPIR device - - - - - Update the configuration information for the given VideoPIR. - - - - - Returns the Video PIR event record based on Event TypeID - - - - - Trigger the Peek In Now Action for VideoPIR. - - - - - Get VideoPIR device events with applied filter condition - - - - - Return a list of WiFi locations and devices. - - - - - Activate WiFi Devices in Total Connect. - - - - - Turn On/Off WiFi Smart Away - - - - - Remove WiFi Device from Total Connect - - - - - This will return the weather forecast for the device location. - - - - - This will return the results for one thermostat. - - - - - Return a list of Lyric locations and devices. - - - - - Activate and Remove Lyric Thermostat in Total Connect. - - - - - Used to Save an image to an object PhotoClassId:1- location, 2 - User image - - - - - Used to Retrieve a Branding Image LOGO - - - - - Returns the data associated with a Location object from the database - - - - - Returns the data associated with the basic attributes of a Location object from the database - - - - - Saves the data associated with a LocationInfo object to the database. Since this method will only update an existing Location, you are required to pass in its LocationId. Pass in a null value for the Image byte array when either the image has not changed or when the default imageIs to be used. Any previous image will be deleted when either a null or actual image is saved. At the curent triggerTime, the Alias is for the one security system associated with this location. - - - - - Saves the data associated with a LocationInfo object to the database. Since this method will only update an existing Location, you are required to pass in its LocationId. Pass in a null value for the Image byte array when either the image has not changed or when the default imageIs to be used. Any previous image will be deleted when either a null or actual image is saved. At the curent triggerTime, the Alias is for the one security system associated with this location. - - - - - Retrieve the list of supported countries - - - - - Retrieve the list of states for a country - - - - - Retrieves the list of countries & States - - - - - Returns the Partners associated with a Location object from the database - - - - - Multiple Skybell Returns the Partners associated with a Location object from the database - - - - - Returns the Partners associated with a Location object from the database - - - - - Multiple Skybell Returns the Partners associated with a Location object from the database - - - - - Subscribe and Unsubscribe Lyric Account - - - - - Returns the Dealer Information - - - - - Returns the Subscriber Information - - - - - Returns the set of available triggerTime zone regions and their ID - - - - - Returns the set of available triggerTime zone regions and their ID for Camera - - - - - Provides version information for the web service. - - - - - Retrieves the set of video file URLs for a device or audit event record - - - - - Retrieves the set of video file URLs for a device or audit event record - - - - - Returns the notes associated with a device or audit event record - - - - - Returns a set of device or audit event records. A maximum of 100 records can be returned per call. - - - - - Returns a set of device or audit event records. A maximum of 100 records can be returned per call. - - - - - Returns doorbell event records. A maximum of 100 records can be returned per call. - - - - - Returns a set of device or audit event records. A maximum of 100 records can be returned per call. - - - - - Returns a set of device or audit event records. A maximum of 100 records can be returned per call.Eevnts by partition - - - - - Returns a list of available event type filter values that are to be used for filtering the event record retrieval. - - - - - Returns a list of available event type filter values that are to be used for filtering the event record retrieval. - - - - - Returns a set of device event records. A maximum of 250 records can be returned per call. The parameter LastEventIdReceived is used to retreive newer records than the ones previously obtained. Entering the most recent event id into this field will return all records that are newer than that record - - - - - Returns a set of device event records. A maximum of 250 records can be returned per call. The parameter LastEventIdReceived is used to retreive newer records than the ones previously obtained. Entering the most recent event id into this field will return all records that are newer than that record - - - - - Returns a set of doorbell event records. A maximum of 250 records can be returned per call. The parameter LastEventIdReceived is used to retreive newer records than the ones previously obtained. Entering the most recent event id into this field will return all records that are newer than that record - - - - - Updates the note associated with a device or audit event. Storing an empty string will clear a note. - - - - - Updates the hidden state of a device or audit event record. Hidden records are not returned during normal GetEvents requests unlessthe ShowHidden parameter is true. - - - - - Updates the lock state of a device or audit event record. When a record is locked, the automated clean up process will retain the locked record. Only unlocked records will be removed. - - - - - Updates the lock state of a device or audit event record. When a record is locked, the automated clean up process will retain the locked record. Only unlocked records will be removed. - - - - - Determine if the camera is available for a stream at the moment. Current reasons for unavailability would be if the camera is updating - - - - - Retrieve the current state (flags, pan/tilt location, WLLED, output state) for the given camera. - - - - - Retrieve the current I/O state (flags, WLLED, output state) for the given camera. - - - - - Retrieve the current pan/tilt location for the given camera. - - - - - Request that the given camera move to the given preset pan/tilt location. - - - - - Request that the current pan/tilt location be stored as the given preset slot for the given camera. - - - - - Request that the given camera move in the specified direction, speed and distance. - - - - - Request that the given camera move to the specified location, based on a 640x480 viewport mapping. - - - - - Request that the WLLED for the given camera be turned on/off. - - - - - Request that the output control for the given camera be turned on/off. - - - - - Request the given camera to archive a video clip to the server. - - - - - Configure the given camera to use the specified video mode. - - - - - Retrieve the list of cameras for the specified session and location. - - - - - Retrieve the list of All cameras for the specified session and location. - - - - - Retrieve the list of All cameras and Multiple Skybell for the specified session and location. - - - - - Retrieve the current configuration information for the given camera. - - - - - Retrieve the current configuration information for the given camera. - - - - - Retrieve the current configuration information (including limits) for the given camera. - - - - - Update the configuration information for the given camera. - - - - - Adjust default camera settings - - - - - Request that the camera firmware be upgraded/changed to the specified version (or default, if unspecified) - - - - - Request a list of available camera firmware upgrade options for the given camera. - - - - - Get camera wireless status - - - - - Get camera Information - provides camera wireless details and Network data - - - - - Gets WAP clients status - - - - - Gets Camera Battery Status - - - - - Get the Event Metadata applicable for the Given Location. Used for Notification Configuration - - - - - Get the Event Metadata applicable for the Given Location. Used for Notification Configuration - - - - - Get the Event Metadata applicable for the Given Location based on Partitions. Used for Notification Configuration - - - - - Get Configured Notification Events at the Given Location. - - - - - Get Configured Notification Events at the Given Location.Added notification flags for each module - - - - - Get Summary of Configured Notification Events in XML at the Given Location. - - - - - Get Summary of Configured Notification Events at the Given Location. - - - - - Update the stored data for the list of event notifications for the given location - - - - - Update the stored data for the list of event notifications for the given location - - - - - Update the stored data for the list of event notifications for the given location - - - - - Get the list of notification states permitted for this location. - - - - - Get the list of notification schedules available. - - - - - Update the stored data for the list of event notification schedules - - - - - Retrieves the Notification Lists associated with current user's TotalConnect account) - - - - - Updates the Notification List associated with the User - - - - - Sends Summary Email about the Notification List to the Admin user - - - - - Enable/disabled notifications for logged in user and/or return notification pause status. - - - - - Get the list of notification states permitted for this location. - - - - - Get the list of notification states permitted for this location. - - - - - [DEPRECATED] Get the Event Metadata applicable for the Given Location. Used for Notification Configuration - - - - - Request for Metadata and Full status of Security Panel for the Given Location and User - - - - - Return the Status of security Panel at multiple Locations for Given User - - - - - Request for Metadata and Full status of Security Panel for the Given Location and User - - - - - Request for Metadata and Full status of Security Panel for the Given Location and User.Added CanBeBypassable flag to determine zone is bypassable or not - - - - - Request for Metadata and Full status of Security Panel for the Given Location and User.Added CanBeBypassable flag to determine zone is bypassable or not - - - - - Request for Full status of Security Panel for the Given Location and User - - - - - Request for Full status of Security Panel for the Given DeviceID and User - - - - - Request for Full status of Security Panel for the Given Location and User - - - - - Request for Full status of Security Panel for the Given Location and User - - - - - Request for Full status of Security Panel for the Given Location and User - - - - - Request for Full status of Security Panel for the Given DeviceID and User - - - - - Get the zones in different states like Alarms, Faults, Trouble, and Bypassed - - - - - [Enriched Method] Get the zones in different states like Alarms, Faults, Trouble, and Bypassed and whether it is Bypassable Zone or Not - - - - - Request for Metadata and Full status of Security Panel for the Given DeviceID and User - - - - - Request for Metadata and Full status of Security Panel for the Given DeviceID and User - - - - - Initiates Zone Bypass for multiple zones - - - - - Initiates Zone Bypass - - - - - Update User's Geofence Area selection - includes Latitude, Longitude and Radius - - - - - Return a Device Invite Token for a Sky Bell User. - - - - - Return Device provisioning status for the given token. - - - - - Update DoorBell Details. - - - - - Removes Doorbell from TC and Skybell - - - - - Removes Doorbell from TC and Skybell for Multiple Skybell per Location - - - - - Get WiFi Door Bell Details. - - - - - Get WiFi Door Bell Details for Multiple Skybell per location. - - - - - Get WiFi Door Bell Settings - - - - - Update WiFi Door Bell Settings - - - - - Get all devices associated to Skybell Account. - - - - - Get Partner Video URL for the device event - - - - - Get DoorBell - Client ID - - - - - Get WiFi Door Bell Diagnostic Details. - - - - - Get WiFi Door Bell Diagnostic Details for Multiple Skybell per Location. - - - - - Get the maximum device count per location for all devices present in that location - - - - - Return Enrollment details for a Partner Camera - - - - - Return Enrollment status for a Partner Camera - - - - - Delete Partner Camera - - - - - Return a Activation status for Lyric Camera. - - - - - Return a Activation status for Lyric Camera. - - - - - Return Access Token detail for App - - - - - Return Refresh Token detail for App - - - - - Return a Settings for Lyric Camera. - - - - - Save the Settings for Lyric Camera. - - - - - Remove Lyric Camera from the Location. - - - - - Return Live Stream detail for Partner Camera - - - - - Return Lyric Camera and RSI Camera status. - - - - - Return Lyric Camera and RSI Camera status. - - - - - Return Live Stream detail for Partner Camera - - - - - Return clip Key detail for App - - - - - Return Live Snapshot detail for Partner Camera - - - - - Save the Settings for Lyric Camera. - - - - - Log Message to Kibana Server - - - - - Return Live Stream detail for Partner Camera - - - - - Save the Settings for VAV Camera. - - - - - Save the Settings for VAV Camera. - - - - - Return List of Partitions for the Given DeviceID - - - - - Return List of Partitions Authority Level info. - - - - - [TC2.1+] R Get User information with Partition Authority - - - - - [Enriched Method] Get the zones in different states like Alarms, Faults, Trouble, and Bypassed and whether it is Bypassable Zone or Not for Multipartition - - - - - Performs Security Panel Quick commands - Arm with specified partitions - - - - - Performs Security Panel Quick commands - Disarm - - - - - Performs Security Panel Quick commands - Arm with specified partitions - - - - - Performs Security Panel Quick commands - Disarm - - - - - configuring enabled feature for each partition-master user - - - - - Stores MobileDeviceToken ID for a User - - - - - Update User's Push notification Subscription - - - - - Remove User's MobileDevice token id - - - - - Pause / Allow all notifications for logged in user - - - - - Get RSI camera wireless, Supervision and Low Battery status - - - - - Look in for RSI - - - - - Set RSI Camera Settings for RSI - - - - - Get RSI Camera Settings for RSI - - - - - Get RSI Video URL Info for the device event - - - - - Return a list of WiFi locations and devices. - - - - - Add/Remoce WiFi Devices in Total Connect. - - - - - Save August Lock OAUTH Access Token in Total Connect. - - - - - Return a list of TCC WiFi locations and devices. - - - - - To Add/Delete the TCC WiFi Thermostats in Total Connect. - - - - - Return Configured TCC WiFi Thermostat Schedules. - - - - - Update the TCC WiFi Thermostat Schedules. - - - - - Success/Failure on Thermostat Access Token Generation - - - - - To Insert the Severe weather test message for the given locationID - - - - - Update a Switch Icon (database only) - - - - - Update a Thermostat schedule (database only) - - - - - Get a Thermostat schedule (from database) - - - - - Execute a single scene - - - - - Create or Edit a single scene - - - - - Delete a single scene - - - - - Get a specific scene per Automation panel (database) - - - - - Get list of scenes per Automation panel (database) - - - - - Get info for all Automation devices per Automation panel (during a panel session from panel, otherwise from database) - - - - - [Transitional State for lock] Get info for all Automation devices per Automation panel (during a panel session from panel, otherwise from database) - Includes HB Thermostat as well - - - - - [Transitional State for lock] Get info for all Automation devices per Automation panel (during a panel session from panel, otherwise from database) - - - - - Get Automation Lock Details. - - - - - Get Device status details will return Lock and security device status - - - - - Execute a action on a Automation panel lock - - - - - Execute a action on a Automation panel thermostat - - - - - Setting Schedule Status for thermostat - - - - - Execute a action on a Automation panel thermostat - - - - - Execute a single action on a Automation panel switch - - - - - Execute Security Panel and Automation Synchronization - - - - - Used to check the status of sync job - - - - - Close Current Security Panel Session - - - - - [Transitional State for lock] Get info for all Automation devices per Automation panel (during a panel session from panel, otherwise from database) - Includes HB Thermostat as well - - - - - [Transitional State for lock] Get info for all Automation devices per Automation panel (during a panel session from panel, otherwise from database) - - - - - Execute a action on a Automation panel thermostat - - - - - Execute Security Panel and Automation Synchronization - - - - - Execute a action on a Automation panel lock - - - - - Retrieve the configuration settings for all the Content - - - - - Save the configuration settings for all the Content - - - - - Retrieve the current weather condition - - - - - Retrieve the five days forecast weather condition - - - - - Retrieve the top 5 dealer messages - - - - - Mark a dealer message as Read - - - - - Retrieve the current weather condition - - - - - Retrieve the five days forecast weather condition - - - - - Used to validate an emailaddress in session - - - - - Used to validate an emailaddress from an external source from an email link - - - - - Used to validate an emailaddress from an external source from an email link - - - - - Used to send an validation link to the user - - - - - Used to send an validation link to the multiple users - - - - - Used to retieve the list of GPS devices associated with a location. - - - - - Used to retrieve the most recent recorded Location related data of the GPS device. - - - - - Used to retrieve the GeoFence information for a particular GPS device - - - - - Used to retrieve the the list of geofences that the GPS device currently is in. - - - - - this will cause the GPS device to return its current location to the database. Retrieval will be from a call to GetGPSDeviceLocationData. - - - - - Updates the Photo associated with a GPS Device and returns the PhotoURL for it. - - - - - Saves the Data for a GPSDevice Only. No Photo alteration will be done. - - - - - Request TWM Session - - - - - To add or Edit the Scenes - - - - - To Retrieve the Scenes information - - - - - To Remove a Scenes - - - - - To Execute the Scenes - - - - - To Get the Smart Action Configuration - - - - - To get the list of EULA's to be signed by the user. - - - - - To get the EULA Text for the given language id and eula id - - - - - To get the EULA Text for the given language id and eula id - - - - - To get the list of All EULA's befor login to be viewed by the user. - - - - - To get the EULA Text for the given language id and eula id - - - - - To update if the device is insecure - - - - - To add or Edit the Smart Action - - - - - To Retrieve the Smart Action information - - - - - - - Performs Security Panel Quick commands - Arm - - - - - Retrieves latest custom Arm settings set by the user - - - - - Performs Security Panel Quick commands - Disarm - - - - - Reads 16x2 Alpha Keypad Display and LED Status of Security System - - - - - Establishes Live Connection to Security System - - - - - Sends Keystroke to the Security Panel - - - - - Override Current User's Security Panel Session with his own Previous Session - - - - - Polling API - Which should be called based on Arm/Disarm API output Result Codes - - - - - Polling API - Which should be called based on Arm/Disarm API output Result Codes - - - - - Returns the current connection status of the security panel - - - - - Refresh or Insert a Command for a Security Panel - - - - - [Partially depreciated in TC2.3+, stuill used for Notifications groups] Get Users that you can Manage - - - - - [Depreciated in TC2.3+] Delete a user - - - - - [Depreciated in TC2.3+] Disable / Enable a user - - - - - Update Eula or SMS Eula for a User - - - - - [Depreciated in TC2.3+] Get User information when editing another user or editing yourself - - - - - [TC2.1+] Replacement for DeleteUserInfo. Deletes a Real User or Marks Virtual user for Deletion - - - - - [TC2.1+] Replacement for DisableEnableUser. Disable / Enable a user - - - - - Deprecated in TC Multilingual - [TC2.1+] Replacement for GetUserInfo. Get User information when editing another user or editing yourself - - - - - [TC2.1+] Replacement for GetUserDetails. Get User information when editing another user or editing yourself-Includes Wifi Lock as well - - - - - [TC3.24 +] Replacement for GetAllUserDetailsEx. It will return user partition related informations - - - - - [TC2.1+] Replacement for GetUserDetails. Get User information when editing another user or editing yourself - - - - - Used to update the usercode after login, so sessionid, oldUsercode, NewUserCode, UserId, LocationID is must - - - - - [TC3.8+] Created for Save MasterUsercode in TC if MasterUsercode changed in the panel. - - - - - [TC2.1+] Replacement for GetUsers. Returns List of Real Users that one can manage if asked at AccountLevel. This also returns Real+Virtual Users if asked at Location Level. - - - - - [TC2.1+] Provides list of SMS Email Carriers - - - - - [TC2.2+] Provides list of Notification Methods - - - - - Save User-Client Preferences - - - - - Get listing of Help Documents URLs - - - - - Used to update only the Language (LocaleId value) for a User. Country Code (ex. en-US) or a language Id as defined within TC2 can be used to update the value in the User Table. - - - - - Used to update the user password after login, so sessioid, OldPassword and NewPassword is must - - - - - [TC3.12+] Used to get feedback from users - - - - - [TC3.12+] Used to get feedback from users along with EmailID and rating - - - - - Validate user code - - - - - Used to update the user password after login, so sessioid, userName and NewPassword is must - - - - - Remote Request for authentication for the given username/password using the specified client application. - - - - - MAC validation request for the given GUID for Mobile Punch thru access - - - - - Request for authentication for the given username/password using the specified client application. - - - - - Request for authentication for the given username/password using the specified client application. - - - - - Request for authentication for the given GUID using the specified client application. - - - - - Request for authentication for the given GUID using the specified client application. - - - - - Request session details for the given sessionID - - - - - Request for authentication for the given username/password using the specified client application and retrieves the session details on successful authentication - - - - - Request for authentication for the given GUID using the specified client application. - - - - - Request for authentication for the given username/password using the specified client application and retrieves the session details on successful authentication - - - - - Authentication for the given username and password using the specified client application and retrieves the session details on successful authentication - - - - - Request for authentication for the given encrypted username/password using the specified client application and retrieves the session details on successful authentication - - - - - Inquire about an active session for the purpose of avoiding a server-side timeout. - - - - - Request that the given sessionID be logged out and/or terminated. - - - - - [DEPRECIATED] Request InterfaceSchema details for the given sessionID/username - - - - - Request InterfaceSchema details for the given sessionID/username - - - - - Request InterfaceSchema details for the given sessionID/username - - - - - Request for Static Key information for Clients - - - - - To Remove a single Smart Action - - - - - To Set the Smart Action state - - - - - To Execute the Smart Action - - - - - To Get the Smart Action Configuration - - - - - Retrieve the current configuration information for the given Video PIR. - - - - - Retrieve the list of Video PIR for the specified session and location. - - - - - Get the capturetypes for VideoPIR device - - - - - Update the configuration information for the given VideoPIR. - - - - - Returns the Video PIR event record based on Event TypeID - - - - - Trigger the Peek In Now Action for VideoPIR. - - - - - Get VideoPIR device events with applied filter condition - - - - - Return a list of WiFi locations and devices. - - - - - Turn On/Off WiFi Smart Away - - - - - Remove WiFi Device from Total Connect - - - - - This will return the weather forecast for the device location. - - - - - This will return the results for one thermostat. - - - - - Return a list of Lyric locations and devices. - - - - - Used to Save an image to an object PhotoClassId:1- location, 2 - User image - - - - - Used to Retrieve a Branding Image LOGO - - - - - Returns the data associated with a Location object from the database - - - - - Returns the data associated with the basic attributes of a Location object from the database - - - - - Retrieve the list of supported countries - - - - - Retrieve the list of states for a country - - - - - Retrieves the list of countries & States - - - - - Returns the Partners associated with a Location object from the database - - - - - Multiple Skybell Returns the Partners associated with a Location object from the database - - - - - Subscribe and Unsubscribe Lyric Account - - - - - Returns the Dealer Information - - - - - Returns the Subscriber Information - - - - - Returns the set of available triggerTime zone regions and their ID - - - - - Returns the set of available triggerTime zone regions and their ID for Camera - - - - - Provides version information for the web service. - - - - - Retrieves the set of video file URLs for a device or audit event record - - - - - Retrieves the set of video file URLs for a device or audit event record - - - - - Returns the notes associated with a device or audit event record - - - - - Returns a set of device or audit event records. A maximum of 100 records can be returned per call. - - - - - Returns a set of device or audit event records. A maximum of 100 records can be returned per call. - - - - - Returns doorbell event records. A maximum of 100 records can be returned per call. - - - - - Returns a list of available event type filter values that are to be used for filtering the event record retrieval. - - - - - Returns a list of available event type filter values that are to be used for filtering the event record retrieval. - - - - - Returns a set of device event records. A maximum of 250 records can be returned per call. The parameter LastEventIdReceived is used to retreive newer records than the ones previously obtained. Entering the most recent event id into this field will return all records that are newer than that record - - - - - Returns a set of device event records. A maximum of 250 records can be returned per call. The parameter LastEventIdReceived is used to retreive newer records than the ones previously obtained. Entering the most recent event id into this field will return all records that are newer than that record - - - - - Returns a set of doorbell event records. A maximum of 250 records can be returned per call. The parameter LastEventIdReceived is used to retreive newer records than the ones previously obtained. Entering the most recent event id into this field will return all records that are newer than that record - - - - - Updates the note associated with a device or audit event. Storing an empty string will clear a note. - - - - - Updates the hidden state of a device or audit event record. Hidden records are not returned during normal GetEvents requests unlessthe ShowHidden parameter is true. - - - - - Updates the lock state of a device or audit event record. When a record is locked, the automated clean up process will retain the locked record. Only unlocked records will be removed. - - - - - Updates the lock state of a device or audit event record. When a record is locked, the automated clean up process will retain the locked record. Only unlocked records will be removed. - - - - - Determine if the camera is available for a stream at the moment. Current reasons for unavailability would be if the camera is updating - - - - - Retrieve the current state (flags, pan/tilt location, WLLED, output state) for the given camera. - - - - - Retrieve the current I/O state (flags, WLLED, output state) for the given camera. - - - - - Retrieve the current pan/tilt location for the given camera. - - - - - Request that the given camera move to the given preset pan/tilt location. - - - - - Request that the current pan/tilt location be stored as the given preset slot for the given camera. - - - - - Request that the given camera move in the specified direction, speed and distance. - - - - - Request that the given camera move to the specified location, based on a 640x480 viewport mapping. - - - - - Request that the WLLED for the given camera be turned on/off. - - - - - Request that the output control for the given camera be turned on/off. - - - - - Request the given camera to archive a video clip to the server. - - - - - Configure the given camera to use the specified video mode. - - - - - Retrieve the list of cameras for the specified session and location. - - - - - Retrieve the list of All cameras for the specified session and location. - - - - - Retrieve the list of All cameras and Multiple Skybell for the specified session and location. - - - - - Retrieve the current configuration information for the given camera. - - - - - Retrieve the current configuration information for the given camera. - - - - - Retrieve the current configuration information (including limits) for the given camera. - - - - - Update the configuration information for the given camera. - - - - - Adjust default camera settings - - - - - Request that the camera firmware be upgraded/changed to the specified version (or default, if unspecified) - - - - - Request a list of available camera firmware upgrade options for the given camera. - - - - - Get camera wireless status - - - - - Get camera Information - provides camera wireless details and Network data - - - - - Gets WAP clients status - - - - - Gets Camera Battery Status - - - - - Get the Event Metadata applicable for the Given Location. Used for Notification Configuration - - - - - Get the Event Metadata applicable for the Given Location. Used for Notification Configuration - - - - - Get the Event Metadata applicable for the Given Location based on Partitions. Used for Notification Configuration - - - - - Get Configured Notification Events at the Given Location. - - - - - Get Configured Notification Events at the Given Location.Added notification flags for each module - - - - - Get Summary of Configured Notification Events in XML at the Given Location. - - - - - Get Summary of Configured Notification Events at the Given Location. - - - - - Get the list of notification states permitted for this location. - - - - - Get the list of notification schedules available. - - - - - Retrieves the Notification Lists associated with current user's TotalConnect account) - - - - - Sends Summary Email about the Notification List to the Admin user - - - - - Enable/disabled notifications for logged in user and/or return notification pause status. - - - - - Get the list of notification states permitted for this location. - - - - - [DEPRECATED] Get the Event Metadata applicable for the Given Location. Used for Notification Configuration - - - - - Request for Metadata and Full status of Security Panel for the Given Location and User - - - - - Request for Metadata and Full status of Security Panel for the Given Location and User - - - - - Request for Metadata and Full status of Security Panel for the Given Location and User.Added CanBeBypassable flag to determine zone is bypassable or not - - - - - Request for Full status of Security Panel for the Given Location and User - - - - - Request for Full status of Security Panel for the Given DeviceID and User - - - - - Request for Full status of Security Panel for the Given Location and User - - - - - Request for Full status of Security Panel for the Given Location and User - - - - - Request for Full status of Security Panel for the Given DeviceID and User - - - - - Get the zones in different states like Alarms, Faults, Trouble, and Bypassed - - - - - [Enriched Method] Get the zones in different states like Alarms, Faults, Trouble, and Bypassed and whether it is Bypassable Zone or Not - - - - - Request for Metadata and Full status of Security Panel for the Given DeviceID and User - - - - - Request for Metadata and Full status of Security Panel for the Given DeviceID and User - - - - - Initiates Zone Bypass for multiple zones - - - - - Initiates Zone Bypass - - - - - Return a Device Invite Token for a Sky Bell User. - - - - - Return Device provisioning status for the given token. - - - - - Removes Doorbell from TC and Skybell - - - - - Removes Doorbell from TC and Skybell for Multiple Skybell per Location - - - - - Get WiFi Door Bell Details. - - - - - Get WiFi Door Bell Details for Multiple Skybell per location. - - - - - Get WiFi Door Bell Settings - - - - - Get all devices associated to Skybell Account. - - - - - Get Partner Video URL for the device event - - - - - Get DoorBell - Client ID - - - - - Get WiFi Door Bell Diagnostic Details. - - - - - Get WiFi Door Bell Diagnostic Details for Multiple Skybell per Location. - - - - - Get the maximum device count per location for all devices present in that location - - - - - Return Enrollment status for a Partner Camera - - - - - Delete Partner Camera - - - - - Return a Activation status for Lyric Camera. - - - - - Return a Activation status for Lyric Camera. - - - - - Return Access Token detail for App - - - - - Return Refresh Token detail for App - - - - - Return a Settings for Lyric Camera. - - - - - Remove Lyric Camera from the Location. - - - - - Return Live Stream detail for Partner Camera - - - - - Return Lyric Camera and RSI Camera status. - - - - - Return Live Stream detail for Partner Camera - - - - - Return clip Key detail for App - - - - - Return Live Snapshot detail for Partner Camera - - - - - Save the Settings for Lyric Camera. - - - - - Log Message to Kibana Server - - - - - Return Live Stream detail for Partner Camera - - - - - Save the Settings for VAV Camera. - - - - - Return List of Partitions Authority Level info. - - - - - [TC2.1+] R Get User information with Partition Authority - - - - - Stores MobileDeviceToken ID for a User - - - - - Update User's Push notification Subscription - - - - - Remove User's MobileDevice token id - - - - - Pause / Allow all notifications for logged in user - - - - - Get RSI camera wireless, Supervision and Low Battery status - - - - - Look in for RSI - - - - - Set RSI Camera Settings for RSI - - - - - Get RSI Camera Settings for RSI - - - - - Get RSI Video URL Info for the device event - - - - - Return a list of WiFi locations and devices. - - - - - Save August Lock OAUTH Access Token in Total Connect. - - - - - Return a list of TCC WiFi locations and devices. - - - - - Return Configured TCC WiFi Thermostat Schedules. - - - - - Success/Failure on Thermostat Access Token Generation - - - - - To Insert the Severe weather test message for the given locationID - - - - - Update a Switch Icon (database only) - - - - - Get a Thermostat schedule (from database) - - - - - Execute a single scene - - - - - Delete a single scene - - - - - Get a specific scene per Automation panel (database) - - - - - Get list of scenes per Automation panel (database) - - - - - Get info for all Automation devices per Automation panel (during a panel session from panel, otherwise from database) - - - - - [Transitional State for lock] Get info for all Automation devices per Automation panel (during a panel session from panel, otherwise from database) - Includes HB Thermostat as well - - - - - [Transitional State for lock] Get info for all Automation devices per Automation panel (during a panel session from panel, otherwise from database) - - - - - Get Automation Lock Details. - - - - - Execute a action on a Automation panel lock - - - - - Execute a action on a Automation panel thermostat - - - - - Setting Schedule Status for thermostat - - - - - Execute a action on a Automation panel thermostat - - - - - Execute a single action on a Automation panel switch - - - - - Execute Security Panel and Automation Synchronization - - - - - Used to check the status of sync job - - - - - Close Current Security Panel Session - - - - - [Transitional State for lock] Get info for all Automation devices per Automation panel (during a panel session from panel, otherwise from database) - Includes HB Thermostat as well - - - - - [Transitional State for lock] Get info for all Automation devices per Automation panel (during a panel session from panel, otherwise from database) - - - - - Retrieve the configuration settings for all the Content - - - - - Retrieve the current weather condition - - - - - Retrieve the five days forecast weather condition - - - - - Retrieve the top 5 dealer messages - - - - - Mark a dealer message as Read - - - - - Retrieve the current weather condition - - - - - Retrieve the five days forecast weather condition - - - - - Used to validate an emailaddress in session - - - - - Used to validate an emailaddress from an external source from an email link - - - - - Used to validate an emailaddress from an external source from an email link - - - - - Used to send an validation link to the user - - - - - Used to send an validation link to the multiple users - - - - - Used to retieve the list of GPS devices associated with a location. - - - - - Used to retrieve the most recent recorded Location related data of the GPS device. - - - - - Used to retrieve the GeoFence information for a particular GPS device - - - - - Used to retrieve the the list of geofences that the GPS device currently is in. - - - - - this will cause the GPS device to return its current location to the database. Retrieval will be from a call to GetGPSDeviceLocationData. - - - - - Updates the Photo associated with a GPS Device and returns the PhotoURL for it. - - - - - Request TWM Session - - - - - To Remove a Scenes - - - - - To Execute the Scenes - - - - - To Get the Smart Action Configuration - - - - - To get the list of EULA's to be signed by the user. - - - - - To get the EULA Text for the given language id and eula id - - - - - To get the EULA Text for the given language id and eula id - - - - - To get the list of All EULA's befor login to be viewed by the user. - - - - - To get the EULA Text for the given language id and eula id - - - - - To update if the device is insecure - - - - - - - Performs Security Panel Quick commands - Arm - - - - - Retrieves latest custom Arm settings set by the user - - - - - Performs Security Panel Quick commands - Disarm - - - - - Reads 16x2 Alpha Keypad Display and LED Status of Security System - - - - - Establishes Live Connection to Security System - - - - - Sends Keystroke to the Security Panel - - - - - Override Current User's Security Panel Session with his own Previous Session - - - - - Polling API - Which should be called based on Arm/Disarm API output Result Codes - - - - - Polling API - Which should be called based on Arm/Disarm API output Result Codes - - - - - Returns the current connection status of the security panel - - - - - Refresh or Insert a Command for a Security Panel - - - - - [Partially depreciated in TC2.3+, stuill used for Notifications groups] Get Users that you can Manage - - - - - [Depreciated in TC2.3+] Delete a user - - - - - [Depreciated in TC2.3+] Disable / Enable a user - - - - - Update Eula or SMS Eula for a User - - - - - [Depreciated in TC2.3+] Get User information when editing another user or editing yourself - - - - - [TC2.1+] Replacement for DeleteUserInfo. Deletes a Real User or Marks Virtual user for Deletion - - - - - [TC2.1+] Replacement for DisableEnableUser. Disable / Enable a user - - - - - Deprecated in TC Multilingual - [TC2.1+] Replacement for GetUserInfo. Get User information when editing another user or editing yourself - - - - - [TC2.1+] Replacement for GetUserDetails. Get User information when editing another user or editing yourself-Includes Wifi Lock as well - - - - - [TC3.24 +] Replacement for GetAllUserDetailsEx. It will return user partition related informations - - - - - [TC2.1+] Replacement for GetUserDetails. Get User information when editing another user or editing yourself - - - - - Used to update the usercode after login, so sessionid, oldUsercode, NewUserCode, UserId, LocationID is must - - - - - [TC3.8+] Created for Save MasterUsercode in TC if MasterUsercode changed in the panel. - - - - - [TC2.1+] Replacement for GetUsers. Returns List of Real Users that one can manage if asked at AccountLevel. This also returns Real+Virtual Users if asked at Location Level. - - - - - [TC2.1+] Provides list of SMS Email Carriers - - - - - [TC2.2+] Provides list of Notification Methods - - - - - Save User-Client Preferences - - - - - Get listing of Help Documents URLs - - - - - Used to update only the Language (LocaleId value) for a User. Country Code (ex. en-US) or a language Id as defined within TC2 can be used to update the value in the User Table. - - - - - Used to update the user password after login, so sessioid, OldPassword and NewPassword is must - - - - - [TC3.12+] Used to get feedback from users - - - - - [TC3.12+] Used to get feedback from users along with EmailID and rating - - - - - Validate user code - - - - - Used to update the user password after login, so sessioid, userName and NewPassword is must - - - - - Remote Request for authentication for the given username/password using the specified client application. - - - - - MAC validation request for the given GUID for Mobile Punch thru access - - - - - Request for authentication for the given username/password using the specified client application. - - - - - Request for authentication for the given username/password using the specified client application. - - - - - Request for authentication for the given GUID using the specified client application. - - - - - Request for authentication for the given GUID using the specified client application. - - - - - Request session details for the given sessionID - - - - - Request for authentication for the given username/password using the specified client application and retrieves the session details on successful authentication - - - - - Request for authentication for the given GUID using the specified client application. - - - - - Request for authentication for the given username/password using the specified client application and retrieves the session details on successful authentication - - - - - Authentication for the given username and password using the specified client application and retrieves the session details on successful authentication - - - - - Request for authentication for the given encrypted username/password using the specified client application and retrieves the session details on successful authentication - - - - - Inquire about an active session for the purpose of avoiding a server-side timeout. - - - - - Request that the given sessionID be logged out and/or terminated. - - - - - [DEPRECIATED] Request InterfaceSchema details for the given sessionID/username - - - - - Request InterfaceSchema details for the given sessionID/username - - - - - Request InterfaceSchema details for the given sessionID/username - - - - - Request for Static Key information for Clients - - - - - To Remove a single Smart Action - - - - - To Set the Smart Action state - - - - - To Execute the Smart Action - - - - - To Get the Smart Action Configuration - - - - - Retrieve the current configuration information for the given Video PIR. - - - - - Retrieve the list of Video PIR for the specified session and location. - - - - - Get the capturetypes for VideoPIR device - - - - - Update the configuration information for the given VideoPIR. - - - - - Returns the Video PIR event record based on Event TypeID - - - - - Trigger the Peek In Now Action for VideoPIR. - - - - - Get VideoPIR device events with applied filter condition - - - - - Return a list of WiFi locations and devices. - - - - - Turn On/Off WiFi Smart Away - - - - - Remove WiFi Device from Total Connect - - - - - This will return the weather forecast for the device location. - - - - - This will return the results for one thermostat. - - - - - Return a list of Lyric locations and devices. - - - - - Used to Save an image to an object PhotoClassId:1- location, 2 - User image - - - - - Used to Retrieve a Branding Image LOGO - - - - - Returns the data associated with a Location object from the database - - - - - Returns the data associated with the basic attributes of a Location object from the database - - - - - Retrieve the list of supported countries - - - - - Retrieve the list of states for a country - - - - - Retrieves the list of countries & States - - - - - Returns the Partners associated with a Location object from the database - - - - - Multiple Skybell Returns the Partners associated with a Location object from the database - - - - - Subscribe and Unsubscribe Lyric Account - - - - - Returns the Dealer Information - - - - - Returns the Subscriber Information - - - - - Returns the set of available triggerTime zone regions and their ID - - - - - Returns the set of available triggerTime zone regions and their ID for Camera - - - - - Provides version information for the web service. - - - - - Retrieves the set of video file URLs for a device or audit event record - - - - - Retrieves the set of video file URLs for a device or audit event record - - - - - Returns the notes associated with a device or audit event record - - - - - Returns a set of device or audit event records. A maximum of 100 records can be returned per call. - - - - - Returns a set of device or audit event records. A maximum of 100 records can be returned per call. - - - - - Returns doorbell event records. A maximum of 100 records can be returned per call. - - - - - Returns a list of available event type filter values that are to be used for filtering the event record retrieval. - - - - - Returns a list of available event type filter values that are to be used for filtering the event record retrieval. - - - - - Returns a set of device event records. A maximum of 250 records can be returned per call. The parameter LastEventIdReceived is used to retreive newer records than the ones previously obtained. Entering the most recent event id into this field will return all records that are newer than that record - - - - - Returns a set of device event records. A maximum of 250 records can be returned per call. The parameter LastEventIdReceived is used to retreive newer records than the ones previously obtained. Entering the most recent event id into this field will return all records that are newer than that record - - - - - Returns a set of doorbell event records. A maximum of 250 records can be returned per call. The parameter LastEventIdReceived is used to retreive newer records than the ones previously obtained. Entering the most recent event id into this field will return all records that are newer than that record - - - - - Updates the note associated with a device or audit event. Storing an empty string will clear a note. - - - - - Updates the hidden state of a device or audit event record. Hidden records are not returned during normal GetEvents requests unlessthe ShowHidden parameter is true. - - - - - Updates the lock state of a device or audit event record. When a record is locked, the automated clean up process will retain the locked record. Only unlocked records will be removed. - - - - - Updates the lock state of a device or audit event record. When a record is locked, the automated clean up process will retain the locked record. Only unlocked records will be removed. - - - - - Determine if the camera is available for a stream at the moment. Current reasons for unavailability would be if the camera is updating - - - - - Retrieve the current state (flags, pan/tilt location, WLLED, output state) for the given camera. - - - - - Retrieve the current I/O state (flags, WLLED, output state) for the given camera. - - - - - Retrieve the current pan/tilt location for the given camera. - - - - - Request that the given camera move to the given preset pan/tilt location. - - - - - Request that the current pan/tilt location be stored as the given preset slot for the given camera. - - - - - Request that the given camera move in the specified direction, speed and distance. - - - - - Request that the given camera move to the specified location, based on a 640x480 viewport mapping. - - - - - Request that the WLLED for the given camera be turned on/off. - - - - - Request that the output control for the given camera be turned on/off. - - - - - Request the given camera to archive a video clip to the server. - - - - - Configure the given camera to use the specified video mode. - - - - - Retrieve the list of cameras for the specified session and location. - - - - - Retrieve the list of All cameras for the specified session and location. - - - - - Retrieve the list of All cameras and Multiple Skybell for the specified session and location. - - - - - Retrieve the current configuration information for the given camera. - - - - - Retrieve the current configuration information for the given camera. - - - - - Retrieve the current configuration information (including limits) for the given camera. - - - - - Update the configuration information for the given camera. - - - - - Adjust default camera settings - - - - - Request that the camera firmware be upgraded/changed to the specified version (or default, if unspecified) - - - - - Request a list of available camera firmware upgrade options for the given camera. - - - - - Get camera wireless status - - - - - Get camera Information - provides camera wireless details and Network data - - - - - Gets WAP clients status - - - - - Gets Camera Battery Status - - - - - Get the Event Metadata applicable for the Given Location. Used for Notification Configuration - - - - - Get the Event Metadata applicable for the Given Location. Used for Notification Configuration - - - - - Get the Event Metadata applicable for the Given Location based on Partitions. Used for Notification Configuration - - - - - Get Configured Notification Events at the Given Location. - - - - - Get Configured Notification Events at the Given Location.Added notification flags for each module - - - - - Get Summary of Configured Notification Events in XML at the Given Location. - - - - - Get Summary of Configured Notification Events at the Given Location. - - - - - Get the list of notification states permitted for this location. - - - - - Get the list of notification schedules available. - - - - - Retrieves the Notification Lists associated with current user's TotalConnect account) - - - - - Sends Summary Email about the Notification List to the Admin user - - - - - Enable/disabled notifications for logged in user and/or return notification pause status. - - - - - Get the list of notification states permitted for this location. - - - - - [DEPRECATED] Get the Event Metadata applicable for the Given Location. Used for Notification Configuration - - - - - Request for Metadata and Full status of Security Panel for the Given Location and User - - - - - Request for Metadata and Full status of Security Panel for the Given Location and User - - - - - Request for Metadata and Full status of Security Panel for the Given Location and User.Added CanBeBypassable flag to determine zone is bypassable or not - - - - - Request for Full status of Security Panel for the Given Location and User - - - - - Request for Full status of Security Panel for the Given DeviceID and User - - - - - Request for Full status of Security Panel for the Given Location and User - - - - - Request for Full status of Security Panel for the Given Location and User - - - - - Request for Full status of Security Panel for the Given DeviceID and User - - - - - Get the zones in different states like Alarms, Faults, Trouble, and Bypassed - - - - - [Enriched Method] Get the zones in different states like Alarms, Faults, Trouble, and Bypassed and whether it is Bypassable Zone or Not - - - - - Request for Metadata and Full status of Security Panel for the Given DeviceID and User - - - - - Request for Metadata and Full status of Security Panel for the Given DeviceID and User - - - - - Initiates Zone Bypass for multiple zones - - - - - Initiates Zone Bypass - - - - - Return a Device Invite Token for a Sky Bell User. - - - - - Return Device provisioning status for the given token. - - - - - Removes Doorbell from TC and Skybell - - - - - Removes Doorbell from TC and Skybell for Multiple Skybell per Location - - - - - Get WiFi Door Bell Details. - - - - - Get WiFi Door Bell Details for Multiple Skybell per location. - - - - - Get WiFi Door Bell Settings - - - - - Get all devices associated to Skybell Account. - - - - - Get Partner Video URL for the device event - - - - - Get DoorBell - Client ID - - - - - Get WiFi Door Bell Diagnostic Details. - - - - - Get WiFi Door Bell Diagnostic Details for Multiple Skybell per Location. - - - - - Get the maximum device count per location for all devices present in that location - - - - - Return Enrollment status for a Partner Camera - - - - - Delete Partner Camera - - - - - Return a Activation status for Lyric Camera. - - - - - Return a Activation status for Lyric Camera. - - - - - Return Access Token detail for App - - - - - Return Refresh Token detail for App - - - - - Return a Settings for Lyric Camera. - - - - - Remove Lyric Camera from the Location. - - - - - Return Live Stream detail for Partner Camera - - - - - Return Lyric Camera and RSI Camera status. - - - - - Return Live Stream detail for Partner Camera - - - - - Return clip Key detail for App - - - - - Return Live Snapshot detail for Partner Camera - - - - - Save the Settings for Lyric Camera. - - - - - Log Message to Kibana Server - - - - - Return Live Stream detail for Partner Camera - - - - - Save the Settings for VAV Camera. - - - - - Return List of Partitions Authority Level info. - - - - - [TC2.1+] R Get User information with Partition Authority - - - - - Stores MobileDeviceToken ID for a User - - - - - Update User's Push notification Subscription - - - - - Remove User's MobileDevice token id - - - - - Pause / Allow all notifications for logged in user - - - - - Get RSI camera wireless, Supervision and Low Battery status - - - - - Look in for RSI - - - - - Set RSI Camera Settings for RSI - - - - - Get RSI Camera Settings for RSI - - - - - Get RSI Video URL Info for the device event - - - - - Return a list of WiFi locations and devices. - - - - - Save August Lock OAUTH Access Token in Total Connect. - - - - - Return a list of TCC WiFi locations and devices. - - - - - Return Configured TCC WiFi Thermostat Schedules. - - - - - Success/Failure on Thermostat Access Token Generation - - - - - To Insert the Severe weather test message for the given locationID - - - - - Update a Switch Icon (database only) - - - - - Get a Thermostat schedule (from database) - - - - - Execute a single scene - - - - - Delete a single scene - - - - - Get a specific scene per Automation panel (database) - - - - - Get list of scenes per Automation panel (database) - - - - - Get info for all Automation devices per Automation panel (during a panel session from panel, otherwise from database) - - - - - [Transitional State for lock] Get info for all Automation devices per Automation panel (during a panel session from panel, otherwise from database) - Includes HB Thermostat as well - - - - - [Transitional State for lock] Get info for all Automation devices per Automation panel (during a panel session from panel, otherwise from database) - - - - - Get Automation Lock Details. - - - - - Execute a action on a Automation panel lock - - - - - Execute a action on a Automation panel thermostat - - - - - Setting Schedule Status for thermostat - - - - - Execute a action on a Automation panel thermostat - - - - - Execute a single action on a Automation panel switch - - - - - Execute Security Panel and Automation Synchronization - - - - - Used to check the status of sync job - - - - - Close Current Security Panel Session - - - - - [Transitional State for lock] Get info for all Automation devices per Automation panel (during a panel session from panel, otherwise from database) - Includes HB Thermostat as well - - - - - [Transitional State for lock] Get info for all Automation devices per Automation panel (during a panel session from panel, otherwise from database) - - - - - Retrieve the configuration settings for all the Content - - - - - Retrieve the current weather condition - - - - - Retrieve the five days forecast weather condition - - - - - Retrieve the top 5 dealer messages - - - - - Mark a dealer message as Read - - - - - Retrieve the current weather condition - - - - - Retrieve the five days forecast weather condition - - - - - Used to validate an emailaddress in session - - - - - Used to validate an emailaddress from an external source from an email link - - - - - Used to validate an emailaddress from an external source from an email link - - - - - Used to send an validation link to the user - - - - - Used to send an validation link to the multiple users - - - - - Used to retieve the list of GPS devices associated with a location. - - - - - Used to retrieve the most recent recorded Location related data of the GPS device. - - - - - Used to retrieve the GeoFence information for a particular GPS device - - - - - Used to retrieve the the list of geofences that the GPS device currently is in. - - - - - this will cause the GPS device to return its current location to the database. Retrieval will be from a call to GetGPSDeviceLocationData. - - - - - Updates the Photo associated with a GPS Device and returns the PhotoURL for it. - - - - - Request TWM Session - - - - - To Remove a Scenes - - - - - To Execute the Scenes - - - - - To Get the Smart Action Configuration - - - - - To get the list of EULA's to be signed by the user. - - - - - To get the EULA Text for the given language id and eula id - - - - - To get the EULA Text for the given language id and eula id - - - - - To get the list of All EULA's befor login to be viewed by the user. - - - - - To get the EULA Text for the given language id and eula id - - - - - To update if the device is insecure - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file