From 90feae184806d2e5676e35f0bfdff5066fa48712 Mon Sep 17 00:00:00 2001 From: DewGew <pierlar@hotmail.com> Date: Thu, 8 Jun 2023 11:43:02 +0200 Subject: [PATCH 01/13] Fixes Depricated RType (devices) for API request. There has been some changes in API calls from Build 15326, 1-jun-2023. --- const.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/const.py b/const.py index 4d1bbbd..f63c2bf 100644 --- a/const.py +++ b/const.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Constants for Google Assistant.""" -VERSION = '1.23.7' +VERSION = '1.23.8' PUBLIC_URL = 'https://[your public url]' CONFIGFILE = 'config/config.yaml' LOGFILE = 'dzga.log' @@ -16,13 +16,14 @@ SESSION_TIMEOUT = 3600 AUTH_CODE_TIMEOUT = 600 -DOMOTICZ_GET_ALL_DEVICES_URL = '/json.htm?type=devices&plan=' -DOMOTICZ_GET_ONE_DEVICE_URL = '/json.htm?type=devices&rid=' -DOMOTICZ_GET_SCENES_URL = '/json.htm?type=scenes' -DOMOTICZ_GET_SETTINGS_URL = '/json.htm?type=settings' -DOMOTICZ_GET_CAMERAS_URL = '/json.htm?type=cameras' +DOMOTICZ_GET_ALL_DEVICES_URL = '/json.htm?type=command¶m=getdevices&plan=' +DOMOTICZ_GET_ONE_DEVICE_URL = '/json.htm?type=command¶m=getdevices&rid=' +DOMOTICZ_GET_SCENES_URL = '/json.htm?type=command¶m=getscenes' +DOMOTICZ_GET_SETTINGS_URL = '/json.htm?type=command¶m=getsettings' +DOMOTICZ_GET_CAMERAS_URL = '/json.htm?type=command¶m=getcameras' DOMOTICZ_GET_VERSION = '/json.htm?type=command¶m=getversion' DOMOTICZ_SEND_COMMAND = 'json.htm?type=command¶m=' +DOMOTICZ_GET_PLANS = '/json.htm?type=command¶m=getplans' # https://developers.google.com/actions/smarthome/guides/ PREFIX_TYPES = 'action.devices.types.' From 6006c5d4c923d866ba04439d729557aba0f668d0 Mon Sep 17 00:00:00 2001 From: DewGew <pierlar@hotmail.com> Date: Thu, 8 Jun 2023 11:44:23 +0200 Subject: [PATCH 02/13] Update smarthome.py --- smarthome.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/smarthome.py b/smarthome.py index 71f3322..5697a8a 100644 --- a/smarthome.py +++ b/smarthome.py @@ -27,6 +27,7 @@ DOMOTICZ_GET_SETTINGS_URL, DOMOTICZ_GET_ONE_DEVICE_URL, DOMOTICZ_GET_SCENES_URL, + DOMOTICZ_GET_PLANS, CONFIGFILE, LOGFILE, REQUEST_SYNC_BASE_URL, @@ -494,7 +495,7 @@ def getPlans(idx): """Get domoticz plan name.""" global settings - url = DOMOTICZ_URL + '/json.htm?type=plans&order=name&used=true' + url = DOMOTICZ_URL + DOMOTICZ_GET_PLANS + '&order=name&used=true' r = requests.get(url, auth=CREDITS) if r.status_code == 200: From 827243b3b7d304cb6e2fe4344d790e1a8d7f02bd Mon Sep 17 00:00:00 2001 From: DewGew <pierlar@hotmail.com> Date: Thu, 8 Jun 2023 13:21:33 +0200 Subject: [PATCH 03/13] Fix group command and status #320 --- smarthome.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/smarthome.py b/smarthome.py index 5697a8a..70c3816 100644 --- a/smarthome.py +++ b/smarthome.py @@ -253,7 +253,9 @@ def getAog(device): aog.id = device["idx"] aog.entity_id = domain + aog.id aog.plan = device.get("PlanID") - aog.state = device.get("Data", "Scene") + aog.state = device.get("Data") + if aog.domain in [DOMAINS['scene'], DOMAINS['group']]: + aog.state = device.get("Status") aog.level = device.get("LevelInt", 0) aog.temp = device.get("Temp") aog.humidity = device.get("Humidity") From 57a729c3761f0a15b749f36023ed4c6866579b17 Mon Sep 17 00:00:00 2001 From: DewGew <pierlar@hotmail.com> Date: Thu, 8 Jun 2023 17:45:10 +0200 Subject: [PATCH 04/13] Create publish_beta.yml --- .github/workflows/publish_beta.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/publish_beta.yml diff --git a/.github/workflows/publish_beta.yml b/.github/workflows/publish_beta.yml new file mode 100644 index 0000000..6bf288b --- /dev/null +++ b/.github/workflows/publish_beta.yml @@ -0,0 +1,21 @@ +name: Publish Docker Image Beta + +on: + workflow_dispatch: + branches: [ "beta" ] +jobs: + publish-docker-image: + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Login to GitHub Container Registry + uses: docker/login-action@v1 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build the Docker image + run: | + docker build . --tag ghcr.io/${{secrets.DOCKER_USER}}/domoticz-google-assistant:beta + docker push ghcr.io/${{secrets.DOCKER_USER}}/domoticz-google-assistant:beta From fcf172a85aebd3457374579492c47640f158d016 Mon Sep 17 00:00:00 2001 From: DewGew <pierlar@hotmail.com> Date: Thu, 8 Jun 2023 17:51:39 +0200 Subject: [PATCH 05/13] Update publish_beta.yml --- .github/workflows/publish_beta.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/publish_beta.yml b/.github/workflows/publish_beta.yml index 6bf288b..712baab 100644 --- a/.github/workflows/publish_beta.yml +++ b/.github/workflows/publish_beta.yml @@ -4,8 +4,7 @@ on: workflow_dispatch: branches: [ "beta" ] jobs: - publish-docker-image: - if: github.event.pull_request.merged == true + publish-docker-image-beta: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 From a3261f1c351bfbe40673849c202231e5d39cf1f6 Mon Sep 17 00:00:00 2001 From: DewGew <pierlar@hotmail.com> Date: Mon, 26 Jun 2023 14:15:18 +0200 Subject: [PATCH 06/13] switchpass in config not needed --- templates/js/functions.js | 1 - 1 file changed, 1 deletion(-) diff --git a/templates/js/functions.js b/templates/js/functions.js index 1af973e..8980c73 100644 --- a/templates/js/functions.js +++ b/templates/js/functions.js @@ -215,7 +215,6 @@ $("#saveSettings").click(function(){ 'roomplan': $('#Domoticzroomplan').val(), 'username': $('#Domoticzusername').val(), 'password': $('#Domoticzpassword').val(), - 'switchProtectionPass': $('#DomoticzswitchProtectionPass').val(), }, } document.getElementById("saveSettings").value = JSON.stringify(stext) From fee3db7a8ec06d9e939b64e1a99c8046083eefd5 Mon Sep 17 00:00:00 2001 From: DewGew <pierlar@hotmail.com> Date: Mon, 26 Jun 2023 14:20:23 +0200 Subject: [PATCH 07/13] switchpass in config not needed anymore --- smarthome.py | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/smarthome.py b/smarthome.py index 70c3816..43bb497 100644 --- a/smarthome.py +++ b/smarthome.py @@ -252,7 +252,7 @@ def getAog(device): aog.domain = domain aog.id = device["idx"] aog.entity_id = domain + aog.id - aog.plan = device.get("PlanID") + aog.plan = device.get("PlanID") aog.state = device.get("Data") if aog.domain in [DOMAINS['scene'], DOMAINS['group']]: aog.state = device.get("Status") @@ -613,17 +613,11 @@ def execute(self, command, params, challenge): if trt.can_execute(command, params): acknowledge = self.state.ack # ack is now stored in state + protect = self.state.protected pincode = False - if configuration['Domoticz']['switchProtectionPass']: - protect = self.state.protected - else: - protect = False - if protect or self.state.domain == DOMAINS['security']: - pincode = configuration['Domoticz']['switchProtectionPass'] - if self.state.domain == DOMAINS['security']: - pincode = self.state.seccode + pincode = self.state.seccode acknowledge = False if challenge is None: raise SmartHomeErrorNoChallenge(ERR_CHALLENGE_NEEDED, 'pinNeeded', @@ -633,10 +627,7 @@ def execute(self, command, params, challenge): raise SmartHomeErrorNoChallenge(ERR_CHALLENGE_NEEDED, 'userCancelled', 'Unable to execute {} for {} - challenge needed '.format( command, self.state.entity_id)) - elif True == protect and pincode != challenge.get('pin'): - raise SmartHomeErrorNoChallenge(ERR_CHALLENGE_NEEDED, 'challengeFailedPinNeeded', - 'Unable to execute {} for {} - challenge needed '.format( - command, self.state.entity_id)) + elif self.state.domain == DOMAINS['security'] and pincode != hashlib.md5( str.encode(challenge.get('pin'))).hexdigest(): raise SmartHomeErrorNoChallenge(ERR_CHALLENGE_NEEDED, 'challengeFailedPinNeeded', @@ -652,7 +643,7 @@ def execute(self, command, params, challenge): 'Unable to execute {} for {} - challenge needed '.format( command, self.state.entity_id)) - trt.execute(command, params) + trt.execute(command, params, challenge) executed = True break From 3a8cf1c0aa2a21c7b906cc95a684a1103cddf2ad Mon Sep 17 00:00:00 2001 From: DewGew <pierlar@hotmail.com> Date: Mon, 26 Jun 2023 14:27:01 +0200 Subject: [PATCH 08/13] Switchpass in config not needed --- trait.py | 142 ++++++++++++++++++++++++------------------------------- 1 file changed, 61 insertions(+), 81 deletions(-) diff --git a/trait.py b/trait.py index 079dfa1..6b7448b 100644 --- a/trait.py +++ b/trait.py @@ -5,7 +5,7 @@ import requests from datetime import datetime -from helpers import SmartHomeError, configuration, logger, tempConvert +from helpers import SmartHomeError, SmartHomeErrorNoChallenge, configuration, logger, tempConvert from const import ( ATTRS_BRIGHTNESS, ATTRS_THERMSTATSETPOINT, @@ -14,6 +14,11 @@ ATTRS_PERCENTAGE, ATTRS_VACUUM_MODES, DOMAINS, + ERR_FUNCTION_NOT_SUPPORTED, + ERR_PROTOCOL_ERROR, + ERR_DEVICE_OFFLINE, + ERR_UNKNOWN_ERROR, + ERR_CHALLENGE_NEEDED, ERR_ALREADY_IN_STATE, ERR_WRONG_PIN, ERR_NOT_SUPPORTED, @@ -81,6 +86,17 @@ CREDITS = (configuration['Domoticz']['username'], configuration['Domoticz']['password']) +def checkCode(self, command, status): + status = status.json() + err = status.get('status') + if err == 'ERROR': + msg = status.get('message') + if msg == 'WRONG CODE': + raise SmartHomeErrorNoChallenge(ERR_CHALLENGE_NEEDED, 'challengeFailedPinNeeded', + 'Unable to execute {} for {} - challenge needed '.format( + command, self.state.entity_id)) + + def register_trait(trait): """Decorate a function to register a trait.""" @@ -116,7 +132,7 @@ def can_execute(self, command, params): """Test if command can be executed.""" return command in self.commands - async def execute(self, command, params): + async def execute(self, command, params, challenge): """Execute a trait command.""" raise NotImplementedError @@ -186,7 +202,7 @@ def query_attributes(self): return response - def execute(self, command, params): + def execute(self, command, params, challenge): """Execute an OnOff command.""" domain = self.state.domain state = self.state.state @@ -213,16 +229,12 @@ def execute(self, command, params): 'Unable to execute {} for {}. Already in state '.format(command, self.state.entity_id)) if protected: - url = url + '&passcode=' + configuration['Domoticz']['switchProtectionPass'] + url = url + '&passcode=' + challenge.get('pin') r = requests.get(url, auth=CREDITS) if protected: - status = r.json() - err = status.get('status') - if err == 'ERROR': - raise SmartHomeError(ERR_WRONG_PIN, - 'Unable to execute {} for {} check your settings'.format(command, - self.state.entity_id)) + checkCode(self, command, r) + @register_trait class SceneTrait(_Trait): @@ -249,7 +261,7 @@ def query_attributes(self): """Return scene query attributes.""" return {} - def execute(self, command, params): + def execute(self, command, params, challenge): """Execute a scene command.""" protected = self.state.protected @@ -261,12 +273,7 @@ def execute(self, command, params): r = requests.get(url, auth=CREDITS) if protected: - status = r.json() - err = status.get('status') - if err == 'ERROR': - raise SmartHomeError(ERR_WRONG_PIN, - 'Unable to execute {} for {} check your settings'.format(command, - self.state.entity_id)) + checkCode(self, command, r) @register_trait @@ -314,7 +321,7 @@ def can_execute(self, command, params): self.state.entity_id)) return command in self.commands - def execute(self, command, params): + def execute(self, command, params, challenge): """Execute a brightness command.""" protected = self.state.protected @@ -326,12 +333,7 @@ def execute(self, command, params): r = requests.get(url, auth=CREDITS) if protected: - status = r.json() - err = status.get('status') - if err == 'ERROR': - raise SmartHomeError(ERR_WRONG_PIN, - 'Unable to execute {} for {} check your settings'.format(command, - self.state.entity_id)) + checkCode(self, command, r) @register_trait @@ -386,7 +388,7 @@ def query_attributes(self): return response - def execute(self, command, params): + def execute(self, command, params, challenge): """Execute a OpenClose command.""" features = self.state.attributes protected = self.state.protected @@ -420,12 +422,8 @@ def execute(self, command, params): r = requests.get(url, auth=CREDITS) if protected: - status = r.json() - err = status.get('status') - if err == 'ERROR': - raise SmartHomeError(ERR_WRONG_PIN, - 'Unable to execute {} for {} check your settings'.format(command, - self.state.entity_id)) + checkCode(self, command, r) + @register_trait class StartStopTrait(_Trait): @@ -465,7 +463,7 @@ def query_attributes(self): return response - def execute(self, command, params): + def execute(self, command, params, challenge): """Execute a StartStop command.""" domain = self.state.domain protected = self.state.protected @@ -483,12 +481,8 @@ def execute(self, command, params): r = requests.get(url, auth=CREDITS) if protected: - status = r.json() - err = status.get('status') - if err == 'ERROR': - raise SmartHomeError(ERR_WRONG_PIN, - 'Unable to execute {} for {} check your settings'.format(command, - self.state.entity_id)) + checkCode(self, command, r) + @register_trait @@ -580,7 +574,7 @@ def query_attributes(self): return response - def execute(self, command, params): + def execute(self, command, params, challenge): """Execute a temperature point or mode command.""" # All sent in temperatures are always in Celsius @@ -681,7 +675,7 @@ def query_attributes(self): return response - def execute(self, command, params): + def execute(self, command, params, challenge): """Execute a temperature point command.""" # All sent in temperatures are always in Celsius if self.state.merge_thermo_idx is not None: @@ -724,7 +718,7 @@ def query_attributes(self): return response - def execute(self, command, params): + def execute(self, command, params, challenge): """Execute an LockUnlock command.""" domain = self.state.domain state = self.state.state @@ -754,12 +748,8 @@ def execute(self, command, params): r = requests.get(url, auth=CREDITS) if protected: - status = r.json() - err = status.get('status') - if err == 'ERROR': - raise SmartHomeError(ERR_WRONG_PIN, - 'Unable to execute {} for {} check your settings'.format(command, - self.state.entity_id)) + checkCode(self, command, r) + @register_trait @@ -812,7 +802,7 @@ def query_attributes(self): return response - def execute(self, command, params): + def execute(self, command, params, challenge): """Execute a color setting command.""" if "temperature" in params["color"]: tempRange = self.kelvinTempMax - self.kelvinTempMin @@ -897,10 +887,10 @@ def query_attributes(self): return response - def execute(self, command, params): + def execute(self, command, params, challenge): """Execute an ArmDisarm command.""" state = self.state.state - seccode = self.state.seccode + seccode = challenge.get('pin') if params["arm"]: if params["armLevel"] == "Arm Home": @@ -926,6 +916,12 @@ def execute(self, command, params): url = DOMOTICZ_URL + "/json.htm?type=command¶m=setsecstatus&secstatus=0&seccode=" + seccode r = requests.get(url, auth=CREDITS) + status = r.json() + err = status.get('status') + if err == 'ERROR': + raise SmartHomeErrorNoChallenge(ERR_CHALLENGE_NEEDED, 'challengeFailedPinNeeded', + 'Unable to execute {} for {} - challenge needed '.format( + command, self.state.entity_id)) @register_trait @@ -975,7 +971,7 @@ def _execute_volume_relative(self, params): int(current + relative * self.state.maxdimlevel / 100)) r = requests.get(url, auth=CREDITS) - def execute(self, command, params): + def execute(self, command, params, challenge): """Execute a volume command.""" if command == COMMAND_SET_VOLUME: self._execute_set_volume(params) @@ -1023,7 +1019,7 @@ def query_attributes(self): self.stream_info = {'cameraStreamAccessUrl': url} return self.stream_info or {} - def execute(self, command, params): + def execute(self, command, params, challenge): """Execute a get camera stream command.""" return @@ -1081,7 +1077,7 @@ def query_attributes(self): return response - def execute(self, command, params): + def execute(self, command, params, challenge): """Execute an SetModes command.""" levelName = base64.b64decode(self.state.selectorLevelName).decode('UTF-8').split("|") protected = self.state.protected @@ -1097,12 +1093,8 @@ def execute(self, command, params): r = requests.get(url, auth=CREDITS) if protected: - status = r.json() - err = status.get('status') - if err == 'ERROR': - raise SmartHomeError(ERR_WRONG_PIN, - 'Unable to execute {} for {} check your settings'.format(command, - self.state.entity_id)) + checkCode(self, command, r) + @register_trait class Timer(_Trait): @@ -1138,7 +1130,7 @@ def query_attributes(self): return response - def execute(self, command, params): + def execute(self, command, params, challenge): """Execute a Timer command.""" if command == COMMAND_TIMER_START: @@ -1210,7 +1202,7 @@ def query_attributes(self): return response - def execute(self, command, params): + def execute(self, command, params, challenge): """Execute a EnergyStorge command.""" # domain = self.state.domain # protected = self.state.protected @@ -1224,12 +1216,8 @@ def execute(self, command, params): # r = requests.get(url, auth=CREDITS) # if protected: - # status = r.json() - # err = status.get('status') - # if err == 'ERROR': - # raise SmartHomeError(ERR_WRONG_PIN, - # 'Unable to execute {} for {} check your settings'.format(command, - # self.state.entity_id)) + # checkCode(self, command, r) + @register_trait class HumiditySettingTrait(_Trait): @@ -1269,7 +1257,7 @@ def query_attributes(self): return response - def execute(self, command, params): + def execute(self, command, params, challenge): """Execute a humidity command.""" # domain = self.state.domain # protected = self.state.protected @@ -1282,12 +1270,8 @@ def execute(self, command, params): # r = requests.get(url, auth=CREDITS) # if protected: - # status = r.json() - # err = status.get('status') - # if err == 'ERROR': - # raise SmartHomeError(ERR_WRONG_PIN, - # 'Unable to execute {} for {} check your settings'.format(command, - # self.state.entity_id)) + # checkCode(self, command, r) + @register_trait class SensorStateTrait(_Trait): @@ -1395,7 +1379,7 @@ def query_attributes(self): # return response - # def execute(self, command, params): + # def execute(self, command, params, challenge): # """Execute an SetFanSpeed command.""" # modes = self.modes # protected = self.state.protected @@ -1411,9 +1395,5 @@ def query_attributes(self): # r = requests.get(url, auth=CREDITS) # if protected: - # status = r.json() - # err = status.get('status') - # if err == 'ERROR': - # raise SmartHomeError(ERR_WRONG_PIN, - # 'Unable to execute {} for {} check your settings'.format(command, - # self.state.entity_id)) + # checkCode(self, command, r) + From 310c246ab0b7800d71703bfc4a575f9bbb9cc66c Mon Sep 17 00:00:00 2001 From: DewGew <pierlar@hotmail.com> Date: Mon, 26 Jun 2023 14:28:10 +0200 Subject: [PATCH 09/13] Switchpass in config not needed --- templates/settings.html | 8 -------- 1 file changed, 8 deletions(-) diff --git a/templates/settings.html b/templates/settings.html index c283a85..284b72d 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -115,14 +115,6 @@ <h4 class="card-title">Domoticz Settings</h4> </div> </div> </div> - <div class="row"> - <div class="col-md-4"> - <div class="form-group"> - <label class="bmd-label-floating">Switch Protection Pass</label> - <input id="DomoticzswitchProtectionPass" name="DomoticzswitchProtectionPass" type="password" class="form-control" value="{{ conf.Domoticz.switchProtectionPass }}"> - </div> - </div> - </div> <div class="clearfix"></div> </form> </div> From 146867daaff6b701ac6237043f0be51f254d9b19 Mon Sep 17 00:00:00 2001 From: DewGew <pierlar@hotmail.com> Date: Mon, 26 Jun 2023 14:29:13 +0200 Subject: [PATCH 10/13] Switchpass not needed anymore --- config/default_config | 1 - 1 file changed, 1 deletion(-) diff --git a/config/default_config b/config/default_config index 793b779..116931c 100644 --- a/config/default_config +++ b/config/default_config @@ -46,7 +46,6 @@ Domoticz: roomplan: '0' username: 'username' password: 'password' - switchProtectionPass: '1234' #Set this to false if ask for pin function is not needed # Report low battry Low_battery_limit: 9 From c0e0bce3e2c459af6b09c0da8f74eac6392815c1 Mon Sep 17 00:00:00 2001 From: DewGew <pierlar@hotmail.com> Date: Mon, 26 Jun 2023 14:35:36 +0200 Subject: [PATCH 11/13] Update const.py --- const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/const.py b/const.py index f63c2bf..d976c47 100644 --- a/const.py +++ b/const.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Constants for Google Assistant.""" -VERSION = '1.23.8' +VERSION = '1.23.9' PUBLIC_URL = 'https://[your public url]' CONFIGFILE = 'config/config.yaml' LOGFILE = 'dzga.log' From e8f22b395f64e72f3aa63e3dea16f9f181305fe2 Mon Sep 17 00:00:00 2001 From: DewGew <pierlar@hotmail.com> Date: Thu, 27 Jul 2023 10:55:51 +0200 Subject: [PATCH 12/13] Fix for chromecast notification when using ssl #335 --- smarthome.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/smarthome.py b/smarthome.py index 43bb497..dc2ba9f 100644 --- a/smarthome.py +++ b/smarthome.py @@ -1197,8 +1197,11 @@ def play(self, s): #command "/play?soundfile.mp3@volume filename = scomm mp3_filename = FILE_DIR + "/sound/" + filename mp3 = Path(mp3_filename) + uses_ssl = ('use_ssl' in configuration and configuration['use_ssl'] is True) if mp3.is_file(): mp3_url = "http://" + IP_Address + ":" + IP_Port + "/sound?" + filename + if uses_ssl: + mp3_url = mp3_url.replace("http", "https") #make a query request for Get /sound rstatus, rmessage = SmartHomeReqHandler.playmedia(mp3_url,'audio/mp3','IDLE', 20) else: From 8c80e9a6b5167146e9d0d68385027a7da4a03226 Mon Sep 17 00:00:00 2001 From: DewGew <pierlar@hotmail.com> Date: Thu, 27 Jul 2023 11:00:55 +0200 Subject: [PATCH 13/13] Update const.py --- const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/const.py b/const.py index d976c47..e7f2d73 100644 --- a/const.py +++ b/const.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Constants for Google Assistant.""" -VERSION = '1.23.9' +VERSION = '1.23.10' PUBLIC_URL = 'https://[your public url]' CONFIGFILE = 'config/config.yaml' LOGFILE = 'dzga.log'