Added Event devices to google assistant

This commit is contained in:
Ziver Koc 2021-08-29 17:00:33 +02:00
parent 2d30b9451b
commit fa80fbc114
6 changed files with 56 additions and 94 deletions

View file

@ -25,9 +25,11 @@ import com.google.protobuf.Struct;
import com.google.protobuf.Value; import com.google.protobuf.Value;
import org.json.JSONObject; import org.json.JSONObject;
import se.hal.HalContext; import se.hal.HalContext;
import se.hal.intf.HalAbstractDevice;
import se.hal.plugin.assistant.google.trait.DeviceTrait; import se.hal.plugin.assistant.google.trait.DeviceTrait;
import se.hal.plugin.assistant.google.trait.DeviceTraitFactory; import se.hal.plugin.assistant.google.trait.DeviceTraitFactory;
import se.hal.plugin.assistant.google.type.DeviceType; import se.hal.plugin.assistant.google.type.DeviceType;
import se.hal.struct.Event;
import se.hal.struct.Sensor; import se.hal.struct.Sensor;
import zutil.db.DBConnection; import zutil.db.DBConnection;
import zutil.log.LogUtil; import zutil.log.LogUtil;
@ -74,32 +76,33 @@ public class SmartHomeImpl extends SmartHomeApp implements TokenRegistrationList
res.setRequestId(syncRequest.requestId); res.setRequestId(syncRequest.requestId);
res.setPayload(new SyncResponse.Payload()); res.setPayload(new SyncResponse.Payload());
List<Sensor> sensors = Collections.EMPTY_LIST; List<HalAbstractDevice> deviceList = new LinkedList<>();
try { try {
DBConnection db = HalContext.getDB(); DBConnection db = HalContext.getDB();
sensors = Sensor.getLocalSensors(db); deviceList.addAll(Sensor.getLocalSensors(db));
deviceList.addAll(Event.getLocalEvents(db));
} catch (SQLException e) { } catch (SQLException e) {
logger.log(Level.WARNING, "Unable to retrieve sensor list.", e); logger.log(Level.WARNING, "Unable to retrieve devices.", e);
} }
res.payload.agentUserId = AGENT_USER_ID; res.payload.agentUserId = AGENT_USER_ID;
res.payload.devices = new SyncResponse.Payload.Device[sensors.size()]; res.payload.devices = new SyncResponse.Payload.Device[deviceList.size()];
for (int i = 0; i < res.payload.devices.length; i++) { for (int i = 0; i < res.payload.devices.length; i++) {
Sensor sensor = sensors.get(i); HalAbstractDevice device = deviceList.get(i);
DeviceType type = DeviceType.getType(sensor); DeviceType type = DeviceType.getType(device);
DeviceTrait[] traits = DeviceTraitFactory.getTraits(sensor); DeviceTrait[] traits = DeviceTraitFactory.getTraits(device);
// Generate payload // Generate payload
SyncResponse.Payload.Device.Builder deviceBuilder = SyncResponse.Payload.Device.Builder deviceBuilder =
new SyncResponse.Payload.Device.Builder() new SyncResponse.Payload.Device.Builder()
.setId("Sensor-" + sensor.getId()) .setId(device.getClass().getSimpleName() + "-" + device.getId())
.setType(type.toString()) .setType(type.toString())
.setTraits(DeviceTraitFactory.getTraitIds(traits)) .setTraits(DeviceTraitFactory.getTraitIds(traits))
.setName( .setName(
DeviceProto.DeviceNames.newBuilder() DeviceProto.DeviceNames.newBuilder()
.setName(sensor.getName()) .setName(device.getName())
.build()) .build())
.setWillReportState(true) .setWillReportState(true)
//.setRoomHint(sensor.getRoom().getName()) //.setRoomHint(sensor.getRoom().getName())
@ -113,18 +116,19 @@ public class SmartHomeImpl extends SmartHomeApp implements TokenRegistrationList
JSONObject attribJson = new JSONObject(); JSONObject attribJson = new JSONObject();
for (DeviceTrait trait : traits) { for (DeviceTrait trait : traits) {
for (Map.Entry<String,Object> entry : trait.generateSyncResponse(sensor.getDeviceConfig()).entrySet()) { for (Map.Entry<String,Object> entry : trait.generateSyncResponse(device.getDeviceConfig()).entrySet()) {
attribJson.put(entry.getKey(), entry.getValue()); attribJson.put(entry.getKey(), entry.getValue());
} }
} }
deviceBuilder.setAttributes(attribJson); deviceBuilder.setAttributes(attribJson);
/*if (device.contains("customData")) { // Set custom data
Map<String, Object> customData = new HashMap<>();
JSONObject customDataJson = new JSONObject();
customDataJson.put("type", device.getClass().getSimpleName());
customDataJson.put("id", device.getId());
deviceBuilder.setCustomData(customDataJson);
String customDataJson = new Gson().toJson(customData);
deviceBuilder.setCustomData(customDataJson);
}*/
res.payload.devices[i] = deviceBuilder.build(); res.payload.devices[i] = deviceBuilder.build();
} }
@ -162,8 +166,6 @@ public class SmartHomeImpl extends SmartHomeApp implements TokenRegistrationList
*/ */
@Override @Override
public QueryResponse onQuery(QueryRequest queryRequest, Map<?, ?> headers) { public QueryResponse onQuery(QueryRequest queryRequest, Map<?, ?> headers) {
logger.fine("Received query request.");
DBConnection db = HalContext.getDB(); DBConnection db = HalContext.getDB();
QueryResponse res = new QueryResponse(); QueryResponse res = new QueryResponse();
@ -175,30 +177,39 @@ public class SmartHomeImpl extends SmartHomeApp implements TokenRegistrationList
if (!"action.devices.QUERY".equals(input.intent)) if (!"action.devices.QUERY".equals(input.intent))
continue; continue;
for (QueryRequest.Inputs.Payload.Device device : ((QueryRequest.Inputs) input).payload.devices) { for (QueryRequest.Inputs.Payload.Device deviceRequest : ((QueryRequest.Inputs) input).payload.devices) {
try { try {
if (!device.getId().startsWith("Sensor-")) logger.fine("Received query request for: type=" + deviceRequest.getCustomData().get("type") + ", id=" + deviceRequest.getCustomData().get("id"));
throw new IllegalArgumentException("Invalid device ID supplied: " + device.getId());
long sensorId = Long.parseLong(device.getId().substring(7)); // Get the number in the id "Sensor-<number>" if (!deviceRequest.getCustomData().containsKey("type") && !deviceRequest.getCustomData().containsKey("id"))
Sensor sensor = Sensor.getSensor(db, sensorId); throw new IllegalArgumentException("Device Type and ID was no supplied: " + deviceRequest.getId());
DeviceTrait[] traits = DeviceTraitFactory.getTraits(sensor);
String deviceType = (String) deviceRequest.getCustomData().get("type");
long deviceId = Long.parseLong((String) deviceRequest.getCustomData().get("id"));
HalAbstractDevice device = null;
switch (deviceType) {
case "Sensor": device = Sensor.getSensor(db, deviceId); break;
case "Event": device = Event.getEvent(db, deviceId); break;
}
logger.fine("Generating response for sensor: " + device.getName() + " (Id: " + device.getId() + ")");
DeviceTrait[] traits = DeviceTraitFactory.getTraits(device);
Map<String, Object> deviceState = new HashMap<>(); Map<String, Object> deviceState = new HashMap<>();
logger.fine("Generating response for sensor: " + sensor.getName() + " (Id: " + sensor.getId() + ")");
for (DeviceTrait trait : traits) { for (DeviceTrait trait : traits) {
deviceState.putAll(trait.generateQueryResponse(sensor.getDeviceData())); deviceState.putAll(trait.generateQueryResponse(device.getDeviceData()));
} }
deviceState.put("status", "SUCCESS"); deviceState.put("status", "SUCCESS");
deviceStates.put(device.getId(), deviceState); deviceStates.put(deviceRequest.getId(), deviceState);
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "Query request failed for sensor: " + device.getId(), e); logger.log(Level.SEVERE, "Query request failed for sensor: " + deviceRequest.getId(), e);
Map<String, Object> failedDevice = new HashMap<>(); Map<String, Object> failedDevice = new HashMap<>();
failedDevice.put("status", "ERROR"); failedDevice.put("status", "ERROR");
failedDevice.put("errorCode", "deviceOffline"); failedDevice.put("errorCode", "deviceOffline");
deviceStates.put(device.id, failedDevice); deviceStates.put(deviceRequest.id, failedDevice);
} }
} }
} }
@ -229,59 +240,6 @@ public class SmartHomeImpl extends SmartHomeApp implements TokenRegistrationList
successfulDevices.add(device.id); successfulDevices.add(device.id);
ReportState.makeRequest(this, userId, device.id, states); ReportState.makeRequest(this, userId, device.id, states);
} catch (Exception e) { } 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(); ExecuteResponse.Payload.Commands failedDevice = new ExecuteResponse.Payload.Commands();
failedDevice.ids = new String[]{device.id}; failedDevice.ids = new String[]{device.id};
failedDevice.status = "ERROR"; failedDevice.status = "ERROR";

View file

@ -24,8 +24,8 @@
package se.hal.plugin.assistant.google.trait; package se.hal.plugin.assistant.google.trait;
import se.hal.intf.HalDeviceConfig;
import se.hal.intf.HalDeviceData; import se.hal.intf.HalDeviceData;
import se.hal.intf.HalSensorConfig;
import java.util.HashMap; import java.util.HashMap;
@ -39,7 +39,7 @@ public abstract class DeviceTrait {
*/ */
abstract String getId(); abstract String getId();
public abstract HashMap<String, Object> generateSyncResponse(HalSensorConfig config); public abstract HashMap<String, Object> generateSyncResponse(HalDeviceConfig config);
public abstract HashMap<String, Object> generateQueryResponse(HalDeviceData data); public abstract HashMap<String, Object> generateQueryResponse(HalDeviceData data);
} }

View file

@ -24,6 +24,7 @@
package se.hal.plugin.assistant.google.trait; package se.hal.plugin.assistant.google.trait;
import se.hal.intf.HalAbstractDevice;
import se.hal.struct.Sensor; import se.hal.struct.Sensor;
import java.util.ArrayList; import java.util.ArrayList;
@ -37,8 +38,8 @@ public class DeviceTraitFactory {
private DeviceTraitFactory() {} private DeviceTraitFactory() {}
public static DeviceTrait[] getTraits(Sensor sensor) { public static DeviceTrait[] getTraits(HalAbstractDevice device) {
switch (sensor.getDeviceData().getClass().getName()) { switch (device.getDeviceData().getClass().getName()) {
case "se.hal.struct.devicedata.DimmerEventData": case "se.hal.struct.devicedata.DimmerEventData":
case "se.hal.struct.devicedata.OnOffEventData": case "se.hal.struct.devicedata.OnOffEventData":
return new DeviceTrait[]{}; return new DeviceTrait[]{};
@ -54,7 +55,7 @@ public class DeviceTraitFactory {
return new DeviceTrait[]{new TemperatureControlTrait()}; return new DeviceTrait[]{new TemperatureControlTrait()};
default: default:
throw new IllegalArgumentException("Unregistered Sensor device data: " + sensor.getDeviceData()); throw new IllegalArgumentException("Unregistered Sensor device data: " + device.getDeviceData());
} }
} }

View file

@ -24,12 +24,13 @@
package se.hal.plugin.assistant.google.trait; package se.hal.plugin.assistant.google.trait;
import se.hal.intf.HalDeviceConfig;
import se.hal.intf.HalDeviceData; import se.hal.intf.HalDeviceData;
import se.hal.intf.HalSensorConfig;
import se.hal.struct.devicedata.HumiditySensorData; import se.hal.struct.devicedata.HumiditySensorData;
import java.util.HashMap; import java.util.HashMap;
public class HumiditySettingTrait extends DeviceTrait { public class HumiditySettingTrait extends DeviceTrait {
@Override @Override
@ -38,7 +39,7 @@ public class HumiditySettingTrait extends DeviceTrait {
} }
@Override @Override
public HashMap<String, Object> generateSyncResponse(HalSensorConfig config) { public HashMap<String, Object> generateSyncResponse(HalDeviceConfig config) {
HashMap<String, Object> response = new HashMap<>(); HashMap<String, Object> response = new HashMap<>();
//response.put("humiditySetpointRange", new HashMap<String, Object>() {{ //response.put("humiditySetpointRange", new HashMap<String, Object>() {{
// put("minPercent", 0); // put("minPercent", 0);

View file

@ -25,12 +25,13 @@
package se.hal.plugin.assistant.google.trait; package se.hal.plugin.assistant.google.trait;
import se.hal.intf.HalDeviceConfig;
import se.hal.intf.HalDeviceData; import se.hal.intf.HalDeviceData;
import se.hal.intf.HalSensorConfig;
import se.hal.struct.devicedata.TemperatureSensorData; import se.hal.struct.devicedata.TemperatureSensorData;
import java.util.HashMap; import java.util.HashMap;
public class TemperatureControlTrait extends DeviceTrait { public class TemperatureControlTrait extends DeviceTrait {
@Override @Override
@ -39,7 +40,7 @@ public class TemperatureControlTrait extends DeviceTrait {
} }
@Override @Override
public HashMap<String, Object> generateSyncResponse(HalSensorConfig config) { public HashMap<String, Object> generateSyncResponse(HalDeviceConfig config) {
HashMap<String, Object> response = new HashMap<>(); HashMap<String, Object> response = new HashMap<>();
response.put("temperatureRange", new HashMap<String, Object>() {{ response.put("temperatureRange", new HashMap<String, Object>() {{
put("minThresholdCelsius", -20); put("minThresholdCelsius", -20);

View file

@ -48,6 +48,7 @@
package se.hal.plugin.assistant.google.type; package se.hal.plugin.assistant.google.type;
import se.hal.intf.HalAbstractDevice;
import se.hal.struct.Sensor; import se.hal.struct.Sensor;
/** /**
@ -146,8 +147,8 @@ public enum DeviceType {
} }
public static DeviceType getType(Sensor sensor) { public static DeviceType getType(HalAbstractDevice device) {
switch (sensor.getDeviceData().getClass().getName()) { switch (device.getDeviceData().getClass().getName()) {
case "se.hal.struct.devicedata.DimmerEventData": case "se.hal.struct.devicedata.DimmerEventData":
case "se.hal.struct.devicedata.OnOffEventData": case "se.hal.struct.devicedata.OnOffEventData":
return LIGHT; return LIGHT;
@ -159,7 +160,7 @@ public enum DeviceType {
return SENSOR; return SENSOR;
default: default:
throw new IllegalArgumentException("Unregistered Sensor device data: " + sensor.getDeviceData()); throw new IllegalArgumentException("Unregistered Sensor device data: " + device.getDeviceData());
} }
} }
} }