From a1ad6bf68b0d65e62efd7e052810ff955c831cc1 Mon Sep 17 00:00:00 2001 From: Tom Hirschberger Date: Wed, 22 Apr 2020 15:02:16 +0200 Subject: [PATCH] working version it is possible to select position either by click or notification --- MMM-SynologySurveillance.js | 215 ++++++++++++++++++++++++++++++++---- node_helper.js | 57 +++++++++- synology-surveillance_h.css | 37 +++++++ synology-surveillance_v.css | 37 +++++++ 4 files changed, 318 insertions(+), 28 deletions(-) diff --git a/MMM-SynologySurveillance.js b/MMM-SynologySurveillance.js index bf968bd..cf67f7c 100644 --- a/MMM-SynologySurveillance.js +++ b/MMM-SynologySurveillance.js @@ -8,6 +8,8 @@ Module.register('MMM-SynologySurveillance', { showOneBig: true, addBigToNormal: false, showBigCamName: false, + showBigPositions: false, + showPositions: false, showCamName: false, showUnreachableCams: true, urlRefreshInterval: 60, @@ -45,21 +47,21 @@ Module.register('MMM-SynologySurveillance', { this.dsPresetCurPosition[curDsIdx] = {} for(var curCamIdx = 0; curCamIdx < this.config.ds[curDsIdx].cams.length; curCamIdx++){ this.dsPresetInfo[curDsIdx][this.config.ds[curDsIdx].cams[curCamIdx].name] = {} - this.dsPresetCurPosition[curDsIdx][curCamIdx] = 0 + this.dsPresetCurPosition[curDsIdx][this.config.ds[curDsIdx].cams[curCamIdx].name] = 0 if(typeof this.config.ds[curDsIdx].cams[curCamIdx].alias !== "undefined"){ var curCamName = this.config.ds[curDsIdx].cams[curCamIdx].alias } else { var curCamName = this.config.ds[curDsIdx].cams[curCamIdx].name } // console.log("Mapping cam name: "+curCamName+" to ds "+curDsIdx+" and cam id "+curCamIdx) - nameDsCamIdxMap[curCamName] = [curDsIdx,curCamIdx] + nameDsCamIdxMap[curCamName] = [curDsIdx,curCamIdx,this.config.ds[curDsIdx].cams[curCamIdx].name] } } for(var curOrderIdx = 0; curOrderIdx < this.config.order.length; curOrderIdx++){ var curOrderName = this.config.order[curOrderIdx] if(typeof nameDsCamIdxMap[curOrderName] !== "undefined"){ - var curRes = [nameDsCamIdxMap[curOrderName][0], nameDsCamIdxMap[curOrderName][1], curOrderName] + var curRes = [nameDsCamIdxMap[curOrderName][0], nameDsCamIdxMap[curOrderName][1], curOrderName, nameDsCamIdxMap[curOrderName][2]] // console.log("Pushing to order (special): "+JSON.stringify(curRes)) this.order.push(curRes) } @@ -73,7 +75,7 @@ Module.register('MMM-SynologySurveillance', { this.dsPresetCurPosition[curDsIdx] = {} for(var curCamIdx = 0; curCamIdx < this.config.ds[curDsIdx].cams.length; curCamIdx++){ this.dsPresetInfo[curDsIdx][this.config.ds[curDsIdx].cams[curCamIdx].name] = {} - this.dsPresetCurPosition[curDsIdx][curCamIdx] = 0 + this.dsPresetCurPosition[curDsIdx][this.config.ds[curDsIdx].cams[curCamIdx].name] = 0 if(typeof this.config.ds[curDsIdx].cams[curCamIdx].alias !== "undefined"){ var curCamName = this.config.ds[curDsIdx].cams[curCamIdx].alias } else { @@ -81,7 +83,7 @@ Module.register('MMM-SynologySurveillance', { } var curRes = [curDsIdx, curCamIdx, curCamName] // console.log("Pushing to order (regular): "+JSON.stringify(curRes)) - this.order.push([curDsIdx, curCamIdx, curCamName]) + this.order.push([curDsIdx, curCamIdx, curCamName, this.config.ds[curDsIdx].cams[curCamIdx].name]) } } } @@ -108,21 +110,21 @@ Module.register('MMM-SynologySurveillance', { if(this.config.vertical && this.config.showOneBig){ if(typeof this.order[this.curBigIdx] !== "undefined"){ - var curDsIdx = this.order[this.curBigIdx][0] - var curCamIdx = this.order[this.curBigIdx][1] - var curCamAlias = this.order[this.curBigIdx][2] - var curCamName = this.config.ds[curDsIdx].cams[curCamIdx].name - var camWrapper = document.createElement("div") + let curDsIdx = this.order[this.curBigIdx][0] + let curCamIdx = this.order[this.curBigIdx][1] + let curCamAlias = this.order[this.curBigIdx][2] + let curCamName = this.config.ds[curDsIdx].cams[curCamIdx].name + let camWrapper = document.createElement("div") camWrapper.className = "camWrapper big "+curDsIdx+"_"+curCamIdx+" "+curCamAlias if(this.config.showBigCamName){ - var camNameWrapper = document.createElement("div") + let camNameWrapper = document.createElement("div") camNameWrapper.className = "name" camNameWrapper.innerHTML = curCamAlias + "
" camWrapper.appendChild(camNameWrapper) } - var innerCamWrapper = document.createElement("div") - var innerCamWrapperClassName = "innerCamWrapper big" + let innerCamWrapper = document.createElement("div") + let innerCamWrapperClassName = "innerCamWrapper big" if((typeof this.dsStreamInfo[curDsIdx] !== "undefined") && (typeof this.dsStreamInfo[curDsIdx][curCamName] !== "undefined") ){ @@ -137,15 +139,46 @@ Module.register('MMM-SynologySurveillance', { innerCamWrapper.className = innerCamWrapperClassName innerCamWrapper.appendChild(cam) camWrapper.appendChild(innerCamWrapper) + + if(self.config.showBigPositions){ + let innerPositionWrapper = document.createElement("div") + innerPositionWrapper.className = "innerPositionWrapper big" + //this.dsPresetInfo[curDsIdx][this.config.ds[curDsIdx].cams[curCamIdx].name] + for(var curPreset in this.dsPresetInfo[curDsIdx][curCamName]) { + let curPosition = this.dsPresetInfo[curDsIdx][curCamName][curPreset].position + console.log("CUR_POS: "+curPosition + " curActive: "+this.dsPresetCurPosition[curDsIdx][curCamName]) + let curPositionName = this.dsPresetInfo[curDsIdx][curCamName][curPreset].name + + var position = document.createElement("div") + //this.dsPresetCurPosition[curDsIdx][this.config.ds[curDsIdx].cams[curCamIdx].name] + position.className = "position big" + if(this.dsPresetCurPosition[curDsIdx][curCamName] === curPosition){ + var positionSelected = document.createElement("div") + positionSelected.className = "selected" + position.appendChild(positionSelected) + } + position.addEventListener("click", ()=>{ + self.dsPresetCurPosition[curDsIdx][curCamName] = curPosition + self.updateDom(self.config.animationSpeed) + self.sendSocketNotification("DS_CHANGE_POSITION", { + dsIdx: curDsIdx, + camName: curCamName, + position: curPosition + } + )}) + innerPositionWrapper.appendChild(position) + } + camWrapper.appendChild(innerPositionWrapper) + } wrapper.appendChild(camWrapper) } } for(let curOrderIdx = 0; curOrderIdx < this.order.length; curOrderIdx++){ - var curDsIdx = this.order[curOrderIdx][0] - var curCamIdx = this.order[curOrderIdx][1] - var curCamAlias = this.order[curOrderIdx][2] - var curCamName = this.config.ds[curDsIdx].cams[curCamIdx].name + let curDsIdx = this.order[curOrderIdx][0] + let curCamIdx = this.order[curOrderIdx][1] + let curCamAlias = this.order[curOrderIdx][2] + let curCamName = this.config.ds[curDsIdx].cams[curCamIdx].name if( (typeof this.config.ds[curDsIdx].cams[curCamIdx].profiles === "undefined") || @@ -158,19 +191,23 @@ Module.register('MMM-SynologySurveillance', { if(!this.config.showOneBig || (curOrderIdx !== this.curBigIdx)){ var camWrapper = document.createElement("div") camWrapper.className = "camWrapper "+curDsIdx+"_"+curCamIdx+" "+curCamAlias - if(this.config.showOneBig){ - camWrapper.addEventListener("click", ()=>{self.sendSocketNotification("SYNO_SS_CHANGE_CAM", {id: curOrderIdx})}) - } if(this.config.showCamName){ var camNameWrapper = document.createElement("div") camNameWrapper.className = "name" camNameWrapper.innerHTML = curCamAlias + if(this.config.showOneBig){ + camNameWrapper.addEventListener("click", ()=>{self.sendSocketNotification("SYNO_SS_CHANGE_CAM", {id: curOrderIdx})}) + } + camWrapper.appendChild(camNameWrapper) } var innerCamWrapper = document.createElement("div") var innerCamWrapperClassName = "innerCamWrapper" + if(this.config.showOneBig){ + innerCamWrapper.addEventListener("click", ()=>{self.sendSocketNotification("SYNO_SS_CHANGE_CAM", {id: curOrderIdx})}) + } if((typeof this.dsStreamInfo[curDsIdx] !== "undefined") && (typeof this.dsStreamInfo[curDsIdx][curCamName] !== "undefined") ){ @@ -185,6 +222,34 @@ Module.register('MMM-SynologySurveillance', { innerCamWrapper.className = innerCamWrapperClassName innerCamWrapper.appendChild(cam) camWrapper.appendChild(innerCamWrapper) + + if(self.config.showPositions){ + let innerPositionWrapper = document.createElement("div") + innerPositionWrapper.className = "innerPositionWrapper" + for(var curPreset in this.dsPresetInfo[curDsIdx][curCamName]) { + let curPosition = this.dsPresetInfo[curDsIdx][curCamName][curPreset].position + let curPositionName = this.dsPresetInfo[curDsIdx][curCamName][curPreset].name + + var position = document.createElement("div") + position.className = "position" + if(this.dsPresetCurPosition[curDsIdx][curCamName] === curPosition){ + var positionSelected = document.createElement("div") + positionSelected.className = "selected" + position.appendChild(positionSelected) + } + position.addEventListener("click", ()=>{ + self.dsPresetCurPosition[curDsIdx][curCamName] = curPosition + self.updateDom(self.config.animationSpeed) + self.sendSocketNotification("DS_CHANGE_POSITION", { + dsIdx: curDsIdx, + camName: curCamName, + position: curPosition + } + )}) + innerPositionWrapper.appendChild(position) + } + camWrapper.appendChild(innerPositionWrapper) + } wrapper.appendChild(camWrapper) } else { if(this.config.vertical && this.config.addBigToNormal){ @@ -216,7 +281,7 @@ Module.register('MMM-SynologySurveillance', { } var innerCamWrapper = document.createElement("div") - var innerCamWrapperClassName = "innerCamWrapper big" + var innerCamWrapperClassName = "innerCamWrapper big" if((typeof this.dsStreamInfo[curDsIdx] !== "undefined") && (typeof this.dsStreamInfo[curDsIdx][curCamName] !== "undefined") ){ @@ -231,6 +296,37 @@ Module.register('MMM-SynologySurveillance', { innerCamWrapper.className = innerCamWrapperClassName innerCamWrapper.appendChild(cam) camWrapper.appendChild(innerCamWrapper) + + if(self.config.showBigPositions){ + let innerPositionWrapper = document.createElement("div") + innerPositionWrapper.className = "innerPositionWrapper big" + //this.dsPresetInfo[curDsIdx][this.config.ds[curDsIdx].cams[curCamIdx].name] + for(var curPreset in this.dsPresetInfo[curDsIdx][curCamName]) { + let curPosition = this.dsPresetInfo[curDsIdx][curCamName][curPreset].position + console.log("CUR_POS: "+curPosition + " curActive: "+this.dsPresetCurPosition[curDsIdx][curCamName]) + let curPositionName = this.dsPresetInfo[curDsIdx][curCamName][curPreset].name + + var position = document.createElement("div") + //this.dsPresetCurPosition[curDsIdx][this.config.ds[curDsIdx].cams[curCamIdx].name] + position.className = "position big" + if(this.dsPresetCurPosition[curDsIdx][curCamName] === curPosition){ + var positionSelected = document.createElement("div") + positionSelected.className = "selected" + position.appendChild(positionSelected) + } + position.addEventListener("click", ()=>{ + self.dsPresetCurPosition[curDsIdx][curCamName] = curPosition + self.updateDom(self.config.animationSpeed) + self.sendSocketNotification("DS_CHANGE_POSITION", { + dsIdx: curDsIdx, + camName: curCamName, + position: curPosition + } + )}) + innerPositionWrapper.appendChild(position) + } + camWrapper.appendChild(innerPositionWrapper) + } wrapper.appendChild(camWrapper) } } @@ -289,6 +385,28 @@ Module.register('MMM-SynologySurveillance', { return nextCamId }, + getNextPositionIdx: function (dsIdx, camName, type=1) { + var nextPostion = this.dsPresetCurPosition[dsIdx][camName] + if((typeof this.dsPresetInfo[dsIdx] !== "undefined") && + (typeof this.dsPresetInfo[dsIdx][camName] !== "undefined") && + (Object.keys(this.dsPresetInfo[dsIdx][camName]).length > 0) + ){ + if(type === 1){ + nextPostion += 1 + if(nextPostion >= Object.keys(this.dsPresetInfo[dsIdx][camName]).length){ + nextPostion = 0 + } + } else if(type === -1){ + nextPostion -= 1 + if(nextPostion < 0){ + nextPostion = Object.keys(this.dsPresetInfo[dsIdx][camName]).length - 1 + } + } + } + return nextPostion + }, + + notificationReceived: function(notification,payload) { if(notification === "SYNO_SS_NEXT_CAM"){ this.curBigIdx = this.getNextCamId(this.curBigIdx, 1) @@ -302,6 +420,52 @@ Module.register('MMM-SynologySurveillance', { this.curBigIdx = this.payload.id this.updateDom(this.config.animationSpeed) } + } else if(notification === "SYNO_SS_NEXT_POSITION"){ + if((typeof payload.dsIdx !== "undefined") && + (typeof payload.camName !== "undefined") + ){ + var dsIdx = payload.dsIdx + var camName = payload.camName + } else { + var dsIdx = this.order[this.curBigIdx][0] + var camName = this.order[this.curBigIdx][3] + } + var position = this.getNextPositionIdx(dsIdx,camName,1) + this.dsPresetCurPosition[dsIdx][camName] = position + + this.sendSocketNotification("DS_CHANGE_POSITION", { + dsIdx: dsIdx, + camName: camName, + position: position, + }) + this.updateDom(this.config.animationSpeed) + } else if(notification === "SYNO_SS_PREVIOUS_POSITION"){ + if((typeof payload.dsIdx !== "undefined") && + (typeof payload.camName !== "undefined") + ){ + var dsIdx = payload.dsIdx + var camName = payload.camName + } else { + var dsIdx = this.order[this.curBigIdx][0] + var camName = this.order[this.curBigIdx][3] + } + var position = this.getNextPositionIdx(dsIdx,camName,-1) + this.dsPresetCurPosition[dsIdx][camName] = position + + this.sendSocketNotification("DS_CHANGE_POSITION", { + dsIdx: dsIdx, + camName: camName, + position: position, + }) + this.updateDom(this.config.animationSpeed) + } else if(notification === "SYNO_SS_CHANGE_POSITION"){ + this.sendSocketNotification("DS_CHANGE_POSITION", { + dsIdx: payload.dsIdx, + camName: payload.camName, + position: payload.position, + }) + this.dsPresetCurPosition[payload.dsIdx][payload.camName] = payload.position + this.updateDom(this.config.animationSpeed) } else if (notification === 'CHANGED_PROFILE'){ if(typeof payload.to !== 'undefined'){ this.currentProfile = payload.to @@ -315,7 +479,7 @@ Module.register('MMM-SynologySurveillance', { socketNotificationReceived: function (notification, payload) { if(notification === "DS_STREAM_INFO"){ console.log("Got new Stream info of ds with id: "+payload.dsIdx) - console.log(JSON.stringify(payload, null, 2)) + console.log(JSON.stringify(payload, null, 3)) if(typeof this.dsStreamInfo[payload.dsIdx] !== "undefined") { var updated = false for(var curKey in Object.keys(this.dsStreamInfo[payload.dsIdx])){ @@ -352,6 +516,13 @@ Module.register('MMM-SynologySurveillance', { this.curBigIdx = payload.id this.updateDom(this.config.animationSpeed) } + } else if (notification === "DS_PTZ_PRESET_INFO"){ + this.dsPresetInfo[payload.dsIdx][payload.camName] = payload.ptzData + } else if(notification === "DS_CHANGED_POSITION"){ + if(this.dsPresetCurPosition[payload.dsIdx][payload.camName] !== payload.position){ + this.dsPresetCurPosition[payload.dsIdx][payload.camName] = payload.position + this.updateDom(this.config.animationSpeed) + } } }, diff --git a/node_helper.js b/node_helper.js index 8bc78b5..1e56702 100644 --- a/node_helper.js +++ b/node_helper.js @@ -10,10 +10,12 @@ module.exports = NodeHelper.create({ start: function () { this.started = false + this.urlUpdateInProgress = false this.ds = {} }, getStreamUrls: function(){ + this.urlUpdateInProgress = true const self = this let result = [] @@ -113,6 +115,7 @@ module.exports = NodeHelper.create({ console.log(JSON.stringify(curPayload,null,2)) + self.urlUpdateInProgress = false self.sendSocketNotification("DS_STREAM_INFO",curPayload) } // else { @@ -127,12 +130,53 @@ module.exports = NodeHelper.create({ } }, - goPosition: function(dsIdx, camId, position){ + + Sleep: function (milliseconds) { + return new Promise(resolve => setTimeout(resolve, milliseconds)); + }, + + goPosition: async function(dsIdx, camName, position){ const self = this - if((typeof self.ds[dsIdx] !== "undefined") && (typeof self.ds[dsIdx].ptzPresetInfo !== "undefined")&& (typeof self.ds[dsIdx].ptzPresetInfo[camId] !== "undefined")){ - if((position >= 0) && (position < Object.keys(self.ds[dsIdx].ptzPresetInfo[camId]).length)){ - self.ds[dsIdx].syno.ss.goPresetPtz({'cameraId':camId, 'position':position}, function(goPtzError,goPtzData){}) + let curDsIdx = dsIdx + let curCamName = camName + let curPosition = position + while(self.urlUpdateInProgress){ + Sleep(1000) + } + + if((typeof self.ds[dsIdx] !== "undefined") && (typeof self.ds[dsIdx].idNameMap !== "undefined")){ + var camId = null + for(var curCamId in self.ds[dsIdx].idNameMap){ + console.log("Checking if camdId "+curCamId+" with name: "+self.ds[dsIdx].idNameMap[curCamId]+" matches name "+camName) + if(self.ds[dsIdx].idNameMap[curCamId] === camName){ + camId = curCamId + break + } + } + + if(camId){ + if((typeof self.ds[dsIdx].ptzPresetInfo !== "undefined")&& (typeof self.ds[dsIdx].ptzPresetInfo[camId] !== "undefined")){ + if((position >= 0) && (position < Object.keys(self.ds[dsIdx].ptzPresetInfo[camId]).length)){ + self.ds[dsIdx].syno.ss.goPresetPtz({'cameraId':camId, 'position':position}, function(goPtzError,goPtzData){ + if(goPtzError){ + console.log("Position could not be changed: "+JSON.stringify(goPtzError)) + } else { + self.sendSocketNotification("DS_CHANGED_POSITION", { + dsIdx: curDsIdx, + camName: curCamName, + position: curPosition + }) + } + }) + } + } else { + console.log("Could not change position of cam: "+camName+" of ds: "+dsIdx+" because no ptz preset info is available!") + } + } else { + console.log("Could not change postion of cam: "+camName+" because no id of this cam is known!") } + } else { + console.log("Could not change position of cam: "+camName+" because no id name mapping is present for this ds ("+dsIdx+") at the moment.") } }, @@ -149,8 +193,9 @@ module.exports = NodeHelper.create({ self.getStreamUrls() } else if (notification === "SYNO_SS_CHANGE_CAM"){ self.sendSocketNotification(notification,payload) - } else if (notification === "SYNO_SS_CHANGE_POSITION"){ - self.goPosition(payload.dsIdx, payload.camId, payload.position) + } else if (notification === "DS_CHANGE_POSITION"){ + console.log("Changing position of cam: "+payload.camName+" of ds: "+payload.dsIdx+" to: "+payload.position) + self.goPosition(payload.dsIdx, payload.camName, payload.position) } } }) diff --git a/synology-surveillance_h.css b/synology-surveillance_h.css index 75e8e20..a85f2e5 100644 --- a/synology-surveillance_h.css +++ b/synology-surveillance_h.css @@ -1,9 +1,12 @@ .synology-surveillance { --cam-bg-color: #2b2c30; --cam-name-bg-color: #1b1b1c; + --postion-color: #5e5f63; + --position-selected-color: #1b1b1c; --cam-wrapper-border-radius: 5px; --cam-border-radius: 5px; --name-border-radius: 5px; + --position-border-radius: 3px; --padding-camWrapper: 5px; --cam-width: 200px; --cam-min-height: calc(var(--cam-width) /1.33); @@ -16,12 +19,46 @@ --icon-postion: calc(var(--cam-min-height)/2 - 25px); --icon-big-position: calc(var(--cam-big-min-height)/2 - 25px); + --position-size: 10px; + --position-big-size: calc(var(--position-size) * 2); + --position-margin: 5px 5px 5px 5px; + justify-content: flex-start; align-items: center; display: flex; flex-wrap: wrap; } +.innerPositionWrapper { + justify-content: center; + align-items: center; + display: flex; + flex-wrap: wrap;; +} + +.position { + margin: var(--position-margin); + padding: 5px; + height: var(--position-size); + width: var(--position-size); + background-color: var(--postion-color); + border-radius: var(--position-border-radius); +} + +.position.big { + height: var(--position-big-size); + width: var(--position-big-size); +} + +.position .selected { + width: 100%; + min-width: 100%; + height: 100%; + min-height: 100%; + border-radius: var(--position-border-radius); + background-color: var(--position-selected-color); +} + .camWrapper { background-color: var(--cam-bg-color); border-radius: var(--cam-wrapper-border-radius); diff --git a/synology-surveillance_v.css b/synology-surveillance_v.css index 96eb836..019c77a 100644 --- a/synology-surveillance_v.css +++ b/synology-surveillance_v.css @@ -2,9 +2,12 @@ --column-cnt: 2; --cam-bg-color: #2b2c30; --cam-name-bg-color: #1b1b1c; + --postion-color: #5e5f63; + --position-selected-color: #1b1b1c; --cam-wrapper-border-radius: 5px; --cam-border-radius: 5px; --name-border-radius: 5px; + --position-border-radius: 3px; --padding-camWrapper: 5px; --cam-width: 200px; --cam-min-height: calc(var(--cam-width) /1.33); @@ -17,6 +20,10 @@ --icon-postion: calc(var(--cam-min-height)/2 - 25px); --icon-big-position: calc(calc(var(--cam-big-min-height)/2) - 25px); + --position-size: 10px; + --position-big-size: calc(var(--position-size) * 2); + --position-margin: 5px 5px 5px 5px; + --width-noSpace: calc(var(--cam-width) * var(--column-cnt)); width: calc(calc(calc(var(--column-cnt) * 3)*var(--padding-camWrapper)) + var(--width-noSpace)); @@ -27,6 +34,36 @@ flex-wrap: wrap; } +.innerPositionWrapper { + justify-content: center; + align-items: center; + display: flex; + flex-wrap: wrap;; +} + +.position { + margin: var(--position-margin); + padding: 5px; + height: var(--position-size); + width: var(--position-size); + background-color: var(--postion-color); + border-radius: var(--position-border-radius); +} + +.position.big { + height: var(--position-big-size); + width: var(--position-big-size); +} + +.position .selected { + width: 100%; + min-width: 100%; + height: 100%; + min-height: 100%; + border-radius: var(--position-border-radius); + background-color: var(--position-selected-color); +} + .camWrapper { background-color: var(--cam-bg-color); border-radius: var(--cam-wrapper-border-radius);