Control Rasp Pi slide shows wirelessly
Evolving the Wireless Clicker
The wireless clicker represents the next evolution of slide-changing technology (Figures 4 and 5). It bypasses the GPIO pins on the Rasp Pi and sends button pushes directly to the Python script over the network. It all happens through the magic of the ESP8266 WiFi microcontroller [4].
Guess what? You can program the ESP8266 module using the Arduino IDE [5], which has become an industry standard development environment. After downloading the latest version from the Arduino site [6] and starting it up, add the libraries, if needed, by clicking on Sketch | Include Library | Manage Libraries. Copy the code in Listing 1 into a new edit window and save the file as slide-scroll
. The IDE might create a new directory.
Listing 1
slide-scroll
001 // 8266 wireless clicker firmware code 002 #include <ESP8266WiFi.h> 003 #include <DNSServer.h> 004 #include <ESP8266WebServer.h> 005 #include <WiFiManager.h> 006 007 void configModeCallback (WiFiManager *myWiFiManager) { 008 Serial.println("Entered config mode"); 009 Serial.println(WiFi.softAPIP()); 010 //if you used auto generated SSID, print it 011 Serial.println(myWiFiManager->getConfigPortalSSID()); 012 } 013 014 const int ledPin = 5; 015 const int buttonPin4 = 4; 016 int buttonState4 = 0; 017 const int buttonPin16 = 16; 018 int buttonState16 = 0; 019 WiFiServer server(1337); 020 021 void printWiFiStatus(); 022 023 void setup(void) { 024 Serial.begin(115200); 025 026 WiFiManager wifiManager; 027 // wifiManager.resetSettings(); 028 wifiManager.setAPCallback(configModeCallback); 029 030 if(!wifiManager.autoConnect()) { 031 Serial.println("failed to connect and hit timeout"); 032 ESP.reset(); 033 delay(1000); 034 } 035 036 // Configure GPIO2 as OUTPUT. 037 pinMode(ledPin, OUTPUT); 038 pinMode(buttonPin4, INPUT); 039 040 // Start TCP server. 041 server.begin(); 042 } 043 void loop(void) { 044 045 // Check if module is still connected to WiFi. 046 if (WiFi.status() != WL_CONNECTED) { 047 Serial.println("WiFi connected inside void loop"); 048 while (WiFi.status() != WL_CONNECTED) { 049 Serial.println("WiFi.status connected loop"); 050 delay(500); 051 } 052 // Print the new IP to Serial. 053 printWiFiStatus(); 054 } 055 056 WiFiClient client = server.available(); 057 058 if (client) { 059 Serial.println("Client connected."); 060 061 while (client.connected()) { 062 063 buttonState4 = digitalRead(buttonPin4); 064 // Serial.println(buttonState4); 065 if (buttonState4 == HIGH) { 066 // digitalWrite(5, HIGH); 067 Serial.println("UP Button pushed"); 068 client.write("U\n"); 069 delay(250); 070 } 071 072 buttonState16 = digitalRead(buttonPin16); 073 // Serial.println(buttonState16); 074 if (buttonState16 == HIGH) { 075 // digitalWrite(5, HIGH); 076 Serial.println("DOWN Button pushed"); 077 client.write("D\n"); 078 delay(250); 079 } 080 081 if (client.available()) { 082 083 char command = client.read(); 084 if (command == 'H') { 085 digitalWrite(ledPin, HIGH); 086 Serial.println("LED is now on."); 087 client.write("LED is now on."); 088 } 089 else if (command == 'L') { 090 digitalWrite(ledPin, LOW); 091 Serial.println("LED is now off."); 092 client.write("LED is now off."); 093 } 094 } 095 } 096 Serial.println("Client disconnected."); 097 client.stop(); 098 } 099 } 100 101 void printWiFiStatus() { 102 Serial.println(""); 103 Serial.print("Connected to "); 104 // Serial.println(ssid); 105 Serial.print("IP address: "); 106 Serial.println(WiFi.localIP()); 107 }
Getting the ESP8266 into programming mode requires a little trick. First, disconnect ESP8266 GPIO pin 0 from the positive 3.3V connection and move it to Ground (GND) on the breadboard. Next, disconnect the TX line and temporarily short the Reset line (REST on the schematic) to GND. Immediately remove REST from GND and plug the TX line back into its proper place in the breadboard. The 8266 is now configured, reset, and ready for a firmware upload.
Hit the Upload button in the IDE, and you should see the program compile the code. After a short while, the blue LED on the ESP8266 should start flashing as the code is uploaded to the chip. Uploading is complete when the LED stops flashing.
To see the text, open the Arduino IDE serial window and push one of the buttons on the clicker. You should see UP Button pushed or DOWN Button pushed each time you push a button.
Configuring networking on the 8266 clicker is done through a web page on the device. Open your standard WiFi access point configuration window on your smartphone and find and click on a new access point with a name 8266, ESP, or something along those lines. Once, that's done, start up a browser on your phone and punch in 192.168.4.1. Hit Enter and you should see a WiFi configuration pop up (Figure 6). Select Configure WiFi, use your local LAN SSID, and enter the correct passphrase, if asked. The ESP8266 will then reboot and connect to your local LAN. You should see a message in the IDE serial terminal saying that you are connected.
Notice the lines of code for a mysterious LED on the wireless clicker. I left that code in so readers could play around with two-way communication. I used the command-line program netcat
[7] from a terminal on my Linux notebook to prototype this funcionality with:
rob% netcat 192.168.1.108 1337
If you type an H, the LED should light; type an L, and it should go out. Ctrl+C exits netcat. You might write some Python code to send an H to the clicker to turn the LED on when you have 5 minutes left in your presentation, for example.
The Python script on the presentation machine (Rasp Pi side) used for wireless operation is just a slightly modded version of the original wired code (Listing 2). The only real differences are in capturing data from a network connection, instead of watching a couple of GPIO pins. I like the idea that it's fairly straightforward to modify the readily available hardware's behavior by simply changing a few lines of code (Listing 3).
Listing 2
Original Wired Script
01 import os 02 import RPi.GPIO as GPIO 03 import time 04 05 GPIO.setmode(GPIO.BCM) 06 07 GPIO.setup(20, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 08 GPIO.setup(21, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 09 10 while True: 11 input_state = GPIO.input(20) 12 if input_state == True: 13 os.system("xdotool search --name 'Impress' key Up") 14 print('Up Button Pressed') 15 time.sleep(0.2) 16 17 input_state = GPIO.input(21) 18 if input_state == True: 19 os.system("xdotool search --name 'Impress' key Down") 20 print('Down Button Pressed') 21 time.sleep(0.2)
Listing 3
wireless-clicker.py
01 #client example 02 import socket 03 import time 04 import os 05 06 client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 07 client_socket.connect(('192.168.1.108', 1337)) 08 while 1: 09 data = client_socket.recv(512) 10 if 'U' in data: 11 os.system("xdotool search --name 'Impress' key Up") 12 print('UP Button Pressed') 13 time.sleep(0.2) 14 15 # input_state = GPIO.input(24) 16 if 'D' in data: 17 os.system("xdotool search --name 'Impress' key Down") 18 print('DOWN Button Pressed') 19 time.sleep(0.2)
Of course, I'm assuming that the ESP8266 wireless clicker connects to the local LAN using an IP address of 192.168.1.108. You might have to adjust that address, depending on your network settings.
Using the Wireless Clicker
Once the wireless clicker is connected to the local LAN, it's easy to use it with the presentation machine. To begin, log in to a terminal on the presentation machine and start the wireless clicker Python script:
rob% python wireless-clicker.py
You should see an UP Button Pressed or DOWN Button Pressed message appear on the terminal screen as you push the buttons on the clicker.
Fire up LibreOffice Impress [8] with your presentation of choice. Under the Slide Sorter tab, be sure to highlight the first slide. Next, click Slide Show | Start from first Slide in the main Impress menu. The first slide in your presentation should appear on your display. Push the Down button on the wireless clicker and you should move to the next slide.
It's important to make sure the cursor is positioned highlighting one of the slides under the Slide Sorter tab; otherwise, Impress won't capture the keystroke in the right window. You'll end up wondering why the clicker doesn't work. I didn't recognize the behavior during one of my conference talks using the wired model and had to revert back to using the keyboard and mousepad. It was a bit of a let-down for the audience.
« Previous 1 2 3 Next »