Merge pull request #79 from wez3/develop

Develop to master
This commit is contained in:
Squandor 2017-01-22 00:59:52 +01:00 committed by GitHub
commit bf95d7b553
40 changed files with 2104 additions and 478 deletions

View File

@ -33,9 +33,11 @@ Just one config is used to configure Domoboard. A example can be found the appli
- top_tiles
- switches
- switch
- Selector Switch
- dimmer
- rgb
- setpoint
- setpoint_slider
- pushon
- pushoff
- group
@ -78,31 +80,31 @@ Check out the page https://github.com/wez3/domoboard-plugins for all plugins.
Here are some screenshots from Domoboard:
![alt tag](https://forsec.nl/wp-content/uploads/domoboard_images/domoboard_1_1.png)
![alt tag](https://domoboard.nl/domoboard_images/domoboard_1_1.png)
Above screenshot shows the components top_tiles, line_charts, switches and weather.
![alt tag](https://forsec.nl/wp-content/uploads/domoboard_images/domoboard_2_2_2_2.png)
![alt tag](https://domoboard.nl/domoboard_images/domoboard_2_2_2_2.png)
Above screenshot shows the mobile view of the Dashboard.
![alt tag](https://forsec.nl/wp-content/uploads/domoboard_images/domoboard_6_6_6_6.png)
![alt tag](https://domoboard.nl/domoboard_images/domoboard_6_6_6_6.png)
Above screenshot shows the Raspberry Pi 7" Touch screen view of the Dashboard.
![alt tag](https://forsec.nl/wp-content/uploads/domoboard_images/screen_domoticz.png)
![alt tag](https://domoboard.nl/domoboard_images/screen_domoticz.png)
Above the components domoticz_smart_charts, domoticz_counter_charts and domoticz_temp_charts.
![alt tag](https://forsec.nl/wp-content/uploads/domoboard_images/domoboard_3_3.png)
![alt tag](https://domoboard.nl/domoboard_images/domoboard_3_3.png)
Above screenshot shows the components bar_charts, donut_charts, switches and power_usage components.
![alt tag](https://forsec.nl/wp-content/uploads/domoboard_images/domoboard_4_4.png)
![alt tag](https://domoboard.nl/domoboard_images/domoboard_4_4.png)
Above screenshots shows the server log component
![alt tag](https://forsec.nl/wp-content/uploads/domoboard_images/domoboard_5_5.png)
![alt tag](https://domoboard.nl/domoboard_images/domoboard_5_5.png)
Above screenshots shows the settings page.

View File

@ -1 +1 @@
1.0.0
1.0.10

View File

@ -9,6 +9,8 @@
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
language = "gb" # Change this to display date/time in local language and format
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 +34,11 @@
[[top_tiles]]
Temperatuur tuin = 31, fire
Temperatuur auto = 22, car
Stroomverbruik TV = 13, plug
Stroomverbruik TV = 13, plug, Usage, Watt
Temperatuur Eindhoven = 54, fire
Temperatuur tuin BMP = 55, fire
Totaal Playstation = 25, plug
Totaal slaapkamer lamp = 12, plug
Totaal Playstation = 25, plug, Usage, Watt
Totaal slaapkamer lamp = 12, plug, CounterToday, kWh
Temperatuur raspberry = 1, car
[[line_charts]]
Temperatuur Slaapkamer = 14, month, temp
@ -52,6 +54,8 @@
Close Garage door = 567, pushoff
Scene Home = 4, scene
Group kitchen lights = 5, group
Thermostaat_slider = 71, setpoint_slider, 18, 28
Selector = 201, selector
[[power_usage]]
Totaal slaapkamer lamp = 12
Totaal playstation = 71
@ -130,7 +134,7 @@
[[[Frontdoor]]]
url = http://x.x.x.x:88/cgi-bin/CGIStream.cgi?cmd=GetMJStream&usr=xxx&pwd=xxx
[[[Backdoor]]]
url = http://x.x.x.x:88/cgi-bin/CGIStream.cgi?cmd=GetMJStream&usr=xxx&pwd=xxx
url = rtsp://x.x.x.x:88/cgi-bin/CGIStream.cgi?cmd=GetMJStream&usr=xxx&pwd=xxx
[server]
[[display_components]]

View File

@ -3,273 +3,72 @@
from flask import request
from flaskext.auth import login_required
import git
import security
import requests, json, re
import os, sys, imp, shutil
import json, os, sys
import security, charts, plugins, webconfig, domoticz
apiDict = {}
indexes = {}
modules = {}
def init():
global modules
modules = loadPlugins()
return 0
modules = plugins.loadPlugins()
return
def addToApi(custom, module, function):
apiDict[custom] = [module, function]
@login_required()
def gateway():
requestedUrl = request.url.split("/api")
custom = request.args.get('custom', '')
if custom == "bar_chart":
result = charts.barChart()
elif custom == "donut_chart":
result = charts.donutChart()
elif custom == "modify_config":
idx = request.args.get('idx', '')
page = request.args.get('page', '')
component = request.args.get('component', '')
description = request.args.get('description', '')
extra = request.args.get('extra', '')
webconfig.writeToConfig(idx, page, component, description, extra)
elif custom == 'indexPlugins':
result = json.dumps(plugins.indexPlugins(request.args))
elif custom == "performUpgrade":
result = json.dumps(webconfig.performUpgrade())
elif custom in apiDict:
module = apiDict.get(custom)[0]
function = apiDict.get(custom)[1]
call = getattr(modules[module], function)
result = call(request.args)
else:
result = domoticz.queryDomoticz(requestedUrl[1])
try:
if not isJson(result):
result = json.dumps(result)
return security.sanitizeJSON(json.loads(result))
except:
return "No results returned"
def setConfig(cfg, orig_cfg):
global config
global originalCfg
config = cfg
originalCfg = orig_cfg
def setModules(modulesList):
global modules
modules = modulesList
def getConfig():
global config
return config
def loadPlugins():
plugin = {}
plugin_dir = os.getcwd() + '/plugins/'
for i in os.listdir(plugin_dir):
if not i == '__init__.py' and i.endswith('.py'):
name = i.replace('.py', '')
try:
plugin[name] = imp.load_source(name, plugin_dir + i)
plugin[name].init()
except ImportError as msg:
sys.exit("Error occured during loading imports for the plugin {}: {}".format(name, msg))
return plugin
def getOriginalConfig():
return originalCfg
@login_required()
def gateway():
requestedUrl = request.url.split("/api")
custom = request.args.get('custom', '')
if custom == "bar_chart":
idxs = request.args.get('idxs', '')
idxArray = idxs.split(",")
resultArray = []
resultDict = {}
for i in idxArray:
qResults = queryDomoticz("?type=devices&rid=" + i)
jsonObj = json.loads(qResults)
resultDict["y"] = jsonObj["result"][0]["Name"]
resultDict["a"] = jsonObj["result"][0]["Data"]
resultArray.append(resultDict.copy())
result = json.dumps(resultArray)
elif custom == "donut_chart":
idxs = request.args.get('idxs', '')
idxArray = idxs.split(",")
resultArray = []
resultDict = {}
for i in idxArray:
qResults = queryDomoticz("?type=devices&rid=" + i)
jsonObj = json.loads(qResults)
resultDict["label"] = jsonObj["result"][0]["Name"]
resultDict["value"] = re.findall("\d+\.?\d+", jsonObj["result"][0]["Data"])
resultArray.append(resultDict.copy())
result = json.dumps(resultArray)
elif custom == "modify_config":
idx = request.args.get('idx', '')
page = request.args.get('page', '')
component = request.args.get('component', '')
description = request.args.get('description', '')
extra = request.args.get('extra', '')
writeToConfig(idx, page, component, description, extra)
elif custom == 'indexPlugins':
result = json.dumps(indexPlugins(request.args))
elif custom in apiDict:
module = apiDict.get(custom)[0]
function = apiDict.get(custom)[1]
call = getattr(modules[module], function)
result = call(request.args)
else:
result = queryDomoticz(requestedUrl[1])
try:
if not is_json(result):
result = json.dumps(result)
return security.sanitizeJSON(json.loads(result))
except:
return "No results returned"
def is_json(myjson):
def isJson(myjson):
try:
json_object = json.loads(str(myjson))
except ValueError, e:
return False
return True
def queryDomoticz(url):
try:
r = requests.get('http://' + config["general_settings"]["server"]["url"] + '/json.htm' + url,
auth=(config["general_settings"]["server"].get("user"), config["general_settings"]["server"].get("password")), timeout=5.00)
except:
return
return r.text
def writeToConfig(idx, page, component, description, extra):
section = dict(originalCfg[page][component])
section[description] = idx
originalCfg[page][component] = section
originalCfg.write()
def checkDomoticzStatus(config):
domoticzDevices = []
domoticzScenes = []
try:
result = json.loads(queryDomoticz("?type=devices&filter=all"))
resultScene = json.loads(queryDomoticz("?type=scenes&filter=all"))
except:
sys.exit("Domoticz is not reachable.")
for device in result["result"]:
domoticzDevices.append(device["idx"])
if 'result' in resultScene:
for device in resultScene["result"]:
domoticzScenes.append(device["idx"])
configuredDevicesInDomoticz(config, domoticzDevices, domoticzScenes)
def configuredDevicesInDomoticz(config, domoticzDevices, domoticzScenes):
for k, v in config.iteritems():
if isinstance(v, dict):
configuredDevicesInDomoticz(v, domoticzDevices, domoticzScenes)
else:
if isinstance(v, int):
if v not in domoticzDevices and v not in domoticzScenes:
sys.exit("Device and/or scene with IDX {} is not available in Domoticz".format(v))
elif isinstance(v, list):
if (v[0].isdigit()) and (v[0] not in domoticzDevices and v[0] not in domoticzScenes):
sys.exit("Device and/or scene with IDX {} is not available in Domoticz".format(v[0]))
def getPluginDict():
global indexes
return indexes
def setPluginDict(d):
global indexes
indexes = d
def getPluginVersion(loc):
f = open(loc, 'r').read().split('\n')
v = None
for l in f:
t = l.split('=')
if t[0] == '@version':
_tmp_v = t[1].split('.')
c = 1
_version = _tmp_v[0] + '.'
while(c < len(_tmp_v)):
_version += _tmp_v[c]
c += 1
return float(_version)
def indexPlugins(params={}):
tmpFolder = 'static/tmp'
indexFolderPath = 'static/tmp/pluginsIndex/'
docsFolderPath = 'static/docs/'
installedPlugins = []
staticFolder = ['css/', 'images/', 'fonts/', 'js/']
indexes = getPluginDict()
pluginParts = ['templates/', 'plugins/']
if 'action' in params:
if not params['action'] == 'getPlugins':
try:
if not int(params['folid']) in indexes:
return "No valid plugin id specified."
except:
return "Please specify integers only."
if 'action' in params:
if params['action'] == 'getPlugins':
folders = filter(lambda x: os.path.isdir(os.path.join(indexFolderPath, x)),
os.listdir(indexFolderPath))
for i in folders:
i = security.sanitizePathBasename(i)
if i != '.git':
fol = {}
fol['id'] = len(indexes)
fol['folder'] = i
fol['status'] = 'install'
for filename in os.listdir('plugins/'):
installedPlugins.append(filename)
for filename in os.listdir(indexFolderPath + i + '/plugins'):
if filename in installedPlugins:
installed_version = getPluginVersion(docsFolderPath + i + '_readme.md')
indexed_version = getPluginVersion(indexFolderPath + i + '/' + docsFolderPath + 'readme.md')
if indexed_version > installed_version:
fol['update'] = 'yes'
else:
fol['update'] = 'no'
fol['status'] = 'remove'
readme = open(indexFolderPath + i + '/' + docsFolderPath + 'readme.md', 'r').read().split('\n')
sumList = {}
for s in readme:
t = s.split('=')
if len(t) > 1:
fol[t[0].replace('@', '')] = t[1]
if not i in (f['folder'] for f in indexes.itervalues()):
indexes[len(indexes)] = fol
else:
for tmp in indexes.itervalues():
if i == tmp['folder']:
for k in fol:
if k != 'id':
indexes[tmp['id']][k] = fol[k]
setPluginDict(indexes)
return indexes
elif params['action'] == 'installPlugin':
if 'folid' in params:
if indexes[int(params['folid'])]['status'] == 'install':
src_path = indexFolderPath + indexes[int(params['folid'])]['folder'] + '/'
for part in pluginParts:
for filename in os.listdir(src_path + part):
shutil.copy(src_path + part + filename, part + filename)
for f in staticFolder:
if os.path.exists(src_path + 'static/' + f):
for filename in os.listdir(src_path + '/static/' + f):
shutil.copy(src_path + 'static/' + f + filename, 'static/' + f + filename)
for filename in os.listdir(src_path + '/' + docsFolderPath):
shutil.copy(src_path + '/' + docsFolderPath + filename, docsFolderPath + indexes[int(params['folid'])]['folder'] + '_' + filename)
indexes[int(params['folid'])]['status'] = 'remove'
global modules
modules = loadPlugins()
return indexes[int(params['folid'])]['folder'] + ' installed.'
else:
return "This plugin is already installed."
elif params['action'] == 'removePlugin':
if 'folid' in params:
if indexes[int(params['folid'])]['status'] == 'remove':
src_path = indexFolderPath + indexes[int(params['folid'])]['folder'] + '/'
for part in pluginParts:
for filename in os.listdir(src_path + part):
os.remove(part + filename)
for f in staticFolder:
if os.path.exists(src_path + 'static/' + f):
for filename in os.listdir(src_path + 'static/' + f):
os.remove('static/' + f + filename)
for filename in os.listdir(src_path + '/' + docsFolderPath):
shutil.copy(src_path + '/' + docsFolderPath + filename, docsFolderPath + indexes[int(params['folid'])]['folder'] + '_' + filename)
indexes[int(params['folid'])]['status'] = 'install'
return indexes[int(params['folid'])]['folder'] + ' removed.'
else:
return "This plugin was already removed."
setPluginDict(indexes)
else:
if not os.path.exists(tmpFolder):
os.makedirs(tmpFolder)
if not os.path.exists(indexFolderPath):
os.makedirs(indexFolderPath)
if not os.path.isfile(indexFolderPath + 'README.md'):
shutil.rmtree(indexFolderPath)
try:
git.Repo.clone_from("https://github.com/wez3/domoboard-plugins.git", indexFolderPath)
except:
print 'indexed'
else:
git.cmd.Git(indexFolderPath).pull("https://github.com/wez3/domoboard-plugins.git")
folders = filter(lambda x: os.path.isdir(os.path.join(indexFolderPath, x)),
os.listdir(indexFolderPath))
return indexPlugins({'action': 'getPlugins'})

33
modules/charts.py Normal file
View File

@ -0,0 +1,33 @@
#!/usr/bin/python
# Provides all charts functionality
import json, re, domoticz
from flask import request
def barChart():
idxs = request.args.get('idxs', '')
idxArray = idxs.split(",")
resultArray = []
resultDict = {}
for i in idxArray:
qResults = domoticz.queryDomoticz("?type=devices&rid=" + i)
jsonObj = json.loads(qResults)
resultDict["y"] = jsonObj["result"][0]["Name"]
resultDict["a"] = jsonObj["result"][0]["Data"]
resultArray.append(resultDict.copy())
result = json.dumps(resultArray)
return result
def donutChart():
idxs = request.args.get('idxs', '')
idxArray = idxs.split(",")
resultArray = []
resultDict = {}
for i in idxArray:
qResults = domoticz.queryDomoticz("?type=devices&rid=" + i)
jsonObj = json.loads(qResults)
resultDict["label"] = jsonObj["result"][0]["Name"]
resultDict["value"] = re.findall("\d+\.?\d+", jsonObj["result"][0]["Data"])
resultArray.append(resultDict.copy())
result = json.dumps(resultArray)
return result

41
modules/domoticz.py Normal file
View File

@ -0,0 +1,41 @@
#!/usr/bin/python
# This file contains all Domoticz related Python functions
import requests, json, sys
import api
def queryDomoticz(url):
config = api.getConfig()
try:
r = requests.get('http://' + config["general_settings"]["server"]["url"] + '/json.htm' + url,
auth=(config["general_settings"]["server"].get("user"), config["general_settings"]["server"].get("password")), timeout=5.00)
except:
return {}
return r.text
def checkDomoticzStatus(config):
domoticzDevices = []
domoticzScenes = []
try:
result = json.loads(queryDomoticz("?type=devices&filter=all"))
resultScene = json.loads(queryDomoticz("?type=scenes&filter=all"))
except:
sys.exit("Domoticz is not reachable.")
for device in result["result"]:
domoticzDevices.append(device["idx"])
if 'result' in resultScene:
for device in resultScene["result"]:
domoticzScenes.append(device["idx"])
configuredDevicesInDomoticz(config, domoticzDevices, domoticzScenes)
def configuredDevicesInDomoticz(config, domoticzDevices, domoticzScenes):
for k, v in config.iteritems():
if isinstance(v, dict):
configuredDevicesInDomoticz(v, domoticzDevices, domoticzScenes)
else:
if isinstance(v, int):
if v not in domoticzDevices and v not in domoticzScenes:
sys.exit("Device and/or scene with IDX {} is not available in Domoticz".format(v))
elif isinstance(v, list):
if (v[0].isdigit()) and (v[0] not in domoticzDevices and v[0] not in domoticzScenes):
sys.exit("Device and/or scene with IDX {} is not available in Domoticz".format(v[0]))

161
modules/plugins.py Normal file
View File

@ -0,0 +1,161 @@
#!/usr/bin/python
# This file contains the functions regarding the plugin manager.
import git, shutil, os, imp, sys
import security, api
import re
indexes = {}
def loadPlugins():
plugin = {}
plugin_dir = os.getcwd() + '/plugins/'
for i in os.listdir(plugin_dir):
if not i == '__init__.py' and i.endswith('.py'):
name = i.replace('.py', '')
try:
plugin[name] = imp.load_source(name, plugin_dir + i)
plugin[name].init()
except ImportError as msg:
moduleName = str(msg).split(' ')[len(str(msg).split(' ')) -1]
sys.exit("Error occured during loading imports for the plugin {}: {}. Install it with 'easy_install {}' or 'pip install {}'".format(name, msg, moduleName , moduleName))
return plugin
def getPluginDict():
global indexes
return indexes
def setPluginDict(d):
global indexes
indexes = d
def getPluginVersion(loc):
f = open(loc, 'r').read().split('@')
v = None
for l in f:
t = l.split('=')
if t[0].lower() == 'version':
_tmp_v = t[1].split('.')
c = 1
_version = _tmp_v[0] + '.'
while(c < len(_tmp_v)):
_version += _tmp_v[c]
c += 1
return float(_version)
def indexPlugins(params={}):
tmpFolder = 'plugins/index'
indexFolderPath = 'plugins/index/'
docsFolderPath = 'static/docs/'
installedPlugins = []
staticFolder = ['css/', 'images/', 'fonts/', 'js/']
indexes = getPluginDict()
pluginParts = ['templates/', 'plugins/']
if 'action' in params:
if not params['action'] == 'getPlugins':
try:
if not int(params['folid']) in indexes:
return "No valid plugin id specified."
except:
return "Please specify integers only."
if 'action' in params:
if params['action'] == 'getPlugins':
folders = filter(lambda x: os.path.isdir(os.path.join(indexFolderPath, x)),
os.listdir(indexFolderPath))
for i in folders:
i = security.sanitizePathBasename(i)
if i != '.git':
fol = {}
fol['id'] = len(indexes)
fol['folder'] = i
fol['status'] = 'install'
for filename in os.listdir('templates/'):
installedPlugins.append(filename)
for filename in os.listdir(indexFolderPath + i + '/templates'):
if filename in installedPlugins:
installed_version = getPluginVersion(docsFolderPath + i + '_readme.md')
indexed_version = getPluginVersion(indexFolderPath + i + '/' + docsFolderPath + 'readme.md')
if indexed_version > installed_version:
fol['update'] = 'yes'
else:
fol['update'] = 'no'
fol['status'] = 'remove'
readme = re.split('@', open(indexFolderPath + i + '/' + docsFolderPath + 'readme.md', 'r').read())#.split('@')
sumList = {}
for s in readme:
if re.search('\w+=', str(s)):
_check = re.search('\w+=', str(s)).group().replace('=', '')
_text = re.sub('\w+=', '', s)
if _check == 'summary' or _check == 'description':
_text = re.sub('\n', '<br>', _text)
fol[_check] = _text
if not i in (f['folder'] for f in indexes.itervalues()):
indexes[len(indexes)] = fol
else:
for tmp in indexes.itervalues():
if i == tmp['folder']:
for k in fol:
if k != 'id':
indexes[tmp['id']][k] = fol[k]
setPluginDict(indexes)
return indexes
elif params['action'] == 'installPlugin':
if 'folid' in params:
if indexes[int(params['folid'])]['status'] == 'install':
src_path = indexFolderPath + indexes[int(params['folid'])]['folder'] + '/'
for part in pluginParts:
for filename in os.listdir(src_path + part):
shutil.copy(src_path + part + filename, part + filename)
for f in staticFolder:
if os.path.exists(src_path + 'static/' + f):
for filename in os.listdir(src_path + '/static/' + f):
shutil.copy(src_path + 'static/' + f + filename, 'static/' + f + filename)
for filename in os.listdir(src_path + '/' + docsFolderPath):
shutil.copy(src_path + '/' + docsFolderPath + filename, docsFolderPath + indexes[int(params['folid'])]['folder'] + '_' + filename)
indexes[int(params['folid'])]['status'] = 'remove'
global modules
modules = loadPlugins()
api.setModules(modules)
return indexes[int(params['folid'])]['folder'] + ' installed.'
else:
return "This plugin is already installed."
elif params['action'] == 'removePlugin':
if 'folid' in params:
if indexes[int(params['folid'])]['status'] == 'remove':
src_path = indexFolderPath + indexes[int(params['folid'])]['folder'] + '/'
for part in pluginParts:
for filename in os.listdir(src_path + part):
os.remove(part + filename)
for f in staticFolder:
if os.path.exists(src_path + 'static/' + f):
for filename in os.listdir(src_path + 'static/' + f):
os.remove('static/' + f + filename)
for filename in os.listdir(src_path + '/' + docsFolderPath):
shutil.copy(src_path + '/' + docsFolderPath + filename, docsFolderPath + indexes[int(params['folid'])]['folder'] + '_' + filename)
indexes[int(params['folid'])]['status'] = 'install'
return indexes[int(params['folid'])]['folder'] + ' removed.'
else:
return "This plugin was already removed."
setPluginDict(indexes)
else:
if not os.path.exists(tmpFolder):
os.makedirs(tmpFolder)
if not os.path.exists(indexFolderPath):
os.makedirs(indexFolderPath)
if not os.path.isfile(indexFolderPath + 'README.md'):
shutil.rmtree(indexFolderPath)
try:
git.Repo.clone_from("https://github.com/wez3/domoboard-plugins.git", indexFolderPath)
except:
print 'indexed'
else:
git.cmd.Git(indexFolderPath).pull("https://github.com/wez3/domoboard-plugins.git")
folders = filter(lambda x: os.path.isdir(os.path.join(indexFolderPath, x)),
os.listdir(indexFolderPath))
return indexPlugins({'action': 'getPlugins'})

28
modules/webconfig.py Normal file
View File

@ -0,0 +1,28 @@
#!/usr/bin/python
# This file contains the functions used for web based configuration of domoboard
import git
import api
from flask import request
def writeToConfig(idx, page, component, description, extra):
originalCfg = api.getOriginalConfig()
section = dict(originalCfg[page][component])
section[description] = idx
originalCfg[page][component] = section
originalCfg.write()
def getVersion():
f = open('VERSION.md', 'r')
version = f.read().rstrip()
f.close()
return version
def performUpgrade():
git.cmd.Git('.').pull()
return "Upgrade completed."
def getCurrentBranch():
repo = git.Repo('.')
branch = repo.active_branch
return branch.name

View File

@ -6,7 +6,9 @@ from collections import OrderedDict
import argparse, socket, re
import hashlib, configobj, json, sys, os
import modules.api as api
import modules.domoticz as domoticz
import modules.security as security
import modules.webconfig as webconfig
app = Flask(__name__)
@ -25,9 +27,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 +47,10 @@ def generatePage():
return render_template('index.html',
configValues = configValues,
blockArray = blockArray,
_csrf_token = session['_csrf_token'])
_csrf_token = session['_csrf_token'],
version = webconfig.getVersion(),
branch = webconfig.getCurrentBranch(),
debug = app.debug)
else:
abort(404)
@ -55,18 +60,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
@ -86,7 +92,7 @@ def login_form():
if g.users[username].authenticate(request.form['password']):
security.generateCsrfToken()
return redirect(url_for('dashboard'))
return render_template('login.html')
return render_template('login.html', failed = "Login failed")
return render_template('login.html')
@app.errorhandler(404)
@ -109,7 +115,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('/')
@ -150,7 +156,7 @@ if __name__ == '__main__':
api.setConfig(config, unsanitizedConfig)
api.init()
validateConfigFormat(config)
api.checkDomoticzStatus(config)
domoticz.checkDomoticzStatus(config)
server_location = config["general_settings"]["server"]["url"]
flask_server_location = config["general_settings"]["server"]["flask_url"]
auth = Auth(app, login_url_name='login_form')
@ -166,6 +172,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))

View File

@ -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);

View File

@ -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;
@ -467,7 +467,7 @@ table.no-margin .progress {
@media(max-width:768px) {
.tile_stats_count .count {
font-size: 30px !important;
font-size: 5.5vw !important;
}
.tile_stats_count .right span {
font-size: 12px;
@ -1961,8 +1961,8 @@ span.right {
}
.tile_stats_count .count {
font-size: 40px;
line-height: 47px;
font-size: 2.5vw;
/* line-height: 47px;*/
font-weight: 600;
}
@ -2292,6 +2292,9 @@ button,
margin-bottom: 5px;
margin-right: 5px;
}
.modal-footer .btn+.btn {
margin-bottom: 5px;
}
.btn-group-vertical .btn,
.btn-group .btn {
@ -6383,12 +6386,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 +6404,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%);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -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() {

View File

@ -1,7 +1,5 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
* Original author of the bootstrap template is Colorlib.
*/
/** ****** left menu *********************** **/
@ -332,4 +330,4 @@ if (typeof NProgress != 'undefined') {
NProgress.done();
});
}
/** ****** NProgress *********************** **/
/** ****** NProgress *********************** **/

View File

@ -22,6 +22,47 @@ function changeSwitch(checkboxElem, idx) {
}
}
// switchSelector
function switchSelector(idx, lvl, bid) {
var old_bid = bid.replace(new RegExp(lvl + '$'), '');
url = '/api?type=devices&rid=' + idx;
requestAPI(flask_server + url, function(d) {
r = JSON.parse(d);
last_active = r['result'][0]['Level'];
if (last_active != 0) {
last_active = last_active + 0;
}
$('#' + old_bid + last_active).removeClass('btn-primary');
$('#' + bid).addClass('btn-primary');
requestAPI(flask_server + '/api?type=command&param=switchlight&idx=' + idx + '&switchcmd=Set%20Level&level=' + lvl + '&passcode=');
});
}
// 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&param=switchlight&idx=" + idx + "&switchcmd=Off&level=0");
} else {
requestAPI(flask_server + "/api?type=command&param=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) {
if (action == 'on') {
@ -57,7 +98,7 @@ function refreshSwitches(updateSwitches, block) {
}
// Top tiles functions
function refreshTopTiles(updateDivs, block, tilesPreviousArray) {
function refreshTopTiles(updateDivs, block, tilesPreviousArray, updateDivsTypeArray, updateDivsUnitsArray) {
if (tilesPreviousArray.length == 0) {
for(var i = 0; i < updateDivs.length; i++){
tilesPreviousArray.push(-1);
@ -69,32 +110,47 @@ 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]].toString();
} else {
var data = "-";
}
var re = /(-?\d+\.?\d*) (.+)/;
//var re = /(-?\d+\.?\d*) (.+)/; -- old regex didn't found an temp value
var re = /(-?\d+[\.*]?\d*)(\s*.*)/;
tilesArray = re.exec(data);
if (tilesArray != null) {
if (tilesArray[1] < tilesPreviousArray[i]) {
$("#" + block + divID).html(tilesArray[1] + "<font size='3'>" + tilesArray[2] + " <i class='fa fa-caret-down fa-lg' style='color:red'></font>");
if (updateDivsUnitsArray[i]) {
tilesArray[2] = updateDivsUnitsArray[i];
}
if (parseFloat(tilesArray[1]) < parseFloat(tilesPreviousArray[i])) {
$("#" + block + divID + "_" + updateDivsTypeArray[i]).html(tilesArray[1] + "<font size=2vw>" + tilesArray[2] + "</font>");
$("#" + block + divID + "_" + updateDivsTypeArray[i] + "_arrow").removeClass("green");
$("#" + block + divID + "_" + updateDivsTypeArray[i] + "_arrow").addClass("red");
$("#" + block + divID + "_" + updateDivsTypeArray[i] + "_arrow").removeClass("fa-caret-up");
$("#" + block + divID + "_" + updateDivsTypeArray[i] + "_arrow").addClass("fa-caret-down");
tilesPreviousArray[i] = tilesArray[1];
} else if (tilesArray[1] > tilesPreviousArray[i]) {
$("#" + block + divID).html(tilesArray[1] + "<font size='3'>" + tilesArray[2] + " <i class='fa fa-caret-up fa-lg' style='color:green'></font>");
} else if (parseFloat(tilesArray[1]) > parseFloat(tilesPreviousArray[i])) {
$("#" + block + divID + "_" + updateDivsTypeArray[i]).html(tilesArray[1] + "<font size=2vw>" + tilesArray[2] + "</font>");
$("#" + block + divID + "_" + updateDivsTypeArray[i] + "_arrow").removeClass("red");
$("#" + block + divID + "_" + updateDivsTypeArray[i] + "_arrow").addClass("green");
$("#" + block + divID + "_" + updateDivsTypeArray[i] + "_arrow").removeClass("fa-caret-down");
$("#" + block + divID + "_" + updateDivsTypeArray[i] + "_arrow").addClass("fa-caret-up");
tilesPreviousArray[i] = tilesArray[1];
}
} else {
$("#" + block + divID + "_" + updateDivsTypeArray[i]).html(tilesArray[1] + "<font size=2vw>" + tilesArray[2] + "</font>");
}
} else {
$("#" + block + divID).html(data);
$("#" + block + divID + "_" + updateDivsTypeArray[i]).html(data);
}
if(data == "On") {
$("#" + block + divID).removeClass("red");
$("#" + block + divID).addClass("green");
$("#" + block + divID + "_" + updateDivsTypeArray[i]).removeClass("red");
$("#" + block + divID + "_" + updateDivsTypeArray[i]).addClass("green");
} else if(data == "Off") {
$("#" + block + divID).removeClass("green");
$("#" + block + divID).addClass("red");
$("#" + block + divID + "_" + updateDivsTypeArray[i]).removeClass("green");
$("#" + block + divID + "_" + updateDivsTypeArray[i]).addClass("red");
} else {
$("#" + block + divID).removeClass("green");
$("#" + block + divID).removeClass("red");
$("#" + block + divID + "_" + updateDivsTypeArray[i]).removeClass("green");
$("#" + block + divID + "_" + updateDivsTypeArray[i]).removeClass("red");
}
});
i = i++;
@ -137,9 +193,25 @@ 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);
});
});
}
function setpointSlider(updateSetpoints, block) {
$.each(updateSetpoints, function(i, setpoint) {
url = "/api?type=devices&rid=" + setpoint[0];
requestAPI(url, function(d) {
var percentage = parseFloat(JSON.parse(d).result[0].Data);
$('#setpoint_slider' + setpoint[0] + "_block_" + block).slider({min:parseInt(setpoint[1]), max:parseInt(setpoint[2]), value: parseFloat(percentage)}).on('slideStop', function(ev) {
changeSetpoint(setpoint[0], parseFloat(ev.value));
} ).data('slider');
$('#stpnt_' + setpoint[0] + "_block_" + block + '_track').css({'background-image': '-webkit-linear-gradient(top, #f9f9f9 0%, red 100%)', 'background-image': '-o-linear-gradient(top, #f9f9f9 0%, red 100%)', 'background-image': 'linear-gradient(to bottom, #f9f9f9 0%, red 100%)'});
});
});
}
@ -169,10 +241,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);
});
}
@ -278,9 +355,6 @@ function modifyConfigButtonClicked(id) {
// Setpoint functions
function changeSetpoint(idx, val) {
if (val.split('.')[1] == '0'){
val = val.split('.')[0];
}
requestAPI(flask_server + "/api?type=command&param=setsetpoint&idx=" + idx + "&setpoint=" + val);
}
@ -341,3 +415,85 @@ 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(branch) {
$.ajax({
url: "https://domoboard.nl/version.md",
cache: false,
success: function( data ) {
if (branch == "master") {
dataFloat = data.split(",")[0];
} else {
dataFloat = data.split(",")[1];
}
var compare = versionCompare(dataFloat, version);
if (compare == 1) {
document.getElementById('curver').innerHTML = version;
document.getElementById('newver').innerHTML = dataFloat;
$( "#version_div" ).removeClass("hide_update");
$( "#version_div" ).addClass("show_update");
}
},
async:true
});
}
function checkVersionSettings(branch) {
$.ajax({
url: "https://domoboard.nl/version.md",
cache: false,
success: function( data ) {
if (branch == "master") {
dataFloat = data.split(",")[0];
} else {
dataFloat = data.split(",")[1];
}
var compare = versionCompare(dataFloat, version);
if (compare == 1) {
$( "#updateView_available" ).removeClass("hide_update");
$( "#updateView_available" ).addClass("show_update");
document.getElementById('curver_settings').innerHTML = version;
document.getElementById('newver_settings').innerHTML = dataFloat;
} else {
$( "#updateView_not_available" ).removeClass("hide_update");
$( "#updateView_not_available" ).addClass("show_update");
}
},
async:true
});
}
function versionCompare(a, b) {
if (a === b) {
return 0;
}
var a_components = a.split(".");
var b_components = b.split(".");
var len = Math.min(a_components.length, b_components.length);
for (var i = 0; i < len; i++) {
if (parseInt(a_components[i]) > parseInt(b_components[i])) {
return 1;
}
if (parseInt(a_components[i]) < parseInt(b_components[i])) {
return -1;
}
}
if (a_components.length > b_components.length) {
return 1;
}
if (a_components.length < b_components.length) {
return -1;
}
return 0;
}

View File

@ -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') {

1216
static/js/moment-with-locales.min.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +0,0 @@
// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
require('../../js/transition.js')
require('../../js/alert.js')
require('../../js/button.js')
require('../../js/carousel.js')
require('../../js/collapse.js')
require('../../js/dropdown.js')
require('../../js/modal.js')
require('../../js/tooltip.js')
require('../../js/popover.js')
require('../../js/scrollspy.js')
require('../../js/tab.js')
require('../../js/affix.js')

View File

@ -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 %}
</script>

View File

@ -15,22 +15,27 @@
</div>
<script type="text/javascript" charset="utf-8">
var bar_chart_block_{{count}} = Morris.Bar({
element: 'morris-bar-chart-{{count}}',
data: [],
xkey: 'y',
ykeys: ['a'],
labels: ['y'],
smooth: true,
resize: true
});
$(document).ready(function() {
var barChartElements=[];
var barChartElementsNames=[];
{% for k, v in blockArray[count]["bar_charts"].iteritems() %}
barChartElements.push("{{v[0]}}");
barChartElements.push("{{v[1]}}");
barChartElementsNames.push("{{k}}");
{% endfor %}
redrawBarChart(barChartElements, bar_chart_block_{{count}});
setInterval(redrawBarChart,9000,barChartElements,bar_chart_block_{{count}});
var bar_chart_block_{{count}} = Morris.Bar({
element: 'morris-bar-chart-{{count}}',
data: [],
xkey: 'l',
ykeys: ['a'],
labels: ['y'],
smooth: true,
resize: true
});
redrawBarChart(barChartElements, bar_chart_block_{{count}}, barChartElementsNames);
setInterval(redrawBarChart,9000,barChartElements,bar_chart_block_{{count}}, barChartElementsNames);
});
</script>

View File

@ -11,15 +11,23 @@
<div style=";overflow: hidden">
<br>
{% for k, v in blockArray[count]["camera"].iteritems() %}
{% if v[1] %}
<script> $('#s_title_{{ count }}').html("{{ v[1] }}");</script>
{% if v[0] %}
<script> $('#s_title_{{ count }}').html("{{ v[0] }}");</script>
{% endif %}
<form class="form-horizontal form-label-left" style="width: 80%; height: 80%; ">
<div class="form-group" style="">
<img id="cam_{{ count }}" style="-webkit-user-select: none; width: 100%; height: 100%; " src="{{v[0]|replace('&amp;', '&')}}" >
<div id="cam_body_{{ count }}" class="form-group" style="">
</div>
</form>
{% endfor %}
</div>
</div>
</div>
<script>
{% for k, v in blockArray[count]["camera"].iteritems() %}
if ("{{v[1]}}".split(':')[0] == 'rtsp') {
$('#cam_body_{{ count }}').append('<object classid="clsid:9BE31822-FDAD-461B-AD51-BE1D1C159921" codebase="http://download.videolan.org/pub/videolan/vlc/last/win32/axvlc.cab" id="vlc" name="vlc" class="vlcPlayer" events="True"> <param name="Src" value="{{v[1]}}" /> <!-- ie --> <param name="ShowDisplay" value="True" /> <param name="AutoLoop" value="True" /> <param name="AutoPlay" value="True" /> <!-- win chrome and firefox--> <embed id="vlcEmb" type="application/x-google-vlc-plugin" version="VideoLAN.VLCPlugin.2" autoplay="yes" loop="no" width="640" height="480" target="{{v[1]}}" ></embed></object>');
} else {
$('#cam_body_{{ count}}').append('<img id="cam_{{ count }}" style="-webkit-user-select: none; width: 100%; height: 100%; " src="{{v[1]|replace('&amp;', '&')}}" >');
}
{% endfor %}
</script>

View File

@ -17,9 +17,9 @@
$(document).ready(function() {
{% for k, v in blockArray[count]["domoticz_counter_charts"].iteritems() %}
ShowGeneralGraph("domoticz-chart-block-{{count}}",{{v[0]}},"{{k}}", 1, "{{v[2]}}", "{{v[1]}}");
ShowGeneralGraph("domoticz-chart-block-{{count}}",{{v[1]}},"{{k}}", 1, "{{v[3]}}", "{{v[2]}}");
$("div#title_block_{{count}} h2").html("{{k}}");
setInterval(ShowGeneralGraph,60000,"domoticz-chart-block-{{count}}",{{v[0]}},"{{k}}", 1, "{{v[2]}}", "{{v[1]}}");
setInterval(ShowGeneralGraph,60000,"domoticz-chart-block-{{count}}",{{v[1]}},"{{k}}", 1, "{{v[3]}}", "{{v[2]}}");
{% endfor %}
});
</script>

View File

@ -17,9 +17,9 @@
$(document).ready(function() {
{% for k, v in blockArray[count]["domoticz_percentage_charts"].iteritems() %}
ShowPercentageLog("domoticz-chart-block-{{count}}",{{v[0]}},"{{k}}", "{{v[1]}}");
ShowPercentageLog("domoticz-chart-block-{{count}}",{{v[1]}},"{{k}}", "{{v[2]}}");
$("div#title_block_{{count}} h2").html("{{k}}");
setInterval(ShowPercentageLog,60000,"domoticz-chart-block-{{count}}",{{v[0]}},"{{k}}", "{{v[1]}}");
setInterval(ShowPercentageLog,60000,"domoticz-chart-block-{{count}}",{{v[1]}},"{{k}}", "{{v[2]}}");
{% endfor %}
});
</script>

View File

@ -17,9 +17,9 @@
$(document).ready(function() {
{% for k, v in blockArray[count]["domoticz_smart_charts"].iteritems() %}
ShowSmartLog("domoticz-chart-block-{{count}}",{{v[0]}},"{{k}}", "{{v[2]}}", "{{v[1]}}");
ShowSmartLog("domoticz-chart-block-{{count}}",{{v[1]}},"{{k}}", "{{v[3]}}", "{{v[2]}}");
$("div#title_block_{{count}} h2").html("{{k}}");
setInterval(ShowSmartLog,60000,"domoticz-chart-block-{{count}}",{{v[0]}},"{{k}}", "{{v[2]}}", "{{v[1]}}");
setInterval(ShowSmartLog,60000,"domoticz-chart-block-{{count}}",{{v[1]}},"{{k}}", "{{v[3]}}", "{{v[2]}}");
{% endfor %}
});
</script>

View File

@ -17,9 +17,9 @@
$(document).ready(function() {
{% for k, v in blockArray[count]["domoticz_temp_charts"].iteritems() %}
ShowTempLog("domoticz-chart-block-{{count}}",{{v[0]}},"{{k}}", "{{v[1]}}");
ShowTempLog("domoticz-chart-block-{{count}}",{{v[1]}},"{{k}}", "{{v[2]}}");
$("div#title_block_{{count}} h2").html("{{k}}");
setInterval(ShowGeneralGraph,60000,"domoticz-chart-block-{{count}}",{{v[0]}},"{{k}}", "{{v[1]}}");
setInterval(ShowGeneralGraph,60000,"domoticz-chart-block-{{count}}",{{v[1]}},"{{k}}", "{{v[2]}}");
{% endfor %}
});
</script>

View File

@ -22,7 +22,7 @@ var donut_chart_block_{{count}} = Morris.Donut({
$(document).ready(function() {
var donutChartElements=[];
{% for k, v in blockArray[count]["donut_charts"].iteritems() %}
donutChartElements.push("{{v[0]}}");
donutChartElements.push("{{v[1]}}");
{% endfor %}
redrawDonutChart(donutChartElements, donut_chart_block_{{count}});
setInterval(redrawDonutChart,9000,donutChartElements, donut_chart_block_{{count}});

View File

@ -9,18 +9,23 @@
<!-- Domoboard -->
<script src="/static/js/custom.js"></script>
<!-- bootstrap-slider -->
<link href="/static/css/bootstrap-slider.css" rel="stylesheet">
<script type="text/javascript" src="/static/js/bootstrap-slider.js"></script>
<script type="text/javascript" src="static/js/moment.min.js"></script>
<script type="text/javascript" src="/static/js/moment-with-locales.min.js"></script>
{% if configValues["domoboard"].get("time") == "True" %}
<script>
$(document).ready(function() {
var interval = setInterval(function() {
var momentNow = moment();
$('#date-part').html(momentNow.format('DD MMMM YYYY'));
$('#time-part').html(momentNow.format('HH:mm'));
$('#date-part').html(momentNow.locale(local_language).format('dddd D MMMM YYYY'));
$('#time-part').html(momentNow.format('HH:mm'));
}, 100);
{% if configValues["domoboard"].get("date") == "True" %}
$('#date-part').removeClass('hide_date');
$('#date-part').addClass('show_date');
{% endif %}
$( "#date-part" ).click(function() {
$('#date-part').removeClass('show_date');
@ -36,7 +41,23 @@
}
});
});
</script>
{% endif %}
<script>
$(document).ready(function() {
setInterval(checkVersion, 43200000, branch);
});
</script>
<script>
var a=document.querySelectorAll("a[href^='/']");
for(var i=0;i<a.length;i++)
{
a[i].onclick=function()
{
window.location=this.getAttribute("href");
return false
}
}
</script>
</body>
</html>

View File

@ -1,16 +1,2 @@
<!-- footer content -->
<div id="custom_notifications" class="custom-notifications dsp_none">
<ul class="list-unstyled notifications clearfix" data-tabbed_notifications="notif-group">
</ul>
<div class="clearfix"></div>
<div id="notif-group" class="tabbed_notifications"></div>
</div>
<!-- /footer content -->
<!-- Domoboard -->
<script src="/static/js/custom.js"></script>
<!-- bootstrap-slider -->
<link href="/static/css/bootstrap-slider.css" rel="stylesheet">
<script type="text/javascript" src="/static/js/bootstrap-slider.js"></script>
<script type="text/javascript" src="static/js/moment.min.js"></script>
</body>
</html>

View File

@ -32,7 +32,7 @@
<link href="/static/images/icons/logo-114x114.png" sizes="114x114" rel="apple-touch-icon-precomposed">
<!-- iPhone non-retina icon (iOS < 7) -->
<link href="/static/images/icons/logo-57x57.png" sizes="57x57" rel="apple-touch-icon-precomposed">
<title>Domoboard</title>
<!-- Bootstrap core CSS -->
<script src="/static/js/jquery-2.2.3.min.js"></script>
@ -43,6 +43,7 @@
<!-- Custom styling plus plugins -->
<script src="/static/js/jquery.nicescroll.min.js"></script>
<script src="/static/js/bootstrap-switch.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
<script src="/static/js/colorpicker/bootstrap-colorpicker.min.js"></script>
@ -61,6 +62,9 @@
var flask_server = "{{ request.url_root[:-1] }}";
var csrf_token = "{{ _csrf_token }}";
var googleMapEmbedKey = "{{ configValues["domoboard"].get("google_maps_api_key") }}"
var local_language = "{{ configValues["domoboard"].get("language") }}"
var version = "{{ version }}";
var branch = "{{ branch }}";
</script>
<script type="text/javascript" src="/static/js/domoboard.js"></script>

View File

@ -27,9 +27,9 @@ var line_chart_block_{{count}} = Morris.Line({
$(document).ready(function() {
{% for k, v in blockArray[count]["line_charts"].iteritems() %}
redrawLineChart("{{v[2]}}",{{v[0]}},"{{v[1]}}", line_chart_block_{{count}});
redrawLineChart("{{v[3]}}",{{v[1]}},"{{v[2]}}", line_chart_block_{{count}});
$("div#title_block_{{count}} h2").html("{{k}}");
setInterval(redrawLineChart,9000,"{{v[2]}}",{{v[0]}},"{{v[1]}}",line_chart_block_{{count}});
setInterval(redrawLineChart,9000,"{{v[3]}}",{{v[1]}},"{{v[2]}}",line_chart_block_{{count}});
});
{% endfor %}
</script>

View File

@ -23,7 +23,7 @@
<div class="panel-heading"> <strong class="">Login</strong>
</div>
<div class="panel-body">
<form class="form-horizontal" role="form" action="/login/" method="post">
<form class="form-horizontal" role="form" action="/login/" method="post" autocomplete="on">
<div class="form-group">
<div class="form-group input-group">
<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
@ -36,6 +36,11 @@
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
{% if failed %}
<div>
<font color="red">{{failed}}</font>
</div>
{% endif %}
<div class="checkbox">
<label class="">
<input type="checkbox" class="">Remember me</label>

View File

@ -21,10 +21,10 @@
$(document).ready(function() {
var location=[];
{% for k, v in blockArray[count]["map"].iteritems() %}
{% if v[1] %}
$('#s_title_{{ count }}').html("{{ v[1] }}");
{% if v[0] %}
$('#s_title_{{ count }}').html("{{ v[0] }}");
{% endif %}
location.push("{{v[0]}}");
location.push("{{v[1]}}");
{% endfor %}
refreshMapLocation(location, "locationIframe-{{count}}");
setInterval(refreshMapLocation, 60000, location, "locationIframe-{{count}}");

View File

@ -61,8 +61,13 @@
<div class="nav toggle navbar-collapse" id="defaultNavbar1">
<a id="menu_toggle"><i class="fa fa-bars"></i></a>
</div>
<div class="show_date" style="cursor: pointer; margin-left: -70px; min-height: 51px;" id="time-part"></div>
<div class="show_date" style="cursor: pointer; float: right; margin-left: -70px; margin-right: 20px; min-height: 51px;" id="time-part"></div>
<div class="hide_date" style="cursor: pointer; padding-left: 2px;" id="date-part"></div>
<div id="version_div" class="hide_update">
<button type="button" class="btn btn-success" data-toggle="modal" data-target="#upgradeModal">
Update available
</button>
</div>
</div>
</nav>
</div>
@ -70,5 +75,36 @@
</div>
<!-- /top navigation -->
<!-- Upgrade Modal -->
<div class="modal fade" id="upgradeModal" tabindex="-1" role="dialog" aria-labelledby="upgradeModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="upgradeModalLabel">Update available</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
</button>
</div>
<div class="modal-body">
<h2>A new update is available for Domoboard.</h2><br />
The current version is <b><span id="curver"></span></b>.<br />
The new version available is: <b><span id="newver"></span></b>.<br />
<br />
{% if debug == True %}
<p><b>Install the new version by pressing the "Upgrade" button below.</b></p>
{% endif %}
{% if debug == False %}
<p><b>Upgrading through Domoboard is only possible when running in debug mode (pass "-d" parameter to server.py). Manual upgrade is possible by performing a "git pull" command.</b></p>
{% endif %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
{% if debug == True %}
<button type="button" class="btn btn-primary" data-dismiss="modal" onclick="javascript:performUpgrade()">Upgrade</button>
{% endif %}
</div>
</div>
</div>
</div>
<!-- page content -->
<div class="right_col" role="main">

View File

@ -3,7 +3,7 @@
<div class="col-md-6 col-sm-6 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>News</h2>
<h2 id="s_title_{{count}}">News</h2>
<ul class="nav navbar-right panel_toolbox">
<li><a class="close-link"><i class="fa fa-close"></i></a>
</li>
@ -12,8 +12,15 @@
</div>
<div id="divRss-{{count}}"></div>
<script>
$(document).ready(function() {
{% for k, v in blockArray[count]["news"].iteritems() %}
{% if v[0] %}
$('#s_title_{{ count }}').html("{{ v[0] }}");
{% endif %}
{% endfor %}
});
$('#divRss-{{count}}').FeedEk({
FeedUrl:'{{blockArray[count]['news'].get('rssfeed')[0]}}',
FeedUrl:"{{blockArray[count]['news'].get('rssfeed')[1]}}",
MaxCount : 5,
ShowDesc : true,
ShowPubDate:true,

View File

@ -22,7 +22,7 @@
{% for k, v in blockArray[count]["power_usage"].iteritems() %}
<tr>
<td>{{k}}</td>
<td id="power_usage_{{v[0]}}_{{count}}">{{v[1]}}</td>
<td id="power_usage_{{v[1]}}_{{count}}">{{v[2]}}</td>
</tr>
{% endfor %}
<tr>
@ -39,7 +39,7 @@
$(document).ready(function() {
var updatePowerUsage_{{count}}=[];
{% for k, v in blockArray[count]["power_usage"].iteritems() %}
updatePowerUsage_{{count}}.push("{{v[0]}}");
updatePowerUsage_{{count}}.push("{{v[1]}}");
{% endfor %}
refreshPowerUsage(updatePowerUsage_{{count}}, "{{count}}");
setInterval(refreshPowerUsage, 9000, updatePowerUsage_{{count}}, "{{count}}");

View File

@ -1,5 +1,8 @@
<link href="static/css/settings.css" rel="stylesheet" type="text/css"/>
<ul class="tab">
<li><a href="javascript:void(0)" id="defaultOpen" class="tablinks"
onclick="openCat(event, 'updates')">Updates</a>
</li>
<li><a href="javascript:void(0)" id="defaultOpen" class="tablinks"
onclick="openCat(event, 'plugins')">Plugins</a>
</li>
@ -7,7 +10,27 @@
onclick="openCat(event, 'settings')">Settings</a>
</li>
</ul>
<div id="updates" class="tabcontent">
<div id="updateView_available" class="hide_update">
<h2>A new update is available for Domoboard.</h2><br />
The current version is <b><span id="curver_settings"></span></b><br />
The new version available is: <b><span id="newver_settings"></span></b><br />
<br />
{% if debug == True %}
<p><b>Install the new version by pressing the "Upgrade" button below.</b></p>
{% endif %}
{% if debug == False %}
<p><b>Upgrading through Domoboard is only possible when running in debug mode (pass "-d" parameter to server.py). Manual upgrade is possible by performing a "git pull" command.</b></p>
{% endif %}
{% if debug == True %}
<button type="button" class="btn btn-primary" data-dismiss="modal" onclick="javascript:performUpgrade()">Upgrade</button>
{% endif %}
</div>
<div id="updateView_not_available" class="hide_update">
<h2>Hurray!</h2><br />
There is no update available for Domoboard.<br /><br />
</div>
</div>
<div id="plugins" class="tabcontent">
<div id="pluginView">
</div>
@ -29,7 +52,7 @@
<div class="dropdown">
<select id="dropDownPage">
{% for k, v in configValues["navbar"].iteritems() %}
<option>{{ v }}</option>
<option>{{ v[0] }}</option>
{% endfor %}
</select>
(Select a page to add the domoticz device to)
@ -53,6 +76,27 @@
<i>This page requires further development. Please use the config file for advanced changes to the dashboard.</i>
<p id="showdevices"></p>
</div>
</div>
<!-- Install Plugin Modal -->
<div style="min-height: 100px;" class="modal fade" id="pluginModal" tabindex="-1" role="dialog" aria-labelledby="pluginModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title" id="pluginModalLabel">Install Plugin</h2>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
</button>
</div>
<div id="plugin_body" class="modal-body">
<p id='plug_desc'></p>
<p id='plug_sum'></p>
<p id="plug_info"></p>
</div>
<div id="plugModalFooter" class="modal-footer">
</div>
</div>
</div>
</div>
<script>
@ -86,42 +130,36 @@
buttons = buttons + "<button onclick='updatePlugin("+ result[i].id + ")' type='button' class='btn updateBtn'>update";
}
buttons = buttons + "<button onclick='" + result[i].status + "Plugin(" + result[i].id + ")' name='"+ result[i].title + "' fol='" + result[i].folder + "' type='button' class='btn " + result[i].status + "Btn'>" + result[i].status + "</button>";
$('#pluginView').append("<div class='pluginItem'><span onclick=getSummary('" + result[i].title + "_summary')>" + result[i].title + " - Author: " + result[i].author + " - version: " + result[i].version + "</span>"+ buttons + "<div id='" + result[i].title + "_summary' class='fullSummary'><span>" + result[i].description + "</span></div></div>");
if (("structure" in result[i]) == true) {
$('#' + result[i].title + "_summary").append('<div>');
$('#' + result[i].title + "_summary").append('<ul>');
for (k in result[i].structure[result[i].folder]) {
for (l in result[i].structure[result[i].folder][k]) {
$('#' + result[i].title + "_summary").append('<li>' + k + '/' + l + '</li>');
}
}
$('#' + result[i].title + "_summary").append('</ul>');
$('#' + result[i].title + "_summary").append('</div>');
}
$('#pluginView').append("<div class='pluginItem'><span id='" + result[i].title +"_summary' onclick=setPluginInfo('" + result[i].id + "') >v" + result[i].version + " - " + result[i].title + " </span>"+ buttons + "</div>");
}
$('.fullSummary').hide();
}
function installPlugin(plugin_id) {
$('#plugin_body').addClass("loading");
var url = "/api?custom=indexPlugins&action=installPlugin&folid=" + plugin_id;
requestAPI(url, function(d){
automaticIndex();
$('#pluginModal').modal('hide');
});
}
function removePlugin(plugin_id) {
$('#plugin_body').addClass("loading");
var url = "/api?custom=indexPlugins&action=removePlugin&folid=" + plugin_id;
requestAPI(url, function(d){
automaticIndex();
$('#pluginModal').modal('hide');
});
}
function updatePlugin(plugin_id) {
function updatePlugin(plugin_id, ob) {
$('#plugin_body').addClass("loading");
var url = "/api?custom=indexPlugins&action=removePlugin&folid=" + plugin_id;
requestAPI(url, function(d) {
var url = "/api?custom=indexPlugins&action=installPlugin&folid=" + plugin_id;
requestAPI(url, function(dd) {
automaticIndex();
$('#pluginModal').modal('hide');
});
});
}
@ -133,22 +171,39 @@
});
}
function getSummary(div_id) {
$('.fullSummary').hide();
$('#' + div_id).show();
function clearModal() {
$('#plug_info').empty();
$('#pluginModalLabel').empty();
$('#plug_desc').empty();
$('#plug_sum').empty();
$('#plugModalFooter').empty();
$('#plugModalFooter').append('<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>');
}
function setPluginInfo(id) {
var url = "/api?custom=indexPlugins";
$('#plugin_body').addClass("loading");
$('#pluginModal').modal('show');
clearModal();
requestAPI(url, function(d){
var res = JSON.parse(d);
$('#pluginModalLabel').html('<b>' + res[id].title + '</b> <span style="float: right;">v' + res[id].version + '</b>');
$('#plug_info').html('<b>Author: ' + res[id].author + '</b>');
$('#plug_desc').html('<h4><b>Description</b></h4>' + res[id].description);
$('#plug_sum').html('<h4><b>Summary</b></h4>' + res[id].summary);
if (res[id].update == 'yes') {
$('#plugModalFooter').append("<button onclick='updatePlugin("+ res[id].id + ")' type='button' class='btn updateBtn'>update");
}
$('#plugModalFooter').append("<button onclick='" + res[id].status + "Plugin(" + res[id].id + ", this)' name='"+ res[id].title + "' fol='" + res[id].folder + "' type='button' class='btn " + res[id].status + "Btn'>" + res[id].status + "</button>");
$('#plugin_body').removeClass("loading");
});
}
$('.pluginItem span').on('click', function() {
console.log('Clicked on Item');
console.log($(this));
});
$(document).ready(function () {
// Get the element with id="defaultOpen" and click on it
document.getElementById("defaultOpen").click();
setInterval(automaticIndex(), 9000);
$('.fullSummary').hide();
checkVersionSettings(branch);
});
retrieveAvailableDevices();
selected_page_settings();
selected_component_settings();

View File

@ -1,4 +1,5 @@
<link href="/static/css/bootstrap-switch.css" rel="stylesheet" type="text/css" />
<link href="/static/css/bootstrap-slider.css" rel="stylesheet">
<link href="/static/css/buttons.css" rel="stylesheet" type="text/css" />
<div class="col-md-6 col-sm-6 col-xs-12">
<div class="x_panel">
@ -16,34 +17,44 @@
<table class="table" style="width: auto;">
{% for k, v in blockArray[count]["switches"].iteritems() %}
<tr>
{% if "dimmer" in v[2] or "rgb" in v[2] %}
<td style="border-top: none; vertical-align: middle;"><a id="Adim_{{v[1]}}_block_{{count}}" style="cursor: pointer;"><label style="cursor: pointer;" class=""> &nbsp;{{k}}</label></a></td>
{% else %}
<td style="border-top: none; vertical-align: middle;"><label class=""> &nbsp;{{k}}</label></td>
{% endif %}
<td style="border-top: none;">
{% if "switch" in v[1] %}
<input id="switch_{{v[0]}}_block_{{count}}" type="checkbox" checked data-size="mini">
{% elif "dimmer" in v[1] %}
<input id="dimmer_{{v[0]}}_block_{{count}}" data-slider-id='dimmer_{{v[0]}}' type="text" test={{ v[1] }} data-slider-min="0" data-slider-max="100" data-slider-step="1" data-slider-value="14" />
{% elif "pushon" in v[1] %}
<button id="push_{{v[0]}}_block_{{count}}" class="btn btn-primary btn-circle">&nbsp;<li class="fa fa-power-off" aria-hidden="true"></i>&nbsp;</button>
{% elif "pushoff" in v[1] %}
<button id="push_{{v[0]}}_block_{{count}}" class="btn btn-danger btn-circle">&nbsp;<li class="fa fa-power-off" aria-hidden="true"></i>&nbsp;</button>
{% elif "group" in v[1] %}
<div><div style="float: left"><button id="groupon_{{v[0]}}_block_{{count}}" class="btn btn-primary btn-circle">&nbsp;<li class="fa fa-power-off" aria-hidden="true"></i>&nbsp;</button></div><div style="padding-left: 20px; float: left"><button id="groupoff_{{v[0]}}_block_{{count}}" class="btn btn-primary btn-circle btn-danger">&nbsp;<li class="fa fa-power-off" aria-hidden="true"></i>&nbsp;</button></div></div>
{% elif "scene" in v[1] %}
<button id="scene_{{v[0]}}_block_{{count}}" class="btn btn-primary btn-circle">&nbsp;<li class="fa fa-power-off" aria-hidden="true"></i>&nbsp;</button>
{% elif "setpoint" in v[1] %}
{% if "switch" in v[2] %}
<input id="switch_{{v[1]}}_block_{{count}}" type="checkbox" checked data-size="mini">
{% elif "dimmer" in v[2] %}
<input id="dimmer_{{v[1]}}_block_{{count}}" data-slider-id='dim_{{v[1]}}_block_{{count}}' type="text" test={{ v[2] }} state="on" data-slider-min="0" data-slider-max="100" data-slider-step="1" data-slider-value="14" />
{% elif "pushon" in v[2] %}
<button id="push_{{v[1]}}_block_{{count}}" class="btn btn-primary btn-circle">&nbsp;<li class="fa fa-power-off" aria-hidden="true"></i>&nbsp;</button>
{% elif "pushoff" in v[2] %}
<button id="push_{{v[1]}}_block_{{count}}" class="btn btn-danger btn-circle">&nbsp;<li class="fa fa-power-off" aria-hidden="true"></i>&nbsp;</button>
{% elif "group" in v[2] %}
<div><div style="float: left"><button id="groupon_{{v[1]}}_block_{{count}}" class="btn btn-primary btn-circle">&nbsp;<li class="fa fa-power-off" aria-hidden="true"></i>&nbsp;</button></div><div style="padding-left: 20px; float: left"><button id="groupoff_{{v[1]}}_block_{{count}}" class="btn btn-primary btn-circle btn-danger">&nbsp;<li class="fa fa-power-off" aria-hidden="true"></i>&nbsp;</button></div></div>
{% elif "scene" in v[2] %}
<button id="scene_{{v[1]}}_block_{{count}}" class="btn btn-primary btn-circle">&nbsp;<li class="fa fa-power-off" aria-hidden="true"></i>&nbsp;</button>
{% elif v[2] == "setpoint" %}
<div>
<div style="float: left; margin-right: 5px"><h1 id="setpoint_{{v[0]}}_block_{{count}}" style="font-size: 16px;"></h1></div>
<div style="float: left; margin-right: 5px"><h1 id="setpoint_{{v[1]}}_block_{{count}}" style="font-size: 16px;"></h1></div>
<div style="float: left">
<div style=""><i onclick="changeUp({{ v[0] }}, {{count}})" class="fa fa-arrow-up" style="font-size: 13px; cursor: pointer;" aria-hidden="true"></i></div>
<div style=""><i onclick="changeDown({{ v[0] }}, {{count}})" class="fa fa-arrow-down" style="font-size: 13px; cursor: pointer;" aria-hidden="true"></i></div>
<div style=""><i onclick="changeUp({{ v[1] }}, {{count}})" class="fa fa-arrow-up" style="font-size: 13px; cursor: pointer;" aria-hidden="true"></i></div>
<div style=""><i onclick="changeDown({{ v[1] }}, {{count}})" class="fa fa-arrow-down" style="font-size: 13px; cursor: pointer;" aria-hidden="true"></i></div>
</div>
</div>
{% elif "rgb" in v[1] %}
&nbsp;<input id="dimmer_{{v[0]}}_block_{{count}}" data-slider-id='dimmer_{{v[0]}}' type="text" data-slider-min="0" data-slider-max="100" data-slider-step="1" data-slider-value="14" />
{% elif "setpoint_slider" in v[2] %}
<input id="setpoint_slider{{v[1]}}_block_{{count}}" data-slider-id='stpnt_{{v[1]}}_block_{{count}}' type="text" state="on" data-slider-min="{{v[3]}}" data-slider-max="{{v[4]}}" data-slider-step="0.5" />
{% elif "selector" in v[2] %}
<div class="btn-toolbar">
<div id="selector_body_{{v[1]}}_block_{{count}}" class="btn-group pull-right" style="width: 100%;"> </div>
</div>
{% elif "rgb" in v[2] %}
&nbsp;<input id="dimmer_{{v[1]}}_block_{{count}}" data-slider-id='dim_{{v[1]}}_block_{{count}}' type="text" data-slider-min="0" data-slider-max="100" data-slider-step="1" data-slider-value="14" />
<br><br>
<button type="button" class="btn btn-primary btn-xs" data-toggle="modal" data-target="#myModal-{{v[0]}}-block-{{count}}">RGB colors</button>
<button type="button" class="btn btn-primary btn-xs" data-toggle="modal" data-target="#myModal-{{v[1]}}-block-{{count}}">RGB colors</button>
<!-- Modal -->
<div class="modal fade bd-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true" id="myModal-{{v[0]}}-block-{{count}}">
<div class="modal fade bd-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true" id="myModal-{{v[1]}}-block-{{count}}">
<div class="modal-dialog modal-sm">
<!-- Modal content-->
@ -53,7 +64,7 @@
<h4 class="modal-title">RGB Selector</h4>
</div>
<div class="modal-body">
<div id="rgb_{{v[0]}}_block_{{count}}" class="inl-bl"></div>
<div id="rgb_{{v[1]}}_block_{{count}}" class="inl-bl"></div>
<style>
.inl-bl {
display: inline-block;
@ -61,7 +72,7 @@
</style>
<script>
$(function() {
$('#rgb_{{v[0]}}_block_{{count}}').colorpicker({
$('#rgb_{{v[1]}}_block_{{count}}').colorpicker({
color: '#ffaa00',
container: true,
inline: true
@ -70,7 +81,7 @@
</script>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" onclick="changeRgbColor('rgb_{{v[0]}}_block_{{count}}')">Save</button>
<button type="button" class="btn btn-default" data-dismiss="modal" onclick="changeRgbColor('rgb_{{v[1]}}_block_{{count}}')">Save</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
@ -90,51 +101,88 @@ $(document).ready(function() {
var updateSwitches_block_{{count}}=[];
var updateDimmers_block_{{count}}=[];
var updateSetpoints_block_{{count}}=[];
var updateSetpoint_sliders_block_{{count}}=[];
{% for k, v in blockArray[count]["switches"].iteritems() %}
{% if v[2] %}
$('#s_title_{{ count }}').html("{{ v[2] }}");
{% if v[0] %}
$('#s_title_{{ count }}').html("{{ v[0] }}");
{% endif %}
{% if v[1] == "switch" %}
$('input[id="switch_{{v[0]}}_block_{{count}}"]').on('switchChange.bootstrapSwitch', function(event, state) {
changeSwitch(this, {{v[0]}});
{% if v[2] == "switch" %}
$('input[id="switch_{{v[1]}}_block_{{count}}"]').on('switchChange.bootstrapSwitch', function(event, state) {
changeSwitch(this, {{v[1]}});
});
updateSwitches_block_{{count}}.push("{{v[0]}}");
{% elif (v[1] == "pushon") %}
$('button[id="push_{{v[0]}}_block_{{count}}"]').click(function(e) {
updateSwitches_block_{{count}}.push("{{v[1]}}");
{% elif (v[2] == "pushon") %}
$('button[id="push_{{v[1]}}_block_{{count}}"]').click(function(e) {
e.preventDefault();
changePush({{v[0]}}, 'on');
changePush({{v[1]}}, 'on');
});
{% elif (v[1] == "pushoff") %}
$('button[id="push_{{v[0]}}_block_{{count}}"]').click(function(e) {
{% elif (v[2] == "pushoff") %}
$('button[id="push_{{v[1]}}_block_{{count}}"]').click(function(e) {
e.preventDefault();
changePush({{v[0]}}, 'off');
changePush({{v[1]}}, 'off');
});
{% elif (v[1] == "group") or (v[1] == "scene") %}
$('button[id="groupon_{{v[0]}}_block_{{count}}"]').click(function(e) {
{% elif (v[2] == "group") or (v[2] == "scene") %}
$('button[id="groupon_{{v[1]}}_block_{{count}}"]').click(function(e) {
e.preventDefault();
changeScene({{v[0]}}, 'on');
changeScene({{v[1]}}, 'on');
});
$('button[id="groupoff_{{v[0]}}_block_{{count}}"]').click(function(e) {
$('button[id="groupoff_{{v[1]}}_block_{{count}}"]').click(function(e) {
e.preventDefault();
changeScene({{v[0]}}, 'off');
changeScene({{v[1]}}, 'off');
});
$('button[id="scene_{{v[0]}}_block_{{count}}"]').click(function(e) {
$('button[id="scene_{{v[1]}}_block_{{count}}"]').click(function(e) {
e.preventDefault();
changeScene({{v[0]}}, 'on');
changeScene({{v[1]}}, 'on');
});
{% elif (v[1] == "setpoint") %}
updateSetpoints_block_{{count}}.push("{{v[0]}}");
{% elif (v[1] == "dimmer" or v[1] == "rgb") %}
updateDimmers_block_{{count}}.push("{{v[0]}}");
{% elif (v[2] == "selector") %}
url = '/api?type=devices&rid=' + {{v[1]}};
requestAPI(flask_server + url, function(d) {
r = JSON.parse(d);
btns = r['result'][0]['LevelNames'].split('|');
if (r['result'][0]['LevelOffHidden'] == true) {
btns.shift();
}
$.each(btns, function (i, lvlname) {
activebtn = r['result'][0]['Level']
if (i != '0') {
i = i + '0';
}
if (activebtn == i) {
btnClass = 'btn btn-primary btn-responsive';
} else {
btnClass = 'btn btn-responsive';
}
bid = 'selector_{{v[1]}}_block_{{count}}_index_';
b = '<button id="' + bid + i + '" onclick="switchSelector({{v[1]}}, ' + i + ', this.id)" class="' + btnClass + '">' + lvlname + '</button>';
$('#selector_body_{{v[1]}}_block_{{count}}').append(b);
$('#' + 'selector_{{v[1]}}_block_{{count}}_index_' + i).click(function(e) {
e.preventDefault();
});
});
});
{% elif (v[2] == "setpoint") %}
updateSetpoints_block_{{count}}.push("{{v[1]}}");
{% elif (v[2] == "setpoint_slider") %}
updateSetpoint_sliders_block_{{count}}.push(["{{v[1]}}", "{{v[3]}}", "{{v[4]}}"]);
{% elif (v[2] == "dimmer" or v[2] == "rgb") %}
$('#Adim_{{v[1]}}_block_{{count}}').click(function(e) {
e.preventDefault();
changeDimmer('dim_{{v[1]}}_block_{{count}}_track', {{v[1]}});
});
updateDimmers_block_{{count}}.push("{{v[1]}}");
{% endif %}
{% endfor %}
refreshSwitches(updateSwitches_block_{{count}}, {{count}});
refreshSetpoints(updateSetpoints_block_{{count}}, {{count}});
dimmerSlider(updateDimmers_block_{{count}}, {{count}});
setpointSlider(updateSetpoint_sliders_block_{{count}}, {{count}});
setInterval(refreshSwitches, 9000, updateSwitches_block_{{count}}, {{count}});
setInterval(dimmerSlider, 9000, updateDimmers_block_{{count}}, {{count}});
setInterval(setpointSlider, 9000, updateSetpoint_sliders_block_{{count}}, {{count}});
setInterval(refreshSetpoints, 9000, updateSetpoints_block_{{count}}, {{count}});
});
</script>

View File

@ -4,8 +4,8 @@
<div class="animated flipInY col-md-2 col-sm-4 col-xs-4 tile_stats_count">
<div class="left"></div>
<div class="right">
<span class="count_top"><i class="fa fa-{{v[1]}}"></i> {{k}}</span>
<div class="count{% if v[2] == "On" %} green{% elif v[2] == "Off" %} red{% endif %} loading" id=top_tiles_block_{{count}}_{{v[0]}} style="white-space: nowrap;">{{v[2]}}</div>
<span class="count_top"><i class="fa fa-{{v[2]}}"></i> {{k}} <i id="top_tiles_block_{{count}}_{{v[1]}}_{% if v[3] %}{{v[3]}}{% else %}Data{% endif %}_arrow" class='fa fa-lg'></i></span>
<div class="count loading" id="top_tiles_block_{{count}}_{{v[1]}}_{% if v[3] %}{{v[3]}}{% else %}Data{% endif %}" style="white-space: nowrap"></div>
</div>
</div>
{% endfor %}
@ -14,15 +14,29 @@
$(document).ready(function() {
var updateDivs_block_{{count}}=[];
var tilesPreviousArray_{{count}}=[];
var updateDivsType_block_{{count}} = [];
var updateDivsUnits_block_{{count}} = [];
{% for k, v in blockArray[count]["top_tiles"].iteritems() %}
updateDivs_block_{{count}}.push("{{v[0]}}");
updateDivs_block_{{count}}.push("{{v[1]}}");
{% if v[3]|length > 3 %}
updateDivsType_block_{{count}}.push("{{v[3]}}");
{% else %}
updateDivsType_block_{{count}}.push("Data");
{% endif %}
{% if v[4] %}
updateDivsUnits_block_{{count}}.push("{{v[4]}}");
{% else %}
updateDivsUnits_block_{{count}}.push(undefined);
{% endif %}
{% endfor %}
tilesPreviousArray_{{count}} = refreshTopTiles(updateDivs_block_{{count}}, "top_tiles_block_{{count}}_", tilesPreviousArray_{{count}});
tilesPreviousArray_{{count}} = refreshTopTiles(updateDivs_block_{{count}}, "top_tiles_block_{{count}}_", tilesPreviousArray_{{count}}, updateDivsType_block_{{count}}, updateDivsUnits_block_{{count}});
tilesPreviousArray_{{count}} = setInterval(refreshTopTiles, 9000, updateDivs_block_{{count}}, "top_tiles_block_{{count}}_", tilesPreviousArray_{{count}}, updateDivsType_block_{{count}}, updateDivsUnits_block_{{count}});
var counter = 0;
for (var i in updateDivs_block_{{count}}) {
$("#top_tiles_block_{{count}}_" + updateDivs_block_{{count}}[i]).removeClass("loading");
$("#top_tiles_block_{{count}}_" + updateDivs_block_{{count}}[i] + "_" + updateDivsType_block_{{count}}[counter]).removeClass("loading");
counter += 1;
}
tilesPreviousArray_{{count}} = setInterval(refreshTopTiles, 9000, updateDivs_block_{{count}}, "top_tiles_block_{{count}}_", tilesPreviousArray_{{count}});
});
</script>
<!-- /top tiles -->

View File

@ -1,17 +0,0 @@
<div class="col-md-6 col-sm-6 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>TV-Gids </h2>
<ul class="nav navbar-right panel_toolbox">
<li><a class="close-link"><i class="fa fa-close"></i></a>
</li>
</ul>
<div class="clearfix"></div>
</div>
<div id="tvgids" style="height: 450px;">
<iframe frameborder=0 style="overflow: hidden; position: relative; height: 100%; width: 100%;" src='https://www.tvgids24.nl/gadget'/></iframe>
</div>
</div>
</div>