diff --git a/example.conf b/example.conf index ddb27e0..94232d0 100644 --- a/example.conf +++ b/example.conf @@ -9,6 +9,7 @@ username = password # Add users for Domoboard here. In this case login with username "username" and password "password" [[domoboard]] time = False # True/False: show time in top bar + date = False # True/False: show date in top bar google_maps_api_key = X # Google Maps Embed API key # Add Navbar items here. The key is the navbar link name. The first value is the URI name, second value can be any font awesome logo to be displayed. @@ -32,11 +33,11 @@ [[top_tiles]] Temperatuur tuin = 31, fire Temperatuur auto = 22, car - Stroomverbruik TV = 13, plug + Stroomverbruik TV = 13, plug, Usage Temperatuur Eindhoven = 54, fire Temperatuur tuin BMP = 55, fire - Totaal Playstation = 25, plug - Totaal slaapkamer lamp = 12, plug + Totaal Playstation = 25, plug, Usage + Totaal slaapkamer lamp = 12, plug, CounterToday Temperatuur raspberry = 1, car [[line_charts]] Temperatuur Slaapkamer = 14, month, temp diff --git a/modules/api.py b/modules/api.py index 969b8ab..08fc453 100644 --- a/modules/api.py +++ b/modules/api.py @@ -79,6 +79,8 @@ def gateway(): writeToConfig(idx, page, component, description, extra) elif custom == 'indexPlugins': result = json.dumps(indexPlugins(request.args)) + elif custom == "performUpgrade": + result = json.dumps(performUpgrade()) elif custom in apiDict: module = apiDict.get(custom)[0] function = apiDict.get(custom)[1] @@ -163,6 +165,10 @@ def getPluginVersion(loc): c += 1 return float(_version) +def performUpgrade(): + git.cmd.Git('.').pull("https://github.com/wez3/domoboard.git") + return "Upgrade completed." + def indexPlugins(params={}): tmpFolder = 'static/tmp' indexFolderPath = 'static/tmp/pluginsIndex/' diff --git a/server.py b/server.py index e5a28cb..f83da6e 100755 --- a/server.py +++ b/server.py @@ -25,9 +25,9 @@ def init(): def generatePage(): requestedRoute = str(request.url_rule)[1:] if configValueExists(requestedRoute): - blockValues = {} + blockValues = OrderedDict() blockArray = [] - configValues = {} + configValues = OrderedDict() configValues["navbar"] = config["navbar"]["menu"] configValues["server_location"] = config["general_settings"]["server"].get("url") configValues["flask_server_location"] = config["general_settings"]["server"].get("flask_url") @@ -45,7 +45,9 @@ def generatePage(): return render_template('index.html', configValues = configValues, blockArray = blockArray, - _csrf_token = session['_csrf_token']) + _csrf_token = session['_csrf_token'], + version = getVersion(), + debug = app.debug) else: abort(404) @@ -55,18 +57,19 @@ def index(): @login_required() def retrieveValue(page, component): - dict = {} + dict = OrderedDict() try: match = re.search("^(.+)\[(.+)\]$", component) if not match: for k, v in config[page][component].iteritems(): - v = strToList(v) - dict[k] = v + l = [None] + l.extend(strToList(v)) + dict[k] = l else: for sk, sv in config[page][match.group(1)][match.group(2)].iteritems(): - sv = strToList(sv) - sv.append(match.group(2)) - dict[sk] = sv + l = [match.group(2)] + l.extend(strToList(sv)) + dict[sk] = l except: dict = {} return dict @@ -109,7 +112,7 @@ def configValueExists(value): def validateConfigFormat(config): requiredSettings = {"general_settings/server": ["url", "flask_url", "user", "password", "secret_key"], - "general_settings/domoboard": ["time"], + "general_settings/domoboard": ["time", "date"], "navbar/menu": [None] } for sect, fields in requiredSettings.iteritems(): section = sect.split('/') @@ -128,6 +131,12 @@ def appendDefaultPages(config): config['log'] = {'display_components': {'components': 'serverlog'}} return config +def getVersion(): + f = open('VERSION.md', 'r') + version = f.read().rstrip() + f.close() + return version + if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument("-c", "--config", dest="configfile", @@ -166,6 +175,6 @@ if __name__ == '__main__': app.add_url_rule('/logout/', 'logout', logout_view, methods=['GET']) app.add_url_rule('/api', 'api', api.gateway, methods=['POST']) try: - app.run(host=flask_server_location.split(":")[0],port=int(flask_server_location.split(":")[1]),threaded=True, extra_files=watchfiles, debug=args.debug) + app.run(host=flask_server_location.split(":")[0],port=int(flask_server_location.split(":")[1]), threaded=True, extra_files=watchfiles, debug=args.debug) except socket.error, exc: - sys.exit("Error when starting the Flask server: %s" % exc) + sys.exit("Error when starting the Flask server: {}".format(exc)) diff --git a/static/css/bootstrap-slider.css b/static/css/bootstrap-slider.css index c53983d..d31b14b 100644 --- a/static/css/bootstrap-slider.css +++ b/static/css/bootstrap-slider.css @@ -152,9 +152,6 @@ } .slider-selection { position: absolute; - background-image: -webkit-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%); - background-image: -o-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%); - background-image: linear-gradient(to bottom, #f9f9f9 0%, #f5f5f5 100%); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9', endColorstr='#fff5f5f5', GradientType=0); -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); diff --git a/static/css/custom.css b/static/css/custom.css index 6db7cf9..913eb92 100755 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -39,7 +39,7 @@ body.nav-sm .main_container .top_nav { } body.nav-sm .nav.side-menu li a { - text-align: left !important; + text-align: center !important; font-weight: 400; font-size: 13px; padding: 10px 5px; @@ -6383,12 +6383,17 @@ ul.notifications { overflow: visible; } #time-part { - padding-top: 16px; - padding-bottom: 16px; + padding-top: 16px; + padding-bottom: 16px; } #date-part { - padding-top: 16px; - padding-bottom: 16px; + padding-top: 16px; + padding-bottom: 16px; +} +#version_div { + float: right; + margin-top:15px; + margin-right:10px; } .show_date { display: inline-block; @@ -6396,3 +6401,20 @@ ul.notifications { .hide_date { display: None; } +.show_update { + display: inline-block; +} +.hide_update { + display: None; +} + +.slider_on { + background-image: -webkit-linear-gradient(top, #f9f9f9 0%, green 100%); + background-image: -o-linear-gradient(top, #f9f9f9 0%, green 100%); + background-image: linear-gradient(to bottom, #f9f9f9 0%, green 100%); +} +.slider_off { + background-image: -webkit-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%); + background-image: -o-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%); + background-image: linear-gradient(to bottom, #f9f9f9 0%, #f5f5f5 100%); +} diff --git a/static/js/bootstrap-slider.js b/static/js/bootstrap-slider.js index f9f3fdd..6ce0596 100755 --- a/static/js/bootstrap-slider.js +++ b/static/js/bootstrap-slider.js @@ -410,8 +410,9 @@ sliderTrackLow.className = "slider-track-low"; sliderTrackSelection = document.createElement("div"); - sliderTrackSelection.className = "slider-selection"; - + //sliderTrackSelection.className = "slider-selection"; + sliderTrackSelection.id = this.options.id + "_track"; + sliderTrackSelection.className = "slider-selection slider_" + this.options.state sliderTrackHigh = document.createElement("div"); sliderTrackHigh.className = "slider-track-high"; @@ -766,7 +767,8 @@ scale: 'linear', focus: false, tooltip_position: null, - labelledby: null + labelledby: null, + state: 'off' }, getElement: function() { diff --git a/static/js/domoboard.js b/static/js/domoboard.js index 4c54582..4f987b6 100644 --- a/static/js/domoboard.js +++ b/static/js/domoboard.js @@ -21,6 +21,31 @@ function changeSwitch(checkboxElem, idx) { requestAPI(flask_server + "/api?type=command¶m=switchlight&idx=" + idx + "&switchcmd=Off" ); } } +// Dimmer functions +function changeDimmer(checkboxElem, idx) { + var chkurl = "/api?type=devices&rid=" + idx; + requestAPI(flask_server + chkurl, function(d) { + _json = JSON.parse(d); + if (_json['result'][0]['Data'] != 'Off') { + requestAPI(flask_server + "/api?type=command¶m=switchlight&idx=" + idx + "&switchcmd=Off&level=0"); + } else { + requestAPI(flask_server + "/api?type=command¶m=switchlight&idx=" + idx + "&switchcmd=On&level=0"); + } + setDimmerState(checkboxElem, idx); + }); +} + +function setDimmerState(id, idx) { + var url = "/api?type=devices&rid=" + idx; + requestAPI(flask_server + url, function(d) { + _json = JSON.parse(d); + if (_json['result'][0]['Data'] != 'Off') { + $('#' + id).css({'background-image': '-webkit-linear-gradient(top, #f9f9f9 0%, green 100%)', 'background-image': '-o-linear-gradient(top, #f9f9f9 0%, green 100%)', 'background-image': 'linear-gradient(to bottom, #f9f9f9 0%, green 100%)'}); + } else { + $('#' + id).css({'background-image': '-webkit-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%)', 'background-image': '-o-linear-gradient(top, #f9f9f9 0%, #f5f5f5 100%)', 'background-image': 'linear-gradient(to bottom, #f9f9f9 0%, #f5f5f5 100%)'}); + } + }); +} // Switch functions function changePush(idx, action) { @@ -57,7 +82,7 @@ function refreshSwitches(updateSwitches, block) { } // Top tiles functions -function refreshTopTiles(updateDivs, block, tilesPreviousArray) { +function refreshTopTiles(updateDivs, block, tilesPreviousArray, updateDivsTypeArray) { if (tilesPreviousArray.length == 0) { for(var i = 0; i < updateDivs.length; i++){ tilesPreviousArray.push(-1); @@ -69,7 +94,7 @@ function refreshTopTiles(updateDivs, block, tilesPreviousArray) { requestAPI(url, function(d) { var obj = JSON.parse(d); if (obj.result != undefined) { - var data = obj.result[0].Data; + var data = obj.result[0][updateDivsTypeArray[i]]; } else { var data = "-"; } @@ -137,9 +162,12 @@ function dimmerSlider(updateDimmers, block) { url = "/api?type=devices&rid=" + dimmerID; requestAPI(url, function(d) { var percentage = JSON.parse(d).result[0].Level; - $('#dimmer_' + dimmerID + "_block_" + block).slider({min:0, max:100, value: percentage}).on('slideStop', function(ev) { changeDimmerSlider($(this).attr('id'), ev.value) } ).data('slider'); - $('#dimmer_' + dimmerID + "_block_" + block).slider().on('slideStop', function(ev) { changeDimmerSlider($(this).attr('id'), ev.value) } ).data('slider'); - }); + $('#dimmer_' + dimmerID + "_block_" + block).slider({min:0, max:100, value: percentage}).on('slideStop', function(ev) { + setDimmerState('dim_' + dimmerID + "_block_" + block + "_track", dimmerID); + changeDimmerSlider($(this).attr('id'), ev.value) + } ).data('slider'); + setDimmerState('dim_' + dimmerID + "_block_" + block + "_track", dimmerID); + }); }); } @@ -169,10 +197,15 @@ function redrawLineChart(sensor, idx, range, block) { }); } -function redrawBarChart(idxs, block) { +function redrawBarChart(idxs, block, barChartElementsNames) { var url = "/api?custom=bar_chart&idxs=" + idxs.join(); + var i = 0; requestAPI(url, function(d){ var data = JSON.parse(d); + for (var key in data) { + data[key]["l"] = barChartElementsNames[i]; + i++; + } block.setData(data); }); } @@ -341,3 +374,53 @@ function changeDown(idx, block) { changeSetpoint(idx, newVal); }, 400); } + +// Update functions +function performUpgrade() { + requestAPI('/api?custom=performUpgrade'); + $( "#version_div" ).removeClass("show_update"); + $( "#version_div" ).addClass("hide_update"); + $( "#updateView_available" ).removeClass("show_update"); + $( "#updateView_available" ).addClass("hide_update"); + $( "#updateView_not_available" ).removeClass("hide_update"); + $( "#updateView_not_available" ).addClass("show_update"); +} + +function checkVersion() { + $.ajax({ + url: "https://domoboard.nl/version.md", + cache: false, + success: function( data ) { + dataFloat = parseFloat(data); + versionFloat = parseFloat(version); + if (dataFloat > versionFloat) { + document.getElementById('curver').innerHTML = version; + document.getElementById('newver').innerHTML = data; + $( "#version_div" ).removeClass("hide_update"); + $( "#version_div" ).addClass("show_update"); + } + }, + async:true + }); + } + +function checkVersionSettings() { + $.ajax({ + url: "https://domoboard.nl/version.md", + cache: false, + success: function( data ) { + dataFloat = parseFloat(data); + versionFloat = parseFloat(version); + if (dataFloat > versionFloat) { + $( "#updateView_available" ).removeClass("hide_update"); + $( "#updateView_available" ).addClass("show_update"); + document.getElementById('curver_settings').innerHTML = version; + document.getElementById('newver_settings').innerHTML = data; + } else { + $( "#updateView_not_available" ).removeClass("hide_update"); + $( "#updateView_not_available" ).addClass("show_update"); + } + }, + async:true + }); + } diff --git a/static/js/domoticz.js b/static/js/domoticz.js index b4f9cf1..160700b 100644 --- a/static/js/domoticz.js +++ b/static/js/domoticz.js @@ -602,7 +602,6 @@ if (period == "day") { var minValue = 10000000; $.each(data.result, function (i, item) { - console.log(item) datatable1.push([GetDateFromString(item.d), parseFloat(item.v_max)]); datatable2.push([GetDateFromString(item.d), parseFloat(item.v_min)]); if (typeof item.v_avg != 'undefined') { diff --git a/templates/area_charts.html b/templates/area_charts.html index 145d5dd..9db18d1 100644 --- a/templates/area_charts.html +++ b/templates/area_charts.html @@ -27,9 +27,9 @@ var area_chart_block_{{count}} = Morris.Area({ $(document).ready(function() { {% for k, v in blockArray[count]["area_charts"].iteritems() %} - redrawAreaChart("{{v[2]}}",{{v[0]}},"{{v[1]}}", area_chart_block_{{count}}); + redrawAreaChart("{{v[3]}}",{{v[1]}},"{{v[2]}}", area_chart_block_{{count}}); $("div#title_block_{{count}} h2").html("{{k}}"); - setInterval(redrawAreaChart,9000,"{{v[2]}}",{{v[0]}},"{{v[1]}}", area_chart_block_{{count}}); + setInterval(redrawAreaChart,9000,"{{v[3]}}",{{v[1]}},"{{v[2]}}", area_chart_block_{{count}}); }); {% endfor %} diff --git a/templates/bar_charts.html b/templates/bar_charts.html index 1b2da23..d3b90e5 100644 --- a/templates/bar_charts.html +++ b/templates/bar_charts.html @@ -15,22 +15,27 @@ diff --git a/templates/camera.html b/templates/camera.html index d0e63fb..693a5ad 100644 --- a/templates/camera.html +++ b/templates/camera.html @@ -11,12 +11,12 @@