Added header parameters to JSON pages, Some cleanup of google assistant example code
This commit is contained in:
parent
0632804bd4
commit
9bca47d566
13 changed files with 806 additions and 15 deletions
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* Copyright 2019 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package se.hal.plugin.assistant.google;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.actions.api.smarthome.*;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.home.graph.v1.DeviceProto;
|
||||
import com.google.protobuf.Struct;
|
||||
import com.google.protobuf.util.JsonFormat;
|
||||
import zutil.log.LogUtil;
|
||||
|
||||
|
||||
public class MySmartHomeApp extends SmartHomeApp {
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
|
||||
@Override
|
||||
public SyncResponse onSync(SyncRequest syncRequest, Map<?, ?> headers) {
|
||||
|
||||
SyncResponse res = new SyncResponse();
|
||||
res.setRequestId(syncRequest.requestId);
|
||||
res.setPayload(new SyncResponse.Payload());
|
||||
|
||||
int numOfDevices = 0;
|
||||
res.payload.devices = new SyncResponse.Payload.Device[numOfDevices];
|
||||
for (int i = 0; i < numOfDevices; i++) {
|
||||
|
||||
SyncResponse.Payload.Device.Builder deviceBuilder =
|
||||
new SyncResponse.Payload.Device.Builder()
|
||||
.setId(device.getId())
|
||||
.setType((String) device.get("type"))
|
||||
.setTraits((List<String>) device.get("traits"))
|
||||
.setName(
|
||||
DeviceProto.DeviceNames.newBuilder()
|
||||
.addAllDefaultNames((List<String>) device.get("defaultNames"))
|
||||
.setName((String) device.get("name"))
|
||||
.addAllNicknames((List<String>) device.get("nicknames"))
|
||||
.build())
|
||||
.setWillReportState((Boolean) device.get("willReportState"))
|
||||
.setRoomHint((String) device.get("roomHint"))
|
||||
.setDeviceInfo(
|
||||
DeviceProto.DeviceInfo.newBuilder()
|
||||
.setManufacturer((String) device.get("manufacturer"))
|
||||
.setModel((String) device.get("model"))
|
||||
.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");
|
||||
}
|
||||
deviceBuilder.setAttributes(attributeBuilder.build());
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (device.contains("otherDeviceIds")) {
|
||||
deviceBuilder.setOtherDeviceIds((List) device.get("otherDeviceIds"));
|
||||
}
|
||||
res.payload.devices[i] = deviceBuilder.build();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResponse onQuery(QueryRequest queryRequest, Map<?, ?> headers) {
|
||||
QueryRequest.Inputs.Payload.Device[] devices = ((QueryRequest.Inputs) queryRequest.getInputs()[0]).payload.devices;
|
||||
QueryResponse res = new QueryResponse();
|
||||
res.setRequestId(queryRequest.requestId);
|
||||
res.setPayload(new QueryResponse.Payload());
|
||||
|
||||
Map<String, Map<String, Object>> deviceStates = new HashMap<>();
|
||||
for (QueryRequest.Inputs.Payload.Device device : devices) {
|
||||
try {
|
||||
Map<String, Object> deviceState = database.getState(userId, device.id);
|
||||
deviceState.put("status", "SUCCESS");
|
||||
deviceStates.put(device.id, deviceState);
|
||||
} catch (Exception e) {
|
||||
logger.error("QUERY FAILED: {}", e);
|
||||
Map<String, Object> failedDevice = new HashMap<>();
|
||||
failedDevice.put("status", "ERROR");
|
||||
failedDevice.put("errorCode", "deviceOffline");
|
||||
deviceStates.put(device.id, failedDevice);
|
||||
}
|
||||
}
|
||||
res.payload.setDevices(deviceStates);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecuteResponse onExecute(ExecuteRequest executeRequest, Map<?, ?> headers) {
|
||||
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) {
|
||||
try {
|
||||
states = database.execute(userId, device.id, command.execution[0]);
|
||||
successfulDevices.add(device.id);
|
||||
ReportState.makeRequest(this, userId, device.id, states);
|
||||
} catch (Exception e) {
|
||||
if (e.getMessage().equals("PENDING")) {
|
||||
ExecuteResponse.Payload.Commands pendingDevice = new ExecuteResponse.Payload.Commands();
|
||||
pendingDevice.ids = new String[]{device.id};
|
||||
pendingDevice.status = "PENDING";
|
||||
commandsResponse.add(pendingDevice);
|
||||
continue;
|
||||
}
|
||||
if (e.getMessage().equals("pinNeeded")) {
|
||||
ExecuteResponse.Payload.Commands failedDevice = new ExecuteResponse.Payload.Commands();
|
||||
failedDevice.ids = new String[]{device.id};
|
||||
failedDevice.status = "ERROR";
|
||||
failedDevice.setErrorCode("challengeNeeded");
|
||||
failedDevice.setChallengeNeeded(
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("type", "pinNeeded");
|
||||
}
|
||||
});
|
||||
failedDevice.setErrorCode(e.getMessage());
|
||||
commandsResponse.add(failedDevice);
|
||||
continue;
|
||||
}
|
||||
if (e.getMessage().equals("challengeFailedPinNeeded")) {
|
||||
ExecuteResponse.Payload.Commands failedDevice = new ExecuteResponse.Payload.Commands();
|
||||
failedDevice.ids = new String[]{device.id};
|
||||
failedDevice.status = "ERROR";
|
||||
failedDevice.setErrorCode("challengeNeeded");
|
||||
failedDevice.setChallengeNeeded(
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("type", "challengeFailedPinNeeded");
|
||||
}
|
||||
});
|
||||
failedDevice.setErrorCode(e.getMessage());
|
||||
commandsResponse.add(failedDevice);
|
||||
continue;
|
||||
}
|
||||
if (e.getMessage().equals("ackNeeded")) {
|
||||
ExecuteResponse.Payload.Commands failedDevice = new ExecuteResponse.Payload.Commands();
|
||||
failedDevice.ids = new String[]{device.id};
|
||||
failedDevice.status = "ERROR";
|
||||
failedDevice.setErrorCode("challengeNeeded");
|
||||
failedDevice.setChallengeNeeded(
|
||||
new HashMap<String, String>() {
|
||||
{
|
||||
put("type", "ackNeeded");
|
||||
}
|
||||
});
|
||||
failedDevice.setErrorCode(e.getMessage());
|
||||
commandsResponse.add(failedDevice);
|
||||
continue;
|
||||
}
|
||||
|
||||
ExecuteResponse.Payload.Commands failedDevice = new ExecuteResponse.Payload.Commands();
|
||||
failedDevice.ids = new String[]{device.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(
|
||||
commandsResponse.toArray(new ExecuteResponse.Payload.Commands[]{}));
|
||||
res.setPayload(payload);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect(DisconnectRequest disconnectRequest, Map<?, ?> headers) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package se.hal.plugin.assistant.google;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.actions.api.smarthome.SmartHomeApp;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.home.graph.v1.HomeGraphApiServiceProto;
|
||||
import com.google.protobuf.Struct;
|
||||
import com.google.protobuf.Value;
|
||||
import com.google.protobuf.util.JsonFormat;
|
||||
import zutil.log.LogUtil;
|
||||
|
||||
/**
|
||||
* A singleton class to encapsulate state reporting behavior with changing ColorSetting state
|
||||
* values.
|
||||
*/
|
||||
final class ReportState {
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
|
||||
|
||||
private ReportState() {}
|
||||
|
||||
/**
|
||||
* Creates and completes a ReportStateAndNotification request
|
||||
*
|
||||
* @param actionsApp The SmartHomeApp instance to use to make the gRPC request
|
||||
* @param userId The agent user ID
|
||||
* @param deviceId The device ID
|
||||
* @param states A Map of state keys and their values for the provided device ID
|
||||
*/
|
||||
public static void makeRequest(SmartHomeApp actionsApp, String userId, String deviceId, Map<String, Object> states) {
|
||||
// Convert a Map of states to a JsonObject
|
||||
JsonObject jsonStates = (JsonObject) JsonParser.parseString(new Gson().toJson(states));
|
||||
ReportState.makeRequest(actionsApp, userId, deviceId, jsonStates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and completes a ReportStateAndNotification request
|
||||
*
|
||||
* @param actionsApp The SmartHomeApp instance to use to make the gRPC request
|
||||
* @param userId The agent user ID
|
||||
* @param deviceId The device ID
|
||||
* @param states A JSON object of state keys and their values for the provided device ID
|
||||
*/
|
||||
public static void makeRequest(SmartHomeApp actionsApp, String userId, String deviceId, JsonObject states) {
|
||||
// Do state name replacement for ColorSetting trait
|
||||
// See https://developers.google.com/assistant/smarthome/traits/colorsetting#device-states
|
||||
JsonObject colorJson = states.getAsJsonObject("color");
|
||||
if (colorJson != null && colorJson.has("spectrumRgb")) {
|
||||
colorJson.add("spectrumRGB", colorJson.get("spectrumRgb"));
|
||||
colorJson.remove("spectrumRgb");
|
||||
}
|
||||
Struct.Builder statesStruct = Struct.newBuilder();
|
||||
try {
|
||||
JsonFormat.parser().ignoringUnknownFields().merge(new Gson().toJson(states), statesStruct);
|
||||
} catch (Exception e) {
|
||||
logger.severe("Failed to build json");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
HomeGraphApiServiceProto.ReportStateAndNotificationDevice.Builder deviceBuilder =
|
||||
HomeGraphApiServiceProto.ReportStateAndNotificationDevice.newBuilder()
|
||||
.setStates(
|
||||
Struct.newBuilder()
|
||||
.putFields(deviceId, Value.newBuilder().setStructValue(statesStruct).build()));
|
||||
|
||||
HomeGraphApiServiceProto.ReportStateAndNotificationRequest request =
|
||||
HomeGraphApiServiceProto.ReportStateAndNotificationRequest.newBuilder()
|
||||
.setRequestId(String.valueOf(Math.random()))
|
||||
.setAgentUserId(userId) // our single user's id
|
||||
.setPayload(
|
||||
HomeGraphApiServiceProto.StateAndNotificationPayload.newBuilder()
|
||||
.setDevices(deviceBuilder))
|
||||
.build();
|
||||
|
||||
actionsApp.reportState(request);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
private SmartHomeDeviceTrait(String typeId) {
|
||||
this.typeId = typeId;
|
||||
}
|
||||
|
||||
public String getString() {
|
||||
return typeId;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Enum for https://developers.google.com/assistant/smarthome/types
|
||||
*/
|
||||
public enum SmartHomeDeviceType {
|
||||
AC_UNIT("action.devices.types.AC_UNIT"),
|
||||
AIRCOOLER("action.devices.types.AIRCOOLER"),
|
||||
AIRFRESHENER("action.devices.types.AIRFRESHENER"),
|
||||
AIRPURIFIER("action.devices.types.AIRPURIFIER"),
|
||||
AUDIO_VIDEO_RECEIVER("action.devices.types.AUDIO_VIDEO_RECEIVER"),
|
||||
AWNING("action.devices.types.AWNING"),
|
||||
BATHTUB("action.devices.types.BATHTUB"),
|
||||
BED("action.devices.types.BED"),
|
||||
BLENDER("action.devices.types.BLENDER"),
|
||||
BLINDS("action.devices.types.BLINDS"),
|
||||
BOILER("action.devices.types.BOILER"),
|
||||
CAMERA("action.devices.types.CAMERA"),
|
||||
CHARGER("action.devices.types.CHARGER"),
|
||||
CLOSET("action.devices.types.CLOSET"),
|
||||
COFFEE_MAKER("action.devices.types.COFFEE_MAKER"),
|
||||
COOKTOP("action.devices.types.COOKTOP"),
|
||||
CURTAIN("action.devices.types.CURTAIN"),
|
||||
DEHUMIDIFIER("action.devices.types.DEHUMIDIFIER"),
|
||||
DEHYDRATOR("action.devices.types.DEHYDRATOR"),
|
||||
DISHWASHERv("action.devices.types.DISHWASHER"),
|
||||
DOOR("action.devices.types.DOOR"),
|
||||
DRAWER("action.devices.types.DRAWER"),
|
||||
DRYER("action.devices.types.DRYER"),
|
||||
FAN("action.devices.types.FAN"),
|
||||
FAUCET("action.devices.types.FAUCET"),
|
||||
FIREPLACE("action.devices.types.FIREPLACE"),
|
||||
FREEZER("action.devices.types.FREEZER"),
|
||||
FRYER("action.devices.types.FRYER"),
|
||||
GARAGE("action.devices.types.GARAGE"),
|
||||
GATE("action.devices.types.GATE"),
|
||||
GRILL("action.devices.types.GRILL"),
|
||||
HEATER("action.devices.types.HEATER"),
|
||||
HOOD("action.devices.types.HOOD"),
|
||||
HUMIDIFIER("action.devices.types.HUMIDIFIER"),
|
||||
KETTLE("action.devices.types.KETTLE"),
|
||||
LIGHT("action.devices.types.LIGHT"),
|
||||
LOCK("action.devices.types.LOCK"),
|
||||
REMOTECONTROL("action.devices.types.REMOTECONTROL"),
|
||||
MOP("action.devices.types.MOP"),
|
||||
MOWER("action.devices.types.MOWER"),
|
||||
MICROWAVE("action.devices.types.MICROWAVE"),
|
||||
MULTICOOKER("action.devices.types.MULTICOOKER"),
|
||||
NETWORK("action.devices.types.NETWORK"),
|
||||
OUTLET("action.devices.types.OUTLET"),
|
||||
OVEN("action.devices.types.OVEN"),
|
||||
PERGOLA("action.devices.types.PERGOLA"),
|
||||
PETFEEDER("action.devices.types.PETFEEDER"),
|
||||
PRESSURECOOKER("action.devices.types.PRESSURECOOKER"),
|
||||
RADIATOR("action.devices.types.RADIATOR"),
|
||||
REFRIGERATOR("action.devices.types.REFRIGERATOR"),
|
||||
ROUTER("action.devices.types.ROUTER"),
|
||||
SCENE("action.devices.types.SCENE"),
|
||||
SENSOR("action.devices.types.SENSOR"),
|
||||
SECURITYSYSTEM("action.devices.types.SECURITYSYSTEM"),
|
||||
SETTOP("action.devices.types.SETTOP"),
|
||||
SHUTTER("action.devices.types.SHUTTER"),
|
||||
SHOWER("action.devices.types.SHOWER"),
|
||||
SMOKE_DETECTOR("action.devices.types.SMOKE_DETECTOR"),
|
||||
SOUSVIDE("action.devices.types.SOUSVIDE"),
|
||||
SPEAKER("action.devices.types.SPEAKER"),
|
||||
STREAMING_BOX("action.devices.types.STREAMING_BOX"),
|
||||
STREAMING_STICK("action.devices.types.STREAMING_STICK"),
|
||||
STREAMING_SOUNDBAR("action.devices.types.STREAMING_SOUNDBAR"),
|
||||
SOUNDBAR("action.devices.types.SOUNDBAR"),
|
||||
SPRINKLER("action.devices.types.SPRINKLER"),
|
||||
STANDMIXER("action.devices.types.STANDMIXER"),
|
||||
SWITCH("action.devices.types.SWITCH"),
|
||||
TV("action.devices.types.TV"),
|
||||
THERMOSTAT("action.devices.types.THERMOSTAT"),
|
||||
VACUUM("action.devices.types.VACUUM"),
|
||||
VALVE("action.devices.types.VALVE"),
|
||||
WASHER("action.devices.types.WASHER"),
|
||||
WATERHEATER("action.devices.types.WATERHEATER"),
|
||||
WATERPURIFIER("action.devices.types.WATERPURIFIER"),
|
||||
WATERSOFTENER("action.devices.types.WATERSOFTENER"),
|
||||
WINDOW("action.devices.types.WINDOW"),
|
||||
YOGURTMAKER("action.devices.types.YOGURTMAKER");
|
||||
|
||||
|
||||
private final String typeId;
|
||||
|
||||
private SmartHomeDeviceType(String typeId) {
|
||||
this.typeId = typeId;
|
||||
}
|
||||
|
||||
public String getString() {
|
||||
return typeId;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2019 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package se.hal.plugin.assistant.google.endpoint;
|
||||
|
||||
import se.hal.intf.HalJsonPage;
|
||||
import zutil.net.http.HttpHeader;
|
||||
import zutil.net.http.HttpPrintStream;
|
||||
import zutil.parser.DataNode;
|
||||
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class FakeAuthServlet extends HalJsonPage {
|
||||
|
||||
public FakeAuthServlet() {
|
||||
super("api/assistant/google/auth");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataNode jsonRespond(
|
||||
HttpPrintStream out,
|
||||
HttpHeader headers,
|
||||
Map<String,Object> session,
|
||||
Map<String,String> cookie,
|
||||
Map<String,String> request) throws Exception {
|
||||
|
||||
StringBuilder redirectURL = new StringBuilder();
|
||||
redirectURL.append(URLDecoder.decode(request.get("redirect_uri"), StandardCharsets.UTF_8));
|
||||
redirectURL.append("?");
|
||||
redirectURL.append("code=").append("xxxxxx");
|
||||
redirectURL.append("state=").append(request.get("state"));
|
||||
|
||||
out.setStatusCode(302);
|
||||
out.setHeader("Location", URLEncoder.encode("/login?responseurl=" + redirectURL.toString(), StandardCharsets.UTF_8));
|
||||
|
||||
return new DataNode(DataNode.DataType.Map);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2019 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package se.hal.plugin.assistant.google.endpoint;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import se.hal.intf.HalJsonPage;
|
||||
import zutil.net.http.HttpHeader;
|
||||
import zutil.net.http.HttpPrintStream;
|
||||
import zutil.parser.DataNode;
|
||||
|
||||
|
||||
public class FakeTokenServlet extends HalJsonPage {
|
||||
private static int secondsInDay = 86400;
|
||||
|
||||
public FakeTokenServlet() {
|
||||
super("api/assistant/google/auth_token");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataNode jsonRespond(
|
||||
HttpPrintStream out,
|
||||
HttpHeader headers,
|
||||
Map<String,Object> session,
|
||||
Map<String,String> cookie,
|
||||
Map<String,String> request) throws Exception {
|
||||
|
||||
String grantType = request.get("grant_type");
|
||||
|
||||
DataNode jsonRes = new DataNode(DataNode.DataType.Map);
|
||||
jsonRes.set("token_type", "bearer");
|
||||
jsonRes.set("access_token", "123access");
|
||||
jsonRes.set("expires_in", secondsInDay);
|
||||
|
||||
if (grantType.equals("authorization_code")) {
|
||||
jsonRes.set("refresh_token", "123refresh");
|
||||
}
|
||||
|
||||
return jsonRes;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2019 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package se.hal.plugin.assistant.google.endpoint;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.actions.api.smarthome.SmartHomeApp;
|
||||
import com.google.auth.oauth2.GoogleCredentials;
|
||||
import se.hal.intf.HalJsonPage;
|
||||
import se.hal.plugin.assistant.google.MySmartHomeApp;
|
||||
import zutil.io.IOUtil;
|
||||
import zutil.log.LogUtil;
|
||||
import zutil.net.http.HttpHeader;
|
||||
import zutil.net.http.HttpPrintStream;
|
||||
import zutil.parser.DataNode;
|
||||
|
||||
/**
|
||||
* Handles request received via HTTP POST and delegates it to your Actions app. See: [Request
|
||||
* handling in Google App
|
||||
* Engine](https://cloud.google.com/appengine/docs/standard/java/how-requests-are-handled).
|
||||
*/
|
||||
public class SmartHomeServlet extends HalJsonPage {
|
||||
private static final Logger logger = LogUtil.getLogger();
|
||||
private final SmartHomeApp actionsApp = new MySmartHomeApp();
|
||||
|
||||
{
|
||||
try {
|
||||
GoogleCredentials credentials =
|
||||
GoogleCredentials.fromStream(getClass().getResourceAsStream("/smart-home-key.json"));
|
||||
actionsApp.setCredentials(credentials);
|
||||
} catch (Exception e) {
|
||||
logger.severe("couldn't load credentials");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public SmartHomeServlet() {
|
||||
super("api/assistant/google/smarthome");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected DataNode jsonRespond(
|
||||
HttpPrintStream out,
|
||||
HttpHeader headers,
|
||||
Map<String,Object> session,
|
||||
Map<String,String> cookie,
|
||||
Map<String,String> request) throws Exception {
|
||||
|
||||
String body = IOUtil.readContentAsString(headers.getInputStream());
|
||||
logger.info("doPost, body = " + body);
|
||||
|
||||
try {
|
||||
String response = actionsApp.handleRequest(body, request).get();
|
||||
|
||||
System.out.println("response = " + asJson);
|
||||
res.getWriter().write(asJson);
|
||||
res.getWriter().flush();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
logger.log(Level.SEVERE, "Failed to handle fulfillment request", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue