integrated Chart.js
integrated Chart.js

--- a/assets/js/iotcc.js
+++ b/assets/js/iotcc.js
@@ -181,6 +181,19 @@
                         $('span[name="' + widgetId + '"]').html(json.value).data('value', json.value);
                         iotCC.animate($('span[name="' + widgetId + '"]').closest(".widgetcontainer"));
                     }
+                } else if (json.widget == 'chart.js') {
+                    if ($('canvas[name="' + widgetId + '"]').exists() == false) {
+                        html = '';
+                        html += '<canvas name="' + widgetId + '" data-widget="' + json.widget + '" data-chart="' + json.chart + '" class="{class11}"></canvas> ' + (json.valuedescription?'<span class="text {class12}">' + json.valuedescription + '</span>':'') + '';
+                        json.content = html;
+                        json.widgetId = widgetId;
+                        iotCC.addWidget(json, function() {
+                            iotCC.createChart(widgetId, json.chart, json.value);
+                        });
+                    } else {
+                        iotCC.createChart(widgetId, json.chart, json.value);
+                        iotCC.animate($('canvas[name="' + widgetId + '"]').closest(".widgetcontainer"));
+                    }
                 }
             } else if (topicPath[4] == 'data') {
                 widget = $('*[name="' + widgetId + '"]').first().data('widget');
@@ -200,6 +213,9 @@
                     if ($('span[name="' + widgetId + '"]').exists() == true) {
                         $('span[name="' + widgetId + '"]').html(json.value).data('value', json.value);
                     }
+                } else if (widget == 'chart.js') {
+                    var chart = $('canvas[name="' + widgetId + '"]').first().data('chart');
+                    iotCC.createChart(widgetId, chart, json.value);
                 }
             } else if (topicPath[3] == 'device') {
                 $(json.pages).each(function(k, page) {
@@ -223,14 +239,20 @@
     formatTopic: function(topic) {
         return topic.replace(/\//gi, '_').replace(/:/gi, '_').replace('_data', '').replace('_config', '');
     },
-    addWidget: function(json) {
+    addWidget: function(json, callback) {
         if (this.templates[json.template] != undefined) {
             iotCC.addHtml(json, this.templates[json.template]);
+            if (callback) {
+                callback();
+            }
         } else {
             // TODO : fetch custom templates over HTTP
             $.get('assets/template/' + json.template + '.html', function(html) {
                 iotCC.templates[json.template] = html;
                 iotCC.addHtml(json, html);
+                if (callback) {
+                    callback();
+                }
             });
         }
     },
@@ -478,6 +500,14 @@
                 iotCC.mqttClient.publish('/iotcc/customSubscription/' + i + '/config', widgetJson, {qos: 1, retained: false});
             }
         }
+    },
+    createChart: function(id, chart, data) {
+        var pieChartCanvas = $('canvas[name="' + id + '"]').get(0).getContext("2d");
+        var myPieChart = new Chart(pieChartCanvas, {
+            type: chart.replace('chart', ''),
+            data: data,
+            options: {}
+        });
     }
 }
 

--- a/assets/js/simulateDevices.js
+++ b/assets/js/simulateDevices.js
@@ -10,6 +10,7 @@
         return;
     }
     if (topicPath[2] == 'device') {
+
         iotCC.mqttClient.publish('/iotcc/heater1/device', '{"name":"House heating 1","desc":"", "pages" : [{"pageId": 10, "pageName": "House heating", "icon": "ion-ios-home", "class1":"bg-blue", "order": "10"}]}', {qos: 1, retained: false});
         iotCC.mqttClient.publish('/iotcc/heater1/heater/config', '{"pageName": "House heating", "pageId": 10, "widget":"radios", "title":"Hollway Heater", "topic":"/iotcc/heater1/heater", "options":[{"checked":true, "label": "Off", "status":"1"}, {"label": "Confort", "status":"2"}, {"label": "Anti freeze", "status":"3"}, {"label": "Confort -2", "status":"4"}], "template": "template-1", "icon": "ion-ios-home", "class4": "bg-blue", "order": 40}', {qos: 1, retained: false});
 
@@ -43,5 +44,9 @@
         iotCC.mqttClient.publish('/iotcc/greenhouse/tempsensor1/data', '{"value":"' + (Math.floor(Math.random() * (10)) + 20) + '"}');
         iotCC.mqttClient.publish('/iotcc/greenhouse/heater/config', '{"pageName": "Greenhouse", "pageId": 40, "widget":"data-control", "format":"int", "title":"Heater", "topic":"/iotcc/greenhouse/heater", "value": "22", "valuedescription": "degrees C", "template": "template-3", "icon": "ion-ios-home", "class": "bg-green", "class2": "text-center", "class10": "xs", "order": 30}', {qos: 1, retained: false});
         iotCC.mqttClient.publish('/iotcc/greenhouse/heater/data', '{"value":"' + (Math.floor(Math.random() * (10)) + 20) + '"}');
+
+        iotCC.mqttClient.publish('/iotcc/watertank/device', '{"name":"Watertank","desc":"", "pages" : [{"pageId" : 1000, "pageName" : "Watertank", "icon": "ion-ios-home", "class1":"bg-green", "order": "100"}]}', {qos: 1, retained: false});
+        iotCC.mqttClient.publish('/iotcc/watertank/level/config', '{"pageName": "Greenhouse", "pageId": 1000, "widget": "chart.js", "chart": "pie", "title": "Watertank level", "topic":"/iotcc/watertank/level", "value": {"labels": ["Full", "Empty"], "datasets": [{"data": [70, 30], "backgroundColor": ["#3c8dbc", "#fff"], "hoverBackgroundColor": [ "#3c8dbc", "#fff"]}]}, "template": "template-3", "icon": "ion-ios-home", "class": "bg-green", "order": 30}', {qos: 1, retained: false});
+        iotCC.mqttClient.publish('/iotcc/watertank/level1/config', '{"pageName": "Greenhouse", "pageId": 1000, "widget": "chart.js", "chart": "doughnut", "title": "Watertank level 2", "topic":"/iotcc/watertank/level2", "value": {"labels": ["Full", "Empty"], "datasets": [{"data": [70, 30], "backgroundColor": ["#3c8dbc", "#fff"], "hoverBackgroundColor": [ "#3c8dbc", "#fff"]}]}, "template": "template-3", "icon": "ion-ios-home", "class": "bg-green", "order": 30}', {qos: 1, retained: false});
     }
 });

file:a/bower.json -> file:b/bower.json
--- a/bower.json
+++ b/bower.json
@@ -21,7 +21,8 @@
     "bootstrap": "^3.3.7",
     "jquery-serialize-object": "^2.5.0",
     "font-awesome": "fontawesome#^4.7.0",
-    "Ionicons": "ionicons#^2.0.1"
+    "Ionicons": "ionicons#^2.0.1",
+    "chart.js": "^2.5.0"
   }
 }
 

file:a/index.html -> file:b/index.html
--- a/index.html
+++ b/index.html
@@ -161,6 +161,8 @@
                                         <option value="radios" data-action="on">Radios (multiple choice action)</option>
                                         <option value="data" data-action="off">Data (show sensor data)</option>
                                         <option value="data-control" data-action="on">Data control (show sensor data/control value/heater)</option>
+                                        <option value="pie" data-action="on">Pie chart</option>
+                                        <option value="doughnut" data-action="on">Doughnut chart</option>
                                     </select>
                                 </div>
                                 <div class="form-group subscriptionWidgetJson">
@@ -420,5 +422,7 @@
 <script type="text/javascript" src="assets/js/iotcc.js"></script>
 <script type="text/javascript" src="assets/js/simulateDevices.js"></script>
 
+<script src="bower_components/chart.js/dist/Chart.min.js"></script>
+
 </body>
 </html>

file:a/readme.md -> file:b/readme.md
--- a/readme.md
+++ b/readme.md
@@ -20,16 +20,20 @@
 - BETA: subscribe to custom topics, assign template for display. To do configurator
 - TODO: custom subscriptions callbacks to parse the message data
 - TODO: OTA updates with widget configuration
+- TODO: /iotcc/+/+/confirm. IoT confirmation of received message
 - TODO: optimizations
 
 How it works (WIP) :
 IoT CC subscribes to
 - /iotcc/+/+/config
 - /iotcc/+/+/data
+- /iotcc/+/+/confirm
 - /iotcc/+/device
 
 IoT CC publishes to
 - /iotcc/device - {"clientId": "{clientId}"}
+- /iotcc/+/+/data - {"status":"{status}", "clientId": "{clientId}"}
+- /iotcc/+/+/data - {"value":"{value}", "clientId": "{clientId}"}
 
 IoT devices subscribe to
 - /iotcc/+/+/data
@@ -38,7 +42,7 @@
 IoT devices publish to :
 - /iotcc/+/device - {"name":"House heating 1","desc":"", "pages" : [{"pageId" : 10, "pageName" : "House heating", "icon": "ion-ios-home"}]}
 - /iotcc/+/+/config - {"pageName": "House heating", "pageId": 10, "widget":"radios", "title":"Hollway Heater", "topic":"/iotcc/heater1/heater", "options":[{"checked":true, "label": "Off", "status":"1"}, {"label": "Confort", "status":"2"}, {"label": "Anti freeze", "status":"3"}, {"label": "Confort -2", "status":"4"}], "template": "template-3", "icon": "ion-ios-home", "bgcolor": "bg-blue", "order": 40}
-- /iotcc/+/+/data - {"status":"{status}"}
+- /iotcc/+/+/confirm - {"status":"{status}"}
 
 ### Desktop interface (WIP)
 ![Alt text](/screenshots/dashboard-desktop.png?raw=true "Desktop interface")

comments