diff --git a/Dockerfile b/Dockerfile index 6795a04..7089253 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,6 +31,8 @@ RUN . /opt/axis/acapsdk/environment-setup* && \ # Build ACAP package WORKDIR "$ACAP_BUILD_DIR" +COPY html/ ./html +ADD https://code.jquery.com/jquery-3.7.1.min.js ./html/js/jquery.min.js COPY LICENSE \ Makefile \ manifest.json \ diff --git a/html/config.html b/html/config.html new file mode 100644 index 0000000..e68fc2a --- /dev/null +++ b/html/config.html @@ -0,0 +1,92 @@ + + + + + + Modbus ACAP Configuration + + + +
+ +
+

Modbus ACAP Configuration

+ + + + + + + +
Application mode + + + +
Modbus TCP/IP port
+ +
+

Modbus server

+ + +

AOA Scenarios

+ + + + + + +
NameID no.Type
+ +

Scenario selected for Modbus output

+ +
+ + + + + + \ No newline at end of file diff --git a/html/js/modbusconfig.js b/html/js/modbusconfig.js new file mode 100644 index 0000000..9315450 --- /dev/null +++ b/html/js/modbusconfig.js @@ -0,0 +1,128 @@ +var params = {}; +var scenarios = {}; +const appname = 'Modbusacap'; +const parambaseurl = '/axis-cgi/param.cgi?action='; +const paramgeturl = parambaseurl + 'list&group= ' + appname + '.'; +const paramseturl = parambaseurl + 'update&' + appname + '.'; +const scenariourl = '/local/objectanalytics/control.cgi'; +const table = document.getElementById("scenarios"); +const port = document.getElementById("port"); +const server = document.getElementById("server"); +const clientcfg = document.getElementById("clientcfg"); +const modeselection = document.getElementById("modeselection"); +const scenarioselection = document.getElementById("scenarioselection"); +const UpdateInterval = 5; +const SERVER = 0; +const CLIENT = 1; + +function portChange(newport) { + setNewValue('Port', newport); +} + +function modeChange(newmode, setparam = true) { + if (setparam) { + setNewValue('Mode', newmode); + } + switch (+newmode) { + case SERVER: + clientcfg.style.display = 'none'; + break; + case CLIENT: + clientcfg.style.display = 'block'; + break; + default: + console.error('Unknown application mode: ' + newmode); + } +} + +function serverChange(newserver) { + setNewValue('Server', newserver); +} + +function scenarioChange(newscenario) { + setNewValue('Scenario', newscenario); +} + +function updateScenarioTable() { + for (let i = table.rows.length - 1; i > 0; i--) { + table.deleteRow(i); + } + for (const scenario of scenarios) { + const row = table.insertRow(); + var i = 0; + const nameCell = row.insertCell(i++); + const idCell = row.insertCell(i++); + const typeCell = row.insertCell(i++); + + idCell.innerText = scenario.id; + nameCell.innerText = scenario.name; + typeCell.innerText = scenario.type.replace(/([A-Z])/g, ' $1').toLowerCase(); + } +} + +function updateScenarioSelection() { + while (scenarioselection.options.length > 0) { + scenarioselection.remove(0); + } + for (const scenario of scenarios) { + scenarioselection.add(new Option(`${scenario.name} (ID: ${scenario.id})`, scenario.id)); + } + scenarioselection.value = +(params['Scenario']); +} + +async function getScenarios() { + try { + const scenarioData = await $.post({ + url: scenariourl, + headers: { + 'Content-Type': 'application/json' + }, + data: '{"apiVersion": "1.2", "method": "getConfiguration"}' + }); + scenarios = scenarioData.data.scenarios; + for (i in scenarioData.data.scenarios) { + console.log('scenario id: ' + scenarios[i].id + ', scenario name: ' + scenarios[i].name + ', type: ' + scenarios[i].type); + } + updateScenarioTable(); + } catch (error) { + alert('Failed to get scenario info from AOA'); + console.error('Failed to get scenario info from AOA: ', error) + } +} + +async function getCurrentValue(param) { + try { + const paramData = await $.get(paramgeturl + param); + params[param] = paramData.split('=')[1]; + console.log('Got ' + param + ' value ' + params[param]); + } catch (error) { + alert('Failed to get parameter ' + param); + } +} + +async function setNewValue(param, value) { + try { + await $.get(paramseturl + param + '=' + value); + params[param] = value; + console.log('Set ' + param + ' value to ' + value); + } catch (error) { + alert('Failed to set parameter ' + param); + } +} + +async function updateValues() { + await getCurrentValue('Mode'); + await getCurrentValue('Port'); + await getCurrentValue('Scenario'); + await getCurrentValue('Server'); + await getScenarios(); + modeChange(+(params['Mode']), false); + modeselection.value = +(params['Mode']); + port.value = +(params['Port']); + updateScenarioSelection(); + server.value = params['Server']; + console.log('Will call again in ' + UpdateInterval + ' seconds to make sure we are in sync with device'); + setTimeout(updateValues, 1000 * UpdateInterval); +} + +updateValues(); diff --git a/manifest.json b/manifest.json index dac7e1c..02f70ec 100644 --- a/manifest.json +++ b/manifest.json @@ -7,9 +7,10 @@ "vendor": "Axis Communications AB", "embeddedSdkVersion": "3.0", "runMode": "respawn", - "version": "1.2.0" + "version": "1.2.1" }, "configuration": { + "settingPage": "config.html", "paramConfig": [ {"name": "Mode", "type": "enum:0|Server, 1|Client", "default": "0"}, {"name": "Port", "type": "int:min=1024,max=65535", "default": "5020"},