Skip to content

Commit

Permalink
[automation] Added Actions for Play and Say which sets the volume (op…
Browse files Browse the repository at this point in the history
…enhab#1854)

* Added Actions for Play and Say which sets the volume

Signed-off-by: Christoph Weitkamp <[email protected]>
  • Loading branch information
cweitkamp authored Dec 1, 2020
1 parent c5f133b commit 0e7563c
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 51 deletions.
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;
}
}

0 comments on commit 0e7563c

Please sign in to comment.