2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-06 06:08:44 +00:00

chartingfrontend: initial work on chart integration in fhem

git-svn-id: https://svn.fhem.de/fhem/trunk@6928 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
johannnes 2014-11-09 14:23:56 +00:00
parent 38c7f42766
commit 59b71ee929
7 changed files with 339 additions and 100 deletions

View File

@ -273,16 +273,17 @@ UPD 2013-03-02_01:53:05 524 www/frontend/app/resources/icons/resultset_last.png
UPD 2013-04-03_07:27:17 733 www/frontend/app/resources/icons/add.png UPD 2013-04-03_07:27:17 733 www/frontend/app/resources/icons/add.png
UPD 2013-04-03_07:27:17 389 www/frontend/app/resources/icons/resultset_previous.png UPD 2013-04-03_07:27:17 389 www/frontend/app/resources/icons/resultset_previous.png
UPD 2013-06-30_11:47:12 101 www/frontend/app/resources/application.css UPD 2013-06-30_11:47:12 101 www/frontend/app/resources/application.css
UPD 2014-11-08_12:33:44 2976 www/frontend/app/app.js UPD 2014-11-09_03:04:11 5622 www/frontend/app/app.js
UPD 2013-04-28_02:00:20 1205 www/frontend/app/view/ChartGridPanel.js UPD 2013-04-28_02:00:20 1205 www/frontend/app/view/ChartGridPanel.js
UPD 2014-11-08_12:44:55 14475 www/frontend/app/view/DevicePanel.js UPD 2014-11-08_12:44:55 14475 www/frontend/app/view/DevicePanel.js
UPD 2014-11-09_03:10:38 747 www/frontend/app/view/ChartViewport.js
UPD 2014-11-08_12:52:12 9085 www/frontend/app/view/TableDataGridPanel.js UPD 2014-11-08_12:52:12 9085 www/frontend/app/view/TableDataGridPanel.js
UPD 2014-04-23_05:47:51 65039 www/frontend/app/view/LineChartPanel.js UPD 2014-11-09_03:08:20 65133 www/frontend/app/view/LineChartPanel.js
UPD 2014-01-12_12:09:17 5144 www/frontend/app/view/StatusPanel.js UPD 2014-01-12_12:09:17 5144 www/frontend/app/view/StatusPanel.js
UPD 2014-11-08_12:54:06 8578 www/frontend/app/view/Viewport.js UPD 2014-11-09_03:08:41 8866 www/frontend/app/view/Viewport.js
UPD 2014-11-08_01:05:40 20348 www/frontend/app/controller/MainController.js UPD 2014-11-09_03:07:33 20348 www/frontend/app/controller/MainController.js
UPD 2014-01-12_02:49:58 16562 www/frontend/app/controller/StatusController.js UPD 2014-01-12_02:49:58 16562 www/frontend/app/controller/StatusController.js
UPD 2014-11-08_12:36:47 111652 www/frontend/app/controller/ChartController.js UPD 2014-11-09_03:07:05 116072 www/frontend/app/controller/ChartController.js
UPD 2014-11-08_12:53:12 5408 www/frontend/app/controller/TableDataController.js UPD 2014-11-08_12:53:12 5408 www/frontend/app/controller/TableDataController.js
UPD 2013-04-01_07:04:35 202 www/frontend/app/model/ReadingsModel.js UPD 2013-04-01_07:04:35 202 www/frontend/app/model/ReadingsModel.js
UPD 2013-04-01_07:04:36 338 www/frontend/app/model/SavedChartsModel.js UPD 2013-04-01_07:04:36 338 www/frontend/app/model/SavedChartsModel.js

View File

@ -10,35 +10,36 @@ Ext.Loader.setConfig({
} }
}); });
Ext.application({ //get url params in order to detect which app to start (fullfeatured or just simpleviewer)
name: 'FHEM Frontend', var paramArr = document.URL.split("?");
requires: [ if (paramArr && paramArr.length > 1 && paramArr[1].indexOf("showchart") > -1) {
'FHEM.view.Viewport' var params = Ext.Object.fromQueryString(paramArr[1]),
], chartid = params.showchart;
Ext.application({
name: 'FHEM Chartviewer',
requires: [
'FHEM.view.ChartViewport'
],
controllers: [
'FHEM.controller.ChartController'
],
controllers: [ launch: function() {
'FHEM.controller.StatusController',
'FHEM.controller.MainController', // Gather information from FHEM
'FHEM.controller.ChartController', var me = this,
'FHEM.controller.TableDataController' url = '../../../fhem?cmd=jsonlist2&XHR=1';
],
Ext.Ajax.request({
launch: function() { method: 'GET',
async: false,
// Gather information from FHEM to display status, devices, etc. disableCaching: false,
var me = this, url: url,
url = '../../../fhem?cmd=jsonlist2&XHR=1'; success: function(response){
Ext.getBody().unmask();
Ext.Ajax.request({
method: 'GET',
async: false,
disableCaching: false,
url: url,
success: function(response){
Ext.getBody().unmask();
try {
FHEM.info = Ext.decode(response.responseText); FHEM.info = Ext.decode(response.responseText);
if (window.location.href.indexOf("frontenddev") > 0) { if (window.location.href.indexOf("frontenddev") > 0) {
FHEM.appPath = 'www/frontenddev/app/'; FHEM.appPath = 'www/frontenddev/app/';
} else { } else {
@ -56,9 +57,7 @@ Ext.application({
if ((!FHEM.dblogname || Ext.isEmpty(FHEM.dblogname)) && Ext.isEmpty(FHEM.filelogs)) { if ((!FHEM.dblogname || Ext.isEmpty(FHEM.dblogname)) && Ext.isEmpty(FHEM.filelogs)) {
Ext.Msg.alert("Error", "Could not find a DbLog or FileLog Configuration. Do you have them already defined?"); Ext.Msg.alert("Error", "Could not find a DbLog or FileLog Configuration. Do you have them already defined?");
} else { } else {
Ext.create("FHEM.view.Viewport", { Ext.create("FHEM.view.ChartViewport", {chartid:chartid});
hidden: true
});
//removing the loadingimage //removing the loadingimage
var p = Ext.DomQuery.select('p[class=loader]')[0], var p = Ext.DomQuery.select('p[class=loader]')[0],
@ -66,14 +65,78 @@ Ext.application({
p.removeChild(img); p.removeChild(img);
// further configuration of viewport starts in maincontroller // further configuration of viewport starts in maincontroller
} }
} catch (e) { },
Ext.Msg.alert("Oh no!", "JsonList did not respond correctly. This is a bug in FHEM. This Frontend cannot work without a valid JsonList response. See this link for details and complain there: http://forum.fhem.de/index.php/topic,17292.msg113132.html#msg113132"); failure: function() {
} Ext.Msg.alert("Error", "The connection to FHEM could not be established");
}, }
failure: function() { });
Ext.Msg.alert("Error", "The connection to FHEM could not be established"); }
} });
}); } else {
Ext.application({
} name: 'FHEM Frontend',
}); requires: [
'FHEM.view.Viewport'
],
controllers: [
'FHEM.controller.StatusController',
'FHEM.controller.MainController',
'FHEM.controller.ChartController',
'FHEM.controller.TableDataController'
],
launch: function() {
// Gather information from FHEM to display status, devices, etc.
var me = this,
url = '../../../fhem?cmd=jsonlist2&XHR=1';
Ext.Ajax.request({
method: 'GET',
async: false,
disableCaching: false,
url: url,
success: function(response){
Ext.getBody().unmask();
try {
FHEM.info = Ext.decode(response.responseText);
if (window.location.href.indexOf("frontenddev") > 0) {
FHEM.appPath = 'www/frontenddev/app/';
} else {
FHEM.appPath = 'www/frontend/app/';
}
FHEM.filelogs = [];
Ext.each(FHEM.info.Results, function(result) {
if (result.Internals.TYPE === "DbLog" && result.Internals.NAME) {
FHEM.dblogname = result.Internals.NAME;
}
if (result.Internals.TYPE === "FileLog") {
FHEM.filelogs.push(result);
}
});
if ((!FHEM.dblogname || Ext.isEmpty(FHEM.dblogname)) && Ext.isEmpty(FHEM.filelogs)) {
Ext.Msg.alert("Error", "Could not find a DbLog or FileLog Configuration. Do you have them already defined?");
} else {
Ext.create("FHEM.view.Viewport", {
hidden: true
});
//removing the loadingimage
var p = Ext.DomQuery.select('p[class=loader]')[0],
img = Ext.DomQuery.select('#loading-overlay')[0];
p.removeChild(img);
// further configuration of viewport starts in maincontroller
}
} catch (e) {
Ext.Msg.alert("Oh no!", "JsonList did not respond correctly. This is a bug in FHEM. This Frontend cannot work without a valid JsonList response. See this link for details and complain there: http://forum.fhem.de/index.php/topic,17292.msg113132.html#msg113132");
}
},
failure: function() {
Ext.Msg.alert("Error", "The connection to FHEM could not be established");
}
});
}
});
}

View File

@ -22,12 +22,21 @@ Ext.define('FHEM.controller.ChartController', {
* minValue of Y2 Axis gets saved here as reference * minValue of Y2 Axis gets saved here as reference
*/ */
minY2Value: 9999999, minY2Value: 9999999,
/**
* are we showing just a simple chart?
*/
simplechartview: false,
refs: [ refs: [
{ {
selector: 'panel[name=chartformpanel]', selector: 'panel[name=chartformpanel]',
ref: 'chartformpanel' //this.getChartformpanel() ref: 'chartformpanel' //this.getChartformpanel()
}, },
{
selector: 'panel[name=chartpanel]',
ref: 'chartpanel' //this.getChartpanel()
},
{ {
selector: 'datefield[name=starttimepicker]', selector: 'datefield[name=starttimepicker]',
ref: 'starttimepicker' //this.getStarttimepicker() ref: 'starttimepicker' //this.getStarttimepicker()
@ -71,6 +80,10 @@ Ext.define('FHEM.controller.ChartController', {
{ {
selector: 'radiogroup[name=datasourceradio]', selector: 'radiogroup[name=datasourceradio]',
ref: 'datasourceradio' //this.getDatasourceradio() ref: 'datasourceradio' //this.getDatasourceradio()
},
{
selector: 'viewport[name=chartviewport]',
ref: 'simplechartviewport'
} }
], ],
@ -100,6 +113,9 @@ Ext.define('FHEM.controller.ChartController', {
'menuitem[name=renamechartfromcontext]': { 'menuitem[name=renamechartfromcontext]': {
click: this.renamechart click: this.renamechart
}, },
'menuitem[name=integratechartfromcontext]': {
click: this.integrateChart
},
'treepanel[name=maintreepanel]': { 'treepanel[name=maintreepanel]': {
itemclick: this.loadsavedchart itemclick: this.loadsavedchart
}, },
@ -129,6 +145,9 @@ Ext.define('FHEM.controller.ChartController', {
}, },
'button[name=loadfullchart]': { 'button[name=loadfullchart]': {
loadchart: this.loadsavedchart loadchart: this.loadsavedchart
},
'viewport[name=chartviewport]': {
afterrender: this.loadAndShowSimpleChart
} }
}); });
@ -321,37 +340,38 @@ Ext.define('FHEM.controller.ChartController', {
yaxes = Ext.ComponentQuery.query('combobox[name=yaxiscombo]'), yaxes = Ext.ComponentQuery.query('combobox[name=yaxiscombo]'),
rowFieldSets = Ext.ComponentQuery.query('fieldset[commonName=singlerowfieldset]'), rowFieldSets = Ext.ComponentQuery.query('fieldset[commonName=singlerowfieldset]'),
yaxesstatistics = Ext.ComponentQuery.query('combobox[name=yaxisstatisticscombo]'), yaxesstatistics = Ext.ComponentQuery.query('combobox[name=yaxisstatisticscombo]'),
axissideradio = Ext.ComponentQuery.query('radiogroup[name=axisside]'); axissideradio = Ext.ComponentQuery.query('radiogroup[name=axisside]'),
starttime = me.getStarttimepicker().getValue(),
var starttime = me.getStarttimepicker().getValue(),
dbstarttime = Ext.Date.format(starttime, 'Y-m-d_H:i:s'), dbstarttime = Ext.Date.format(starttime, 'Y-m-d_H:i:s'),
endtime = me.getEndtimepicker().getValue(), endtime = me.getEndtimepicker().getValue(),
dbendtime = Ext.Date.format(endtime, 'Y-m-d_H:i:s'), dbendtime = Ext.Date.format(endtime, 'Y-m-d_H:i:s'),
dynamicradio = Ext.ComponentQuery.query('radiogroup[name=dynamictime]')[0], dynamicradio = Ext.ComponentQuery.query('radiogroup[name=dynamictime]')[0],
chartpanel = me.getLinechartpanel(), chartpanel = me.getLinechartpanel(),
hiddenchartdiv = Ext.get("hiddenchart"); hiddenchartdiv = Ext.get("hiddenchart"),
existingchart = Ext.ComponentQuery.query('panel[name=chartpanel]')[0],
//cleanup chartpanel store = Ext.create('FHEM.store.ChartStore'),
var existingchartgrid = Ext.ComponentQuery.query('panel[name=chartgridpanel]')[0];
if (!existingchartgrid) {
var chartdatagrid = Ext.create('FHEM.view.ChartGridPanel', {
name: 'chartgridpanel',
minHeight: 200,
maxHeight: 200,
collapsed: true
});
chartpanel.add(chartdatagrid);
} else {
existingchartgrid.down('grid').getStore().removeAll();
}
var existingchart = Ext.ComponentQuery.query('panel[name=chartpanel]')[0];
if (existingchart) {
existingchart.destroy();
}
var store = Ext.create('FHEM.store.ChartStore'),
proxy = store.getProxy(), proxy = store.getProxy(),
chart; chart;
//cleanup chartpanel
if (!me.simplechartview) {
var existingchartgrid = Ext.ComponentQuery.query('panel[name=chartgridpanel]')[0];
if (!existingchartgrid) {
var chartdatagrid = Ext.create('FHEM.view.ChartGridPanel', {
name: 'chartgridpanel',
minHeight: 200,
maxHeight: 200,
collapsed: true
});
chartpanel.add(chartdatagrid);
} else {
existingchartgrid.down('grid').getStore().removeAll();
}
}
if (existingchart) {
existingchart.destroy();
}
if (hidden === true) { if (hidden === true) {
chart = me.createChart(store, hiddenchartdiv); chart = me.createChart(store, hiddenchartdiv);
@ -470,41 +490,48 @@ Ext.define('FHEM.controller.ChartController', {
i++; i++;
}); });
}, 300); }, 100);
}, },
/** /**
* resize the chart to fit the centerpanel * resize the chart to fit the centerpanel
*/ */
resizeChart: function() { resizeChart: function() {
var lcp = Ext.ComponentQuery.query('linechartpanel')[0]; var me = this,
var lcv = Ext.ComponentQuery.query('chart')[0]; lcp = Ext.ComponentQuery.query('linechartpanel')[0],
var cfp = Ext.ComponentQuery.query('form[name=chartformpanel]')[0]; lcv = Ext.ComponentQuery.query('chart')[0],
var cdg = Ext.ComponentQuery.query('panel[name=chartgridpanel]')[0]; cfp = Ext.ComponentQuery.query('form[name=chartformpanel]')[0],
cdg = Ext.ComponentQuery.query('panel[name=chartgridpanel]')[0] || true;
if (lcv) { if (lcv) {
if (lcp && lcv && cfp && cdg) { if (lcp && lcv && cfp && cdg) {
var lcph = lcp.getHeight(), var lcph = lcp.getHeight(),
lcpw = lcp.getWidth(), lcpw = lcp.getWidth(),
cfph = cfp.getHeight(), cfph = cfp.getHeight(),
cdgh = cdg.getHeight(); cdgh = Ext.isObject(cdg) ? cdg.getHeight() : 0;
if (lcph && lcpw && cfph && cdgh) { if (Ext.isNumeric(lcph) &&
var chartheight = lcph - cfph - cdgh - 80; Ext.isNumeric(lcpw) &&
var chartwidth = lcpw - 5; Ext.isNumeric(cfph) &&
lcv.height = chartheight; Ext.isNumeric(cdgh)) {
lcv.width = chartwidth;
//render after 50ms to get component right var chartheight = lcph - cfph - cdgh - 80;
window.setTimeout(function() { var chartwidth = lcpw - 5;
if (lcv.series.get(0).hideAll) { lcv.height = chartheight;
lcv.series.get(0).hideAll(); lcv.width = chartwidth;
} //render after 50ms to get component right
lcv.doComponentLayout(); window.setTimeout(function() {
if (lcv.series.get(0).showAll) { if (lcv.series.get(0).hideAll) {
lcv.series.get(0).showAll(); lcv.series.get(0).hideAll();
} }
lcv.redraw(); lcv.doComponentLayout();
}, 50); if (lcv.series.get(0).showAll) {
lcv.series.get(0).showAll();
}
lcv.redraw();
me.fireEvent("chartready");
}, 50);
} }
} }
} }
@ -519,7 +546,7 @@ Ext.define('FHEM.controller.ChartController', {
var chart = Ext.create('Ext.panel.Panel', { var chart = Ext.create('Ext.panel.Panel', {
title: 'Chart', title: 'Chart',
name: 'chartpanel', name: 'chartpanel',
collapsible: true, collapsible: !me.simplechartview,
titleCollapse: true, titleCollapse: true,
animCollapse: false, animCollapse: false,
width: hidden ? 1 : false, width: hidden ? 1 : false,
@ -944,7 +971,6 @@ Ext.define('FHEM.controller.ChartController', {
} }
//as we have the valuetext, we can fill the grid //as we have the valuetext, we can fill the grid
//fill the grid with the data
me.fillChartGrid(json.data, valuetext); me.fillChartGrid(json.data, valuetext);
var timestamptext; var timestamptext;
@ -1170,6 +1196,7 @@ Ext.define('FHEM.controller.ChartController', {
} }
me.getLinechartpanel().setLoading(false); me.getLinechartpanel().setLoading(false);
}, },
/** /**
@ -1181,6 +1208,11 @@ Ext.define('FHEM.controller.ChartController', {
var chart = Ext.ComponentQuery.query('chart')[0], var chart = Ext.ComponentQuery.query('chart')[0],
axis; axis;
// make chart visible before manipulating axes
if (!chart.isVisible()) {
chart.up().up().show();
}
if (axisside === "left") { if (axisside === "left") {
axis = chart.axes.get(0); axis = chart.axes.get(0);
axistitle = this.getChartformpanel().down('textfield[name=leftaxistitle]').getValue(); axistitle = this.getChartformpanel().down('textfield[name=leftaxistitle]').getValue();
@ -2015,7 +2047,10 @@ Ext.define('FHEM.controller.ChartController', {
} }
this.requestChartData(false, hidden); this.requestChartData(false, hidden);
this.getLinechartpanel().setTitle(name); // set title only in standard mode to master panel (not simple chart view)
if (!me.simplechartview) {
this.getLinechartpanel().setTitle(name);
}
} else { } else {
Ext.Msg.alert("Error", "The Chart could not be loaded! RawChartdata was: <br>" + chartdata); Ext.Msg.alert("Error", "The Chart could not be loaded! RawChartdata was: <br>" + chartdata);
} }
@ -2176,9 +2211,10 @@ Ext.define('FHEM.controller.ChartController', {
* fill the charts grid with data * fill the charts grid with data
*/ */
fillChartGrid: function(jsondata, valuetext) { fillChartGrid: function(jsondata, valuetext) {
if (jsondata && jsondata[0]) {
//this.getChartformpanel().collapse(); var grid = this.getChartdatagrid();
if (grid && jsondata && jsondata[0]) {
var store = this.getChartdatagrid().getStore(), var store = this.getChartdatagrid().getStore(),
columnwidth = 0, columnwidth = 0,
storefields = [], storefields = [],
@ -2365,5 +2401,101 @@ Ext.define('FHEM.controller.ChartController', {
}); });
} }
Ext.ComponentQuery.query('treepanel')[0].setLoading(false); Ext.ComponentQuery.query('treepanel')[0].setLoading(false);
},
/**
* method used to retrieve config of a saved chart and create the desired chart for
* simpler fhem integration (simple chart view)
*/
loadAndShowSimpleChart: function() {
// get the chartconfig for the given id
var me = this,
chartid = me.getSimplechartviewport().chartid,
config = {};
me.simplechartview = true;
// first, check the filelogs
Ext.each(FHEM.filelogcharts, function(log) {
if (log.ID === parseInt(chartid,10)) {
config.raw = {};
config.raw.data = log;
me.on("chartready", function() {
var c = Ext.ComponentQuery.query('chart')[0];
c.setHeight(c.getHeight() + 30);
c.up().setTitle(log.NAME);
});
me.loadsavedchart(false, config, false);
return false;
}
});
// if no filelog found, search the db
if (Ext.isEmpty(config.raw)) {
//load the saved charts store with configured dblog name
var me = this,
store = Ext.create('FHEM.store.SavedChartsStore', {});
store.getProxy().url = '../../../fhem?cmd=get+' + FHEM.dblogname + '+-+webchart+""+""+""+getcharts&XHR=1';
store.load();
store.on("load", function() {
store.each(function(rec) {
if (rec.raw.NAME && rec.raw.NAME === chartid) {
config = rec;
me.on("chartready", function() {
var c = Ext.ComponentQuery.query('chart')[0];
c.setHeight(c.getHeight() + 30);
c.up().setTitle(rec.raw.NAME);
});
me.loadsavedchart(false, config, false);
return false;
}
});
// if no match found, throw error
if (Ext.isEmpty(config.raw)) {
Ext.Msg.alert("Error", "The chart could not be found!");
return;
}
});
}
},
/**
* method shows an fhem definition for this chart
* to integrate it as an iframe in the fhem view
*/
integrateChart: function(menu) {
/**
* define charttest weblink iframe http://192.168.0.111:8085/fhem/frontenddev/index.html?a=b&c=d&showchart=sdfsd
attr charttest htmlattr width="500" height="300"
attr charttest room Keller
*/
var me = this,
rec = menu.record,
url = window.location.href,
id;
if (!rec || !rec.raw || !rec.raw.data) {
Ext.Msg.alert("Error", "Invalid configuration, please report!");
return false;
}
url += '?showchart=';
if (rec.raw.data.TYPE === "savedfilelogchart") {
url += rec.raw.data.ID;
} else {
url += rec.raw.data.NAME;
}
Ext.create('Ext.window.Window', {
width: 600,
height: 150,
html: 'Copy the following code to your fhem.cfg and modify it to integrate this chart in your FHEM views:<br><br>' +
'define ' + rec.raw.data.NAME + ' weblink iframe ' + url + '<br>' +
'attr ' + rec.raw.data.NAME + ' htmlattr width="500" height="300"<br>' +
'attr ' + rec.raw.data.NAME + ' room Keller<br>'
}).show();
} }
}); });

View File

@ -93,7 +93,7 @@ Ext.define('FHEM.controller.MainController', {
}); });
var sp = this.getStatustextfield(); var sp = this.getStatustextfield();
sp.setText("Frontend Version: 1.1.0 - 2014-11-08"); sp.setText("Frontend Version: 1.1.1 - 2014-11-09");
this.setupTree(); this.setupTree();
}, },

View File

@ -0,0 +1,33 @@
/**
* The main application viewport, which displays the charts
* @extends Ext.Viewport
*/
Ext.define('FHEM.view.ChartViewport', {
extend: 'Ext.Viewport',
name: 'chartviewport',
layout: 'fit',
requires: [
'FHEM.view.LineChartPanel',
'Ext.panel.Panel'
],
/**
* the given chart reference
*/
chartid: null,
initComponent: function() {
var me = this;
Ext.apply(me, {
items: [
{
xtype: 'linechartpanel',
name: 'linechartpanel',
hideSettingsPanel: true,
preventHeader: true
}
]
});
me.callParent(arguments);
}
});

View File

@ -69,7 +69,12 @@ Ext.define('FHEM.view.LineChartPanel', {
/** /**
* the title * the title
*/ */
title: 'Line Chart', title: false,
/**
*
*/
hideSettingsPanel: false,
/** /**
* init function * init function
@ -101,6 +106,7 @@ Ext.define('FHEM.view.LineChartPanel', {
collapsible: true, collapsible: true,
titleCollapse: true, titleCollapse: true,
animCollapse: false, animCollapse: false,
hidden: me.hideSettingsPanel,
items: [ items: [
{ {
xtype: 'fieldset', xtype: 'fieldset',

View File

@ -159,6 +159,10 @@ Ext.define('FHEM.view.Viewport', {
text: 'Rename Chart', text: 'Rename Chart',
name: 'renamechartfromcontext', name: 'renamechartfromcontext',
record: rec record: rec
}, '-', {
text: 'Integrate in FHEM',
name: 'integratechartfromcontext',
record: rec
} }
] ]
}).showAt(e.xy); }).showAt(e.xy);