-
11Step 11
Text-to-Speech Code
The code to interface to espeak is in a separate file: speech.py
import time from espeak import espeak from espeak import core as espeak_core def say(*args): done_synth = [False] def synth_callback(event, pos, length): if event == espeak_core.event_MSG_TERMINATED: done_synth[0] = True espeak.set_SynthCallback(synth_callback) call_result = espeak.synth(*args) while call_result and not done_synth[0]: time.sleep(0.05) return call_result
This is lifted from a forum post by the wrapper's author Siegfried Gevatter.
The text to be spoken is passed to espeak.synth() and the routine then waits until the message has been spoken and the event_MSG_TERMINATED has been triggered.
-
12Step 12
Installation
Make a new directory, say /home/pi/Python with subdirectory /home/pi/Python/templates.
Put the .py files in Python, and the .html files in templates.
Follow the instructions to edit /etc/alsa/alsa.conf and /home/pi/.asoundrc if necessary.
You should now be able to run the server from the directory /home/pi/Python by typing:
sudo python piHole.py
Make sure you know your Raspberry Pi's IP address (type "ip address show" from the command line - let's say yours is 192.168.1.123), then fire up a browser on any machine on your LAN and enter the address http://192.168.1.123:9012 and you should see the main menu.
The ":9012" bit at the end is a port number. You'll see I specified this port number in the app.run() call at the bottom of the main program. (You can use "any" port number, I chose 9012 because it's piHole's project number at hackaday.io.)
(You could leave out the port argument to app.run() and the default, :80 would be used, but I'm sure you'll want to have other services/servers running on your Pi. Also a unique port number makes it easy to access your Pi from the internet - see below.)
if you want to be able to access piHole from outside your home LAN, you'll need to
a. Configure your router to assign a static IP address to your Pi.
b. Configure your router to forward port 9012 to your Pi's IP address.
c. Know your external IP address! (Let's say it's 99.99.99.99.)
Now you can just enter http://99.99.99.99:9012 in your browser's address bar to access piHole from anywhere.
(Note that some routers - e.g. Comcast gateways - don't support Nat loopback, and consequently you won't be able to access your Pi using your external IP address from within your home LAN. Just connect to your elderly neighbour's "linksys" WLAN to test.)
-
13Step 13
Making the Script Autorun at Boot
Raspbian Jessie uses systemd to start and stop daemons (servers/services).
I followed these instructions to create the file /lib/systemd/system/piHole.service
Description=piHole Service After=multi-user.target [Service] Type=idle ExecStart=/usr/bin/python /home/pi/Python/piHole.py Restart=always [Install] WantedBy=multi-user.target
Note that the path to piHole.py should match your installation directory. I've added a "Restart=always" directive so systemd will restart piHole if it exits/crashes for any reason.With the attached code, you can force a restart remotely by entering the address "http://192.168.1.123:9012/quit"; in your browser.
You'll need to use "sudo" to copy/edit the piHole.service file into the directory /lib/systemd/system and you need to give the file the correct permissions by running
sudo chmod 644 /lib/systemd/system/piHole.service
When this is done, you can force systemd to read the new file by enteringsudo systemctl daemon-reload
and you can then start the service by runningsudo systemctl enable piHole.service
You can check on the status of the service by running
sudo systemctl status piHole.service
If you're running an older version of Raspbian you'll have to google for "how to autorun a Python script using init.d". I can't say which of the dozens of search results you should try because I haven't tried any of them. -
14Step 14
Summary
And that's it!
I hope this simple project gives you some new tools to play with and inspires swarms of talking projects. For my own part, I'll probably port piHole to an existing (non-Pi) Linux server that's sitting in my living room anyway. But I'll certainly be re-using bits of piHole in future Pi Zero projects (with Adafruit's GPIO 18 hack).
-
15Step 15
P.S.
I'm shocked, shocked! to note that my kids are abusing piHole. I've modified the code for Say_post(), log_add() and piHole_log.html to show "where" the message originated.
@app.route('/say', methods=['POST']) def say_post(): name = request.form['name'] text = request.form['text'] speech.say(name + " says " + text) log_add(name, request.environ['REMOTE_ADDR'], text) templateData = {'name' : name} return render_template("piHole_say.html", **templateData)
def log_add(who, where, what): global message_log when = time.strftime('%H:%M:%S') message_log.append((when, where, who, what))
<!DOCTYPE HTML> <html> <head> {# Define "row" class with tab stops #} <style> {body: font-family: arial;} div.row span{position: absolute;} div.row span:nth-child(1){left: 0px;} div.row span:nth-child(2){left: 70px;} div.row span:nth-child(3){left: 160px;} div.row span:nth-child(4){left: 250px;} </style> {# Refresh the page every 15 seconds #} <META HTTP-EQUIV="refresh" CONTENT="15"> </head> <h1>piHole - Message log</h1> <body> {# Column headers #} <div class="row"> <span><b>When?</b></span> <span><b>Where?</b></span> <span><b>Who?</b></span> <span><b>What?</b></span> </div><br> {# Jinja2 loop displaying each entry tuple in data parameter "log" #} {% for entry in log %} <div class="row"> <span>{{entry.0}}</span> <span>{{entry.1}}</span> <span>{{entry.2}}</span> <span>{{entry.3}}</span> </div><br> {% endfor %} <br> <a href="/say">Send text-to-speech message</a><br> <a href="/">Main menu</a> </body> </html>
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
Works wonderfully! Note in step 11 the code omits the imports, which are in the linked forum post code.
Are you sure? yes | no
Thanks for the feedback Denise. Fixed in §11
Are you sure? yes | no