Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[automation] Added Actions for Play and Say which sets the volume #1854

Merged
merged 4 commits into from
Dec 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@
import static java.util.stream.Collectors.toList;

import java.io.File;
import java.math.BigDecimal;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand All @@ -42,14 +41,15 @@
import org.osgi.service.component.annotations.Reference;

/**
* This class dynamically provides the Play action type.
* This class dynamically provides the Play and Say action types.
* This is necessary since there is no other way to provide dynamic config param options for module types.
*
* @author Kai Kreuzer - Initial contribution
* @author Simon Kaufmann - added "say" action
* @author Christoph Weitkamp - Added parameter volume
*/
@NonNullByDefault
@Component(immediate = true)
@Component(service = ModuleTypeProvider.class)
public class MediaActionTypeProvider implements ModuleTypeProvider {

private final AudioManager audioManager;
Expand All @@ -62,43 +62,45 @@ public MediaActionTypeProvider(final @Reference AudioManager audioManager) {
@SuppressWarnings("unchecked")
@Override
public @Nullable ModuleType getModuleType(String UID, @Nullable Locale locale) {
if (PlayActionHandler.TYPE_ID.equals(UID)) {
return getPlayActionType(locale);
} else if (SayActionHandler.TYPE_ID.equals(UID)) {
return getSayActionType(locale);
} else {
return null;
switch (UID) {
case PlayActionHandler.TYPE_ID:
return getPlayActionType(locale);
case SayActionHandler.TYPE_ID:
return getSayActionType(locale);
default:
return null;
}
}

@Override
public Collection<ModuleType> getModuleTypes(@Nullable Locale locale) {
return Stream.of(getPlayActionType(locale), getSayActionType(locale)).collect(Collectors.toList());
return List.of(getPlayActionType(locale), getSayActionType(locale));
}

private ModuleType getPlayActionType(@Nullable Locale locale) {
return new ActionType(PlayActionHandler.TYPE_ID, getConfigPlayDesc(locale), "play a sound",
"Plays a sound file.", null, Visibility.VISIBLE, new ArrayList<>(), new ArrayList<>());
"Plays a sound file. Optionally sets the volume.", null, Visibility.VISIBLE, null, null);
}

private ModuleType getSayActionType(@Nullable Locale locale) {
return new ActionType(SayActionHandler.TYPE_ID, getConfigSayDesc(locale), "say something",
"Speaks a given text through a natural voice.", null, Visibility.VISIBLE, new ArrayList<>(),
new ArrayList<>());
"Speaks a given text through a natural voice. Optionally sets the volume.", null, Visibility.VISIBLE,
null, null);
}

private List<ConfigDescriptionParameter> getConfigPlayDesc(@Nullable Locale locale) {
ConfigDescriptionParameter param1 = ConfigDescriptionParameterBuilder
.create(PlayActionHandler.PARAM_SOUND, Type.TEXT).withRequired(true).withLabel("Sound")
.withDescription("the sound to play").withOptions(getSoundOptions()).withLimitToOptions(true).build();
return List.of(param1, getAudioSinkConfigDescParam(locale));
return List.of(
ConfigDescriptionParameterBuilder.create(PlayActionHandler.PARAM_SOUND, Type.TEXT).withRequired(true)
.withLabel("Sound").withDescription("the sound to play").withOptions(getSoundOptions())
.withLimitToOptions(true).build(),
getAudioSinkConfigDescParam(locale), getVolumeConfigDescParam(locale));
}

private List<ConfigDescriptionParameter> getConfigSayDesc(@Nullable Locale locale) {
ConfigDescriptionParameter param1 = ConfigDescriptionParameterBuilder
.create(SayActionHandler.PARAM_TEXT, Type.TEXT).withRequired(true).withLabel("Text")
.withDescription("the text to speak").build();
return List.of(param1, getAudioSinkConfigDescParam(locale));
return List.of(
ConfigDescriptionParameterBuilder.create(SayActionHandler.PARAM_TEXT, Type.TEXT).withRequired(true)
.withLabel("Text").withDescription("the text to speak").build(),
getAudioSinkConfigDescParam(locale), getVolumeConfigDescParam(locale));
}

private ConfigDescriptionParameter getAudioSinkConfigDescParam(@Nullable Locale locale) {
Expand All @@ -109,6 +111,14 @@ private ConfigDescriptionParameter getAudioSinkConfigDescParam(@Nullable Locale
return param2;
}

private ConfigDescriptionParameter getVolumeConfigDescParam(@Nullable Locale locale) {
ConfigDescriptionParameter param3 = ConfigDescriptionParameterBuilder
.create(SayActionHandler.PARAM_VOLUME, Type.INTEGER).withLabel("Volume")
.withDescription("the volume to use").withMinimum(BigDecimal.ZERO).withMaximum(BigDecimal.valueOf(100))
.withStepSize(BigDecimal.ONE).build();
return param3;
}

/**
* This method creates one option for every file that is found in the sounds directory.
* As a label, the file extension is removed and the string is capitalized.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,39 @@
import java.util.Collection;
import java.util.List;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.audio.AudioManager;
import org.openhab.core.automation.Action;
import org.openhab.core.automation.Module;
import org.openhab.core.automation.handler.BaseModuleHandlerFactory;
import org.openhab.core.automation.handler.ModuleHandler;
import org.openhab.core.automation.handler.ModuleHandlerFactory;
import org.openhab.core.voice.VoiceManager;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;

/**
*
* @author Kai Kreuzer - Initial contribution
* @author Christoph Weitkamp - Added parameter volume
*/
@NonNullByDefault
@Component(service = ModuleHandlerFactory.class)
public class MediaModuleHandlerFactory extends BaseModuleHandlerFactory {

private static final Collection<String> TYPES = List.of(SayActionHandler.TYPE_ID, PlayActionHandler.TYPE_ID);
private VoiceManager voiceManager;
private AudioManager audioManager;
private final VoiceManager voiceManager;
private final AudioManager audioManager;

@Activate
public MediaModuleHandlerFactory(final @Reference AudioManager audioManager,
final @Reference VoiceManager voiceManager) {
this.audioManager = audioManager;
this.voiceManager = voiceManager;
}

@Override
@Deactivate
Expand All @@ -49,7 +61,7 @@ public Collection<String> getTypes() {
}

@Override
protected ModuleHandler internalCreate(Module module, String ruleUID) {
protected @Nullable ModuleHandler internalCreate(Module module, String ruleUID) {
if (module instanceof Action) {
switch (module.getTypeUID()) {
case SayActionHandler.TYPE_ID:
Expand All @@ -62,22 +74,4 @@ protected ModuleHandler internalCreate(Module module, String ruleUID) {
}
return null;
}

@Reference
protected void setAudioManager(AudioManager audioManager) {
this.audioManager = audioManager;
}

protected void unsetAudioManager(AudioManager audioManager) {
this.audioManager = null;
}

@Reference
protected void setVoiceManager(VoiceManager voiceManager) {
this.voiceManager = voiceManager;
}

protected void unsetVoiceManager(VoiceManager voiceManager) {
this.voiceManager = null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,56 @@
*/
package org.openhab.core.automation.module.media.internal;

import java.math.BigDecimal;
import java.util.Map;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.audio.AudioException;
import org.openhab.core.audio.AudioManager;
import org.openhab.core.automation.Action;
import org.openhab.core.automation.handler.BaseActionModuleHandler;
import org.openhab.core.library.types.PercentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* This is an ModuleHandler implementation for Actions that play a sound file from the file system.
*
* @author Kai Kreuzer - Initial contribution
* @author Christoph Weitkamp - Added parameter volume
*/
@NonNullByDefault
public class PlayActionHandler extends BaseActionModuleHandler {

public static final String TYPE_ID = "media.PlayAction";
public static final String PARAM_SOUND = "sound";
public static final String PARAM_SINK = "sink";
public static final String PARAM_VOLUME = "volume";

private final Logger logger = LoggerFactory.getLogger(PlayActionHandler.class);

private final AudioManager audioManager;

private final String sound;
private final String sink;
private final @Nullable PercentType volume;

public PlayActionHandler(Action module, AudioManager audioManager) {
super(module);
this.audioManager = audioManager;

this.sound = module.getConfiguration().get(PARAM_SOUND).toString();
this.sink = module.getConfiguration().get(PARAM_SINK).toString();

Object volumeParam = module.getConfiguration().get(PARAM_VOLUME);
this.volume = volumeParam instanceof BigDecimal ? new PercentType((BigDecimal) volumeParam) : null;
}

@Override
public Map<String, Object> execute(Map<String, Object> context) {
String sound = module.getConfiguration().get(PARAM_SOUND).toString();
String sink = (String) module.getConfiguration().get(PARAM_SINK);
public @Nullable Map<String, Object> execute(Map<String, Object> context) {
try {
audioManager.playFile(sound, sink);
audioManager.playFile(sound, sink, volume);
} catch (AudioException e) {
logger.error("Error playing sound '{}': {}", sound, e.getMessage());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,50 @@
*/
package org.openhab.core.automation.module.media.internal;

import java.math.BigDecimal;
import java.util.Map;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.Action;
import org.openhab.core.automation.handler.BaseActionModuleHandler;
import org.openhab.core.library.types.PercentType;
import org.openhab.core.voice.VoiceManager;

/**
* This is an ModuleHandler implementation for Actions that trigger a TTS output through "say".
*
* @author Kai Kreuzer - Initial contribution
* @author Christoph Weitkamp - Added parameter volume
*/
@NonNullByDefault
public class SayActionHandler extends BaseActionModuleHandler {

public static final String TYPE_ID = "media.SayAction";
public static final String PARAM_TEXT = "text";
public static final String PARAM_SINK = "sink";
public static final String PARAM_VOLUME = "volume";

private final VoiceManager voiceManager;

private final String text;
private final String sink;
private final @Nullable PercentType volume;

public SayActionHandler(Action module, VoiceManager voiceManager) {
super(module);
this.voiceManager = voiceManager;

text = module.getConfiguration().get(PARAM_TEXT).toString();
sink = module.getConfiguration().get(PARAM_SINK).toString();

Object volumeParam = module.getConfiguration().get(PARAM_VOLUME);
this.volume = volumeParam instanceof BigDecimal ? new PercentType((BigDecimal) volumeParam) : null;
}

@Override
public Map<String, Object> execute(Map<String, Object> context) {
String text = module.getConfiguration().get(PARAM_TEXT).toString();
String sink = (String) module.getConfiguration().get(PARAM_SINK);
voiceManager.say(text, null, sink);
public @Nullable Map<String, Object> execute(Map<String, Object> context) {
voiceManager.say(text, null, sink, volume);
return null;
}
}