diff --git a/const.py b/const.py index 4df763b..9e418de 100644 --- a/const.py +++ b/const.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Constants for Google Assistant.""" -VERSION = '1.23.3' +VERSION = '1.23.6' PUBLIC_URL = 'https://[your public url]' CONFIGFILE = 'config/config.yaml' LOGFILE = 'dzga.log' diff --git a/requirements/pip-requirements.txt b/requirements/pip-requirements.txt index 8a6407e..493bdf5 100644 --- a/requirements/pip-requirements.txt +++ b/requirements/pip-requirements.txt @@ -4,8 +4,8 @@ future>=0.18.2 idna>=2.8 pid>=3.0.3 PyYAML>=5.1.2 -requests>=2.22.0 -urllib3>=1.25.7 +requests>=2.30.0 +urllib3>=1.26,<2 GitPython>=3.0.5 google-auth>=1.8.1 wheel>=0.34.2 @@ -13,6 +13,6 @@ Jinja2>=2.11.3 PyChromecast==9.1.2 gTTS>=2.2.1 unicode-slugify>=0.1.3 -protobuf==3.20.0 +protobuf==3.20.2 zeroconf>=0.25.1 casttube>=0.2.0 diff --git a/smarthome.py b/smarthome.py index 73bac92..28bbd75 100644 --- a/smarthome.py +++ b/smarthome.py @@ -5,6 +5,7 @@ import re import subprocess import sys +import time import yaml from collections.abc import Mapping from itertools import product @@ -389,6 +390,7 @@ def getAog(device): return aog +aogDevsReady = False aogDevs = {} deviceList = {} @@ -438,6 +440,9 @@ def getDevices(devices="all", idx="0"): devlist = [(d.name, int(d.id), d.domain, d.state, d.room, d.nicknames, d.report_state, d.entity_id) for d in aogDevs.values()] devlist.sort(key=takeSecond) deviceList = json.dumps(devlist) + + if "all" == devices: + aogDevsReady = True def takeSecond(elem): return elem[1] @@ -457,6 +462,7 @@ def deep_update(target, source): def getSettings(): """Get domoticz settings.""" global settings + global aogDevsReady url = DOMOTICZ_URL + DOMOTICZ_GET_SETTINGS_URL r = requests.get(url, auth=CREDITS) @@ -469,7 +475,8 @@ def getSettings(): settings['Language'] = devs['Language'] getVersion() - + aogDevsReady = True + logger.debug(json.dumps(settings, indent=2, sort_keys=False, ensure_ascii=False)) def getVersion(): @@ -588,7 +595,7 @@ def query_serialize(self): # if state.state == STATE_UNAVAILABLE: # return {'online': False} - attrs = {'online': True} + attrs = {'online': True, 'status': "SUCCESS"} for trt in self.traits(): deep_update(attrs, trt.query_attributes()) @@ -652,6 +659,8 @@ def execute(self, command, params, challenge): def async_update(self): """Update the entity with latest info from Domoticz.""" + if not self.state: + return if self.state.domain == DOMAINS['group'] or self.state.domain == DOMAINS['scene']: getDevices('scene') @@ -1022,9 +1031,11 @@ def smarthome_sync(self, payload, token): https://developers.google.com/actions/smarthome/create-app#actiondevicessync """ devices = [] + aogDevsReady = False # lock smarthome_query while reloading devices aogDevs.clear() getDevices() # sync all devices getSettings() + agent_user_id = token.get('userAgentId', None) for state in aogDevs.values(): @@ -1047,14 +1058,19 @@ def smarthome_query(self, payload, token): """ response = {} devices = {} - + + loopCount = 5 + while (loopCount>0 and not aogDevsReady): # whait for 5 seconds if aogDevs array is refreshed + time.sleep(1) + loopCount -= 1 + for device in payload.get('devices', []): devid = device['id'] _GoogleEntity(aogDevs.get(devid, None)).async_update() state = aogDevs.get(devid, None) if not state: # If we can't find a state, the device is offline - devices[devid] = {'online': False} + devices[devid] = {'online': False, 'status': "OFFLINE"} continue e = _GoogleEntity(state) @@ -1062,7 +1078,7 @@ def smarthome_query(self, payload, token): devices[devid] = e.query_serialize() except Exception: logger.error("Unexpected error serializing query for %s", state) - devices[devid] = {"online": False} + devices[devid] = {"online": False, 'status': "ERROR"} response = {'devices': devices} logger.info(json.dumps(response, indent=2, sort_keys=True, ensure_ascii=False)) @@ -1090,6 +1106,7 @@ def smarthome_exec(self, payload, token): if entity_id not in entities: if len(aogDevs) == 0: + aogDevsReady = False getDevices() getSettings() @@ -1146,7 +1163,7 @@ def say(self, s): #command "/say?text-to-say/lang@volume@device" SmartHomeReqHandler.send_resp("Error", s.url.query, scomm, stime, s) return itext = scomm.replace(" ","-") - itext=itext.split("/") + itext = itext.split("/") text = itext[0] if not text: return False @@ -1192,13 +1209,13 @@ def play(self, s): #command "/play?soundfile.mp3@volume else: rstatus="Error" rmessage = str(mp3_filename) + ", file not found!" - if rvol!="?": + if rvol != "?": answ, message = SmartHomeReqHandler.setvolume(str(round(rvol*100))) rmessage = rmessage + " restore volume " + str(round(rvol*100)) - if rcontent!="?": + if rcontent != "?": answ, message = SmartHomeReqHandler.playmedia(rcontent, rtype, 'PLAYING', 40) rmessage = rmessage + " restore stream : " + rcontent - if rdevice!="?": + if rdevice != "?": answ, message = SmartHomeReqHandler.switchdevice(rdevice) rmessage = rmessage + " restore device '" + rdevice+ "'" SmartHomeReqHandler.send_resp(rstatus, "play " + s.url.query, rmessage, stime, s) @@ -1223,31 +1240,31 @@ def send_resp(rstatus, rcommand, rmessage, stime, s): rtype = mc.status.content_type rpstate = mc.status.player_state if rpstate == "UNKNOWN": - rcontent="?" - rtype="?" - message='{"device":"'+ cast.device.friendly_name + '","status":"' + rstatus + '","command":"' + rcommand + '","volume":"' +rvolume +'","starttime":"' + stime + '","endtime":"' + etime + '","playstate":"' + rpstate + '","content":"' + rcontent + '","type":"' + rtype + '","message":"' + rmessage+ '"}' + rcontent = "?" + rtype = "?" + message = '{"device":"'+ cast.device.friendly_name + '","status":"' + rstatus + '","command":"' + rcommand + '","volume":"' +rvolume +'","starttime":"' + stime + '","endtime":"' + etime + '","playstate":"' + rpstate + '","content":"' + rcontent + '","type":"' + rtype + '","message":"' + rmessage+ '"}' s.send_json(200, message, False) logger.info(message) def read_input(ctext): global cast, mc, chromecasts stime = time.strftime("%d/%m/%y %H:%M:%S", time.localtime()) - answ="OK" - message="" + answ = "OK" + message = "" rdevice = "?" rvol = "?" rcontent = "?" rtype = "?" ctext = ctext.split("@") try: - svol=ctext[1] + svol = ctext[1] except: - svol="" + svol = "" try: - sdevice=ctext[2] + sdevice = ctext[2] except: - sdevice="" - if sdevice!="": + sdevice = "" + if sdevice != "": rdevice = cast.device.friendly_name answ, message = SmartHomeReqHandler.switchdevice(sdevice) if answ == "Error": @@ -1260,7 +1277,7 @@ def read_input(ctext): else: rcontent = "?" rtype = "?" - if svol!="": + if svol != "": cast.wait() rvol = cast.status.volume_level answ, message = SmartHomeReqHandler.setvolume(svol) @@ -1278,11 +1295,11 @@ def switchdevice(sdevice): return "OK","Switched to device " + str(cast.device.friendly_name) except Exception as e: logger.error('chromecasts init not succeeded, error : %s' % e) - return "Error","Not switched to device " + str(sdevice) + return "Error", "Not switched to device " + str(sdevice) def setvolume(svol): global cast, mc, chromecasts - svol=svol.replace("%","") + svol = svol.replace("%","") try: cast.wait() cast.set_volume(int(svol)/100) @@ -1291,7 +1308,7 @@ def setvolume(svol): return "OK","Volume level set to : " + svol +"%" except Exception as e: logger.error('Chromecast setvolume unsuccesfull, error : %s' % e) - return "Error","Volume level not set to : " + svol +"%" + return "Error", "Volume level not set to : " + svol +"%" def playmedia(pmedia,ptype, wstate, tmax): try: @@ -1299,17 +1316,17 @@ def playmedia(pmedia,ptype, wstate, tmax): mc.block_until_active() cast.wait() pstate = "?" - i=1 #max x seconds + i = 1 #max x seconds while (mc.status.player_state != wstate or pstate != wstate) and i