diff --git a/data/index.html b/data/index.html index 5f29818..534e1d8 100644 --- a/data/index.html +++ b/data/index.html @@ -22,18 +22,18 @@ --> Huebner Inverter Management Console - - - - - - - - - - - - + + + + + + + + + + + + @@ -392,6 +392,7 @@

Spot Values

+ diff --git a/data/inverter.js b/data/inverter.js index 596343b..df04ca6 100644 --- a/data/inverter.js +++ b/data/inverter.js @@ -67,9 +67,10 @@ var paramsCache = { var inverter = { firmwareVersion: 0, + paramListRequestPending: false, /** @brief send a command to the inverter */ - sendCmd: function(cmd, replyFunc, repeat) + sendCmd: function(cmd, replyFunc, repeat, doneFunc) { var xmlhttp=new XMLHttpRequest(); var req = "/cmd?cmd=" + cmd; @@ -92,6 +93,7 @@ var inverter = { if ( paramsCache.failedFetchCount < 2 && typeof ui !== 'undefined') { ui.hideCommunicationErrorBar(); } + if (doneFunc) doneFunc(xmlhttp.status); } } @@ -105,6 +107,11 @@ var inverter = { /** @brief get the params from the inverter */ getParamList: function(replyFunc, includeHidden) { + if (inverter.paramListRequestPending) { + return false; + } + + inverter.paramListRequestPending = true; var cmd = includeHidden ? "json hidden" : "json"; inverter.sendCmd(cmd, function(reply) { @@ -124,7 +131,14 @@ var inverter = { paramsCache.setData(params); if (replyFunc) replyFunc(params); + }, undefined, function() { + inverter.paramListRequestPending = false; + if (typeof ui !== 'undefined') { + ui.refreshPending = false; + } }); + + return true; }, /** @brief get CAN mapping from the inverter - only meant for wifi <-> can bridge */ diff --git a/data/style.css b/data/style.css index b2d9717..cc0efac 100644 --- a/data/style.css +++ b/data/style.css @@ -322,6 +322,40 @@ tr:hover { height: 90vh; } +#spotValues { + width: auto; + max-width: 100%; + display: inline-table; + vertical-align: top; +} + +#spotValues td, +#spotValues th { + padding: 7px 12px; +} + +#spotValues th:first-child, +#spotValues td:first-child { + width: 24px; + padding-left: 8px; + padding-right: 8px; +} + +#spotValues th:nth-child(2), +#spotValues td:nth-child(2) { + min-width: 24rem; +} + +#spotValues th:nth-child(3), +#spotValues td:nth-child(3) { + min-width: 12rem; +} + +#spotValues th:nth-child(4), +#spotValues td:nth-child(4) { + min-width: 6rem; +} + /* content */ #content { diff --git a/data/ui.js b/data/ui.js index 96bcdd8..3147c71 100644 --- a/data/ui.js +++ b/data/ui.js @@ -23,16 +23,19 @@ var ui = { // The API endpoint to query to get firmware release available in Github githubFirmwareReleaseURL: 'https://api.github.com/repos/jsphuebner/stm32-sine/releases', - //Handle for auto refresh interval + //Handle for auto refresh interval autoRefreshHandle: 0, + refreshPending: false, // temp variable to store updates from Parameter Database paramUpdates: "", + webVersion: "2.2.4", // Status of visibility of parameter categories. E.g. Motor, Inverter. true = visible, false = not visible. categoryVisible: {}, navbarIsBig: true, + activePage: "dashboard", shrinkNavbar: function() { document.getElementById("navbar").style.width = "60px"; @@ -105,6 +108,7 @@ var ui = { // show selected tab document.getElementById(pageName).style.display = "flex"; elmnt.style.backgroundColor = color; + ui.activePage = pageName; // Right menu has nothing in it for spot values, so hide it var mainRights = document.getElementsByClassName("main-right"); @@ -165,9 +169,18 @@ var ui = { /** @brief automatically update data on the UI */ refresh: function() { - ui.updateTables(); - ui.refreshStatusBox(); - ui.refreshMessagesBox(); + if (ui.refreshPending) { + return; + } + + if (ui.activePage === "spotvalues") { + ui.refreshSpotValues(); + } + else { + ui.updateTables(); + ui.refreshStatusBox(); + ui.refreshMessagesBox(); + } }, getNodeId: function() { @@ -225,6 +238,7 @@ var ui = { } document.getElementById("spinner-div").style.visibility = "visible"; + ui.refreshPending = true; inverter.getParamList(function(values) { @@ -232,6 +246,8 @@ var ui = { var tableSpot = document.getElementById("spotValues"); var lastCategory = ""; var params = {}; + var spotValueGroups = {}; + var spotValueGroupOrder = []; while (tableParam.rows.length > 1) tableParam.deleteRow(1); while (tableSpot.rows.length > 1) tableSpot.deleteRow(1); @@ -313,8 +329,13 @@ var ui = { } else { - var checkHtml = ' l'; - checkHtml += ' r'; + var separatorIndex = name.indexOf('_'); + var spotCategory = separatorIndex > 0 ? name.substring(0, separatorIndex) : "General"; + var spotName = separatorIndex > 0 ? name.substring(separatorIndex + 1) : name; + if (!spotValueGroups[spotCategory]) { + spotValueGroups[spotCategory] = []; + spotValueGroupOrder.push(spotCategory); + } var unit = param.unit; if (param.enums) @@ -340,7 +361,32 @@ var ui = { display = param.value; } - ui.addRow(tableSpot, [ nameWithTooltip, display, unit ], true); + var spotNameWithTooltip = nameWithTooltip; + if (spotNameWithTooltip === name) { + spotNameWithTooltip = spotName; + } else { + spotNameWithTooltip = "
" + spotName + "" + docstring + "
"; + } + + spotValueGroups[spotCategory].push({ + name: name, + displayName: spotNameWithTooltip, + displayValue: display, + unit: unit + }); + } + } + + for (var groupIdx = 0; groupIdx < spotValueGroupOrder.length; groupIdx++) + { + var groupName = spotValueGroupOrder[groupIdx]; + ui.addRow(tableSpot, [ "" ], true); + + for (var itemIdx = 0; itemIdx < spotValueGroups[groupName].length; itemIdx++) + { + var spotValue = spotValueGroups[groupName][itemIdx]; + var spotRow = ui.addRow(tableSpot, [ "", spotValue.displayName, spotValue.displayValue, spotValue.unit ], true); + spotRow.dataset.spotValue = spotValue.name; } } ui.populateVersion(); @@ -348,7 +394,12 @@ var ui = { document.getElementById("paramDownload").href = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(params, null, 2)); document.getElementById("spinner-div").style.visibility = "hidden"; + ui.refreshPending = false; }); + + if (!inverter.paramListRequestPending) { + ui.refreshPending = false; + } }, /** @brief Adds row to a table @@ -368,6 +419,8 @@ var ui = { cell.colSpan = colSpan; cell.innerHTML = content[i]; } + + return tr; }, /** @brief fill out version box in the bottom left corner of the screen */ @@ -377,7 +430,7 @@ var ui = { versionDiv.innerHTML = ""; var firmwareVersion = String(paramsCache.get('version')); versionDiv.innerHTML += "firmware : " + firmwareVersion + "
"; - versionDiv.innerHTML += "web : v2.2" + versionDiv.innerHTML += "web : v" + ui.webVersion; }, /** @brief If beta features are visible, hide them. If hidden, show them. */ @@ -1115,6 +1168,48 @@ var ui = { * ~~~ SPOT VALUES ~~~ */ + getSelectedSpotValueNames: function() + { + var selected = []; + var rows = document.querySelectorAll('#spotBody tr[data-spot-value]'); + for (var i = 0; i < rows.length; i++) + { + selected.push(rows[i].dataset.spotValue); + } + return selected; + }, + + refreshSpotValues: function() + { + var selected = ui.getSelectedSpotValueNames(); + if (!selected.length) { + return; + } + + inverter.getValues(selected, 1, function(values) + { + for (var i = 0; i < selected.length; i++) + { + var name = selected[i]; + if (!values[name] || !values[name].length) { + continue; + } + var entry = paramsCache.getEntry(name); + if (entry) { + entry.value = values[name][0]; + } + var displayValue = values[name][0]; + if (entry && entry.enums && entry.enums[displayValue] !== undefined) { + displayValue = entry.enums[displayValue]; + } + var row = document.querySelector('#spotBody tr[data-spot-value="' + name + '"]'); + if (row && row.cells.length > 2) { + row.cells[2].textContent = displayValue; + } + } + }); + }, + /** * ~~~ PLOT & GAUGE ~~~
Name Value Unit