[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:
parent
33faa51d7c
commit
b27ddbe9fc
|
@ -45,7 +45,6 @@ import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
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.JsonActivities.Activity;
|
||||||
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAnnouncementContent;
|
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAnnouncementContent;
|
||||||
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAnnouncementTarget;
|
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;
|
||||||
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAscendingAlarm.AscendingAlarmModel;
|
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAscendingAlarm.AscendingAlarmModel;
|
||||||
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAutomation;
|
import org.openhab.binding.amazonechocontrol.internal.jsons.JsonAutomation;
|
||||||
|
@ -147,7 +145,7 @@ public class Connection {
|
||||||
private @Nullable String accountCustomerId;
|
private @Nullable String accountCustomerId;
|
||||||
private @Nullable String customerName;
|
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, TextToSpeech> textToSpeeches = Collections.synchronizedMap(new LinkedHashMap<>());
|
||||||
private Map<Integer, Volume> volumes = Collections.synchronizedMap(new LinkedHashMap<>());
|
private Map<Integer, Volume> volumes = Collections.synchronizedMap(new LinkedHashMap<>());
|
||||||
private Map<String, LinkedBlockingQueue<QueueObject>> devices = 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,
|
public void announcement(Device device, String speak, String bodyText, @Nullable String title,
|
||||||
@Nullable Integer ttsVolume, @Nullable Integer standardVolume) {
|
@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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we lock announcements until we have finished adding this one
|
// 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();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
Announcement announcement = Objects.requireNonNull(announcements.computeIfAbsent(
|
AnnouncementWrapper announcement = Objects.requireNonNull(announcements.computeIfAbsent(
|
||||||
Objects.hash(speak, bodyText, title), k -> new Announcement(speak, bodyText, title)));
|
Objects.hash(speak, plainBody, title), k -> new AnnouncementWrapper(speak, plainBody, title)));
|
||||||
announcement.devices.add(device);
|
announcement.devices.add(device);
|
||||||
announcement.ttsVolumes.add(ttsVolume);
|
announcement.ttsVolumes.add(ttsVolume);
|
||||||
announcement.standardVolumes.add(standardVolume);
|
announcement.standardVolumes.add(standardVolume);
|
||||||
|
@ -1340,37 +1342,18 @@ public class Connection {
|
||||||
Lock lock = locks.computeIfAbsent(TimerType.ANNOUNCEMENT, k -> new ReentrantLock());
|
Lock lock = locks.computeIfAbsent(TimerType.ANNOUNCEMENT, k -> new ReentrantLock());
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
Iterator<Announcement> iterator = announcements.values().iterator();
|
Iterator<AnnouncementWrapper> iterator = announcements.values().iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
Announcement announcement = iterator.next();
|
AnnouncementWrapper announcement = iterator.next();
|
||||||
try {
|
try {
|
||||||
List<Device> devices = announcement.devices;
|
List<Device> devices = announcement.devices;
|
||||||
if (!devices.isEmpty()) {
|
if (!devices.isEmpty()) {
|
||||||
String speak = announcement.speak;
|
JsonAnnouncementContent content = new JsonAnnouncementContent(announcement);
|
||||||
String bodyText = announcement.bodyText;
|
|
||||||
String title = announcement.title;
|
|
||||||
|
|
||||||
Map<String, Object> parameters = new HashMap<>();
|
Map<String, Object> parameters = new HashMap<>();
|
||||||
parameters.put("expireAfter", "PT5S");
|
parameters.put("expireAfter", "PT5S");
|
||||||
JsonAnnouncementContent[] contentArray = new JsonAnnouncementContent[1];
|
parameters.put("content", new JsonAnnouncementContent[] { content });
|
||||||
JsonAnnouncementContent content = new JsonAnnouncementContent();
|
parameters.put("target", new JsonAnnouncementTarget(devices));
|
||||||
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);
|
|
||||||
|
|
||||||
String customerId = getCustomerId(devices.get(0).deviceOwnerCustomerId);
|
String customerId = getCustomerId(devices.get(0).deviceOwnerCustomerId);
|
||||||
if (customerId != null) {
|
if (customerId != null) {
|
||||||
|
@ -2023,7 +2006,7 @@ public class Connection {
|
||||||
true, true, null, 0);
|
true, true, null, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Announcement {
|
public static class AnnouncementWrapper {
|
||||||
public List<Device> devices = new ArrayList<>();
|
public List<Device> devices = new ArrayList<>();
|
||||||
public String speak;
|
public String speak;
|
||||||
public String bodyText;
|
public String bodyText;
|
||||||
|
@ -2031,7 +2014,7 @@ public class Connection {
|
||||||
public List<@Nullable Integer> ttsVolumes = new ArrayList<>();
|
public List<@Nullable Integer> ttsVolumes = new ArrayList<>();
|
||||||
public List<@Nullable Integer> standardVolumes = 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.speak = speak;
|
||||||
this.bodyText = bodyText;
|
this.bodyText = bodyText;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
|
|
|
@ -92,7 +92,7 @@ public class ChannelHandlerAnnouncement extends ChannelHandler {
|
||||||
body = e.getLocalizedMessage();
|
body = e.getLocalizedMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thingHandler.startAnnouncment(device, speak, Objects.requireNonNullElse(body, ""), title, volume);
|
thingHandler.startAnnouncement(device, speak, Objects.requireNonNullElse(body, ""), title, volume);
|
||||||
}
|
}
|
||||||
refreshChannel();
|
refreshChannel();
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,6 @@ public interface IAmazonThingHandler {
|
||||||
|
|
||||||
void updateChannelState(String channelId, State state);
|
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;
|
@Nullable Integer volume) throws IOException, URISyntaxException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,6 @@ import org.openhab.binding.amazonechocontrol.internal.jsons.JsonDevices.Device;
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public interface IEchoThingHandler extends IAmazonThingHandler {
|
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;
|
@Nullable Integer volume) throws IOException, URISyntaxException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,12 +25,12 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
@ -198,11 +198,11 @@ public class AccountHandler extends BaseBridgeHandler implements IWebSocketComma
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 {
|
@Nullable Integer volume) throws IOException, URISyntaxException {
|
||||||
EchoHandler echoHandler = findEchoHandlerBySerialNumber(device.serialNumber);
|
EchoHandler echoHandler = findEchoHandlerBySerialNumber(device.serialNumber);
|
||||||
if (echoHandler != null) {
|
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) {
|
public @Nullable Device findDeviceJson(@Nullable String serialNumber) {
|
||||||
Device result = null;
|
if (serialNumber == null || serialNumber.isEmpty()) {
|
||||||
if (serialNumber != null && !serialNumber.isEmpty()) {
|
return null;
|
||||||
Map<String, Device> jsonSerialNumberDeviceMapping = this.jsonSerialNumberDeviceMapping;
|
|
||||||
result = jsonSerialNumberDeviceMapping.get(serialNumber);
|
|
||||||
}
|
}
|
||||||
return result;
|
return this.jsonSerialNumberDeviceMapping.get(serialNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Device findDeviceJsonBySerialOrName(@Nullable String serialOrName) {
|
public @Nullable Device findDeviceJsonBySerialOrName(@Nullable String serialOrName) {
|
||||||
|
@ -609,15 +607,9 @@ public class AccountHandler extends BaseBridgeHandler implements IWebSocketComma
|
||||||
return null;
|
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))
|
d -> serialOrName.equalsIgnoreCase(d.serialNumber) || serialOrName.equalsIgnoreCase(d.accountName))
|
||||||
.findFirst();
|
.findFirst().orElse(null);
|
||||||
|
|
||||||
if (device.isPresent()) {
|
|
||||||
return device.get();
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Device> updateDeviceList() {
|
public List<Device> updateDeviceList() {
|
||||||
|
@ -636,15 +628,8 @@ public class AccountHandler extends BaseBridgeHandler implements IWebSocketComma
|
||||||
}
|
}
|
||||||
if (devices != null) {
|
if (devices != null) {
|
||||||
// create new device map
|
// create new device map
|
||||||
Map<String, Device> newJsonSerialDeviceMapping = new HashMap<>();
|
jsonSerialNumberDeviceMapping = devices.stream().filter(device -> device.serialNumber != null)
|
||||||
for (Device device : devices) {
|
.collect(Collectors.toMap(d -> Objects.requireNonNull(d.serialNumber), d -> d));
|
||||||
String serialNumber = device.serialNumber;
|
|
||||||
if (serialNumber != null) {
|
|
||||||
newJsonSerialDeviceMapping.put(serialNumber, device);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
jsonSerialNumberDeviceMapping = newJsonSerialDeviceMapping;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WakeWord[] wakeWords = currentConnection.getWakeWords();
|
WakeWord[] wakeWords = currentConnection.getWakeWords();
|
||||||
|
|
|
@ -713,7 +713,7 @@ public class EchoHandler extends BaseThingHandler implements IEchoThingHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 {
|
@Nullable Integer volume) throws IOException, URISyntaxException {
|
||||||
Connection connection = this.findConnection();
|
Connection connection = this.findConnection();
|
||||||
if (connection == null) {
|
if (connection == null) {
|
||||||
|
|
|
@ -14,27 +14,42 @@ package org.openhab.binding.amazonechocontrol.internal.jsons;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
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
|
* announcements
|
||||||
*
|
*
|
||||||
* @author Michael Geramb - Initial contribution
|
* @author Michael Geramb - Initial contribution
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class JsonAnnouncementContent {
|
public class JsonAnnouncementContent {
|
||||||
|
|
||||||
public String locale = "";
|
public String locale = "";
|
||||||
public final Display display = new Display();
|
public Display display;
|
||||||
public final Speak speak = new Speak();
|
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 static class Display {
|
||||||
public @Nullable String title;
|
public String title;
|
||||||
public @Nullable String body;
|
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 static class Speak {
|
||||||
public String type = "text";
|
public String type;
|
||||||
public @Nullable String value;
|
public String value;
|
||||||
|
|
||||||
|
public Speak(String speakText) {
|
||||||
|
type = (speakText.startsWith("<speak>") && speakText.endsWith("</speak>")) ? "ssml" : "text";
|
||||||
|
value = speakText;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.amazonechocontrol.internal.jsons;
|
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.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
|
@ -25,7 +28,12 @@ import org.eclipse.jdt.annotation.Nullable;
|
||||||
public class JsonAnnouncementTarget {
|
public class JsonAnnouncementTarget {
|
||||||
|
|
||||||
public @Nullable String customerId;
|
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 static class TargetDevice {
|
||||||
public @Nullable String deviceSerialNumber;
|
public @Nullable String deviceSerialNumber;
|
||||||
|
|
Loading…
Reference in New Issue