[amazonechoontrol] fix announcement without speak (#9213)

* fix announcement without speak
* improve code

Signed-off-by: Jan N. Klug <jan.n.klug@rub.de>
This commit is contained in:
J-N-K 2020-12-04 02:24:56 +01:00 committed by GitHub
parent 33faa51d7c
commit b27ddbe9fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 62 additions and 71 deletions

View File

@ -45,7 +45,6 @@ import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import javax.net.ssl.HttpsURLConnection;
@ -56,7 +55,6 @@ import org.openhab.binding.amazonechocontrol.internal.jsons.JsonActivities;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonActivities.Activity;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAnnouncementContent;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAnnouncementTarget;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAnnouncementTarget.TargetDevice;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAscendingAlarm;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAscendingAlarm.AscendingAlarmModel;
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAutomation;
@ -147,7 +145,7 @@ public class Connection {
private @Nullable String accountCustomerId;
private @Nullable String customerName;
private Map<Integer, Announcement> announcements = Collections.synchronizedMap(new LinkedHashMap<>());
private Map<Integer, AnnouncementWrapper> announcements = Collections.synchronizedMap(new LinkedHashMap<>());
private Map<Integer, TextToSpeech> textToSpeeches = Collections.synchronizedMap(new LinkedHashMap<>());
private Map<Integer, Volume> volumes = Collections.synchronizedMap(new LinkedHashMap<>());
private Map<String, LinkedBlockingQueue<QueueObject>> devices = Collections.synchronizedMap(new LinkedHashMap<>());
@ -1313,16 +1311,20 @@ public class Connection {
public void announcement(Device device, String speak, String bodyText, @Nullable String title,
@Nullable Integer ttsVolume, @Nullable Integer standardVolume) {
if (speak.replaceAll("<.+?>", " ").replaceAll("\\s+", " ").trim().isEmpty()) {
String plainSpeak = speak.replaceAll("<.+?>", " ").replaceAll("\\s+", " ").trim();
String plainBody = bodyText.replaceAll("<.+?>", " ").replaceAll("\\s+", " ").trim();
if (plainSpeak.isEmpty() && plainBody.isEmpty()) {
// if there is neither a bodytext nor (except tags) a speaktext, we have nothing to announce
return;
}
// we lock announcements until we have finished adding this one
Lock lock = locks.computeIfAbsent(TimerType.ANNOUNCEMENT, k -> new ReentrantLock());
Lock lock = Objects.requireNonNull(locks.computeIfAbsent(TimerType.ANNOUNCEMENT, k -> new ReentrantLock()));
lock.lock();
try {
Announcement announcement = Objects.requireNonNull(announcements.computeIfAbsent(
Objects.hash(speak, bodyText, title), k -> new Announcement(speak, bodyText, title)));
AnnouncementWrapper announcement = Objects.requireNonNull(announcements.computeIfAbsent(
Objects.hash(speak, plainBody, title), k -> new AnnouncementWrapper(speak, plainBody, title)));
announcement.devices.add(device);
announcement.ttsVolumes.add(ttsVolume);
announcement.standardVolumes.add(standardVolume);
@ -1340,37 +1342,18 @@ public class Connection {
Lock lock = locks.computeIfAbsent(TimerType.ANNOUNCEMENT, k -> new ReentrantLock());
lock.lock();
try {
Iterator<Announcement> iterator = announcements.values().iterator();
Iterator<AnnouncementWrapper> iterator = announcements.values().iterator();
while (iterator.hasNext()) {
Announcement announcement = iterator.next();
AnnouncementWrapper announcement = iterator.next();
try {
List<Device> devices = announcement.devices;
if (!devices.isEmpty()) {
String speak = announcement.speak;
String bodyText = announcement.bodyText;
String title = announcement.title;
JsonAnnouncementContent content = new JsonAnnouncementContent(announcement);
Map<String, Object> parameters = new HashMap<>();
parameters.put("expireAfter", "PT5S");
JsonAnnouncementContent[] contentArray = new JsonAnnouncementContent[1];
JsonAnnouncementContent content = new JsonAnnouncementContent();
content.display.title = title == null || title.isEmpty() ? "openHAB" : title;
content.display.body = bodyText.replaceAll("<.+?>", " ").replaceAll("\\s+", " ").trim();
if (speak.startsWith("<speak>") && speak.endsWith("</speak>")) {
content.speak.type = "ssml";
}
content.speak.value = speak;
contentArray[0] = content;
parameters.put("content", contentArray);
JsonAnnouncementTarget target = new JsonAnnouncementTarget();
target.customerId = devices.get(0).deviceOwnerCustomerId;
TargetDevice[] targetDevices = devices.stream().map(TargetDevice::new)
.collect(Collectors.toList()).toArray(new TargetDevice[0]);
target.devices = targetDevices;
parameters.put("target", target);
parameters.put("content", new JsonAnnouncementContent[] { content });
parameters.put("target", new JsonAnnouncementTarget(devices));
String customerId = getCustomerId(devices.get(0).deviceOwnerCustomerId);
if (customerId != null) {
@ -2023,7 +2006,7 @@ public class Connection {
true, true, null, 0);
}
private static class Announcement {
public static class AnnouncementWrapper {
public List<Device> devices = new ArrayList<>();
public String speak;
public String bodyText;
@ -2031,7 +2014,7 @@ public class Connection {
public List<@Nullable Integer> ttsVolumes = new ArrayList<>();
public List<@Nullable Integer> standardVolumes = new ArrayList<>();
public Announcement(String speak, String bodyText, @Nullable String title) {
public AnnouncementWrapper(String speak, String bodyText, @Nullable String title) {
this.speak = speak;
this.bodyText = bodyText;
this.title = title;

View File

@ -92,7 +92,7 @@ public class ChannelHandlerAnnouncement extends ChannelHandler {
body = e.getLocalizedMessage();
}
}
thingHandler.startAnnouncment(device, speak, Objects.requireNonNullElse(body, ""), title, volume);
thingHandler.startAnnouncement(device, speak, Objects.requireNonNullElse(body, ""), title, volume);
}
refreshChannel();
}

View File

@ -31,6 +31,6 @@ public interface IAmazonThingHandler {
void updateChannelState(String channelId, State state);
void startAnnouncment(Device device, String speak, String bodyText, @Nullable String title,
void startAnnouncement(Device device, String speak, String bodyText, @Nullable String title,
@Nullable Integer volume) throws IOException, URISyntaxException;
}

View File

@ -26,6 +26,6 @@ import org.openhab.binding.amazonechocontrol.internal.jsons.JsonDevices.Device;
*/
@NonNullByDefault
public interface IEchoThingHandler extends IAmazonThingHandler {
void startAnnouncment(Device device, String speak, String bodyText, @Nullable String title,
void startAnnouncement(Device device, String speak, String bodyText, @Nullable String title,
@Nullable Integer volume) throws IOException, URISyntaxException;
}

View File

@ -25,12 +25,12 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
@ -198,11 +198,11 @@ public class AccountHandler extends BaseBridgeHandler implements IWebSocketComma
}
@Override
public void startAnnouncment(Device device, String speak, String bodyText, @Nullable String title,
public void startAnnouncement(Device device, String speak, String bodyText, @Nullable String title,
@Nullable Integer volume) throws IOException, URISyntaxException {
EchoHandler echoHandler = findEchoHandlerBySerialNumber(device.serialNumber);
if (echoHandler != null) {
echoHandler.startAnnouncment(device, speak, bodyText, title, volume);
echoHandler.startAnnouncement(device, speak, bodyText, title, volume);
}
}
@ -596,12 +596,10 @@ public class AccountHandler extends BaseBridgeHandler implements IWebSocketComma
}
public @Nullable Device findDeviceJson(@Nullable String serialNumber) {
Device result = null;
if (serialNumber != null && !serialNumber.isEmpty()) {
Map<String, Device> jsonSerialNumberDeviceMapping = this.jsonSerialNumberDeviceMapping;
result = jsonSerialNumberDeviceMapping.get(serialNumber);
if (serialNumber == null || serialNumber.isEmpty()) {
return null;
}
return result;
return this.jsonSerialNumberDeviceMapping.get(serialNumber);
}
public @Nullable Device findDeviceJsonBySerialOrName(@Nullable String serialOrName) {
@ -609,15 +607,9 @@ public class AccountHandler extends BaseBridgeHandler implements IWebSocketComma
return null;
}
Optional<Device> device = this.jsonSerialNumberDeviceMapping.values().stream().filter(
return this.jsonSerialNumberDeviceMapping.values().stream().filter(
d -> serialOrName.equalsIgnoreCase(d.serialNumber) || serialOrName.equalsIgnoreCase(d.accountName))
.findFirst();
if (device.isPresent()) {
return device.get();
} else {
return null;
}
.findFirst().orElse(null);
}
public List<Device> updateDeviceList() {
@ -636,15 +628,8 @@ public class AccountHandler extends BaseBridgeHandler implements IWebSocketComma
}
if (devices != null) {
// create new device map
Map<String, Device> newJsonSerialDeviceMapping = new HashMap<>();
for (Device device : devices) {
String serialNumber = device.serialNumber;
if (serialNumber != null) {
newJsonSerialDeviceMapping.put(serialNumber, device);
}
}
jsonSerialNumberDeviceMapping = newJsonSerialDeviceMapping;
jsonSerialNumberDeviceMapping = devices.stream().filter(device -> device.serialNumber != null)
.collect(Collectors.toMap(d -> Objects.requireNonNull(d.serialNumber), d -> d));
}
WakeWord[] wakeWords = currentConnection.getWakeWords();

View File

@ -713,7 +713,7 @@ public class EchoHandler extends BaseThingHandler implements IEchoThingHandler {
}
@Override
public void startAnnouncment(Device device, String speak, String bodyText, @Nullable String title,
public void startAnnouncement(Device device, String speak, String bodyText, @Nullable String title,
@Nullable Integer volume) throws IOException, URISyntaxException {
Connection connection = this.findConnection();
if (connection == null) {

View File

@ -14,27 +14,42 @@ package org.openhab.binding.amazonechocontrol.internal.jsons;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.amazonechocontrol.internal.Connection;
/**
* The {@link JsonActivity} encapsulate the GSON data of the sequence command AlexaAnnouncement for sending
* The {@link JsonAnnouncementContent} encapsulate the GSON data of the sequence command AlexaAnnouncement for sending
* announcements
*
* @author Michael Geramb - Initial contribution
*/
@NonNullByDefault
public class JsonAnnouncementContent {
public String locale = "";
public final Display display = new Display();
public final Speak speak = new Speak();
public Display display;
public Speak speak;
public JsonAnnouncementContent(Connection.AnnouncementWrapper announcement) {
display = new Display(announcement.bodyText, announcement.title);
speak = new Speak(announcement.speak);
}
public static class Display {
public @Nullable String title;
public @Nullable String body;
public String title;
public String body;
public Display(String body, @Nullable String title) {
this.body = body;
this.title = (title == null || title.isEmpty() ? "openHAB" : title);
}
}
public static class Speak {
public String type = "text";
public @Nullable String value;
public String type;
public String value;
public Speak(String speakText) {
type = (speakText.startsWith("<speak>") && speakText.endsWith("</speak>")) ? "ssml" : "text";
value = speakText;
}
}
}

View File

@ -12,6 +12,9 @@
*/
package org.openhab.binding.amazonechocontrol.internal.jsons;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
@ -25,7 +28,12 @@ import org.eclipse.jdt.annotation.Nullable;
public class JsonAnnouncementTarget {
public @Nullable String customerId;
public @Nullable TargetDevice @Nullable [] devices;
public List<TargetDevice> devices;
public JsonAnnouncementTarget(List<JsonDevices.Device> deviceList) {
customerId = deviceList.get(0).deviceOwnerCustomerId;
devices = deviceList.stream().map(TargetDevice::new).collect(Collectors.toList());
}
public static class TargetDevice {
public @Nullable String deviceSerialNumber;