custom subscriptions BETA
custom subscriptions BETA

--- a/assets/js/iotcc.js
+++ b/assets/js/iotcc.js
@@ -1,8 +1,3 @@
-var appOptions = {
-    templateDebug: false,
-    pageContainer: true
-};
-
 var iotCC = {
     mqttDefaultConfig: {
         clientId: 'IoTCC_' + Math.random(),
@@ -34,21 +29,20 @@
         'connect': [],
         'message': []
     },
-    init: function(mqttConfig) {
+    appConfig: {
+        templateDebug: false,
+        pageContainer: true
+    },
+    init: function() {
         if (typeof jQuery == 'undefined') {
-            this.showNotification('jQuery', 'IoT Control Center requires jQuery', 'dashboard', 'danger');
+            this.showNotification('jQuery', 'IoT Control Center requires jQuery', 'dashboard-notification', 'danger');
             logger.log ('IoT Control center requires jQuery');
             return;
         }
-        var config = this.getConfig();
-        if (typeof config == 'undefined') {
-            this.showNotification('MQTT connection data', 'Please set the MQTT connection data in Settings', 'dashboard', 'danger');
-            logger.log ('MQTT conection data is not set');
-            return;
-        }
+        this.getConfig();
         // TODO: check for localStorage object
 
-        this.showNotification('Connecting to MQTT server', 'Trying to connect to ' + this.mqttConfig.host + ':' + this.mqttConfig.port, 'dashboard', 'info');
+        this.showNotification('Connecting to MQTT server', 'Trying to connect to ' + this.mqttConfig.host + ':' + this.mqttConfig.port, 'dashboard-notification', 'info');
 
         this.mqttClient = mqtt.connect('ws' + (this.mqttConfig.secure==true?'s':'') + '://' + this.mqttConfig.host + ':' + this.mqttConfig.port, this.mqttConfig);
 
@@ -59,7 +53,7 @@
 
         this.mqttClient.on('connect', function() {
             if (iotCC.mqttConfig.debug) logger.log('client connected:' + iotCC.mqttConfig.clientId);
-            iotCC.showNotification('Connected to MQTT server ' + iotCC.mqttConfig.host + ':' + iotCC.mqttConfig.port, 'Waiting to receive data from devices.', 'dashboard', 'info');
+            iotCC.showNotification('Connected to MQTT server ' + iotCC.mqttConfig.host + ':' + iotCC.mqttConfig.port, 'Waiting to receive data from devices.', 'dashboard-notification', 'info');
 
             for(var callback in iotCC.events.connect) {
                 try {
@@ -76,8 +70,10 @@
         this.mqttClient.subscribe('/+/+/device', {qos: 1});
 
         this.refreshDevices();
+        this.customSubscriptions();
 
         this.mqttClient.on('message', function(topic, message, packet) {
+            iotCC.handleCustomSubscriptions(topic, message);
             try {
                 var json = JSON.parse(message.toString());
             } catch(err){
@@ -88,7 +84,7 @@
             var topicPath = topic.split('/'),
             widgetId = iotCC.formatTopic(topic),
             widget, html;
-            $('.notification-dashboard').addClass('hide');
+            $('.dashboard-notification-html').remove();
             if (iotCC.mqttConfig.debug) {
                 logger.log('Received Topic:= ' + topic + '\n\tMessage:= ' + message.toString());
             }
@@ -96,6 +92,7 @@
             if (topicPath[4] == 'config') {
                 var page = {'pageId': json.pageId, 'pageName': json.pageName, 'icon': json.icon};
                 iotCC.addPage(page);
+                var publishTopic = json.publishTopic ? json.publishTopic : json.topic + '/data';
                 if (json.widget == 'toggle') {
                     if ($('input[name="' + widgetId + '"]').exists() == false) {
                         html = '<label class="switch switch--material {class4}">';
@@ -111,10 +108,10 @@
                         json.callback = function() {
                             if ($(this).prop('checked') == true) {
                                 $(this).data('status', 1);
-                                iotCC.mqttClient.publish(json.topic + '/data', '{"status":1}', {qos: 1, retained: false});
+                                iotCC.mqttClient.publish(publishTopic, '{"status":1}', {qos: 1, retained: false});
                             } else {
                                 $(this).data('status', 0);
-                                iotCC.mqttClient.publish(json.topic + '/data', '{"status":0}', {qos: 1, retained: false});
+                                iotCC.mqttClient.publish(publishTopic, '{"status":0}', {qos: 1, retained: false});
                             }
                         };
                         iotCC.addWidget(json);
@@ -136,7 +133,7 @@
                         json.widgetId = widgetId;
                         json.selector = 'input';
                         json.callback = function() {
-                            iotCC.mqttClient.publish(json.topic + '/data', '{"status":"' + $(this).data('status') + '"}', {qos: 1, retained: false});
+                            iotCC.mqttClient.publish(publishTopic, '{"status":"' + $(this).data('status') + '"}', {qos: 1, retained: false});
                         };
                         iotCC.addWidget(json);
                     } else {
@@ -158,7 +155,7 @@
                             var action = $(this).data('action');
                             var value = $('span[name="' + $(this).attr('name') + '"]').data('value');
                             value = action == '+' ? iotCC.formatData(value, json.format) + 1 : iotCC.formatData(value, json.format) - 1;
-                            iotCC.mqttClient.publish(json.topic + '/data', '{"value":"' + value + '"}', {qos: 1, retained: false});
+                            iotCC.mqttClient.publish(publishTopic, '{"value":"' + value + '"}', {qos: 1, retained: false});
                         };
                         iotCC.addWidget(json);
                     } else {
@@ -249,7 +246,7 @@
             } else {
                 var html = '<div class="row page hide" data-page="' + page.pageId + '" data-order="' + page.order + '"></div>';
             }
-            if (appOptions.pageContainer) {
+            if (iotCC.appConfig.pageContainer) {
                 var html2 = '<div class="box pagecontainer {class}" data-page="' + page.pageId + '" data-order="' + page.order + '">';
                 html2 += '<div class="box-header with-border {class1}">';
                 html2 += '<h3 class="box-title {class2}">' + page.pageName + '</h3>';
@@ -282,7 +279,7 @@
             $('.pagination').append(html);
             $('label').filter('[data-pagination="' + page.pageId + '"]').click(function(e){
                 var pageId = $(this).data('pagination');
-                if (appOptions.pageContainer) {
+                if (iotCC.appConfig.pageContainer) {
                     $('div.pagecontainer').addClass('hide');
                     $('div.pagecontainer').filter('[data-page="' + pageId + '"]').removeClass('hide');
                 } else {
@@ -296,49 +293,62 @@
         }
     },
     saveConfig: function() {
-        var config = {
-            'clientId': $('#mqttClientId').val(),
-            'host': $('#mqttHost').val(),
-            'port': $('#mqttPort').val(),
-            'username': $('#mqttUser').val(),
-            'password': $('#mqttPass').val(),
-            'secure': $('#mqttSecure').prop('checked'),
-            'debug': $('#mqttDebug').prop('checked'),
-            'simulateDevices': $('#mqttSimulateDevices').prop('checked'),
-        };
+        var config = JSON.parse(localStorage.getItem('iotCCConfig')) || {};
+        config.mqttConfig = $('#mqttConfig').serializeObject();
+        config.mqttConfig.secure = $('#secure').prop('checked');
+        config.mqttConfig.debug = $('#debug').prop('checked');
+        config.mqttConfig.simulateDevices = $('#simulateDevices').prop('checked');
 
         try {
-            localStorage.setItem('mqttConfig', JSON.stringify(config));
-            iotCC.showNotification('MQTT connection data', 'Data saved succesfully', 'settings', 'info', 3);
-            this.getConfig();
+            localStorage.setItem('iotCCConfig', JSON.stringify(config));
+            iotCC.showNotification('MQTT connection data', 'Data saved succesfully', 'settings-notification1', 'info', 1.5);
         } catch(ex) {
-            iotCC.showNotification('MQTT connection data', 'Cannot save data to local storage', 'settings', 'danger', 5);
+            iotCC.showNotification('MQTT connection data', 'Cannot save data to local storage', 'settings-notification1', 'danger', 3);
         }
     },
     getConfig: function() {
         try {
-            var config = JSON.parse(localStorage.getItem('mqttConfig'));
-            this.mqttConfig = Object.assign(this.mqttDefaultConfig, config);
-            $('#mqttClientId').val(this.mqttConfig.clientId);
-            $('#mqttHost').val(this.mqttConfig.host);
-            $('#mqttPort').val(this.mqttConfig.port);
-            $('#mqttUser').val(this.mqttConfig.username);
-            $('#mqttPass').val(this.mqttConfig.password);
-            $('#mqttSecure').prop('checked', this.mqttConfig.secure);
-            $('#mqttDebug').prop('checked', this.mqttConfig.debug);
-            $('#mqttSimulateDevices').prop('checked', this.mqttConfig.simulateDevices);
+            var config = JSON.parse(localStorage.getItem('iotCCConfig')) || {};
+            this.mqttConfig = Object.assign(this.mqttDefaultConfig, config.mqttConfig);
+            for(var key in this.mqttConfig) {
+                var value = this.mqttConfig[key];
+                if (value == true || false) {
+                    $('input[name="' + key + '"]').prop("checked", value);
+                } else {
+                    $('input[name="' + key + '"]').val(value);
+                }
+            }
+
+            this.appConfig = Object.assign(this.appConfig, config.appConfig);
+            for(var key in this.appConfig) {
+                var value = this.appConfig[key];
+                if (value == true || false) {
+                    $('input[name="' + key + '"]').prop("checked", value);
+                } else {
+                    $('input[name="' + key + '"]').val(value);
+                }
+            }
+            $('#iotccconfig').html(localStorage.getItem('iotCCConfig'));
         } catch(ex) {
+            console.log (ex);
             return;
         }
-        return this.mqttConfig;
-    },
-    showNotification: function(title, content, section, cls, timer) {
-        $('div.notification-' + section).removeClass('hide').addClass('callout-' + cls);
-        $('div.notification-' + section).find('span').html(content);
-        $('div.notification-' + section).find('h4').html(title);
+        return config;
+    },
+    showNotification: function(title, content, prepend, type, timer) {
+        var html = '<div class="col-md-12 ' + prepend + '-html">';
+        html += '<div class="callout callout-' + type + '">';
+        html += '<h4>' + title + '</h4>';
+        html += '<span>' + content + '</span>';
+        html += '</div>';
+        html += '</div>';
+
+        if ($('.' + prepend + '-html').exists()) $('.' + prepend + '-html').remove();
+        $('.' + prepend).prepend(html);
+
         if (timer != undefined) {
             setTimeout(function() {
-                $('div.notification-' + section).addClass('hide');
+                $('.' + prepend + '-html').remove();
             }, timer * 1000);
         }
     },
@@ -366,17 +376,92 @@
         for (var key in json) {
             html = html.replace('{' + key + '}', json[key]);
         }
-        if (appOptions.templateDebug == false) {
+        if (this.appConfig.templateDebug == false) {
             html = html.replace(/{(\w*)}/g, '');
         }
         return html;
+    },
+    customSubscriptions: function() {
+        var config = JSON.parse(localStorage.getItem('iotCCConfig')) || {};
+        $('.subscriptions-table').find('tr').remove();
+        for (i in config.customSubscriptions) {
+            var subscription = config.customSubscriptions[i];
+            var html = '<tr>';
+            html += '<td><a href="#" class="btn fa fa-edit"></a><a href="#" class="btn fa fa-remove"></a></td>';
+            html += '<td>' + i + '</td>';
+            html += '<td>' + subscription.topic + '</td>';
+            html += '<td>' + subscription.widget + '</td>';
+            html += '<td>' + subscription.widgetJson + '</td>';
+            html += '<td>' + subscription.actionTopic + '</td>';
+            html += '<td>' + subscription.active + '</td>';
+            html += '</tr>';
+            $('.subscriptions-table').append(html);
+            if (subscription.topic) this.mqttClient.subscribe(subscription.topic, {qos: 1});
+        }
+        $('.subscriptions-table').find('a.fa-edit').click(function(e){
+            e.preventDefault();
+            var tr = $(this).parent().parent();
+            $('input[name="index"]').val( $(tr).find('td:eq(1)').html() );
+            $('input[name="topic"]').val( $(tr).find('td:eq(2)').html() );
+            $('select[name="widget"]').val( $(tr).find('td:eq(3)').html() ).trigger('change');
+            $('input[name="widgetJson"]').val( $(tr).find('td:eq(4)').html() );
+            $('input[name="actionTopic"]').val( $(tr).find('td:eq(5)').html() );
+            $('input[name="active"]').prop('checked', $(tr).find('td:eq(6)').html()=='true'?true:false);
+        });
+        $('.subscriptions-table').find('a.fa-remove').click(function(e){
+            e.preventDefault();
+            var tr = $(this).parent().parent();
+            var index = $(tr).find('td:eq(1)').html();
+            try {
+                var config = JSON.parse(localStorage.getItem('iotCCConfig')) || {};
+                var data = config.customSubscriptions || [];
+                data.splice(index);
+                config.customSubscriptions = data;
+
+                localStorage.setItem('iotCCConfig', JSON.stringify(config));
+                iotCC.showNotification('Custom subscriptions', 'Data deleted succesfully', 'subscriptions-notification', 'info', 1.5);
+                iotCC.customSubscriptions();
+            } catch(ex) {
+                console.log (ex);
+                iotCC.showNotification('Custom subscriptions', 'Cannot save data to local storage', 'subscriptions-notification', 'danger', 3);
+            }
+        });
+    },
+    handleCustomSubscriptions: function(topic, message) {
+        message = message.toString();
+        var config = JSON.parse(localStorage.getItem('iotCCConfig')) || {};
+        for (i in config.customSubscriptions) {
+            var subscription = config.customSubscriptions[i];
+            if (topic == subscription.topic) {
+                widgetJson = JSON.parse(subscription.widgetJson);
+                if (subscription.widget == 'toggle') {
+                    if (parseInt(message) > 0) {
+                        widgetJson.checked = true;
+                    } else {
+                        widgetJson.checked = false;
+                    }
+                } else if (subscription.widget == 'radios') {
+                    for(i in widgetJson.options) {
+                        if (widgetJson.options[i].status == message) {
+                            widgetJson.options[i].checked = true;
+                        } else {
+                            widgetJson.options[i].checked = false;
+                        }
+                    }
+                } else if (subscription.widget == 'data' || subscription.widget == 'data-control') {
+                    widgetJson.value = message.toString();
+                }
+                widgetJson = JSON.stringify(widgetJson);
+                iotCC.mqttClient.publish('/iotcc/customSubscription/' + i + '/config', widgetJson, {qos: 1, retained: false});
+            }
+        }
     }
 }
 
 jQuery.fn.exists = function(){return ($(this).length > 0);}
  $(document).ready(function(){
 
-    $('.navigation').click(function(e){
+    $('.navigation').click(function(e) {
         e.preventDefault();
         var section = $(this).data('section');
         $('.navigation').parent().removeClass('active');
@@ -386,47 +471,85 @@
     });
 
     $('label').filter('[data-pagination="0"]').click(function(e){
-        if (appOptions.pageContainer) {
+        if (iotCC.appConfig.pageContainer) {
             $('div.pagecontainer').removeClass('hide');
         } else {
             $('div.page').removeClass('hide');
         }
     });
 
-    $('#saveMqttConfig').click(function(e){
+    $('#saveMqttConfig').click(function(e) {
         e.preventDefault();
         iotCC.saveConfig();
     });
 
-    $('#saveOptions').click(function(e){
-        e.preventDefault();
-        var config = {
-            'pageContainer': $('#pageContainer').prop('checked'),
-            'templateDebug': $('#templateDebug').prop('checked'),
-        };
+    $('#saveAppConfig').click(function(e) {
+        e.preventDefault();
+        var config = JSON.parse(localStorage.getItem('iotCCConfig'));
+        config.appConfig = $('#appConfig').serializeObject();
+        config.appConfig.pageContainer = $('#pageContainer').prop('checked');
+        config.appConfig.templateDebug = $('#templateDebug').prop('checked');
 
         try {
-            localStorage.setItem('appOptions', JSON.stringify(config));
-            iotCC.showNotification('Options', 'Data saved succesfully', 'settings', 'info', 3);
+            localStorage.setItem('iotCCConfig', JSON.stringify(config));
+            iotCC.showNotification('Options', 'Data saved succesfully', 'settings-notification2', 'info', 1.5);
         } catch(ex) {
-            iotCC.showNotification('Options', 'Cannot save data to local storage', 'settings', 'danger', 5);
-        }
-    });
-
-    appOptions = Object.assign(appOptions, JSON.parse(localStorage.getItem('appOptions')));
-    for(var key in appOptions) {
-        var value = appOptions[key];
-        if (value == true || false) {
-            $('input[name="' + key + '"]').prop("checked", value);
+            iotCC.showNotification('Options', 'Cannot save data to local storage', 'settings-notification2', 'danger', 3);
+        }
+    });
+
+    $('a').filter('[data-toggle="control-refresh"]').click(function(e) {
+        e.preventDefault();
+        iotCC.refreshDevices();
+    });
+
+
+    $('#widget').change(function(e) {
+        e.preventDefault();
+        if ($(this).find('option:selected').data('action') == 'on') {
+            $('.subscriptionAction').removeClass('hide');
         } else {
-            $('input[name="' + key + '"]').val(value);
-        }
-    }
-
-    $('a').filter('[data-toggle="control-refresh"]').click(function(e){
-        e.preventDefault();
-        iotCC.refreshDevices();
-    });
+            $('.subscriptionAction').addClass('hide');
+        }
+    });
+
+    $('#saveSubscription').click(function(e) {
+        e.preventDefault();
+        var form = $('#customSubscriptions').serializeObject();
+        form.active = $('#active').prop('checked');
+        try {
+            var config = JSON.parse(localStorage.getItem('iotCCConfig')) || {};
+            var data = config.customSubscriptions || [];
+            if (form.index) {
+                data[form.index] = form;
+            } else {
+                data.push(form);
+            }
+            config.customSubscriptions = data;
+
+            localStorage.setItem('iotCCConfig', JSON.stringify(config));
+            iotCC.showNotification('Custom subscriptions', 'Data saved succesfully', 'subscriptions-notification', 'info', 1.5);
+            iotCC.customSubscriptions();
+            $('#customSubscriptions')[0].reset();
+        } catch(ex) {
+            console.log (ex);
+            iotCC.showNotification('Custom subscriptions', 'Cannot save data to local storage', 'subscriptions-notification', 'danger', 3);
+        }
+    });
+
+    $('#saveIoTCCConfig').click(function(e) {
+        e.preventDefault();
+        var config = $('#iotccconfig').val();
+        try {
+            JSON.parse(config);
+            localStorage.setItem('iotCCConfig', config);
+            iotCC.showNotification('IoTCC Config', 'Data saved succesfully', 'settings-notification3', 'info', 1.5);
+        } catch(ex) {
+            console.log (ex);
+            iotCC.showNotification('IoTCC Config', 'Cannot save data to local storage', 'settings-notification3', 'danger', 3);
+        }
+    });
+
     iotCC.init();
 });
 

file:a/bower.json -> file:b/bower.json
--- a/bower.json
+++ b/bower.json
@@ -18,7 +18,8 @@
   "dependencies": {
     "jquery": "^3.1.1",
     "AdminLTE": "adminlte#^2.3.11",
-    "bootstrap": "^3.3.7"
+    "bootstrap": "^3.3.7",
+    "jquery-serialize-object": "^2.5.0"
   }
 }
 

file:a/index.html -> file:b/index.html
--- a/index.html
+++ b/index.html
@@ -60,6 +60,11 @@
                     </a>
                 </li>
                 <li>
+                    <a href="#" class="navigation" data-section="custom-subscriptions">
+                        <i class="fa fa-list"></i> <span>Custom subscriptions</span>
+                    </a>
+                </li>
+                <li>
                     <a href="#" class="navigation" data-section="settings">
                         <i class="fa fa-gears"></i> <span>Settings</span>
                     </a>
@@ -83,6 +88,13 @@
             </ol>
         </section>
 
+        <section class="content-header hide" data-section="custom-subscriptions">
+            <h1>Custom subscriptions</h1>
+            <ol class="breadcrumb">
+                <li class="active"><i class="fa fa-list"></i> Custom subscriptions</li>
+            </ol>
+        </section>
+
         <section class="content-header hide" data-section="settings">
             <h1>Settings</h1>
             <ol class="breadcrumb">
@@ -100,7 +112,7 @@
         <!-- Dashboard content -->
         <section class="content" data-section="dashboard">
 
-            <div class="row">
+            <div class="row dashboard-notification">
                 <div class="col-md-12">
                     <div class="tab-bar tab-bar--top tab-bar--material pagination hide">
                         <label class="tab-bar__item tab-bar--material__item" data-pagination="0" data-order="0">
@@ -114,11 +126,83 @@
                 </div>
             </div>
 
+        </section>
+
+        <!-- Custom subscriptions content -->
+        <section class="content hide" data-section="custom-subscriptions">
+
+            <div class="row subscriptions-notification">
+                <div class="col-md-12">
+                    <div class="box box-primary">
+                        <div class="box-header with-border">
+                            <h3 class="box-title">Add new subscription</h3>
+                        </div>
+                        <!-- /.box-header -->
+                        <!-- form start -->
+                        <form id="customSubscriptions">
+                            <div class="box-body">
+                                <div class="form-group">
+                                    <label for="topic">Subscription topic</label>
+                                    <input type="text" class="form-control" id="topic" name="topic" placeholder="Topic" />
+                                </div>
+                                <div class="form-group">
+                                    <label for="widget">Widget</label>
+                                    <select class="form-control" name="widget" id="widget">
+                                        <option>-- select widget --</option>
+                                        <option value="toggle" data-action="on">Toggle (on/off toggle)</option>
+                                        <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>
+                                    </select>
+                                </div>
+                                <div class="form-group subscriptionWidgetJson">
+                                    <label for="widgetJson">Widget JSON options</label>
+                                    <input type="text" class="form-control" id="widgetJson" name="widgetJson" placeholder="Widget JSON options" />
+                                </div>
+                                <div class="form-group subscriptionAction hide">
+                                    <label for="actionTopic">Widget action topic</label>
+                                    <input type="text" class="form-control" id="actionTopic" name="actionTopic" placeholder="Widget action topic" />
+                                </div>
+                                <div class="checkbox">
+                                    <label for="active">
+                                    <input type="checkbox" id="active" name="active" /> Activate
+                                </label>
+                                </div>
+                            </div>
+                            <!-- /.box-body -->
+
+                            <div class="box-footer">
+                                <button type="submit" class="btn btn-primary" id="saveSubscription">Save</button>
+                            </div>
+                            <input type="hidden" name="index" />
+                        </form>
+                    </div>
+                </div>
+            </div>
+
             <div class="row">
-                <div class="col-md-12">
-                    <div class="callout notification-dashboard hide">
-                        <h4></h4>
-                        <span></span>
+                <div class="col-xs-12">
+                    <div class="box">
+                        <div class="box-header">
+                            <h3 class="box-title">Subscriptions</h3>
+                        </div>
+                        <div class="box-body table-responsive no-padding">
+                            <table class="table table-hover">
+                                <thead>
+                                    <tr>
+                                        <th></th>
+                                        <th>ID</th>
+                                        <th>Topic</th>
+                                        <th>Widget</th>
+                                        <th>Widget JSON</th>
+                                        <th>Action topic</th>
+                                        <th>Active</th>
+                                    </tr>
+                                </thead>
+                                <tbody class="subscriptions-table">
+                                </tbody>
+                            </table>
+                        </div>
                     </div>
                 </div>
             </div>
@@ -128,16 +212,7 @@
         <!-- Settings content -->
         <section class="content hide" data-section="settings">
 
-            <div class="row">
-                <div class="col-md-12">
-                    <div class="callout notification-settings hide">
-                        <h4></h4>
-                        <span></span>
-                    </div>
-                </div>
-            </div>
-
-            <div class="row">
+            <div class="row settings-notification1">
                 <div class="col-md-12">
                     <div class="box box-primary">
                         <div class="box-header with-border">
@@ -148,38 +223,38 @@
                         <form id="mqttConfig">
                             <div class="box-body">
                                 <div class="form-group">
-                                    <label for="mqttClientId">Client ID</label>
-                                    <input type="text" class="form-control" id="mqttClientId" name="mqttClientId" placeholder="Client ID" />
-                                </div>
-                                <div class="form-group">
-                                    <label for="mqttHost">Host</label>
-                                    <input type="text" class="form-control" id="mqttHost" name="mqttHost" placeholder="Host" />
-                                </div>
-                                <div class="form-group">
-                                    <label for="mqttHost">Port</label>
-                                    <input type="text" class="form-control" id="mqttPort" name="mqttPort" placeholder="Port" />
-                                </div>
-                                <div class="form-group">
-                                    <label for="mqttUser">Username</label>
-                                    <input type="text" class="form-control" id="mqttUser" name="mqttUser" placeholder="Username" />
-                                </div>
-                                <div class="form-group">
-                                    <label for="mqttPass">Password</label>
-                                    <input type="text" class="form-control" id="mqttPass" name="mqttPass" placeholder="Password" />
-                                </div>
-                                <div class="checkbox">
-                                    <label for="mqttSecure">
-                                    <input type="checkbox" id="mqttSecure" name="mqttSecure" /> Secure
+                                    <label for="clientId">Client ID</label>
+                                    <input type="text" class="form-control" id="clientId" name="clientId" placeholder="Client ID" />
+                                </div>
+                                <div class="form-group">
+                                    <label for="host">Host</label>
+                                    <input type="text" class="form-control" id="host" name="host" placeholder="Host" />
+                                </div>
+                                <div class="form-group">
+                                    <label for="port">Port</label>
+                                    <input type="text" class="form-control" id="port" name="port" placeholder="Port" />
+                                </div>
+                                <div class="form-group">
+                                    <label for="username">Username</label>
+                                    <input type="text" class="form-control" id="username" name="username" placeholder="Username" />
+                                </div>
+                                <div class="form-group">
+                                    <label for="password">Password</label>
+                                    <input type="text" class="form-control" id="password" name="password" placeholder="Password" />
+                                </div>
+                                <div class="checkbox">
+                                    <label for="secure">
+                                    <input type="checkbox" id="secure" name="secure" /> Secure
                                 </label>
                                 </div>
                                 <div class="checkbox">
-                                    <label for="mqttDebug">
-                                    <input type="checkbox" id="mqttDebug" name="mqttDebug" /> Debug
+                                    <label for="debug">
+                                    <input type="checkbox" id="debug" name="debug" /> Debug
                                 </label>
                                 </div>
                                 <div class="checkbox">
-                                    <label for="mqttSimulateDevices">
-                                    <input type="checkbox" id="mqttSimulateDevices" name="mqttSimulateDevices" /> Simulate devices
+                                    <label for="simulateDevices">
+                                    <input type="checkbox" id="simulateDevices" name="simulateDevices" /> Simulate devices
                                 </label>
                                 </div>
                             </div>
@@ -193,7 +268,7 @@
                 </div>
             </div>
 
-            <div class="row">
+            <div class="row settings-notification2">
                 <div class="col-md-12">
                     <div class="box box-primary">
                         <div class="box-header with-border">
@@ -201,7 +276,7 @@
                         </div>
                         <!-- /.box-header -->
                         <!-- form start -->
-                        <form id="options">
+                        <form id="appConfig">
                             <div class="box-body">
                                 <div class="checkbox">
                                     <label for="pageContainer">
@@ -217,12 +292,38 @@
                             <!-- /.box-body -->
 
                             <div class="box-footer">
-                                <button type="submit" class="btn btn-primary" id="saveOptions">Save</button>
+                                <button type="submit" class="btn btn-primary" id="saveAppConfig">Save</button>
                             </div>
                         </form>
                     </div>
                 </div>
             </div>
+
+            <div class="row settings-notification3">
+                <div class="col-md-12">
+                    <div class="box box-primary">
+                        <div class="box-header with-border">
+                            <h3 class="box-title">Backup/Restore</h3>
+                        </div>
+                        <!-- /.box-header -->
+                        <!-- form start -->
+                        <form id="iotCCConfig">
+                            <div class="box-body">
+                                <div class="form-group">
+                                    <label for="iotccconfig">IoTCC Config</label>
+                                    <textarea class="form-control" id="iotccconfig" name="iotccconfig" placeholder="IoTCC Config" rows="10"></textarea>
+                                </div>
+                            </div>
+                            <!-- /.box-body -->
+
+                            <div class="box-footer">
+                                <button type="submit" class="btn btn-primary" id="saveIoTCCConfig">Save</button>
+                            </div>
+                        </form>
+                    </div>
+                </div>
+            </div>
+
         </section>
         <!-- /.content -->
 
@@ -285,10 +386,11 @@
 
 <script type="text/javascript" src="bower_components/jquery/dist/jquery.min.js"></script>
 <script type="text/javascript" src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
+<script type="text/javascript" src="bower_components/jquery-serialize-object/dist/jquery.serialize-object.min.js"></script>
 <!-- AdminLTE App -->
 <script type="text/javascript">
     var AdminLTEOptions = {
-        sidebarExpandOnHover: true
+        //sidebarExpandOnHover: true
     };
 </script>
 <script type="text/javascript" src="bower_components/AdminLTE/dist/js/app.min.js"></script>

comments