Separated traits into their own classes, added humidity

This commit is contained in:
Ziver Koc 2020-12-08 23:15:20 +01:00
parent a968c1a91e
commit d7a14a4899
7 changed files with 270 additions and 174 deletions

View file

@ -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<String, Object> attributes = new HashMap<>();
attributes.putAll((Map<String, Object>) 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<String,Object> entry : trait.generateSyncResponse(sensor.getDeviceConfig()).entrySet()) {
attribJson.put(entry.getKey(), entry.getValue());
}
deviceBuilder.setAttributes(attributeBuilder.build());
}*/
}
deviceBuilder.setAttributes(attribJson);
/*if (device.contains("customData")) {
Map<String, Object> customData = new HashMap<>();
customData.putAll((Map<String, Object>) 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-<number>"
Sensor sensor = Sensor.getSensor(db, sensorId);
DeviceTrait[] traits = DeviceTraitFactory.getTraits(sensor);
Map<String, Object> 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");

View file

@ -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<String> getTraitIds(Sensor sensor) {
List<String> list = new ArrayList<>();
for (SmartHomeDeviceTrait trait : getTraits(sensor)) {
list.add(trait.toString());
}
return list;
}
}

View file

@ -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<String, Object> generateSyncResponse(HalSensorConfig config);
public abstract HashMap<String, Object> generateQueryResponse(HalDeviceData data);
}

View file

@ -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<String> getTraitIds(DeviceTrait[] traits) {
List<String> list = new ArrayList<>(traits.length);
for (DeviceTrait trait : traits) {
list.add(trait.getId());
}
return list;
}
}

View file

@ -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<String, Object> generateSyncResponse(HalSensorConfig config) {
HashMap<String, Object> response = new HashMap<>();
//response.put("humiditySetpointRange", new HashMap<String, Object>() {{
// put("minPercent", -20);
// put("maxPercent", 60);
//}});
//response.put("commandOnlyHumiditySetting", false);
response.put("queryOnlyHumiditySetting", false);
return response;
}
@Override
public HashMap<String, Object> generateQueryResponse(HalDeviceData data) {
HashMap<String, Object> response = new HashMap<>();
if (data instanceof TemperatureSensorData) {
//response.put("humiditySetpointPercent", data.getData());
response.put("humidityAmbientPercent", data.getData());
}
return response;
}
}

View file

@ -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<String, Object> generateSyncResponse(HalSensorConfig config) {
HashMap<String, Object> response = new HashMap<>();
response.put("temperatureRange", new HashMap<String, Object>() {{
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<String, Object> generateQueryResponse(HalDeviceData data) {
HashMap<String, Object> response = new HashMap<>();
if (data instanceof TemperatureSensorData) {
//response.put("temperatureSetpointCelsius", data.getData());
response.put("temperatureAmbientCelsius", data.getData());
}
return response;
}
}

View file

@ -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":