diff --git a/DeviceAPI/API_AwairSensor.py b/DeviceAPI/API_AwairSensor.py index 3bc5883d8b88457e246264642a7eb838ccfbada6..75e6d9d0e92f17b3b0cc2f9ddd5568c5a79603ed 100644 --- a/DeviceAPI/API_AwairSensor.py +++ b/DeviceAPI/API_AwairSensor.py @@ -2,7 +2,6 @@ from __future__ import division from bemoss_lib.utils.BEMOSS_ONTOLOGY import BEMOSS_ONTOLOGY from DeviceAPI.BaseAPI import baseAPI -from settings import AWAIR_TOKEN import requests import urllib2 import datetime @@ -17,16 +16,15 @@ class API(baseAPI): self._debug = False def API_info(self): - #TODO: create chart_template and html_template for awair return [{'device_model' : 'Awair+', 'vendor_name' : 'Awair', 'communication' : 'WiFi', - 'device_type_id' : 4,'api_name': 'API_AwairSensor', 'html_template': '---', 'agent_type': 'BasicAgent', + 'device_type_id' : 4,'api_name': 'API_AwairSensor', 'html_template': 'sensors/iaq_sensor.html', 'agent_type': 'BasicAgent', 'identifiable': False, 'authorizable': False, 'is_cloud_device' : True, 'schedule_weekday_period': '4', 'schedule_weekend_period': '4', - 'allow_schedule_period_delete': False, 'chart_template': '---'}] + 'allow_schedule_period_delete': False, 'chart_template': 'charts/charts_iaq_sensor.html'}] def dashboard_view(self): - return {"top": {"type": "number", "value": "co2"}, "center": {"type": "number", "value": "voc"}, - "bottom": {"type": "number", "value": "dust"}} + return {"top": BEMOSS_ONTOLOGY.CO2.NAME, "center": {"type": "number", "value": "voc"}, + "bottom": BEMOSS_ONTOLOGY.DUST.NAME} def ontology(self): return {"co2":BEMOSS_ONTOLOGY.CO2,"dust":BEMOSS_ONTOLOGY.DUST, @@ -91,7 +89,7 @@ class API(baseAPI): def main(): # Step1: create an object with initialized data from DeviceDiscovery Agent # requirements for instantiation1. model, 2.type, 3.api, 4. address - Awair = API(model='Awair+',agent_id='iaqsensor',api='API_AwairSensor',password='Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNTUxOSJ9.3YE0APseF-aLMcjTMSbN4bHgE--ZgcuWBEXVs-5TTO4') + Awair = API(model='Awair+',agent_id='iaqsensor',address=9338,api='API_AwairSensor',password='Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiNTUxOSJ9.3YE0APseF-aLMcjTMSbN4bHgE--ZgcuWBEXVs-5TTO4') print("{0}agent is initialzed for {1} using API={2}".format(Awair.get_variable('agent_id'),Awair.get_variable('model'),Awair.get_variable('api'))) #Awair.getModelVendor() Awair.getDeviceStatus() diff --git a/Web_Server/static/app_js/charts/charts_iaq_sensor.js b/Web_Server/static/app_js/charts/charts_iaq_sensor.js new file mode 100644 index 0000000000000000000000000000000000000000..913055c7809ece62788bebfd75ec832a9a7e383b --- /dev/null +++ b/Web_Server/static/app_js/charts/charts_iaq_sensor.js @@ -0,0 +1,1169 @@ +/** + * Created by avijit on 9/22/17. + */ + + +$(document).ready(function(){ + $.csrftoken(); + + /** + * Plot functions and values for Temperature + * @type {{legend: {show: boolean, labels: string[]}, series: *[], cursor: {show: boolean, zoom: boolean}, seriesDefaults: {show: boolean, showMarker: boolean, pointLabels: {show: boolean}, rendererOption: {smooth: boolean}}, axesDefaults: {labelRenderer: jQuery.jqplot.CanvasAxisLabelRenderer}, axes: {xaxis: {label: string, renderer: jQuery.jqplot.DateAxisRenderer, tickOptions: {formatString: string}, numberTicks: number, min: *, max: *}, yaxis: {min: number, max: number, label: string}, y2axis: {min: number, max: number, label: string}}}} + */ + + //Plot options + var options_temp = { + legend: { + show: true, + labels:["Indoor Temperature"] + }, + series:[{ + label: 'Temperature (F)', + neighborThreshold: -1, + yaxis: 'yaxis' + }], + cursor: { + show: true, + zoom: true + }, + seriesDefaults: { + show: true, + showMarker:false, + pointLabels: {show:false}, + rendererOption:{smooth: true} + }, + axesDefaults: { + labelRenderer: $.jqplot.CanvasAxisLabelRenderer + }, + axes: { + xaxis: { + label: "Time", + renderer: $.jqplot.DateAxisRenderer, + tickOptions:{formatString:'%m/%d, %H:%M'}, + + min : _indoor_temp[0][0], + max: _indoor_temp[_indoor_temp.length-1][0] + }, + yaxis: { + autoscale: true, + label: "Temperature (F)" + } + } + }; + + + + //Initialize plot for temperature + var data_points_temp = [_indoor_temp]; + var plot_temp = $.jqplot('chart100', data_points_temp ,options_temp); + $("#indoor_temp").attr('checked','checked'); + + temp = { + seriesStyles: { + seriesColors: ['red', 'orange', 'yellow', 'green', 'blue', 'indigo'], + highlightColors: ['lightpink', 'lightsalmon', 'lightyellow', 'lightgreen', 'lightblue', 'mediumslateblue'] + }, + grid: { + + }, + axesStyles: { + borderWidth: 0, + label: { + fontFamily: 'Sans', + textColor: 'white', + fontSize: '9pt' + } + } + }; + + + plot_temp.themeEngine.newTheme('uma', temp); + plot_temp.activateTheme('uma'); + + var timeOut_temp; + + function update_plot_temp(_data) { + + _indoor_temp = _data.temperature; + + var new_data = []; + + $.each($('input:checked'), function(index, value){ + + if (this.id == 'indoor_temp') { + new_data.push(_indoor_temp); + options_temp.legend.labels.push(this.value); + } + + options_temp.axes.xaxis.min = _indoor_temp[0][0]; + options_temp.axes.xaxis.max = _indoor_temp[_indoor_temp.length-1][0]; + }); + + if (plot_temp) { + plot_temp.destroy(); + } + + + plot2_temp = $.jqplot('chart100', new_data ,options_temp); + plot2_temp.themeEngine.newTheme('uma', temp); + plot2_temp.activateTheme('uma'); + + console.log('nowww'); + $("#auto_update_temp").attr('disabled','disabled'); + $("#stop_auto_update_temp").removeAttr('disabled'); + } + + + function do_update_temp() { + var from_date = $("#from_date").val(); + var to_date = $("#to_date").val(); + var values = { + "mac": mac, + "from_dt": from_date, + "to_dt": to_date + }; + var jsonText = JSON.stringify(values); + console.log(jsonText); + + $.ajax({ + url : '/charts/'+mac+'/', + + type: 'POST', + data: jsonText, + dataType: 'json', + + success : function(data) { + + console.log ("testing"); + console.log (typeof(data)); + + + update_plot_temp(data); + + }, + error: function(data) { + + clearTimeout(timeOut_temp); + $('.bottom-right').notify({ + message: { text: 'Communication Error. Try again later!'}, + type: 'blackgloss', + fadeOut: { enabled: true, delay: 5000 } + }).show(); + } + }); + timeOut_temp = setTimeout(do_update_temp, 30000); + //},5000); + } + + //Auto update the chart + $('#auto_update_temp').click( function(evt){ + evt.preventDefault(); + do_update_temp(); + }); + + $('#stop_auto_update_temp').click(function(){ + clearTimeout(timeOut_temp); + $('#stop_auto_update_temp').attr('disabled', 'disabled'); + $('#auto_update_temp').removeAttr('disabled'); + }); + + $('#stack_chart_temp').click( function(evt){ + evt.preventDefault(); + stackCharts_temp(); + }); + + function stackCharts_temp(){ + if (timeOut_temp) { + clearTimeout(timeOut_temp); + $('#stop_auto_update_temp').attr('disabled', 'disabled'); + $('#auto_update_temp').removeAttr('disabled'); + } + options_temp.legend.labels = []; + var new_data = []; + $.each($('input:checked'), function(index, value){ + + if (this.id == 'indoor_temp') { + new_data.push(_indoor_temp); + options_temp.legend.labels.push(this.value); + } + + + options_temp.axes.xaxis.min = _indoor_temp[0][0]; + options_temp.axes.xaxis.max = _indoor_temp[_indoor_temp.length-1][0]; + }); + + + if (plot_temp) { + plot_temp.destroy(); + } + + + plot2_temp = $.jqplot('chart100', new_data ,options_temp); + plot2_temp.themeEngine.newTheme('uma', temp); + plot2_temp.activateTheme('uma'); + + } + + /** + * Plot functions and values for Humidity + * @type {{legend: {show: boolean, labels: string[]}, series: *[], cursor: {show: boolean, zoom: boolean}, seriesDefaults: {show: boolean, showMarker: boolean, pointLabels: {show: boolean}, rendererOption: {smooth: boolean}}, axesDefaults: {labelRenderer: jQuery.jqplot.CanvasAxisLabelRenderer}, axes: {xaxis: {label: string, renderer: jQuery.jqplot.DateAxisRenderer, tickOptions: {formatString: string}, numberTicks: number, min: *, max: *}, yaxis: {min: number, max: number, label: string}, y2axis: {min: number, max: number, label: string}}}} + */ + + //Plot options + var options_humidity = { + legend: { + show: true, + labels:["Indoor Humidity"] + }, + series:[{ + label: 'Humidity (%)', + neighborThreshold: -1, + yaxis: 'yaxis' + }], + cursor: { + show: true, + zoom: true + }, + seriesDefaults: { + show: true, + showMarker:false, + pointLabels: {show:false}, + rendererOption:{smooth: true} + }, + axesDefaults: { + labelRenderer: $.jqplot.CanvasAxisLabelRenderer + }, + axes: { + xaxis: { + label: "Time", + renderer: $.jqplot.DateAxisRenderer, + tickOptions:{formatString:'%m/%d, %H:%M'}, + + min : _indoor_humidity[0][0], + max: _indoor_humidity[_indoor_humidity.length-1][0] + }, + yaxis: { + autoscale: true, + label: "Humidity (%)" + } + } + }; + + + + //Initialize plot for humidity + var data_points_humidity = [_indoor_humidity]; + var plot_humidity = $.jqplot('chart101', data_points_humidity ,options_humidity); + $("#indoor_humidity").attr('checked','checked'); + //$("#outdoor_humidity").attr('checked','checked'); + + temp = { + seriesStyles: { + seriesColors: ['red', 'orange', 'yellow', 'green', 'blue', 'indigo'], + highlightColors: ['lightpink', 'lightsalmon', 'lightyellow', 'lightgreen', 'lightblue', 'mediumslateblue'] + }, + grid: { + + }, + axesStyles: { + borderWidth: 0, + label: { + fontFamily: 'Sans', + textColor: 'white', + fontSize: '9pt' + } + } + }; + + + plot_humidity.themeEngine.newTheme('uma', temp); + plot_humidity.activateTheme('uma'); + + var timeOut_humidity; + + function update_plot_humidity(_data) { + + _indoor_humidity = _data.humidity; + + var new_data = []; + + $.each($('input:checked'), function(index, value){ + + if (this.id == 'indoor_humidity') { + new_data.push(_indoor_humidity); + options_humidity.legend.labels.push(this.value); + } + + options_humidity.axes.xaxis.min = _indoor_humidity[0][0]; + options_humidity.axes.xaxis.max = _indoor_humidity[_indoor_humidity.length-1][0]; + }); + + if (plot_humidity) { + plot_humidity.destroy(); + } + + + plot2_humidity = $.jqplot('chart101', new_data ,options_humidity); + plot2_humidity.themeEngine.newTheme('uma', temp); + plot2_humidity.activateTheme('uma'); + + console.log('nowww'); + $("#auto_update_humidity").attr('disabled','disabled'); + $("#stop_auto_update_humidity").removeAttr('disabled'); + } + + + function do_update_humidity() { + var from_date = $("#from_date").val(); + var to_date = $("#to_date").val(); + var values = { + "mac": mac, + "from_dt": from_date, + "to_dt": to_date + }; + var jsonText = JSON.stringify(values); + console.log(jsonText); + + $.ajax({ + url : '/charts/'+mac+'/', + + type: 'POST', + data: jsonText, + dataType: 'json', + + success : function(data) { + + console.log ("testing"); + console.log (data); + update_plot_humidity(data); + + }, + error: function(data) { + + clearTimeout(timeOut_humidity); + $('.bottom-right').notify({ + message: { text: 'Communication Error. Try again later!'}, + type: 'blackgloss', + fadeOut: { enabled: true, delay: 5000 } + }).show(); + } + }); + timeOut_humidity = setTimeout(do_update_humidity, 30000); + } + + //Auto update the chart + $('#auto_update_humidity').click( function(evt){ + evt.preventDefault(); + do_update_humidity(); + }); + + $('#stop_auto_update_humidity').click(function(){ + clearTimeout(timeOut_humidity); + $('#stop_auto_update_humidity').attr('disabled', 'disabled'); + $('#auto_update_humidity').removeAttr('disabled'); + }); + + $('#stack_chart_humidity').click( function(evt){ + evt.preventDefault(); + stackCharts_humidity(); + }); + + function stackCharts_humidity(){ + if (timeOut_humidity) { + clearTimeout(timeOut_humidity); + $('#stop_auto_update_humidity').attr('disabled', 'disabled'); + $('#auto_update_humidity').removeAttr('disabled'); + } + options_humidity.legend.labels = []; + var new_data = []; + $.each($('input:checked'), function(index, value){ + + if (this.id == 'indoor_humidity') { + new_data.push(_indoor_humidity); + options_humidity.legend.labels.push(this.value); + } + + + options_humidity.axes.xaxis.min = _indoor_humidity[0][0]; + options_humidity.axes.xaxis.max = _indoor_humidity[_indoor_humidity.length-1][0]; + }); + + + if (plot_humidity) { + plot_humidity.destroy(); + } + + + plot2_humidity = $.jqplot('chart101', new_data ,options_humidity); + plot2_humidity.themeEngine.newTheme('uma', temp); + plot2_humidity.activateTheme('uma'); + + } + + + + + + /** + * Plot functions and values for CO2 + * @type {{legend: {show: boolean, labels: string[]}, series: {label: string, neighborThreshold: number, yaxis: string}[], cursor: {show: boolean, zoom: boolean}, seriesDefaults: {show: boolean, showMarker: boolean, pointLabels: {show: boolean}, rendererOption: {smooth: boolean}}, axesDefaults: {labelRenderer: jQuery.jqplot.CanvasAxisLabelRenderer}, axes: {xaxis: {label: string, renderer: jQuery.jqplot.DateAxisRenderer, tickOptions: {formatString: string}, numberTicks: number, min: *, max: *}, yaxis: {min: number, max: number, label: string}}}} + */ + //Plot options + var options_co2 = { + legend: { + show: true, + labels:["CO2"] + }, + series:[{ + label: 'CO2 (ppm)', + neighborThreshold: -1, + yaxis: 'yaxis' + }], + cursor: { + show: true, + zoom: true + }, + seriesDefaults: { + show: true, + showMarker:false, + pointLabels: {show:false}, + rendererOption:{smooth: true} + }, + axesDefaults: { + labelRenderer: $.jqplot.CanvasAxisLabelRenderer + }, + axes: { + xaxis: { + label: "Time", + renderer: $.jqplot.DateAxisRenderer, + tickOptions:{formatString:'%m/%d, %H:%M'}, + + min : _co2[0][0], + max: _co2[_co2.length-1][0] + }, + yaxis: { + autoscale: true, + label: "CO2 (ppm)" + } + } + }; + + + + //Initialize plot for CO2 + var data_points_co2 = [_co2]; + var plot_co2 = $.jqplot('chart102', data_points_co2 ,options_co2); + $("#co2").attr('checked','checked'); + + temp = { + seriesStyles: { + seriesColors: ['red', 'orange', 'yellow', 'green', 'blue', 'indigo'], + highlightColors: ['lightpink', 'lightsalmon', 'lightyellow', 'lightgreen', 'lightblue', 'mediumslateblue'] + }, + grid: { + + }, + axesStyles: { + borderWidth: 0, + label: { + fontFamily: 'Sans', + textColor: 'white', + fontSize: '9pt' + } + } + }; + + + plot_co2.themeEngine.newTheme('uma', temp); + plot_co2.activateTheme('uma'); + + var timeOut_co2; + + function update_plot_co2(_data) { + _co2 = _data.co2; + + var new_data = []; + + $.each($('input:checked'), function(index, value){ + + if (this.id == 'co2') { + + if (typeof(_co2) == 'string') + { + _co2 = $.parseJSON(_co2); + } + new_data.push(_co2); + options_co2.legend.labels.push(this.value); + } + + options_co2.axes.xaxis.min = _co2[0][0]; + options_co2.axes.xaxis.max = _co2[_co2.length-1][0]; + }); + + if (plot_co2) { + plot_co2.destroy(); + } + + + plot2_co2 = $.jqplot('chart102', new_data ,options_co2); + plot2_co2.themeEngine.newTheme('uma', temp); + plot2_co2.activateTheme('uma'); + + console.log('nowww'); + $("#auto_update_co2").attr('disabled','disabled'); + $("#stop_auto_update_co2").removeAttr('disabled'); + } + + + function do_update_co2() { + var from_date = $("#from_date").val(); + var to_date = $("#to_date").val(); + var values = { + "mac": mac, + "from_dt": from_date, + "to_dt": to_date + }; + var jsonText = JSON.stringify(values); + console.log(jsonText); + + $.ajax({ + url : '/charts/'+mac+'/', + + type: 'POST', + data: jsonText, + dataType: 'json', + + success : function(data) { + + console.log ("testing"); + console.log (data); + update_plot_co2(data); + + }, + error: function(data) { + + clearTimeout(timeOut_co2); + $('.bottom-right').notify({ + message: { text: 'Communication Error. Try again later!'}, + type: 'blackgloss', + fadeOut: { enabled: true, delay: 5000 } + }).show(); + } + }); + timeOut_co2 = setTimeout(do_update_co2, 30000); + //},5000); + } + + //Auto update the chart + $('#auto_update_co2').click( function(evt){ + evt.preventDefault(); + do_update_co2(); + }); + + $('#stop_auto_update_co2').click(function(){ + clearTimeout(timeOut_co2); + $('#stop_auto_update_co2').attr('disabled', 'disabled'); + $('#auto_update_co2').removeAttr('disabled'); + }); + + $('#stack_chart_co2').click( function(evt){ + evt.preventDefault(); + stackCharts_co2(); + }); + + function stackCharts_co2(){ + if (timeOut_co2) { + clearTimeout(timeOut_co2); + $('#stop_auto_update_co2').attr('disabled', 'disabled'); + $('#auto_update_co2').removeAttr('disabled'); + } + options_co2.legend.labels = []; + var new_data = []; + $.each($('input:checked'), function(index, value){ + if (this.id == 'co2') { + if (typeof(_co2) == 'string') + { + _co2 = $.parseJSON(_co2); + } + new_data.push(_co2); + options_co2.legend.labels.push(this.value); + } + + options_co2.axes.xaxis.min = _co2[0][0]; + options_co2.axes.xaxis.max = _co2[_co2.length-1][0]; + }); + + + if (plot_co2) { + plot_co2.destroy(); + } + + + plot2_co2 = $.jqplot('chart102', new_data ,options_co2); + plot2_co2.themeEngine.newTheme('uma', temp); + plot2_co2.activateTheme('uma'); + + } + + /** + * Plot functions and values for VOC + * @type {{legend: {show: boolean, labels: string[]}, series: {label: string, neighborThreshold: number, yaxis: string}[], cursor: {show: boolean, zoom: boolean}, seriesDefaults: {show: boolean, showMarker: boolean, pointLabels: {show: boolean}, rendererOption: {smooth: boolean}}, axesDefaults: {labelRenderer: jQuery.jqplot.CanvasAxisLabelRenderer}, axes: {xaxis: {label: string, renderer: jQuery.jqplot.DateAxisRenderer, tickOptions: {formatString: string}, numberTicks: number, min: *, max: *}, yaxis: {min: number, max: number, label: string}}}} + */ + //Plot options + var options_voc = { + legend: { + show: true, + labels:["VOC"] + }, + series:[{ + label: 'VOC (ppb)', + neighborThreshold: -1, + yaxis: 'yaxis' + }], + cursor: { + show: true, + zoom: true + }, + seriesDefaults: { + show: true, + showMarker:false, + pointLabels: {show:false}, + rendererOption:{smooth: true} + }, + axesDefaults: { + labelRenderer: $.jqplot.CanvasAxisLabelRenderer + }, + axes: { + xaxis: { + label: "Time", + renderer: $.jqplot.DateAxisRenderer, + tickOptions:{formatString:'%m/%d, %H:%M'}, + + min : _voc[0][0], + max: _voc[_voc.length-1][0] + }, + yaxis: { + autoscale: true, + label: "VOC (ppb)" + } + } + }; + + + + //Initialize plot for VOC + var data_points_voc = [_voc]; + var plot_voc = $.jqplot('chart103', data_points_voc ,options_voc); + $("#voc").attr('checked','checked'); + + temp = { + seriesStyles: { + seriesColors: ['red', 'orange', 'yellow', 'green', 'blue', 'indigo'], + highlightColors: ['lightpink', 'lightsalmon', 'lightyellow', 'lightgreen', 'lightblue', 'mediumslateblue'] + }, + grid: { + + }, + axesStyles: { + borderWidth: 0, + label: { + fontFamily: 'Sans', + textColor: 'white', + fontSize: '9pt' + } + } + }; + + + plot_voc.themeEngine.newTheme('uma', temp); + plot_voc.activateTheme('uma'); + + var timeOut_voc; + + function update_plot_voc(_data) { + _voc = _data.voc; + + var new_data = []; + + $.each($('input:checked'), function(index, value){ + + if (this.id == 'voc') { + if (typeof(_voc) == 'string') { + _voc = $.parseJSON(_voc); + } + new_data.push(_voc); + options_voc.legend.labels.push(this.value); + } + + options_voc.axes.xaxis.min = _voc[0][0]; + options_voc.axes.xaxis.max = _voc[_voc.length-1][0]; + }); + + if (plot_voc) { + plot_voc.destroy(); + } + + + plot2_voc = $.jqplot('chart103', new_data ,options_voc); + plot2_voc.themeEngine.newTheme('uma', temp); + plot2_voc.activateTheme('uma'); + + console.log('nowww'); + $("#auto_update_voc").attr('disabled','disabled'); + $("#stop_auto_update_voc").removeAttr('disabled'); + } + + + function do_update_voc() { + var from_date = $("#from_date").val(); + var to_date = $("#to_date").val(); + var values = { + "mac": mac, + "from_dt": from_date, + "to_dt": to_date + }; + var jsonText = JSON.stringify(values); + console.log(jsonText); + + $.ajax({ + url : '/charts/'+mac+'/', + + type: 'POST', + data: jsonText, + dataType: 'json', + + success : function(data) { + + console.log ("testing"); + console.log (data); + update_plot_voc(data); + + }, + error: function(data) { + + clearTimeout(timeOut_voc); + $('.bottom-right').notify({ + message: { text: 'Communication Error. Try again later!'}, + type: 'blackgloss', + fadeOut: { enabled: true, delay: 5000 } + }).show(); + } + }); + timeOut_voc = setTimeout(do_update_voc, 30000); + //},5000); + } + + //Auto update the chart + $('#auto_update_voc').click( function(evt){ + evt.preventDefault(); + do_update_voc(); + }); + + $('#stop_auto_update_voc').click(function(){ + clearTimeout(timeOut_voc); + $('#stop_auto_update_voc').attr('disabled', 'disabled'); + $('#auto_update_voc').removeAttr('disabled'); + }); + + $('#stack_chart_voc').click( function(evt){ + evt.preventDefault(); + stackCharts_voc(); + }); + + function stackCharts_voc(){ + if (timeOut_voc) { + clearTimeout(timeOut_voc); + $('#stop_auto_update_voc').attr('disabled', 'disabled'); + $('#auto_update_voc').removeAttr('disabled'); + } + options_voc.legend.labels = []; + var new_data = []; + $.each($('input:checked'), function(index, value){ + if (this.id == 'voc') { + if (typeof(_voc) == 'string') { + _voc = $.parseJSON(_voc); + } + new_data.push(_voc); + options_voc.legend.labels.push(this.value); + } + + options_voc.axes.xaxis.min = _voc[0][0]; + options_voc.axes.xaxis.max = _voc[_voc.length-1][0]; + }); + + + if (plot_voc) { + plot_voc.destroy(); + } + + + plot2_voc = $.jqplot('chart103', new_data ,options_voc); + plot2_voc.themeEngine.newTheme('uma', temp); + plot2_voc.activateTheme('uma'); + + } + + + /** + * Plot functions and values for Dust + * @type {{legend: {show: boolean, labels: string[]}, series: {label: string, neighborThreshold: number, yaxis: string}[], cursor: {show: boolean, zoom: boolean}, seriesDefaults: {show: boolean, showMarker: boolean, pointLabels: {show: boolean}, rendererOption: {smooth: boolean}}, axesDefaults: {labelRenderer: jQuery.jqplot.CanvasAxisLabelRenderer}, axes: {xaxis: {label: string, renderer: jQuery.jqplot.DateAxisRenderer, tickOptions: {formatString: string}, numberTicks: number, min: *, max: *}, yaxis: {min: number, max: number, label: string}}}} + */ + //Plot options + var options_dust = { + legend: { + show: true, + labels:["Dust"] + }, + series:[{ + label: 'Dust (ug/m^3)', + neighborThreshold: -1, + yaxis: 'yaxis' + }], + cursor: { + show: true, + zoom: true + }, + seriesDefaults: { + show: true, + showMarker:false, + pointLabels: {show:false}, + rendererOption:{smooth: true} + }, + axesDefaults: { + labelRenderer: $.jqplot.CanvasAxisLabelRenderer + }, + axes: { + xaxis: { + label: "Time", + renderer: $.jqplot.DateAxisRenderer, + tickOptions:{formatString:'%m/%d, %H:%M'}, + + min : _dust[0][0], + max: _dust[_dust.length-1][0] + }, + yaxis: { + autoscale: true, + label: "Dust (ug/m^3)" + } + } + }; + + + + //Initialize plot for Dust + var data_points_dust = [_dust]; + var plot_dust = $.jqplot('chart104', data_points_dust ,options_dust); + $("#dust").attr('checked','checked'); + + temp = { + seriesStyles: { + seriesColors: ['red', 'orange', 'yellow', 'green', 'blue', 'indigo'], + highlightColors: ['lightpink', 'lightsalmon', 'lightyellow', 'lightgreen', 'lightblue', 'mediumslateblue'] + }, + grid: { + + }, + axesStyles: { + borderWidth: 0, + label: { + fontFamily: 'Sans', + textColor: 'white', + fontSize: '9pt' + } + } + }; + + + plot_dust.themeEngine.newTheme('uma', temp); + plot_dust.activateTheme('uma'); + + var timeOut_dust; + + function update_plot_dust(_data) { + _dust = _data.dust; + + var new_data = []; + + $.each($('input:checked'), function(index, value){ + + if (this.id == 'dust') { + if (typeof(_dust) == 'string') { + _dust = $.parseJSON(_dust); + } + new_data.push(_dust); + options_dust.legend.labels.push(this.value); + } + + options_dust.axes.xaxis.min = _dust[0][0]; + options_dust.axes.xaxis.max = _dust[_dust.length-1][0]; + }); + + if (plot_dust) { + plot_dust.destroy(); + } + + + plot2_dust = $.jqplot('chart104', new_data ,options_dust); + plot2_dust.themeEngine.newTheme('uma', temp); + plot2_dust.activateTheme('uma'); + + console.log('nowww'); + $("#auto_update_dust").attr('disabled','disabled'); + $("#stop_auto_update_dust").removeAttr('disabled'); + } + + + function do_update_dust() { + var from_date = $("#from_date").val(); + var to_date = $("#to_date").val(); + var values = { + "mac": mac, + "from_dt": from_date, + "to_dt": to_date + }; + var jsonText = JSON.stringify(values); + console.log(jsonText); + + $.ajax({ + url : '/charts/'+mac+'/', + + type: 'POST', + data: jsonText, + dataType: 'json', + + success : function(data) { + + console.log ("testing"); + console.log (data); + update_plot_dust(data); + + }, + error: function(data) { + + clearTimeout(timeOut_dust); + $('.bottom-right').notify({ + message: { text: 'Communication Error. Try again later!'}, + type: 'blackgloss', + fadeOut: { enabled: true, delay: 5000 } + }).show(); + } + }); + timeOut_dust = setTimeout(do_update_dust, 30000); + //},5000); + } + + //Auto update the chart + $('#auto_update_dust').click( function(evt){ + evt.preventDefault(); + do_update_dust(); + }); + + $('#stop_auto_update_dust').click(function(){ + clearTimeout(timeOut_dust); + $('#stop_auto_update_dust').attr('disabled', 'disabled'); + $('#auto_update_dust').removeAttr('disabled'); + }); + + $('#stack_chart_dust').click( function(evt){ + evt.preventDefault(); + stackCharts_dust(); + }); + + function stackCharts_dust(){ + if (timeOut_dust) { + clearTimeout(timeOut_dust); + $('#stop_auto_update_dust').attr('disabled', 'disabled'); + $('#auto_update_dust').removeAttr('disabled'); + } + options_dust.legend.labels = []; + var new_data = []; + $.each($('input:checked'), function(index, value){ + if (this.id == 'dust') { + if (typeof(_dust) == 'string') { + _dust = $.parseJSON(_dust); + } + new_data.push(_dust); + options_dust.legend.labels.push(this.value); + } + + options_dust.axes.xaxis.min = _dust[0][0]; + options_dust.axes.xaxis.max = _dust[_dust.length-1][0]; + }); + + + if (plot_dust) { + plot_dust.destroy(); + } + + + plot2_dust = $.jqplot('chart104', new_data ,options_dust); + plot2_dust.themeEngine.newTheme('uma', temp); + plot2_dust.activateTheme('uma'); + + } + + + $("#get_stat").click(function(evt) { + evt.preventDefault(); + var from_date = $("#from_date").val(); + var to_date = $("#to_date").val(); + get_statistics(from_date, to_date); + + }); + + function get_statistics(from_date, to_date) { + var values = { + "mac": mac, + "from_dt": from_date, + "to_dt": to_date + }; + var jsonText = JSON.stringify(values); + console.log(jsonText); + + $.ajax({ + url : '/charts/' + mac + '/', + + type: 'POST', + data: jsonText, + dataType: 'json', + + success : function(data) { + + + + if (data.temperature.length == 0) { + $('.bottom-right').notify({ + message: { text: 'No data found for the selected time period.'}, + type: 'blackgloss', + fadeOut: { enabled: true, delay: 5000 } + }).show(); + } else { + + update_plot_temp(data); + $("#auto_update_temp").removeAttr('disabled'); + $("#stop_auto_update_temp").attr('disabled','disabled'); + update_plot_humidity(data); + $("#auto_update_humidity").removeAttr('disabled'); + $("#stop_auto_update_humidity").attr('disabled','disabled'); + update_plot_co2(data); + $("#auto_update_co2").removeAttr('disabled'); + $("#stop_auto_update_co2").attr('disabled','disabled'); + update_plot_voc(data); + $("#auto_update_voc").removeAttr('disabled'); + $("#stop_auto_update_voc").attr('disabled','disabled'); + update_plot_dust(data); + $("#auto_update_dust").removeAttr('disabled'); + $("#stop_auto_update_dust").attr('disabled','disabled'); + + } + }, + error: function(data) { + + + $('.bottom-right').notify({ + message: { text: 'Communication Error. Try again later!'+data}, + type: 'blackgloss', + fadeOut: { enabled: true, delay: 5000 } + }).show(); + } + }); + + } + + $("#export_data").click(function(evt) { + evt.preventDefault(); + var from_date = $("#from_date").val(); + var to_date = $("#to_date").val(); + export_to_spreadsheet(from_date, to_date); + + }); + + + function export_to_spreadsheet(from_date, to_date) { + var values = { + "mac": mac, + "from_dt": from_date, + "to_dt": to_date + }; + var jsonText = JSON.stringify(values); + console.log(jsonText); + $.ajax({ + url : 'charts/download_sheet/' + mac + '/', + type: 'POST', + data: jsonText, + dataType: 'json', + success : function(data) { + if (data.length == 0) { + $('.bottom-right').notify({ + message: { text: 'No data found for the selected time period.'}, + type: 'blackgloss', + fadeOut: { enabled: true, delay: 5000 } + }).show(); + } else { + JSONToCSVConvertor(data, mac, true); + + } + }, + error: function(data) { + $('.bottom-right').notify({ + message: { text: 'Communication Error. Try again later!'+data}, + type: 'blackgloss', + fadeOut: { enabled: true, delay: 5000 } + }).show(); + } + }); + } + + + function JSONToCSVConvertor(JSONData, ReportTitle, ShowLabel) { + //If JSONData is not an object then JSON.parse will parse the JSON string in an Object + var arrData = typeof JSONData != 'object' ? JSON.parse(JSONData) : JSONData; + var CSV = ''; + //This condition will generate the Label/Header + if (ShowLabel) { + var row = ""; + //This loop will extract the label from 1st index of on array + for (var index in arrData[0]) { + //Now convert each value to string and comma-seprated + row += index + ','; + } + row = row.slice(0, -1); + //append Label row with line break + CSV += row + '\r\n'; + } + //1st loop is to extract each row + for (var i = 0; i < arrData.length; i++) { + var row = ""; + //2nd loop will extract each column and convert it in string comma-seprated + for (var index in arrData[i]) { + row += '"' + arrData[i][index] + '",'; + } + row.slice(0, row.length - 1); + //add a line break after each row + CSV += row + '\r\n'; + } + if (CSV == '') { + alert("Invalid data"); + return; + } + //Generate a file name + var fileName = "timeseries_"; + //this will remove the blank-spaces from the title and replace it with an underscore + fileName += ReportTitle.replace(/ /g,"_"); + //Initialize file format you want csv or xls + var uri = 'data:text/csv;charset=utf-8,' + escape(CSV); + //this trick will generate a temp tag + var link = document.createElement("a"); + link.href = uri; + //set the visibility hidden so it will not effect on your web-layout + link.style = "visibility:hidden"; + link.download = fileName + ".csv"; + //this part will append the anchor tag and remove it after automatic click + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + + + +}); \ No newline at end of file diff --git a/Web_Server/static/app_js/iaq_sensor.js b/Web_Server/static/app_js/iaq_sensor.js new file mode 100644 index 0000000000000000000000000000000000000000..2a65fca2c29cd7f71ac41375959705c4916f9522 --- /dev/null +++ b/Web_Server/static/app_js/iaq_sensor.js @@ -0,0 +1,50 @@ +/** + * Created by avijit on 9/22/17. + */ + +$( document ).ready(function() { + $.csrftoken(); + + var ws = new WebSocket("ws://" + window.location.host + "/socket_agent/"+device_data.agent_id); + + ws.onopen = function () { + ws.send("WS opened from html page"); + }; + + ws.onmessage = function (event) { + var _data = event.data; + _data = $.parseJSON(_data); + var topic = _data['topic']; + // ["", "agent", "ui", device_type, command, building_name, zone_id, agent_id] + if (topic) { + topic = topic.split('/'); + console.log(topic); + // to/ui/from/agent_id/device_status_response + // to/ui/from/agent_id/device_update_response + if (topic[3] == device_data.agent_id && topic[4] == 'device_status_response') { + if ($.type( _data['message'] ) === "string"){ + var _message = $.parseJSON(_data['message']); + if ($.type(_message) != "object"){ + _message = $.parseJSON(_message) + } + change_iaq_sensor_values(_message); + } else if ($.type( _data['message'] ) === "object"){ + change_iaq_sensor_values(_data['message']); + } + + } + } + }; + + + function change_iaq_sensor_values(data) { + + $("#temperature").text(data.temperature); + $("#humidity").text(data.humidity); + $("#co2").text(data.co2); + $("#voc").text(data.voc); + $("#dust").text(data.dust); + + } + +}); diff --git a/Web_Server/webapps/charts/templates/charts/charts_iaq_sensor.html b/Web_Server/webapps/charts/templates/charts/charts_iaq_sensor.html new file mode 100644 index 0000000000000000000000000000000000000000..a7636e14a55199e51acb37d5a8a21cc81378e080 --- /dev/null +++ b/Web_Server/webapps/charts/templates/charts/charts_iaq_sensor.html @@ -0,0 +1,350 @@ +{% load dashboard_extras %} +{% load switch_case %} +{% load device_count_in_zone %} +{% load timedelta %} +{% load user_role %} + + + + +BEMOSS Charts and Statistics + + + + + + + + + + + + + + + + + + + + + + + + + +{% include 'common/top_nav.html' %} +
+{% include 'common/side_nav.html' %} +
+
+
{% csrf_token %} +
+
+

{{ node_name }} : {{ nickname }} Statistics

+
+
+ +
+
+
+
+ From: + + +
+
+
+
+
+
+ To: + + +
+
+
+
+
+ +
+
+ {% if request.user|has_group:'Admin' or request.user|has_group:'Zone Manager'%} +
+
+ +
+
+ {% endif %} +
+ + +
+
+
+
+

{{ nickname }} : Temperature

+
+
+
+
+
+
+
+
+
+

Data points

+
+
+
+
+
+
+

+
+ +
+
+
+
+
+ + +
+
+
+
+
+
+
+
+

{{ nickname }} : Humidity

+
+
+
+
+
+
+
+
+
+

Data points

+
+
+
+
+
+
+

+
+ +
+
+
+
+
+ + +
+
+
+
+
+
+
+
+

{{ nickname }} : CO2

+
+
+
+
+
+
+
+
+
+

Data points

+
+
+
+
+
+
+

+
+ +
+
+
+
+
+ + +
+
+
+
+
+
+
+
+

{{ nickname }} : VOC

+
+
+
+
+
+
+
+
+
+

Data points

+
+
+
+
+ + +
+

+
+ +
+
+
+
+
+ + +
+
+
+
+
+
+
+
+

{{ nickname }} : Dust

+
+
+
+
+
+
+
+
+
+

Data points

+
+
+
+
+ + +
+

+
+ +
+
+
+
+
+ + +
+
+
+
+
+
+
+
+ + + + + + + + + + +{% include 'common/theme_changer.html' %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Web_Server/webapps/device/templates/sensors/iaq_sensor.html b/Web_Server/webapps/device/templates/sensors/iaq_sensor.html new file mode 100644 index 0000000000000000000000000000000000000000..41bef9fc5985c6755c8b13b5c775e0153c97e71b --- /dev/null +++ b/Web_Server/webapps/device/templates/sensors/iaq_sensor.html @@ -0,0 +1,111 @@ +{% load dashboard_extras %} +{% load switch_case %} +{% load device_count_in_zone %} +{% load timedelta %} + + + +{{ device_info.node.node_name }}: Indoor Air Quality Sensor - {{ device_info.nickname }} + + + + + + + + + + + + + + + + + + + + + + +{% include 'common/top_nav.html' %} +
+{% include 'common/side_nav.html' %} +
+ +
+ {% csrf_token %} +
+
+
+

{{device_info.node.node_name}} : {{device_info.nickname}}

+
+
+
+ {% for iteration in 5|times %} +
+ + +
+
{% cycle "Temperature" "Humidity" "CO2" "VOC" "Dust" %}
+ {% cycle 'temperature' 'humidity' 'co2' 'voc' 'dust' as var silent %} + {% cycle ' F' ' %' ' ppm' ' ppb' ' ug/m^3' as unit silent%} + +
{{ device_data.data|get_item_in_dict:var }} {{ unit }}
+ +
+ +
+
+
+ {% endfor %} +
+
+
+
+
+
+ +
+
+ +
+
+ + + + + + + + + + + + + +{% include 'common/theme_changer.html' %} + + + \ No newline at end of file diff --git a/Web_Server/webapps/discovery/migrations/0002_auto_20170922_1822.py b/Web_Server/webapps/discovery/migrations/0002_auto_20170922_1822.py new file mode 100644 index 0000000000000000000000000000000000000000..8ef8eda3acfeb2670d4d001851ab185300c88879 --- /dev/null +++ b/Web_Server/webapps/discovery/migrations/0002_auto_20170922_1822.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10 on 2017-09-22 18:22 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('discovery', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='passwordsmanager', + name='password', + field=models.CharField(max_length=256, verbose_name='password'), + ), + ]