initial working status (overview for each device)
This commit is contained in:
+243
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* main.js
|
||||
*
|
||||
* This file is part of the VE.Direct web UI
|
||||
* https://git.schauaus.at/VE-Tools/VE.Direct-webui
|
||||
* It is licensed under the GPL3.0 or later.
|
||||
* You should have received a copy of the license with this software
|
||||
*/
|
||||
|
||||
var deviceDataParsed = false
|
||||
var deviceDataSet = {}
|
||||
var deviceDataTimer;
|
||||
var deviceIds = {}
|
||||
var devices = [];
|
||||
var deviceTimer;
|
||||
var i18n = {}
|
||||
var lang = 'de'
|
||||
|
||||
function checkFile(url) {
|
||||
let xhr = new XMLHttpRequest()
|
||||
xhr.open('HEAD', url, false);
|
||||
xhr.send()
|
||||
return xhr.status !==404
|
||||
}
|
||||
|
||||
function fileReadJson(ReturnFunction, url, params = "") {
|
||||
let xhr = new XMLHttpRequest()
|
||||
xhr.onload = function () {
|
||||
if(xhr.status == 200)
|
||||
ReturnFunction(xhr.response)
|
||||
else return false
|
||||
}
|
||||
xhr.onerror = function() { return false }
|
||||
xhr.open('POST', url, true)
|
||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
xhr.responseType = 'json'
|
||||
xhr.send(params)
|
||||
}
|
||||
|
||||
function getDeviceData(device) {
|
||||
if(!device.startsWith('0x')) //check if device ID is valid
|
||||
return false
|
||||
fileReadJson(parseDeviceData, './dbQuery.php', 'q=deviceData&device=' + device)
|
||||
}
|
||||
|
||||
function getDeviceIds() {
|
||||
let xhr = new XMLHttpRequest()
|
||||
xhr.onload = function() {
|
||||
if(xhr.status === 200)
|
||||
deviceIds = xhr.response
|
||||
}
|
||||
xhr.open('GET', './deviceIds.json', true)
|
||||
xhr.responseType = 'json'
|
||||
xhr.send()
|
||||
}
|
||||
|
||||
function getDevices() {
|
||||
if(Object.keys(deviceIds).length < 1) return
|
||||
if(Object.keys(i18n).lenght < 1) return
|
||||
clearInterval(deviceTimer)
|
||||
let xhr = new XMLHttpRequest()
|
||||
xhr.onload = function() {
|
||||
if(xhr.status != 200) { // error handling
|
||||
devices = false
|
||||
}
|
||||
else { //process data
|
||||
devices = []
|
||||
for(let i=0; i<xhr.response.length; i++) {
|
||||
devices.push(xhr.response[i][0])
|
||||
}
|
||||
renderDeviceList()
|
||||
}
|
||||
}
|
||||
xhr.onerror = function() {
|
||||
devices = false
|
||||
}
|
||||
xhr.open("POST", "dbQuery.php", true);
|
||||
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
xhr.responseType = 'json'
|
||||
xhr.send("q=devices");
|
||||
}
|
||||
|
||||
function getLang(i18n_data) {
|
||||
i18n[lang] = i18n_data
|
||||
}
|
||||
|
||||
function initialize () {
|
||||
getDeviceIds()
|
||||
fileReadJson(getLang, './i18n/' + lang + '.json')
|
||||
deviceTimer = setInterval( getDevices, 100)
|
||||
document.getElementById('liDashboard').addEventListener("click", showDevice)
|
||||
}
|
||||
|
||||
function parseDeviceData(data) {
|
||||
deviceDataParsed = false
|
||||
deviceDataSet = {}
|
||||
for(let i=0; i < data.length; i++) {
|
||||
let date = data[i][0]
|
||||
let time = data[i][1]
|
||||
let dataPoint = data[i][2]
|
||||
|
||||
let year = date.split('-')[0]
|
||||
let month = date.split('-')[1]
|
||||
let day = date.split('-')[2]
|
||||
|
||||
if(!deviceDataSet[year])
|
||||
deviceDataSet[year] = {}
|
||||
if(!deviceDataSet[year][month])
|
||||
deviceDataSet[year][month] = {}
|
||||
if(!deviceDataSet[year][month][day])
|
||||
deviceDataSet[year][month][day] = {}
|
||||
deviceDataSet[year][month][day][time] = JSON.parse(dataPoint)
|
||||
}
|
||||
deviceDataParsed = true
|
||||
}
|
||||
|
||||
function renderDeviceDetails(device) {
|
||||
let deviceName = device.split('-')[0]
|
||||
let deviceSN = device.split('-')[1]
|
||||
|
||||
document.getElementById('deviceDetailsName').innerHTML = ""
|
||||
document.getElementById('deviceDetailsSN').innerHTML = ""
|
||||
document.getElementById('deviceDetailsProductImage').src = ""
|
||||
|
||||
//load product images
|
||||
let deviceImagePath = './images/' + deviceName
|
||||
if( checkFile(deviceImagePath + '.jpg') )
|
||||
deviceImagePath += '.jpg'
|
||||
else if( checkFile(deviceImagePath + '.png') )
|
||||
deviceImagePath += '.png'
|
||||
if( deviceImagePath.endsWith('.jpg') || deviceImagePath.endsWith('.png') )
|
||||
document.getElementById('deviceDetailsProductImage').src = deviceImagePath
|
||||
|
||||
//set basic information about the device
|
||||
document.getElementById('deviceDetailsName').innerHTML = deviceIds[deviceName]
|
||||
document.getElementById('deviceDetailsSN').innerHTML = i18n[lang]['serialNumber'] + ": " + deviceSN
|
||||
|
||||
//query device data from database and store it in global variable
|
||||
deviceDataParsed = false
|
||||
deviceDataSet = {}
|
||||
getDeviceData(device)
|
||||
|
||||
//view data on frontend
|
||||
deviceDataTimer = setInterval(showDeviceData, 100)
|
||||
}
|
||||
|
||||
function renderDeviceList() {
|
||||
for(let i=0; i < devices.length; i++) {
|
||||
let device = devices[i].split('-')[0]
|
||||
let sn = devices[i].split('-')[1]
|
||||
let classStyle = (i % 2) ? 'bright' : 'dark'
|
||||
|
||||
let block = document.createElement('div')
|
||||
block.classList.add('padding')
|
||||
block.classList.add(classStyle)
|
||||
block.id = 'li' + devices[i]
|
||||
|
||||
let productImage = document.createElement('img')
|
||||
let productImagePath = './images/' + device
|
||||
if( checkFile(productImagePath + '.jpg') )
|
||||
productImage.src = productImagePath + '.jpg'
|
||||
else if( checkFile(productImagePath + '.png') )
|
||||
productImage.src = productImagePath + '.png'
|
||||
|
||||
if(productImage.src) {
|
||||
productImage.classList.add('productImageSmall')
|
||||
block.appendChild(productImage)
|
||||
}
|
||||
document.getElementById('productList').appendChild(block)
|
||||
|
||||
block.append(deviceIds[device])
|
||||
block.innerHTML += "<br>\r\n<small>" + i18n[lang]['serialNumber'] + ': ' + sn + '<small>'
|
||||
block.addEventListener("click", showDevice)
|
||||
}
|
||||
}
|
||||
|
||||
function showDevice(event) {
|
||||
let deviceName = event.currentTarget.id.substr(2)
|
||||
if(deviceName == "Dashboard") {
|
||||
document.getElementById('deviceDetails').style.display = "none" //hide device details
|
||||
document.getElementById('dashboard').style.display = "inline-block"
|
||||
}
|
||||
else {
|
||||
document.getElementById('dashboard').style.display = "none" //hide dashboard
|
||||
|
||||
//cleanup device details
|
||||
let deviceDetailNode = document.getElementById('deviceDetails')
|
||||
while(deviceDetailNode.children.length > 3)
|
||||
deviceDetailNode.removeChild( deviceDetailNode.children[ deviceDetailNode.children.length - 1 ] )
|
||||
|
||||
//show device data block and fill in the details
|
||||
document.getElementById('deviceDetails').style.display = "inline-block"
|
||||
renderDeviceDetails(deviceName)
|
||||
}
|
||||
}
|
||||
|
||||
function showDeviceData() {
|
||||
if(!deviceDataParsed) return
|
||||
clearInterval(deviceDataTimer)
|
||||
|
||||
//parse years, months, days and timestamps
|
||||
let years = Object.keys(deviceDataSet)
|
||||
years.sort()
|
||||
let latestYear = years[years.length - 1]
|
||||
let months = Object.keys(deviceDataSet[latestYear])
|
||||
months.sort()
|
||||
let latestMonth = months[months.length - 1]
|
||||
let days = Object.keys(deviceDataSet[latestYear][latestMonth])
|
||||
days.sort()
|
||||
let latestDay = days[days.length - 1]
|
||||
let timestamps = Object.keys( deviceDataSet[latestYear][latestMonth][latestDay] )
|
||||
timestamps.sort()
|
||||
let latestTimestamp = timestamps[timestamps.length - 1]
|
||||
let latestDataPoint = document.createElement('div')
|
||||
latestDataPoint.innerHTML = i18n[lang]['latestDataPoint'] + ': ' + latestYear + '-' + latestMonth + '-' + latestDay + ' ' + latestTimestamp
|
||||
document.getElementById('deviceDetails').appendChild(latestDataPoint)
|
||||
|
||||
//parse latest datapoint regarding system power, system voltage, solar power, solar voltage
|
||||
let latestDataSet = deviceDataSet[latestYear][latestMonth][latestDay][latestTimestamp]
|
||||
let latestPowerData = document.createElement('table')
|
||||
if(latestDataSet['PPV'])
|
||||
latestPowerData.innerHTML += '<tr><td>' + i18n[lang]['datafield_PPV'] + ': ' + latestDataSet['PPV'] + 'W' + '</td></tr>'
|
||||
if(latestDataSet['VPV'])
|
||||
latestPowerData.innerHTML += '<tr><td>' + i18n[lang]['datafield_VPV'] + ': ' + parseInt(latestDataSet['VPV']) / 1000 + 'V' + '</td></tr>'
|
||||
if(latestDataSet['V'])
|
||||
latestPowerData.innerHTML += '<tr><td>' + i18n[lang]['datafield_V'] + ': ' + parseInt(latestDataSet['V']) / 1000 + 'V' + '</td></tr>'
|
||||
if(latestDataSet['I'])
|
||||
latestPowerData.innerHTML += '<tr><td>' + i18n[lang]['datafield_I'] + ': ' + parseInt(latestDataSet['I']) / 1000 + 'A' + '</td></tr>'
|
||||
if(latestDataSet['P'])
|
||||
latestPowerData.innerHTML += '<tr><td>' + i18n[lang]['datafield_P'] + ': ' + latestDataSet['P'] + 'W' + '</td></tr>'
|
||||
if(latestDataSet['H20'])
|
||||
latestPowerData.innerHTML += '<tr><td>' + i18n[lang]['datafield_H20'] + ': ' + parseInt(latestDataSet['H20']) * 0.01 + 'kWh' + '</td></tr>'
|
||||
if(latestDataSet['H22'])
|
||||
latestPowerData.innerHTML += '<tr><td>' + i18n[lang]['datafield_H22'] + ': ' + parseInt(latestDataSet['H22']) / 100 + 'kWh' + '</td></tr>'
|
||||
if(latestDataSet['H19'])
|
||||
latestPowerData.innerHTML += '<tr><td>' + i18n[lang]['datafield_H19'] + ': ' + parseInt(latestDataSet['H19']) / 100 + 'kWh' + '</td></tr>'
|
||||
if(latestDataSet['H21'])
|
||||
latestPowerData.innerHTML += '<tr><td>' + i18n[lang]['datafield_H21'] + ': ' + parseInt(latestDataSet['H21']) + 'W' + '</td></tr>'
|
||||
if(latestDataSet['H23'])
|
||||
latestPowerData.innerHTML += '<tr><td>' + i18n[lang]['datafield_H23'] + ': ' + parseInt(latestDataSet['H23']) + 'W' + '</td></tr>'
|
||||
|
||||
document.getElementById('deviceDetails').appendChild(latestPowerData)
|
||||
}
|
||||
Reference in New Issue
Block a user