diff --git a/docs/brain/neurons/volume.md b/docs/brain/neurons/volume.md new file mode 100644 index 00000000..387a85c9 --- /dev/null +++ b/docs/brain/neurons/volume.md @@ -0,0 +1,68 @@ +Update the volume + +## Input parameters + +| parameter | required | type | default | choices | comment | +|:----------|:---------|:-------|:--------|:----------------|:-----------------------------------------------------------------------------------| +| level | yes | int | None | | The volume level to set or increase or decrease depending of the selected 'action' | +| action | no | string | set | set,raise,lower | The action to apply to the volume | + +Action type: + +- **set:** set the 'level' value as new volume level +- **raise:** increase the current volume level with the value provided in 'level' +- **lower:** decrease the current volume level with the value provided in 'level' + +## Returned values + +| name | description | type | sample | +|:--------------|:---------------------------------------|:-------|:-------| +| asked_level | The level variable sent to the neuron | int | 22 | +| asked_action | The action variable sent to the neuron | string | set | +| current_level | The current volume level on the system | int | 50 | + + +## Synapses example + +Set the volume to 50% +```yaml +- name: "set-volume" + signals: + - order: "set the volume to 50" + neurons: + - volume: + level: "50" +``` + +Set the volume dynamically +```yaml +- name: "set-volume-dynamic" + signals: + - order: "set the volume to {{ volume }}" + neurons: + - volume: + level: "{{ volume }}" +``` +>**Note:** Depending of your STT engine, the caught 'volume' variable can be a string. For example "twenty" instead of "20". + +Raise the volume +```yaml +- name: "raise-volume" + signals: + - order: "raise the volume" + neurons: + - volume: + level: "10" + action: "raise" +``` + +Reduce the volume +```yaml +- name: "lower-volume" + signals: + - order: "reduce the volume" + neurons: + - volume: + level: "10" + action: "lower" +``` diff --git a/kalliope/neurons/volume/__init__.py b/kalliope/neurons/volume/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/kalliope/neurons/volume/volume.py b/kalliope/neurons/volume/volume.py new file mode 100644 index 00000000..bf644740 --- /dev/null +++ b/kalliope/neurons/volume/volume.py @@ -0,0 +1,83 @@ +import logging + +from kalliope.core import NeuronModule +import alsaaudio + +from kalliope.core.NeuronModule import InvalidParameterException + +logging.basicConfig() +logger = logging.getLogger("kalliope") + + +class SoundManager(object): + + try: + m = alsaaudio.Mixer() + except alsaaudio.ALSAAudioError: + # no master, we are on a Rpi + try: + m = alsaaudio.Mixer("PCM") + except alsaaudio.ALSAAudioError: + # no audio config at all + m = None + + @classmethod + def set_volume(cls, volume_level): + if cls.m is not None: + cls.m.setvolume(int(volume_level)) + + @classmethod + def get_volume(cls): + if cls.m is not None: + vol = cls.m.getvolume() + return int(vol[0]) + return None + + +class Volume(NeuronModule): + + def __init__(self, **kwargs): + super(Volume, self).__init__(**kwargs) + + self.level = kwargs.get('level', None) + self.action = kwargs.get('action', "set") # can be set, raise or lower + + # check parameters + if self._is_parameters_ok(): + if self.action == "set": + logger.debug("[Volume] set volume to: {}".format(self.level)) + SoundManager.set_volume(self.level) + if self.action == "raise": + current_level = SoundManager.get_volume() + level_to_set = self.level + current_level + if level_to_set > 100: + level_to_set = 100 + logger.debug("[Volume] set volume to: {}".format(level_to_set)) + SoundManager.set_volume(level_to_set) + if self.action == "lower": + current_level = SoundManager.get_volume() + level_to_set = self.level - current_level + if level_to_set < 0: + level_to_set = 0 + logger.debug("[Volume] set volume to: {}".format(level_to_set)) + SoundManager.set_volume(level_to_set) + + message = { + "asked_level": self.level, + "asked_action": self.action, + "current_level": SoundManager.get_volume() + } + self.say(message) + + def _is_parameters_ok(self): + if self.level is None: + raise InvalidParameterException("[Volume] level need to be set") + try: + self.level = int(self.level) + except ValueError: + raise InvalidParameterException("[Volume] level '{}' is not a valid integer".format(self.level)) + if self.level < 0 or self.level > 100: + raise InvalidParameterException("[Volume] level need to be placed between 0 and 100") + if self.action not in ["set", "raise", "lower"]: + raise InvalidParameterException("[Volume] action can be 'set', 'raise' or 'lower'") + return True