Skip to content

Commit b280ab7

Browse files
committed
initial commit
0 parents  commit b280ab7

11 files changed

+446
-0
lines changed

Diff for: CODE_OF_CONDUCT.md

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Contributor Covenant Code of Conduct
2+
3+
## Our Pledge
4+
5+
In the interest of fostering an open and welcoming environment, we as
6+
contributors and maintainers pledge to making participation in our project and
7+
our community a harassment-free experience for everyone, regardless of age, body
8+
size, disability, ethnicity, sex characteristics, gender identity and expression,
9+
level of experience, education, socio-economic status, nationality, personal
10+
appearance, race, religion, or sexual identity and orientation.
11+
12+
## Our Standards
13+
14+
Examples of behavior that contributes to creating a positive environment
15+
include:
16+
17+
* Using welcoming and inclusive language
18+
* Being respectful of differing viewpoints and experiences
19+
* Gracefully accepting constructive criticism
20+
* Focusing on what is best for the community
21+
* Showing empathy towards other community members
22+
23+
Examples of unacceptable behavior by participants include:
24+
25+
* The use of sexualized language or imagery and unwelcome sexual attention or
26+
advances
27+
* Trolling, insulting/derogatory comments, and personal or political attacks
28+
* Public or private harassment
29+
* Publishing others' private information, such as a physical or electronic
30+
address, without explicit permission
31+
* Other conduct which could reasonably be considered inappropriate in a
32+
professional setting
33+
34+
## Our Responsibilities
35+
36+
Project maintainers are responsible for clarifying the standards of acceptable
37+
behavior and are expected to take appropriate and fair corrective action in
38+
response to any instances of unacceptable behavior.
39+
40+
Project maintainers have the right and responsibility to remove, edit, or
41+
reject comments, commits, code, wiki edits, issues, and other contributions
42+
that are not aligned to this Code of Conduct, or to ban temporarily or
43+
permanently any contributor for other behaviors that they deem inappropriate,
44+
threatening, offensive, or harmful.
45+
46+
## Scope
47+
48+
This Code of Conduct applies both within project spaces and in public spaces
49+
when an individual is representing the project or its community. Examples of
50+
representing a project or community include using an official project e-mail
51+
address, posting via an official social media account, or acting as an appointed
52+
representative at an online or offline event. Representation of a project may be
53+
further defined and clarified by project maintainers.
54+
55+
## Enforcement
56+
57+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
58+
reported by contacting the project team at [email protected]. All
59+
complaints will be reviewed and investigated and will result in a response that
60+
is deemed necessary and appropriate to the circumstances. The project team is
61+
obligated to maintain confidentiality with regard to the reporter of an incident.
62+
Further details of specific enforcement policies may be posted separately.
63+
64+
Project maintainers who do not follow or enforce the Code of Conduct in good
65+
faith may face temporary or permanent repercussions as determined by other
66+
members of the project's leadership.
67+
68+
## Attribution
69+
70+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71+
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72+
73+
[homepage]: https://www.contributor-covenant.org
74+
75+
For answers to common questions about this code of conduct, see
76+
https://www.contributor-covenant.org/faq

Diff for: CONTRIBUTING.md

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
How to Contribute
2+
=================
3+
4+
Contributions are welcome! Not familiar with the codebase yet? No problem!
5+
There are many ways to contribute to open source projects: reporting bugs,
6+
helping with the documentation, spreading the word and of course, adding
7+
new features and patches.
8+
9+
Getting Started
10+
---------------
11+
* Make sure you have a GitHub account.
12+
* Open a [new issue](https://github.com/snipsco/snips-app-template-py/issues), assuming one does not already exist.
13+
* Clearly describe the issue including steps to reproduce when it is a bug.
14+
15+
Making Changes
16+
--------------
17+
* Fork this repository.
18+
* Create a feature branch from where you want to base your work.
19+
* Make commits of logical units (if needed rebase your feature branch before
20+
submitting it).
21+
* Check for unnecessary whitespace with ``git diff --check`` before committing.
22+
* Make sure your commit messages are well formatted.
23+
* If your commit fixes an open issue, reference it in the commit message (f.e. `#15`).
24+
* Run all the tests (if existing) to assure nothing else was accidentally broken.
25+
26+
These guidelines also apply when helping with documentation.
27+
28+
Submitting Changes
29+
------------------
30+
* Push your changes to a feature branch in your fork of the repository.
31+
* Submit a `Pull Request`.
32+
* Wait for maintainer feedback.

Diff for: LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2018 [email protected]
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Diff for: README.md

+168
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
- [Requirements](#Requirements)
2+
- [AEC](#AEC)
3+
- [Demo](#Demo)
4+
- [Command-List](#Command-list)
5+
- [Tips](#Tips)
6+
7+
8+
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/snipsco/snips-app-template-py/blob/master/LICENSE)
9+
10+
Control your rtl sdr dongle and listen to fm radio with snips
11+
12+
## Requirements
13+
14+
The app use `rtl_fm` to access the radio:
15+
16+
```bash
17+
# install the rtl-sdr tool
18+
sudo apt-get install rtl-sdr
19+
```
20+
21+
The app must access the usb rtl_sdr dongle:
22+
23+
```
24+
# grant access to the usb dongle and audio to the skill server
25+
sudo usermod -a -G plugdev _snips-skills
26+
```
27+
28+
If you use `pulseaudio` the app must have access to pulseaudio:
29+
30+
```
31+
# grant access to the usb dongle and audio to the skill server
32+
sudo usermod -a -G pulse-access _snips-skills
33+
```
34+
35+
## AEC
36+
37+
for best result it is advised to setup the AEC module with pulseaudio:
38+
39+
```bash
40+
#! /bin/bash
41+
set -e
42+
43+
# Install PulseAudio
44+
sudo apt-get update
45+
sudo apt-get install -y --reinstall pulseaudio
46+
47+
# Comment the lines that overwrite the asound.conf
48+
sudo sed -i.bak 's/^\(.*asound\.conf.*\)/# \1/' /usr/bin/seeed-voicecard
49+
50+
# redirect alsa traffic to pulseaudio through the pulse alsa module
51+
sudo rm /etc/asound.conf || true
52+
sudo tee /etc/asound.conf > /dev/null <<EOS
53+
pcm.!default {
54+
type pulse
55+
fallback "sysdefault"
56+
}
57+
ctl.!default {
58+
type pulse
59+
fallback "sysdefault"
60+
}
61+
EOS
62+
63+
# Do NOT run pulseaudio in realtime mode as it will crash on loading echo cancellation
64+
sudo tee /lib/systemd/system/pulseaudio.service > /dev/null <<EOS
65+
[Unit]
66+
Description=PulseAudio Daemon
67+
[Install]
68+
WantedBy=multi-user.target
69+
[Service]
70+
Type=simple
71+
PrivateTmp=true
72+
Environment=HOME=/tmp/pulseaudio
73+
ExecStart=/usr/bin/pulseaudio -v --daemonize=no --system --realtime=no --log-target=journal
74+
ExecStop=/usr/bin/pulseaudio -k
75+
Restart=always
76+
RestartSec=2
77+
EOS
78+
79+
# Allow users access to pulseaudio on next login
80+
sudo usermod -a -G pulse-access _snips
81+
sudo usermod -a -G pulse-access pi
82+
83+
# Change default sample rate to something higher
84+
sudo sed -i.bak 's/^;\?\s*default-sample-rate.*/default-sample-rate = 48000/' /etc/pulse/daemon.conf
85+
86+
# Add a script to enable the echo cancellation module once pulseaudio has loaded the soundcard
87+
sudo tee /usr/local/bin/pulse-aec.sh > /dev/null <<'EOS'
88+
#!/bin/bash
89+
# name of the mic and speaker to use
90+
mic="alsa_input.platform-soc_sound.analog-stereo"
91+
speaker="alsa_output.platform-soc_sound.analog-stereo"
92+
# wait for the source to exist
93+
for (( ; ; ))
94+
do
95+
sleep 1
96+
found=`pactl list sources | grep Name: | grep -v ".monitor" | grep ${mic} | wc -l `
97+
if [ "$found" == "1" ]
98+
then
99+
break
100+
fi
101+
done
102+
sleep 2
103+
# load the echo-cancel module
104+
pactl load-module \
105+
module-echo-cancel \
106+
source_master=${mic} \
107+
sink_master=${speaker} \
108+
aec_method=webrtc \
109+
use_master_format=1 \
110+
aec_args='"high_pass_filter=1 noise_suppression=0 analog_gain_control=0"'
111+
EOS
112+
113+
# The script is owned by the pulseaudio system user
114+
pulse_user=pulse
115+
sudo chmod +x /usr/local/bin/pulse-aec.sh
116+
sudo chown ${pulse_user}:${pulse_user} /usr/local/bin/pulse-aec.sh
117+
118+
# Add a service file to run the aec script before the audio server but after pulseaudio
119+
sudo tee /lib/systemd/system/pulseaudio-aec.service > /dev/null <<EOS
120+
[Unit]
121+
Description=PulseAudio AEC Module
122+
After=pulseaudio.service
123+
[Install]
124+
WantedBy=multi-user.target
125+
[Service]
126+
Type=simple
127+
User=${pulse_user}
128+
Group=${pulse_user}
129+
ExecStart=/usr/local/bin/pulse-aec.sh
130+
EOS
131+
132+
# Only run the audio server once echo cancellation is loaded
133+
sudo tee /etc/systemd/system/multi-user.target.wants/snips-audio-server.service > /dev/null <<EOS
134+
[Unit]
135+
Description=Snips Audio Server
136+
After=network.target pulseaudio.service pulseaudio-aec.service
137+
[Service]
138+
User=_snips
139+
Group=_snips
140+
ExecStart=/usr/bin/snips-audio-server
141+
Restart=always
142+
RestartSec=2
143+
[Install]
144+
WantedBy=multi-user.target
145+
EOS
146+
147+
# change default sink and source
148+
sudo sed -i.bak 's/^;\?\s*default-sink.*/default-sink = alsa_output.platform-soc_sound.analog-stereo.echo-cancel/' /etc/pulse/client.conf
149+
sudo sed -i.bak 's/^;\?\s*default-source.*/default-source = alsa_input.platform-soc_sound.analog-stereo.echo-cancel/' /etc/pulse/client.conf
150+
151+
sudo systemctl enable pulseaudio.service
152+
sudo systemctl enable pulseaudio-aec.service
153+
sudo systemctl enable snips-audio-server.service
154+
155+
sudo reboot
156+
```
157+
158+
## Demo
159+
160+
TODO
161+
162+
## Command-list
163+
164+
TOD
165+
166+
## Tips
167+
168+
you must stop the radio before stopping the skill.

Diff for: action-app_radiofm.py

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/usr/bin/env python2
2+
# -*- coding: utf-8 -*-
3+
4+
from snipsTools import SnipsConfigParser
5+
from hermes_python.hermes import Hermes
6+
from hermes_python.ontology import *
7+
import io
8+
#import os
9+
import subprocess
10+
11+
CONFIG_INI = "config.ini"
12+
13+
# If this skill is supposed to run on the satellite,
14+
# please get this mqtt connection info from <config.ini>
15+
# Hint: MQTT server is always running on the master device
16+
MQTT_IP_ADDR = "localhost"
17+
MQTT_PORT = 1883
18+
MQTT_ADDR = "{}:{}".format(MQTT_IP_ADDR, str(MQTT_PORT))
19+
20+
class SnipsAppRadioFM(object):
21+
"""This Class is connecting the snips intents with the two actions.
22+
The fm_start.sh and fm_stop.sh shell scripts contains the radio specifics
23+
commandes you can easly tweak and change the ctronlled radio system by
24+
editing those two script files.
25+
"""
26+
27+
def __init__(self):
28+
# get the configuration if needed
29+
try:
30+
self.config = SnipsConfigParser.read_configuration_file(CONFIG_INI)
31+
except :
32+
self.config = None
33+
34+
# start listening to MQTT
35+
self.start_blocking()
36+
37+
def playRadioFM_callback(self, hermes, intent_message):
38+
# terminate the session first if not continue
39+
hermes.publish_end_session(intent_message.session_id, "")
40+
41+
print '[Received] intent: {}'.format(intent_message.intent.intent_name)
42+
frequency = intent_message.slots.frequency.first().value
43+
#print frequency
44+
subprocess.Popen(['/var/lib/snips/skills/snips-app-radiofm/fm_start.sh',frequency])
45+
46+
hermes.publish_start_session_notification(intent_message.site_id, frequency, "")
47+
48+
def stopRadioFM_callback(self, hermes, intent_message):
49+
# terminate the session first if not continue
50+
hermes.publish_end_session(intent_message.session_id, "")
51+
52+
print '[Received] intent: {}'.format(intent_message.intent.intent_name)
53+
subprocess.Popen(['/var/lib/snips/skills/snips-app-radiofm/fm_stop.sh'])
54+
#os.system('/var/lib/snips/skills/snips-app-radiofm/fm_stop.sh &')
55+
56+
# --> Master callback function, triggered everytime an intent is recognized
57+
def master_intent_callback(self,hermes, intent_message):
58+
coming_intent = intent_message.intent.intent_name
59+
if ':' in coming_intent:
60+
coming_intent = coming_intent.split(":")[1]
61+
if coming_intent == 'playRadioFM':
62+
self.playRadioFM_callback(hermes, intent_message)
63+
if coming_intent == 'stopRadioFM':
64+
self.stopRadioFM_callback(hermes, intent_message)
65+
# more callback and if condition goes here...
66+
67+
# --> Register callback function and start MQTT
68+
def start_blocking(self):
69+
with Hermes(MQTT_ADDR) as h:
70+
h.subscribe_intents(self.master_intent_callback).start()
71+
72+
if __name__ == "__main__":
73+
SnipsAppRadioFM()

Diff for: config.ini.default

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# no section for preset values
2+
3+
[secret]
4+
#empty value for secret values

Diff for: fm_start.sh

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/sh
2+
killall rtl_fm
3+
rtl_fm -f $1e6 -s 200000 -r 48000 | aplay -r 48000 -f S16_LE &
4+
#rtl_fm -M wbfm -f $1e6 -s 200000 -r 48000 | aplay -r 48000 -f S16_LE &

Diff for: fm_stop.sh

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/sh
2+
killall rtl_fm

Diff for: requirements.txt

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Bindings for the hermes protocol
2+
hermes-python>=0.1
3+
4+
# More dependency goes here..

0 commit comments

Comments
 (0)