Creating an Update Daemon for SUSI Smart Speaker

A daemon in reference of operating systems is a computer program that runs as a background process rather than under direct control of the user. Various daemons are being used in SUSI smart speaker. The following daemons have been created Update Daemon Media Discovery Daemon Factory Reset Daemon  In this blog, we’ll be discussing the implementation of the Update Daemon in SUSI.AI Update Daemon Due to the ever-growing coding community, it is needed to provide regular updates to the smart speaker and keep it in sync with the latest technology. Hence an Update Daemon was required that could fetch updates at a regular interval. The Updated Daemon was implemented in the following steps 1.Deciding the Update Interval How frequently should we check for updates was the first question that was tackled while implementing this daemon. We decided that we should check for Update, every time the Raspberry Pi starts and an internet connection was available. 2. Implementing The Decision To start the Update script every time the Raspberry Pi starts, we decided to create Systemd rules. [Unit] Description=Update Check- SUSI Linux Wants=network-online.target After=network-online.target [Service] Type=oneshot ExecStart=/home/pi/SUSI.AI/susi_linux/update_daemon/update_check.sh [Install] WantedBy=multi-user.target The above rule waits for a network connection to be established with the Raspberry Pi and then triggers a bash script that fetches updates 3. Fetching The Updates Now, a bash script was prepared that would fetch the latest changes from the online repo and merge the latest changes in the local repo   #!/bin/sh UPSTREAM=${1:-'@{u}'} LOCAL=$(git rev-parse @) REMOTE=$(git rev-parse "$UPSTREAM") BASE=$(git merge-base @ "$UPSTREAM") CHECK='' if [ $LOCAL = $REMOTE ] then    echo "Up-to-date"    CHECK='up-to-date' elif [ $LOCAL = $BASE ] then    echo "Need to pull"    CHECK=”Need-to-pull” else    echo "Diverged" fi if [$CHECK = "Need-to-pull"] then    git fetch UPSTREAM    git merge UPSTREAM/master fi   Resources https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/sect-managing_services_with_systemd-unit_files https://github.com/fossasia/susi_linux https://github.com/fossasia/susi_server Tags   susi.ai, gsoc, gsoc’18, fossasia, update, daemon, update_daemon, smart speaker, systemd, hardware

Continue ReadingCreating an Update Daemon for SUSI Smart Speaker

Create a Wireless Access Point Using a Raspberry Pi to Connect with SUSI Smart Speaker

To use the pi as a wifi bridge, a local network or just as a wifi range extender.We at FOSSASIA are using it as a network to connect between our SUSI.AI smart speaker and the Android and IOS devices. Or maybe because you can !! :’) Requirements: Raspberry Pi Model 3(since we will be using an internal wifi) Power supply for the Pi. Monitor (optional) Keyboard (optional) Mouse (optional) Steps: 1.Install and upgrade raspbian   Sudo apt-get update && sudo apt-get install   2. Install hostapd and dnsmasq . This will allow us to use our raspberry pi as a wireless access point   apt-get remove --purge hostapd -yqq apt-get update -yqq apt-get upgrade -yqq apt-get install hostapd dnsmasq -yqq   3. Now we will add broadcasting IP and DNS address in the dnsmasq configuration file To access the configuration file use: sudo nano /etc/dnsmasq.co   And to the bottom of the file, add the following commands   interface=wlan0 dhcp-range=10.0.0.2,10.0.0.5,255.255.255.0,12h   Now to select the SSID and the PASSWORD for the access point, we’ll need to change the configurations of hostapd package sudo nano /etc/hostapd/hostapd.conf   Then, use the following commands :   interface=wlan0 hw_mode=g channel=10 auth_algs=1 wpa=2 wpa_key_mgmt=WPA-PSK wpa_pairwise=CCMP rsn_pairwise=CCMP wpa_passphrase="your_broadcasting_password" ssid="your_broadcasting_ssid" ieee80211n=1 wmm_enabled=1 ht_capab=[HT40][SHORT-GI-20][DSSS_CCK-40]   To finally sum up the configuration, we’ll have to create a  custom network interface that combines all the settings that we have made. sudo nano /etc/network/interfaces   And add the following lines it the EOF allow-hotplug wlan0 iface wlan0 inet static address 10.0.0.1 netmask 255.255.255.0 network 10.0.0.0 broadcast 10.0.0.255   Now, we just have to have to disable default interfaces so that they do not interfere with the custom interfaces that we have made. To do so   sudo nano /etc/dhcpcd.conf   Add the following line at the end of the file denyinterfaces wlan0   Now just restart the services   systemctl enable hostapd && systemctl enable dnsmasq sudo service hostapd start && sudo service dnsmasq start sudo reboot   Now, you will be able to enjoy a self-made access point which is used as a basic mode of connection in SUSI Smart Speaker and can also be used in various other access point methods.   References https://frillip.com/using-your-raspberry-pi-3-as-a-wifi-access-point-with-hostapd/ https://github.com/fossasia/susi_linux https://learn.adafruit.com/setting-up-a-raspberry-pi-as-a-wifi-access-point/overview   Tags GSOC’18 , FOSSASIA, ACCESS_POINT, SUSI.AI, GSOC, SUSI , SMART_SPEAKER

Continue ReadingCreate a Wireless Access Point Using a Raspberry Pi to Connect with SUSI Smart Speaker

Adding Audio Streaming from Youtube in SUSI Linux

In this blog post we will describe how the youtube streaming works in the SUSI smart speaker and how audio is streamed directly from youtube videos. To achieve this process, we have used an amazing Open-Source project called MPV music Player along with python libraries like Subprocess. 1.Processing a Query to the server Firstly , the user asks the smart speaker to play the youtube audio by simply adding a ‘play’ word before his/her favorite song. eg. I’ll say ‘play despacito’ and then the command is recognized and a query is sent to the server which sends the following response as a JSON object. "actions": [      {        "type": "answer",        "expression": "Playing Luis Fonsi - Despacito ft. Daddy Yankee"      },      {        "identifier": "kJQP7kiw5Fk",        "identifier_type": "youtube",        "type": "video_play"      }] 2.Parsing the response Then the speaker parses the response in the following way. The Speaker traverses through all the actions returned in the response and checks for all the “identifier” by assigning a custom class to it. class VideoAction(BaseAction):    def __init__(self, identifier , identifier_type):        super().__init__()        self.identifier = identifier        self.identifier_type = identifier_type Now we check whether the query is the type of a custom class VideoAction and then the client processes the query as the response.       elif isinstance(action, VideoAction):           result['identifier'] = action.identifier            audio_url = result['identifier']   3.Implementing the Actions Now that we have identified that the response contains a Video Action, we can finally implement a way to play the audio from the URL. We use a music player called MPV Music Player and the library Subprocess to make it run asynchronously. if 'identifier' in reply.keys():    classifier = reply['identifier']    if classifier[:3] == 'ytd':        video_url = reply['identifier']        video_pid = subprocess.Popen('mpv --no-video https://www.youtube.com/watch?v={} --really-quiet &'.format(video_url[4:]), shell=True)  # nosec #pylint-disable type: ignore        self.video_pid = video_pid.pid This is how audio is streamed from youtube videos in SUSI Smart Speaker. Resources https://github.com/mpv-player/mpv https://docs.python.org/2/library/subprocess.html https://github.com/fossasia/susi_linux https://github.com/fossasia/susi_api_wrapper Tags fossasia, gsoc’18, susi, susi.ai, youtube, music, mp3 , mpv, audio stream  

Continue ReadingAdding Audio Streaming from Youtube in SUSI Linux

Adding Offline support To SUSI Linux

Till now, SUSI smart speaker was working only as an online model like the other speakers in the market. For the first time, we have introduced a feature which allows the speaker to work offline. We deployed the server on the hardware itself and also provide the option of an online server as a fallback.   The Offline Support was implemented in the following steps   Step 1: Deploying SUSI Server Locally   Firstly , configure a bash script to allow automatic deployment of the server along with the initialization of the susi_linux script.   echo "Deploying local server" if  [ ! -e "susi-server" ] then    git clone https://github.com/fossasia/susi_server.git fi if [ -e "susi_server" ] then        cd susi_server    git submodule update --recursive --remote    git submodule update --init --recursive    ./gradlew build    bin/start.sh fi    The above builds the server and deploys it on ‘localhost:4000’.   Then, add the following test on SUSI Linux wrapper to check if the local server is up and running. Using the local server not adds an offline support but also increases the efficiency by around 30%. def check_local_server():    test_params = {        'q': 'Hello',        'timezoneOffset': int(time.timezone / 60)    }    try:        chat_url = 'http://localhost:4000/susi/chat.json'        if (requests.get(chat_url, test_params)):            print('connected to local server')            global api_endpoint            api_endpoint = 'http://localhost:4000'    except requests.exceptions.ConnectionError:        print('local server is down') check_local_server()   As shown above, this is a test checking for the local server. If the local server is down, the online server is chosen as a fallback   Step 2: Adding an Offline STT Service Now, that we are able to process a query offline. We must have a way in which, we can recognize the user’s voice commands without using the internet. For that, we use the service of PocketSphinx. But first, we check if the internet is available or not   def internet_on():        try:            urllib2.urlopen('http://216.58.192.142', timeout=1)  # nosec #pylint-disable type: ignore            return True  # pylint-enable        except urllib2.URLError as err:            print(err)            return False   If the internet connection is available, we use the online STT service which is Google STT ( default) and switch over to PocketSphinx in case the internet connection is not available.   Step 3: Adding the Offline TTS service Finally, we’ll need an offline TTS service which will help us turn SUSI’s response to voice commands. We’ll be using a service called flite TTS as our offline TTS.   elif payload == 'ConnectionError':             self.notify_renderer('error', 'connection')                                  self.notify_renderer('error', 'connection')             config['default_tts'] = 'flite'             os.system('play extras/connect-error.wav')                 We check if there is a ConnectionError, and then we switch to flite TTS after play an error query   Final Output: We now get a Smart Speaker which is functional without any internet connection.   References https://cmusphinx.github.io/wiki/sphinxinaction/ http://www.festvox.org/flite/ https://github.com/fossasia/susi_linux  Tags   Fossasia, susi, gsoc, gsoc’18, offline_tts , offline_stt ,flite , pocketsphinx

Continue ReadingAdding Offline support To SUSI Linux

Creating a Media Daemon for SUSI Smart Speaker

A daemon in reference of operating systems is a computer program that runs as a background process rather than under direct control of the user. Various daemons are being used in SUSI smart speaker. The following features have been created Update Daemon Media Discovery Daemon Factory Reset Daemon In this blog, we’ll be discussing the implementation of the Media Discovery Daemon Media Discovery Daemon: The SUSI Smart speaker will have an essential feature which will allow the Users to play music from their USB devices. Hence , a media daemon will be running which will detect a USB connection and then scan it’s contents checking for all the mp3 files and then create custom SUSI skills to allow SUSI Smart Speaker to play music from your USB device.   The Media Daemon was implemented in the following steps 1.UDEV Rules We had to figure out a way to run our daemon as soon as the user inserted the USB storage and stop the daemon as soon as the USB storage was removed   So, we used UDEV rules to trigger the Media Daemon.   ACTION=="add", KERNEL=="sd?", SUBSYSTEM=="block", ENV{ID_BUS}=="usb", RUN="/home/pi/SUSI.AI/susi_linux/media_daemon/autostart.sh"ACTION=="remove, KERNEL=="sd?", SUBSYSTEM=="block", ENV{ID_BUS}=="usb", RUN="/home/pi/SUSI.AI/susi_linux/media_daemon/autostop.sh" The Udev rules trigger a script called ‘autostart.sh’  on USB detection and a script called ‘autostop.sh’ on USB removal. 2. Custom Skill Creation As the USB connection is now detected ,a script is triggered which checks the presence of a  local SUSI server in the repo. If a local server instance is detected,a python script is triggered which parses through the USB mount point and checks for the list of mp3 files present in the storage device and then create a custom skill file in the local server instance.   media_daemon_folder = os.path.dirname(os.path.abspath(__file__)) base_folder = os.path.dirname(media_daemon_folder) server_skill_folder = os.path.join(base_folder, 'susi_server/susi_server/data/generic_skills/media_discovery') server_settings_folder = os.path.join(base_folder, 'susi_server/susi_server/data/settings') def make_skill(): # pylint-enable    name_of_usb = get_mount_points()    print(type(name_of_usb))    print(name_of_usb[0])    x = name_of_usb[0]    os.chdir('{}'.format(x[1]))    USB = name_of_usb[0]    mp3_files = glob("*.mp3")    f = open( media_daemon_folder +'/custom_skill.txt','w')    music_path = list()    for mp in mp3_files:        music_path.append("{}".format(USB[1]) + "/{}".format(mp))    song_list = " ".join(music_path)    skills = ['play audio','!console:Playing audio from your usb device','{"actions":[','{"type":"audio_play", "identifier_type":"url", "identifier":"file://'+str(song_list) +'"}',']}','eol']    for skill in skills:        f.write(skill + '\n')    f.close()    shutil.move( media_daemon_folder + 'custom_skill.txt', server_skill_folder)    f2 = open(server_settings_folder + 'customized_config.properties','a')    f2.write('local.mode = true')    f2.close() def get_usb_devices():    sdb_devices = map(os.path.realpath, glob('/sys/block/sd*'))    usb_devices = (dev for dev in sdb_devices        if 'usb' in dev.split('/')[5])    return dict((os.path.basename(dev), dev) for dev in usb_devices) def get_mount_points(devices=None):    devices = devices or get_usb_devices() # if devices are None: get_usb_devices    output = check_output(['mount']).splitlines() #nosec #pylint-disable type: ignore    output = [tmp.decode('UTF-8') for tmp in output ] # pytlint-enable    def is_usb(path):        return any(dev in path for dev in devices)    usb_info = (line for line in output if is_usb(line.split()[0]))    return [(info.split()[0], info.split()[2]) for info in usb_info]    Now a custom skill file will be created in the local server instance by the name of `custom_skill.txt` and the user can play audio from USB by speaking the command ‘play audio’   3. Preparing for the Next USB insertion Now if the User wants to update his/her music library…

Continue ReadingCreating a Media Daemon for SUSI Smart Speaker

Connecting to a Raspberry Pi through a SSH connection Wirelessly

The tech stack of the SUSI.AI smart speaker project is mainly Python/Bash scripts. Every smart speaker has an essential feature that allows the user’s mobile device to connect and give instructions to the speaker wirelessly. To make this connection possible, we are trying to implement this using an SSH connection. Why SSH? SSH(a.k.a Secure Shell) is a cryptographic connection which allows secure transfer of data even over an unsecured connection.SSH connection even allows TCP as well as X11 forwarding which are an added bonus. Step 1: Initial Setup Both the raspberry Pi with raspbian installed and the mobile device should be on a same wireless network One should have an SSH viewer like JuiceSSH(Android) and iTerminal(IOS) installed on their mobile devices Now we must enable SSH on our raspberry Pi Step 2: Enabling SSH on Raspberry PI To enable SSH on your Pi , follow the steps mentioned below: Menu > Preferences > Raspberry Pi Configuration. Choose the interfaces tab and enable SSH Step 3:Setting Up the client   Login to your raspberry pi as the root user (pi by default) Type the following command to know the broadcasting ip address pi@raspberrypi:hostname -I   Now , open the client on your mobile device and add the configurations By default the username of the system is ‘pi’ and the password is ‘raspberry’ Step 4: Changing the default SSH password Since the default password of every RaspberryPi is the same. So , the pi can be accessed by any device that has access to the local network which is not a secure way of accessing the device In the SSH window type ‘passwd’ Type the current password Type the new password Re-enter the new password Now you will be able to login to your raspberry through an SSH connection Resources https://www.raspberrypi.org/ https://canva.com/ https://github.com/fossasia/susi_linux Tags Fossasia, gsoc, gsoc’18, susi, susi.ai, hardware,susi_linux

Continue ReadingConnecting to a Raspberry Pi through a SSH connection Wirelessly