From 5857c4db4653ac5257fd8a7747ecb273aea2d58e Mon Sep 17 00:00:00 2001 From: TrystanLea Date: Fri, 15 Sep 2017 14:55:12 +0100 Subject: [PATCH 01/50] All device module commits from emoncms device-integration branch Contributions from @adminde and @TrystanLea --- README.md | 1 - Views/device.js | 15 +- Views/device_api.php | 16 +- Views/device_dialog.js | 360 +++++++++++++++++++++++++++++++++++++ Views/device_dialog.php | 154 ++++++++++++++++ Views/device_view.php | 160 +++++++---------- data/amig.json | 154 ++++++++-------- data/amrm.json | 66 +++---- data/emonpi-HEM.json | 37 ++++ data/emonpi-SPV1.json | 91 ++++++++++ data/emonpi-SPV2.json | 91 ++++++++++ data/emonth.json | 95 +++++----- data/emontx-HEM.json | 37 ++++ data/emontx-HP.json | 37 ++++ data/emontx-SPV1.json | 91 ++++++++++ data/emontx-SPV2.json | 91 ++++++++++ data/example.json | 53 ------ data/smartmeter.json | 51 ------ data/smartplug.json | 38 ++++ device_controller.php | 81 +++++++-- device_menu.php | 2 +- device_model.php | 382 +++++++++++++--------------------------- device_schema.php | 8 +- device_template.php | 296 +++++++++++++++++++++++++++++++ 24 files changed, 1767 insertions(+), 640 deletions(-) delete mode 100644 README.md create mode 100644 Views/device_dialog.js create mode 100644 Views/device_dialog.php create mode 100644 data/emonpi-HEM.json create mode 100644 data/emonpi-SPV1.json create mode 100644 data/emonpi-SPV2.json create mode 100644 data/emontx-HEM.json create mode 100644 data/emontx-HP.json create mode 100644 data/emontx-SPV1.json create mode 100644 data/emontx-SPV2.json delete mode 100644 data/example.json delete mode 100644 data/smartmeter.json create mode 100644 data/smartplug.json create mode 100644 device_template.php diff --git a/README.md b/README.md deleted file mode 100644 index b3d215b..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# Please note: We are currently working on integrating the device module directly in emoncms core, see https://github.com/emoncms/emoncms/tree/device-integration diff --git a/Views/device.js b/Views/device.js index 4f6120d..f1a2568 100644 --- a/Views/device.js +++ b/Views/device.js @@ -6,6 +6,13 @@ var device = { return result; }, + 'get':function(id) + { + var result = {}; + $.ajax({ url: path+"device/get.json", data: "id="+id, async: false, success: function(data) {result = data;} }); + return result; + }, + 'set':function(id, fields) { var result = {}; @@ -18,22 +25,22 @@ var device = { $.ajax({ url: path+"device/delete.json", data: "id="+id, async: false, success: function(data){} }); }, - 'create':function(id) + 'create':function(nodeid, name, description, type) { - $.ajax({ url: path+"device/create.json", data: "id="+id, async: false, success: function(data){} }); + $.ajax({ url: path+"device/create.json", data: "nodeid="+nodeid+"&name="+name+"&description="+description+"&type="+type, async: false, success: function(data){} }); }, 'listtemplates':function() { var result = {}; - $.ajax({ url: path+"device/listtemplates.json", dataType: 'json', async: false, success: function(data) {result = data;} }); + $.ajax({ url: path+"device/template/list.json", dataType: 'json', async: false, success: function(data) {result = data;} }); return result; }, 'inittemplate':function(id) { var result = {}; - $.ajax({ url: path+"device/inittemplate.json", data: "id="+id, dataType: 'json', async: false, success: function(data) {result = data;} }); + $.ajax({ url: path+"device/template/init.json", data: "id="+id, dataType: 'json', async: false, success: function(data) {result = data;} }); return result; } } diff --git a/Views/device_api.php b/Views/device_api.php index b9e8011..8e7f560 100644 --- a/Views/device_api.php +++ b/Views/device_api.php @@ -36,11 +36,17 @@ - - - - - + + + +
device/list.json
device/get.json?id=1
device/create.json
device/delete.json?id=0
device/set.json?id=0&fields={"name":"Test","description":"Room","nodeid":"House","type":"test"}
device/listtemplates.json
device/inittemplate.json?id=0
device/create.json?nodeid=Test&name=Test
device/delete.json?id=1
device/set.json?id=1&fields={"name":"Test","description":"Room","nodeid":"House","type":"test"}
+ +

+ + + + +
device/template/list.json
device/template/listshort.json
device/template/get.json?device=example
device/template/init.json?id=1
diff --git a/Views/device_dialog.js b/Views/device_dialog.js new file mode 100644 index 0000000..110e5f9 --- /dev/null +++ b/Views/device_dialog.js @@ -0,0 +1,360 @@ +var device_dialog = +{ + templates: null, + deviceType: null, + device: null, + + 'loadConfig':function(templates, device) { + this.templates = templates; + + if (device != null) { + this.deviceType = device.type; + this.device = device; + } + else { + this.deviceType = null; + this.device = null; + } + + this.drawConfig(); + + // Initialize callbacks + this.registerConfigEvents(); + }, + + 'drawConfig':function() { + + $("#device-config-modal").modal('show'); + this.adjustConfigModal(); + this.clearConfigModal(); + + var out = ""; + + var categories = []; + var devicesByCategory = {}; + for (var id in this.templates) { + var device = this.templates[id]; + device['id'] = id; + + if (devicesByCategory[device.category] == undefined) { + devicesByCategory[device.category] = []; + categories.push(device.category); + } + devicesByCategory[device.category].push(device); + } + // Place OpenEnergyMonitor prominently at first place, while sorting other categories + if (categories.indexOf('OpenEnergyMonitor') > -1) { + categories.splice(categories.indexOf('OpenEnergyMonitor'), 1); + categories.sort() + categories = ['OpenEnergyMonitor'].concat(categories); + } + + for (var i in categories) { + var category = categories[i]; + + var groups = []; + var devicesByGroup = {}; + for (var i in devicesByCategory[category]) { + var group = devicesByCategory[category][i].group; + if (devicesByGroup[group] == undefined) { + devicesByGroup[group] = []; + groups.push(group); + } + devicesByGroup[group].push(devicesByCategory[category][i]); + } + groups.sort(); + + out += "" + out += ""; + out += ""+category+""; + out += ""; + out += ""; + + for (var i in groups) { + var group = groups[i]; + + out += "" + out += ""; + out += ""+group+""; + out += ""; + out += ""; + + out += ""; + + for (var i in devicesByGroup[group]) { + var id = devicesByGroup[group][i].id; + var name = devicesByGroup[group][i].name; + if (name.length > 25) { + name = name.substr(0, 25) + "..."; + } + + out += ""; + out += ""+name+""; + out += ""; + } + out += ""; + } + } + $("#template-table").html(out); + + if (this.deviceType != null && this.deviceType != '') { + var template = this.templates[this.deviceType] + + $(".category-body[category='"+template.category+"']").show(); + $(".group-body[category='"+template.category+"'][group='"+template.group+"']").show(); + $(".group-row[type='"+this.deviceType+"']").addClass("device-selected"); + + $('#template-description').html(''+template.description+''); + $('#template-info').show(); + } + }, + + 'clearConfigModal':function() { + $("#template-table").text(''); + + var tooltip = "Defaults, like inputs and associated feeds will be automaticaly configured together with the device." + + "

" + + "Initializing a device usualy should only be done once on installation.
" + + "If the configuration was already applied, only missing inputs and feeds will be created."; + + $('#template-tooltip').attr("title", tooltip).tooltip({html: true}); + + if (this.device != null) { + $('#device-config-node').val(this.device.nodeid); + $('#device-config-name').val(this.device.name); + $('#device-config-description').val(this.device.description); + + $('#device-config-delete').show(); + } + else { + $('#device-config-node').val(''); + $('#device-config-name').val(''); + $('#device-config-description').val(''); + + $('#device-config-delete').hide(); + } + }, + + 'adjustConfigModal':function() { + + var width = $(window).width(); + var height = $(window).height(); + + if ($("#device-config-modal").length) { + var h = height - $("#device-config-modal").position().top - 180; + $("#device-config-body").height(h); + } + + $("#content-wrapper").css("transition","0"); + $("#sidebar-wrapper").css("transition","0"); + if (width < 1024) { + $("#content-wrapper").css("margin-left","0"); + $("#sidebar-wrapper").css("width","0"); + $("#sidebar-open").show(); + + $("#content-wrapper").css("transition","0.5s"); + $("#sidebar-wrapper").css("transition","0.5s"); + } else { + $("#content-wrapper").css("margin-left","250px"); + $("#sidebar-wrapper").css("width","250px"); + $("#sidebar-open").hide(); + $("#sidebar-close").hide(); + } + }, + + 'registerConfigEvents':function() { + + $('#template-table .category-header').off('click').on('click', function() { + var category = $(this).attr("category"); + + var e = $(".group-header[category='"+category+"']"); + if (e.is(":visible")) { + $(".group-body[category='"+category+"']").hide(); + e.hide(); + } + else { + e.show(); + + // If a device is selected and in the category to uncollapse, show and select it + if (device_dialog.deviceType != null && device_dialog.deviceType != '') { + var template = device_dialog.templates[device_dialog.deviceType]; + if (category == template.category) { + $(".group-body[category='"+template.category+"'][group='"+template.group+"']").show(); + $(".group-row[type='"+device_dialog.deviceType+"']").addClass("device-selected"); + } + } + } + }); + + $('#template-table .group-header').off('click').on('click', function() { + var group = $(this).attr("group"); + var category = $(this).attr("category"); + + var e = $(".group-body[group='"+group+"'][category='"+category+"']"); + if (e.is(":visible")) { + e.hide(); + } + else { + e.show(); + + // If a device is selected and in the category to uncollapse, show and select it + if (device_dialog.deviceType != null && device_dialog.deviceType != '') { + var template = device_dialog.templates[device_dialog.deviceType]; + if (category == template.category && group == template.group) { + $(".group-row[type='"+device_dialog.deviceType+"']").addClass("device-selected"); + } + } + } + }); + + $("#template-table .group-row").off('click').on('click', function () { + var type = $(this).attr("type"); + + $(".group-row[type='"+device_dialog.deviceType+"']").removeClass("device-selected"); + if (device_dialog.deviceType !== type) { + $(this).addClass("device-selected"); + device_dialog.deviceType = type; + + var template = device_dialog.templates[type]; + $('#template-description').html(''+template.description+''); + $('#template-info').show(); + } + else { + device_dialog.deviceType = null; + $('#template-description').text(''); + $('#template-info').hide(); + } + }); + + $("#sidebar-open").off('click').on('click', function () { + $("#sidebar-wrapper").css("width","250px"); + $("#sidebar-close").show(); + }); + + $("#sidebar-close").off('click').on('click', function () { + $("#sidebar-wrapper").css("width","0"); + $("#sidebar-close").hide(); + }); + + $("#device-save").off('click').on('click', function () { + + var node = $('#device-config-node').val(); + var name = $('#device-config-name').val(); + + if (name && node) { + var desc = $('#device-config-description').val(); + + if (device_dialog.device != null) { + var fields = {}; + if (device_dialog.device.nodeid != node) fields['node'] = node; + if (device_dialog.device.name != name) fields['name'] = name; + if (device_dialog.device.description != desc) fields['description'] = desc; + if (device_dialog.device.type != device_dialog.deviceType) { + if (device_dialog.deviceType != null) { + fields['type'] = device_dialog.deviceType; + } + else fields['type'] = ''; + } + + var result = device.set(device_dialog.device.id, fields); + if (typeof result.success !== 'undefined' && !result.success) { + alert('Unable to update device fields:\n'+result.message); + return false; + } + update(); + + if (device_dialog.device.type != device_dialog.deviceType + && device_dialog.deviceType != null) { + + var result = device.inittemplate(device_dialog.device.id); + if (typeof result.success !== 'undefined' && !result.success) { + alert('Unable to initialize device:\n'+result.message); + return false; + } + } + } + else { + var id = device.create(node, name, desc, device_dialog.deviceType); + update(); + + if (id && device_dialog.deviceType != null) { + var result = device.inittemplate(id); + if (typeof result.success !== 'undefined' && !result.success) { + alert('Unable to initialize device:\n'+result.message); + return false; + } + } + } + $('#device-config-modal').modal('hide'); + } + else { + alert('Device needs to be configured first.'); + return false; + } + }); + + $("#device-delete").off('click').on('click', function () { + + $('#device-config-modal').modal('hide'); + + device_dialog.loadDelete(device_dialog.device, null); + }); + }, + + 'loadInit': function(device) { + this.device = device; + + $('#device-init-modal').modal('show'); + $('#device-init-modal-label').html('Initialize Device: '+device.name+''); + + // Initialize callbacks + this.registerInitEvents(); + }, + + 'registerInitEvents':function() { + + $("#device-init-confirm").off('click').on('click', function() { + var result = device.inittemplate(device_dialog.device.id); + + if (typeof result.success !== 'undefined' && !result.success) { + alert('Unable to initialize device:\n'+result.message); + return false; + } + $('#device-init-modal').modal('hide'); + + return true; + }); + }, + + 'loadDelete': function(device, tablerow) { + this.device = device; + + $('#device-delete-modal').modal('show'); + $('#device-delete-modal-label').html('Delete Device: '+device.name+''); + + // Initialize callbacks + this.registerDeleteEvents(tablerow); + }, + + 'registerDeleteEvents':function(row) { + + $("#device-delete-confirm").off('click').on('click', function() { + device.remove(device_dialog.device.id); + if (row != null) { + table.remove(row); + update(); + } + else if (typeof device_dialog.device.inputs != undefined) { + // If the table row is undefined and an input list exists, the config dialog + // was opened in the input view and all corresponding inputs will be deleted + var inputIds = []; + for (var i in device_dialog.device.inputs) { + var inputId = device_dialog.device.inputs[i].id; + inputIds.push(parseInt(inputId)); + } + input.delete_multiple(inputIds); + } + $('#device-delete-modal').modal('hide'); + }); + } +} diff --git a/Views/device_dialog.php b/Views/device_dialog.php new file mode 100644 index 0000000..d571c11 --- /dev/null +++ b/Views/device_dialog.php @@ -0,0 +1,154 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Views/device_view.php b/Views/device_view.php index 7ea9f7f..38e8569 100644 --- a/Views/device_view.php +++ b/Views/device_view.php @@ -1,11 +1,5 @@ $value) - { - $devices[$key] = ((!isset($value->name) || $value->name == "" ) ? $key : $value->name); - } ?> @@ -16,68 +10,41 @@ #table input[type="text"] { width: 88%; } +#table td:nth-of-type(1) { width:5%;} +#table th:nth-of-type(5), td:nth-of-type(5) { text-align: right; } +#table th:nth-of-type(6), td:nth-of-type(6) { text-align: right; } +#table th[fieldg="time"] { font-weight:normal; text-align: right; } +#table td:nth-of-type(7) { width:14px; text-align: center; } +#table td:nth-of-type(8) { width:14px; text-align: center; } +#table td:nth-of-type(9) { width:14px; text-align: center; } +#table td:nth-of-type(10) { width:14px; text-align: center; }
-
-

+
+

loading...
- -
+ +
-


-

+


+

+ +

+ +
+ +

-

- +

+
- - - + diff --git a/data/amig.json b/data/amig.json index d94674d..a75daf4 100644 --- a/data/amig.json +++ b/data/amig.json @@ -1,11 +1,13 @@ { "name": "AMIG", + "category": "Datalogger", + "group": "ArchiMetrics", "description": "INPUTS & FEEDS for AMIG Logger from archimetrics.co.uk", "inputs": [{ "name": "n1T", "description": "N1 Temperature", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n1T" @@ -16,7 +18,7 @@ "name": "n1R", "description": "N1 RH", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n1R" @@ -27,7 +29,7 @@ "name": "n1D", "description": "N1 DewPoint", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n1D" @@ -38,7 +40,7 @@ "name": "n2T", "description": "N2 Temperature", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n2T" @@ -49,7 +51,7 @@ "name": "n2R", "description": "N2 RH", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n2R" @@ -60,7 +62,7 @@ "name": "n2D", "description": "N2 DewPoint", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n2D" @@ -71,7 +73,7 @@ "name": "n3T", "description": "N3 Temperature", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n3T" @@ -82,7 +84,7 @@ "name": "n3R", "description": "N3 RH", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n3R" @@ -93,7 +95,7 @@ "name": "n3D", "description": "N3 DewPoint", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n3D" @@ -104,7 +106,7 @@ "name": "n4T", "description": "N4 Temperature", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n4T" @@ -115,7 +117,7 @@ "name": "n4R", "description": "N4 RH", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n4R" @@ -126,7 +128,7 @@ "name": "n4D", "description": "N4 DewPoint", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n4D" @@ -137,7 +139,7 @@ "name": "iTS", "description": "Internal Temperature Surface", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "iTS" @@ -148,7 +150,7 @@ "name": "eTS", "description": "External Temperature Surface", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "eTS" @@ -159,7 +161,7 @@ "name": "eSR", "description": "External Solar Radiation", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "eSR" @@ -170,7 +172,7 @@ "name": "iTA", "description": "Internal Temperature Air", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "iTA" @@ -181,7 +183,7 @@ "name": "iRH", "description": "Internal RH", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "iRH" @@ -192,7 +194,7 @@ "name": "iDP", "description": "Internal DewPoint", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "iDP" @@ -203,7 +205,7 @@ "name": "eTA", "description": "External Temperature Air", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "eTA" @@ -214,7 +216,7 @@ "name": "eRH", "description": "External RH", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "eRH" @@ -225,7 +227,7 @@ "name": "eDP", "description": "External DewPoint", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "eDP" @@ -236,7 +238,7 @@ "name": "hfV", "description": "HeatFlux Voltage", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "hfV" @@ -247,7 +249,7 @@ "name": "hfW", "description": "HeatFlux Watts", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "hfW" @@ -258,7 +260,7 @@ "name": "CO2", "description": "Carbon Dioxide", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "CO2" @@ -269,7 +271,7 @@ "name": "SYS", "description": "System Temperature", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "SYS" @@ -279,151 +281,151 @@ "feeds": [{ "name": "n1T", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "n1R", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "n1D", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "n2T", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "n2R", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "n2D", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "n3T", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "n3R", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "n3D", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "n4T", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "n4R", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "n4D", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "iTS", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "eTS", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "eSR", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "iTA", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "iRH", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "iDP", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "eTA", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "eRH", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "eDP", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "hfV", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "hfW", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "CO2", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }, { "name": "SYS", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" + "engine": "Engine::PHPFINA", + "interval": "10" }] -} \ No newline at end of file +} diff --git a/data/amrm.json b/data/amrm.json index 8c7f021..e9e2873 100644 --- a/data/amrm.json +++ b/data/amrm.json @@ -1,11 +1,13 @@ { "name": "AMRM", + "category": "Datalogger", + "group": "ArchiMetrics", "description": "INPUTS & FEEDS for AMRM Logger from archimetrics.co.uk", "inputs": [{ "name": "n1T", "description": "N1 Temperature", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n1T" @@ -16,7 +18,7 @@ "name": "n2T", "description": "N2 Temperature", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n2T" @@ -27,7 +29,7 @@ "name": "n3T", "description": "N3 Temperature", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n3T" @@ -38,7 +40,7 @@ "name": "n4T", "description": "N4 Temperature", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n4T" @@ -49,7 +51,7 @@ "name": "n1IM", "description": "N1 IM", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n1IM" @@ -60,7 +62,7 @@ "name": "n2IM", "description": "N2 IM", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n2IM" @@ -71,7 +73,7 @@ "name": "n3IM", "description": "N3 IM", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n3IM" @@ -82,7 +84,7 @@ "name": "n4IM", "description": "N4 IM", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n4IM" @@ -93,7 +95,7 @@ "name": "n1DM", "description": "N1 DM", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n1DM" @@ -104,7 +106,7 @@ "name": "n2DM", "description": "N2 DM", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n2DM" @@ -115,7 +117,7 @@ "name": "n3DM", "description": "N3 DM", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n3DM" @@ -126,7 +128,7 @@ "name": "n4DM", "description": "N4 DM", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "n4DM" @@ -137,7 +139,7 @@ "name": "iTA", "description": "Internal Temperature Air", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "iTA" @@ -148,7 +150,7 @@ "name": "iRH", "description": "Internal RH", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "iRH" @@ -159,7 +161,7 @@ "name": "iDP", "description": "Internal Dew Point", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "iDP" @@ -170,7 +172,7 @@ "name": "SYS", "description": "System Temperature", "processList": [{ - "process": "1", + "process": "log_to_feed", "arguments": { "type": "ProcessArg::FEEDID", "value": "SYS" @@ -180,98 +182,98 @@ "feeds": [{ "name": "n1T", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", + "engine": "Engine::PHPFINA", "interval": "10" }, { "name": "n2T", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", + "engine": "Engine::PHPFINA", "interval": "10" }, { "name": "n3T", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", + "engine": "Engine::PHPFINA", "interval": "10" }, { "name": "n4T", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", + "engine": "Engine::PHPFINA", "interval": "10" }, { "name": "n1IM", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", + "engine": "Engine::PHPFINA", "interval": "10" }, { "name": "n2IM", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", + "engine": "Engine::PHPFINA", "interval": "10" }, { "name": "n3IM", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", + "engine": "Engine::PHPFINA", "interval": "10" }, { "name": "n4IM", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", + "engine": "Engine::PHPFINA", "interval": "10" }, { "name": "n1DM", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", + "engine": "Engine::PHPFINA", "interval": "10" }, { "name": "n2DM", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", + "engine": "Engine::PHPFINA", "interval": "10" }, { "name": "n3DM", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", + "engine": "Engine::PHPFINA", "interval": "10" }, { "name": "n4DM", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", + "engine": "Engine::PHPFINA", "interval": "10" }, { "name": "iTA", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", + "engine": "Engine::PHPFINA", "interval": "10" }, { "name": "iRH", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", + "engine": "Engine::PHPFINA", "interval": "10" }, { "name": "iDP", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", + "engine": "Engine::PHPFINA", "interval": "10" }, { "name": "SYS", "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", + "engine": "Engine::PHPFINA", "interval": "10" }] } diff --git a/data/emonpi-HEM.json b/data/emonpi-HEM.json new file mode 100644 index 0000000..91db450 --- /dev/null +++ b/data/emonpi-HEM.json @@ -0,0 +1,37 @@ +{ + "name": "HomeEnergyMonitor", + "category": "OpenEnergyMonitor", + "group": "EmonPi", + "description": "Basic EmonPi Home Energy Monitor configuration", + "inputs": [ + { + "name": "power1", + "description": "House consumption", + "processList": [ + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "use" } + }, + { + "process": "power_to_kwh", + "arguments": {"type": "ProcessArg::FEEDID", "value": "use_kwh" } + } + ] + } + ], + + "feeds": [ + { + "name": "use", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "use_kwh", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + } + ] +} diff --git a/data/emonpi-SPV1.json b/data/emonpi-SPV1.json new file mode 100644 index 0000000..65e6438 --- /dev/null +++ b/data/emonpi-SPV1.json @@ -0,0 +1,91 @@ +{ + "name": "Solar PV Type 1", + "category": "OpenEnergyMonitor", + "group": "EmonPi", + "description": "EmonPi Solar PV Type 1 template", + "inputs": [ + { + "name": "power1", + "description": "House consumption", + "processList": [ + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "use" } + }, + { + "process": "power_to_kwh", + "arguments": {"type": "ProcessArg::FEEDID", "value": "use_kwh" } + }, + { + "process": "subtract_input", + "arguments": {"type": "ProcessArg::INPUTID", "value": "power2" } + }, + { + "process": "allowpositive", + "arguments": {"type": "ProcessArg::NONE"} + }, + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "import" } + }, + { + "process": "power_to_kwh", + "arguments": {"type": "ProcessArg::FEEDID", "value": "import_kwh" } + } + ] + }, + { + "name": "power2", + "description": "Solar generation", + "processList": [ + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "solar" } + }, + { + "process": "power_to_kwh", + "arguments": {"type": "ProcessArg::FEEDID", "value": "solar_kwh" } + } + ] + } + ], + + "feeds": [ + { + "name": "use", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "use_kwh", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "solar", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "solar_kwh", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "import", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "import_kwh", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + } + ] +} diff --git a/data/emonpi-SPV2.json b/data/emonpi-SPV2.json new file mode 100644 index 0000000..6e41064 --- /dev/null +++ b/data/emonpi-SPV2.json @@ -0,0 +1,91 @@ +{ + "name": "Solar PV Type 2", + "category": "OpenEnergyMonitor", + "group": "EmonPi", + "description": "EmonPi Solar PV Type 2 template", + "inputs": [ + { + "name": "power1", + "description": "House consumption", + "processList": [ + { + "process": "allowpositive", + "arguments": {"type": "ProcessArg::NONE"} + }, + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "import" } + }, + { + "process": "power_to_kwh", + "arguments": {"type": "ProcessArg::FEEDID", "value": "import_kwh" } + } + ] + }, + { + "name": "power2", + "description": "Solar generation", + "processList": [ + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "solar" } + }, + { + "process": "power_to_kwh", + "arguments": {"type": "ProcessArg::FEEDID", "value": "solar_kwh" } + }, + { + "process": "add_input", + "arguments": {"type": "ProcessArg::INPUTID", "value": "power1" } + }, + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "use" } + }, + { + "process": "power_to_kwh", + "arguments": {"type": "ProcessArg::FEEDID", "value": "use_kwh" } + } + ] + } + ], + + "feeds": [ + { + "name": "use", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "use_kwh", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "solar", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "solar_kwh", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "import", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "import_kwh", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + } + ] +} diff --git a/data/emonth.json b/data/emonth.json index 41e9aac..68fe1ac 100644 --- a/data/emonth.json +++ b/data/emonth.json @@ -1,54 +1,43 @@ -{ "name": "EmonTH", - "description": "Automatic inputs and feeds creation for emonTH device.", - "inputs": [ - { - "name": "1", - "description": "Temperature C", - "processList": [ - { - "process": "1", - "arguments": {"type": "ProcessArg::FEEDID", "value": "tempC" } - } - ] - }, - { - "name": "2", - "description": "Humidity Rh%", - "processList": [ - { - "process": "1", - "arguments": {"type": "ProcessArg::FEEDID", "value": "humiRH" } - } - ] - }, - { - "name": "3", - "description": "Internal Battery", - "processList": [ - { - "process": "1", - "arguments": {"type": "ProcessArg::FEEDID", "value": "batV" } - } - ] - } - ], +{ + "name": "EmonTH", + "category": "OpenEnergyMonitor", + "group": "Temperature & Humidity", + "description": "Automatic inputs and feeds creation for emonTH device.", + "inputs": [ + { + "name": "temperature", + "description": "Temperature C", + "processList": [ + { + "process": "1", + "arguments": {"type": "ProcessArg::FEEDID", "value": "emonth_temperature" } + } + ] + }, + { + "name": "humidity", + "description": "Humidity Rh%", + "processList": [ + { + "process": "1", + "arguments": {"type": "ProcessArg::FEEDID", "value": "emonth_humidity" } + } + ] + } + ], - "feeds": [ - { - "name": "tempC", - "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" - }, - { - "name": "humiRH", - "type": "DataType::REALTIME", - "engine": "Engine::MYSQL" - }, - { - "name": "batV", - "type": "DataType::REALTIME", - "engine": "Engine::MYSQL" - } - ] -} \ No newline at end of file + "feeds": [ + { + "name": "emonth_temperature", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "60" + }, + { + "name": "emonth_humidity", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "60" + } + ] +} diff --git a/data/emontx-HEM.json b/data/emontx-HEM.json new file mode 100644 index 0000000..3078a58 --- /dev/null +++ b/data/emontx-HEM.json @@ -0,0 +1,37 @@ +{ + "name": "HomeEnergyMonitor", + "category": "OpenEnergyMonitor", + "group": "EmonTx", + "description": "Basic EmonTx v3 Home Energy Monitor configuration", + "inputs": [ + { + "name": "power1", + "description": "House consumption", + "processList": [ + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "use" } + }, + { + "process": "power_to_kwh", + "arguments": {"type": "ProcessArg::FEEDID", "value": "use_kwh" } + } + ] + } + ], + + "feeds": [ + { + "name": "use", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "use_kwh", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + } + ] +} diff --git a/data/emontx-HP.json b/data/emontx-HP.json new file mode 100644 index 0000000..4811240 --- /dev/null +++ b/data/emontx-HP.json @@ -0,0 +1,37 @@ +{ + "name": "Heatpump Monitor", + "category": "OpenEnergyMonitor", + "group": "EmonTx", + "description": "Heatpump Monitor firmware for EmonTx v3", + "inputs": [ + { + "name": "P1", + "description": "Consumption", + "processList": [ + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "use" } + }, + { + "process": "power_to_kwh", + "arguments": {"type": "ProcessArg::FEEDID", "value": "use_kwh" } + } + ] + } + ], + + "feeds": [ + { + "name": "use", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "use_kwh", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + } + ] +} diff --git a/data/emontx-SPV1.json b/data/emontx-SPV1.json new file mode 100644 index 0000000..54b3f9a --- /dev/null +++ b/data/emontx-SPV1.json @@ -0,0 +1,91 @@ +{ + "name": "Solar PV Type 1", + "category": "OpenEnergyMonitor", + "group": "EmonTx", + "description": "EmonTx Solar PV Type 1 template using CT4 for solar", + "inputs": [ + { + "name": "power1", + "description": "House consumption", + "processList": [ + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "use" } + }, + { + "process": "power_to_kwh", + "arguments": {"type": "ProcessArg::FEEDID", "value": "use_kwh" } + }, + { + "process": "subtract_input", + "arguments": {"type": "ProcessArg::INPUTID", "value": "power4" } + }, + { + "process": "allowpositive", + "arguments": {"type": "ProcessArg::NONE"} + }, + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "import" } + }, + { + "process": "power_to_kwh", + "arguments": {"type": "ProcessArg::FEEDID", "value": "import_kwh" } + } + ] + }, + { + "name": "power4", + "description": "Solar generation", + "processList": [ + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "solar" } + }, + { + "process": "power_to_kwh", + "arguments": {"type": "ProcessArg::FEEDID", "value": "solar_kwh" } + } + ] + } + ], + + "feeds": [ + { + "name": "use", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "use_kwh", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "solar", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "solar_kwh", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "import", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "import_kwh", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + } + ] +} diff --git a/data/emontx-SPV2.json b/data/emontx-SPV2.json new file mode 100644 index 0000000..9159a07 --- /dev/null +++ b/data/emontx-SPV2.json @@ -0,0 +1,91 @@ +{ + "name": "Solar PV Type 2", + "category": "OpenEnergyMonitor", + "group": "EmonTx", + "description": "EmonTx Solar PV Type 2 template using CT4 for solar", + "inputs": [ + { + "name": "power1", + "description": "House consumption", + "processList": [ + { + "process": "allowpositive", + "arguments": {"type": "ProcessArg::NONE"} + }, + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "import" } + }, + { + "process": "power_to_kwh", + "arguments": {"type": "ProcessArg::FEEDID", "value": "import_kwh" } + } + ] + }, + { + "name": "power4", + "description": "Solar generation", + "processList": [ + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "solar" } + }, + { + "process": "power_to_kwh", + "arguments": {"type": "ProcessArg::FEEDID", "value": "solar_kwh" } + }, + { + "process": "add_input", + "arguments": {"type": "ProcessArg::INPUTID", "value": "power1" } + }, + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "use" } + }, + { + "process": "power_to_kwh", + "arguments": {"type": "ProcessArg::FEEDID", "value": "use_kwh" } + } + ] + } + ], + + "feeds": [ + { + "name": "use", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "use_kwh", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "solar", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "solar_kwh", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "import", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + }, + { + "name": "import_kwh", + "type": "DataType::REALTIME", + "engine": "Engine::PHPFINA", + "interval": "10" + } + ] +} diff --git a/data/example.json b/data/example.json deleted file mode 100644 index 4816fce..0000000 --- a/data/example.json +++ /dev/null @@ -1,53 +0,0 @@ -{ "name": "Demonstration", - "description": "Automatic inputs and feeds creation for demonstration devices.", - "inputs": [ - { - "name": "iload", - "description": "Consumption intensity", - "processList": [ - { - "process": "1", - "arguments": {"type": "ProcessArg::FEEDID", "value": "fILoad" } - }, - { - "process": "29", - "arguments": {"type": "ProcessArg::FEEDID", "value": "fPLoad" } - } - ] - }, - { - "name": "pload", - "description": "Consumption power", - "processList": "" - } - ], - - "feeds": [ - { - "name": "fILoad", - "type": "DataType::REALTIME", - "engine": "Engine::MYSQL", - "interval": "5" - }, - { - "name": "fPLoad", - "type": "DataType::REALTIME", - "engine": "Engine::MYSQL" - }, - { - "name": "fVirtual", - "type": "DataType::REALTIME", - "engine": "Engine::VIRTUALFEED", - "processList": [ - { - "process": "53", - "arguments": {"type": "ProcessArg::FEEDID", "value": "fILoad" } - }, - { - "process": "2", - "arguments": {"type": "ProcessArg::VALUE", "value": "2" } - } - ] - } - ] -} \ No newline at end of file diff --git a/data/smartmeter.json b/data/smartmeter.json deleted file mode 100644 index 8707a86..0000000 --- a/data/smartmeter.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "smartmeter", - "description": "Automatic inputs and feeds creation for smartmeter device.", - "inputs": [ - { - "name": "P1", - "description": "CT1 Power", - "processList": [ - { - "process": "1", - "arguments": {"type": "ProcessArg::FEEDID", "value": "use" } - }, - { - "process": "4", - "arguments": {"type": "ProcessArg::FEEDID", "value": "use_kwh" } - } - ] - }, - { - "name": "E1", - "description": "CT1 Energy", - "processList": [ - { - "process": "34", - "arguments": {"type": "ProcessArg::FEEDID", "value": "use_wh" } - } - ] - } - ], - - "feeds": [ - { - "name": "use", - "type": "DataType::REALTIME", - "engine": "Engine::PHPFINA", - "interval": "10" - }, - { - "name": "use_kwh", - "type": "DataType::REALTIME", - "engine": "Engine::PHPFINA", - "interval": "10" - }, - { - "name": "use_wh", - "type": "DataType::REALTIME", - "engine": "Engine::PHPFINA", - "interval": "10" - } - ] -} diff --git a/data/smartplug.json b/data/smartplug.json new file mode 100644 index 0000000..ba282d2 --- /dev/null +++ b/data/smartplug.json @@ -0,0 +1,38 @@ +{ + "name": "smartplug", + "category": "OpenEnergyMonitor", + "group": "smartplug", + "description": "smartplug", + "inputs": [ + { + "name": "period", + "description": "period", + "processList": [] + }, + { + "name": "end", + "description": "end", + "processList": [] + }, + { + "name": "interruptible", + "description": "interruptible", + "processList": [] + }, + { + "name": "status", + "description": "status", + "processList": [] + } + ], + + "feeds": [], + + "control": + { + "period": {"type":"text","default":0}, + "end": {"type":"text","default":0}, + "interruptible": {"type":"checkbox","default":0}, + "status": {"type":"checkbox","default":0} + } +} diff --git a/device_controller.php b/device_controller.php index b000c69..ceaad99 100644 --- a/device_controller.php +++ b/device_controller.php @@ -15,26 +15,77 @@ function device_controller() if ($route->format == 'html') { if ($route->action == "view" && $session['write']) { - $devices_templates = $device->get_templates(); - $result = view("Modules/device/Views/device_view.php",array('devices_templates'=>$devices_templates)); + $device_templates = $device->get_template_list_short(); + $result = view("Modules/device/Views/device_view.php",array('devices'=>$device_templates)); } if ($route->action == 'api') $result = view("Modules/device/Views/device_api.php", array()); } if ($route->format == 'json') { - // Used in conjunction with input name describe to auto create device - if ($route->action == "autocreate") { - if ($session['userid']>0 && $session['write']) $result = $device->autocreate($session['userid'],get('nodeid'),get('type')); + // --------------------------------------------------------------- + // Method for sharing authentication details with a node + // that does not require copying and pasting passwords and apikeys + // 1. device requests authentication - reply "request registered" + // 2. notification asks user whether to allow or deny device + // 3. user clicks on allow + // 4. device makes follow up request for authentication + // - reply authentication details + // --------------------------------------------------------------- + if ($redis && $route->action == "auth") { + // 1. Register request for authentication details, or provide if allowed + if ($route->subaction=="request") { + $ip = $_SERVER['REMOTE_ADDR']; + + $allow_ip = $redis->get("device_auth_allow"); + // Only show authentication details to allowed ip address + if ($allow_ip==$ip) { + $redis->del("device_auth_allow"); + global $mqtt_server; + $result = $mqtt_server["user"].":".$mqtt_server["password"].":".$mqtt_server["basetopic"]; + } else { + $redis->set("device_auth",json_encode(array("ip"=>$ip))); + $result = "request registered"; + } + $route->format = "text"; + } + // 2. User checks for device waiting for authentication + else if ($route->subaction=="check" && $session['write']) { + if ($device_auth = $redis->get("device_auth")) { + $result = json_decode($device_auth); + } else { + $result = "no devices"; + } + } + // 3. User allows device to receive authentication details + else if ($route->subaction=="allow" && $session['write']) { + $ip = get("ip"); + $redis->set("device_auth_allow",$ip); // Temporary availability of auth for device ip address + $redis->expire("device_auth_allow",60); // Expire after 60 seconds + $redis->del("device_auth"); + $result = true; + } } else if ($route->action == 'list') { if ($session['userid']>0 && $session['write']) $result = $device->get_list($session['userid']); } elseif ($route->action == "create") { - if ($session['userid']>0 && $session['write']) $result = $device->create($session['userid']); + if ($session['userid']>0 && $session['write']) $result = $device->create($session['userid'],get("nodeid"),get("name"),get("description"),get("type")); } - elseif ($route->action == "listtemplates") { - if ($session['userid']>0 && $session['write']) $result = $device->get_templates(); + // Used in conjunction with input name describe to auto create device + else if ($route->action == "autocreate") { + if ($session['userid']>0 && $session['write']) $result = $device->autocreate($session['userid'],get('nodeid'),get('type')); + } + elseif ($route->action == "template" && $route->subaction != "init") { + if ($route->subaction == "list") { + if ($session['userid']>0 && $session['write']) $result = $device->get_template_list(); + } + elseif ($route->subaction == "listshort") { + if ($session['userid']>0 && $session['write']) $result = $device->get_template_list_short(); + } + else if ($route->subaction == "get") { + if ($session['userid']>0 && $session['write']) $result = $device->get_template(get('device')); + } } else { $deviceid = (int) get('id'); @@ -43,13 +94,17 @@ function device_controller() $deviceget = $device->get($deviceid); if (isset($session['write']) && $session['write'] && $session['userid']>0 && $deviceget['userid']==$session['userid']) { if ($route->action == "get") $result = $deviceget; - if ($route->action == "delete") $result = $device->delete($deviceid); - if ($route->action == 'set') $result = $device->set_fields($deviceid, get('fields')); - if ($route->action == 'inittemplate') $result = $device->init_template($deviceid); + else if ($route->action == "delete") $result = $device->delete($deviceid); + else if ($route->action == 'set') $result = $device->set_fields($deviceid, get('fields')); + else if ($route->action == 'template' && $route->subaction == 'init') { + if (isset($_GET['type'])) { + $device->set_fields($deviceid, json_encode(array("type"=>$_GET['type']))); + } + $result = $device->init_template($deviceid); + } } } - else - { + else { $result = array('success'=>false, 'message'=>'Device does not exist'); } } diff --git a/device_menu.php b/device_menu.php index def92bb..0b47ef4 100644 --- a/device_menu.php +++ b/device_menu.php @@ -4,4 +4,4 @@ bindtextdomain($domain, "Modules/device/locale"); bind_textdomain_codeset($domain, 'UTF-8'); - $menu_dropdown_config[] = array('name'=> dgettext($domain, "Device Setup"), 'icon'=>'icon-facetime-video', 'path'=>"device/view" , 'session'=>"write", 'order' => 45 ); + $menu_dropdown_config[] = array('name'=> dgettext($domain, "Device Setup"), 'icon'=>'icon-home', 'path'=>"device/view" , 'session'=>"write", 'order' => 45 ); diff --git a/device_model.php b/device_model.php index d9941da..3b5963e 100644 --- a/device_model.php +++ b/device_model.php @@ -13,9 +13,11 @@ class Device { - private $mysqli; - private $redis; + public $mysqli; + public $redis; private $log; + + private $templates = array(); public function __construct($mysqli,$redis) { @@ -101,6 +103,14 @@ public function exists_name($userid,$name) $result = $this->mysqli->query("SELECT id FROM device WHERE userid = '$userid' AND name = '$name'"); if ($result->num_rows>0) { $row = $result->fetch_array(); return $row['id']; } else return false; } + + public function exists_nodeid($userid,$nodeid) + { + $userid = intval($userid); + $nodeid = preg_replace('/[^\p{L}_\p{N}\s-:]/u','',$nodeid); + $result = $this->mysqli->query("SELECT id FROM device WHERE userid = '$userid' AND nodeid = '$nodeid'"); + if ($result->num_rows>0) { $row = $result->fetch_array(); return $row['id']; } else return false; + } public function get($id) { @@ -181,30 +191,43 @@ public function autocreate($userid,$_nodeid,$_type) $name = "$nodeid:$type"; - if (!$this->exists_name($userid,$name)) { - $deviceid = $this->create($userid); - if ($deviceid>0) { - $result = $this->set_fields($deviceid,json_encode(array("name"=>$name,"nodeid"=>$nodeid,"type"=>$type))); - if ($result["success"]==true) { - return $this->init_template($deviceid); - } else { - return $result; - } - } else { - return array("success"=>false, "message"=>"Device creation failed"); - } + $deviceid = $this->exists_nodeid($userid, $nodeid); + + if (!$deviceid) { + $deviceid = $this->create($userid, $nodeid, null, null, null); + if (!$deviceid) return array("success"=>false, "message"=>"Device creation failed"); + } + + $result = $this->set_fields($deviceid,json_encode(array("name"=>$name,"nodeid"=>$nodeid,"type"=>$type))); + if ($result["success"]==true) { + return $this->init_template($deviceid); } else { - return array("success"=>false, "message"=>"Device name already exists"); + return $result; } } - public function create($userid) + public function create($userid, $nodeid, $name, $description, $type) { $userid = intval($userid); - $devicekey = md5(uniqid(mt_rand(), true)); - $this->mysqli->query("INSERT INTO device (`userid`, `name`, `description`, `nodeid`, `devicekey`) VALUES ('$userid','New Device','','New Node','$devicekey')"); - if ($this->redis) $this->load_to_redis($userid); - return $this->mysqli->insert_id; + $nodeid = preg_replace('/[^\p{L}_\p{N}\s-:]/u', '', $nodeid); + if (isset($name)) { + $name = preg_replace('/[^\p{L}_\p{N}\s-:]/u', '', $name); + } + else $name = $nodeid; + + if (isset($description)) { + $description= preg_replace('/[^\p{L}_\p{N}\s-:]/u', '', $description); + } + else $description = ''; + + if (!$this->exists_nodeid($userid,$nodeid)) { + $devicekey = md5(uniqid(mt_rand(), true)); + $this->mysqli->query("INSERT INTO device (`userid`, `nodeid`, `name`, `description`, `type`, `devicekey`) VALUES ('$userid','$nodeid','$name','$description','$type','$devicekey')"); + if ($this->redis) $this->load_to_redis($userid); + return $this->mysqli->insert_id; + } else { + return false; + } } public function delete($id) @@ -227,7 +250,7 @@ public function delete($id) } } } - + public function set_fields($id,$fields) { $id = (int) $id; @@ -270,263 +293,112 @@ public function set_fields($id,$fields) } } - public function get_templates() + public function get_template_list() { - $devices = array(); - $devices = $this->load_devices_template(); - return $devices; + return $this->load_modules(); } - private function load_devices_template() { - $list = array(); - foreach (glob("Modules/device/data/*.json") as $file) { - $content = json_decode(file_get_contents($file)); - $list[basename($file, ".json")] = $content; + public function get_template_list_short() + { + if (empty($this->templates)) { // Cache it now + $this->load_modules(); } - return $list; + return $this->templates; } - - public function init_template($id) + + public function get_template($device) { - $id = (int) $id; - if (!$this->exist($id)) return array('success'=>false, 'message'=>'Device does not exist'); - - $result = $this->mysqli->query("SELECT * FROM device WHERE id = '$id'"); - $row = (array) $result->fetch_object(); - - if (isset($row['type']) && $row['type']) { - $file = "Modules/device/data/".$row['type'].".json"; - if (file_exists($file)) { - $template = json_decode(file_get_contents($file)); - } else { - return array('success'=>false, 'message'=>"Template file not found '" . $file . "'"); - } - - $userid = $row['userid']; - $node = $row['nodeid']; - $feeds = $template->feeds; - $inputs = $template->inputs; - - // Create feeds - $result = $this->create_feeds($userid, $node, $feeds); - if ($result["success"] !== true) { - return array('success'=>false, 'message'=>'Error while creating the feeds. ' . $result['message']); - } - - // Create inputs - $result = $this->create_inputs($userid, $node, $inputs); - if ($result !== true) { - return array('success'=>false, 'message'=>'Error while creating the inputs.'); - } - - // Create inputs processes - $result = $this->create_inputs_processes($feeds, $inputs); - if ($result["success"] !== true) { - return array('success'=>false, 'message'=>'Error while creating the inputs process list. ' . $result['message']); - } - - // Create feeds processes - $result = $this->create_feeds_processes($feeds, $inputs); - if ($result["success"] !== true) { - return array('success'=>false, 'message'=>'Error while creating the feeds process list. ' . $result['message']); - } + if (empty($this->templates)) { // Cache it now + $this->load_modules(); } - return array('success'=>true, 'message'=>'Device initialized'); - } - - // Create the feeds - private function create_feeds($userid, $node, &$feedArray) { - global $feed_settings; - - require_once "Modules/feed/feed_model.php"; - $feed = new Feed($this->mysqli,$this->redis,$feed_settings); - - foreach($feedArray as $f) { - // Create each feed - $name = $f->name; - if (property_exists($f, "tag")) { - $tag = $f->tag; - } else { - $tag = $node; - } - $datatype = constant($f->type); // DataType:: - $engine = constant($f->engine); // Engine:: - $options_in = new stdClass(); - if (property_exists($f, "interval")) { - $options_in->interval = $f->interval; - } - $this->log->info("create_feeds() userid=$userid tag=$tag name=$name datatype=$datatype engine=$engine"); - $result = $feed->create($userid,$tag,$name,$datatype,$engine,$options_in); - if($result["success"] !== true) { - return $result; + + if (isset($this->templates[$device])) { + $module = $this->templates[$device]['module']; + $class = $this->get_module_class($module); + if ($class != null) { + return $class->get($device); } - $f->feedId = $result["feedid"]; // Assign the created feed id to the feeds array } - return $result; - } - - // Create the inputs - private function create_inputs($userid, $node, &$inputArray) { - require_once "Modules/input/input_model.php"; - $input = new Input($this->mysqli,$this->redis, null); - - foreach($inputArray as $i) { - // Create each input - $name = $i->name; - $description = $i->description; - if(property_exists($i, "node")) { - $nodeid = $i->node; - } else { - $nodeid = $node; - } - - $inputId = $input->exists_nodeid_name($userid,$nodeid,$name); - - if ($inputId==false) { - $this->log->info("create_inputs() userid=$userid nodeid=$nodeid name=$name description=$description"); - $inputId = $input->create_input($userid, $nodeid, $name); - if(!$input->exists($inputId)) { - return false; - } - $input->set_fields($inputId, '{"description":"'.$description.'"}'); - } - $i->inputId = $inputId; // Assign the created input id to the inputs array + else { + return array('success'=>false, 'message'=>'Device template does not exist'); } - return true; + + return array('success'=>false, 'message'=>'Unknown error while loading device template details'); } - // Create the inputs process lists - private function create_inputs_processes($feedArray, $inputArray) { - require_once "Modules/input/input_model.php"; - $input = new Input($this->mysqli,$this->redis, null); - - foreach($inputArray as $i) { - // for each input - if (isset($i->processList)) { - $inputId = $i->inputId; - $result = $this->convertTemplateProcessList($feedArray, $inputArray, $i->processList); - if (isset($result["success"])) { - return $result; // success is only filled if it was an error - } - - $processes = implode(",", $result); - if ($processes != "") { - $this->log->info("create_inputs_processes() calling input->set_processlist inputId=$inputId processes=$processes"); - $input->set_processlist($inputId, $processes); - } - } + public function init_template($id) + { + if (empty($this->templates)) { // Cache it now + $this->load_modules(); } - - return array('success'=>true); - } - - private function create_feeds_processes($feedArray, $inputArray) { - global $feed_settings; - - require_once "Modules/feed/feed_model.php"; - $feed = new Feed($this->mysqli,$this->redis,$feed_settings); - - foreach($feedArray as $f) { - // for each feed - if (($f->engine == Engine::VIRTUALFEED) && isset($f->processList)) { - $feedId = $f->feedId; - $result = $this->convertTemplateProcessList($feedArray, $inputArray, $f->processList); - if (isset($result["success"])) { - return $result; // success is only filled if it was an error - } - - $processes = implode(",", $result); - if ($processes != "") { - $this->log->info("create_feeds_processes() calling feed->set_processlist feedId=$feedId processes=$processes"); - $feed->set_processlist($feedId, $processes); + + $id = (int) $id; + if (!$this->exist($id)) return array('success'=>false, 'message'=>'Device does not exist'); + + $device = $this->get($id); + if (isset($device['type']) && $device['type'] != 'null' && $device['type']) { + if (isset($this->templates[$device['type']])) { + $module = $this->templates[$device['type']]['module']; + $class = $this->get_module_class($module); + if ($class != null) { + return $class->init($device['userid'], $device['nodeid'], $device['name'], $device['type']); } } + else { + return array('success'=>false, 'message'=>'Device template does not exist'); + } } - - return array('success'=>true); + else { + return array('success'=>false, 'message'=>'Device type not specified'); + } + + return array('success'=>false, 'message'=>'Unknown error while initializing device'); } - - // Converts template processList - private function convertTemplateProcessList($feedArray, $inputArray, $processArray){ - $resultProcesslist = array(); - if (is_array($processArray)) { - require_once "Modules/process/process_model.php"; - $process = new Process(null,null,null,null); - $process_list = $process->get_process_list(); // emoncms supported processes - - // create each processlist - foreach($processArray as $p) { - $proc_name = $p->process; - if (!isset($process_list[$proc_name])) { - $this->log->error("convertProcess() Process '$proc_name' not supported. Module missing?"); - return array('success'=>false, 'message'=>"Process '$proc_name' not supported. Module missing?"); - } - - // Arguments - if(isset($p->arguments)) { - if(isset($p->arguments->type)) { - $type = @constant($p->arguments->type); // ProcessArg:: - $process_type = $process_list[$proc_name][1]; // get emoncms process ProcessArg - - if ($process_type != $type) { - $this->log->error("convertProcess() Bad device template. Missmatch ProcessArg type. Got '$type' expected '$process_type'. process='$proc_name' type='".$p->arguments->type."'"); - return array('success'=>false, 'message'=>"Bad device template. Missmatch ProcessArg type. Got '$type' expected '$process_type'. process='$proc_name' type='".$p->arguments->type."'"); - } - if (isset($p->arguments->value)) { - $value = $p->arguments->value; - } else { - $this->log->error("convertProcess() Bad device template. Undefined argument value. process='$proc_name' type='".$p->arguments->type."'"); - return array('success'=>false, 'message'=>"Bad device template. Undefined argument value. process='$proc_name' type='".$p->arguments->type."'"); - } - - if ($type === ProcessArg::VALUE) { - } else if ($type === ProcessArg::INPUTID) { - $temp = $this->searchArray($inputArray,'name',$value); // return input array that matches $inputArray[]['name']=$value - if ($temp->inputId > 0) { - $value = $temp->inputId; - } else { - $this->log->error("convertProcess() Bad device template. Input name '$value' was not found. process='$proc_name' type='".$p->arguments->type."'"); - return array('success'=>false, 'message'=>"Bad device template. Input name '$value' was not found. process='$proc_name' type='".$p->arguments->type."'"); - } - } else if ($type === ProcessArg::FEEDID) { - $temp = $this->searchArray($feedArray,'name',$value); // return feed array that matches $feedArray[]['name']=$value - if ($temp->feedId > 0) { - $value = $temp->feedId; - } else { - $this->log->error("convertProcess() Bad device template. Feed name '$value' was not found. process='$proc_name' type='".$p->arguments->type."'"); - return array('success'=>false, 'message'=>"Bad device template. Feed name '$value' was not found. process='$proc_name' type='".$p->arguments->type."'"); - } - } else if ($type === ProcessArg::NONE) { - $value = 0; - } else if ($type === ProcessArg::TEXT) { -// } else if ($type === ProcessArg::SCHEDULEID) { //not supporte for now - } else { - $this->log->error("convertProcess() Bad device template. Unsuported argument type. process='$proc_name' type='".$p->arguments->type."'"); - return array('success'=>false, 'message'=>"Bad device template. Unsuported argument type. process='$proc_name' type='".$p->arguments->type."'"); - } - - } else { - $this->log->error("convertProcess() Bad device template. Argument type is missing, set to NONE if not required. process='$proc_name' type='".$p->arguments->type."'"); - return array('success'=>false, 'message'=>"Bad device template. Argument type is missing, set to NONE if not required. process='$proc_name' type='".$p->arguments->type."'"); + private function load_modules() + { + $list = array(); + $dir = scandir("Modules"); + for ($i=2; $iget_module_class($dir[$i]); + if ($class != null) { + $module_templates = $class->get_list(); + foreach($module_templates as $key => $value){ + $list[$key] = $value; + + $device = array( + 'module'=>$dir[$i] + ); + $device["name"] = ((!isset($value->name) || $value->name == "" ) ? $key : $value->name); + $device["category"] = ((!isset($value->category) || $value->category== "" ) ? "General" : $value->category); + $device["group"] = ((!isset($value->group) || $value->group== "" ) ? "Miscellaneous" : $value->group); + $device["description"] = (!isset($value->description) ? "" : $value->description); + $device["control"] = (!isset($value->control) ? false : true); + $this->templates[$key] = $device; } - - $this->log->info("convertProcess() process process='$proc_name' type='".$p->arguments->type."' value='" . $value . "'"); - $resultProcesslist[] = $proc_name.":".$value; - - } else { - $this->log->error("convertProcess() Bad device template. Missing processlist arguments. process='$proc_name'"); - return array('success'=>false, 'message'=>"Bad device template. Missing processlist arguments. process='$proc_name'"); } } } - return $resultProcesslist; + return $list; } - private function searchArray($array, $key, $val) { - foreach ($array as $item) - if (isset($item->$key) && $item->$key == $val) - return $item; - return null; + private function get_module_class($module) + { + /* + magic function __call (above) MUST BE USED with this. + Load additional template module files. + Looks in the folder Modules/modulename/ for a file modulename_template.php + (module_name all lowercase but class ModulenameTemplate in php file that is CamelCase) + */ + $module_file = "Modules/".$module."/".$module."_template.php"; + $module_class = null; + if(file_exists($module_file)){ + require_once($module_file); + + $module_class_name = ucfirst(strtolower($module)."Template"); + $module_class = new $module_class_name($this); + } + return $module_class; } } diff --git a/device_schema.php b/device_schema.php index 3f5e403..ace40a6 100644 --- a/device_schema.php +++ b/device_schema.php @@ -3,10 +3,10 @@ $schema['device'] = array( 'id' => array('type' => 'int(11)', 'Null'=>'NO', 'Key'=>'PRI', 'Extra'=>'auto_increment'), 'userid' => array('type' => 'int(11)'), + 'nodeid' => array('type' => 'text'), 'name' => array('type' => 'text', 'default'=>''), 'description' => array('type' => 'text','default'=>''), - 'type' => array('type' => 'varchar(32)'), - 'nodeid' => array('type' => 'text'), - 'devicekey' => array('type' => 'varchar(64)'), - 'time' => array('type' => 'int(10)') + 'type' => array('type' => 'varchar(32)'), + 'devicekey' => array('type' => 'varchar(64)'), + 'time' => array('type' => 'int(10)') ); \ No newline at end of file diff --git a/device_template.php b/device_template.php new file mode 100644 index 0000000..deb684f --- /dev/null +++ b/device_template.php @@ -0,0 +1,296 @@ +mysqli = &$parent->mysqli; + $this->redis = &$parent->redis; + $this->log = new EmonLogger(__FILE__); + } + + public function get_list() { + return $this->load_templates(); + } + + private function load_templates() { + $list = array(); + foreach (glob("Modules/device/data/*.json") as $file) { + $content = json_decode(file_get_contents($file)); + $list[basename($file, ".json")] = $content; + } + return $list; + } + + public function get($device) { + $device = preg_replace('/[^\p{L}_\p{N}\s-:]/u','',$device); + + if (file_exists("Modules/device/data/$device.json")) { + return json_decode(file_get_contents("Modules/device/data/$device.json")); + } + } + + public function init($userid, $nodeid, $name, $type) { + $file = "Modules/device/data/".$type.".json"; + if (file_exists($file)) { + $template = json_decode(file_get_contents($file)); + } else { + return array('success'=>false, 'message'=>"Template file not found '" . $file . "'"); + } + + $feeds = $template->feeds; + $inputs = $template->inputs; + + // Create feeds + $result = $this->create_feeds($userid, $nodeid, $feeds); + if ($result["success"] !== true) { + return array('success'=>false, 'message'=>'Error while creating the feeds. ' . $result['message']); + } + + // Create inputs + $result = $this->create_inputs($userid, $nodeid, $inputs); + if ($result !== true) { + return array('success'=>false, 'message'=>'Error while creating the inputs.'); + } + + // Create inputs processes + $result = $this->create_inputs_processes($feeds, $inputs); + if ($result["success"] !== true) { + return array('success'=>false, 'message'=>'Error while creating the inputs process list. ' . $result['message']); + } + + // Create feeds processes + $result = $this->create_feeds_processes($feeds, $inputs); + if ($result["success"] !== true) { + return array('success'=>false, 'message'=>'Error while creating the feeds process list. ' . $result['message']); + } + + return array('success'=>true, 'message'=>'Device initialized'); + } + + // Create the feeds + private function create_feeds($userid, $node, &$feedArray) { + global $feed_settings; + + require_once "Modules/feed/feed_model.php"; + $feed = new Feed($this->mysqli,$this->redis,$feed_settings); + + $result = array("success"=>true); + + foreach($feedArray as $f) { + // Create each feed + $name = $f->name; + if (property_exists($f, "tag")) { + $tag = $f->tag; + } else { + $tag = $node; + } + $datatype = constant($f->type); // DataType:: + $engine = constant($f->engine); // Engine:: + $options_in = new stdClass(); + if (property_exists($f, "interval")) { + $options_in->interval = $f->interval; + } + $this->log->info("create_feeds() userid=$userid tag=$tag name=$name datatype=$datatype engine=$engine"); + $result = $feed->create($userid,$tag,$name,$datatype,$engine,$options_in); + if($result["success"] !== true) { + return $result; + } + $f->feedId = $result["feedid"]; // Assign the created feed id to the feeds array + } + return $result; + } + + // Create the inputs + private function create_inputs($userid, $node, &$inputArray) { + require_once "Modules/input/input_model.php"; + $input = new Input($this->mysqli,$this->redis, null); + + foreach($inputArray as $i) { + // Create each input + $name = $i->name; + $description = $i->description; + if(property_exists($i, "node")) { + $nodeid = $i->node; + } else { + $nodeid = $node; + } + + $inputId = $input->exists_nodeid_name($userid,$nodeid,$name); + + if ($inputId==false) { + $this->log->info("create_inputs() userid=$userid nodeid=$nodeid name=$name description=$description"); + $inputId = $input->create_input($userid, $nodeid, $name); + if(!$input->exists($inputId)) { + return false; + } + $input->set_fields($inputId, '{"description":"'.$description.'"}'); + } + $i->inputId = $inputId; // Assign the created input id to the inputs array + } + return true; + } + + // Create the inputs process lists + private function create_inputs_processes($feedArray, $inputArray) { + require_once "Modules/input/input_model.php"; + $input = new Input($this->mysqli,$this->redis, null); + + foreach($inputArray as $i) { + // for each input + if (isset($i->processList)) { + $inputId = $i->inputId; + $result = $this->convert_processes($feedArray, $inputArray, $i->processList); + if (isset($result["success"])) { + return $result; // success is only filled if it was an error + } + + $processes = implode(",", $result); + if ($processes != "") { + $this->log->info("create_inputs_processes() calling input->set_processlist inputId=$inputId processes=$processes"); + $input->set_processlist($inputId, $processes); + } + } + } + + return array('success'=>true); + } + + private function create_feeds_processes($feedArray, $inputArray) { + global $feed_settings; + + require_once "Modules/feed/feed_model.php"; + $feed = new Feed($this->mysqli,$this->redis,$feed_settings); + + foreach($feedArray as $f) { + // for each feed + if (($f->engine == Engine::VIRTUALFEED) && isset($f->processList)) { + $feedId = $f->feedId; + $result = $this->convert_processes($feedArray, $inputArray, $f->processList); + if (isset($result["success"])) { + return $result; // success is only filled if it was an error + } + + $processes = implode(",", $result); + if ($processes != "") { + $this->log->info("create_feeds_processes() calling feed->set_processlist feedId=$feedId processes=$processes"); + $feed->set_processlist($feedId, $processes); + } + } + } + + return array('success'=>true); + } + + // Converts template processList + private function convert_processes($feed_array, $input_array, $process_array){ + $result = array(); + + if (is_array($process_array)) { + require_once "Modules/process/process_model.php"; + $process = new Process(null,null,null,null); + $process_list = $process->get_process_list(); // emoncms supported processes + + $process_list_by_name = array(); + foreach ($process_list as $process_id=>$process_item) { + $name = $process_item[2]; + $process_list_by_name[$name] = $process_id; + } + + // create each processlist + foreach($process_array as $p) { + $proc_name = $p->process; + + // If process names are used map to process id + if (isset($process_list_by_name[$proc_name])) $proc_name = $process_list_by_name[$proc_name]; + + if (!isset($process_list[$proc_name])) { + $this->log->error("convertProcess() Process '$proc_name' not supported. Module missing?"); + return array('success'=>false, 'message'=>"Process '$proc_name' not supported. Module missing?"); + } + + // Arguments + if(isset($p->arguments)) { + if(isset($p->arguments->type)) { + $type = @constant($p->arguments->type); // ProcessArg:: + $process_type = $process_list[$proc_name][1]; // get emoncms process ProcessArg + + if ($process_type != $type) { + $this->log->error("convertProcess() Bad device template. Missmatch ProcessArg type. Got '$type' expected '$process_type'. process='$proc_name' type='".$p->arguments->type."'"); + return array('success'=>false, 'message'=>"Bad device template. Missmatch ProcessArg type. Got '$type' expected '$process_type'. process='$proc_name' type='".$p->arguments->type."'"); + } + + if (isset($p->arguments->value)) { + $value = $p->arguments->value; + } else if ($type === ProcessArg::NONE) { + $value = 0; + } else { + $this->log->error("convertProcess() Bad device template. Undefined argument value. process='$proc_name' type='".$p->arguments->type."'"); + return array('success'=>false, 'message'=>"Bad device template. Undefined argument value. process='$proc_name' type='".$p->arguments->type."'"); + } + + if ($type === ProcessArg::VALUE) { + } else if ($type === ProcessArg::INPUTID) { + $temp = $this->search_array($input_array,'name',$value); // return input array that matches $inputArray[]['name']=$value + if ($temp->inputId > 0) { + $value = $temp->inputId; + } else { + $this->log->error("convertProcess() Bad device template. Input name '$value' was not found. process='$proc_name' type='".$p->arguments->type."'"); + return array('success'=>false, 'message'=>"Bad device template. Input name '$value' was not found. process='$proc_name' type='".$p->arguments->type."'"); + } + } else if ($type === ProcessArg::FEEDID) { + $temp = $this->search_array($feed_array,'name',$value); // return feed array that matches $feedArray[]['name']=$value + if ($temp->feedId > 0) { + $value = $temp->feedId; + } else { + $this->log->error("convertProcess() Bad device template. Feed name '$value' was not found. process='$proc_name' type='".$p->arguments->type."'"); + return array('success'=>false, 'message'=>"Bad device template. Feed name '$value' was not found. process='$proc_name' type='".$p->arguments->type."'"); + } + } else if ($type === ProcessArg::NONE) { + $value = 0; + } else if ($type === ProcessArg::TEXT) { +// } else if ($type === ProcessArg::SCHEDULEID) { //not supporte for now + } else { + $this->log->error("convertProcess() Bad device template. Unsuported argument type. process='$proc_name' type='".$p->arguments->type."'"); + return array('success'=>false, 'message'=>"Bad device template. Unsuported argument type. process='$proc_name' type='".$p->arguments->type."'"); + } + + } else { + $this->log->error("convertProcess() Bad device template. Argument type is missing, set to NONE if not required. process='$proc_name' type='".$p->arguments->type."'"); + return array('success'=>false, 'message'=>"Bad device template. Argument type is missing, set to NONE if not required. process='$proc_name' type='".$p->arguments->type."'"); + } + + $this->log->info("convertProcess() process process='$proc_name' type='".$p->arguments->type."' value='" . $value . "'"); + $result[] = $proc_name.":".$value; + + } else { + $this->log->error("convertProcess() Bad device template. Missing processlist arguments. process='$proc_name'"); + return array('success'=>false, 'message'=>"Bad device template. Missing processlist arguments. process='$proc_name'"); + } + } + } + return $result; + } + + private function search_array($array, $key, $val) { + foreach ($array as $item) + if (isset($item->$key) && $item->$key == $val) + return $item; + return null; + } +} From 0b819e615b09b4492e1268e4a6bbc312bdc257f5 Mon Sep 17 00:00:00 2001 From: Trystan Lea Date: Wed, 20 Sep 2017 08:44:42 +0000 Subject: [PATCH 02/50] Fix case where device type is no longer recognised - missing template --- Views/device_dialog.js | 20 +++++++++++--------- Views/device_view.php | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Views/device_dialog.js b/Views/device_dialog.js index 110e5f9..18e6564 100644 --- a/Views/device_dialog.js +++ b/Views/device_dialog.js @@ -98,14 +98,16 @@ var device_dialog = $("#template-table").html(out); if (this.deviceType != null && this.deviceType != '') { - var template = this.templates[this.deviceType] - - $(".category-body[category='"+template.category+"']").show(); - $(".group-body[category='"+template.category+"'][group='"+template.group+"']").show(); - $(".group-row[type='"+this.deviceType+"']").addClass("device-selected"); - - $('#template-description').html(''+template.description+''); - $('#template-info').show(); + if (this.templates[this.deviceType]!=undefined) { + var template = this.templates[this.deviceType] + + $(".category-body[category='"+template.category+"']").show(); + $(".group-body[category='"+template.category+"'][group='"+template.group+"']").show(); + $(".group-row[type='"+this.deviceType+"']").addClass("device-selected"); + + $('#template-description').html(''+template.description+''); + $('#template-info').show(); + } } }, @@ -178,7 +180,7 @@ var device_dialog = // If a device is selected and in the category to uncollapse, show and select it if (device_dialog.deviceType != null && device_dialog.deviceType != '') { var template = device_dialog.templates[device_dialog.deviceType]; - if (category == template.category) { + if (template && category == template.category) { $(".group-body[category='"+template.category+"'][group='"+template.group+"']").show(); $(".group-row[type='"+device_dialog.deviceType+"']").addClass("device-selected"); } diff --git a/Views/device_view.php b/Views/device_view.php index 38e8569..0b07b77 100644 --- a/Views/device_view.php +++ b/Views/device_view.php @@ -91,7 +91,7 @@ function update(){ table.data = data; for (d in data) { - if (data[d]['type'] !== null && data[d]['type'] != '') { + if (data[d]['type'] !== null && data[d]['type'] != '' && devices[data[d]['type']]!=undefined) { data[d]['typename'] = devices[data[d]['type']].name; } else data[d]['typename'] = ''; From cd1ddab2f44a421c276d9112d1b1a09134fb72b5 Mon Sep 17 00:00:00 2001 From: Adrian Minde Date: Mon, 13 Nov 2017 18:45:35 +0100 Subject: [PATCH 03/50] Fix device view API hint for empty device lists not showing --- Views/device_view.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Views/device_view.php b/Views/device_view.php index 0b07b77..7e77cc3 100644 --- a/Views/device_view.php +++ b/Views/device_view.php @@ -28,11 +28,11 @@
-


+


- +

- +

@@ -104,11 +104,11 @@ function update(){ table.draw(); if (table.data.length != 0) { - $("#nodevices").hide(); - $("#localheading").show(); + $("#device-none").hide(); + $("#local-header").show(); } else { - $("#nodevices").show(); - $("#localheading").hide(); + $("#device-none").show(); + $("#local-header").hide(); } }}); } From b26a744b80240f91538d8adce364735f90148093 Mon Sep 17 00:00:00 2001 From: Adrian Minde Date: Mon, 13 Nov 2017 18:48:28 +0100 Subject: [PATCH 04/50] Fix bug where devices are not initialized immediately after creation --- README.md | 4 ++-- Views/device.js | 12 ++++++++---- Views/device_dialog.js | 8 ++++---- Views/device_dialog.php | 2 +- device_menu.php | 8 +++++++- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 69da238..10fb79e 100644 --- a/README.md +++ b/README.md @@ -60,11 +60,11 @@ Click save to continue. ![3.png](files/3.png) -With the device created the next step is to initialize the device, click on the cycling arrows 'refresh icon' to bring up the initialization window. +When a new device is created, it will automatically be initialized and all input processes and feeds will be created, according to the pre-defined template. If the template needs to be applied again, as e.g. a process list was experimented on and altered, or single feeds deleted, it may be re-initialized. Clicking the cycling arrows 'refresh icon' will bring up the initialization window. ![4.png](files/4.png) -Click 'Initialize' to initialize the device which will create the input processes and feeds according to the pre-defined template. +Click 'Initialize' to re-initialize the device and to confirm the creation of missing feeds and inputs, as well as the reset of configured processes to their original state. ![5.png](files/5.png) diff --git a/Views/device.js b/Views/device.js index f1a2568..420cbc4 100644 --- a/Views/device.js +++ b/Views/device.js @@ -22,22 +22,26 @@ var device = { 'remove':function(id) { - $.ajax({ url: path+"device/delete.json", data: "id="+id, async: false, success: function(data){} }); + var result = {}; + $.ajax({ url: path+"device/delete.json", data: "id="+id, async: false, success: function(data) {result = data;} }); + return result; }, 'create':function(nodeid, name, description, type) { - $.ajax({ url: path+"device/create.json", data: "nodeid="+nodeid+"&name="+name+"&description="+description+"&type="+type, async: false, success: function(data){} }); + var result = {}; + $.ajax({ url: path+"device/create.json", data: "nodeid="+nodeid+"&name="+name+"&description="+description+"&type="+type, async: false, success: function(data) {result = data;} }); + return result; }, - 'listtemplates':function() + 'listTemplates':function() { var result = {}; $.ajax({ url: path+"device/template/list.json", dataType: 'json', async: false, success: function(data) {result = data;} }); return result; }, - 'inittemplate':function(id) + 'initTemplate':function(id) { var result = {}; $.ajax({ url: path+"device/template/init.json", data: "id="+id, dataType: 'json', async: false, success: function(data) {result = data;} }); diff --git a/Views/device_dialog.js b/Views/device_dialog.js index 18e6564..8a25bf7 100644 --- a/Views/device_dialog.js +++ b/Views/device_dialog.js @@ -248,7 +248,7 @@ var device_dialog = if (device_dialog.device != null) { var fields = {}; - if (device_dialog.device.nodeid != node) fields['node'] = node; + if (device_dialog.device.nodeid != node) fields['nodeid'] = node; if (device_dialog.device.name != name) fields['name'] = name; if (device_dialog.device.description != desc) fields['description'] = desc; if (device_dialog.device.type != device_dialog.deviceType) { @@ -268,7 +268,7 @@ var device_dialog = if (device_dialog.device.type != device_dialog.deviceType && device_dialog.deviceType != null) { - var result = device.inittemplate(device_dialog.device.id); + var result = device.initTemplate(device_dialog.device.id); if (typeof result.success !== 'undefined' && !result.success) { alert('Unable to initialize device:\n'+result.message); return false; @@ -280,7 +280,7 @@ var device_dialog = update(); if (id && device_dialog.deviceType != null) { - var result = device.inittemplate(id); + var result = device.initTemplate(id); if (typeof result.success !== 'undefined' && !result.success) { alert('Unable to initialize device:\n'+result.message); return false; @@ -316,7 +316,7 @@ var device_dialog = 'registerInitEvents':function() { $("#device-init-confirm").off('click').on('click', function() { - var result = device.inittemplate(device_dialog.device.id); + var result = device.initTemplate(device_dialog.device.id); if (typeof result.success !== 'undefined' && !result.success) { alert('Unable to initialize device:\n'+result.message); diff --git a/Views/device_dialog.php b/Views/device_dialog.php index d571c11..16f0ab9 100644 --- a/Views/device_dialog.php +++ b/Views/device_dialog.php @@ -116,7 +116,7 @@

- +

diff --git a/device_menu.php b/device_menu.php index 0b47ef4..480ea6c 100644 --- a/device_menu.php +++ b/device_menu.php @@ -4,4 +4,10 @@ bindtextdomain($domain, "Modules/device/locale"); bind_textdomain_codeset($domain, 'UTF-8'); - $menu_dropdown_config[] = array('name'=> dgettext($domain, "Device Setup"), 'icon'=>'icon-home', 'path'=>"device/view" , 'session'=>"write", 'order' => 45 ); + $menu_dropdown_config[] = array( + 'name'=> dgettext($domain, "Device Setup"), + 'icon'=>'icon-home', + 'path'=>"device/view" , + 'session'=>"write", + 'order' => 45 + ); From 337e2c7eb73f2649d27d92cd1b489516cdee1cfe Mon Sep 17 00:00:00 2001 From: Adrian Minde Date: Mon, 13 Nov 2017 19:01:26 +0100 Subject: [PATCH 05/50] Fix device creation alert for existing nodes not showing --- Views/device_dialog.js | 10 +++++-- device_model.php | 65 ++++++++++++++++++++++++------------------ 2 files changed, 45 insertions(+), 30 deletions(-) diff --git a/Views/device_dialog.js b/Views/device_dialog.js index 8a25bf7..63b7741 100644 --- a/Views/device_dialog.js +++ b/Views/device_dialog.js @@ -276,11 +276,15 @@ var device_dialog = } } else { - var id = device.create(node, name, desc, device_dialog.deviceType); + var result = device.create(node, name, desc, device_dialog.deviceType); + if (typeof result.success !== 'undefined' && !result.success) { + alert('Unable to create device:\n'+result.message); + return false; + } update(); - if (id && device_dialog.deviceType != null) { - var result = device.initTemplate(id); + if (result && device_dialog.deviceType != null) { + var result = device.initTemplate(result); if (typeof result.success !== 'undefined' && !result.success) { alert('Unable to initialize device:\n'+result.message); return false; diff --git a/device_model.php b/device_model.php index 3b5963e..b9923ef 100644 --- a/device_model.php +++ b/device_model.php @@ -94,16 +94,15 @@ public function exist($id) } return $deviceexist; } - - - public function exists_name($userid,$name) + + public function exists_name($userid, $name) { $userid = intval($userid); $name = preg_replace('/[^\p{L}_\p{N}\s-:]/u','',$name); $result = $this->mysqli->query("SELECT id FROM device WHERE userid = '$userid' AND name = '$name'"); if ($result->num_rows>0) { $row = $result->fetch_array(); return $row['id']; } else return false; } - + public function exists_nodeid($userid,$nodeid) { $userid = intval($userid); @@ -116,23 +115,28 @@ public function get($id) { $id = (int) $id; if (!$this->exist($id)) return array('success'=>false, 'message'=>'Device does not exist'); - - $result = $this->mysqli->query("SELECT * FROM device WHERE id = '$id'"); - $row = (array) $result->fetch_object(); - - return $row; + + if ($this->redis) { + // Get from redis cache + $device = $this->redis->hGetAll("device:$id"); + } else { + // Get from mysql db + $result = $this->mysqli->query("SELECT `id`, `userid`, `nodeid`, `name`, `description`, `type`, `devicekey`, `time` FROM device WHERE id = '$id'"); + $device = (array) $result->fetch_object(); + } + return $device; } - + public function get_list($userid) { if ($this->redis) { - return $this->redis_getlist($userid); + return $this->get_list_redis($userid); } else { - return $this->mysql_getlist($userid); + return $this->get_list_mysql($userid); } } - private function redis_getlist($userid) + private function get_list_redis($userid) { $userid = (int) $userid; if (!$this->redis->exists("user:device:$userid")) $this->load_to_redis($userid); @@ -149,12 +153,12 @@ private function redis_getlist($userid) return $devices; } - private function mysql_getlist($userid) + private function get_list_mysql($userid) { $userid = (int) $userid; $devices = array(); - $result = $this->mysqli->query("SELECT `id`, `userid`, `name`, `description`, `type`, `nodeid`, `devicekey`, `time` FROM device WHERE userid = '$userid'"); + $result = $this->mysqli->query("SELECT `id`, `userid`, `nodeid`, `name`, `description`, `type`, `devicekey`, `time` FROM device WHERE userid = '$userid'"); while ($row = (array)$result->fetch_object()) { $devices[] = $row; @@ -165,21 +169,22 @@ private function mysql_getlist($userid) private function load_to_redis($userid) { $this->redis->delete("user:device:$userid"); - $result = $this->mysqli->query("SELECT `id`, `name`, `description`, `type`, `nodeid`, `devicekey` FROM device WHERE userid = '$userid'"); + $result = $this->mysqli->query("SELECT `id`, `userid`, `nodeid`, `name`, `description`, `type`, `devicekey` FROM device WHERE userid = '$userid'"); while ($row = $result->fetch_object()) { $this->redis->sAdd("user:device:$userid", $row->id); $this->redis->hMSet("device:".$row->id,array( 'id'=>$row->id, + 'userid'=>$row->userid, + 'nodeid'=>$row->nodeid, 'name'=>$row->name, 'description'=>$row->description, 'type'=>$row->type, - 'nodeid'=>$row->nodeid, 'devicekey'=>$row->devicekey )); } } - + public function autocreate($userid,$_nodeid,$_type) { $userid = intval($userid); @@ -205,7 +210,7 @@ public function autocreate($userid,$_nodeid,$_type) return $result; } } - + public function create($userid, $nodeid, $name, $description, $type) { $userid = intval($userid); @@ -220,13 +225,19 @@ public function create($userid, $nodeid, $name, $description, $type) } else $description = ''; - if (!$this->exists_nodeid($userid,$nodeid)) { + if (!$this->exists_nodeid($userid, $nodeid)) { $devicekey = md5(uniqid(mt_rand(), true)); - $this->mysqli->query("INSERT INTO device (`userid`, `nodeid`, `name`, `description`, `type`, `devicekey`) VALUES ('$userid','$nodeid','$name','$description','$type','$devicekey')"); - if ($this->redis) $this->load_to_redis($userid); - return $this->mysqli->insert_id; - } else { - return false; + $result = $this->mysqli->query("INSERT INTO device (`userid`, `nodeid`, `name`, `description`, `type`, `devicekey`) VALUES ('$userid','$nodeid','$name','$description','$type','$devicekey')"); + $deviceid = $this->mysqli->insert_id; + + if ($deviceid > 0) { + if ($this->redis) $this->load_to_redis($userid); + } else return array('success'=>false, 'result'=>"SQL returned invalid insert feed id"); + + return $deviceid; + } + else { + return array('success'=>false, 'message'=>'Device for the node "'.$nodeid.'" already exists'); } } @@ -250,8 +261,8 @@ public function delete($id) } } } - - public function set_fields($id,$fields) + + public function set_fields($id, $fields) { $id = (int) $id; if (!$this->exist($id)) return array('success'=>false, 'message'=>'Device does not exist'); From 45c4fe4d457dbb74a6e24e3a5441d1bd11cb6a3b Mon Sep 17 00:00:00 2001 From: Trystan Lea Date: Thu, 16 Nov 2017 07:55:25 +0000 Subject: [PATCH 06/50] attempting to catch a crash condition --- device_model.php | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/device_model.php b/device_model.php index 3b5963e..82eba3a 100644 --- a/device_model.php +++ b/device_model.php @@ -109,7 +109,14 @@ public function exists_nodeid($userid,$nodeid) $userid = intval($userid); $nodeid = preg_replace('/[^\p{L}_\p{N}\s-:]/u','',$nodeid); $result = $this->mysqli->query("SELECT id FROM device WHERE userid = '$userid' AND nodeid = '$nodeid'"); - if ($result->num_rows>0) { $row = $result->fetch_array(); return $row['id']; } else return false; + + if (isset($result->num_rows) && $result->num_rows>0) { + $row = $result->fetch_array(); + return $row['id']; + } else { + $this->log->warn("exists_nodeid = false, for userid = $userid and nodeid = $nodeid"); + return false; + } } public function get($id) @@ -135,7 +142,11 @@ public function get_list($userid) private function redis_getlist($userid) { $userid = (int) $userid; - if (!$this->redis->exists("user:device:$userid")) $this->load_to_redis($userid); + + if (!$this->redis->exists("user:device:$userid")) { + $this->log->warn("calling load_to_redis in redis_getlist"); + $this->load_to_redis($userid); + } $devices = array(); $deviceids = $this->redis->sMembers("user:device:$userid"); @@ -166,6 +177,11 @@ private function load_to_redis($userid) { $this->redis->delete("user:device:$userid"); $result = $this->mysqli->query("SELECT `id`, `name`, `description`, `type`, `nodeid`, `devicekey` FROM device WHERE userid = '$userid'"); + if (!$result) { + $this->log->warn("load_to_redis error, result=false, userid = $userid"); + return false; + } + while ($row = $result->fetch_object()) { $this->redis->sAdd("user:device:$userid", $row->id); @@ -194,6 +210,7 @@ public function autocreate($userid,$_nodeid,$_type) $deviceid = $this->exists_nodeid($userid, $nodeid); if (!$deviceid) { + $this->log->warn("autocreate user=$userid, nodeid=$nodeid"); $deviceid = $this->create($userid, $nodeid, null, null, null); if (!$deviceid) return array("success"=>false, "message"=>"Device creation failed"); } @@ -223,7 +240,10 @@ public function create($userid, $nodeid, $name, $description, $type) if (!$this->exists_nodeid($userid,$nodeid)) { $devicekey = md5(uniqid(mt_rand(), true)); $this->mysqli->query("INSERT INTO device (`userid`, `nodeid`, `name`, `description`, `type`, `devicekey`) VALUES ('$userid','$nodeid','$name','$description','$type','$devicekey')"); - if ($this->redis) $this->load_to_redis($userid); + if ($this->redis) { + $this->log->warn("calling load_to_redis in device->create"); + $this->load_to_redis($userid); + } return $this->mysqli->insert_id; } else { return false; @@ -246,6 +266,7 @@ public function delete($id) if ($this->redis) { if (isset($row['userid']) && $row['userid']) { $this->redis->delete("device:".$id); + $this->log->warn("calling load_to_redis in device->delete"); $this->load_to_redis($row['userid']); } } @@ -278,12 +299,14 @@ public function set_fields($id,$fields) // Convert to a comma seperated string for the mysql query $fieldstr = implode(",",$array); $this->mysqli->query("UPDATE device SET ".$fieldstr." WHERE `id` = '$id'"); + $this->log->warn("set_fields $fieldstr, $id"); if ($this->mysqli->affected_rows>0){ if ($this->redis) { $result = $this->mysqli->query("SELECT userid FROM device WHERE id='$id'"); $row = (array) $result->fetch_object(); if (isset($row['userid']) && $row['userid']) { + $this->log->warn("calling load_to_redis in device->set_fields"); $this->load_to_redis($row['userid']); } } From 1eea6c2a81950c4b695a609e546be8c74ed0a00c Mon Sep 17 00:00:00 2001 From: Adrian Minde Date: Thu, 16 Nov 2017 12:14:28 +0100 Subject: [PATCH 07/50] Improve caching and fix set_processlist --- Views/device_dialog.php | 11 +- device_controller.php | 15 +- device_model.php | 299 +++++++++++++++++++++++++--------------- device_template.php | 219 ++++++++++++++++------------- 4 files changed, 320 insertions(+), 224 deletions(-) diff --git a/Views/device_dialog.php b/Views/device_dialog.php index 16f0ab9..27c56c6 100644 --- a/Views/device_dialog.php +++ b/Views/device_dialog.php @@ -111,12 +111,11 @@
@@ -136,7 +135,7 @@



- +

diff --git a/device_controller.php b/device_controller.php index ceaad99..7c4c6bc 100644 --- a/device_controller.php +++ b/device_controller.php @@ -15,7 +15,7 @@ function device_controller() if ($route->format == 'html') { if ($route->action == "view" && $session['write']) { - $device_templates = $device->get_template_list_short(); + $device_templates = $device->get_template_list_meta(); $result = view("Modules/device/Views/device_view.php",array('devices'=>$device_templates)); } if ($route->action == 'api') $result = view("Modules/device/Views/device_api.php", array()); @@ -69,19 +69,19 @@ function device_controller() else if ($route->action == 'list') { if ($session['userid']>0 && $session['write']) $result = $device->get_list($session['userid']); } - elseif ($route->action == "create") { + else if ($route->action == "create") { if ($session['userid']>0 && $session['write']) $result = $device->create($session['userid'],get("nodeid"),get("name"),get("description"),get("type")); } // Used in conjunction with input name describe to auto create device else if ($route->action == "autocreate") { if ($session['userid']>0 && $session['write']) $result = $device->autocreate($session['userid'],get('nodeid'),get('type')); } - elseif ($route->action == "template" && $route->subaction != "init") { + else if ($route->action == "template" && $route->subaction != "init") { if ($route->subaction == "list") { if ($session['userid']>0 && $session['write']) $result = $device->get_template_list(); } - elseif ($route->subaction == "listshort") { - if ($session['userid']>0 && $session['write']) $result = $device->get_template_list_short(); + else if ($route->subaction == "listshort") { + if ($session['userid']>0 && $session['write']) $result = $device->get_template_list_meta(); } else if ($route->subaction == "get") { if ($session['userid']>0 && $session['write']) $result = $device->get_template(get('device')); @@ -96,7 +96,8 @@ function device_controller() if ($route->action == "get") $result = $deviceget; else if ($route->action == "delete") $result = $device->delete($deviceid); else if ($route->action == 'set') $result = $device->set_fields($deviceid, get('fields')); - else if ($route->action == 'template' && $route->subaction == 'init') { + else if ($route->action == 'template' && + $route->subaction == 'init') { if (isset($_GET['type'])) { $device->set_fields($deviceid, json_encode(array("type"=>$_GET['type']))); } @@ -107,7 +108,7 @@ function device_controller() else { $result = array('success'=>false, 'message'=>'Device does not exist'); } - } + } } return array('content'=>$result); diff --git a/device_model.php b/device_model.php index 80aa93a..44486a2 100644 --- a/device_model.php +++ b/device_model.php @@ -1,12 +1,12 @@ log = new EmonLogger(__FILE__); } - public function devicekey_session($devicekey_in) + public function devicekey_session($devicekey) { - $devicekey_in = $this->mysqli->real_escape_string($devicekey_in); + $devicekey = $this->mysqli->real_escape_string($devicekey); $session = array(); $time = time(); - + //---------------------------------------------------- // Check for devicekey login //---------------------------------------------------- - if($this->redis && $this->redis->exists("device:key:$devicekey_in")) + if($this->redis && $this->redis->exists("device:key:$devicekey")) { - $session['userid'] = $this->redis->get("device:key:$devicekey_in:user"); + $session['userid'] = $this->redis->get("device:key:$devicekey:user"); $session['read'] = 0; $session['write'] = 1; $session['admin'] = 0; $session['lang'] = "en"; // API access is always in english $session['username'] = "API"; - $session['deviceid'] = $this->redis->get("device:key:$devicekey_in:device"); - $session['nodeid'] = $this->redis->get("device:key:$devicekey_in:node"); + $session['deviceid'] = $this->redis->get("device:key:$devicekey:device"); + $session['nodeid'] = $this->redis->get("device:key:$devicekey:node"); $this->redis->hMset("device:lastvalue:".$session['device'], array('time' => $time)); } else { - $result = $this->mysqli->query("SELECT id, userid, nodeid FROM device WHERE devicekey='$devicekey_in'"); + $result = $this->mysqli->query("SELECT id, userid, nodeid FROM device WHERE devicekey='$devicekey'"); if ($result->num_rows == 1) { $row = $result->fetch_array(); @@ -65,9 +63,9 @@ public function devicekey_session($devicekey_in) $session['nodeid'] = $row['nodeid']; if ($this->redis) { - $this->redis->set("device:key:$devicekey_in:user",$row['userid']); - $this->redis->set("device:key:$devicekey_in:device",$row['id']); - $this->redis->set("device:key:$devicekey_in:node",$row['nodeid']); + $this->redis->set("device:key:$devicekey:user",$row['userid']); + $this->redis->set("device:key:$devicekey:device",$row['id']); + $this->redis->set("device:key:$devicekey:node",$row['nodeid']); $this->redis->hMset("device:lastvalue:".$row['id'], array('time' => $time)); } else { //$time = date("Y-n-j H:i:s", $time); @@ -76,23 +74,36 @@ public function devicekey_session($devicekey_in) } } } - + return $session; } public function exist($id) { - $id = intval($id); static $device_exists_cache = array(); // Array to hold the cache if (isset($device_exists_cache[$id])) { - $deviceexist = $device_exists_cache[$id]; // Retrieve from static cache - } else { - $result = $this->mysqli->query("SELECT id FROM device WHERE id = '$id'"); - $deviceexist = $result->num_rows>0; - $device_exists_cache[$id] = $deviceexist; // Cache it - $this->log->info("exist() $id"); + $device_exist = $device_exists_cache[$id]; // Retrieve from static cache + } + else { + $device_exist = false; + if ($this->redis) { + if (!$this->redis->exists("device:$id")) { + if ($this->load_device_to_redis($id)) { + $device_exist = true; + } + } + else { + $device_exist = true; + } + } + else { + $id = intval($id); + $result = $this->mysqli->query("SELECT id FROM device WHERE id = '$id'"); + if ($result->num_rows > 0) $device_exist = true; + } + $device_exists_cache[$id] = $device_exist; // Cache it } - return $deviceexist; + return $device_exist; } public function exists_name($userid, $name) @@ -109,19 +120,18 @@ public function exists_nodeid($userid,$nodeid) $nodeid = preg_replace('/[^\p{L}_\p{N}\s-:]/u','',$nodeid); $result = $this->mysqli->query("SELECT id FROM device WHERE userid = '$userid' AND nodeid = '$nodeid'"); - if (isset($result->num_rows) && $result->num_rows>0) { + if (isset($result->num_rows) && $result->num_rows > 0) { $row = $result->fetch_array(); return $row['id']; } else { - $this->log->warn("exists_nodeid = false, for userid = $userid and nodeid = $nodeid"); return false; } } public function get($id) { - $id = (int) $id; - if (!$this->exist($id)) return array('success'=>false, 'message'=>'Device does not exist'); + $id = intval($id); + if (!$this->exist($id)) $this->load_device_to_redis($id); if ($this->redis) { // Get from redis cache @@ -145,11 +155,11 @@ public function get_list($userid) private function get_list_redis($userid) { - $userid = (int) $userid; + $userid = intval($userid); if (!$this->redis->exists("user:device:$userid")) { - $this->log->warn("calling load_to_redis in redis_getlist"); - $this->load_to_redis($userid); + $this->log->info("Load devices to redis in get_list_redis"); + $this->load_list_to_redis($userid); } $devices = array(); @@ -166,10 +176,10 @@ private function get_list_redis($userid) private function get_list_mysql($userid) { - $userid = (int) $userid; + $userid = intval($userid); $devices = array(); - - $result = $this->mysqli->query("SELECT `id`, `userid`, `nodeid`, `name`, `description`, `type`, `devicekey`, `time` FROM device WHERE userid = '$userid'"); + + $result = $this->mysqli->query("SELECT `id`, `userid`, `nodeid`, `name`, `description`, `type`, `devicekey`, `time` FROM device WHERE userid = '$userid' ORDER BY nodeid, name asc"); while ($row = (array)$result->fetch_object()) { $devices[] = $row; @@ -177,20 +187,14 @@ private function get_list_mysql($userid) return $devices; } - private function load_to_redis($userid) + private function load_list_to_redis($userid) { $this->redis->delete("user:device:$userid"); - - $result = $this->mysqli->query("SELECT `id`, `userid`, `nodeid`, `name`, `description`, `type`, `devicekey` FROM device WHERE userid = '$userid'"); - if (!$result) { - $this->log->warn("load_to_redis error, result=false, userid = $userid"); - return false; - } - + $result = $this->mysqli->query("SELECT `id`, `userid`, `nodeid`, `name`, `description`, `type`, `devicekey` FROM device WHERE userid = '$userid' ORDER BY nodeid, name asc"); while ($row = $result->fetch_object()) { $this->redis->sAdd("user:device:$userid", $row->id); - $this->redis->hMSet("device:".$row->id,array( + $this->redis->hMSet("device:".$row->id, array( 'id'=>$row->id, 'userid'=>$row->userid, 'nodeid'=>$row->nodeid, @@ -202,21 +206,44 @@ private function load_to_redis($userid) } } - public function autocreate($userid,$_nodeid,$_type) + private function load_device_to_redis($id) + { + $this->redis->delete("user:device:$userid"); + $result = $this->mysqli->query("SELECT `id`, `userid`, `nodeid`, `name`, `description`, `type`, `devicekey` FROM device WHERE id = '$id' ORDER BY nodeid, name asc"); + if ($result->num_rows>0) { + $row = $result->fetch_array(); + $userid = $row->userid; + + $this->redis->sAdd("user:device:$userid", $row->id); + $this->redis->hMSet("device:".$row->id, array( + 'id'=>$row->id, + 'userid'=>$row->userid, + 'nodeid'=>$row->nodeid, + 'name'=>$row->name, + 'description'=>$row->description, + 'type'=>$row->type, + 'devicekey'=>$row->devicekey + )); + return true; + } + return false; + } + + public function autocreate($userid, $_nodeid, $_type) { $userid = intval($userid); $nodeid = preg_replace('/[^\p{L}_\p{N}\s-:]/u','',$_nodeid); - if ($_nodeid!=$nodeid) return array("success"=>false, "message"=>"Invalid nodeid"); + if ($_nodeid != $nodeid) return array("success"=>false, "message"=>"Invalid nodeid"); $type = preg_replace('/[^\/\|\,\w\s-:]/','',$_type); - if ($_type!=$type) return array("success"=>false, "message"=>"Invalid type"); + if ($_type != $type) return array("success"=>false, "message"=>"Invalid type"); $name = "$nodeid:$type"; $deviceid = $this->exists_nodeid($userid, $nodeid); if (!$deviceid) { - $this->log->warn("autocreate user=$userid, nodeid=$nodeid"); + $this->log->info("Automatically create device for user=$userid, nodeid=$nodeid"); $deviceid = $this->create($userid, $nodeid, null, null, null); if (!$deviceid) return array("success"=>false, "message"=>"Device creation failed"); } @@ -227,7 +254,7 @@ public function autocreate($userid,$_nodeid,$_type) } else { return $result; } - } + } public function create($userid, $nodeid, $name, $description, $type) { @@ -245,54 +272,53 @@ public function create($userid, $nodeid, $name, $description, $type) if (!$this->exists_nodeid($userid, $nodeid)) { $devicekey = md5(uniqid(mt_rand(), true)); - + $result = $this->mysqli->query("INSERT INTO device (`userid`, `nodeid`, `name`, `description`, `type`, `devicekey`) VALUES ('$userid','$nodeid','$name','$description','$type','$devicekey')"); $deviceid = $this->mysqli->insert_id; if ($deviceid > 0) { if ($this->redis) { - $this->log->warn("calling load_to_redis in device->create"); - $this->load_to_redis($userid); + $this->log->info("Load devices to redis in create"); + $this->load_list_to_redis($userid); } - } else return array('success'=>false, 'result'=>"SQL returned invalid insert feed id"); - - return $deviceid; - } else { - return array('success'=>false, 'message'=>'Device for the node "'.$nodeid.'" already exists'); + return $deviceid; + } + else return array('success'=>false, 'result'=>"SQL returned invalid insert feed id"); } + else return array('success'=>false, 'message'=>'Device for the node "'.$nodeid.'" already exists'); } public function delete($id) { - $id = (int) $id; + $id = intval($id); if (!$this->exist($id)) return array('success'=>false, 'message'=>'Device does not exist'); - + if ($this->redis) { $result = $this->mysqli->query("SELECT userid FROM device WHERE `id` = '$id'"); $row = (array) $result->fetch_object(); } - + $result = $this->mysqli->query("DELETE FROM device WHERE `id` = '$id'"); if (isset($device_exists_cache[$id])) { unset($device_exists_cache[$id]); } // Clear static cache if ($this->redis) { if (isset($row['userid']) && $row['userid']) { $this->redis->delete("device:".$id); - $this->log->warn("calling load_to_redis in device->delete"); - $this->load_to_redis($row['userid']); + $this->log->info("Load devices to redis in delete"); + $this->load_list_to_redis($row['userid']); } } } public function set_fields($id, $fields) { - $id = (int) $id; + $id = intval($id); if (!$this->exist($id)) return array('success'=>false, 'message'=>'Device does not exist'); - + $fields = json_decode(stripslashes($fields)); - + $array = array(); - + // Repeat this line changing the field name to add fields that can be updated: if (isset($fields->name)) $array[] = "`name` = '".preg_replace('/[^\p{L}_\p{N}\s-:]/u','',$fields->name)."'"; if (isset($fields->description)) $array[] = "`description` = '".preg_replace('/[^\p{L}_\p{N}\s-:]/u','',$fields->description)."'"; @@ -307,19 +333,17 @@ public function set_fields($id, $fields) $array[] = "`devicekey` = '".$devicekey."'"; } if (isset($fields->type)) $array[] = "`type` = '".preg_replace('/[^\/\|\,\w\s-:]/','',$fields->type)."'"; - + // Convert to a comma seperated string for the mysql query $fieldstr = implode(",",$array); $this->mysqli->query("UPDATE device SET ".$fieldstr." WHERE `id` = '$id'"); - $this->log->warn("set_fields $fieldstr, $id"); - + if ($this->mysqli->affected_rows>0){ if ($this->redis) { $result = $this->mysqli->query("SELECT userid FROM device WHERE id='$id'"); $row = (array) $result->fetch_object(); if (isset($row['userid']) && $row['userid']) { - $this->log->warn("calling load_to_redis in device->set_fields"); - $this->load_to_redis($row['userid']); + $this->load_list_to_redis($row['userid']); } } return array('success'=>true, 'message'=>'Field updated'); @@ -333,50 +357,80 @@ public function get_template_list() return $this->load_modules(); } - public function get_template_list_short() + public function get_template_list_meta() { - if (empty($this->templates)) { // Cache it now - $this->load_modules(); + $templates = array(); + + if ($this->redis) { + if (!$this->redis->exists("device:template:keys")) $this->load_modules(); + + $keys = $this->redis->sMembers("device:template:keys"); + foreach ($keys as $key) { + $template = $this->redis->hGetAll("device:template:$key"); + $template["control"] = (bool) $template["control"]; + $templates[$key] = $template; + } } - return $this->templates; + else { + if (empty($this->templates)) { // Cache it now + $this->load_modules(); + } + $templates = $this->templates; + } + return $templates; } - - public function get_template($device) + + public function get_template($key) { - if (empty($this->templates)) { // Cache it now - $this->load_modules(); - } - - if (isset($this->templates[$device])) { - $module = $this->templates[$device]['module']; + $template = $this->get_template_meta($key); + if (isset($template)) { + $module = $template['module']; $class = $this->get_module_class($module); if ($class != null) { - return $class->get($device); + return $class->get_template($key); } } else { return array('success'=>false, 'message'=>'Device template does not exist'); } - return array('success'=>false, 'message'=>'Unknown error while loading device template details'); } - public function init_template($id) + private function get_template_meta($key) { - if (empty($this->templates)) { // Cache it now - $this->load_modules(); - } + $template = null; - $id = (int) $id; - if (!$this->exist($id)) return array('success'=>false, 'message'=>'Device does not exist'); + if ($this->redis) { + if (!$this->redis->exists("device:template:$key")) { + $this->load_modules(); + } + if ($this->redis->exists("device:template:$key")) { + $template = $this->redis->hGetAll("device:template:$key"); + } + } + else { + if (empty($this->templates)) { // Cache it now + $this->load_modules(); + } + if (isset($this->templates[$key])) { + $template = $this->templates[$key]; + } + } + return $template; + } + + public function init_template($id) + { + $id = intval($id); $device = $this->get($id); if (isset($device['type']) && $device['type'] != 'null' && $device['type']) { - if (isset($this->templates[$device['type']])) { - $module = $this->templates[$device['type']]['module']; + $template = $this->get_template_meta($device['type']); + if (isset($template)) { + $module = $template['module']; $class = $this->get_module_class($module); if ($class != null) { - return $class->init($device['userid'], $device['nodeid'], $device['name'], $device['type']); + return $class->init_template($device['userid'], $device['nodeid'], $device['name'], $device['type']); } } else { @@ -392,30 +446,29 @@ public function init_template($id) private function load_modules() { - $list = array(); + if ($this->redis) { + $this->redis->delete("device:template:keys"); + } + else { + $this->templates = array(); + } + $templates = array(); + $dir = scandir("Modules"); for ($i=2; $iget_module_class($dir[$i]); if ($class != null) { - $module_templates = $class->get_list(); - foreach($module_templates as $key => $value){ - $list[$key] = $value; - - $device = array( - 'module'=>$dir[$i] - ); - $device["name"] = ((!isset($value->name) || $value->name == "" ) ? $key : $value->name); - $device["category"] = ((!isset($value->category) || $value->category== "" ) ? "General" : $value->category); - $device["group"] = ((!isset($value->group) || $value->group== "" ) ? "Miscellaneous" : $value->group); - $device["description"] = (!isset($value->description) ? "" : $value->description); - $device["control"] = (!isset($value->control) ? false : true); - $this->templates[$key] = $device; + $module_templates = $class->get_template_list(); + foreach($module_templates as $key => $value) { + $this->cache_template($dir[$i], $key, $value); + $templates[$key] = $value; } } } } - return $list; + + return $templates; } private function get_module_class($module) @@ -436,4 +489,24 @@ private function get_module_class($module) } return $module_class; } + + private function cache_template($module, $key, $template) + { + $meta = array( + "module"=>$module + ); + $meta["name"] = ((!isset($template->name) || $template->name == "" ) ? $key : $template->name); + $meta["category"] = ((!isset($template->category) || $template->category== "" ) ? "General" : $template->category); + $meta["group"] = ((!isset($template->group) || $template->group== "" ) ? "Miscellaneous" : $template->group); + $meta["description"] = (!isset($template->description) ? "" : $template->description); + $meta["control"] = (!isset($template->control) ? false : true); + + if ($this->redis) { + $this->redis->sAdd("device:template:keys", $key); + $this->redis->hMSet("device:template:$key", $meta); + } + else { + $this->templates[$key] = $meta; + } + } } diff --git a/device_template.php b/device_template.php index deb684f..a7017b8 100644 --- a/device_template.php +++ b/device_template.php @@ -13,10 +13,10 @@ class DeviceTemplate { - private $mysqli; - private $redis; - private $log; - + protected $mysqli; + protected $redis; + protected $log; + // Module required constructor, receives parent as reference public function __construct(&$parent) { $this->mysqli = &$parent->mysqli; @@ -24,11 +24,11 @@ public function __construct(&$parent) { $this->log = new EmonLogger(__FILE__); } - public function get_list() { - return $this->load_templates(); + public function get_template_list() { + return $this->load_template_list(); } - private function load_templates() { + protected function load_template_list() { $list = array(); foreach (glob("Modules/device/data/*.json") as $file) { $content = json_decode(file_get_contents($file)); @@ -37,45 +37,45 @@ private function load_templates() { return $list; } - public function get($device) { - $device = preg_replace('/[^\p{L}_\p{N}\s-:]/u','',$device); + public function get_template($type) { + $type = preg_replace('/[^\p{L}_\p{N}\s-:]/u','', $type); - if (file_exists("Modules/device/data/$device.json")) { - return json_decode(file_get_contents("Modules/device/data/$device.json")); + if (file_exists("Modules/device/data/$type.json")) { + return json_decode(file_get_contents("Modules/device/data/$type.json")); } } - public function init($userid, $nodeid, $name, $type) { - $file = "Modules/device/data/".$type.".json"; + public function init_template($userid, $nodeid, $name, $type) { + $file = "Modules/device/data/".$type.".json"; if (file_exists($file)) { $template = json_decode(file_get_contents($file)); } else { - return array('success'=>false, 'message'=>"Template file not found '" . $file . "'"); + return array('success'=>false, 'message'=>"Template file not found '".$file."'"); } - + $feeds = $template->feeds; $inputs = $template->inputs; - + // Create feeds $result = $this->create_feeds($userid, $nodeid, $feeds); if ($result["success"] !== true) { return array('success'=>false, 'message'=>'Error while creating the feeds. ' . $result['message']); } - + // Create inputs $result = $this->create_inputs($userid, $nodeid, $inputs); if ($result !== true) { return array('success'=>false, 'message'=>'Error while creating the inputs.'); } - + // Create inputs processes - $result = $this->create_inputs_processes($feeds, $inputs); + $result = $this->create_input_processes($userid, $feeds, $inputs); if ($result["success"] !== true) { return array('success'=>false, 'message'=>'Error while creating the inputs process list. ' . $result['message']); } - + // Create feeds processes - $result = $this->create_feeds_processes($feeds, $inputs); + $result = $this->create_feed_processes($userid, $feeds, $inputs); if ($result["success"] !== true) { return array('success'=>false, 'message'=>'Error while creating the feeds process list. ' . $result['message']); } @@ -84,86 +84,103 @@ public function init($userid, $nodeid, $name, $type) { } // Create the feeds - private function create_feeds($userid, $node, &$feedArray) { + protected function create_feeds($userid, $nodeid, &$feeds) { global $feed_settings; - + require_once "Modules/feed/feed_model.php"; - $feed = new Feed($this->mysqli,$this->redis,$feed_settings); + $feed = new Feed($this->mysqli, $this->redis, $feed_settings); $result = array("success"=>true); - foreach($feedArray as $f) { + foreach($feeds as $f) { // Create each feed $name = $f->name; if (property_exists($f, "tag")) { $tag = $f->tag; } else { - $tag = $node; + $tag = $nodeid; } $datatype = constant($f->type); // DataType:: $engine = constant($f->engine); // Engine:: - $options_in = new stdClass(); + $options = new stdClass(); if (property_exists($f, "interval")) { - $options_in->interval = $f->interval; + $options->interval = $f->interval; } - $this->log->info("create_feeds() userid=$userid tag=$tag name=$name datatype=$datatype engine=$engine"); - $result = $feed->create($userid,$tag,$name,$datatype,$engine,$options_in); - if($result["success"] !== true) { - return $result; + + $feedid = $feed->get_id($userid, $name); + + if ($feedid == false) { + $this->log->info("create_feeds() userid=$userid tag=$tag name=$name datatype=$datatype engine=$engine"); + $result = $feed->create($userid, $tag, $name, $datatype, $engine, $options); + if($result["success"] !== true) { + return $result; + } + $feedid = $result["feedid"]; // Assign the created feed id to the feeds array } - $f->feedId = $result["feedid"]; // Assign the created feed id to the feeds array + + $f->feedid = $feedid; } return $result; } // Create the inputs - private function create_inputs($userid, $node, &$inputArray) { + protected function create_inputs($userid, $nodeid, &$inputs) { require_once "Modules/input/input_model.php"; - $input = new Input($this->mysqli,$this->redis, null); - - foreach($inputArray as $i) { - // Create each input - $name = $i->name; - $description = $i->description; - if(property_exists($i, "node")) { - $nodeid = $i->node; - } else { - $nodeid = $node; - } - - $inputId = $input->exists_nodeid_name($userid,$nodeid,$name); - - if ($inputId==false) { - $this->log->info("create_inputs() userid=$userid nodeid=$nodeid name=$name description=$description"); - $inputId = $input->create_input($userid, $nodeid, $name); - if(!$input->exists($inputId)) { - return false; + $input = new Input($this->mysqli, $this->redis, null); + + foreach($inputs as $i) { + // Create each input + $name = $i->name; + $description = $i->description; + if(property_exists($i, "node")) { + $node = $i->node; + } else { + $node = $nodeid; } - $input->set_fields($inputId, '{"description":"'.$description.'"}'); - } - $i->inputId = $inputId; // Assign the created input id to the inputs array + + $inputid = $input->exists_nodeid_name($userid, $node, $name); + + if ($inputid == false) { + $this->log->info("create_inputs() userid=$userid nodeid=$node name=$name description=$description"); + $inputid = $input->create_input($userid, $node, $name); + if(!$input->exists($inputid)) { + return false; + } + $input->set_fields($inputid, '{"description":"'.$description.'"}'); + } + $i->inputid = $inputid; // Assign the created input id to the inputs array } return true; } // Create the inputs process lists - private function create_inputs_processes($feedArray, $inputArray) { + protected function create_input_processes($userid, $feeds, $inputs) { + global $user, $feed_settings; + + require_once "Modules/feed/feed_model.php"; + $feed = new Feed($this->mysqli, $this->redis, $feed_settings); + require_once "Modules/input/input_model.php"; - $input = new Input($this->mysqli,$this->redis, null); - - foreach($inputArray as $i) { + $input = new Input($this->mysqli, $this->redis, $feed); + + require_once "Modules/process/process_model.php"; + $process = new Process($this->mysqli, $input, $feed, $user->get_timezone($userid)); + $process_list = $process->get_process_list(); // emoncms supported processes + + foreach($inputs as $i) { // for each input - if (isset($i->processList)) { - $inputId = $i->inputId; - $result = $this->convert_processes($feedArray, $inputArray, $i->processList); + if (isset($i->processList) || isset($i->processlist)) { + $processes = isset($i->processList) ? $i->processList : $i->processlist; + $inputid = $i->inputid; + $result = $this->convert_processes($feeds, $inputs, $processes, $process_list); if (isset($result["success"])) { return $result; // success is only filled if it was an error } $processes = implode(",", $result); if ($processes != "") { - $this->log->info("create_inputs_processes() calling input->set_processlist inputId=$inputId processes=$processes"); - $input->set_processlist($inputId, $processes); + $this->log->info("create_inputs_processes() calling input->set_processlist inputid=$inputid processes=$processes"); + $input->set_processlist($userid, $inputid, $processes, $process_list); } } } @@ -171,49 +188,53 @@ private function create_inputs_processes($feedArray, $inputArray) { return array('success'=>true); } - private function create_feeds_processes($feedArray, $inputArray) { - global $feed_settings; - + protected function create_feed_processes($userid, $feeds, $inputs) { + global $user, $feed_settings; + require_once "Modules/feed/feed_model.php"; - $feed = new Feed($this->mysqli,$this->redis,$feed_settings); - - foreach($feedArray as $f) { + $feed = new Feed($this->mysqli, $this->redis, $feed_settings); + + require_once "Modules/input/input_model.php"; + $input = new Input($this->mysqli, $this->redis, $feed); + + require_once "Modules/process/process_model.php"; + $process = new Process($this->mysqli, $input, $feed, $user->get_timezone($userid)); + $process_list = $process->get_process_list(); // emoncms supported processes + + foreach($feeds as $f) { // for each feed - if (($f->engine == Engine::VIRTUALFEED) && isset($f->processList)) { - $feedId = $f->feedId; - $result = $this->convert_processes($feedArray, $inputArray, $f->processList); + if (($f->engine == Engine::VIRTUALFEED) && (isset($f->processList) || isset($f->processlist))) { + $processes = isset($f->processList) ? $f->processList : $f->processlist; + $feedid = $f->feedid; + $result = $this->convert_processes($feeds, $inputs, $processes, $process_list); if (isset($result["success"])) { return $result; // success is only filled if it was an error } $processes = implode(",", $result); if ($processes != "") { - $this->log->info("create_feeds_processes() calling feed->set_processlist feedId=$feedId processes=$processes"); - $feed->set_processlist($feedId, $processes); + $this->log->info("create_feeds_processes() calling feed->set_processlist feedId=$feedid processes=$processes"); + $feed->set_processlist($userid, $feedid, $processes, $process_list); } } } - + return array('success'=>true); } - + // Converts template processList - private function convert_processes($feed_array, $input_array, $process_array){ + protected function convert_processes($feeds, $inputs, $processes, $process_list){ $result = array(); - if (is_array($process_array)) { - require_once "Modules/process/process_model.php"; - $process = new Process(null,null,null,null); - $process_list = $process->get_process_list(); // emoncms supported processes - + if (is_array($processes)) { $process_list_by_name = array(); - foreach ($process_list as $process_id=>$process_item) { + foreach ($process_list as $process_id => $process_item) { $name = $process_item[2]; $process_list_by_name[$name] = $process_id; } - // create each processlist - foreach($process_array as $p) { + // create each processList + foreach($processes as $p) { $proc_name = $p->process; // If process names are used map to process id @@ -246,17 +267,17 @@ private function convert_processes($feed_array, $input_array, $process_array){ if ($type === ProcessArg::VALUE) { } else if ($type === ProcessArg::INPUTID) { - $temp = $this->search_array($input_array,'name',$value); // return input array that matches $inputArray[]['name']=$value - if ($temp->inputId > 0) { - $value = $temp->inputId; + $temp = $this->search_array($inputs, 'name', $value); // return input array that matches $inputArray[]['name']=$value + if ($temp->inputid > 0) { + $value = $temp->inputid; } else { $this->log->error("convertProcess() Bad device template. Input name '$value' was not found. process='$proc_name' type='".$p->arguments->type."'"); return array('success'=>false, 'message'=>"Bad device template. Input name '$value' was not found. process='$proc_name' type='".$p->arguments->type."'"); } } else if ($type === ProcessArg::FEEDID) { - $temp = $this->search_array($feed_array,'name',$value); // return feed array that matches $feedArray[]['name']=$value - if ($temp->feedId > 0) { - $value = $temp->feedId; + $temp = $this->search_array($feeds, 'name', $value); // return feed array that matches $feedArray[]['name']=$value + if ($temp->feedid > 0) { + $value = $temp->feedid; } else { $this->log->error("convertProcess() Bad device template. Feed name '$value' was not found. process='$proc_name' type='".$p->arguments->type."'"); return array('success'=>false, 'message'=>"Bad device template. Feed name '$value' was not found. process='$proc_name' type='".$p->arguments->type."'"); @@ -279,18 +300,20 @@ private function convert_processes($feed_array, $input_array, $process_array){ $result[] = $proc_name.":".$value; } else { - $this->log->error("convertProcess() Bad device template. Missing processlist arguments. process='$proc_name'"); - return array('success'=>false, 'message'=>"Bad device template. Missing processlist arguments. process='$proc_name'"); + $this->log->error("convertProcess() Bad device template. Missing processList arguments. process='$proc_name'"); + return array('success'=>false, 'message'=>"Bad device template. Missing processList arguments. process='$proc_name'"); } } } return $result; } - private function search_array($array, $key, $val) { - foreach ($array as $item) - if (isset($item->$key) && $item->$key == $val) + protected function search_array($array, $key, $val) { + foreach ($array as $item) { + if (isset($item->$key) && $item->$key == $val) { return $item; + } + } return null; } } From 92fa154243b6044e667ad23893824caa4ce81d74 Mon Sep 17 00:00:00 2001 From: Adrian Minde Date: Thu, 16 Nov 2017 16:01:32 +0100 Subject: [PATCH 08/50] Backwards compatibility and fix feed tag verification --- device_model.php | 37 +++++++++++++++++++++++-------------- device_template.php | 2 +- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/device_model.php b/device_model.php index 44486a2..cd23b08 100644 --- a/device_model.php +++ b/device_model.php @@ -131,12 +131,19 @@ public function exists_nodeid($userid,$nodeid) public function get($id) { $id = intval($id); - if (!$this->exist($id)) $this->load_device_to_redis($id); + if (!$this->exist($id) && !$this->load_device_to_redis($id)) { + return array('success'=>false, 'message'=>'Device does not exist'); + } if ($this->redis) { // Get from redis cache - $device = $this->redis->hGetAll("device:$id"); - } else { + $device = (array) $this->redis->hGetAll("device:$id"); + if (empty($device['userid'])) { + $device = $this->load_device_to_redis($id); + } + $device['time'] = $this->redis->hget("device:lastvalue:".$id, 'time'); + } + else { // Get from mysql db $result = $this->mysqli->query("SELECT `id`, `userid`, `nodeid`, `name`, `description`, `type`, `devicekey`, `time` FROM device WHERE id = '$id'"); $device = (array) $result->fetch_object(); @@ -166,10 +173,12 @@ private function get_list_redis($userid) $deviceids = $this->redis->sMembers("user:device:$userid"); foreach ($deviceids as $id) { - $row = $this->redis->hGetAll("device:$id"); - $lastvalue = $this->redis->hMget("device:lastvalue:".$id,array('time')); - $row['time'] = $lastvalue['time']; - $devices[] = $row; + $device = $this->redis->hGetAll("device:$id"); + if (empty($device['userid'])) { + $device = $this->load_device_to_redis($id); + } + $device['time'] = $this->redis->hget("device:lastvalue:".$id, 'time'); + $devices[] = $device; } return $devices; } @@ -180,7 +189,7 @@ private function get_list_mysql($userid) $devices = array(); $result = $this->mysqli->query("SELECT `id`, `userid`, `nodeid`, `name`, `description`, `type`, `devicekey`, `time` FROM device WHERE userid = '$userid' ORDER BY nodeid, name asc"); - while ($row = (array)$result->fetch_object()) + while ($row = (array) $result->fetch_object()) { $devices[] = $row; } @@ -208,14 +217,12 @@ private function load_list_to_redis($userid) private function load_device_to_redis($id) { - $this->redis->delete("user:device:$userid"); $result = $this->mysqli->query("SELECT `id`, `userid`, `nodeid`, `name`, `description`, `type`, `devicekey` FROM device WHERE id = '$id' ORDER BY nodeid, name asc"); if ($result->num_rows>0) { - $row = $result->fetch_array(); + $row = $result->fetch_object(); $userid = $row->userid; - $this->redis->sAdd("user:device:$userid", $row->id); - $this->redis->hMSet("device:".$row->id, array( + $device = array( 'id'=>$row->id, 'userid'=>$row->userid, 'nodeid'=>$row->nodeid, @@ -223,8 +230,10 @@ private function load_device_to_redis($id) 'description'=>$row->description, 'type'=>$row->type, 'devicekey'=>$row->devicekey - )); - return true; + ); + $this->redis->sAdd("user:device:$userid", $row->id); + $this->redis->hMSet("device:".$row->id, $device); + return $device; } return false; } diff --git a/device_template.php b/device_template.php index a7017b8..b06fd8e 100644 --- a/device_template.php +++ b/device_template.php @@ -107,7 +107,7 @@ protected function create_feeds($userid, $nodeid, &$feeds) { $options->interval = $f->interval; } - $feedid = $feed->get_id($userid, $name); + $feedid = $feed->exists_tag_name($userid, $name); if ($feedid == false) { $this->log->info("create_feeds() userid=$userid tag=$tag name=$name datatype=$datatype engine=$engine"); From b9c5fe2b88019bd7f044c6413dc2958384d0c70b Mon Sep 17 00:00:00 2001 From: Adrian Minde Date: Thu, 16 Nov 2017 16:17:39 +0100 Subject: [PATCH 09/50] Add inline comments regarding backwards compatibility issues --- device_model.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/device_model.php b/device_model.php index cd23b08..9597122 100644 --- a/device_model.php +++ b/device_model.php @@ -138,6 +138,8 @@ public function get($id) if ($this->redis) { // Get from redis cache $device = (array) $this->redis->hGetAll("device:$id"); + // Verify, if the cached device contains the userid, to avoid compatibility issues + // with former versions where the userid was not cached. if (empty($device['userid'])) { $device = $this->load_device_to_redis($id); } @@ -174,6 +176,8 @@ private function get_list_redis($userid) foreach ($deviceids as $id) { $device = $this->redis->hGetAll("device:$id"); + // Verify, if the cached device contains the userid, to avoid compatibility issues + // with former versions where the userid was not cached. if (empty($device['userid'])) { $device = $this->load_device_to_redis($id); } From 6d504266a942fa92d77194383c613c169b32b810 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 16 Nov 2017 17:41:06 +0000 Subject: [PATCH 10/50] add versioning --- module.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 module.json diff --git a/module.json b/module.json new file mode 100644 index 0000000..f60114e --- /dev/null +++ b/module.json @@ -0,0 +1,4 @@ +{ + "name" : "Device", + "version" : "1.1.0" +} From 51706576b181a094f5a51bf02a17bb73f302407b Mon Sep 17 00:00:00 2001 From: TrystanLea Date: Tue, 21 Nov 2017 16:28:53 +0000 Subject: [PATCH 11/50] fix missing $tag in exists_tag_name --- data/emonth.json | 9 +++++---- device_template.php | 6 +++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/data/emonth.json b/data/emonth.json index 68fe1ac..8c101e7 100644 --- a/data/emonth.json +++ b/data/emonth.json @@ -1,7 +1,7 @@ { - "name": "EmonTH", - "category": "OpenEnergyMonitor", - "group": "Temperature & Humidity", + "name": "test", + "category": "OpenEnergyMonitor", + "group": "Temperature & Humidity", "description": "Automatic inputs and feeds creation for emonTH device.", "inputs": [ { @@ -31,7 +31,8 @@ "name": "emonth_temperature", "type": "DataType::REALTIME", "engine": "Engine::PHPFINA", - "interval": "60" + "interval": "60", + "tag": "mytag" }, { "name": "emonth_humidity", diff --git a/device_template.php b/device_template.php index b06fd8e..c35db42 100644 --- a/device_template.php +++ b/device_template.php @@ -85,6 +85,7 @@ public function init_template($userid, $nodeid, $name, $type) { // Create the feeds protected function create_feeds($userid, $nodeid, &$feeds) { + $this->log->info("create_feeds"); global $feed_settings; require_once "Modules/feed/feed_model.php"; @@ -107,7 +108,7 @@ protected function create_feeds($userid, $nodeid, &$feeds) { $options->interval = $f->interval; } - $feedid = $feed->exists_tag_name($userid, $name); + $feedid = $feed->exists_tag_name($userid, $tag, $name); if ($feedid == false) { $this->log->info("create_feeds() userid=$userid tag=$tag name=$name datatype=$datatype engine=$engine"); @@ -116,6 +117,9 @@ protected function create_feeds($userid, $nodeid, &$feeds) { return $result; } $feedid = $result["feedid"]; // Assign the created feed id to the feeds array + $this->log->info("-- $name:$tag create feedid=$feedid"); + } else { + $this->log->info("-- $name:$tag exists feedid=$feedid"); } $f->feedid = $feedid; From 35e211d3d5f5727f8282e99befd42442d5414051 Mon Sep 17 00:00:00 2001 From: TrystanLea Date: Tue, 21 Nov 2017 18:10:00 +0000 Subject: [PATCH 12/50] basic log output of device initialisation --- Views/device_dialog.js | 30 ++++++++++++++++++- Views/device_dialog.php | 10 +++++-- data/emonth.json | 7 ++--- device_template.php | 64 +++++++++++++++++++++-------------------- 4 files changed, 72 insertions(+), 39 deletions(-) diff --git a/Views/device_dialog.js b/Views/device_dialog.js index 63b7741..112b94e 100644 --- a/Views/device_dialog.js +++ b/Views/device_dialog.js @@ -273,6 +273,15 @@ var device_dialog = alert('Unable to initialize device:\n'+result.message); return false; } + + if (result.log!=undefined) { + $('#device-config-modal').modal('hide'); + + $('#device-init-modal').modal('show'); + $('#device-init-modal-label').html('Initialize Device: '+device.name+''); + $("#device-init-modal-log").html("Device initialized
"+result.log+"
"); + $(".pre-init").hide(); $(".post-init").show(); + } } } else { @@ -289,6 +298,17 @@ var device_dialog = alert('Unable to initialize device:\n'+result.message); return false; } + + if (result.log!=undefined) { + $('#device-config-modal').modal('hide'); + $('#device-init-modal').modal('show'); + $('#device-init-modal-label').html('Initialize Device: '+device.name+''); + + $('#device-init-modal').modal('show'); + $('#device-init-modal-label').html('Initialize Device: '+device.name+''); + $("#device-init-modal-log").html("Device initialized
"+result.log+"
"); + $(".pre-init").hide(); $(".post-init").show(); + } } } $('#device-config-modal').modal('hide'); @@ -310,6 +330,8 @@ var device_dialog = 'loadInit': function(device) { this.device = device; + $(".pre-init").show(); $(".post-init").hide(); + $('#device-init-modal').modal('show'); $('#device-init-modal-label').html('Initialize Device: '+device.name+''); @@ -326,7 +348,13 @@ var device_dialog = alert('Unable to initialize device:\n'+result.message); return false; } - $('#device-init-modal').modal('hide'); + + if (result.log!=undefined) { + $("#device-init-modal-log").html("Device initialized
"+result.log+"
"); + $(".pre-init").hide(); $(".post-init").show(); + } + + // $('#device-init-modal').modal('hide'); return true; }); diff --git a/Views/device_dialog.php b/Views/device_dialog.php index 27c56c6..d78b625 100644 --- a/Views/device_dialog.php +++ b/Views/device_dialog.php @@ -110,6 +110,7 @@

@@ -150,4 +154,4 @@ $(window).resize(function() { device_dialog.adjustConfigModal() }); - \ No newline at end of file + diff --git a/data/emonth.json b/data/emonth.json index 8c101e7..bdeb938 100644 --- a/data/emonth.json +++ b/data/emonth.json @@ -1,7 +1,7 @@ { - "name": "test", - "category": "OpenEnergyMonitor", - "group": "Temperature & Humidity", + "name": "EmonTH", + "category": "OpenEnergyMonitor", + "group": "Temperature & Humidity", "description": "Automatic inputs and feeds creation for emonTH device.", "inputs": [ { @@ -32,7 +32,6 @@ "type": "DataType::REALTIME", "engine": "Engine::PHPFINA", "interval": "60", - "tag": "mytag" }, { "name": "emonth_humidity", diff --git a/device_template.php b/device_template.php index c35db42..178c059 100644 --- a/device_template.php +++ b/device_template.php @@ -56,43 +56,32 @@ public function init_template($userid, $nodeid, $name, $type) { $feeds = $template->feeds; $inputs = $template->inputs; + $log = ""; + // Create feeds - $result = $this->create_feeds($userid, $nodeid, $feeds); - if ($result["success"] !== true) { - return array('success'=>false, 'message'=>'Error while creating the feeds. ' . $result['message']); - } + $log .= $this->create_feeds($userid, $nodeid, $feeds); // Create inputs - $result = $this->create_inputs($userid, $nodeid, $inputs); - if ($result !== true) { - return array('success'=>false, 'message'=>'Error while creating the inputs.'); - } + $log .= $this->create_inputs($userid, $nodeid, $inputs); // Create inputs processes - $result = $this->create_input_processes($userid, $feeds, $inputs); - if ($result["success"] !== true) { - return array('success'=>false, 'message'=>'Error while creating the inputs process list. ' . $result['message']); - } + $log .= $this->create_input_processes($userid, $feeds, $inputs); // Create feeds processes - $result = $this->create_feed_processes($userid, $feeds, $inputs); - if ($result["success"] !== true) { - return array('success'=>false, 'message'=>'Error while creating the feeds process list. ' . $result['message']); - } + $log .= $this->create_feed_processes($userid, $feeds, $inputs); - return array('success'=>true, 'message'=>'Device initialized'); + return array('success'=>true, 'message'=>'Device initialized', 'log'=>$log); } // Create the feeds protected function create_feeds($userid, $nodeid, &$feeds) { - $this->log->info("create_feeds"); global $feed_settings; + $log = "feeds:\n"; + require_once "Modules/feed/feed_model.php"; $feed = new Feed($this->mysqli, $this->redis, $feed_settings); - $result = array("success"=>true); - foreach($feeds as $f) { // Create each feed $name = $f->name; @@ -114,23 +103,26 @@ protected function create_feeds($userid, $nodeid, &$feeds) { $this->log->info("create_feeds() userid=$userid tag=$tag name=$name datatype=$datatype engine=$engine"); $result = $feed->create($userid, $tag, $name, $datatype, $engine, $options); if($result["success"] !== true) { - return $result; + $log .= "-- ERROR $name:$tag\n"; + } else { + $feedid = $result["feedid"]; // Assign the created feed id to the feeds array + $log .= "-- CREATE $name:$tag\n"; } - $feedid = $result["feedid"]; // Assign the created feed id to the feeds array - $this->log->info("-- $name:$tag create feedid=$feedid"); } else { - $this->log->info("-- $name:$tag exists feedid=$feedid"); + $log .= "-- EXISTS $name:$tag\n"; } $f->feedid = $feedid; } - return $result; + return $log; } // Create the inputs protected function create_inputs($userid, $nodeid, &$inputs) { require_once "Modules/input/input_model.php"; $input = new Input($this->mysqli, $this->redis, null); + + $log = "inputs:\n"; foreach($inputs as $i) { // Create each input @@ -148,13 +140,17 @@ protected function create_inputs($userid, $nodeid, &$inputs) { $this->log->info("create_inputs() userid=$userid nodeid=$node name=$name description=$description"); $inputid = $input->create_input($userid, $node, $name); if(!$input->exists($inputid)) { - return false; + $log .= "-- ERROR $node:$name\n"; + } else { + $log .= "-- CREATE $node:$name\n"; } $input->set_fields($inputid, '{"description":"'.$description.'"}'); + } else { + $log .= "-- EXISTS $node:$name\n"; } $i->inputid = $inputid; // Assign the created input id to the inputs array } - return true; + return $log; } // Create the inputs process lists @@ -171,6 +167,8 @@ protected function create_input_processes($userid, $feeds, $inputs) { $process = new Process($this->mysqli, $input, $feed, $user->get_timezone($userid)); $process_list = $process->get_process_list(); // emoncms supported processes + $log = "input processes:\n"; + foreach($inputs as $i) { // for each input if (isset($i->processList) || isset($i->processlist)) { @@ -178,18 +176,19 @@ protected function create_input_processes($userid, $feeds, $inputs) { $inputid = $i->inputid; $result = $this->convert_processes($feeds, $inputs, $processes, $process_list); if (isset($result["success"])) { - return $result; // success is only filled if it was an error + $log .= "-- set processlist ERROR $inputid ".$result["message"]; } $processes = implode(",", $result); if ($processes != "") { $this->log->info("create_inputs_processes() calling input->set_processlist inputid=$inputid processes=$processes"); $input->set_processlist($userid, $inputid, $processes, $process_list); + $log .= "-- set processlist inputid=$inputid processes=$processes\n"; } } } - return array('success'=>true); + return $log; } protected function create_feed_processes($userid, $feeds, $inputs) { @@ -205,6 +204,8 @@ protected function create_feed_processes($userid, $feeds, $inputs) { $process = new Process($this->mysqli, $input, $feed, $user->get_timezone($userid)); $process_list = $process->get_process_list(); // emoncms supported processes + $log = "feed processes:\n"; + foreach($feeds as $f) { // for each feed if (($f->engine == Engine::VIRTUALFEED) && (isset($f->processList) || isset($f->processlist))) { @@ -212,18 +213,19 @@ protected function create_feed_processes($userid, $feeds, $inputs) { $feedid = $f->feedid; $result = $this->convert_processes($feeds, $inputs, $processes, $process_list); if (isset($result["success"])) { - return $result; // success is only filled if it was an error + $log .= "-- set processlist ERROR $feedid ".$result["message"]; } $processes = implode(",", $result); if ($processes != "") { $this->log->info("create_feeds_processes() calling feed->set_processlist feedId=$feedid processes=$processes"); $feed->set_processlist($userid, $feedid, $processes, $process_list); + $log .= "-- set processlist feedid=$inputid processes=$processes\n"; } } } - return array('success'=>true); + return $log; } // Converts template processList From 17b3f22db5ed6df51f01938643bbe03107e936c2 Mon Sep 17 00:00:00 2001 From: TrystanLea Date: Tue, 21 Nov 2017 18:17:15 +0000 Subject: [PATCH 13/50] show device name and minor formatting --- Views/device_dialog.js | 8 +++----- device_template.php | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Views/device_dialog.js b/Views/device_dialog.js index 112b94e..dd5cda5 100644 --- a/Views/device_dialog.js +++ b/Views/device_dialog.js @@ -278,7 +278,7 @@ var device_dialog = $('#device-config-modal').modal('hide'); $('#device-init-modal').modal('show'); - $('#device-init-modal-label').html('Initialize Device: '+device.name+''); + $('#device-init-modal-label').html('Initialize Device: '+name+''); $("#device-init-modal-log").html("Device initialized
"+result.log+"
"); $(".pre-init").hide(); $(".post-init").show(); } @@ -301,11 +301,9 @@ var device_dialog = if (result.log!=undefined) { $('#device-config-modal').modal('hide'); + $('#device-init-modal').modal('show'); - $('#device-init-modal-label').html('Initialize Device: '+device.name+''); - - $('#device-init-modal').modal('show'); - $('#device-init-modal-label').html('Initialize Device: '+device.name+''); + $('#device-init-modal-label').html('Initialize Device: '+name+''); $("#device-init-modal-log").html("Device initialized
"+result.log+"
"); $(".pre-init").hide(); $(".post-init").show(); } diff --git a/device_template.php b/device_template.php index 178c059..a21129c 100644 --- a/device_template.php +++ b/device_template.php @@ -183,7 +183,7 @@ protected function create_input_processes($userid, $feeds, $inputs) { if ($processes != "") { $this->log->info("create_inputs_processes() calling input->set_processlist inputid=$inputid processes=$processes"); $input->set_processlist($userid, $inputid, $processes, $process_list); - $log .= "-- set processlist inputid=$inputid processes=$processes\n"; + $log .= "-- set processlist inputid=$inputid\n $processes\n"; } } } @@ -220,7 +220,7 @@ protected function create_feed_processes($userid, $feeds, $inputs) { if ($processes != "") { $this->log->info("create_feeds_processes() calling feed->set_processlist feedId=$feedid processes=$processes"); $feed->set_processlist($userid, $feedid, $processes, $process_list); - $log .= "-- set processlist feedid=$inputid processes=$processes\n"; + $log .= "-- set processlist feedid=$inputid $processes\n"; } } } From f45695df888f645ba168d5a7ac71848b73870561 Mon Sep 17 00:00:00 2001 From: TrystanLea Date: Tue, 21 Nov 2017 20:17:11 +0000 Subject: [PATCH 14/50] improve readability of device init log --- data/emonth.json | 4 ++-- device_template.php | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/data/emonth.json b/data/emonth.json index bdeb938..5119451 100644 --- a/data/emonth.json +++ b/data/emonth.json @@ -9,7 +9,7 @@ "description": "Temperature C", "processList": [ { - "process": "1", + "process": "log_to_feed", "arguments": {"type": "ProcessArg::FEEDID", "value": "emonth_temperature" } } ] @@ -19,7 +19,7 @@ "description": "Humidity Rh%", "processList": [ { - "process": "1", + "process": "log_to_feed", "arguments": {"type": "ProcessArg::FEEDID", "value": "emonth_humidity" } } ] diff --git a/device_template.php b/device_template.php index a21129c..22148ed 100644 --- a/device_template.php +++ b/device_template.php @@ -65,7 +65,7 @@ public function init_template($userid, $nodeid, $name, $type) { $log .= $this->create_inputs($userid, $nodeid, $inputs); // Create inputs processes - $log .= $this->create_input_processes($userid, $feeds, $inputs); + $log .= $this->create_input_processes($userid, $feeds, $inputs, $nodeid); // Create feeds processes $log .= $this->create_feed_processes($userid, $feeds, $inputs); @@ -103,18 +103,18 @@ protected function create_feeds($userid, $nodeid, &$feeds) { $this->log->info("create_feeds() userid=$userid tag=$tag name=$name datatype=$datatype engine=$engine"); $result = $feed->create($userid, $tag, $name, $datatype, $engine, $options); if($result["success"] !== true) { - $log .= "-- ERROR $name:$tag\n"; + $log .= "-- ERROR $tag:$name\n"; } else { $feedid = $result["feedid"]; // Assign the created feed id to the feeds array - $log .= "-- CREATE $name:$tag\n"; + $log .= "-- CREATE $tag:$name\n"; } } else { - $log .= "-- EXISTS $name:$tag\n"; + $log .= "-- EXISTS $tag:$name\n"; } $f->feedid = $feedid; } - return $log; + return $log."\n"; } // Create the inputs @@ -150,11 +150,11 @@ protected function create_inputs($userid, $nodeid, &$inputs) { } $i->inputid = $inputid; // Assign the created input id to the inputs array } - return $log; + return $log."\n"; } // Create the inputs process lists - protected function create_input_processes($userid, $feeds, $inputs) { + protected function create_input_processes($userid, $feeds, $inputs, $nodeid) { global $user, $feed_settings; require_once "Modules/feed/feed_model.php"; @@ -183,12 +183,12 @@ protected function create_input_processes($userid, $feeds, $inputs) { if ($processes != "") { $this->log->info("create_inputs_processes() calling input->set_processlist inputid=$inputid processes=$processes"); $input->set_processlist($userid, $inputid, $processes, $process_list); - $log .= "-- set processlist inputid=$inputid\n $processes\n"; + $log .= "-- SET ".$nodeid.":".$i->name."\n $processes\n"; } } } - return $log; + return $log."\n"; } protected function create_feed_processes($userid, $feeds, $inputs) { @@ -225,7 +225,7 @@ protected function create_feed_processes($userid, $feeds, $inputs) { } } - return $log; + return $log."\n"; } // Converts template processList From 03394e3a951b7bfd562804e6d98877c1e82862f1 Mon Sep 17 00:00:00 2001 From: TrystanLea Date: Tue, 21 Nov 2017 21:46:04 +0000 Subject: [PATCH 15/50] - remove inline editor - use of mysql prepared statements for all queries with string based parameters --- Views/device_dialog.js | 5 ++ Views/device_dialog.php | 1 + Views/device_view.php | 19 ++-- device_model.php | 193 ++++++++++++++++++++++++---------------- 4 files changed, 129 insertions(+), 89 deletions(-) diff --git a/Views/device_dialog.js b/Views/device_dialog.js index dd5cda5..737826d 100644 --- a/Views/device_dialog.js +++ b/Views/device_dialog.js @@ -323,6 +323,11 @@ var device_dialog = device_dialog.loadDelete(device_dialog.device, null); }); + + $("#device-init").off('click').on('click', function () { + $('#device-config-modal').modal('hide'); + device_dialog.loadInit(device_dialog.device); + }); }, 'loadInit': function(device) { diff --git a/Views/device_dialog.php b/Views/device_dialog.php index d78b625..59020e2 100644 --- a/Views/device_dialog.php +++ b/Views/device_dialog.php @@ -100,6 +100,7 @@ diff --git a/Views/device_view.php b/Views/device_view.php index 7e77cc3..a042a1f 100644 --- a/Views/device_view.php +++ b/Views/device_view.php @@ -68,17 +68,15 @@ table.deletedata = false; table.fields = { //'id':{'type':"fixed"}, - 'nodeid':{'title':'','type':"text"}, - 'name':{'title':'','type':"text"}, - 'description':{'title':'','type':"text"}, + 'nodeid':{'title':'','type':"fixed"}, + 'name':{'title':'','type':"fixed"}, + 'description':{'title':'','type':"fixed"}, 'typename':{'title':'','type':"fixed"}, - 'devicekey':{'title':'','type':"text"}, + 'devicekey':{'title':'','type':"fixed"}, 'time':{'title':'', 'type':"updated"}, - //'public':{'title':"", 'type':"icon", 'trueicon':"icon-globe", 'falseicon':"icon-lock"}, + // 'public':{'title':"", 'type':"icon", 'trueicon':"icon-globe", 'falseicon':"icon-lock"}, // Actions - 'edit-action':{'title':'', 'type':"edit"}, 'delete-action':{'title':'', 'type':"delete"}, - 'init-action':{'title':'', 'type':"iconbasic", 'icon':'icon-refresh'}, 'config-action':{'title':'', 'type':"iconconfig", 'icon':'icon-wrench'} } @@ -141,13 +139,6 @@ function updaterStart(func, interval) device_dialog.loadDelete(localDevice, row); }); - $("#table").on('click', '.icon-refresh', function() { - - // Get device of clicked row - var localDevice = table.data[$(this).attr('row')]; - device_dialog.loadInit(localDevice); - }); - $("#table").on('click', '.icon-wrench', function() { // Get device of clicked row diff --git a/device_model.php b/device_model.php index 9597122..ff00339 100644 --- a/device_model.php +++ b/device_model.php @@ -26,7 +26,12 @@ public function __construct($mysqli,$redis) public function devicekey_session($devicekey) { - $devicekey = $this->mysqli->real_escape_string($devicekey); + // 1. Only allow alphanumeric characters + // if (!ctype_alnum($devicekey)) return array(); + + // 2. Only allow 32 character length + if (strlen($devicekey)!=32) return array(); + $session = array(); $time = time(); @@ -47,30 +52,31 @@ public function devicekey_session($devicekey) } else { - $result = $this->mysqli->query("SELECT id, userid, nodeid FROM device WHERE devicekey='$devicekey'"); - if ($result->num_rows == 1) - { - $row = $result->fetch_array(); - if ($row['id'] != 0) - { - $session['userid'] = $row['userid']; - $session['read'] = 0; - $session['write'] = 1; - $session['admin'] = 0; - $session['lang'] = "en"; // API access is always in english - $session['username'] = "API"; - $session['deviceid'] = $row['id']; - $session['nodeid'] = $row['nodeid']; + $stmt = $this->mysqli->prepare("SELECT id, userid, nodeid FROM device WHERE devicekey=?"); + $stmt->bind_param("s",$devicekey); + $stmt->execute(); + $stmt->bind_result($id,$userid,$nodeid); + $result = $stmt->fetch(); + $stmt->close(); + + if ($result && $id>0) { + $session['userid'] = $userid; + $session['read'] = 0; + $session['write'] = 1; + $session['admin'] = 0; + $session['lang'] = "en"; // API access is always in english + $session['username'] = "API"; + $session['deviceid'] = $id; + $session['nodeid'] = $nodeid; - if ($this->redis) { - $this->redis->set("device:key:$devicekey:user",$row['userid']); - $this->redis->set("device:key:$devicekey:device",$row['id']); - $this->redis->set("device:key:$devicekey:node",$row['nodeid']); - $this->redis->hMset("device:lastvalue:".$row['id'], array('time' => $time)); - } else { - //$time = date("Y-n-j H:i:s", $time); - $this->mysqli->query("UPDATE device SET time='$time' WHERE id = '".$row['id']."'"); - } + if ($this->redis) { + $this->redis->set("device:key:$devicekey:user",$userid); + $this->redis->set("device:key:$devicekey:device",$id); + $this->redis->set("device:key:$devicekey:node",$nodeid); + $this->redis->hMset("device:lastvalue:$id", array('time' => $time)); + } else { + //$time = date("Y-n-j H:i:s", $time); + $this->mysqli->query("UPDATE device SET time='$time' WHERE id = '$id"); } } } @@ -97,7 +103,7 @@ public function exist($id) } } else { - $id = intval($id); + $id = (int) $id; $result = $this->mysqli->query("SELECT id FROM device WHERE id = '$id'"); if ($result->num_rows > 0) $device_exist = true; } @@ -108,29 +114,37 @@ public function exist($id) public function exists_name($userid, $name) { - $userid = intval($userid); + $userid = (int) $userid; $name = preg_replace('/[^\p{L}_\p{N}\s-:]/u','',$name); - $result = $this->mysqli->query("SELECT id FROM device WHERE userid = '$userid' AND name = '$name'"); - if ($result->num_rows>0) { $row = $result->fetch_array(); return $row['id']; } else return false; + + $stmt = $this->mysqli->prepare("SELECT id FROM device WHERE userid=? AND name=?"); + $stmt->bind_param("is",$userid,$name); + $stmt->execute(); + $stmt->bind_result($id); + $result = $stmt->fetch(); + $stmt->close(); + + if ($result && $id>0) return $id; else return false; } public function exists_nodeid($userid,$nodeid) { - $userid = intval($userid); + $userid = (int) $userid; $nodeid = preg_replace('/[^\p{L}_\p{N}\s-:]/u','',$nodeid); - $result = $this->mysqli->query("SELECT id FROM device WHERE userid = '$userid' AND nodeid = '$nodeid'"); + + $stmt = $this->mysqli->prepare("SELECT id FROM device WHERE userid=? AND nodeid=?"); + $stmt->bind_param("is",$userid,$nodeid); + $stmt->execute(); + $stmt->bind_result($id); + $result = $stmt->fetch(); + $stmt->close(); - if (isset($result->num_rows) && $result->num_rows > 0) { - $row = $result->fetch_array(); - return $row['id']; - } else { - return false; - } + if ($result && $id>0) return $id; else return false; } public function get($id) { - $id = intval($id); + $id = (int) $id; if (!$this->exist($id) && !$this->load_device_to_redis($id)) { return array('success'=>false, 'message'=>'Device does not exist'); } @@ -147,7 +161,7 @@ public function get($id) } else { // Get from mysql db - $result = $this->mysqli->query("SELECT `id`, `userid`, `nodeid`, `name`, `description`, `type`, `devicekey`, `time` FROM device WHERE id = '$id'"); + $result = $this->mysqli->query("SELECT `id`,`userid`,`nodeid`,`name`,`description`,`type`,`devicekey`,`time` FROM device WHERE id = '$id'"); $device = (array) $result->fetch_object(); } return $device; @@ -164,7 +178,7 @@ public function get_list($userid) private function get_list_redis($userid) { - $userid = intval($userid); + $userid = (int) $userid; if (!$this->redis->exists("user:device:$userid")) { $this->log->info("Load devices to redis in get_list_redis"); @@ -189,19 +203,18 @@ private function get_list_redis($userid) private function get_list_mysql($userid) { - $userid = intval($userid); - $devices = array(); + $userid = (int) $userid; + $devices = array(); $result = $this->mysqli->query("SELECT `id`, `userid`, `nodeid`, `name`, `description`, `type`, `devicekey`, `time` FROM device WHERE userid = '$userid' ORDER BY nodeid, name asc"); - while ($row = (array) $result->fetch_object()) - { - $devices[] = $row; - } + while ($row = (array) $result->fetch_object()) $devices[] = $row; + return $devices; } private function load_list_to_redis($userid) { + $userid = (int) $userid; $this->redis->delete("user:device:$userid"); $result = $this->mysqli->query("SELECT `id`, `userid`, `nodeid`, `name`, `description`, `type`, `devicekey` FROM device WHERE userid = '$userid' ORDER BY nodeid, name asc"); while ($row = $result->fetch_object()) @@ -221,6 +234,7 @@ private function load_list_to_redis($userid) private function load_device_to_redis($id) { + $id = (int) $id; $result = $this->mysqli->query("SELECT `id`, `userid`, `nodeid`, `name`, `description`, `type`, `devicekey` FROM device WHERE id = '$id' ORDER BY nodeid, name asc"); if ($result->num_rows>0) { $row = $result->fetch_object(); @@ -244,7 +258,7 @@ private function load_device_to_redis($id) public function autocreate($userid, $_nodeid, $_type) { - $userid = intval($userid); + $userid = (int) $userid; $nodeid = preg_replace('/[^\p{L}_\p{N}\s-:]/u','',$_nodeid); if ($_nodeid != $nodeid) return array("success"=>false, "message"=>"Invalid nodeid"); @@ -271,22 +285,37 @@ public function autocreate($userid, $_nodeid, $_type) public function create($userid, $nodeid, $name, $description, $type) { - $userid = intval($userid); + $userid = (int) $userid; + $nodeid = preg_replace('/[^\p{L}_\p{N}\s-:]/u', '', $nodeid); + if (isset($name)) { $name = preg_replace('/[^\p{L}_\p{N}\s-:]/u', '', $name); + } else { + $name = $nodeid; } - else $name = $nodeid; if (isset($description)) { $description= preg_replace('/[^\p{L}_\p{N}\s-:]/u', '', $description); + } else { + $description = ''; + } + + if (isset($type)) { + $type= preg_replace('/[^\p{L}_\p{N}\s-:]/u', '', $type); + } else { + $type = ''; } - else $description = ''; if (!$this->exists_nodeid($userid, $nodeid)) { $devicekey = md5(uniqid(mt_rand(), true)); - $result = $this->mysqli->query("INSERT INTO device (`userid`, `nodeid`, `name`, `description`, `type`, `devicekey`) VALUES ('$userid','$nodeid','$name','$description','$type','$devicekey')"); + $stmt = $this->mysqli->prepare("INSERT INTO device (userid,nodeid,name,description,type,devicekey) VALUES (?,?,?,?,?,?)"); + $stmt->bind_param("isssss",$userid,$nodeid,$name,$description,$type,$devicekey); + $result = $stmt->execute(); + $stmt->close(); + if (!$result) return array('success'=>false, 'message'=>_("Error creating device")); + $deviceid = $this->mysqli->insert_id; if ($deviceid > 0) { @@ -298,12 +327,12 @@ public function create($userid, $nodeid, $name, $description, $type) } else return array('success'=>false, 'result'=>"SQL returned invalid insert feed id"); } - else return array('success'=>false, 'message'=>'Device for the node "'.$nodeid.'" already exists'); + else return array('success'=>false, 'message'=>'Device already exists'); } public function delete($id) { - $id = intval($id); + $id = (int) $id; if (!$this->exist($id)) return array('success'=>false, 'message'=>'Device does not exist'); if ($this->redis) { @@ -323,35 +352,48 @@ public function delete($id) } } - public function set_fields($id, $fields) + public function set_fields($id,$fields) { - $id = intval($id); + $id = (int) $id; if (!$this->exist($id)) return array('success'=>false, 'message'=>'Device does not exist'); - $fields = json_decode(stripslashes($fields)); - $array = array(); - - // Repeat this line changing the field name to add fields that can be updated: - if (isset($fields->name)) $array[] = "`name` = '".preg_replace('/[^\p{L}_\p{N}\s-:]/u','',$fields->name)."'"; - if (isset($fields->description)) $array[] = "`description` = '".preg_replace('/[^\p{L}_\p{N}\s-:]/u','',$fields->description)."'"; - if (isset($fields->nodeid)) $array[] = "`nodeid` = '".preg_replace('/[^\p{L}_\p{N}\s-:]/u','',$fields->nodeid)."'"; - if (isset($fields->devicekey)) { - $devicekey = preg_replace('/[^\p{L}_\p{N}\s-:]/u','',$fields->devicekey); - $result = $this->mysqli->query("SELECT devicekey FROM device WHERE devicekey='$devicekey'"); - if ($result->num_rows > 0) - { - return array('success'=>false, 'message'=>'Field devicekey is invalid'); // is duplicate - } - $array[] = "`devicekey` = '".$devicekey."'"; + $success = false; + + if (isset($fields->name)) { + if (preg_replace('/[^\p{N}\p{L}_\s-:]/u','',$fields->name)!=$fields->name) return array('success'=>false, 'message'=>'invalid characters in device name'); + $stmt = $this->mysqli->prepare("UPDATE device SET name = ? WHERE id = ?"); + $stmt->bind_param("si",$fields->name,$id); + if ($stmt->execute()) $success = true; + $stmt->close(); } - if (isset($fields->type)) $array[] = "`type` = '".preg_replace('/[^\/\|\,\w\s-:]/','',$fields->type)."'"; - // Convert to a comma seperated string for the mysql query - $fieldstr = implode(",",$array); - $this->mysqli->query("UPDATE device SET ".$fieldstr." WHERE `id` = '$id'"); + if (isset($fields->description)) { + if (preg_replace('/[^\p{N}\p{L}_\s-:]/u','',$fields->description)!=$fields->description) return array('success'=>false, 'message'=>'invalid characters in device description'); + $stmt = $this->mysqli->prepare("UPDATE device SET description = ? WHERE id = ?"); + $stmt->bind_param("si",$fields->description,$id); + if ($stmt->execute()) $success = true; + $stmt->close(); + } + + if (isset($fields->nodeid)) { + if (preg_replace('/[^\p{N}\p{L}_\s-:]/u','',$fields->nodeid)!=$fields->nodeid) return array('success'=>false, 'message'=>'invalid characters in device nodeid'); + $stmt = $this->mysqli->prepare("UPDATE device SET nodeid = ? WHERE id = ?"); + $stmt->bind_param("si",$fields->nodeid,$id); + if ($stmt->execute()) $success = true; + $stmt->close(); + } + + if (isset($fields->type)) { + if (preg_replace('/[^\/\|\,\w\s-:]/','',$fields->type)!=$fields->type) return array('success'=>false, 'message'=>'invalid characters in device type'); + $stmt = $this->mysqli->prepare("UPDATE device SET type = ? WHERE id = ?"); + $stmt->bind_param("si",$fields->type,$id); + if ($stmt->execute()) $success = true; + $stmt->close(); + } + + if ($success){ - if ($this->mysqli->affected_rows>0){ if ($this->redis) { $result = $this->mysqli->query("SELECT userid FROM device WHERE id='$id'"); $row = (array) $result->fetch_object(); @@ -359,6 +401,7 @@ public function set_fields($id, $fields) $this->load_list_to_redis($row['userid']); } } + return array('success'=>true, 'message'=>'Field updated'); } else { return array('success'=>false, 'message'=>'Field could not be updated'); @@ -434,7 +477,7 @@ private function get_template_meta($key) public function init_template($id) { - $id = intval($id); + $id = (int) $id; $device = $this->get($id); if (isset($device['type']) && $device['type'] != 'null' && $device['type']) { From 4180986cfe8918d0659b6982d58f5127942a30db Mon Sep 17 00:00:00 2001 From: TrystanLea Date: Wed, 22 Nov 2017 07:52:02 +0000 Subject: [PATCH 16/50] save and init button in dialog --- Views/device_dialog.js | 4 ++++ Views/device_dialog.php | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Views/device_dialog.js b/Views/device_dialog.js index 737826d..baf5ecd 100644 --- a/Views/device_dialog.js +++ b/Views/device_dialog.js @@ -10,10 +10,14 @@ var device_dialog = if (device != null) { this.deviceType = device.type; this.device = device; + $("#device-init").show(); + $("#device-save").html("Save"); } else { this.deviceType = null; this.device = null; + $("#device-init").hide(); + $("#device-save").html("Save & Initialize"); } this.drawConfig(); diff --git a/Views/device_dialog.php b/Views/device_dialog.php index 59020e2..25fb3b0 100644 --- a/Views/device_dialog.php +++ b/Views/device_dialog.php @@ -100,7 +100,7 @@ From 7286c9cbe36576c63cb81e0a1cc01d8235c07753 Mon Sep 17 00:00:00 2001 From: TrystanLea Date: Wed, 22 Nov 2017 08:46:56 +0000 Subject: [PATCH 17/50] ip address sanitisation --- device_controller.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/device_controller.php b/device_controller.php index 7c4c6bc..a792bed 100644 --- a/device_controller.php +++ b/device_controller.php @@ -37,6 +37,10 @@ function device_controller() if ($route->subaction=="request") { $ip = $_SERVER['REMOTE_ADDR']; + $ip_parts = explode(".",$ip); + for ($i=0; $iget("device_auth_allow"); // Only show authentication details to allowed ip address if ($allow_ip==$ip) { @@ -60,6 +64,11 @@ function device_controller() // 3. User allows device to receive authentication details else if ($route->subaction=="allow" && $session['write']) { $ip = get("ip"); + + $ip_parts = explode(".",$ip); + for ($i=0; $iset("device_auth_allow",$ip); // Temporary availability of auth for device ip address $redis->expire("device_auth_allow",60); // Expire after 60 seconds $redis->del("device_auth"); From 527a7d1bd71852e1b02639f0e125ae8e0269e0a1 Mon Sep 17 00:00:00 2001 From: TrystanLea Date: Wed, 22 Nov 2017 09:16:47 +0000 Subject: [PATCH 18/50] processlist log --- device_template.php | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/device_template.php b/device_template.php index 22148ed..e3f2bd6 100644 --- a/device_template.php +++ b/device_template.php @@ -176,14 +176,15 @@ protected function create_input_processes($userid, $feeds, $inputs, $nodeid) { $inputid = $i->inputid; $result = $this->convert_processes($feeds, $inputs, $processes, $process_list); if (isset($result["success"])) { - $log .= "-- set processlist ERROR $inputid ".$result["message"]; + $log .= "-- SET ERROR ".$nodeid.":".$i->name." ".$result["message"]; } $processes = implode(",", $result); if ($processes != "") { $this->log->info("create_inputs_processes() calling input->set_processlist inputid=$inputid processes=$processes"); $input->set_processlist($userid, $inputid, $processes, $process_list); - $log .= "-- SET ".$nodeid.":".$i->name."\n $processes\n"; + $log .= "-- SET ".$nodeid.":".$i->name."\n"; + $log .= $this->log_processlist($processes,$input,$feed,$process_list); } } } @@ -213,14 +214,15 @@ protected function create_feed_processes($userid, $feeds, $inputs) { $feedid = $f->feedid; $result = $this->convert_processes($feeds, $inputs, $processes, $process_list); if (isset($result["success"])) { - $log .= "-- set processlist ERROR $feedid ".$result["message"]; + $log .= "-- SET ERROR $feedid ".$result["message"]; } $processes = implode(",", $result); if ($processes != "") { $this->log->info("create_feeds_processes() calling feed->set_processlist feedId=$feedid processes=$processes"); $feed->set_processlist($userid, $feedid, $processes, $process_list); - $log .= "-- set processlist feedid=$inputid $processes\n"; + $log .= "-- SET feedid=$feedid\n"; + $log .= $this->log_processlist($processes,$input,$feed,$process_list); } } } @@ -322,4 +324,25 @@ protected function search_array($array, $key, $val) { } return null; } + + private function log_processlist($processes,$input,$feed,$process_list) { + $log = ""; + $process_parts = explode(",",$processes); + foreach ($process_parts as $pair) { + $pair = explode(":",$pair); + $pid = $pair[0]; + $arg = $pair[1]; + + if ($process_list[$pid][1]==ProcessArg::INPUTID) { + $i = $input->get_details($arg); + $arg = $f['nodeid'].":".$f['name']; + } + else if ($process_list[$pid][1]==ProcessArg::FEEDID) { + $f = $feed->get($arg); + $arg = $f['tag'].":".$f['name']; + } + $log .= " ".$process_list[$pid][2]." ".$arg."\n"; + } + return $log; + } } From 6765d5c55c4f6b5ecb32f1bd7930c235fcf83bea Mon Sep 17 00:00:00 2001 From: TrystanLea Date: Wed, 22 Nov 2017 10:10:59 +0000 Subject: [PATCH 19/50] - show init message on device creation - show re-init button without init message for subsequent initialisation --- Views/device_dialog.js | 93 +++++++++++++++-------------------------- Views/device_dialog.php | 2 +- 2 files changed, 35 insertions(+), 60 deletions(-) diff --git a/Views/device_dialog.js b/Views/device_dialog.js index baf5ecd..0f548b5 100644 --- a/Views/device_dialog.js +++ b/Views/device_dialog.js @@ -269,23 +269,9 @@ var device_dialog = } update(); - if (device_dialog.device.type != device_dialog.deviceType - && device_dialog.deviceType != null) { - - var result = device.initTemplate(device_dialog.device.id); - if (typeof result.success !== 'undefined' && !result.success) { - alert('Unable to initialize device:\n'+result.message); - return false; - } - - if (result.log!=undefined) { - $('#device-config-modal').modal('hide'); - - $('#device-init-modal').modal('show'); - $('#device-init-modal-label').html('Initialize Device: '+name+''); - $("#device-init-modal-log").html("Device initialized
"+result.log+"
"); - $(".pre-init").hide(); $(".post-init").show(); - } + if (device_dialog.device.type != device_dialog.deviceType && device_dialog.deviceType != null) { + $('#device-config-modal').modal('hide'); + device_dialog.loadInit(false); // skip_check = false } } else { @@ -297,20 +283,9 @@ var device_dialog = update(); if (result && device_dialog.deviceType != null) { - var result = device.initTemplate(result); - if (typeof result.success !== 'undefined' && !result.success) { - alert('Unable to initialize device:\n'+result.message); - return false; - } - - if (result.log!=undefined) { - $('#device-config-modal').modal('hide'); - - $('#device-init-modal').modal('show'); - $('#device-init-modal-label').html('Initialize Device: '+name+''); - $("#device-init-modal-log").html("Device initialized
"+result.log+"
"); - $(".pre-init").hide(); $(".post-init").show(); - } + $('#device-config-modal').modal('hide'); + device_dialog.device = {id: result, name: name}; + device_dialog.loadInit(false); // skip_check = false } } $('#device-config-modal').modal('hide'); @@ -322,49 +297,49 @@ var device_dialog = }); $("#device-delete").off('click').on('click', function () { - $('#device-config-modal').modal('hide'); - device_dialog.loadDelete(device_dialog.device, null); }); $("#device-init").off('click').on('click', function () { - $('#device-config-modal').modal('hide'); - device_dialog.loadInit(device_dialog.device); + $('#device-config-modal').modal('hide'); + device_dialog.loadInit(true); // skip_check = true }); }, - 'loadInit': function(device) { - this.device = device; + 'loadInit': function(skip_check) { - $(".pre-init").show(); $(".post-init").hide(); - $('#device-init-modal').modal('show'); - $('#device-init-modal-label').html('Initialize Device: '+device.name+''); + $('#device-init-modal-label').html('Initialize Device: '+device_dialog.device.name+''); // Initialize callbacks - this.registerInitEvents(); + if (!skip_check) { + $(".pre-init").show(); $(".post-init").hide(); + + $("#device-init-confirm").off('click').on('click', function() { + var result = device.initTemplate(device_dialog.device.id); + device_dialog.showInitLog(result); + }); + } else { + var result = device.initTemplate(device_dialog.device.id); + device_dialog.showInitLog(result); + } }, + + 'showInitLog': function (result) { - 'registerInitEvents':function() { + $(".pre-init").hide(); $(".post-init").show(); - $("#device-init-confirm").off('click').on('click', function() { - var result = device.initTemplate(device_dialog.device.id); - - if (typeof result.success !== 'undefined' && !result.success) { - alert('Unable to initialize device:\n'+result.message); - return false; - } - - if (result.log!=undefined) { - $("#device-init-modal-log").html("Device initialized
"+result.log+"
"); - $(".pre-init").hide(); $(".post-init").show(); - } - - // $('#device-init-modal').modal('hide'); - - return true; - }); + if (typeof result.success !== 'undefined' && !result.success) { + alert('Unable to initialize device:\n'+result.message); + return false; + } + + if (result.log!=undefined) { + $("#device-init-modal-log").html("Device initialized
"+result.log+"
"); + } + + return true; }, 'loadDelete': function(device, tablerow) { diff --git a/Views/device_dialog.php b/Views/device_dialog.php index 25fb3b0..abf72ff 100644 --- a/Views/device_dialog.php +++ b/Views/device_dialog.php @@ -2,7 +2,7 @@ global $path; ?> - + @@ -117,22 +138,42 @@

diff --git a/Views/device_view.php b/Views/device_view.php index 76a55a1..0ab21ed 100644 --- a/Views/device_view.php +++ b/Views/device_view.php @@ -63,9 +63,7 @@ 'dummy-5':{'title':'', 'type':"blank"}, 'time':{'title':'', 'type':"group-updated"}, 'dummy-7':{'title':'', 'type':"blank"}, - 'dummy-8':{'title':'', 'type':"blank"}, - 'dummy-9':{'title':'', 'type':"blank"}, - 'dummy-10':{'title':'', 'type':"blank"} + 'dummy-8':{'title':'', 'type':"blank"} } table.deletedata = false; diff --git a/data/OpenEnergyMonitor/emonpi-HEM.json b/data/OpenEnergyMonitor/emonpi-HEM.json index 91db450..11b4ae7 100644 --- a/data/OpenEnergyMonitor/emonpi-HEM.json +++ b/data/OpenEnergyMonitor/emonpi-HEM.json @@ -10,11 +10,11 @@ "processList": [ { "process": "log_to_feed", - "arguments": {"type": "ProcessArg::FEEDID", "value": "use" } + "arguments": { "type": "ProcessArg::FEEDID", "value": "use" } }, { "process": "power_to_kwh", - "arguments": {"type": "ProcessArg::FEEDID", "value": "use_kwh" } + "arguments": { "type": "ProcessArg::FEEDID", "value": "use_kwh" } } ] } diff --git a/data/OpenEnergyMonitor/emonth.json b/data/OpenEnergyMonitor/emonth.json index 5119451..9f03e4f 100644 --- a/data/OpenEnergyMonitor/emonth.json +++ b/data/OpenEnergyMonitor/emonth.json @@ -8,20 +8,20 @@ "name": "temperature", "description": "Temperature C", "processList": [ - { - "process": "log_to_feed", - "arguments": {"type": "ProcessArg::FEEDID", "value": "emonth_temperature" } - } + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "emonth_temperature" } + } ] }, { "name": "humidity", "description": "Humidity Rh%", "processList": [ - { - "process": "log_to_feed", - "arguments": {"type": "ProcessArg::FEEDID", "value": "emonth_humidity" } - } + { + "process": "log_to_feed", + "arguments": {"type": "ProcessArg::FEEDID", "value": "emonth_humidity" } + } ] } ], @@ -31,7 +31,7 @@ "name": "emonth_temperature", "type": "DataType::REALTIME", "engine": "Engine::PHPFINA", - "interval": "60", + "interval": "60" }, { "name": "emonth_humidity", diff --git a/device_controller.php b/device_controller.php index 32bc762..c21bbfe 100644 --- a/device_controller.php +++ b/device_controller.php @@ -85,7 +85,7 @@ function device_controller() else if ($route->action == "autocreate") { if ($session['userid']>0 && $session['write']) $result = $device->autocreate($session['userid'],get('nodeid'),get('type')); } - else if ($route->action == "template" && $route->subaction != "init") { + else if ($route->action == "template" && $route->subaction != "prepare" && $route->subaction != "init") { if ($route->subaction == "list") { if ($session['userid']>0 && $session['write']) $result = $device->get_template_list_full(); } @@ -106,12 +106,12 @@ function device_controller() else if ($route->action == "delete") $result = $device->delete($deviceid); else if ($route->action == 'set') $result = $device->set_fields($deviceid, get('fields')); else if ($route->action == "setnewdevicekey") $result = $device->set_new_devicekey($deviceid); - else if ($route->action == 'template' && - $route->subaction == 'init') { + else if ($route->action == 'template') { if (isset($_GET['type'])) { $device->set_fields($deviceid, json_encode(array("type"=>$_GET['type']))); } - $result = $device->init_template($deviceid); + if ($route->subaction == 'prepare') $result = $device->prepare_template($deviceid); + else if ($route->subaction == 'init') $result = $device->init_template($deviceid, get('template')); } } } diff --git a/device_model.php b/device_model.php index 9328398..3143c4c 100644 --- a/device_model.php +++ b/device_model.php @@ -517,8 +517,8 @@ private function get_template_meta($key) } return $template; } - - public function init_template($id) + + public function prepare_template($id) { $id = (int) $id; @@ -529,7 +529,31 @@ public function init_template($id) $module = $template['module']; $class = $this->get_module_class($module); if ($class != null) { - return $class->init_template($device['userid'], $device['nodeid'], $device['name'], $device['type']); + return $class->prepare_template($device); + } + } + return array('success'=>false, 'message'=>'Device template does not exist'); + } + else { + return array('success'=>false, 'message'=>'Device type not specified'); + } + return array('success'=>false, 'message'=>'Unknown error while preparing device initialization'); + } + + public function init_template($id, $template) + { + $id = intval($id); + + if (isset($template)) $template = json_decode($template); + + $device = $this->get($id); + if (isset($device['type']) && $device['type'] != 'null' && $device['type']) { + $meta = $this->get_template_meta($device['type']); + if (isset($meta)) { + $module = $meta['module']; + $class = $this->get_module_class($module); + if ($class != null) { + return $class->init_template($device['userid'], $template); } } else { diff --git a/device_template.php b/device_template.php index 240738b..fe4c6d2 100644 --- a/device_template.php +++ b/device_template.php @@ -1,12 +1,12 @@ load_template_list(); + if (!isset($list[$type])) { + return array('success'=>false, 'message'=>'Device template "'.$type.'" not found'); + } return $list[$type]; } - - public function init_template($userid, $nodeid, $name, $type) { - - $userid = (int) $userid; - - $list = $this->load_template_list(); - if (!isset($list[$type])) return array('success'=>false, 'message'=>"Template file not found '".$type."'"); - $template = $list[$type]; - - $feeds = $template->feeds; - $inputs = $template->inputs; + + public function prepare_template($device) { - $log = ""; + $userid = intval($device['userid']); - // Create feeds - $log .= $this->create_feeds($userid, $nodeid, $feeds); + $result = $this->get_template($device['type']); + if (!is_object($result)) { + return $result; + } - // Create inputs - $log .= $this->create_inputs($userid, $nodeid, $inputs); + if (isset($result->feeds)) { + $feeds = $result->feeds; + $this->prepare_feeds($userid, $device['nodeid'], $feeds); + } + else { + $feeds = []; + } - // Create inputs processes - $log .= $this->create_input_processes($userid, $feeds, $inputs, $nodeid); + if (isset($result->inputs)) { + $inputs = $result->inputs; + $this->prepare_inputs($userid, $device['nodeid'], $inputs); + } + else { + $inputs = []; + } - // Create feeds processes - $log .= $this->create_feed_processes($userid, $feeds, $inputs); + if (!empty($feeds)) { + $this->prepare_input_processes($userid, $feeds, $inputs); + } + if (!empty($inputs)) { + $this->prepare_feed_processes($userid, $feeds, $inputs); + } - return array('success'=>true, 'message'=>'Device initialized', 'log'=>$log); + return array('success'=>true, 'feeds'=>$feeds, 'inputs'=>$inputs); } - // Create the feeds - protected function create_feeds($userid, $nodeid, &$feeds) { - global $feed_settings; + public function init_template($userid, $template) { + + $userid = intval($userid); - $log = "feeds:\n"; + if (!is_object($template)) { + return array('success'=>false, 'message'=>'Invalid device template'); + } + + if (isset($template->feeds)) { + $feeds = $template->feeds; + $this->create_feeds($userid, $feeds); + } + else { + $feeds = []; + } + + if (isset($template->inputs)) { + $inputs = $template->inputs; + $this->create_inputs($userid, $inputs); + } + else { + $inputs = []; + } + + if (!empty($inputs)) { + $this->create_input_processes($userid, $feeds, $inputs); + } + if (!empty($feeds)) { + $this->create_feed_processes($userid, $feeds, $inputs); + } + + return array('success'=>true, 'message'=>'Device initialized'); + } + + protected function prepare_feeds($userid, $nodeid, &$feeds) { + global $feed_settings; require_once "Modules/feed/feed_model.php"; $feed = new Feed($this->mysqli, $this->redis, $feed_settings); foreach($feeds as $f) { - // Create each feed $name = $f->name; - if (property_exists($f, "tag")) { - $tag = $f->tag; - } else { - $tag = $nodeid; + if (!isset($f->tag)) { + $f->tag = $nodeid; } - $datatype = constant($f->type); // DataType:: - $engine = constant($f->engine); // Engine:: - $options = new stdClass(); - if (property_exists($f, "interval")) { - $options->interval = $f->interval; - } - - $feedid = $feed->exists_tag_name($userid, $tag, $name); + $feedid = $feed->exists_tag_name($userid, $f->tag, $f->name); if ($feedid == false) { - $this->log->info("create_feeds() userid=$userid tag=$tag name=$name datatype=$datatype engine=$engine"); - $result = $feed->create($userid, $tag, $name, $datatype, $engine, $options); - if($result["success"] !== true) { - $log .= "-- ERROR $tag|$name\n"; - } else { - $feedid = $result["feedid"]; // Assign the created feed id to the feeds array - $log .= "-- CREATE $tag|$name\n"; - } - } else { - $log .= "-- EXISTS $tag|$name\n"; + $f->action = 'create'; + $f->id = -1; + } + else { + $f->action = 'none'; + $f->id = $feedid; } - - $f->feedid = $feedid; } - return $log."\n"; } - // Create the inputs - protected function create_inputs($userid, $nodeid, &$inputs) { + protected function prepare_inputs($userid, $nodeid, &$inputs) { require_once "Modules/input/input_model.php"; $input = new Input($this->mysqli, $this->redis, null); - $log = "inputs:\n"; - foreach($inputs as $i) { - // Create each input - $name = $i->name; - $description = $i->description; - if(property_exists($i, "node")) { - $node = $i->node; - } else { - $node = $nodeid; + if(!isset($i->node)) { + $i->node = $nodeid; } - $inputid = $input->exists_nodeid_name($userid, $node, $name); - + $inputid = $input->exists_nodeid_name($userid, $i->node, $i->name); if ($inputid == false) { - $this->log->info("create_inputs() userid=$userid nodeid=$node name=$name description=$description"); - $inputid = $input->create_input($userid, $node, $name); - if(!$input->exists($inputid)) { - $log .= "-- ERROR $node|$name\n"; - } else { - $log .= "-- CREATE $node|$name\n"; - } - $input->set_fields($inputid, '{"description":"'.$description.'"}'); - } else { - $log .= "-- EXISTS $node|$name\n"; + $i->action = 'create'; + $i->id = -1; + } + else { + $i->action = 'none'; + $i->id = $inputid; } - $i->inputid = $inputid; // Assign the created input id to the inputs array } - return $log."\n"; } - - // Create the inputs process lists - protected function create_input_processes($userid, $feeds, $inputs, $nodeid) { + + // Prepare the input process lists + protected function prepare_input_processes($userid, $feeds, &$inputs) { global $user, $feed_settings; require_once "Modules/feed/feed_model.php"; @@ -170,32 +178,38 @@ protected function create_input_processes($userid, $feeds, $inputs, $nodeid) { $process = new Process($this->mysqli, $input, $feed, $user->get_timezone($userid)); $process_list = $process->get_process_list(); // emoncms supported processes - $log = "input processes:\n"; - foreach($inputs as $i) { // for each input - if (isset($i->processList) || isset($i->processlist)) { - $processes = isset($i->processList) ? $i->processList : $i->processlist; - $inputid = $i->inputid; - $result = $this->convert_processes($feeds, $inputs, $processes, $process_list); - if (isset($result["success"])) { - $log .= "-- SET ERROR ".$nodeid."|".$i->name." ".$result["message"]; - } - - $processes = implode(",", $result); - if ($processes != "") { - $this->log->info("create_inputs_processes() calling input->set_processlist inputid=$inputid processes=$processes"); - $input->set_processlist($userid, $inputid, $processes, $process_list); - $log .= "-- SET ".$nodeid."|".$i->name."\n"; - $log .= $this->log_processlist($processes,$input,$feed,$process_list); + if (isset($i->id) && (isset($i->processList) || isset($i->processlist))) { + $processes = isset($i->processList) ? $i->processList : $i->processlist; + if (!empty($processes)) { + $processes = $this->prepare_processes($feeds, $inputs, $processes, $process_list); + if (isset($i->action) && $i->action != 'create') { + $processes_input = $input->get_processlist($i->id); + if (!isset($processes['success'])) { + if ($processes_input == '' && $processes != '') { + $i->action = 'set'; + } + else if ($processes_input != $processes) { + $i->action = 'override'; + } + } + else { + if ($processes_input == '') { + $i->action = 'set'; + } + else { + $i->action = 'override'; + } + } + } } } } - - return $log."\n"; } - - protected function create_feed_processes($userid, $feeds, $inputs) { + + // Prepare the feed process lists + protected function prepare_feed_processes($userid, &$feeds, $inputs) { global $user, $feed_settings; require_once "Modules/feed/feed_model.php"; @@ -208,115 +222,280 @@ protected function create_feed_processes($userid, $feeds, $inputs) { $process = new Process($this->mysqli, $input, $feed, $user->get_timezone($userid)); $process_list = $process->get_process_list(); // emoncms supported processes - $log = "feed processes:\n"; - foreach($feeds as $f) { // for each feed - if (($f->engine == Engine::VIRTUALFEED) && (isset($f->processList) || isset($f->processlist))) { - $processes = isset($f->processList) ? $f->processList : $f->processlist; - $feedid = $f->feedid; - $result = $this->convert_processes($feeds, $inputs, $processes, $process_list); - if (isset($result["success"])) { - $log .= "-- SET ERROR $feedid ".$result["message"]; - } - - $processes = implode(",", $result); - if ($processes != "") { - $this->log->info("create_feeds_processes() calling feed->set_processlist feedId=$feedid processes=$processes"); - $feed->set_processlist($userid, $feedid, $processes, $process_list); - $log .= "-- SET feedid=$feedid\n"; - $log .= $this->log_processlist($processes,$input,$feed,$process_list); + if ($f->engine == Engine::VIRTUALFEED && isset($f->id) && (isset($f->processList) || isset($f->processlist))) { + $processes = isset($f->processList) ? $f->processList : $f->processlist; + if (!empty($processes)) { + $processes = $this->prepare_processes($feeds, $inputs, $processes, $process_list); + if (isset($f->action) && $f->action != 'create') { + $processes_input = $feed->get_processlist($f->id); + if (!isset($processes['success'])) { + if ($processes_input == '' && $processes != '') { + $f->action = 'set'; + } + else if ($processes_input != $processes) { + $f->action = 'override'; + } + } + else { + if ($processes_input == '') { + $f->action = 'set'; + } + else { + $f->action = 'override'; + } + } + } } } } + } + + // Prepare template processes + protected function prepare_processes($feeds, $inputs, &$processes, $process_list) { + $process_list_by_name = array(); + foreach ($process_list as $process_id => $process_item) { + $name = $process_item[2]; + $process_list_by_name[$name] = $process_id; + } + $processes_converted = array(); - return $log."\n"; + $failed = false; + foreach($processes as &$process) { + // If process names are used map to process id + if (isset($process_list_by_name[$process->process])) $process->process = $process_list_by_name[$process->process]; + + $process_id = $process->process; + if (!isset($process_list[$process_id])) { + $this->log->error("prepare_processes() Process '$process_id' not supported. Module missing?"); + return array('success'=>false, 'message'=>"Process '$process_id' not supported. Module missing?"); + } + + $process->name = $process_list[$process->process][0]; + + // Arguments + if(isset($process->arguments)) { + if(isset($process->arguments->type)) { + $process->arguments->type = @constant($process->arguments->type); // ProcessArg:: + $process_type = $process_list[$process_id][1]; // get emoncms process ProcessArg + + if ($process_type != $process->arguments->type) { + $this->log->error("prepare_processes() Bad device template. Missmatch ProcessArg type. Got '$process->arguments->type' expected '$process_type'. process='$process_id'"); + return array('success'=>false, 'message'=>"Bad device template. Missmatch ProcessArg type. Got '$process->arguments->type' expected '$process_type'. process='$process_id'"); + } + + $result = $this->convert_process($feeds, $inputs, $process); + if (isset($result["success"])) { + $failed = true; + } + else { + $processes_converted[] = $result; + } + } + else { + $this->log->error("prepare_processes() Bad device template. Argument type is missing, set to NONE if not required. process='$process->process' type='".$process->arguments->type."'"); + return array('success'=>false, 'message'=>"Bad device template. Argument type is missing, set to NONE if not required. process='$process->process' type='".$process->arguments->type."'"); + } + } + else { + $this->log->error("prepare_processes() Bad device template. Missing processList arguments. process='$process->process'"); + return array('success'=>false, 'message'=>"Bad device template. Missing processList arguments. process='$process->process'"); + } + } + if (!$failed) { + return implode(",", $processes_converted); + } + return array('success'=>false, 'message'=>"Unable to convert all prepared processes"); } - // Converts template processList - protected function convert_processes($feeds, $inputs, $processes, $process_list){ - $result = array(); - - if (is_array($processes)) { - $process_list_by_name = array(); - foreach ($process_list as $process_id => $process_item) { - $name = $process_item[2]; - $process_list_by_name[$name] = $process_id; + // Create the feeds + protected function create_feeds($userid, &$feeds) { + global $feed_settings; + + require_once "Modules/feed/feed_model.php"; + $feed = new Feed($this->mysqli, $this->redis, $feed_settings); + + foreach($feeds as $f) { + $datatype = constant($f->type); // DataType:: + $engine = constant($f->engine); // Engine:: + $options = new stdClass(); + if (property_exists($f, "interval")) { + $options->interval = $f->interval; } - - // create each processList - foreach($processes as $p) { - $proc_name = $p->process; - - // If process names are used map to process id - if (isset($process_list_by_name[$proc_name])) $proc_name = $process_list_by_name[$proc_name]; + + if ($f->action === 'create') { + $this->log->info("create_feeds() userid=$userid tag=$f->tag name=$f->name datatype=$datatype engine=$engine"); - if (!isset($process_list[$proc_name])) { - $this->log->error("convertProcess() Process '$proc_name' not supported. Module missing?"); - return array('success'=>false, 'message'=>"Process '$proc_name' not supported. Module missing?"); + $result = $feed->create($userid, $f->tag, $f->name, $datatype, $engine, $options); + if($result["success"] !== true) { + $this->log->error("create_feeds() failed for userid=$userid tag=$f->tag name=$f->name datatype=$datatype engine=$engine"); + } + else { + $f->id = $result["feedid"]; // Assign the created feed id to the feeds array } + } + } + } - // Arguments - if(isset($p->arguments)) { - if(isset($p->arguments->type)) { - $type = @constant($p->arguments->type); // ProcessArg:: - $process_type = $process_list[$proc_name][1]; // get emoncms process ProcessArg + // Create the inputs + protected function create_inputs($userid, &$inputs) { + require_once "Modules/input/input_model.php"; + $input = new Input($this->mysqli, $this->redis, null); + + foreach($inputs as $i) { + if ($i->action === 'create') { + $this->log->info("create_inputs() userid=$userid nodeid=$i->node name=$i->name description=$i->description"); + + $inputid = $input->create_input($userid, $i->node, $i->name); + if(!$input->exists($inputid)) { + $this->log->error("create_inputs() failed for userid=$userid nodeid=$i->node name=$i->name description=$i->description"); + } + else { + $input->set_fields($inputid, '{"description":"'.$i->description.'"}'); + $i->id = $inputid; // Assign the created input id to the inputs array + } + } + } + } - if ($process_type != $type) { - $this->log->error("convertProcess() Bad device template. Missmatch ProcessArg type. Got '$type' expected '$process_type'. process='$proc_name' type='".$p->arguments->type."'"); - return array('success'=>false, 'message'=>"Bad device template. Missmatch ProcessArg type. Got '$type' expected '$process_type'. process='$proc_name' type='".$p->arguments->type."'"); + // Create the input process lists + protected function create_input_processes($userid, $feeds, $inputs) { + global $user, $feed_settings; + + require_once "Modules/feed/feed_model.php"; + $feed = new Feed($this->mysqli, $this->redis, $feed_settings); + + require_once "Modules/input/input_model.php"; + $input = new Input($this->mysqli, $this->redis, $feed); + + require_once "Modules/process/process_model.php"; + $process = new Process($this->mysqli, $input, $feed, $user->get_timezone($userid)); + $process_list = $process->get_process_list(); // emoncms supported processes + + foreach($inputs as $i) { + if ($i->action !== 'none') { + if (isset($i->id) && (isset($i->processList) || isset($i->processlist))) { + $processes = isset($i->processList) ? $i->processList : $i->processlist; + $inputid = $i->id; + + if (is_array($processes)) { + $processes_converted = array(); + + $failed = false; + foreach($processes as $process) { + $result = $this->convert_process($feeds, $inputs, $process); + if (isset($result["success"])) { + $failed = true; + break; + } + $processes_converted[] = $result; } - - if (isset($p->arguments->value)) { - $value = $p->arguments->value; - } else if ($type === ProcessArg::NONE) { - $value = 0; - } else { - $this->log->error("convertProcess() Bad device template. Undefined argument value. process='$proc_name' type='".$p->arguments->type."'"); - return array('success'=>false, 'message'=>"Bad device template. Undefined argument value. process='$proc_name' type='".$p->arguments->type."'"); + $processes = implode(",", $processes_converted); + if (!$failed && $processes != "") { + $this->log->info("create_inputs_processes() calling input->set_processlist inputid=$inputid processes=$processes"); + $input->set_processlist($userid, $inputid, $processes, $process_list); } + } + } + } + } + } - if ($type === ProcessArg::VALUE) { - } else if ($type === ProcessArg::INPUTID) { - $temp = $this->search_array($inputs, 'name', $value); // return input array that matches $inputArray[]['name']=$value - if ($temp->inputid > 0) { - $value = $temp->inputid; - } else { - $this->log->error("convertProcess() Bad device template. Input name '$value' was not found. process='$proc_name' type='".$p->arguments->type."'"); - return array('success'=>false, 'message'=>"Bad device template. Input name '$value' was not found. process='$proc_name' type='".$p->arguments->type."'"); - } - } else if ($type === ProcessArg::FEEDID) { - $temp = $this->search_array($feeds, 'name', $value); // return feed array that matches $feedArray[]['name']=$value - if ($temp->feedid > 0) { - $value = $temp->feedid; - } else { - $this->log->error("convertProcess() Bad device template. Feed name '$value' was not found. process='$proc_name' type='".$p->arguments->type."'"); - return array('success'=>false, 'message'=>"Bad device template. Feed name '$value' was not found. process='$proc_name' type='".$p->arguments->type."'"); + // Create the feed process lists + protected function create_feed_processes($userid, $feeds, $inputs) { + global $user, $feed_settings; + + require_once "Modules/feed/feed_model.php"; + $feed = new Feed($this->mysqli, $this->redis, $feed_settings); + + require_once "Modules/input/input_model.php"; + $input = new Input($this->mysqli, $this->redis, $feed); + + require_once "Modules/process/process_model.php"; + $process = new Process($this->mysqli, $input, $feed, $user->get_timezone($userid)); + $process_list = $process->get_process_list(); // emoncms supported processes + + foreach($feeds as $f) { + if ($f->action !== 'none') { + if ($f->engine == Engine::VIRTUALFEED && isset($f->id) && (isset($f->processList) || isset($f->processlist))) { + $processes = isset($f->processList) ? $f->processList : $f->processlist; + $feedid = $f->id; + + if (is_array($processes)) { + $processes_converted = array(); + + $failed = false; + foreach($processes as $process) { + $result = $this->convert_process($feeds, $inputs, $process); + if (isset($result["success"])) { + $failed = true; + break; } - } else if ($type === ProcessArg::NONE) { - $value = 0; - } else if ($type === ProcessArg::TEXT) { -// } else if ($type === ProcessArg::SCHEDULEID) { //not supporte for now - } else { - $this->log->error("convertProcess() Bad device template. Unsuported argument type. process='$proc_name' type='".$p->arguments->type."'"); - return array('success'=>false, 'message'=>"Bad device template. Unsuported argument type. process='$proc_name' type='".$p->arguments->type."'"); + $processes_converted[] = $result; + } + $processes = implode(",", $processes_converted); + if (!$failed && $processes != "") { + $this->log->info("create_feeds_processes() calling feed->set_processlist feedId=$feedid processes=$processes"); + $feed->set_processlist($userid, $feedid, $processes, $process_list); } - - } else { - $this->log->error("convertProcess() Bad device template. Argument type is missing, set to NONE if not required. process='$proc_name' type='".$p->arguments->type."'"); - return array('success'=>false, 'message'=>"Bad device template. Argument type is missing, set to NONE if not required. process='$proc_name' type='".$p->arguments->type."'"); } - - $this->log->info("convertProcess() process process='$proc_name' type='".$p->arguments->type."' value='" . $value . "'"); - $result[] = $proc_name.":".$value; - - } else { - $this->log->error("convertProcess() Bad device template. Missing processList arguments. process='$proc_name'"); - return array('success'=>false, 'message'=>"Bad device template. Missing processList arguments. process='$proc_name'"); } } } - return $result; + } + + // Converts template process + protected function convert_process($feeds, $inputs, $process) { + + if (isset($process->arguments->value)) { + $value = $process->arguments->value; + } + else if ($process->arguments->type === ProcessArg::NONE) { + $value = 0; + } + else { + $this->log->error("convertProcess() Bad device template. Undefined argument value. process='$process->process' type='".$process->arguments->type."'"); + return array('success'=>false, 'message'=>"Bad device template. Undefined argument value. process='$process->process' type='".$process->arguments->type."'"); + } + + if ($process->arguments->type === ProcessArg::VALUE) { + } + else if ($process->arguments->type === ProcessArg::INPUTID) { + $temp = $this->search_array($inputs, 'name', $value); // return input array that matches $inputArray[]['name']=$value + if (isset($temp->id) && $temp->id > 0) { + $value = $temp->id; + } + else { + $this->log->info("convertProcess() Input name '$value' was not found. process='$process->process' type='".$process->arguments->type."'"); + return array('success'=>false, 'message'=>"Input name '$value' was not found. process='$process->process' type='".$process->arguments->type."'"); + } + } + else if ($process->arguments->type === ProcessArg::FEEDID) { + $temp = $this->search_array($feeds, 'name', $value); // return feed array that matches $feedArray[]['name']=$value + if (isset($temp->id) && $temp->id > 0) { + $value = $temp->id; + } + else { + $this->log->info("convertProcess() Feed name '$value' was not found. process='$process->process' type='".$process->arguments->type."'"); + return array('success'=>false, 'message'=>"Feed name '$value' was not found. process='$process->process' type='".$process->arguments->type."'"); + } + } + else if ($process->arguments->type === ProcessArg::NONE) { + $value = 0; + } + else if ($process->arguments->type === ProcessArg::TEXT) { + } + else if ($process->arguments->type === ProcessArg::SCHEDULEID) { + //not supporte for now + } + else { + $this->log->error("convertProcess() Bad device template. Unsuported argument type. process='$process->process' type='".$process->arguments->type."'"); + return array('success'=>false, 'message'=>"Bad device template. Unsuported argument type. process='$process->process' type='".$process->arguments->type."'"); + } + + $this->log->info("convertProcess() process process='$process->process' type='".$process->arguments->type."' value='" . $value . "'"); + return $process->process.":".$value; } protected function search_array($array, $key, $val) { @@ -327,13 +506,4 @@ protected function search_array($array, $key, $val) { } return null; } - - private function log_processlist($processes,$input,$feed,$process_list) { - $log = ""; - $process_parts = explode(",",$processes); - foreach ($process_parts as $pair) { - $log .= " ".$pair."\n"; - } - return $log; - } } From 886a22720f3137e328e45aa560529784d8cbab75 Mon Sep 17 00:00:00 2001 From: Adrian Minde Date: Tue, 19 Dec 2017 22:09:56 +0100 Subject: [PATCH 31/50] Fix init dry-run checkbox deselection --- Views/device_dialog.js | 20 ++++++++------------ device_template.php | 2 +- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/Views/device_dialog.js b/Views/device_dialog.js index d46af18..8253ab3 100644 --- a/Views/device_dialog.js +++ b/Views/device_dialog.js @@ -355,10 +355,10 @@ var device_dialog = var feed = result.feeds[i]; var row = ""; if (feed.action.toLowerCase() == "none") { - row += ""; + row += ""; } else { - row += ""; + row += ""; } row += ""+device_dialog.drawInitAction(feed.action)+"" row += ""+feed.tag+""+feed.name+""; @@ -379,10 +379,10 @@ var device_dialog = var input = result.inputs[i]; var row = ""; if (input.action.toLowerCase() == "none") { - row += ""; + row += ""; } else { - row += ""; + row += ""; } row += ""+device_dialog.drawInitAction(input.action)+"" row += ""+input.node+""+input.name+""+input.description+""; @@ -469,10 +469,8 @@ var device_dialog = device_dialog.deviceTemplate.feeds.length > 0) { var feeds = device_dialog.deviceTemplate.feeds; - $("#device-init-feeds-table tr").find('input[type="checkbox"]:checked') - .each(function (i, row) { - - template['feeds'].push(feeds[i]); + $("#device-init-feeds-table tr").find('input[type="checkbox"]:checked').each(function() { + template['feeds'].push(feeds[$(this).attr("row")]); }); } @@ -481,10 +479,8 @@ var device_dialog = device_dialog.deviceTemplate.inputs.length > 0) { var inputs = device_dialog.deviceTemplate.inputs; - $("#device-init-inputs-table tr").find('input[type="checkbox"]:checked') - .each(function (i, row) { - - template['inputs'].push(inputs[i]); + $("#device-init-inputs-table tr").find('input[type="checkbox"]:checked').each(function() { + template['inputs'].push(inputs[$(this).attr("row")]); }); } diff --git a/device_template.php b/device_template.php index fe4c6d2..dd9f61b 100644 --- a/device_template.php +++ b/device_template.php @@ -482,7 +482,7 @@ protected function convert_process($feeds, $inputs, $process) { } } else if ($process->arguments->type === ProcessArg::NONE) { - $value = 0; + $value = ""; } else if ($process->arguments->type === ProcessArg::TEXT) { } From 1ee0a5d36a985133b1e62a82c054f7a46d656628 Mon Sep 17 00:00:00 2001 From: TrystanLea Date: Mon, 8 Jan 2018 12:21:47 +0000 Subject: [PATCH 32/50] update schema --- device_schema.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/device_schema.php b/device_schema.php index ace40a6..3b44a78 100644 --- a/device_schema.php +++ b/device_schema.php @@ -1,7 +1,7 @@ array('type' => 'int(11)', 'Null'=>'NO', 'Key'=>'PRI', 'Extra'=>'auto_increment'), + 'id' => array('type' => 'int(11)', 'Null'=>false, 'Key'=>'PRI', 'Extra'=>'auto_increment'), 'userid' => array('type' => 'int(11)'), 'nodeid' => array('type' => 'text'), 'name' => array('type' => 'text', 'default'=>''), @@ -9,4 +9,4 @@ 'type' => array('type' => 'varchar(32)'), 'devicekey' => array('type' => 'varchar(64)'), 'time' => array('type' => 'int(10)') -); \ No newline at end of file +); From 7bf448534922fde46d25c17ef15fdb21a5e3827d Mon Sep 17 00:00:00 2001 From: Adrian Minde Date: Wed, 17 Jan 2018 15:19:35 +0100 Subject: [PATCH 33/50] Send template init arguments as post parameters --- Views/device.js | 2 +- device_controller.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Views/device.js b/Views/device.js index 03b940a..20bb83b 100644 --- a/Views/device.js +++ b/Views/device.js @@ -58,7 +58,7 @@ var device = { 'initTemplate':function(id, template) { var result = {}; - $.ajax({ url: path+"device/template/init.json", data: "id="+id+"&template="+JSON.stringify(template), dataType: 'json', async: false, success: function(data) {result = data;} }); + $.ajax({ url: path+"device/template/init.json?id="+id, type: 'POST', data: "template="+JSON.stringify(template), dataType: 'json', async: false, success: function(data) {result = data;} }); return result; } } diff --git a/device_controller.php b/device_controller.php index c21bbfe..1b0215a 100644 --- a/device_controller.php +++ b/device_controller.php @@ -111,7 +111,7 @@ function device_controller() $device->set_fields($deviceid, json_encode(array("type"=>$_GET['type']))); } if ($route->subaction == 'prepare') $result = $device->prepare_template($deviceid); - else if ($route->subaction == 'init') $result = $device->init_template($deviceid, get('template')); + else if ($route->subaction == 'init') $result = $device->init_template($deviceget, $_POST['template']); } } } From 02e424fa731b529bed960b0248b1aa10e9d93b98 Mon Sep 17 00:00:00 2001 From: Adrian Minde Date: Wed, 17 Jan 2018 15:21:32 +0100 Subject: [PATCH 34/50] Use standard prepared template for init if none was passed --- device_template.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/device_template.php b/device_template.php index dd9f61b..0918973 100644 --- a/device_template.php +++ b/device_template.php @@ -90,7 +90,11 @@ public function init_template($userid, $template) { $userid = intval($userid); if (!is_object($template)) { - return array('success'=>false, 'message'=>'Invalid device template'); + $result = $this->prepare_template($device); + if (isset($result["success"]) && !$result["success"]) { + return $result; + } + $template = $result; } if (isset($template->feeds)) { From 0746571d69f58469e487bea336aabecf1b1b84d5 Mon Sep 17 00:00:00 2001 From: Adrian Minde Date: Wed, 17 Jan 2018 22:04:02 +0100 Subject: [PATCH 35/50] Make sure, template passed to init is an object --- device_template.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/device_template.php b/device_template.php index 0918973..925c90b 100644 --- a/device_template.php +++ b/device_template.php @@ -89,13 +89,14 @@ public function init_template($userid, $template) { $userid = intval($userid); - if (!is_object($template)) { + if (empty($template)) { $result = $this->prepare_template($device); if (isset($result["success"]) && !$result["success"]) { return $result; } $template = $result; } + if (!is_object($template)) $template = (object) $template; if (isset($template->feeds)) { $feeds = $template->feeds; From 241da578315567a245d4d072445b3bad35932f52 Mon Sep 17 00:00:00 2001 From: Trystan Lea Date: Wed, 24 Jan 2018 14:32:58 +0000 Subject: [PATCH 36/50] add control nodes to device-integration --- data/Control/openevse.json | 41 +++++++++++++++++++++++++++++++ data/{ => Control}/smartplug.json | 7 +++--- data/Control/wifirelay.json | 41 +++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 data/Control/openevse.json rename data/{ => Control}/smartplug.json (82%) create mode 100644 data/Control/wifirelay.json diff --git a/data/Control/openevse.json b/data/Control/openevse.json new file mode 100644 index 0000000..8a10dd9 --- /dev/null +++ b/data/Control/openevse.json @@ -0,0 +1,41 @@ +{ + "name": "openevse", + "category": "Control", + "group": "control", + "description": "openevse", + "inputs": [ + { + "name": "period", + "description": "period", + "processList": [] + }, + { + "name": "end", + "description": "end", + "processList": [] + }, + { + "name": "interruptible", + "description": "interruptible", + "processList": [] + }, + { + "name": "status", + "description": "status", + "processList": [] + } + ], + + "feeds": [], + + "control": + { + "active": {"name":"Active","type":"checkbox","default":1}, + "period": {"name":"Run period", "type":"time","default":0,"resolution":0.5}, + "end": {"name":"Complete by", "type":"time","default":0,"resolution":0.5}, + "repeat": {"type":"weekly-scheduler","default":[1,1,1,1,1,0,0]}, + "interruptible": {"name":"Ok to interrupt schedule","type":"checkbox","default":0}, + "runonce": {"type":"","default":true}, + "basic": {"type":"","default":0} + } +} diff --git a/data/smartplug.json b/data/Control/smartplug.json similarity index 82% rename from data/smartplug.json rename to data/Control/smartplug.json index 4509df8..62f82ef 100644 --- a/data/smartplug.json +++ b/data/Control/smartplug.json @@ -1,7 +1,7 @@ { "name": "smartplug", - "category": "OpenEnergyMonitor", - "group": "smartplug", + "category": "Control", + "group": "control", "description": "smartplug", "inputs": [ { @@ -30,10 +30,11 @@ "control": { + "active": {"name":"Active","type":"checkbox","default":1}, "period": {"name":"Run period", "type":"time","default":0,"resolution":0.5}, "end": {"name":"Complete by", "type":"time","default":0,"resolution":0.5}, "repeat": {"type":"weekly-scheduler","default":[1,1,1,1,1,0,0]}, - "interruptible": {"type":"checkbox","default":0}, + "interruptible": {"name":"Ok to interrupt schedule","type":"checkbox","default":0}, "runonce": {"type":"","default":true}, "basic": {"type":"","default":0} } diff --git a/data/Control/wifirelay.json b/data/Control/wifirelay.json new file mode 100644 index 0000000..693bf98 --- /dev/null +++ b/data/Control/wifirelay.json @@ -0,0 +1,41 @@ +{ + "name": "wifirelay", + "category": "Control", + "group": "control", + "description": "wifirelay", + "inputs": [ + { + "name": "period", + "description": "period", + "processList": [] + }, + { + "name": "end", + "description": "end", + "processList": [] + }, + { + "name": "interruptible", + "description": "interruptible", + "processList": [] + }, + { + "name": "status", + "description": "status", + "processList": [] + } + ], + + "feeds": [], + + "control": + { + "active": {"name":"Active","type":"checkbox","default":1}, + "period": {"name":"Run period", "type":"time","default":0,"resolution":0.5}, + "end": {"name":"Complete by", "type":"time","default":0,"resolution":0.5}, + "repeat": {"type":"weekly-scheduler","default":[1,1,1,1,1,0,0]}, + "interruptible": {"name":"Ok to interrupt schedule","type":"checkbox","default":0}, + "runonce": {"type":"","default":true}, + "basic": {"type":"","default":0} + } +} From ada239ba793a1a5fe65abcff06f9eaa55cfe0e66 Mon Sep 17 00:00:00 2001 From: Trystan Lea Date: Wed, 24 Jan 2018 20:35:29 +0000 Subject: [PATCH 37/50] fix bug where only 1 device gets loaded to redis device list and then no further devices are added --- device_model.php | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/device_model.php b/device_model.php index 3143c4c..dcb4220 100644 --- a/device_model.php +++ b/device_model.php @@ -235,23 +235,10 @@ private function load_list_to_redis($userid) private function load_device_to_redis($id) { $id = (int) $id; - $result = $this->mysqli->query("SELECT `id`, `userid`, `nodeid`, `name`, `description`, `type`, `devicekey` FROM device WHERE id = '$id' ORDER BY nodeid, name asc"); + $result = $this->mysqli->query("SELECT `userid` FROM device WHERE id = '$id'"); if ($result->num_rows>0) { $row = $result->fetch_object(); - $userid = $row->userid; - - $device = array( - 'id'=>$row->id, - 'userid'=>$row->userid, - 'nodeid'=>$row->nodeid, - 'name'=>$row->name, - 'description'=>$row->description, - 'type'=>$row->type, - 'devicekey'=>$row->devicekey - ); - $this->redis->sAdd("user:device:$userid", $row->id); - $this->redis->hMSet("device:".$row->id, $device); - return $device; + $this->load_list_to_redis($row->userid); } return false; } From e9ee9998765b8735fe8fd1c262e37a5d824ff9c0 Mon Sep 17 00:00:00 2001 From: Adrian Minde Date: Thu, 17 May 2018 14:13:34 +0200 Subject: [PATCH 38/50] Add template prefix option and minor improvements --- Views/device.js | 33 ++-- Views/device_api.php | 8 +- Views/device_dialog.js | 45 ++++-- Views/device_dialog.php | 40 ++--- Views/device_view.php | 2 +- data/Control/openevse.json | 14 +- data/Control/smartplug.json | 16 +- data/Control/wifirelay.json | 14 +- device_controller.php | 25 +-- device_model.php | 296 ++++++++++++++++++------------------ device_template.php | 71 +++++---- 11 files changed, 294 insertions(+), 270 deletions(-) diff --git a/Views/device.js b/Views/device.js index 20bb83b..3416e85 100644 --- a/Views/device.js +++ b/Views/device.js @@ -1,64 +1,49 @@ var device = { - 'list':function() - { + 'list':function() { var result = {}; $.ajax({ url: path+"device/list.json", dataType: 'json', async: false, success: function(data) {result = data;} }); return result; }, - 'get':function(id) - { + 'get':function(id) { var result = {}; $.ajax({ url: path+"device/get.json", data: "id="+id, async: false, success: function(data) {result = data;} }); return result; }, - 'set':function(id, fields) - { + 'set':function(id, fields) { var result = {}; $.ajax({ url: path+"device/set.json", data: "id="+id+"&fields="+JSON.stringify(fields), async: false, success: function(data) {result = data;} }); return result; }, - 'setNewDeviceKey':function(id) - { + 'setNewDeviceKey':function(id) { var result = {}; $.ajax({ url: path+"device/setnewdevicekey.json", data: "id="+id, async: false, success: function(data) {result = data;} }); return result; }, - 'remove':function(id) - { + 'remove':function(id) { var result = {}; $.ajax({ url: path+"device/delete.json", data: "id="+id, async: false, success: function(data) {result = data;} }); return result; }, - 'create':function(nodeid, name, description, type) - { + 'create':function(nodeid, name, description, type) { var result = {}; $.ajax({ url: path+"device/create.json", data: "nodeid="+nodeid+"&name="+name+"&description="+description+"&type="+type, async: false, success: function(data) {result = data;} }); return result; }, - 'listTemplates':function() - { + 'init':function(id, template) { var result = {}; - $.ajax({ url: path+"device/template/list.json", dataType: 'json', async: false, success: function(data) {result = data;} }); + $.ajax({ url: path+"device/init.json?id="+id, type: 'POST', data: "template="+JSON.stringify(template), dataType: 'json', async: false, success: function(data) {result = data;} }); return result; }, - 'prepareTemplate':function(id) - { + 'prepareTemplate':function(id) { var result = {}; $.ajax({ url: path+"device/template/prepare.json", data: "id="+id, dataType: 'json', async: false, success: function(data) {result = data;} }); return result; - }, - - 'initTemplate':function(id, template) - { - var result = {}; - $.ajax({ url: path+"device/template/init.json?id="+id, type: 'POST', data: "template="+JSON.stringify(template), dataType: 'json', async: false, success: function(data) {result = data;} }); - return result; } } diff --git a/Views/device_api.php b/Views/device_api.php index 0420987..c3a183f 100644 --- a/Views/device_api.php +++ b/Views/device_api.php @@ -39,15 +39,15 @@ device/create.json?nodeid=Test&name=Test device/delete.json?id=1 device/set.json?id=1&fields={"name":"Test","description":"Room","nodeid":"House","type":"test"} + device/init.json?id=1

- + -
device/template/list.json
device/template/listshort.json
device/template/get.json?device=example
device/template/get.json?type=example
device/template/prepare.json?id=1
device/template/init.json?id=1
@@ -55,7 +55,3 @@

\'\\Modules\\device\\data\\*.json\''); ?>

- - - - diff --git a/Views/device_dialog.js b/Views/device_dialog.js index 8253ab3..bca1ba4 100644 --- a/Views/device_dialog.js +++ b/Views/device_dialog.js @@ -4,7 +4,7 @@ var device_dialog = deviceTemplate: null, deviceType: null, device: null, - + 'loadConfig':function(templates, device) { this.templates = templates; @@ -20,9 +20,6 @@ var device_dialog = } this.drawConfig(); - - // Initialize callbacks - this.registerConfigEvents(); }, 'drawConfig':function() { @@ -91,8 +88,8 @@ var device_dialog = name = name.substr(0, 25) + "..."; } - out += ""; - out += ""+name+""; + out += ""; + out += ""+name+""; out += ""; } out += ""; @@ -104,7 +101,7 @@ var device_dialog = if (this.templates[this.deviceType]!=undefined) { var template = this.templates[this.deviceType] - $(".category-body[category='"+template.category+"']").show(); + $(".group-header[category='"+template.category+"']").show(); $(".group-body[category='"+template.category+"'][group='"+template.group+"']").show(); $(".group-row[type='"+this.deviceType+"']").addClass("device-selected"); @@ -112,6 +109,9 @@ var device_dialog = $('#template-info').show(); } } + + // Initialize callbacks + this.registerConfigEvents(); }, 'clearConfigModal':function() { @@ -130,7 +130,7 @@ var device_dialog = $('#device-config-description').val(this.device.description); $('#device-config-devicekey').val(this.device.devicekey).prop("disabled", false); $("#device-config-devicekey-new").prop("disabled", false); - $('#device-config-delete').show(); + $('#device-delete').show(); $("#device-init").show(); $("#device-save").html("Save"); } @@ -140,10 +140,11 @@ var device_dialog = $('#device-config-description').val(''); $('#device-config-devicekey').val('').prop("disabled", true); $("#device-config-devicekey-new").prop("disabled", true); - $('#device-config-delete').hide(); + $('#device-delete').hide(); $("#device-init").hide(); $("#device-save").html("Save & Initialize"); } + device_dialog.drawTemplate(); }, 'adjustConfigModal':function() { @@ -233,10 +234,13 @@ var device_dialog = } else { device_dialog.deviceType = null; + $('#template-description').text(''); $('#template-info').hide(); $("#device-init").show() } + + device_dialog.drawTemplate(); }); $("#sidebar-open").off('click').on('click', function () { @@ -304,7 +308,7 @@ var device_dialog = return false; } }); - + $("#device-delete").off('click').on('click', function () { $('#device-config-modal').modal('hide'); device_dialog.loadDelete(device_dialog.device, null); @@ -318,8 +322,19 @@ var device_dialog = $("#device-config-devicekey-new").off('click').on('click', function () { device_dialog.device.devicekey = device.setNewDeviceKey(device_dialog.device.id); $('#device-config-devicekey').val(device_dialog.device.devicekey); - }); - + }); + }, + + 'drawTemplate':function() { + if (this.deviceType !== null && this.deviceType in this.templates) { + var template = this.templates[this.deviceType]; + $('#template-description').html(''+template.description+''); + $('#template-info').show(); + } + else { + $('#template-description').text(''); + $('#template-info').hide(); + } }, 'loadInit': function() { @@ -336,7 +351,7 @@ var device_dialog = $('#device-init-modal').modal('hide'); var template = device_dialog.parseTemplate(); - var result = device.initTemplate(device_dialog.device.id, template); + var result = device.init(device_dialog.device.id, template); if (typeof result.success !== 'undefined' && !result.success) { alert('Unable to initialize device:\n'+result.message); return false; @@ -463,7 +478,7 @@ var device_dialog = 'parseTemplate': function() { var template = {}; - + template['feeds'] = []; if (typeof device_dialog.deviceTemplate.feeds !== 'undefined' && device_dialog.deviceTemplate.feeds.length > 0) { @@ -489,7 +504,7 @@ var device_dialog = 'loadDelete': function(device, tablerow) { this.device = device; - + $('#device-delete-modal').modal('show'); $('#device-delete-modal-label').html('Delete Device: '+device.name+''); diff --git a/Views/device_dialog.php b/Views/device_dialog.php index 7973e24..a5fdc07 100644 --- a/Views/device_dialog.php +++ b/Views/device_dialog.php @@ -2,7 +2,7 @@ global $path; ?> - +