Looks like we have a winner
In a previous post, I ranted about a new setup for playing back recorded Made with Magic shows using a Raspberry Pi and an Arduino. The goal was to come up with an affordable setup that can transmit Made with Magic codes that are tightly synchronized with multimedia output. Initial results looked great. The prospect of having a low-cost Made with Magic player that can handle multi-media content is tantalizing, but some questions remained. I couldn't predict if the newer Raspberry Pi models would work the same way as my ancient Raspberry B does. And I don't have enough MWM recordings that have been tightly sync'd to media files to let me conclude that the sync is completely reliable.
Since that post, community member Jorge obtained a Raspberry Pi 3 and, so far, he's been able to confirm that the newer Raspberry models do work with this setup. That's encouraging. Better still, he's done a lot of synchronization work and he tells me that the sync with the new setup is, indeed, good. Excellent. So it looks like we do have a reliable, multimedia enabled Made with Magic player that can be setup for around $80.
Installation hints to make things go smoother
A few things came up while helping Jorge get setup and are worth mentioning. What seems to work best for getting FPP going on the Pi 3 is to install Version 1.8 of Falcon Player. One thing that isn't always clear in the setup instructions is that the Pi has to be connected to Internet via network cable before inserting the SD card and powering up. The Falcon installer scripts immediately heads out over the Internet to download additional packages and do updates. Without that connection, you're not going to be successful.
Another thing that's not always clear is that you gotta have an attached USB storage device. That's where the installer is going to try to initialize the file storage directories. If you don't have an attached USB storage device you'll see an endless progression of notices posted to your screen telling you to plug in such a device and you won't get past that step.
Once the installation finishes, there is often a notice saying you can now log in to http://fpp.local/ and access the admin page. That may or may not work for you. If it doesn't, check the boot up messages on your TV screen and see if you can find anything telling you what IP address was assigned to your Raspberry when it came up. As I write this, http://fpp.local isn't working using my Windows laptop and I have to use http://192.168.0.123 instead. However, my iPhone has no problem getting there using http://fpp.local.
Thinking about trying to use a Pi zero?
Now, some of you have probably seen the new Pi zeros and are wondering if it's possible to shave costs by using one of those. However, the FPP installation requirements make installation on the new Pi zeros a non-starter. I wasted a week trying to work around all the gotchas with nothing to show for it. None of the methods I read about on the various pages/forums worked - including installing on a Pi 3 and then transferring the SD card to the zero. Nope. Theoretically, use of a USB hub should make this possible. But my zero didn't recognize most of the devices plugged into the hub causing things to fail miserably. And the version of Raspbian currently included in the FPP distro (Wheezy) doesn't recognize the zero's wifi hardware. Installing The Stretch Raspbian distro on the zero got the wifi working but installing FPP on top of that didn't work. There's indications that an upcoming version of FPP may switch to the Stretch distro, but we don't seem to be there yet. So, for now, I'm recommending to avoid the Pi zeros. More struggle involved than you're probably looking for. Someday. Just not today.
Having said that, the problem is FPP and not the new zero. If you're willing to forgo all the benefits gained by piggy backing on the FPP platform and setup your own operating environment, you'll be able to replicate the current functionality cuz what we're doing right now is simply running shell scripts. It would be a lot of work but you could go with Node.js and socket.io and build something equivalent for somewhere in the neighborhood of less than $40. But I'm going to guess that most readers will be content to go with the Pi 3 model running FPP to start with and then see what develops for the Pi zeros in the future.
Building a Made with Magic controller page
Encouraged by the good news from Jorge, I managed to get my hands on a newer Raspberry model (version 3) and did some more work to see if I can make the FPP setup a bit more user friendly. Why? Several reasons. The Falcon Player wasn't really designed to be a primary end user interactive tool. The web interface is really helpful but it does have some quirks that some users may find annoying after a while. For instance, when you want to run a script to start a show, you have to click through a few menu layers to get to where you select the desired script and hit the run button. This gets the show going, but it also creates a new browser tab/window. And it does that each time the run button is clicked. Doesn't take long to end up with a bunch of new open windows that need to be closed manually. And, if you start a playback and then decide you want to play something else, you need to wait until the current playback ends or you'll have multiple playbacks running on top of each other. Kind of messy and inconvenient.
Paradoxically, one of the main features that persuaded me to select the Falcon Player platform is that it was designed and built to be controlled using a web interface. So, to come up with something a bit more user friendly, all we need to do is examine the urls they use and then craft our own web page to operate the way we want it to. Looks like the web server looks for pages at /opt/fpp/www and most of the pages are written in the PHP language - that's good cuz it's one I'm familiar with. Hmmm. Looks like all the pages were setup with root/root access privileges. OK. So run touch sudo /opt/fpp/www/mwm.php and then sudo chown fpp /opt/fpp/www/mwm.php. Now it should be possible to compose our new page there and easily make updates using ftp.
Getting a handle on the tab proliferation problem
We're gonna need to pull a list of available scripts to execute and display those a links. PHP can handle that for us. Then we need to use Javascript so we can asynchronously send links to the server without having to open a new window or causing the current window to pause until the media file ends. Javascript can also provide updates to let us know what's happening and to implement some operating rules. Rules? Yeah. For instance, it's probably a good idea to only run one show at a time. And, since anyone with access to the same network could have access to the Stop control, maybe only the person that requested the current show should have access to the Stop control while their show is running so they get to enjoy the whole thing without mischievous interruptions. I'm sure you know who I'm talking about, right?
Some of these ideas are rolled into the mwm.php script that's included in the zip file you can access by clicking here. But some of the changes work best when implemented in a script file. So I've also included a new script template, mwmshelltemplate.sh, in that zip archive. I recommend switching any existing script files you already have to this newer template if you want the new player page to work as expected. You'll also find a .stopvideos.sh file in the archive. That's adapted from a script I found in the script repository. It's function should be self evident. It includes a call to stop.mwm that will turn off the LEDs of MWM devices to prevent carry over effects.
Good script filenames make the output much friendlier
As the MwM page began to take shape, it became clear that more info about each script was needed to have any idea of what each script does. Cryptic filenames for the scripts don't cut it. Nor was the prospect of setting up a separate database very appealing. Maybe the easiest way to handle this is to store the info in the script filenames and then use PHP to parse them and present in a logical manner. The way this is currently handled is to encode three bits of information in the script filename that are separated with the '_' character and looks something like this:
DWO_Jingle-Bells_2016-01-05.sh
The first segment indicates the Disney Park, and maybe also a subcategory. In this case, DWO is parsed by the mwm.php and expanded to Disney World - Osborne Lights. This serves as the heading for shows grouped under that title. Then comes the show name. Spaces are problematic in filenames using Linux. So the '-' character is used instead and is replaced by mwm.php during parsing. Finally, there is the date segment. It's probable that there could be several versions of shows like World of Color and/or any of the Fireworks shows. Including a date segment should help keep those sorted out.
To get this post out as quickly as possible, I haven't yet taken the time to plunk in a number of Park/subcat items into mwm.php. To extend what's available, edit mwm.php where it looks like:
$parks = array();
$parks['DL']='Disneyland';
$parks['DLP']='Disneyland - Parades';
$parks['DWO']='Disney World - Osborne Lights';
I think you get the idea.
One at a time, please
I've already mentioned that it's possible to get two shows running at the same time if you click another while one is already running. A change to the scripts can keep this from happening:
# only allow one show to play at a time
if ! pgrep -x "omxplayer" > /dev/null
then
sudo /home/fpp/media/upload/mwmplayer -d $MWMDELAY -b $BAUD -f $MWMFILE &
sleep $MEDIADELAY
sudo -u fpp /usr/bin/omxplayer --no-keys $MEDIADIR/$TYPE/$MEDIAFILE &
fi
Simple. Have the script check to see if omxplayer is already running and only play the show if it's not. This design is built into the new script template
This feature works hand-in-hand with another feature in mwm.php that only gives access to the stop button to the person who started the current show. This keeps bratty siblings/friends/parents from interrupting your show:
function sendRequest(req){
var oReq = new XMLHttpRequest();
oReq.addEventListener("loadend", loadEnd);
oReq.open("GET", req.href);
oReq.send();
var str = req.href;
var ff = document.getElementById('playing');
ff.innerHTML=req.innerHTML;
document.getElementById('off').removeAttribute("disabled");
return false;
}
function loadEnd(e) {
console.log("The transfer is complete.");
var ff = document.getElementById('playing');
ff.innerHTML = " ";
document.getElementById('off').setAttribute("disabled", "disabled");
}
The only gotcha with this setup occurs if the person who started the show clicks another show while the current show is still running. That will cause the Stop button to become disabled and you'll have to navigate to the main FPP scripts section to run .stopvideos.sh and stop the show.
For developers, let's clean up the Arduino script and make it handle missing checksums
In the previous post, I included an Arduino script that wasn't all that well suited for the task. I've gone through and cleaned up the code a bit and removed junk that isn't needed. Then I added in code to complete the checksums for phrases missing that byte. Should make it easier on developers to do their thing without having to calculate all those checksums. So I recommend switching to using the included ArduinoRaspberryMWMDev.ino.
What now?
Download and unpack the zip file. Then use the FPP filemanager to upload the following to the indicated sections:
Video
Jinglebells360.mp4
Audio
msep.mp3
Scripts
mwmshelltemplate.sh
.stopvideos.sh
DWO_Jingle-Bells_2016-01-05.sh
DLP_Main-St-Electrical-Parade_2017.sh
Uploads
mwm.php
stop.mwm
jingle_bells.mwm
mwmplayer
mwmplayer4.c
MSEP_dht0009_ESP.txt
Arduino
ArduinoRaspberryMWMDev.ino
Then fire up a browser and go to either http://fpp.local/mwm.php or http://youripaddress/mwm.php and see if it works.
How does all this fit in with the new Connect 3.0 stuff?
Short answer: it doesn't
Right now, none of this seems to work with the new Connect 3.0 hats. For some reason, the new hats won't respond to the transmitted IR codes from the legacy shows. Don't know why. The new hats do respond to shorter codes like those sent from wand devices. They have the traditional IR receivers like all the previous MWM merchandise. So? It's a bit of a puzzle right now.
Anything we can do about that?
The next thing to try with the Connect 3.0 hats is to convert the show codes to Bluetooth ADV packets and send those out at the appropriate times to see if they can keep up with the program if the codes arrive via Bluetooth instead of IR. Sniffing the Bluetooth communications, I've come to the conclusion that the new hats don't actually connect to a specific master Bluetooth transmitter. Rather, the codes are packed into ADV packets in the 128 bit UUID segment. That nicely provides for 16 bytes - which is the max length for legacy MWM phrases, minus the leading 0x9X and trailing checksum. The leading 0x9X isn't necessary as all commands will be 16 bytes - period. The checksum isn't needed as the Bluetooth packet has it's own checksum. So that explains that. Any MWM phrase that's less than 16 bytes appears to be packed with leading 0x70 bytes to get the total up to 16. We can see this strategy preserved in the IR phrases sent out by the new hats when they echo commands to nearby legacy devices during the TV specials. Each transmission from the Connect 3.0 hat is similar to:
9F 70 70 70 70 71 3E 11 27 62 D2 38 02 03 20 02 10 92
They're all the same length. The padding with 0x70 bytes is included in the echoed IR transmissions. And that seems to work just fine for the legacy devices - as long as they are very close to the Connect 3.0 hats.
OK. So how are we going to start sending out Bluetooth ADV packets? Good question. The new hats use what looks like a Nordic Semi chip to handle the Connect 3.0 processing. So maybe we could go that route. But what seems more enticing is to see if the new Raspberry Pi 3 with their built in Bluetooth capabilities can do the deed.
The approach seems straightforward. Have the Raspberry read the legacy codes and when the timestamp says it's time to send, chop off the leading 0x9X and trailing checksum and pad the result with leading 0x70 bytes. Package the code into the UUID segment of a Bluetooth ADV packet and send it out on channels 37,38 and 39. Done. Now all I gotta do is figure out how to do that and give it a try. Should be interesting. From what I read, most Bluetooth devices conserve power by sleeping between checks for ADV packets. The length of time spent sleeping is adjustable. The longer between checks, the more power saved. Doesn't seem like the ideal setup for a device intended for precise on demand responses. We'll see.
How about real-time conversion of Connect 3.0 commands into legacy IR codes?
It's kind of depressing to see all those older Made with Magic goodies lying there doing nothing during those special TV broadcasts. Ought to be some way to get them in on the festivities. Well, the Connect 3.0 devices DO echo the commands in IR format. But the transmission distance is not very far. To get better coverage, we'd need to build our own Bluetooth responder that can read the Bluetooth ADV packets and convert those into IR equivalents that can be blasted out as a stronger signal to make all those venerable ancient ones happy, too. Any way you slice it, gonna have to roll up the sleeves and dig into this Bluetooth stuff in the near future. Oh goodie. As if there wasn't already more than enough to do.