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 8df37963..10cd3480 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 @@ -25,14 +25,16 @@ import com.google.actions.api.smarthome.*; import com.google.auth.oauth2.AccessToken; import com.google.auth.oauth2.GoogleCredentials; import com.google.home.graph.v1.DeviceProto; +import org.json.JSONObject; import se.hal.HalContext; -import se.hal.plugin.assistant.google.data.SmartHomeDeviceType; +import se.hal.plugin.assistant.google.trait.DeviceTrait; +import se.hal.plugin.assistant.google.trait.DeviceTraitFactory; +import se.hal.plugin.assistant.google.type.DeviceType; import se.hal.struct.Sensor; import zutil.db.DBConnection; import zutil.log.LogUtil; import zutil.net.http.page.oauth.OAuth2Registry.TokenRegistrationListener; -import se.hal.plugin.assistant.google.data.SmartHomeDeviceTrait; -import se.hal.plugin.assistant.google.data.SmartHomeDeviceType; + public class SmartHomeImpl extends SmartHomeApp implements TokenRegistrationListener { private static final Logger logger = LogUtil.getLogger(); @@ -81,12 +83,16 @@ public class SmartHomeImpl extends SmartHomeApp implements TokenRegistrationList res.payload.devices = new SyncResponse.Payload.Device[sensors.size()]; for (int i = 0; i < res.payload.devices.length; i++) { Sensor sensor = sensors.get(i); + DeviceType type = DeviceType.getType(sensor); + DeviceTrait[] traits = DeviceTraitFactory.getTraits(sensor); + + // Generate payload SyncResponse.Payload.Device.Builder deviceBuilder = new SyncResponse.Payload.Device.Builder() .setId("Sensor-" + sensor.getId()) - .setType(SmartHomeDeviceType.getType(sensor).toString()) - .setTraits(SmartHomeDeviceTrait.getTraitIds(sensor)) + .setType(type.toString()) + .setTraits(DeviceTraitFactory.getTraitIds(traits)) .setName( DeviceProto.DeviceNames.newBuilder() .setName(sensor.getName()) @@ -100,21 +106,17 @@ public class SmartHomeImpl extends SmartHomeApp implements TokenRegistrationList //.setHwVersion((String) device.get("hwVersion")) //.setSwVersion((String) device.get("swVersion")) .build()); - /*if (device.contains("attributes")) { - Map attributes = new HashMap<>(); - attributes.putAll((Map) device.get("attributes")); - String attributesJson = new Gson().toJson(attributes); - Struct.Builder attributeBuilder = Struct.newBuilder(); - try { - JsonFormat.parser().ignoringUnknownFields().merge(attributesJson, attributeBuilder); - } catch (Exception e) { - logger.error("FAILED TO BUILD"); + + JSONObject attribJson = new JSONObject(); + for (DeviceTrait trait : traits) { + for (Map.Entry entry : trait.generateSyncResponse(sensor.getDeviceConfig()).entrySet()) { + attribJson.put(entry.getKey(), entry.getValue()); } - deviceBuilder.setAttributes(attributeBuilder.build()); - }*/ + } + deviceBuilder.setAttributes(attribJson); + /*if (device.contains("customData")) { Map customData = new HashMap<>(); - customData.putAll((Map) device.get("customData")); String customDataJson = new Gson().toJson(customData); deviceBuilder.setCustomData(customDataJson); @@ -150,22 +152,12 @@ public class SmartHomeImpl extends SmartHomeApp implements TokenRegistrationList long sensorId = Long.parseLong(device.getId().substring(7)); // Get the number in the id "Sensor-" Sensor sensor = Sensor.getSensor(db, sensorId); + DeviceTrait[] traits = DeviceTraitFactory.getTraits(sensor); Map deviceState = new HashMap<>(); - switch (sensor.getDeviceData().getClass().getName()) { - case "se.hal.struct.devicedata.HumiditySensorData": - deviceState.put("humidity", sensor.getDeviceData().getData()); - break; - case "se.hal.struct.devicedata.LightSensorData": - deviceState.put("light", sensor.getDeviceData().getData()); - break; - case "se.hal.struct.devicedata.PowerConsumptionSensorData": - deviceState.put("power", sensor.getDeviceData().getData()); - break; - case "se.hal.struct.devicedata.TemperatureSensorData": - deviceState.put("temperature", sensor.getDeviceData().getData()); - break; + for (DeviceTrait trait : traits) { + deviceState.putAll(trait.generateQueryResponse(sensor.getDeviceData())); } deviceState.put("status", "SUCCESS"); diff --git a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/data/SmartHomeDeviceTrait.java b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/data/SmartHomeDeviceTrait.java deleted file mode 100644 index 5652687a..00000000 --- a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/data/SmartHomeDeviceTrait.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * 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. - */ - -/* - * 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.data; - -import se.hal.struct.Sensor; - -import java.util.ArrayList; -import java.util.List; - -/** - * Enum for https://developers.google.com/assistant/smarthome/traits - */ -public enum SmartHomeDeviceTrait { - AppSelector("action.devices.traits.AppSelector"), - ArmDisarm("action.devices.traits.ArmDisarm"), - Brightness("action.devices.traits.Brightness"), - CameraStream("action.devices.traits.CameraStream"), - Channel("action.devices.traits.Channel"), - ColorSetting("action.devices.traits.ColorSetting"), - Cook("action.devices.traits.Cook"), - Dispense("action.devices.traits.Dispense"), - Dock("action.devices.traits.Dock"), - EnergyStorage("action.devices.traits.EnergyStorage"), - FanSpeed("action.devices.traits.FanSpeed"), - Fill("action.devices.traits.Fill"), - HumiditySetting("action.devices.traits.HumiditySetting"), - InputSelector("action.devices.traits.InputSelector"), - LightEffects("action.devices.traits.LightEffects"), - Locator("action.devices.traits.Locator"), - LockUnlock("action.devices.traits.LockUnlock"), - MediaState("action.devices.traits.MediaState"), - Modes("action.devices.traits.Modes"), - NetworkControl("action.devices.traits.NetworkControl"), - OnOff("action.devices.traits.OnOff"), - OpenClose("action.devices.traits.OpenClose"), - Reboot("action.devices.traits.Reboot"), - Rotation("action.devices.traits.Rotation"), - RunCycle("action.devices.traits.RunCycle"), - SensorState("action.devices.traits.SensorState"), - Scene("action.devices.traits.Scene"), - SoftwareUpdate("action.devices.traits.SoftwareUpdate"), - StartStop("action.devices.traits.StartStop"), - StatusReport("action.devices.traits.StatusReport"), - TemperatureControl("action.devices.traits.TemperatureControl"), - TemperatureSetting("action.devices.traits.TemperatureSetting"), - Timer("action.devices.traits.Timer"), - Toggles("action.devices.traits.Toggles"), - TransportControl("action.devices.traits.TransportControl"), - Volume("action.devices.traits.Volume"); - - - - private final String typeId; - - - SmartHomeDeviceTrait(String typeId) { - this.typeId = typeId; - } - - - public String toString() { - return typeId; - } - - - public static SmartHomeDeviceTrait[] getTraits(Sensor sensor) { - switch (sensor.getDeviceData().getClass().getName()) { - case "se.hal.struct.devicedata.DimmerEventData": - case "se.hal.struct.devicedata.SwitchEventData": - return new SmartHomeDeviceTrait[]{OnOff}; - - case "se.hal.struct.devicedata.PowerConsumptionSensorData": - case "se.hal.struct.devicedata.HumiditySensorData": - case "se.hal.struct.devicedata.LightSensorData": - return new SmartHomeDeviceTrait[]{SensorState}; - - case "se.hal.struct.devicedata.TemperatureSensorData": - return new SmartHomeDeviceTrait[]{TemperatureSetting}; - - default: - throw new IllegalArgumentException("Unregistered Sensor device data: " + sensor.getDeviceData()); - } - } - - public static List getTraitIds(Sensor sensor) { - List list = new ArrayList<>(); - - for (SmartHomeDeviceTrait trait : getTraits(sensor)) { - list.add(trait.toString()); - } - - return list; - } -} 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 new file mode 100644 index 00000000..306027ab --- /dev/null +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/DeviceTrait.java @@ -0,0 +1,45 @@ +/* + * 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.HalDeviceData; +import se.hal.intf.HalSensorConfig; + +import java.util.HashMap; + +/** + * https://developers.google.com/assistant/smarthome/traits + */ +public abstract class DeviceTrait { + + /** + * @return the API specific ID of this trait + */ + abstract String getId(); + + public abstract HashMap generateSyncResponse(HalSensorConfig config); + + public abstract HashMap generateQueryResponse(HalDeviceData data); +} 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 new file mode 100644 index 00000000..d6785a12 --- /dev/null +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/DeviceTraitFactory.java @@ -0,0 +1,70 @@ +/* + * 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.struct.Sensor; + +import java.util.ArrayList; +import java.util.List; + +/** + * A factory class that will associate traits to Hal devices + */ +public class DeviceTraitFactory { + + private DeviceTraitFactory() {} + + + public static DeviceTrait[] getTraits(Sensor sensor) { + switch (sensor.getDeviceData().getClass().getName()) { + case "se.hal.struct.devicedata.DimmerEventData": + case "se.hal.struct.devicedata.SwitchEventData": + return new DeviceTrait[]{}; + + case "se.hal.struct.devicedata.PowerConsumptionSensorData": + case "se.hal.struct.devicedata.LightSensorData": + return new DeviceTrait[]{}; + + case "se.hal.struct.devicedata.HumiditySensorData": + return new DeviceTrait[]{new HumiditySettingTrait()}; + + case "se.hal.struct.devicedata.TemperatureSensorData": + return new DeviceTrait[]{new TemperatureControlTrait()}; + + default: + throw new IllegalArgumentException("Unregistered Sensor device data: " + sensor.getDeviceData()); + } + } + + public static List getTraitIds(DeviceTrait[] traits) { + List list = new ArrayList<>(traits.length); + + for (DeviceTrait trait : traits) { + list.add(trait.getId()); + } + + return list; + } +} 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 new file mode 100644 index 00000000..78038df1 --- /dev/null +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/HumiditySettingTrait.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.HalDeviceData; +import se.hal.intf.HalSensorConfig; +import se.hal.struct.devicedata.TemperatureSensorData; + +import java.util.HashMap; + +public class HumiditySettingTrait extends DeviceTrait { + + @Override + String getId() { + return "action.devices.traits.HumiditySetting"; + } + + @Override + public HashMap generateSyncResponse(HalSensorConfig config) { + HashMap response = new HashMap<>(); + //response.put("humiditySetpointRange", new HashMap() {{ + // put("minPercent", -20); + // put("maxPercent", 60); + //}}); + //response.put("commandOnlyHumiditySetting", false); + response.put("queryOnlyHumiditySetting", false); + return response; + } + + @Override + public HashMap generateQueryResponse(HalDeviceData data) { + HashMap response = new HashMap<>(); + + if (data instanceof TemperatureSensorData) { + //response.put("humiditySetpointPercent", data.getData()); + response.put("humidityAmbientPercent", data.getData()); + } + + 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 new file mode 100644 index 00000000..2246f34d --- /dev/null +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/trait/TemperatureControlTrait.java @@ -0,0 +1,66 @@ +/* + * 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.HalDeviceData; +import se.hal.intf.HalSensorConfig; +import se.hal.struct.devicedata.TemperatureSensorData; + +import java.util.HashMap; + +public class TemperatureControlTrait extends DeviceTrait { + + @Override + String getId() { + return "action.devices.traits.TemperatureControl"; + } + + @Override + public HashMap generateSyncResponse(HalSensorConfig config) { + HashMap response = new HashMap<>(); + response.put("temperatureRange", new HashMap() {{ + put("minThresholdCelsius", -20); + put("maxThresholdCelsius", 60); + }}); + //response.put("temperatureStepCelsius", 0.5); + response.put("temperatureUnitForUX", "C"); + //response.put("commandOnlyTemperatureControl", false); + response.put("queryOnlyTemperatureControl", true); + return response; + } + + @Override + public HashMap generateQueryResponse(HalDeviceData data) { + HashMap response = new HashMap<>(); + + if (data instanceof TemperatureSensorData) { + //response.put("temperatureSetpointCelsius", data.getData()); + response.put("temperatureAmbientCelsius", data.getData()); + } + + return response; + } +} diff --git a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/data/SmartHomeDeviceType.java b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/type/DeviceType.java similarity index 97% rename from plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/data/SmartHomeDeviceType.java rename to plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/type/DeviceType.java index 0c7622cc..2c36330b 100644 --- a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/data/SmartHomeDeviceType.java +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/type/DeviceType.java @@ -46,14 +46,14 @@ * THE SOFTWARE. */ -package se.hal.plugin.assistant.google.data; +package se.hal.plugin.assistant.google.type; import se.hal.struct.Sensor; /** * Enum for https://developers.google.com/assistant/smarthome/types */ -public enum SmartHomeDeviceType { +public enum DeviceType { AC_UNIT("action.devices.types.AC_UNIT"), AIRCOOLER("action.devices.types.AIRCOOLER"), AIRFRESHENER("action.devices.types.AIRFRESHENER"), @@ -136,7 +136,7 @@ public enum SmartHomeDeviceType { private final String typeId; - private SmartHomeDeviceType(String typeId) { + private DeviceType(String typeId) { this.typeId = typeId; } @@ -146,7 +146,7 @@ public enum SmartHomeDeviceType { } - public static SmartHomeDeviceType getType(Sensor sensor) { + public static DeviceType getType(Sensor sensor) { switch (sensor.getDeviceData().getClass().getName()) { case "se.hal.struct.devicedata.DimmerEventData": case "se.hal.struct.devicedata.SwitchEventData":