Wiki »
Provisioning 2.0¶
Провижионинг состоит из набора процедур и конфигурационного файла json.
Расположение конфигурационного файла по-умолчанию находится по адресу - http://wrtech.local/update/WR-330/config.json
- Набор процедур:
- обновление прошивки или bootstrap - wrtImageUpdate()
- обновление logo, отображаемое при запуске приставки - wrtLogoUpdate()
- обновление приложений (services), находящихся в внутреннем портале - wrtServiceListUpdate()
Три способа реализации provisioning'а:¶
Files:
autoconfig_1_json_in_sync.js
autoconfig_2_json_out_async.js - является также и 3 вариантом, различие в расположении js файла.
config.json
- 1 Сценарий provisioning'а и конфигурационный файл расположены на странице самого портала или странице "предзагрузки" (адрес портала по-умолчанию http://wrtech.local).
js script и json config на портале.
function wrtImageUpdate(args) { console.log("trying update from: " + args.url); if (location.search.indexOf("skipupdate") == -1) { //если портал не был открыт с опцией пропуска обновления, обновление прошивки stbUpdate.startCheck(args.url); if (stbUpdate.getStatus() == 21) { // файл прошивки доступен и заголовок прочитан console.log("image is available, header parsed"); if(typeof(args.imageDate) !== "number") { args.imageDate = Date.parse(stbUpdate.getImageDateStr()); console.log("got date from image: " + args.imageDate); } if (args.curDate < args.imageDate) { //файл на сервере новее, чем текущая прошивка или безусловно console.log("got new update"); WRT.UpdateGui( //запуск обновления args.url, //файл прошивки location.origin + location.pathname + (location.search ? location.search + "&" : "?") + "skipupdate", //адрес для возврата в случае отмены или ошибки скачивания (текущий + skipupdate) args.forced //true - принудительно запустить обновление, false - предварительно спросить ); return true; } else { console.log("already updated"); } } } else { console.log("update is skiped"); } return false; } function wrtEnvsUpdate(envs) { for(key in envs) { if (typeof(envs[key]) === 'string') { console.log("key: " + key + "; old: " + WRT.getEnv(key) + " new: " + envs[key]); if(WRT.getEnv(key) !== envs[key]) { WRT.setEnv(key, envs[key]); } } } } function wrtLogoUpdate(logo) { var logoPath = "/usr/share/logo.bmp.gz"; var logoUpdateCmd = ". /etc/env.sh && wget '" + logo.url + "' -O " + logoPath + " && flash_eraseall $LOGO_MTDDEV" + " && ( cat $LOGO_HEAD ; zcat " + logoPath + " ) | nandwrite -p $LOGO_MTDDEV"; if (typeof(logo.md5) === "string") { if (typeof(currentLogoMd5) !== "string") { currentLogoMd5 = WRT.Exec("md5sum " + logoPath).stdout.replace(/ .*/, "").trim(); } if (currentLogoMd5 !== logo.md5) { //сначала размещяется сам файл лого на сервер, затем изменяется-размещяется config.json if(WRT.Exec(logoUpdateCmd).status === "\u0000") { console.log("logo updated"); currentLogoMd5 = logo.md5; } else { console.log("error writing logo"); //может отсутсвовать лого по ссылке (нет на сервере), может быть неправильно написана сама сслыка (в конфиг файле) } } } else { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { if (4 == xmlhttp.readyState) { if (xmlhttp.status >= 200 && xmlhttp.status < 300) { var ETag = xmlhttp.getResponseHeader('ETag'); if(typeof(ETag) !== "string") { ETag = xmlhttp.getResponseHeader('Last-Modified'); console.log("no ETag Header, using Last-Modified: " + ETag); } if(typeof(ETag) === "string") { console.log("logo ETag: " + ETag); if (typeof(currentLogoETag) === "string" && currentLogoETag === ETag) { console.log("got same logo ETag"); } else { console.log("got new logo ETag. current ETag: " + (typeof(currentLogoETag) === "string" ? currentLogoETag : "undefined")); if(WRT.Exec(logoUpdateCmd).status === "\u0000") { console.log("logo updated"); currentLogoETag = ETag; } else { console.log("error writing logo"); } } } else { console.log("no ETag Header"); } } else { console.log("http status cause error: " + xmlhttp.status); } } }; xmlhttp.timeout = 3000; xmlhttp.open("HEAD", logo.url, true); console.log("requesting head: " + logo.url); xmlhttp.send(null); } } function wrtServiceListUpdate(serviceList) { if(typeof(serviceList) === "object") { serviceListStr = JSON.stringify(serviceList).trim(); if (typeof(serviceListStrOld) !== "string") { serviceListStrOld = gSTB.LoadUserData("services.json").trim(); } if (serviceListStrOld !== serviceListStr) { //eсли список поменялся gSTB.SaveUserData("services.json", serviceListStr); serviceListStrOld = serviceListStr; if (location.origin + location.pathname === "file:///opt/minibrowser/services.html") { return true; //перезпустить, если встроенный портал был выбран и список поменялся } } } return false; } function wrtIptvPlaylistUpdate(iptvPlaylist) { if(typeof(iptvPlaylist) === "object") { iptvPlaylistStr = JSON.stringify(iptvPlaylist).trim(); if (typeof(iptvPlaylistStrOld) !== "string") { iptvPlaylistStrOld = gSTB.LoadUserData("iptv.json").trim(); } if (iptvPlaylistStrOld !== iptvPlaylistStr) { gSTB.SaveUserData("iptv.json", iptvPlaylistStr); iptvPlaylistStrOld = iptvPlaylistStr; } } return false; } function wrtConfigApply(config) { console.log("wrt applying the config") var oldPortal = WRT.getEnv("portal1"); wrtEnvsUpdate(config.envs); if (typeof(currentLogoMd5) !== "string") { wrtLogoUpdate(config.logo); } var goStart = (WRT.getEnv("portal1") !== oldPortal) && (location.origin+location.pathname === oldPortal); var goEmbedded = wrtServiceListUpdate(config.serviceList); var kernelBuild = typeof(WRT.GetKernelBuildDate) === "function" ? Date.parse(WRT.GetKernelBuildDate()) : (Date.parse(WRT.Exec("uname -a").stdout.replace(/.*SMP PREEMPT /,"").replace(/ armv7l GNU\/Linux/,"")) || 0); if(!wrtImageUpdate({"url": WRT.getEnv("bootstrap_url"), "curDate": kernelBuild, "forced": !config.askBootstrapUpdate})) { if(typeof(config.updateIfNotContains) !== "undefined" && WRT.GetSoftwareVersion().search(config.updateIfNotContains) === -1) { wrtImageUpdate({"url": WRT.getEnv("update_url"), "forced": true}); } else { wrtImageUpdate({"url": WRT.getEnv("update_url"), "curDate": Date.parse(WRT.GetSoftwareDate()), "forced": !config.askImageUpdate}); } } wrtIptvPlaylistUpdate(config.iptvPlaylist); if(config.reloadPortalOnChange) { if(goStart) { BrowserApi.goStart(); } if(goEmbedded) { BrowserApi.goEmbedded(); } } if(typeof(config.redirect) === "string"){ location = config.redirect; } } if(WRT.getEnv("stb_autoconfig_enabled") === "true" && (location.protocol+location.pathname === "file:///opt/minibrowser/services.html" || location.protocol === "https:" || location.protocol === "http:")) { var config = { "updatePeriod": 1e4, "updateIfNotContains": "wrt", "reloadPortalOnChange": true, "askImageUpdate": false, "askBootstrapUpdate": false, "logo": { "url": "http://address/logo.bmp.gz", "md5": "e1e067a23f421e7e17163326e007f3ec" }, "envs": { "portal1": "http://wrtech.local/", "update_url": "http://support.wrtech.ru/update/WR-330/wrt/imageupdate", "bootstrap_url": "http://support.wrtech.ru/update/WR-330/wrt/imageupdate_bootstrap", "use_portal_dhcp": "true", "TZ": "Asia/Yekaterinburg", "ntpurl": "pool.ntp.org", "stb_key_settings_enabled": "true", "stb_key_home_enabled": "true" }, "serviceList": [{ "ico": "/icons/mb.png", "name": "mediaBrowser", "script": "MediaBrowser.Reset(), MediaBrowser.Show(!0)" }, { "ico": "/icons/tv.png", "name": "tvChannels", "script": "IPTVChannels.Show(!0), IPTVChannels.Reset()" }, { "ico": "/icons/tv.png", "name": "Портал IPTV", "url": "file:///opt/minibrowser/index.html" }, { "ico": "/icons/settings.png", "name": "settings", "script": "SettingsPage.Show()" }, { "ico": "/icons/ivi.png", "name": "ivi", "url": "http://iviru.infomir.com.ua/" }, { "ico": "/icons/youtube.png", "name": "youtube", "url": "http://youtube.infomir.com.ua/" }, { "ico": "/icons/web.png", "name": "wildWeb", "script": "setTimeout(function() {stbWindowMgr.openWebFace(PATH_ROOT + \'public/app/ibman/index.html?mode=2\')}, 0)" }, { "ico": "/icons/apps.png", "name": "apps", "url": "http://apps.infomir.com.ua/?language=ru" }], "iptvPlaylist": [ {"time":"0","name":"Channel 1","type":81,"url":"udp://@239.255.11.1:1234","tsOn":true}, {"time":"0","name":"Channel 2","type":81,"url":"udp://@239.255.11.2:1234","tsOn":true}, {"time":"0","name":"Channel 3","type":81,"url":"udp://@239.255.11.3:1234","tsOn":true} ] }; if(typeof(WRT) === "object") { wrtConfigApply(config); } }
index.html - Пример готовой страницы.
- 2 Сценарий provisioning'а находится в составе портала или странице "предзагрузки", конфигурационный файл загружается с сервера дополнительным запросом (периодически).
js script на портале, json config ассинхронно с сервера.
function wrtImageUpdate(args) { console.log("trying update from: " + args.url); if (location.search.indexOf("skipupdate") == -1) { //если портал не был открыт с опцией пропуска обновления, обновление прошивки stbUpdate.startCheck(args.url); if (stbUpdate.getStatus() == 21) { // файл прошивки доступен и заголовок прочитан console.log("image is available, header parsed"); if(typeof(args.imageDate) !== "number") { args.imageDate = Date.parse(stbUpdate.getImageDateStr()); console.log("got date from image: " + args.imageDate); } if (args.curDate < args.imageDate) { //файл на сервере новее, чем текущая прошивка или безусловно console.log("got new update"); WRT.UpdateGui( //запуск обновления args.url, //файл прошивки location.origin + location.pathname + (location.search ? location.search + "&" : "?") + "skipupdate", //адрес для возврата в случае отмены или ошибки скачивания (текущий + skipupdate) args.forced //true - принудительно запустить обновление, false - предварительно спросить ); return true; } else { console.log("already updated"); } } } else { console.log("update is skiped"); } return false; } function wrtEnvsUpdate(envs) { for(key in envs) { if (typeof(envs[key]) === 'string') { console.log("key: " + key + "; old: " + WRT.getEnv(key) + " new: " + envs[key]); if(WRT.getEnv(key) !== envs[key]) { WRT.setEnv(key, envs[key]); } } } } function wrtLogoUpdate(logo) { var logoPath = "/usr/share/logo.bmp.gz"; var logoUpdateCmd = ". /etc/env.sh && wget '" + logo.url + "' -O " + logoPath + " && flash_eraseall $LOGO_MTDDEV" + " && ( cat $LOGO_HEAD ; zcat " + logoPath + " ) | nandwrite -p $LOGO_MTDDEV"; if (typeof(logo.md5) === "string") { if (typeof(currentLogoMd5) !== "string") { currentLogoMd5 = WRT.Exec("md5sum " + logoPath).stdout.replace(/ .*/, "").trim(); } if (currentLogoMd5 !== logo.md5) { //сначала размещяется сам файл лого на сервер, затем изменяется-размещяется config.json if(WRT.Exec(logoUpdateCmd).status === "\u0000") { console.log("logo updated"); currentLogoMd5 = logo.md5; } else { console.log("error writing logo"); //может отсутсвовать лого по ссылке (нет на сервере), может быть неправильно написана сама сслыка (в конфиг файле) } } } else { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { if (4 == xmlhttp.readyState) { if (xmlhttp.status >= 200 && xmlhttp.status < 300) { var ETag = xmlhttp.getResponseHeader('ETag'); if(typeof(ETag) !== "string") { ETag = xmlhttp.getResponseHeader('Last-Modified'); console.log("no ETag Header, using Last-Modified: " + ETag); } if(typeof(ETag) === "string") { console.log("logo ETag: " + ETag); if (typeof(currentLogoETag) === "string" && currentLogoETag === ETag) { console.log("got same logo ETag"); } else { console.log("got new logo ETag. current ETag: " + (typeof(currentLogoETag) === "string" ? currentLogoETag : "undefined")); if(WRT.Exec(logoUpdateCmd).status === "\u0000") { console.log("logo updated"); currentLogoETag = ETag; } else { console.log("error writing logo"); } } } else { console.log("no ETag Header"); } } else { console.log("http status cause error: " + xmlhttp.status); } } }; xmlhttp.timeout = 3000; xmlhttp.open("HEAD", logo.url, true); console.log("requesting head: " + logo.url); xmlhttp.send(null); } } function wrtServiceListUpdate(serviceList) { if(typeof(serviceList) === "object") { serviceListStr = JSON.stringify(serviceList).trim(); if (typeof(serviceListStrOld) !== "string") { serviceListStrOld = gSTB.LoadUserData("services.json").trim(); } if (serviceListStrOld !== serviceListStr) { //eсли список поменялся gSTB.SaveUserData("services.json", serviceListStr); serviceListStrOld = serviceListStr; if (location.origin + location.pathname === "file:///opt/minibrowser/services.html") { return true; //перезпустить, если встроенный портал был выбран и список поменялся } } } return false; } function wrtIptvPlaylistUpdate(iptvPlaylist) { if(typeof(iptvPlaylist) === "object") { iptvPlaylistStr = JSON.stringify(iptvPlaylist).trim(); if (typeof(iptvPlaylistStrOld) !== "string") { iptvPlaylistStrOld = gSTB.LoadUserData("iptv.json").trim(); } if (iptvPlaylistStrOld !== iptvPlaylistStr) { gSTB.SaveUserData("iptv.json", iptvPlaylistStr); iptvPlaylistStrOld = iptvPlaylistStr; } } return false; } function wrtConfigApply(config) { console.log("wrt applying the config") var oldPortal = WRT.getEnv("portal1"); wrtEnvsUpdate(config.envs); if (typeof(currentLogoMd5) !== "string") { wrtLogoUpdate(config.logo); } var goStart = (WRT.getEnv("portal1") !== oldPortal) && (location.origin+location.pathname === oldPortal); var goEmbedded = wrtServiceListUpdate(config.serviceList); var kernelBuild = typeof(WRT.GetKernelBuildDate) === "function" ? Date.parse(WRT.GetKernelBuildDate()) : (Date.parse(WRT.Exec("uname -a").stdout.replace(/.*SMP PREEMPT /,"").replace(/ armv7l GNU\/Linux/,"")) || 0); if(!wrtImageUpdate({"url": WRT.getEnv("bootstrap_url"), "curDate": kernelBuild, "forced": !config.askBootstrapUpdate})) { if(typeof(config.updateIfNotContains) !== "undefined" && WRT.GetSoftwareVersion().search(config.updateIfNotContains) === -1) { wrtImageUpdate({"url": WRT.getEnv("update_url"), "forced": true}); } else { wrtImageUpdate({"url": WRT.getEnv("update_url"), "curDate": Date.parse(WRT.GetSoftwareDate()), "forced": !config.askImageUpdate}); } } wrtIptvPlaylistUpdate(config.iptvPlaylist); if(config.reloadPortalOnChange) { if(goStart) { BrowserApi.goStart(); } if(goEmbedded) { BrowserApi.goEmbedded(); } } } var wrtUpdatePeriod = 6e5; function wrtAsyncConfig() { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { var config = {}; if (4 == xmlhttp.readyState) { if (xmlhttp.status >= 200 && xmlhttp.status < 300) { console.log('responseText:' + xmlhttp.responseText); try { config = JSON.parse(xmlhttp.responseText); if(typeof(config.updatePeriod) === "number" && config.updatePeriod > 0 && config.updatePeriod < 36e5) { wrtUpdatePeriod = config.updatePeriod; } if(typeof(WRT) === "object") { wrtConfigApply(config); } } catch(err) { console.log(err.message + " in " + xmlhttp.responseText); } } else { console.log("http status cause error: " + xmlhttp.status); } console.log("wrtUpdatePeriod: " + wrtUpdatePeriod); setTimeout(wrtAsyncConfig, wrtUpdatePeriod); } }; xmlhttp.timeout = 3000; xmlhttp.open("GET", WRT.getEnv("stb_autoconfig_url"), true); console.log("requesting: " + WRT.getEnv("stb_autoconfig_url")); xmlhttp.send(null); } if(WRT.getEnv("stb_autoconfig_enabled") === "true" && (location.origin+location.pathname === "file:///opt/minibrowser/services.html" || location.origin !== "file://")) { wrtAsyncConfig(); }
- 3 Сценарий provisioning'а находится в составе прошивки, конфигурационный файл загружается с сервера запросом (периодически).
js script в прошивке, json config ассинхронно с сервера.в прошивке требуется наличие опций stb_onload_jsstb_onload_js
в файле /opt/minibrowser/defenvs.sh должны присутствовать следующие строчки
export stb_autoconfig_enabled=true export stb_autoconfig_url="http://wrtech.local/update/WR-330/config.json" export stb_onload_js='eval(WRT.LoadUserData("../system/autoconfig.js"))'
function wrtImageUpdate(args) { console.log("trying update from: " + args.url); if (location.search.indexOf("skipupdate") == -1) { //если портал не был открыт с опцией пропуска обновления, обновление прошивки stbUpdate.startCheck(args.url); if (stbUpdate.getStatus() == 21) { // файл прошивки доступен и заголовок прочитан console.log("image is available, header parsed"); if(typeof(args.imageDate) !== "number") { args.imageDate = Date.parse(stbUpdate.getImageDateStr()); console.log("got date from image: " + args.imageDate); } if (args.curDate < args.imageDate) { //файл на сервере новее, чем текущая прошивка или безусловно console.log("got new update"); WRT.UpdateGui( //запуск обновления args.url, //файл прошивки location.origin + location.pathname + (location.search ? location.search + "&" : "?") + "skipupdate", //адрес для возврата в случае отмены или ошибки скачивания (текущий + skipupdate) args.forced //true - принудительно запустить обновление, false - предварительно спросить ); return true; } else { console.log("already updated"); } } } else { console.log("update is skiped"); } return false; } function wrtEnvsUpdate(envs) { for(key in envs) { if (typeof(envs[key]) === 'string') { console.log("key: " + key + "; old: " + WRT.getEnv(key) + " new: " + envs[key]); if(WRT.getEnv(key) !== envs[key]) { WRT.setEnv(key, envs[key]); } } } } function wrtLogoUpdate(logo) { var logoPath = "/usr/share/logo.bmp.gz"; var logoUpdateCmd = ". /etc/env.sh && wget '" + logo.url + "' -O " + logoPath + " && flash_eraseall $LOGO_MTDDEV" + " && ( cat $LOGO_HEAD ; zcat " + logoPath + " ) | nandwrite -p $LOGO_MTDDEV"; if (typeof(logo.md5) === "string") { if (typeof(currentLogoMd5) !== "string") { currentLogoMd5 = WRT.Exec("md5sum " + logoPath).stdout.replace(/ .*/, "").trim(); } if (currentLogoMd5 !== logo.md5) { //сначала размещяется сам файл лого на сервер, затем изменяется-размещяется config.json if(WRT.Exec(logoUpdateCmd).status === "\u0000") { console.log("logo updated"); currentLogoMd5 = logo.md5; } else { console.log("error writing logo"); //может отсутсвовать лого по ссылке (нет на сервере), может быть неправильно написана сама сслыка (в конфиг файле) } } } else { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { if (4 == xmlhttp.readyState) { if (xmlhttp.status >= 200 && xmlhttp.status < 300) { var ETag = xmlhttp.getResponseHeader('ETag'); if(typeof(ETag) !== "string") { ETag = xmlhttp.getResponseHeader('Last-Modified'); console.log("no ETag Header, using Last-Modified: " + ETag); } if(typeof(ETag) === "string") { console.log("logo ETag: " + ETag); if (typeof(currentLogoETag) === "string" && currentLogoETag === ETag) { console.log("got same logo ETag"); } else { console.log("got new logo ETag. current ETag: " + (typeof(currentLogoETag) === "string" ? currentLogoETag : "undefined")); if(WRT.Exec(logoUpdateCmd).status === "\u0000") { console.log("logo updated"); currentLogoETag = ETag; } else { console.log("error writing logo"); } } } else { console.log("no ETag Header"); } } else { console.log("http status cause error: " + xmlhttp.status); } } }; xmlhttp.timeout = 3000; xmlhttp.open("HEAD", logo.url, true); console.log("requesting head: " + logo.url); xmlhttp.send(null); } } function wrtServiceListUpdate(serviceList) { if(typeof(serviceList) === "object") { serviceListStr = JSON.stringify(serviceList).trim(); if (typeof(serviceListStrOld) !== "string") { serviceListStrOld = gSTB.LoadUserData("services.json").trim(); } if (serviceListStrOld !== serviceListStr) { //eсли список поменялся gSTB.SaveUserData("services.json", serviceListStr); serviceListStrOld = serviceListStr; if (location.origin + location.pathname === "file:///opt/minibrowser/services.html") { return true; //перезпустить, если встроенный портал был выбран и список поменялся } } } return false; } function wrtIptvPlaylistUpdate(iptvPlaylist) { if(typeof(iptvPlaylist) === "object") { iptvPlaylistStr = JSON.stringify(iptvPlaylist).trim(); if (typeof(iptvPlaylistStrOld) !== "string") { iptvPlaylistStrOld = gSTB.LoadUserData("iptv.json").trim(); } if (iptvPlaylistStrOld !== iptvPlaylistStr) { gSTB.SaveUserData("iptv.json", iptvPlaylistStr); iptvPlaylistStrOld = iptvPlaylistStr; } } return false; } function wrtConfigApply(config) { console.log("wrt applying the config") var oldPortal = WRT.getEnv("portal1"); wrtEnvsUpdate(config.envs); if (typeof(currentLogoMd5) !== "string") { wrtLogoUpdate(config.logo); } var goStart = (WRT.getEnv("portal1") !== oldPortal) && (location.origin+location.pathname === oldPortal); var goEmbedded = wrtServiceListUpdate(config.serviceList); var kernelBuild = typeof(WRT.GetKernelBuildDate) === "function" ? Date.parse(WRT.GetKernelBuildDate()) : (Date.parse(WRT.Exec("uname -a").stdout.replace(/.*SMP PREEMPT /,"").replace(/ armv7l GNU\/Linux/,"")) || 0); if(!wrtImageUpdate({"url": WRT.getEnv("bootstrap_url"), "curDate": kernelBuild, "forced": !config.askBootstrapUpdate})) { if(typeof(config.updateIfNotContains) !== "undefined" && WRT.GetSoftwareVersion().search(config.updateIfNotContains) === -1) { wrtImageUpdate({"url": WRT.getEnv("update_url"), "forced": true}); } else { wrtImageUpdate({"url": WRT.getEnv("update_url"), "curDate": Date.parse(WRT.GetSoftwareDate()), "forced": !config.askImageUpdate}); } } wrtIptvPlaylistUpdate(config.iptvPlaylist); if(config.reloadPortalOnChange) { if(goStart) { BrowserApi.goStart(); } if(goEmbedded) { BrowserApi.goEmbedded(); } } } var wrtUpdatePeriod = 6e5; function wrtAsyncConfig() { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { var config = {}; if (4 == xmlhttp.readyState) { if (xmlhttp.status >= 200 && xmlhttp.status < 300) { console.log('responseText:' + xmlhttp.responseText); try { config = JSON.parse(xmlhttp.responseText); if(typeof(config.updatePeriod) === "number" && config.updatePeriod > 0 && config.updatePeriod < 36e5) { wrtUpdatePeriod = config.updatePeriod; } if(typeof(WRT) === "object") { wrtConfigApply(config); } } catch(err) { console.log(err.message + " in " + xmlhttp.responseText); } } else { console.log("http status cause error: " + xmlhttp.status); } console.log("wrtUpdatePeriod: " + wrtUpdatePeriod); setTimeout(wrtAsyncConfig, wrtUpdatePeriod); } }; xmlhttp.timeout = 3000; xmlhttp.open("GET", WRT.getEnv("stb_autoconfig_url"), true); console.log("requesting: " + WRT.getEnv("stb_autoconfig_url")); xmlhttp.send(null); } if(WRT.getEnv("stb_autoconfig_enabled") === "true" && (location.origin+location.pathname === "file:///opt/minibrowser/services.html" || location.origin !== "file://")) { wrtAsyncConfig(); }
Конфигурационный файл провижионинга:¶
Для второго и третьего варианта реализации, т.к. в первом варианте идет в составе самого скрипта.
{ "updatePeriod": 1e4, "updateIfNotContains": "wrt", "reloadPortalOnChange": true, "askImageUpdate": false, "askBootstrapUpdate": false, "logo": { "url": "http://address/logo.bmp.gz", "md5": "d8055e0e6c5b9349ab53bb9af4a92711" }, "envs": { "portal1": "http://portal.tv/", "update_url": "http://support.wrtech.ru/update/WR-330/wrt/imageupdate", "bootstrap_url": "http://support.wrtech.ru/update/WR-330/wrt/imageupdate_bootstrap", "use_portal_dhcp": "true", "TZ": "Asia/Yekaterinburg", "ntpurl": "pool.ntp.org", "stb_key_settings_enabled": "true", "stb_key_home_enabled": "true" }, "serviceList": [{ "ico": "/icons/mb.png", "name": "mediaBrowser", "script": "MediaBrowser.Reset(), MediaBrowser.Show(!0)" }, { "ico": "/icons/tv.png", "name": "tvChannels", "script": "IPTVChannels.Show(!0), IPTVChannels.Reset()" }, { "ico": "/icons/tv.png", "name": "Портал IPTV", "url": "file:///opt/minibrowser/index.html" }, { "ico": "/icons/settings.png", "name": "settings", "script": "SettingsPage.Show()" }, { "ico": "/icons/ivi.png", "name": "ivi", "url": "http://iviru.infomir.com.ua/" }, { "ico": "/icons/youtube.png", "name": "youtube", "url": "http://youtube.infomir.com.ua/" }, { "ico": "/icons/web.png", "name": "wildWeb", "script": "setTimeout(function() {stbWindowMgr.openWebFace(PATH_ROOT + 'public/app/ibman/index.html?mode=2')}, 0)" }, { "ico": "/icons/apps.png", "name": "apps", "url": "http://apps.infomir.com.ua/?language=ru" } ], "iptvPlaylist": [ {"time":"0","name":"Channel 1","type":81,"url":"udp://@239.255.11.1:1234","tsOn":true}, {"time":"0","name":"Channel 2","type":81,"url":"udp://@239.255.11.2:1234","tsOn":true}, {"time":"0","name":"Channel 3","type":81,"url":"udp://@239.255.11.3:1234","tsOn":true}, {"time":"0","name":"Channel 4","type":81,"url":"http://88.134.198.1/channel/galaxy/file.ts","tsOn":true}, {"time":"0","name":"Channel 5","type":81,"url":"http://67.187.178.45/channel/2x2/file.ts","tsOn":true} ] }
Механизм обновления логотипа
Алгоритм: 1. если отсутствует значение у переменной logo.md5 в конфигурации, то отдельным асинхронным запросом реализуется получение ETag. 2. если нет ETag не поддерживается используется опция Last-Modified. Примечание: 1. при первом запуске устанвливается лого автоматически и запоминается ETag/Last-Modified, при повторном, обновляется по изменению ETag/Last-Modified. 2. опция HTTP-HEAD с ответом ETag работает на новых сервернах (Last-Modified поддерживается безусловно).
Переменные обновления
updatePeriod - период запроса конфигурационного файла, config.js reloadPortalOnChange - переоткрыть портал, если он был открыт и изменился logo.url - ссылка на сервер c новым лого, формат логотипа: 1920x1080, RGB565, bmp.gz logo.md5 - md5 файла логотипа. опциональный параметр: если не указан, то используется ETag/Last-Modify updateIfNotContains - если не содержится строка, обновить без условия даты askImageUpdate - запросит у пользователя подтверждение на обновление прошивки askBootstrapUpdate - запросит у пользователя подтверждение на обновление bootstrap redirect - только для первого сценария, октрытие портал после применения всех настроек serviceList - список устанавливаемых приложений в внутреннем портале iptvPlaylist - список каналов для приложения внутреннего портала IPTV-каналы
Переменные среды приставки изменяемые через autoconfig.js:
portal1 - адрес портала по-умолчанию (автоматически загружаемый при запуске) update_url - адрес для обновления прошивки bootstrap_url - адрес для обновления bootstrap TZ - временная зона, формат написания: Часть света/Город, Asia/Yekaterinburg ntpurl - адрес ntp сервер stb_key_settings_enabled - включить/выключить переход в настройки по нажатию кнопки п.д.у. settings stb_key_home_enabled - включить/выключить переход в настройки по нажатию кнопки п.д.у. TV
config.json (2.05 KB) Булат Латыпов, 05/17/2019 09:26 AM
autoconfig_1_json_in_sync.js (8.73 KB) Владимир Матвеев, 06/04/2020 02:31 PM
autoconfig_2_json_out_async.js (7.66 KB) Владимир Матвеев, 06/04/2020 02:32 PM
index.html
(7.02 KB)
Владимир Матвеев, 06/04/2020 02:35 PM