@@ -6,6 +6,7 @@ local nameOfModule = 'CSK_MultiRemoteCamera'
66-- If App property "LuaLoadAllEngineAPI" is FALSE, use this to load and check for required APIs
77-- This can improve performance of garbage collection
88local availableAPIs = require (' Sensors/MultiRemoteCamera/helper/checkAPIs' ) -- can be used to adjust function scope of the module related on available APIs of the device
9+ local json = require (' Sensors/MultiRemoteCamera/helper/Json' )
910---- -------------------------------------------------------
1011-- Logger
1112_G .logger = Log .SharedLogger .create (' ModuleLogger' )
@@ -18,6 +19,11 @@ local viewerId = scriptParams:get('viewerId') -- Viewer ID
1819local lastImage = nil -- holds image to post process (e.g. after changing parameters)
1920local lastTimestamp = DateTime .getTimestamp () -- timestamp to calculate processing time
2021local fpsCounter = 0 -- counter to calculate FPS
22+ local secIP = ' 192.168.136.100' -- IP of SEC100 camera
23+
24+ local queue = Script .Queue .create () -- Queue to stop SEC100 streaming processing if increasing too much
25+ queue :setPriority (" MID" )
26+ queue :setMaxQueueSize (1 )
2127
2228-- See parameter documenation within Model
2329local imageProcessingParams = {}
@@ -31,12 +37,18 @@ imageProcessingParams.saveAllImages = scriptParams:get('saveAllImages')
3137imageProcessingParams .imageSaveFormat = scriptParams :get (' imageSaveFormat' )
3238imageProcessingParams .imageSaveJpgFormatCompression = scriptParams :get (' imageSaveJpgFormatCompression' )
3339imageProcessingParams .imageSavePngFormatCompression = scriptParams :get (' imageSavePngFormatCompression' )
40+ imageProcessingParams .httpClientInstance = scriptParams :get (' httpClientInstance' )
41+ imageProcessingParams .secUser = scriptParams :get (' secUser' )
42+ imageProcessingParams .secUserPassword = scriptParams :get (' secUserPassword' )
43+ imageProcessingParams .secMode = scriptParams :get (' secMode' )
44+ imageProcessingParams .secWebSocketClientInstance = scriptParams :get (' secWebSocketClientInstance' )
3445
3546imageProcessingParams .activeInUI = false -- Is this instance currently selected in UI
3647imageProcessingParams .viewerActive = false -- Should the image be shown in viewer
3748
3849local viewer = View .create (viewerId ) -- Viewer to show image
3950local imageQueue = Script .Queue .create () -- Queue to stop processing if increasing too much
51+ local jpeg = Image .Format .JPEG .create () -- Image decoder for SEC100 images
4052
4153-- Event to forward image to other modules
4254Script .serveEvent (" CSK_MultiRemoteCamera.OnNewImageCamera" .. cameraNumberString , " MultiRemoteCamera_OnNewImageCamera" .. cameraNumberString , ' object:1:Image, int:?' )
@@ -190,6 +202,101 @@ local function deregisterCamera(camera)
190202end
191203Script .register (" CSK_MultiRemoteCamera.OnDeregisterCamera" .. cameraNumberString , deregisterCamera )
192204
205+ -- #############################################
206+ -- ################### SEC100 ##################
207+ -- #############################################
208+
209+ local function buildDigest (_table )
210+ local hash = Hash .SHA256 .create ()
211+ hash :update (table.concat (_table , " :" ) )
212+ return hash :getHashValueHex ()
213+ end
214+
215+ local function computeResponseHash (challenge , action , user , password )
216+ local nonce = challenge .nonce
217+ local ha1 , ha2
218+ if challenge .salt == nil then
219+ ha1 = buildDigest ({user , challenge .realm , password })
220+ else
221+ local saltStr = " "
222+ for _ , i in ipairs (challenge .salt ) do
223+ saltStr = saltStr .. string.char (i )
224+ end
225+ ha1 = buildDigest ({user , challenge .realm , password , saltStr })
226+ end
227+ ha2 = buildDigest ({" POST" , action })
228+ return buildDigest ({ha1 , nonce , ha2 })
229+ end
230+
231+ --- Function to trigger SEC camera
232+ --- @param command string Command to send to SEC camera
233+ --- @param data string Data for command
234+ --- @return bool suc Success of trigger
235+ local function triggerSEC (command , data )
236+
237+ local _ , challengeResponse = Script .callFunction (' CSK_MultiHTTPClient.sendRequest' .. tostring (imageProcessingParams .httpClientInstance ), ' POST' , ' http://' .. secIP .. ' /api/getChallenge' , 80 , nil , ' {"data":{"user": "' .. imageProcessingParams .secUser .. ' "}}' , ' application/json' )
238+ local challengeResponseContent = json .decode (challengeResponse )
239+ if challengeResponseContent .Response then
240+
241+ local response = json .decode (challengeResponseContent .Response )
242+
243+ if response .challenge then
244+ local responseHash = computeResponseHash (response .challenge , command , imageProcessingParams .secUser , imageProcessingParams .secUserPassword )
245+ local requestBody
246+
247+ if data then
248+ requestBody = ' {"header":{"user":"' .. imageProcessingParams .secUser .. ' ","response":"' .. responseHash .. ' ","realm":"SICK Sensor","opaque":"' .. response .challenge .opaque .. ' ","nonce":"' .. response .challenge .nonce .. ' "},' .. data .. ' }'
249+ else
250+ requestBody = ' {"header":{"user":"' .. imageProcessingParams .secUser .. ' ","response":"' .. responseHash .. ' ","realm":"SICK Sensor","opaque":"' .. response .challenge .opaque .. ' ","nonce":"' .. response .challenge .nonce .. ' "}}'
251+ end
252+
253+ local requestResponse
254+ local responseData
255+ if command == ' latestSnapshot' then
256+ _ , requestResponse = Script .callFunction (' CSK_MultiHTTPClient.sendRequest' .. tostring (imageProcessingParams .httpClientInstance ), ' POST' , ' http://' .. secIP .. ' /file/download/' .. command , 80 , nil , requestBody , ' image/jpeg' )
257+ responseData = json .decode (requestResponse )
258+ if responseData .StatusCode == 200 then
259+ local img = jpeg :decode (responseData .Response )
260+ handleOnNewImageProcessing (img )
261+ return true
262+ else
263+ _G .logger :warning (nameOfModule .. " : Request did not work." )
264+ return false
265+ end
266+ else
267+ _ , requestResponse = Script .callFunction (' CSK_MultiHTTPClient.sendRequest' .. tostring (imageProcessingParams .httpClientInstance ), ' POST' , ' http://' .. secIP .. ' /api/' .. command , 80 , nil , requestBody , ' application/json' )
268+ responseData = json .decode (requestResponse )
269+ if responseData .StatusCode ~= 200 then
270+ _G .logger :warning (nameOfModule .. " : Request did not work." )
271+ return false
272+ else
273+ return true
274+ end
275+ end
276+ else
277+ _G .logger :warning (nameOfModule .. " : Request challenge did not work." )
278+ return false
279+ end
280+ else
281+ return false
282+ end
283+ end
284+
285+ --- Function to unpack image out of binary data (e.g. received by SEC100)
286+ --- @param data binary Data
287+ --- @param format enum Message format.
288+ local function unpackBinaryImage (data , format )
289+ if format == ' BINARY' then
290+ local img = jpeg :decode (data )
291+ handleOnNewImageProcessing (img )
292+ end
293+ end
294+ queue :setFunction (unpackBinaryImage )
295+
296+ -- #############################################
297+ -- ################ SEC100 END #################
298+ -- #############################################
299+
193300--- Function to handle updates of processing parameters from Controller
194301--- @param cameraNo int Number of camera instance to update
195302--- @param parameter string Parameter to update
@@ -204,6 +311,37 @@ local function handleOnNewImageProcessingParameter(cameraNo, parameter, value)
204311 elseif cameraNo == cameraNumber then
205312 if parameter == ' saveLastImage' then
206313 saveImage (lastImage )
314+ elseif parameter == ' secWebSocketClientInstance' then
315+ -- Script.deregister('CSK_MultiWebSocketClient.OnNewData' .. tostring(imageProcessingParams.secWebSocketClientInstance), unpackBinaryImage)
316+ imageProcessingParams .secWebSocketClientInstance = value
317+ elseif parameter == ' SEC100_IP' then
318+ secIP = value
319+ elseif parameter == ' secMode' then
320+ if value == ' Snapshot' then
321+ local suc = triggerSEC (' SnapshotMode' , ' "data":{"SnapshotMode": 1}' )
322+ if not suc then
323+ CSK_MultiRemoteCamera .disconnectCamera ()
324+ end
325+ elseif value == ' Stream' then
326+ triggerSEC (' SnapshotMode' , ' "data":{"SnapshotMode": 0}' )
327+ local suc = triggerSEC (' EventTriggerEvent' )
328+ if not suc then
329+ CSK_MultiRemoteCamera .disconnectCamera ()
330+ end
331+ Script .register (' CSK_MultiWebSocketClient.OnNewData' .. tostring (imageProcessingParams .secWebSocketClientInstance ), unpackBinaryImage )
332+ queue :setFunction (unpackBinaryImage )
333+ end
334+ elseif parameter == ' secStream' then
335+ if value == false then
336+ Script .deregister (' CSK_MultiWebSocketClient.OnNewData' .. tostring (imageProcessingParams .secWebSocketClientInstance ), unpackBinaryImage )
337+ else
338+ Script .register (' CSK_MultiWebSocketClient.OnNewData' .. tostring (imageProcessingParams .secWebSocketClientInstance ), unpackBinaryImage )
339+ queue :setFunction (unpackBinaryImage )
340+ end
341+ elseif parameter == ' SEC100_Trigger' then
342+ triggerSEC (' SnapshotTriggerSnapshot' )
343+ Script .sleep (200 )
344+ triggerSEC (' latestSnapshot' )
207345 else
208346 if not parameter == ' activeInUI' then
209347 _G .logger :fine (nameOfModule .. " : Update parameter '" .. parameter .. " ' of cameraNo." .. tostring (cameraNo ) .. " to value = " .. tostring (value ))
0 commit comments