diff --git a/init_db.py b/init_db.py index 0a53bef..35b1aea 100644 --- a/init_db.py +++ b/init_db.py @@ -3,6 +3,7 @@ from flask_sqlalchemy import SQLAlchemy from sqlalchemy_json import mutable_json_type from modules.helpers import logger, generateToken +from modules.domoticz import saveJson app = Flask(__name__) @@ -23,6 +24,7 @@ class User(db.Model): admin = db.Column(db.Boolean, default=False, nullable=False) googleassistant = db.Column(db.Boolean, default=False, nullable=False) authtoken = db.Column(db.String(100)) + device_config = db.Column(mutable_json_type(dbtype=db.JSON, nested=True)) def __repr__(self): return f"" @@ -58,8 +60,9 @@ def __repr__(self): domouser='domoticz', domopass='password', admin=True, - googleassistant=True, + googleassistant=False, authtoken=generateToken(username), + device_config={} ) db.session.add(new_user) @@ -90,6 +93,8 @@ def __repr__(self): db.session.add(settings) try: db.session.commit() + data = {} + saveJson(username, data) logger.info("Database is created...") except Exception: logger.info('Database already created') diff --git a/modules/database.py b/modules/database.py index 1957275..7244fa8 100644 --- a/modules/database.py +++ b/modules/database.py @@ -19,6 +19,7 @@ class User(UserMixin, db.Model): admin = db.Column(db.Boolean, default=False, nullable=False) googleassistant = db.Column(db.Boolean, default=False, nullable=False) authtoken = db.Column(db.String(100)) + device_config = db.Column(mutable_json_type(dbtype=db.JSON, nested=True)) def __repr__(self): return f"" @@ -37,4 +38,4 @@ class Settings(db.Model): armlevels = db.Column(mutable_json_type(dbtype=db.JSON, nested=True)) def __repr__(self): - return f"" \ No newline at end of file + return f"" diff --git a/modules/domoticz.py b/modules/domoticz.py index 2c4738a..7ce3b98 100644 --- a/modules/domoticz.py +++ b/modules/domoticz.py @@ -32,6 +32,17 @@ def AogGetDomain(device): return None return None + +def getDesc(user_id, state): + user = User.query.filter_by(username=user_id).first() + + if state.id in user.device_config: + desc = user.device_config[state.id] + return desc + else: + return None + + # Get additional settings from domoticz description in tags def getDeviceConfig(descstr): ISLIST = ['nicknames'] @@ -60,6 +71,7 @@ def getDeviceConfig(descstr): except: logger.error('Error parsing device configuration from Domoticz device description:', rawconfig[0]) return None + return cfgdict return None @@ -80,7 +92,7 @@ def getAog(device, user_id=None): aog.id = domain + "_" + device.get('idx') aog.name = { 'name' : device.get('Name').replace(" ","_"), - 'nicknames': [device.get('Name')] + 'nicknames': [] } if device.get('Type') in ['Light/Switch', 'Color Switch', 'Lighting 1', 'Lighting 2', 'Lighting 5', 'RFY', 'Value']: aog.type = 'action.devices.types.LIGHT' @@ -92,6 +104,7 @@ def getAog(device, user_id=None): aog.type = 'action.devices.types.FAN' if device.get('Image') == 'Heating': aog.type = 'action.devices.types.HEATER' + aog.customData['dzTags'] = False """ Get additional settings from domoticz description @@ -108,7 +121,16 @@ def getAog(device, user_id=None): (supports levelnames: 'off', 'heat', 'cool', 'auto', 'fan-only', 'purifier', 'eco', 'dry') """ - desc = getDeviceConfig(device.get("Description")) + + # Try to get device specific voice control configuration from Domoticz + desc = getDesc(user_id, aog) + if desc is None: + desc = getDeviceConfig(device.get("Description")) + if desc is not None: + logger.info(' tags found for idx %s in domoticz description.', aog.id) + aog.customData['dzTags'] = True + + if desc is not None: n = desc.get('nicknames', None) if n is not None: @@ -152,7 +174,7 @@ def getAog(device, user_id=None): aog.customData['idx'] = device.get('idx') aog.customData['domain'] = domain aog.customData['protected'] = device.get('Protected') - aog.notificationSupportedByAgent = (True if domain in ['SmokeDetector', 'Doorbell'] else False) + aog.notificationSupportedByAgent = (True if domain in ['SmokeDetector', 'Doorbell', 'DoorLock'] else False) if domain == 'Scene': aog.type = 'action.devices.types.SCENE' @@ -353,7 +375,7 @@ def queryDomoticz(username, url): auth=domoCredits, timeout=5.00) except: return "{}" - + return r.text def getDomoticzDevices(user_id): diff --git a/modules/routes.py b/modules/routes.py index 5c8d333..3f65aaf 100644 --- a/modules/routes.py +++ b/modules/routes.py @@ -1,5 +1,6 @@ import os import modules.config as config +import json from time import sleep from flask_login import login_required, current_user @@ -36,17 +37,131 @@ def dashboard(): @login_required def devices(): + reportstate = report_state.enable_report_state() dbsettings = Settings.query.get_or_404(1) devices = get_devices(current_user.username) + dbuser = User.query.filter_by(username=current_user.username).first() + + if request.method == "POST": + + deviceconfig = dbuser.device_config + + if request.form['submit'] == 'device_settings': + idx = request.form.get('device_id') + hideDevice = request.form.get('hideDevice') + willReportState = request.form.get('willReportState') + challenge = request.form.get('2FA') + room = request.form.get('room') + nicknames = request.form.get('nicknames') + devicetype = request.form.get('devicetype') + minThreehold = request.form.get('minThreehold') + maxThreehold = request.form.get('maxThreehold') + camurl = request.form.get('camurl') + actual_temp_idx = request.form.get('actual_temp_idx') + selector_modes_idx = request.form.get('selector_modes_idx') + + if idx not in deviceconfig.keys(): + deviceconfig[idx] = {} + + if hideDevice == 'on': + deviceconfig[idx].update({'hide': True}) + elif idx in deviceconfig.keys() and 'hide' in deviceconfig[idx]: + deviceconfig[idx].pop('hide') + + if willReportState != 'on': + deviceconfig[idx].update({'report_state': False}) + elif idx in deviceconfig.keys() and 'report_state' in deviceconfig[idx]: + deviceconfig[idx].pop('report_state') + + if challenge == 'ackNeeded': + deviceconfig[idx].update({'ack': True}) + elif idx in deviceconfig.keys() and 'ack' in deviceconfig[idx]: + deviceconfig[idx].pop('ack') + + if room is not None: + if room != '': + deviceconfig[idx].update({'room': room}) + elif idx in deviceconfig.keys() and 'room' in deviceconfig[idx]: + deviceconfig[idx].pop('room') + + if nicknames is not None: + if nicknames != '': + names = nicknames.split(", ") + names = list(filter(None, names)) + deviceconfig[idx].update({'nicknames':names}) + elif idx in deviceconfig.keys() and 'nicknames' in deviceconfig[idx]: + deviceconfig[idx].pop('nicknames') + + if devicetype is not None: + if devicetype != 'default': + deviceconfig[idx].update({'devicetype': devicetype}) + elif idx in deviceconfig.keys() and 'devicetype' in deviceconfig[idx]: + deviceconfig[idx].pop('devicetype') + + if minThreehold is not None: + if minThreehold != '': + deviceconfig[idx].update({'minThreehold': int(minThreehold)}) + elif idx in deviceconfig.keys() and 'minThreehold' in deviceconfig[idx]: + deviceconfig[idx].pop('minThreehold') + + if maxThreehold is not None: + if maxThreehold != '': + deviceconfig[idx].update({'maxThreehold': int(maxThreehold)}) + elif idx in deviceconfig.keys() and 'maxThreehold' in deviceconfig[idx]: + deviceconfig[idx].pop('maxThreehold') + + if actual_temp_idx is not None: + if actual_temp_idx != '': + deviceconfig[idx].update({'actual_temp_idx': actual_temp_idx}) + elif idx in deviceconfig.keys() and 'actual_temp_idx' in deviceconfig[idx]: + deviceconfig[idx].pop('actual_temp_idx') + + if selector_modes_idx is not None: + if selector_modes_idx != '': + deviceconfig[idx].update({'selector_modes_idx': selector_modes_idx}) + elif idx in deviceconfig.keys() and 'selector_modes_idx' in deviceconfig[idx]: + deviceconfig[idx].pop('selector_modes_idx') + + if camurl is not None: + if camurl != '': + deviceconfig[idx].update({'camurl': camurl}) + elif idx in deviceconfig.keys() and 'camurl' in deviceconfig[idx]: + deviceconfig[idx].pop('camurl') + + if deviceconfig[idx] == {}: + deviceconfig.pop(idx) + + dbuser.device_config.update(deviceconfig) + db.session.add(dbuser) + db.session.commit() + + armedhome = request.form.get('armedhome') + armedaway = request.form.get('armedaway') + if (armedhome is not None) or (armedaway is not None): + armedhome = armedhome.split(", ") + armedaway = armedaway.split(", ") + armhome = list(filter(None, armedhome)) + armaway = list(filter(None, armedaway)) + dbsettings.armlevels.update({'armhome': armhome, 'armaway': armaway}) + + db.session.add(dbsettings) + db.session.commit() + + logger.info("Device settings saved") + + return redirect(url_for('devices')) + + if request.method == "GET": - return render_template('devices.html', - user=User.query.filter_by(username=current_user.username).first(), - dbsettings=dbsettings, - reportstate=reportstate, - devices=devices, - _csrf_token=session['_csrf_token'] - ) + + return render_template('devices.html', + user=dbuser, + dbsettings=dbsettings, + reportstate=reportstate, + devices=devices, + _csrf_token=session['_csrf_token'] + ) @login_required @@ -78,7 +193,7 @@ def settings(): dbuser = User.query.filter_by(username=current_user.username).first() dbsettings = Settings.query.get_or_404(1) - + if request.form['submit'] == 'save_user_settings': dbuser.domo_url = request.form.get('domourl') dbuser.domouser = request.form.get('domouser') @@ -100,10 +215,6 @@ def settings(): dbsettings.use_ssl = (request.form.get('ssl') == 'true') dbsettings.ssl_cert = request.form.get('sslcert') dbsettings.ssl_key = request.form.get('sslkey') - armhome = request.form.get('armhome') - armaway = request.form.get('armaway') - - dbsettings.armlevels.update({'armhome': armhome, 'armaway': armaway}) db.session.add(dbsettings) db.session.commit() @@ -122,8 +233,8 @@ def settings(): return redirect(url_for('settings')) add_new_user = User(email=newemail, username=newuser, password=newpass, - roomplan='0', domo_url='http://192.168.1.13:8080', domouser='domoticz', domopass='password', - admin=newadmin, googleassistant=newgoogleassistant, authtoken=generateToken(newuser)) + roomplan='0', domo_url='http://192.168.1.99:8080', domouser='domoticz', domopass='password', + admin=newadmin, googleassistant=newgoogleassistant, authtoken=generateToken(newuser), device_config={}) db.session.add(add_new_user) db.session.commit() diff --git a/static/css/style.css b/static/css/style.css index f7e3b63..8ab8a72 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -102,6 +102,45 @@ h6 { /*-------------------------------------------------------------- # Override some default Bootstrap stylings --------------------------------------------------------------*/ +.forkme { + margin: 0 -21px 0 0; +} +.logging_window{ + display: block; + padding: 9.5px; + font-size: 16px; + line-height: 1.42857143; + color: #333; + word-break: break-all; + word-wrap: break-word; + background-color: #f5f5f5; + border: 1px solid #ccc; + border-radius: 4px; + width: 100%; + height: 400px; + margin: auto; +} +.icon { + border: transparent; + border-radius: 15px; + box-shadow: 0px 0 30px rgba(1, 41, 112, 0.1); +} +.click { + cursor: pointer; + } +.icon:hover { + background: #f6f9ff; +} +.input-group button { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.form-control[type="color"]{ + display: inline-block; + padding: 0.10rem; +} + /* Dropdown menus */ .dropdown-menu { border-radius: 4px; diff --git a/static/js/smarthome.js b/static/js/smarthome.js index 9bc44eb..c3bde6f 100644 --- a/static/js/smarthome.js +++ b/static/js/smarthome.js @@ -270,8 +270,7 @@ function getVersion() { var url = "/api?type=command¶m=getversion" requestAPI(url).then(jsonData => { var data = jsonData - console.log(data.version); - $('#dzga-version').html('23.3') + $('#dzga-version').html('23.6') $('#dz-version').html(data.version) }); } diff --git a/templates/dashboard.html b/templates/dashboard.html index a2d549a..ab7486f 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -4,31 +4,6 @@ {% include 'sidebar.html' %} - - -
@@ -482,7 +457,7 @@
Hidden devices Description {{ v['name']['name'].replace("_", " ") }}