Skip to content
This repository has been archived by the owner on Feb 16, 2024. It is now read-only.

Commit

Permalink
Merge pull request #323 from DewGew/beta
Browse files Browse the repository at this point in the history
Fixes issues #307 #313 #315 #317 #319
  • Loading branch information
DewGew authored May 10, 2023
2 parents 0998ced + ecd58a4 commit 2b2de51
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 36 deletions.
2 changes: 1 addition & 1 deletion const.py
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
6 changes: 3 additions & 3 deletions requirements/pip-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ 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
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
73 changes: 45 additions & 28 deletions smarthome.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import re
import subprocess
import sys
import time
import yaml
from collections.abc import Mapping
from itertools import product
Expand Down Expand Up @@ -389,6 +390,7 @@ def getAog(device):

return aog

aogDevsReady = False
aogDevs = {}
deviceList = {}

Expand Down Expand Up @@ -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]
Expand All @@ -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)
Expand All @@ -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():
Expand Down Expand Up @@ -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())

Expand Down Expand Up @@ -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')
Expand Down Expand Up @@ -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():
Expand All @@ -1047,22 +1058,27 @@ 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)
try:
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))
Expand Down Expand Up @@ -1090,6 +1106,7 @@ def smarthome_exec(self, payload, token):

if entity_id not in entities:
if len(aogDevs) == 0:
aogDevsReady = False
getDevices()
getSettings()

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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":
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -1291,25 +1308,25 @@ 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:
mc.play_media(pmedia, ptype)
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<tmax:
pstate = mc.status.player_state
time.sleep(1)
i+=1
message="play mp3 : " + pmedia + ", volume : " + str((round(cast.status.volume_level * 100))) + "%" + " on device '" + str(cast.device.friendly_name) + "' playerstate : " + mc.status.player_state
i += 1
message = "play mp3 : " + pmedia + ", volume : " + str((round(cast.status.volume_level * 100))) + "%" + " on device '" + str(cast.device.friendly_name) + "' playerstate : " + mc.status.player_state
logger.info(message)
return "OK","Playing "+ str(pmedia) + ", type " + str(ptype)
return "OK", "Playing " + str(pmedia) + ", type " + str(ptype)
except Exception as e:
logger.error('Chromecast playmedia unsuccefull, error : %s' % e)
return "Error","Error playing "+ str(pmedia) + ", type " +str(ptype)
return "Error", "Error playing " + str(pmedia) + ", type " +str(ptype)

def pycast(self, s):
global cast, mc, chromecasts
Expand Down
4 changes: 0 additions & 4 deletions trait.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,6 @@ def execute(self, command, params):

if domain not in [DOMAINS['sensor']]:
if domain == DOMAINS['group']:
url = DOMOTICZ_URL + '/json.htm?type=command&param=switchscene&idx=' + self.state.id + '&switchcmd=' + (
'On' if params['on'] else 'Off')
url = DOMOTICZ_URL + '/json.htm?type=command&param=switchscene&idx=' + self.state.id + '&switchcmd='
if params['on'] is True and state == 'Off':
url += 'On'
Expand All @@ -205,8 +203,6 @@ def execute(self, command, params):
raise SmartHomeError(ERR_ALREADY_IN_STATE,
'Unable to execute {} for {}. Already in state '.format(command, self.state.entity_id))
else:
url = DOMOTICZ_URL + '/json.htm?type=command&param=switchlight&idx=' + self.state.id + '&switchcmd=' + (
'On' if params['on'] else 'Off')
url = DOMOTICZ_URL + '/json.htm?type=command&param=switchlight&idx=' + self.state.id + '&switchcmd='
if params['on'] is True and state == 'Off':
url += 'On'
Expand Down

0 comments on commit 2b2de51

Please sign in to comment.