Added more google traits and implemented execution function
This commit is contained in:
parent
08fd1b6edd
commit
4339239c33
8 changed files with 274 additions and 32 deletions
|
|
@ -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-<number>"
|
||||
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<ExecuteResponse.Payload.Commands> commandsResponse = new ArrayList<>();
|
||||
List<String> successfulDevices = new ArrayList<>();
|
||||
Map<String, Object> 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(
|
||||
|
|
|
|||
|
|
@ -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<String, Object> generateSyncResponse(HalDeviceConfig config);
|
||||
|
||||
public abstract HashMap<String, Object> generateQueryResponse(HalDeviceData data);
|
||||
|
||||
public void execute(HalAbstractDevice device, ExecuteRequest.Inputs.Payload.Commands.Execution execution) {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<String, Object> generateSyncResponse(HalDeviceConfig config) {
|
||||
HashMap<String, Object> response = new HashMap<>();
|
||||
response.put("commandOnlyOnOff", false);
|
||||
response.put("queryOnlyOnOff", false);
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<String, Object> generateQueryResponse(HalDeviceData data) {
|
||||
HashMap<String, Object> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String, Object> generateSyncResponse(HalDeviceConfig config) {
|
||||
HashMap<String, Object> response = new HashMap<>();
|
||||
response.put("queryOnlyOnOff", true);
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<String, Object> generateQueryResponse(HalDeviceData data) {
|
||||
HashMap<String, Object> response = new HashMap<>();
|
||||
|
||||
if (data instanceof OpenClosedEventData) {
|
||||
response.put("openPercent", ((OpenClosedEventData) data).isOpen() ? 100 : 0);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String, Object> generateSyncResponse(HalDeviceConfig config) {
|
||||
HashMap<String, Object> response = new HashMap<>();
|
||||
ArrayList<HashMap> sensorStatesSupported = new ArrayList<>();
|
||||
|
||||
/*sensorStatesSupported.add(new HashMap<String, Object>() {{
|
||||
put("name", xxx);
|
||||
put("maxThresholdCelsius", 60);
|
||||
}});*/
|
||||
|
||||
response.put("sensorStatesSupported", sensorStatesSupported);
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<String, Object> generateQueryResponse(HalDeviceData data) {
|
||||
HashMap<String, Object> response = new HashMap<>();
|
||||
ArrayList<HashMap> currentSensorStateData = new ArrayList<>();
|
||||
|
||||
/*currentSensorStateData.add(new HashMap<String, Object>() {{
|
||||
put("name", xxx);
|
||||
put("currentSensorState", xxx);
|
||||
put("rawValue", xxx);
|
||||
}});*/
|
||||
|
||||
response.put("currentSensorStateData", currentSensorStateData);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue