Looks like I spoke too soon. I changed the screen change time to get more time to troubleshoot and now everything seems to be working fine, including theater mode.
Hey Lucky,
Thanks for adding the Theater Mode; Iāve just installed your panel for the first time and Iām trying the ābasicā screen save mode first and have discovered another āfeature neededā at least for me ;-(
I have 3 tablets on the wall; one is vertically placed and the other two are horizontally placed.
The way I have the panels in HabPanel setup is; I have one for Horizontal and one for Vertical since the layout and widget sizes are so much different based on the orientation of the tablet.
For example, I have a panel called Weather and another called Weather-V which means a vertical layout. I have many panels setup like this . . .
The issue Iām having is; if I enable the screen saver and choose the panels I want to rotate through, it applies to both my horizontal and vertical tablets which means its going to show panels that will not fit or look proper on one of the tablet orientations.
Iām not sure if Iām SOL or is there something we can do to address this scenario?
Vertical:
Horizontal:
Yes, those temps are accurate!
Best, Jay
Thatās pretty much the issue with HabPanel in general. All settings are shared across ALL devices. Let me see if I can come up with a way to have different hpex configs per device, stored on different String items.
Chicago temperatureā¦1ā¦ yikes!!!
me is in floridaā¦ and Iām bummed because 60 F
Done. Get latest from the git
You can have as many device as you want, and all of them can be configured to have their own settings/configuration.
Thanks Lucky for allowing this change. It will be a HUGE help for everybody. My issue is getting the updated JSON into the panel. I have cleared the browser cache and tried another browser (Windows Chrome and Firefox) but it continues to bring in the same looking JSON for configuration.
I did download the latest ZIP off of GIT per your recommendation and the date of the JSON file is 1/29/19 @ 5:39 pm so Iām pretty sure I got the last update of it.
Every time I try from scratch it seems to keep my OLD configuration (panel rotation ids) which means to me itās NOT really getting deleted when I delete the panel and the JSON widget.
Any advise?
Best, Jay
Json config will look the same lol. You need to go to Advanced tab under the settings page and use a different Item string. You need to type āI understoodā in the box to make it editable.
For some reason the image upload isnāt workingā¦
Hereās my screen shots of what Iām seeing. Yup, the platform for displaying images is down.
Iām not seeing anywhere to type in āI understoodā, I even typed it in the RAW white space but that didnāt work.
Best, Jay
Yup. Seems like youāre still on the older version. My commits can be seen from https://github.com/LuckyMallari/hpex/commits/master
You need to download from github and replace everything in the habpanelex folder with the files from the download.
The images seem to be working now. You can see the new version from the image in the above postā¦
Yup, I did it again this morning and pulled it from this tree GitHub - LuckyMallari/hpex at facf703843f5014a5fdb211481005eec728d990c
I deleted the widget on Habpanelex, the panel itself and the JSON import.
I deleted the habpanelex folder in HTML and then put the new version in there and re-did the same process all over again.
Itās still showing the OLD setup along with it remembering my panel configuration IDs in the order I want them in.
Do I need to blow away cache/tmp directories?
Best, Jay
Yeah try emptying your cache. It might be caching the js files and html
I cleared the cache & tmp directories along with a clean boot up with your latest download and itās still showing the last version of the functionality.
Iām not sure how to remove this from my system completely to get the updated version?
Best, Jay
Hey Lucky,
Just to confirm I have the latest version from GIT, what file can I look into and see what to confirm I have the actual changes?
Best, Jay
Can you post a screenshot of your habpanelex folder. It should be oh-conf-htmlā¦ place the habpanelex there. If it ask you to replace old stuff, say yes. So it should be conf-html-habpanelex-the js files etc.
There is only ONE JS file in that folder.
Hereās the content of it:
/*
HPEx - (H)ab(P)anel(Ex)tension
Extends HabPanel Functionality
Lucky Mallari
https://github.com/LuckyMallari/hpex
MIT License
Copyright (c) 2019 Lucky Mallari https://github.com/LuckyMallari/hpex
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
(function () {
'use strict';
// Polyfills
(function hpexpolyfills() {
if (!Element.prototype.matches) {
Element.prototype.matches =
Element.prototype.matchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.msMatchesSelector ||
Element.prototype.oMatchesSelector ||
Element.prototype.webkitMatchesSelector ||
function (s) {
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
i = matches.length;
while (--i >= 0 && matches.item(i) !== this) { }
return i > -1;
};
}
})();
var app = angular.module('app', []);
app.constant('DEFAULTCONFIG', {
"initComplete": true,
"isShowInDrawer": false,
"screensaver": {
"isEnabled": true,
"timeoutSeconds": 120,
"dashboardList": "",
"durationSeconds": 10,
"isFullScreen": true
},
"theaterMode": {
"isEnabled": true,
"isOn": false,
"color": "rgba(0,0,0,0.90)",
"triggeringItem": null
}
});
app.service('HPExUtils', ['DEFAULTCONFIG',
function (DEFAULTCONFIG) {
var logTag = 'HPExUtils';
var serviceApi = {};
var log = function (s) { console.log(logTag + ": " + s); }
var synchrounousRestCall = function (method, itemName, body, mime) {
var xhr = new XMLHttpRequest();
var url = '/rest/items/' + itemName;
if ((method || "").toUpperCase() === 'GET') {
url += '?lucky=' + Math.random().toString().substring(2, 10) + 'charms'
}
xhr.open(method, url, false);
mime = mime || "application/json";
if ((method || "").toUpperCase() !== "GET")
xhr.setRequestHeader("Content-Type", mime);
xhr.setRequestHeader("Accept", "application/json");
xhr.send(body && JSON.stringify(body) || null);
if (xhr.status !== 200 && xhr.status !== 201)
return {
status: xhr.status,
result: null
};
return {
status: xhr.status,
result: xhr.responseText
};
}
serviceApi.getConfig = function (id) {
var c = synchrounousRestCall('GET', id);
if (c == null || c.status !== 200) {
// Config does not exist. Create an item for it.
log("Config item does not exist. Creating one..")
var data = {
"type": "String",
"name": id,
"label": "HPEx Config for " + id
};
var d = synchrounousRestCall('PUT', id, data);
// Then retrieve it
c = synchrounousRestCall('GET', id);
}
try {
c = c && c.result && JSON.parse(c.result);
} catch (e) {
c = "{}"
}
c = c.state;
try {
c = JSON.parse(c);
} catch (e) {
c = "{}";
}
if (c.initComplete) {
log("Config item found.")
return c;
}
log("Initializing Config.")
c = DEFAULTCONFIG;
c.initComplete = true;
synchrounousRestCall('POST', id, c, "text/plain");
log("Config init complete.")
return c;
}
serviceApi.saveConfig = function (id, configData) {
return synchrounousRestCall('POST', id, configData, "text/plain");
}
var getDom = function (d) {
return typeof (d) === "object" ? d : document.querySelector(d);
};
serviceApi.hasParent = function (childSelector, parentSelector) {
return serviceApi.findParent(childSelector, parentSelector) !== null;
};
serviceApi.findParent = function (childSelector, parentSelector) {
var child = getDom(childSelector);
return child && child.closest(parentSelector);
};
var init = function () { log("Init!"); return true; };
serviceApi.init = init();
return serviceApi;
}
]);
app.service('HPExService', ['$rootScope', '$location', 'OHService', 'HPExUtils', '$compile',
function ($rootScope, $location, OHService, HPExUtils, $compile) {
var logTag = 'HPExService';
var serviceApi = {};
var log = function (s) { console.log(logTag + ": " + s); }
var protectedConfigData = HPExUtils.getConfig("habpanelExConfig");
serviceApi.goToDashboard = function (name) {
$location.url('/view/' + name);
};
serviceApi.saveConfig = function (newConfig) {
protectedConfigData = newConfig;
return HPExUtils.saveConfig("habpanelExConfig", newConfig);
};
serviceApi.getConfig = function () {
return angular.copy(protectedConfigData);
}
serviceApi.toast = function (message) {
};
var init = function () {
log("Init!");
return true;
};
serviceApi.init = init(); 1
return serviceApi;
}
]);
app.service('HPExScrSaverService', ['HPExService', '$rootScope', 'HPExUtils', '$interval', '$timeout', 'PersistenceService',
function (HPExService, $rootScope, HPExUtils, $interval, $timeout, PersistenceService) {
var logTag = 'HPExScrSaverService';
var log = function (s) { console.log(logTag + ": " + s); }
var serviceApi = {};
var eventsList = ["mousemove", "keyup", "keydown", "click"];
var timers = {
idleTimer: null,
screenSaverTimer: null
}
var config = {};
var currentIndex = 0;
serviceApi.getAvailablePanelIds = function () {
return extractIds(PersistenceService.getDashboards()).join(', ');
}
var resetTimer = function () {
stopIdleTimer();
startIdleTimer();
};
var idleHit = function () {
var interval = config.durationSeconds || 10;
timers.screenSaverTimer = $interval(next, interval * 1000);
}
var next = function () {
var nextDb = config.dashboardList[currentIndex];
HPExService.goToDashboard(nextDb);
if (currentIndex == config.dashboardList.length - 1)
currentIndex = 0;
else
currentIndex++;
};
var startIdleTimer = function () {
var timeout = config.timeoutSeconds || 300;
timers.idleTimer = $timeout(idleHit, timeout * 1000);
};
var stopIdleTimer = function () {
$timeout.cancel(timers.idleTimer);
$interval.cancel(timers.screenSaverTimer);
timers.idleTime = null;
timers.screenSaverTimer = null;
};
var listen = function () {
for (var i = 0; i < eventsList.length; i++) {
var e = eventsList[i];
document.addEventListener(e, resetTimer);
}
};
var unlisten = function () {
for (var i = 0; i < eventsList.length; i++) {
var e = eventsList[i];
document.removeEventListener(e, resetTimer);
}
};
var extractIds = function (a) {
var l = [];
if (!Array.isArray(a)) {
if (typeof (a) === "string") {
return a.split(",");
} else {
return null;
}
}
for (var i = 0; i < a.length; i++) {
var d = a[i];
d.id && d.id !== "HabPanelEx" && l.push(d.id);
}
return l;
}
var initConfig = function () {
config = angular.copy(HPExService.getConfig());
config = config && config.screensaver || {};
if (!config.dashboardList) {
config.dashboardList = PersistenceService.getDashboards();
}
config.dashboardList = extractIds(config.dashboardList);
};
var ssMain = function () {
if (config.isEnabled) {
listen();
resetTimer();
} else {
unlisten();
stopIdleTimer();
}
};
var onConfigChanged = function () {
initConfig();
ssMain();
};
var onInit = function () {
initConfig();
ssMain();
log("Init");
};
$rootScope.$on('HPExEvent.configChanged', onConfigChanged);
onInit();
return serviceApi;
}
]);
app.controller('HPExDrawerCtrl', ['$scope', 'HPExService', '$rootScope', 'HPExUtils', 'HPExScrSaverService',
function ($scope, HPExService, $rootScope, HPExUtils, HPExScrSaverService) {
var logTag = 'HPExDrawerCtrl';
var log = function (s) { console.log(logTag + ": " + s); }
var onDestroy = function () {
log("Destroyed!");
};
var showOrHide = function () {
var found = HPExUtils.findParent('.hpex-drawer', 'li');
if (found) {
if ($scope.config.isShowInDrawer) {
found.style.display = "block";
return;
}
found.style.display = "none";
}
return !!found;
};
var onInit = function () {
log("Init");
$scope.config = HPExService.getConfig();
showOrHide();
};
$rootScope.$on('HPExEvent.configChanged', onInit);
$scope.$on('$destroy', onDestroy);
onInit();
}]
);
app.service('HPExModalService', ['$uibModal',
function ($uibModal) {
var serviceApi = {};
var bucket = { modalInstance: null };
serviceApi.open = function (title, message) {
bucket.modalInstance = $uibModal.open({
templateUrl: '/static/habpanelex/tpl/modal.html?lucky=' + Math.random().toString().substring(2, 7),
backdrop: 'static',
controller: function ($scope, $uibModalInstance) {
$scope.close = $uibModalInstance.close;
$scope.title = title;
$scope.message = message;
}
})
};
serviceApi.close = function () {
bucket.modalInstance.close();
};
return serviceApi;
}
]);
/*
Main Settings Controller
*/
app.controller('HPExCtrl', ['$scope', 'HPExService', 'HPExUtils', '$rootScope', 'HPExScrSaverService', 'HPExModalService',
function ($scope, HPExService, HPExUtils, $rootScope, HPExScrSaverService, HPExModalService) {
var logTag = 'HPExCtrl';
$scope.header = "HPEx";
$scope.availablePanelIds = HPExScrSaverService.getAvailablePanelIds();
$scope.instanceId = Math.random().toString(36).substring(2);
$scope.isDrawer = function () {
var retVal = HPExUtils.hasParent('.hpex-main_' + $scope.instanceId, '.drawer');
return retVal;
};
$scope.saveConfig = function () {
var r = HPExService.saveConfig($scope.config);
if (r.status === 201 || r.status === 200) {
$rootScope.$broadcast('HPExEvent.configChanged');
HPExModalService.open('Config', 'Saved');
}
else {
HPExModalService.open('Config', 'Failed');
}
}
$scope.cancelConfig = function () {
onInit();
HPExModalService.open('Config', 'Canceled');
}
var log = function (s) { console.log(logTag + ": " + s); }
var onInit = function () {
$scope.config = HPExService.getConfig();
log("Init");
};
var onDestroy = function () {
log("Destroyed!");
};
$scope.$on('$destroy', onDestroy);
onInit();
}
]);
app.service('HPExFSService', ['$rootScope', 'HPExService',
function ($rootScope, HPExService) {
var logTag = 'HPExFSService';
var serviceApi = {};
var config = {};
var onConfigChanged = function () {
config = HPExService.getConfig();
};
var log = function (s) { console.log(logTag + ": " + s); }
var onInit = function () {
config = HPExService.getConfig();
log("Init");
};
serviceApi.startTheaterMode = function () {
var el = document.getElementById('theaterModeMainEl');
el && (el.style.display = "block");
};
serviceApi.stopTheaterMode = function () {
var el = document.getElementById('theaterModeMainEl');
el && (el.style.display = "none");
};
serviceApi.toggleTheaterMode = function () {
var el = document.getElementById('theaterModeMainEl');
var d = el && el.style.display;
if (d) {
el.style.display = el.style.display == "none" ? "block" : "none";
}
};
$rootScope.$on('HPExEvent.configChanged', onConfigChanged);
onInit();
return serviceApi;
}
]);
app.controller('HPExTheaterCtrl', ['$scope', 'HPExFSService',
function ($scope, HPExFSService) {
$scope.on = function () {
HPExFSService.startTheaterMode();
};
$scope.off = function () {
HPExFSService.stopTheaterMode();
};
$scope.toggle = function () {
HPExFSService.toggleTheaterMode();
};
}
]);
app.directive('habPanelEx', function () {
return {
templateUrl: '/static/habpanelex/tpl/main.html?lucky=' + Math.random().toString().substring(2, 7),
restrict: 'A',
controller: 'HPExCtrl',
scope: false
};
});
})();
Best, Jay
I see. For some reason you are not downloading the latest version. Go back to github and see there are 2 js files now. Inside ctrl.js there should be a saveNewConfig function. I donāt see that in the one you pasted above.
Download it from the main github repo/url and not from a commit url. https://github.com/LuckyMallari/hpex
Iāve downloaded it from both of these URLās and there is still only ONE .JS in the habpanelex folder.
There is another .JS file but itās outside of the habpenalex folder called polyfills.js
Should I just drag polyfills.js into the habpanelex folder?
Best, Jay
Then thereās something wrong with your browser. I just tried it using my phone and files are there
Download the zip. Unzip everything to habpanelex folder.
I have that exact structure; but your instructions say ONLY to the Copy habpanelex folder to your OpenHABās conf/html folder.
Iām not copying the stuff outside of the habpanelex folder which is the TPL & IMG folder, README, Polyfills.js and ctrl.js folders to conf/html folder on OH.
What I have in the *habpanelex folder is: img, tpl folders and a ctrl.js file
Best, Jay