{"_id":"@denevads/smo_vanilla","_rev":"3-dc8093b59e3234e097a8136bd7278255","name":"@denevads/smo_vanilla","dist-tags":{"latest":"1.0.2"},"versions":{"1.0.0":{"name":"@denevads/smo_vanilla","version":"1.0.0","author":{"name":"Icon Multimedia S.L."},"license":"ISC","_id":"@denevads/smo_vanilla@1.0.0","maintainers":[{"name":"denevads","email":"iconmultimedialabs@gmail.com"}],"dist":{"shasum":"60911d010e8ee6c4c677bf758a6884de9f3e424f","tarball":"https://registry.npmjs.org/@denevads/smo_vanilla/-/smo_vanilla-1.0.0.tgz","fileCount":4,"integrity":"sha512-BRN0L0E2nlyyMKvUv/zJseGUmkcY2n+qHW03Gltc7otgKySBYPIjs+PkpQMThb07U8wOKmJ5VU9wlKz2e46VIg==","signatures":[{"sig":"MEYCIQCtwqM0WUId25urJpmPaTFBPW6xHXVGHQNr+ILFtbmOVgIhAP6399ov2UvH1L3yTQRwDGPWlyHKHsRqmQtbHzaUaWAT","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":15500},"main":"src/denevaSmo.js","gitHead":"a75b4663469a64b98ae54546ada5dc71fdfa7529","_npmUser":{"name":"denevads","email":"iconmultimedialabs@gmail.com"},"_npmVersion":"9.7.2","description":"Vanilla JavaScript library","directories":{},"_nodeVersion":"22.17.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/smo_vanilla_1.0.0_1753859818747_0.3350457434673946","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@denevads/smo_vanilla","version":"1.0.1","author":{"name":"Icon Multimedia S.L."},"license":"ISC","_id":"@denevads/smo_vanilla@1.0.1","maintainers":[{"name":"denevads","email":"iconmultimedialabs@gmail.com"}],"dist":{"shasum":"98a9fc7c05e1d061e24b0557fa23ebf1ec2673ce","tarball":"https://registry.npmjs.org/@denevads/smo_vanilla/-/smo_vanilla-1.0.1.tgz","fileCount":4,"integrity":"sha512-4hzkErKzGWkWCup0MpfFy/mW5BQRfRvNnMkG+3qrTqzubg92iuPm2edF7/6IqrXBPrZYp3g1gAi24U2DdwxNyQ==","signatures":[{"sig":"MEUCIF8wyYmKJ5nTjvTMkPL0bUjcWp3ktqq+FOSvZXDHwq8jAiEAr/CZLQyohrla35XdacYoxmYQkuaOlrVn1RV2GxofwVY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":14402},"main":"src/denevaSmo.js","gitHead":"a75b4663469a64b98ae54546ada5dc71fdfa7529","_npmUser":{"name":"denevads","email":"iconmultimedialabs@gmail.com"},"_npmVersion":"9.7.2","description":"Vanilla JavaScript library","directories":{},"_nodeVersion":"22.17.0","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/smo_vanilla_1.0.1_1753859890721_0.11552930613484835","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@denevads/smo_vanilla","version":"1.0.2","description":"Vanilla JavaScript library","main":"src/denevaSmo.js","author":{"name":"Icon Multimedia S.L."},"license":"ISC","_id":"@denevads/smo_vanilla@1.0.2","gitHead":"3853fb097d5da9a1fbf9ef71d7d93286f9dbcf39","_nodeVersion":"22.14.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-y+8VgldhRsSl2fjoQZwG40nRD34Fl3lvwVyeosZHLH9s7pReSc/Sp7n2NBef48a+3NN6Og+acHAoB2BUmyQNow==","shasum":"96008d9253b759c1fe6ccb1ae7f5d6d2fc7355d4","tarball":"https://registry.npmjs.org/@denevads/smo_vanilla/-/smo_vanilla-1.0.2.tgz","fileCount":4,"unpackedSize":37971,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBeJ5SfQK0Cxict0v2GK/B6L1O+HLb2/k3v8aIDdTWcQAiAl8nK5L0hfugSL8ZuIYof+XuEi3YN3WtcgBMOmBn5KWg=="}]},"_npmUser":{"name":"denevads","email":"iconmultimedialabs@gmail.com"},"directories":{},"maintainers":[{"name":"denevads","email":"iconmultimedialabs@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/smo_vanilla_1.0.2_1787124885714_0.806488767559473"},"_hasShrinkwrap":false}},"time":{"created":"2025-07-30T07:16:58.617Z","modified":"2026-08-19T07:34:46.000Z","1.0.0":"2025-07-30T07:16:58.917Z","1.0.1":"2025-07-30T07:18:10.910Z","1.0.2":"2026-08-19T07:34:45.834Z"},"author":{"name":"Icon Multimedia S.L."},"license":"ISC","description":"Vanilla JavaScript library","maintainers":[{"name":"denevads","email":"iconmultimedialabs@gmail.com"}],"readme":"# Librería SMO (vanilla JS) — Deneva SmartObjects\r\n\r\nDocumentación técnica de la librería de comunicación **SMO** en su versión **vanilla JavaScript** (sin frameworks), usada para desarrollar SmartObjects HTML5 para la plataforma de cartelería digital Deneva.\r\n\r\n> Existe una segunda generación de esta librería, empaquetada como paquete npm de Angular (`@denevads/dnv-smo`). Este documento cubre **exclusivamente la versión vanilla**, publicada en npm como [`@denevads/smo_vanilla`](https://www.npmjs.com/package/@denevads/smo_vanilla) (versiones `1.0.0` y `1.0.1`, código idéntico en ambas).\r\n>\r\n> **Este documento está verificado contra el código fuente real publicado en npm**, no solo contra manuales internos. La sección [Diferencias con documentación antigua](#diferencias-con-documentación-antigua) explica qué nombres han cambiado respecto a los manuales de 2016/2021.\r\n\r\n## Índice\r\n\r\n1. [¿Qué es un SmartObject?](#qué-es-un-smartobject)\r\n2. [Entorno de ejecución](#entorno-de-ejecución)\r\n3. [Instalación](#instalación)\r\n4. [Estructura de un proyecto SMO](#estructura-de-un-proyecto-smo)\r\n5. [Variables comunes (SMO.vars)](#variables-comunes-smovars)\r\n6. [ModoPresentacion](#modopresentacion)\r\n7. [RelojMaestro](#relojmaestro)\r\n8. [defaultVars() y logging](#defaultvars-y-logging)\r\n9. [API real: window.SMO (llamadas del player al SMO)](#api-real-windowsmo-llamadas-del-player-al-smo)\r\n10. [API real: window.Dnv.smoCallbacks (llamadas del SMO al player)](#api-real-windowdnvsmocallbacks-llamadas-del-smo-al-player)\r\n11. [Flujo de comunicación completo](#flujo-de-comunicación-completo)\r\n12. [Fuentes de datos (Datasources / RSS)](#fuentes-de-datos-datasources--rss)\r\n13. [⚠️ Bugs conocidos en el paquete publicado (v1.0.0 / v1.0.1)](#️-bugs-conocidos-en-el-paquete-publicado-v100--v101)\r\n14. [Diferencias con documentación antigua](#diferencias-con-documentación-antigua)\r\n15. [Compatibilidad y limitaciones](#compatibilidad-y-limitaciones)\r\n16. [Validación y despliegue](#validación-y-despliegue)\r\n17. [Fuentes de esta documentación](#fuentes-de-esta-documentación)\r\n\r\n## ¿Qué es un SmartObject?\r\n\r\nUn **SmartObject (SMO)** es un componente \"inteligente\" hecho con HTML5 + CSS3 + JavaScript que se ejecuta dentro de una plantilla de Deneva. Tiene dos responsabilidades:\r\n\r\n1. **Lee información**: accede a una URL que se le pasa, o a datos que el player le deja en una ruta local (normalmente un XML descargado en disco por el propio player).\r\n2. **Muestra información**: cada SMO tiene su propio diseño en pantalla y su propia lógica visual (no es lo mismo pintar un mapa de temperaturas que un ticker de redes sociales).\r\n\r\nLa idea general es siempre la misma: hay un XML (o JSON) de entrada en algún sitio, y el SMO lo interpreta para colocar textos/imágenes en pantalla, incluso actualizándolos en tiempo real.\r\n\r\n## Entorno de ejecución\r\n\r\nPara evitar que las funciones JavaScript de varios objetos colisionen entre sí cuando conviven en la misma plantilla, cada SMO se ejecuta dentro de su propio **`<iframe>`**. Si una plantilla tiene varios SMOs, se crea un iframe por cada uno.\r\n\r\nLa comunicación entre el SMO (dentro del iframe) y la página principal (el player, fuera del iframe) se realiza mediante **`window.postMessage`**, envuelta por la librería en dos objetos globales:\r\n\r\n- **`window.SMO`**: expone las funciones que el player invoca *sobre* el SMO (recibir datos, arrancar reproducción...) y guarda el estado del propio SMO (`SMO.vars`, `SMO.id`).\r\n- **`window.Dnv`**: expone las funciones que el SMO invoca *hacia* el player (`Dnv.smoCallbacks.*`), además de los enumerados de niveles de log y alarma.\r\n\r\n## Instalación\r\n\r\n```bash\r\nnpm i @denevads/smo_vanilla\r\n```\r\n\r\nEl `package.json` del paquete apunta como entry point a `src/denevaSmo.js`:\r\n\r\n```json\r\n{\r\n  \"name\": \"@denevads/smo_vanilla\",\r\n  \"version\": \"1.0.1\",\r\n  \"description\": \"Vanilla JavaScript library\",\r\n  \"main\": \"src/denevaSmo.js\",\r\n  \"author\": \"Icon Multimedia S.L.\",\r\n  \"license\": \"ISC\"\r\n}\r\n```\r\n\r\nAl cargar `denevaSmo.js`, la propia librería se auto-inicializa al final del fichero (`SMO.init(); Dnv.init();`): parsea los parámetros de la URL a `SMO.vars` y registra el listener `window.onmessage` que recibe las llamadas del player.\r\n\r\n## Estructura de un proyecto SMO\r\n\r\n```\r\nmi-smo/\r\n├── index.html\r\n├── css/\r\n│   └── estilos.css\r\n├── js/\r\n│   ├── lib/                  # Librería del paquete npm — NO SE MODIFICA\r\n│   │   ├── denevaSmo.js       # window.SMO + window.Dnv (comunicación vía postMessage)\r\n│   │   └── utils.js           # Logging (logDebug/logInfo/logWarning/logError) y parseo XML\r\n│   └── smo.js                 # Lógica específica de este SMO (aquí se desarrolla la funcionalidad)\r\n└── includes/                  # Opcional: fonts, imágenes, vídeos, XML de ejemplo...\r\n```\r\n\r\nEl paquete final se distribuye como un fichero `.wgt`: simplemente se comprime todo el proyecto en `.zip` y se renombra la extensión a `.wgt` para darlo de alta en Deneva.\r\n\r\n> Nota histórica: en manuales antiguos estos ficheros se llamaban `SMO_Common.js` y `smartobject.js`. En el paquete npm actual están unificados en `denevaSmo.js`.\r\n\r\n## Variables comunes (SMO.vars)\r\n\r\n`SMO.init()` parsea automáticamente todos los parámetros GET de la URL del iframe y los expone en **`SMO.vars`**. Si existe el parámetro `idSmo`, también se guarda en `SMO.id` (usado internamente en todos los mensajes salientes hacia el player). Si no llega `idSmo`, la librería avisa por consola: `[SMO] [No idSmo found in URL]`.\r\n\r\nVariables comunes a cualquier SMO:\r\n\r\n| Variable | Descripción |\r\n|---|---|\r\n| `url` | URL externa a la que debe conectarse el SMO para obtener su fuente RSS. |\r\n| `CurrentPlantilla` | Código de la plantilla que carga el SMO. |\r\n| `LocalData` | Directorio donde se guardan los datos locales. |\r\n| `RelojMaestro` | Ver sección [RelojMaestro](#relojmaestro). |\r\n| `Lang` | Nemónico del idioma (`ES`, `EN`, etc.). |\r\n| `locale` | Idioma y país con formato `language_territory@country`. |\r\n| `ModoPresentacion` | Ver sección [ModoPresentacion](#modopresentacion). |\r\n| `ancho` / `alto` | Dimensiones del iframe donde se pinta el SMO. |\r\n| `idSmo` | Identificador de comunicación del SMO con el elemento padre (se copia a `SMO.id`). |\r\n| `nombreSMO` | Convención interna (no forzada por la librería) para identificar el SMO en los logs — se usa dentro de `utils.js`. |\r\n| `DebugModeSMO` | Si vale `\"log\"`, las funciones de log también hacen `console.log`/`console.debug` en local, además de enviarlo al player en producción. |\r\n\r\nAdemás de estas, cada SMO puede definir sus propias variables/metadatos personalizados, que llegan igualmente como parámetros GET (por ejemplo `ColordeFondo`, `NumItems`, etc.):\r\n\r\n```\r\nindex.html?ColordeFondo=000000&ColorTexto=ffffff&NumItems=22\r\n```\r\n\r\n## ModoPresentacion\r\n\r\nIndica el entorno en el que se está ejecutando el SMO. Es fundamental tenerlo en cuenta para decidir qué datos mostrar (reales vs. datos de ejemplo/hardcodeados):\r\n\r\n| Valor | Entorno |\r\n|---|---|\r\n| `1` | **EditorForm**: capa dentro del editor de Deneva. |\r\n| `2` | **EditorPrevio**: previo de la plantilla dentro del editor (botón \"previo plantilla\"). |\r\n| `3` | **PrevioPlantilla**: previo de la plantilla desde la web de Deneva (se ejecuta en el navegador del usuario). |\r\n| `4` | **PrevioRecurso**: previo del recurso individual en la web (sin plantilla, sin metadatos ni fuente RSS reales). |\r\n| `5` | **SalidaPantalla**: producción, dentro del player real. **Único entorno con todos los datos disponibles.** También es el único valor en el que la librería envía logs al player (ver siguiente sección). |\r\n| `6` | **PrevioCanal**: previo de un canal completo desde la web. |\r\n\r\nBuena práctica: comprobar `ModoPresentacion != 5` para decidir cuándo usar datos de ejemplo en vez de esperar datos reales.\r\n\r\n## RelojMaestro\r\n\r\nVariable booleana (numérica) que indica el comportamiento de bucle del SMO:\r\n\r\n- `0`: el SMO, al terminar de reproducir su contenido, vuelve a empezar (bucle infinito).\r\n- `1`: al terminar, el SMO debe avisar a la salida llamando a `Dnv.smoCallbacks.urlNext()` (ver más abajo) para que esta pase al siguiente contenido programado.\r\n\r\n## defaultVars() y logging\r\n\r\n`defaultVars()` sigue siendo el patrón recomendado (no obligatorio en cuanto al nombre) para inicializar valores por defecto. Es imprescindible para poder previsualizar el SMO sin necesidad de embeberlo en una plantilla real:\r\n\r\n```js\r\nfunction defaultVars() {\r\n  SMO.vars['nombreSMO'] = 'SMO Base v01.00';\r\n  SMO.vars['BgColor'] = SMO.vars['BgColor'] || '#000000';\r\n  SMO.vars['FgColor'] = SMO.vars['FgColor'] || '#FFFFFF';\r\n  SMO.vars['RelojMaestro'] = SMO.vars['RelojMaestro'] || 0;\r\n  SMO.vars['ModoPresentacion'] = SMO.vars['ModoPresentacion'] || 4;\r\n}\r\n```\r\n\r\nEl paquete npm incluye en `utils.js` unas funciones de log ya hechas sobre `Dnv.LogLevel` (ver [siguiente sección](#api-real-windowdnvsmocallbacks-llamadas-del-smo-al-player)):\r\n\r\n```js\r\nfunction logDebug(texto)   { log(texto, Dnv.LogLevel.Debug) }\r\nfunction logInfo(texto)    { log(texto, Dnv.LogLevel.Info) }\r\nfunction logWarning(texto) { log(texto, Dnv.LogLevel.Warning) }\r\nfunction logError(texto)   { log(texto, Dnv.LogLevel.Error) }\r\nfunction log(texto, level) {\r\n  var strLog = '[' + SMO.vars.nombreSMO + ']' + texto;\r\n  if (SMO.vars.ModoPresentacion == \"5\") Dnv.smoCallbacks.smoLog(strLog, level);\r\n  if (SMO.vars.DebugModeSMO == \"log\") console.log(strLog);\r\n}\r\n```\r\n\r\n`utils.js` también captura errores no críticos con `window.onerror` (para que un fallo puntual no detenga todo el SMO) y expone `parseTexto(xml)` para parsear un string XML a `Document` (usa `DOMParser`, con fallback a `ActiveXObject` para IE muy antiguo) y `getDummyData()` para obtener un XML de ejemplo hardcodeado cuando no hay datos reales disponibles.\r\n\r\n## API real: window.SMO (llamadas del player al SMO)\r\n\r\nEstas funciones las invoca el **player** para comunicarse con el SMO (normalmente a través del mecanismo interno `Dnv.init()`, que escucha `window.onmessage` y llama a la función indicada en `target`, p.ej. `\"SMO.setDatasource\"`):\r\n\r\n| Método | Descripción |\r\n|---|---|\r\n| `SMO.init()` | Se ejecuta automáticamente al cargar la librería. Parsea los parámetros GET de la URL a `SMO.vars` y fija `SMO.id` desde `vars.idSmo`. |\r\n| `SMO.start()` | El player indica al SMO que puede empezar a reproducirse. Dispara internamente el evento `event_start` — suscríbete con `window.addEventListener('event_start', fn)`. |\r\n| `SMO.setDatasource(data)` | El player envía al SMO los datos que debe pintar (`data = { xml: strDataXML }`). Dispara `event_new_datasource` — suscríbete con `window.addEventListener('event_new_datasource', fn)`. |\r\n| `SMO.getVariable(data)` | Respuesta a una petición de variable (`data = { variable, valor }`). Dispara `event_get_variable`. |\r\n| `SMO.setCurrentStream(stream)` | Informa al SMO del stream actual. Dispara `event_current_stream`. |\r\n| `SMO.infoCurrentLocation(data)` | Informa posición/tamaño actual del SMO (`{ top, left, width, height }`). Dispara `event_info_current_location`. |\r\n| `SMO.setSalidaData(data)` | Respuesta a `getSalidaData` (`{ dataKey, data }`). Dispara `event_set_salida_data`. |\r\n| `SMO.updatefromsalida(data)` | Notificación recibida de un topic al que el SMO esté suscrito (ver `addObserver`/`notify`). Dispara `event_update_from_salida`. |\r\n| `SMO.startCheckDatasource()` | Programa una comprobación periódica de la fuente de datos (cada 10s tras un primer intento al segundo). |\r\n\r\nAdemás, hay un grupo de métodos orientados a gestión de recursos/almacenamiento (`getRecursosByCodigo`, `getRecursosByMetadato`, `getRecursosByMetadatos`, `getRecursos`, `getRecursosDefault`, `getRecursosRelleno`, `getVariableStorage`, `checkHealth`, `checkHealthPrinter`, `getValorCalendario`, `getLocalDatasource`) — **no documentados en ningún manual anterior** y, como se explica en [Bugs conocidos](#️-bugs-conocidos-en-el-paquete-publicado-v100--v101), actualmente rotos en el código publicado.\r\n\r\n## API real: window.Dnv.smoCallbacks (llamadas del SMO al player)\r\n\r\nEstas funciones las llama el **SMO** para comunicarse con el player. Internamente todas hacen `window.parent.postMessage({ target: \"Dnv.smoCallbacks.<nombre>\", objData: ..., idSmo: window.SMO.id }, \"*\")`.\r\n\r\n| Método | Descripción |\r\n|---|---|\r\n| `onSmoLoad()` | El SMO avisa al player que ha cargado y está listo para recibir datos. |\r\n| `onSmoReady()` | El SMO ha terminado de pintar sus datos iniciales y está listo para reproducirse. |\r\n| `smoLog(msn, level)` | Envía un mensaje de log al player. `level` es uno de `Dnv.LogLevel` (ver abajo). |\r\n| `smoAlarma(msn, level)` | Envía una alarma. `level` es uno de `Dnv.AlarmaLevel` (ver abajo). |\r\n| `reiniciarDispositivo(msn)` | Permite reiniciar el player indicando el motivo. **Solo Player HTML5.** |\r\n| `urlNext()` | Indica que el SMO ha terminado su reproducción (solo tiene efecto real si `RelojMaestro = 1`). |\r\n| `exitInteractivity()` | Sale del canal interactivo y vuelve al canal de reposo. **Solo Android y Player PC.** |\r\n| `showBrowser()` / `closeBrowser()` | **DEPRECATED, no implementadas** — solo hacen `console.warn`. |\r\n| `urlNextDirectamente()` | **No implementada** — solo hace `console.warn`. |\r\n| `setVariable(variable, valor)` | Pide al player que fije el valor de una variable. |\r\n| `getVariable(variable)` | Pide el valor de una variable (respuesta vía `SMO.getVariable`). |\r\n| `getFile(file)` | Solicita un fichero al player. |\r\n| `setLocalData(variable, valor)` | Guarda un dato local en el player. |\r\n| `getLocalData(variable)` | Pide un dato local guardado previamente. |\r\n| `getCurrentStream()` | Pide el stream actual (respuesta vía `SMO.setCurrentStream`). |\r\n| `finAviso(id)` | Notifica el fin de un aviso concreto. |\r\n| `refreshDatasource(codigo)` | Pide refrescar una fuente de datos concreta. |\r\n| `getLocation()` | Pide la ubicación/posición actual. |\r\n| `getSalidaData(data)` | Pide un dato concreto a la salida; el player hace un `switch` sobre el string recibido y devuelve el JSON correspondiente (respuesta vía `SMO.setSalidaData`). |\r\n| `ejecutaFuncion(data)` | Pide al player ejecutar una función (`{ funcion, params }`); solo implementada para un caso concreto. |\r\n| `addObserver(data)` | Suscribe al SMO a un `topic` para recibir notificaciones (respuesta vía `SMO.updatefromsalida`). |\r\n| `notify(data)` | Envía un mensaje a un topic (`{ destino, value }`); lo reciben los SMOs suscritos a través de `SMO.updatefromsalida`. |\r\n| `playOnceChannel(codigoCanal)` | Reproduce una vez el canal indicado; después el player vuelve al canal inicial. |\r\n| `stopPlayChannel()` | Fuerza la vuelta al canal inicial cuando se llamó a `playOnceChannel`. ⚠️ ver bug conocido. |\r\n| `playOnceChannelByTrigger(trigger)` | Reproduce una vez el canal que tenga ese trigger definido. |\r\n| `stopPlayOnceChannelByTrigger()` | Fuerza la vuelta al canal inicial cuando se llamó a `playOnceChannelByTrigger`. |\r\n\r\nEnumerados disponibles:\r\n\r\n```js\r\nDnv.LogLevel = {\r\n  Debug: 0,\r\n  Info: 1,\r\n  Warning: 2,\r\n  Error: 3,\r\n};\r\n\r\nDnv.AlarmaLevel = {\r\n  Ok_off: 0,\r\n  Ok: 1,\r\n  Scanning: 2,\r\n  Timeout: 3,\r\n  Warning: 4,\r\n  Error: 5,\r\n};\r\n```\r\n\r\nEjemplo real de lo que se envía \"por debajo\" al llamar a `smoLog`:\r\n\r\n```js\r\nwindow.parent.postMessage({\r\n  target: \"Dnv.smoCallbacks.smoLog\",\r\n  objData: { txt: \"mensaje de log\", level: Dnv.LogLevel.Info },\r\n  idSmo: window.SMO.id,\r\n}, \"*\");\r\n```\r\n\r\n## Flujo de comunicación completo\r\n\r\n1. La página principal (padre) carga el iframe del SMO, pasándole las variables comunes y las propias de configuración por la URL. Al cargar la librería, `SMO.init()` y `Dnv.init()` se ejecutan automáticamente.\r\n2. El SMO avisa al padre: `Dnv.smoCallbacks.onSmoLoad()`.\r\n3. El padre envía los datos: `SMO.setDatasource({ xml })` → dentro del SMO, esto dispara el evento `event_new_datasource`, al que el SMO debe estar suscrito con `window.addEventListener`.\r\n4. Una vez leída la fuente de datos, el SMO avisa que está listo: `Dnv.smoCallbacks.onSmoReady()`.\r\n5. El padre indica al SMO que puede empezar a reproducir: `SMO.start()` → dispara `event_start` dentro del SMO.\r\n6. Durante la reproducción, el SMO puede: pedir refrescar la fuente de datos (`refreshDatasource`), enviar logs (`smoLog`) o alarmas (`smoAlarma`), pedir/fijar variables (`getVariable`/`setVariable`), suscribirse a topics (`addObserver`) o notificar a otros SMOs (`notify`).\r\n7. El padre, a su vez, puede enviar nuevos valores de variables, actualizar la fuente de datos, o notificar por topic (`SMO.updatefromsalida`).\r\n8. Si `RelojMaestro = 1`, al terminar su contenido el SMO llama a `Dnv.smoCallbacks.urlNext()` para que el player avance al siguiente contenido.\r\n\r\n```\r\nPadre (player)                                    SMO (iframe)\r\n     |------------------ carga iframe -------------------->|\r\n     |<---------- Dnv.smoCallbacks.onSmoLoad() ------------|\r\n     |---- SMO.setDatasource({xml}) [event_new_datasource]>|\r\n     |<--------- Dnv.smoCallbacks.onSmoReady() -------------|\r\n     |------------ SMO.start() [event_start] -------------->|\r\n     |                                                       |  (reproducción en bucle)\r\n     |<---- smoLog() / smoAlarma() / getVariable() ---------|\r\n     |---- setVariable() / SMO.updatefromsalida() ---------->|\r\n     |<--------- Dnv.smoCallbacks.urlNext() -----------------|  (solo si RelojMaestro = 1)\r\n```\r\n\r\n## Fuentes de datos (Datasources / RSS)\r\n\r\nTambién llamadas \"fuentes de datos\", son ficheros XML con la información que necesita el SMO para funcionar. Pueden generarse manualmente o por el propio sistema.\r\n\r\nEstructura básica:\r\n\r\n```xml\r\n<datasource Id='17281' FiltroMetadato='' Cachear='0' Timestamp='2021-10-19 10:01:43'>\r\n  <key>\r\n    <item></item>\r\n  </key>\r\n</datasource>\r\n```\r\n\r\n- `FiltroMetadato`: el SMO no necesita leerlo; es la salida la que ya filtra los datos según este atributo.\r\n- `Cachear`: indica si las imágenes/vídeos se cargan desde local o desde la URL indicada en la fuente RSS.\r\n- `Timestamp`: hora de la última actualización de los datos.\r\n\r\n## ⚠️ Bugs conocidos en el paquete publicado (v1.0.0 / v1.0.1)\r\n\r\nVerificado leyendo directamente `src/denevaSmo.js` del tarball publicado en npm (el código es idéntico en ambas versiones):\r\n\r\n- **Variable `data` no declarada**: `getRecursosByCodigo`, `getRecursosByMetadato`, `getRecursosByMetadatos`, `getRecursos`, `getRecursosDefault`, `getRecursosRelleno`, `getVariableStorage`, `checkHealth`, `checkHealthPrinter`, `getValorCalendario` y `getLocalDatasource` no reciben `data` como parámetro de la función pero lo usan dentro (`new CustomEvent(..., data)`). Llamarlas lanza `ReferenceError: data is not defined`.\r\n- **Función inexistente**: `SMO.startCheckDatasource()` llama periódicamente a `SMO.getDatasource()`, que no está definida en ningún sitio del objeto `SMO`.\r\n- **Typo `parent` → `arent`**: `Dnv.smoCallbacks.finAviso(id)` escribe `arent.postMessage(...)` en vez de `parent.postMessage(...)`, lo que también lanza un `ReferenceError` al ejecutarse.\r\n- **Target mal escrito**: `Dnv.smoCallbacks.stopPlayChannel()` envía `target: \"Dnv.smoCallbacks.stopPlayOnceChannel\"` (con \"Once\") en lugar de `\"Dnv.smoCallbacks.stopPlayChannel\"`. El nombre de la función y el `target` del mensaje no coinciden.\r\n- **Comentario desalineado con el código**: el comentario sobre `SMO.setDatasource` sugiere suscribirse con `SMO.event_new_datasource`, pero esa propiedad no existe en el objeto; solo funciona usando el string literal `'event_new_datasource'` directamente en `addEventListener`.\r\n\r\nSi vas a apoyarte en alguna de estas funciones, conviene probarla primero o contactar con el equipo que mantiene el paquete antes de asumir que funciona igual que en la documentación.\r\n\r\n## Diferencias con documentación antigua\r\n\r\nLos manuales internos de 2016/2021 (`API Deneva SmartObjects HTML5`, `Externalización SMOS v1.4`) describen una API con otros nombres. Esta tabla resume qué ha cambiado respecto al código realmente publicado hoy en npm:\r\n\r\n| Documentación antigua (2016/2021) | Código real en npm (`smo_vanilla` v1.0.x) |\r\n|---|---|\r\n| `SmoEvent.raise(SmoEvent.ON_LOAD)` | `Dnv.smoCallbacks.onSmoLoad()` |\r\n| `SmoEvent.raise(SmoEvent.ON_READY)` | `Dnv.smoCallbacks.onSmoReady()` |\r\n| `SmoEvent.raise(SmoEvent.ON_NEXT)` | `Dnv.smoCallbacks.urlNext()` |\r\n| `log4ever(txt, LOG_LEVEL)` | `Dnv.smoCallbacks.smoLog(msn, level)` (con helpers `logDebug/logInfo/logWarning/logError` en `utils.js`) |\r\n| `LogUtils.LEVEL_DEBUG / INFO / WARN / ERROR / FATAL` | `Dnv.LogLevel.Debug / Info / Warning / Error` (namespace distinto y **ya no existe `FATAL`**) |\r\n| `SMO.setDatasource(xml)` recibía el XML directamente | `SMO.setDatasource(data)` dispara un `CustomEvent`; el SMO debe suscribirse con `addEventListener('event_new_datasource', ...)` en vez de recibir el XML como argumento de una función propia |\r\n| `events.updateFromSalida` (camelCase) | `SMO.updatefromsalida` (todo en minúsculas) |\r\n| `smoCallBacks.notify({ plantilla, destino, value })` | `Dnv.smoCallbacks.notify({ destino, value })` — ya no hace falta incluir `idSmo`/`plantilla` a mano, viaja siempre en el envoltorio del mensaje |\r\n| `SMO_Common.js` + `smartobject.js` | `denevaSmo.js` (unificado) |\r\n\r\nSe mantienen con el mismo nombre: `SMO.start()`, `exitInteractivity()`, `addObserver()`, `getVariable()`, `playOnceChannel()`, `playOnceChannelByTrigger()`, `stopPlayOnceChannelByTrigger()`.\r\n\r\nSon completamente nuevos (no aparecían en ninguna documentación anterior): `SMO.getVariable`, `setCurrentStream`, `infoCurrentLocation`, `setSalidaData`, toda la familia `getRecursos*`, `getVariableStorage`, `checkHealth*`, `getValorCalendario`, `getLocalDatasource`, `startCheckDatasource`; y en `Dnv.smoCallbacks`: `smoAlarma`, `reiniciarDispositivo`, `setVariable`, `getFile`, `setLocalData`, `getLocalData`, `getCurrentStream`, `finAviso`, `refreshDatasource`, `getLocation`, `getSalidaData`, `ejecutaFuncion`; además del enumerado `Dnv.AlarmaLevel`.\r\n\r\n## Compatibilidad y limitaciones\r\n\r\n- **JavaScript**: se recomienda encarecidamente **ECMAScript 5**, ya que las limitaciones técnicas de los SMO equivalen a las de Internet Explorer 11 en cuanto a CSS y JS.\r\n- **Navegadores mínimos soportados**: IE11/Edge y Chrome en sus versiones estándar; en sistemas embebidos hay más restricciones (Android 4.4+, LG WebOS 2 / Safari 6-6.1, Samsung SSSP / Safari 7.1-8).\r\n- **Sin conexión constante**: evitar dependencias externas (CDNs, tipografías remotas, etc.) salvo que sea imprescindible (p. ej. la propia fuente RSS), ya que los players pueden ejecutarse sin conexión continua a internet. Cualquier recurso externo necesario debe empaquetarse dentro del proyecto.\r\n- **Aislamiento por iframe**: obligatorio para evitar colisiones de JS entre SMOs que convivan en la misma plantilla.\r\n\r\n## Validación y despliegue\r\n\r\n1. Desarrollar y probar el SMO localmente usando `defaultVars()` para simular metadatos.\r\n2. Empaquetar el proyecto como `.wgt` (zip renombrado).\r\n3. Enviarlo a ICON Multimedia para darlo de alta como SmartObject en la base de datos.\r\n4. Validar en los entornos de producción reales:\r\n   - Player Deneva PC\r\n   - Player Deneva Android\r\n   - Player Deneva SmartTV (LG WebOS, Samsung SSSP, Toshiba)\r\n","readmeFilename":"README.md"}