From 4339239c33fb61a531dcbb41f9c02097f0a3a454 Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Mon, 30 Aug 2021 01:16:00 +0200 Subject: [PATCH] Added more google traits and implemented execution function --- .../assistant/google/SmartHomeImpl.java | 66 ++++++++------- .../assistant/google/trait/DeviceTrait.java | 4 + .../google/trait/DeviceTraitFactory.java | 11 ++- .../google/trait/HumiditySettingTrait.java | 3 + .../assistant/google/trait/OnOffTrait.java | 82 +++++++++++++++++++ .../google/trait/OpenCloseTrait.java | 63 ++++++++++++++ .../google/trait/SensorStateTrait.java | 74 +++++++++++++++++ .../google/trait/TemperatureControlTrait.java | 3 + 8 files changed, 274 insertions(+), 32 deletions(-) create mode 100644 plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/OnOffTrait.java create mode 100644 plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/OpenCloseTrait.java create mode 100644 plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/SensorStateTrait.java diff --git a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/SmartHomeImpl.java b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/SmartHomeImpl.java index c03c883f..b97f9540 100644 --- a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/SmartHomeImpl.java +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/SmartHomeImpl.java @@ -24,13 +24,16 @@ import com.google.home.graph.v1.HomeGraphApiServiceProto; import com.google.protobuf.Struct; import com.google.protobuf.Value; import org.json.JSONObject; +import se.hal.EventControllerManager; import se.hal.HalContext; import se.hal.intf.HalAbstractDevice; import se.hal.plugin.assistant.google.trait.DeviceTrait; import se.hal.plugin.assistant.google.trait.DeviceTraitFactory; +import se.hal.plugin.assistant.google.trait.OnOffTrait; import se.hal.plugin.assistant.google.type.DeviceType; import se.hal.struct.Event; import se.hal.struct.Sensor; +import se.hal.struct.devicedata.OnOffEventData; import zutil.db.DBConnection; import zutil.log.LogUtil; import zutil.net.http.page.oauth.OAuth2Registry.TokenRegistrationListener; @@ -64,8 +67,6 @@ public class SmartHomeImpl extends SmartHomeApp implements TokenRegistrationList /** * https://developers.google.com/assistant/smarthome/reference/intent/sync - * - * TODO: https://developers.google.com/assistant/smarthome/traits/temperaturesetting */ @SuppressWarnings("unchecked") @Override @@ -124,10 +125,10 @@ public class SmartHomeImpl extends SmartHomeApp implements TokenRegistrationList // Set custom data - /*JSONObject customDataJson = new JSONObject(); + JSONObject customDataJson = new JSONObject(); customDataJson.put("type", device.getClass().getSimpleName()); customDataJson.put("id", device.getId()); - deviceBuilder.setCustomData(customDataJson);*/ + deviceBuilder.setCustomData(customDataJson); res.payload.devices[i] = deviceBuilder.build(); } @@ -181,12 +182,11 @@ public class SmartHomeImpl extends SmartHomeApp implements TokenRegistrationList try { logger.fine("Received query request for: type=" + deviceRequest.getId()); - String[] deviceIdArray = deviceRequest.getId().split("-"); - if (deviceIdArray.length != 2) - throw new IllegalArgumentException("Invalid device ID: " + deviceRequest.getId()); + if (!deviceRequest.getCustomData().containsKey("type") && !deviceRequest.getCustomData().containsKey("id")) + throw new IllegalArgumentException("Device Type and ID was no supplied in customData: " + deviceRequest.getId()); - String deviceTypeStr = deviceIdArray[0]; - long deviceId = Long.parseLong(deviceIdArray[1]); // Get the number in the id "Sensor-" + String deviceTypeStr = (String) deviceRequest.getCustomData().get("type"); + long deviceId = Long.parseLong((String) deviceRequest.getCustomData().get("id")); HalAbstractDevice device; switch (deviceTypeStr) { @@ -229,37 +229,47 @@ public class SmartHomeImpl extends SmartHomeApp implements TokenRegistrationList */ @Override public ExecuteResponse onExecute(ExecuteRequest executeRequest, Map headers) { - logger.fine("Received execute request."); + DBConnection db = HalContext.getDB(); ExecuteResponse res = new ExecuteResponse(); - List commandsResponse = new ArrayList<>(); - List successfulDevices = new ArrayList<>(); - Map states = new HashMap<>(); - ExecuteRequest.Inputs.Payload.Commands[] commands = - ((ExecuteRequest.Inputs) executeRequest.inputs[0]).payload.commands; -/* for (ExecuteRequest.Inputs.Payload.Commands command : commands) { - for (ExecuteRequest.Inputs.Payload.Commands.Devices device : command.devices) { + for (ExecuteRequest.Inputs.Payload.Commands command : ((ExecuteRequest.Inputs) executeRequest.inputs[0]).payload.commands) { + for (ExecuteRequest.Inputs.Payload.Commands.Devices deviceRequest : command.devices) { try { - states = database.execute(userId, device.id, command.execution[0]); - successfulDevices.add(device.id); - ReportState.makeRequest(this, userId, device.id, states); + if (!deviceRequest.getCustomData().containsKey("type") && !deviceRequest.getCustomData().containsKey("id")) + throw new IllegalArgumentException("Device Type and ID was no supplied in customData: " + deviceRequest.getId()); + + String deviceTypeStr = (String) deviceRequest.getCustomData().get("type"); + long deviceId = Long.parseLong((String) deviceRequest.getCustomData().get("id")); + + HalAbstractDevice device; + switch (deviceTypeStr) { + case "Sensor": device = Sensor.getSensor(db, deviceId); break; + case "Event": device = Event.getEvent(db, deviceId); break; + default: throw new IllegalArgumentException("Unknown device type: " + deviceTypeStr); + } + + for (ExecuteRequest.Inputs.Payload.Commands.Execution execution : command.execution) { + if ("action.devices.traits.OnOff".equals(execution.command)) { // TODO: This looks ugly! + new OnOffTrait().execute(device, execution); + } else + throw new UnsupportedOperationException("Unsupported command requested: " + execution.command); + } + + ExecuteResponse.Payload.Commands successfulCommands = new ExecuteResponse.Payload.Commands(); + successfulCommands.status = "SUCCESS"; + successfulCommands.ids = new String[]{deviceRequest.id}; + commandsResponse.add(successfulCommands); } catch (Exception e) { ExecuteResponse.Payload.Commands failedDevice = new ExecuteResponse.Payload.Commands(); - failedDevice.ids = new String[]{device.id}; + failedDevice.ids = new String[]{deviceRequest.id}; failedDevice.status = "ERROR"; failedDevice.setErrorCode(e.getMessage()); commandsResponse.add(failedDevice); } } - }*/ - - ExecuteResponse.Payload.Commands successfulCommands = new ExecuteResponse.Payload.Commands(); - successfulCommands.status = "SUCCESS"; - successfulCommands.setStates(states); - successfulCommands.ids = successfulDevices.toArray(new String[]{}); - commandsResponse.add(successfulCommands); + } res.requestId = executeRequest.requestId; ExecuteResponse.Payload payload = new ExecuteResponse.Payload( diff --git a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/DeviceTrait.java b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/DeviceTrait.java index ad748163..8a2dbec2 100644 --- a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/DeviceTrait.java +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/DeviceTrait.java @@ -24,6 +24,8 @@ package se.hal.plugin.assistant.google.trait; +import com.google.actions.api.smarthome.ExecuteRequest; +import se.hal.intf.HalAbstractDevice; import se.hal.intf.HalDeviceConfig; import se.hal.intf.HalDeviceData; @@ -42,4 +44,6 @@ public abstract class DeviceTrait { public abstract HashMap generateSyncResponse(HalDeviceConfig config); public abstract HashMap generateQueryResponse(HalDeviceData data); + + public void execute(HalAbstractDevice device, ExecuteRequest.Inputs.Payload.Commands.Execution execution) {} } diff --git a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/DeviceTraitFactory.java b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/DeviceTraitFactory.java index 6e3fafa1..c348c683 100644 --- a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/DeviceTraitFactory.java +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/DeviceTraitFactory.java @@ -46,17 +46,20 @@ public class DeviceTraitFactory { switch (device.getDeviceData().getClass().getName()) { case "se.hal.struct.devicedata.DimmerEventData": case "se.hal.struct.devicedata.OnOffEventData": - return new DeviceTrait[]{}; + return new DeviceTrait[]{new OnOffTrait()}; + + case "se.hal.struct.devicedata.OpenClosedEventData": + return new DeviceTrait[]{new OpenCloseTrait()}; case "se.hal.struct.devicedata.PowerConsumptionSensorData": case "se.hal.struct.devicedata.LightSensorData": - return new DeviceTrait[]{}; + return new DeviceTrait[]{new SensorStateTrait()}; case "se.hal.struct.devicedata.HumiditySensorData": - return new DeviceTrait[]{new HumiditySettingTrait()}; + return new DeviceTrait[]{new SensorStateTrait(), new HumiditySettingTrait()}; case "se.hal.struct.devicedata.TemperatureSensorData": - return new DeviceTrait[]{new TemperatureControlTrait()}; + return new DeviceTrait[]{new SensorStateTrait(), new TemperatureControlTrait()}; default: throw new IllegalArgumentException("Unregistered Sensor device data: " + device.getDeviceData()); diff --git a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/HumiditySettingTrait.java b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/HumiditySettingTrait.java index ec1e7019..e42b5b3c 100644 --- a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/HumiditySettingTrait.java +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/HumiditySettingTrait.java @@ -31,6 +31,9 @@ import se.hal.struct.devicedata.HumiditySensorData; import java.util.HashMap; +/** + * https://developers.google.com/assistant/smarthome/traits/humiditysetting + */ public class HumiditySettingTrait extends DeviceTrait { @Override diff --git a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/OnOffTrait.java b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/OnOffTrait.java new file mode 100644 index 00000000..c2b704fc --- /dev/null +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/OnOffTrait.java @@ -0,0 +1,82 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Ziver Koc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package se.hal.plugin.assistant.google.trait; + + +import com.google.actions.api.smarthome.ExecuteRequest; +import se.hal.EventControllerManager; +import se.hal.intf.HalAbstractDevice; +import se.hal.intf.HalDeviceConfig; +import se.hal.intf.HalDeviceData; +import se.hal.struct.Event; +import se.hal.struct.devicedata.OnOffEventData; +import se.hal.struct.devicedata.TemperatureSensorData; + +import java.util.HashMap; + + +/** + * https://developers.google.com/assistant/smarthome/traits/onoff + */ +public class OnOffTrait extends DeviceTrait { + + @Override + String getId() { + return "action.devices.traits.OnOff"; + } + + @Override + public HashMap generateSyncResponse(HalDeviceConfig config) { + HashMap response = new HashMap<>(); + response.put("commandOnlyOnOff", false); + response.put("queryOnlyOnOff", false); + return response; + } + + @Override + public HashMap generateQueryResponse(HalDeviceData data) { + HashMap response = new HashMap<>(); + + if (data instanceof OnOffEventData) { + response.put("on", ((OnOffEventData) data).isOn()); + } + + return response; + } + + @Override + public void execute(HalAbstractDevice device, ExecuteRequest.Inputs.Payload.Commands.Execution execution) { + if ("action.devices.commands.OnOff".equals(execution.command)) { + OnOffEventData eventData = new OnOffEventData(); + if ("on".equals(execution.getParams().get("on"))) + eventData.turnOn(); + else + eventData.turnOff(); + + device.setDeviceData(eventData); + EventControllerManager.getInstance().send((Event) device); + } + } +} diff --git a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/OpenCloseTrait.java b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/OpenCloseTrait.java new file mode 100644 index 00000000..7d85277a --- /dev/null +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/OpenCloseTrait.java @@ -0,0 +1,63 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Ziver Koc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package se.hal.plugin.assistant.google.trait; + + +import se.hal.intf.HalDeviceConfig; +import se.hal.intf.HalDeviceData; +import se.hal.struct.devicedata.OnOffEventData; +import se.hal.struct.devicedata.OpenClosedEventData; + +import java.util.HashMap; + + +/** + * https://developers.google.com/assistant/smarthome/traits/openclose + */ +public class OpenCloseTrait extends DeviceTrait { + + @Override + String getId() { + return "action.devices.traits.OpenClose"; + } + + @Override + public HashMap generateSyncResponse(HalDeviceConfig config) { + HashMap response = new HashMap<>(); + response.put("queryOnlyOnOff", true); + return response; + } + + @Override + public HashMap generateQueryResponse(HalDeviceData data) { + HashMap response = new HashMap<>(); + + if (data instanceof OpenClosedEventData) { + response.put("openPercent", ((OpenClosedEventData) data).isOpen() ? 100 : 0); + } + + return response; + } +} diff --git a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/SensorStateTrait.java b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/SensorStateTrait.java new file mode 100644 index 00000000..804bb3a8 --- /dev/null +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/SensorStateTrait.java @@ -0,0 +1,74 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020 Ziver Koc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package se.hal.plugin.assistant.google.trait; + + +import se.hal.intf.HalDeviceConfig; +import se.hal.intf.HalDeviceData; +import se.hal.struct.devicedata.OpenClosedEventData; + +import java.util.ArrayList; +import java.util.HashMap; + + +/** + * https://developers.google.com/assistant/smarthome/traits/openclose + */ +public class SensorStateTrait extends DeviceTrait { + + @Override + String getId() { + return "action.devices.traits.SensorState"; + } + + @Override + public HashMap generateSyncResponse(HalDeviceConfig config) { + HashMap response = new HashMap<>(); + ArrayList sensorStatesSupported = new ArrayList<>(); + + /*sensorStatesSupported.add(new HashMap() {{ + put("name", xxx); + put("maxThresholdCelsius", 60); + }});*/ + + response.put("sensorStatesSupported", sensorStatesSupported); + return response; + } + + @Override + public HashMap generateQueryResponse(HalDeviceData data) { + HashMap response = new HashMap<>(); + ArrayList currentSensorStateData = new ArrayList<>(); + + /*currentSensorStateData.add(new HashMap() {{ + put("name", xxx); + put("currentSensorState", xxx); + put("rawValue", xxx); + }});*/ + + response.put("currentSensorStateData", currentSensorStateData); + return response; + } +} diff --git a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/TemperatureControlTrait.java b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/TemperatureControlTrait.java index b0c053cb..c6130300 100644 --- a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/TemperatureControlTrait.java +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/TemperatureControlTrait.java @@ -32,6 +32,9 @@ import se.hal.struct.devicedata.TemperatureSensorData; import java.util.HashMap; +/** + * https://developers.google.com/assistant/smarthome/traits/temperaturecontrol + */ public class TemperatureControlTrait extends DeviceTrait { @Override