Introduction: WiFi/Bluetooth Speaker

Introduction, how it all began...

A long long time ago (well last year to be exact) my son came home from school with his end of year project, to build a motorized drawbridge. I, being the interfering father jumped all over this and next thing you know I was killing two birds with one stone, allowing me to get my first rPi (which I had heard about but never really explored) and bonding with my son with a shared objective. Probably should have reversed the order of that previous sentence!

Anyhow to cut a long story short, we ended up dismantling an old ink jet printer to cannibalise its parts, full of motors and drive belts, (and sticky ink!!!) and with my newly acquired rPi we ended up, having also learnt rudimentary Python, with a working model. This unfortunately never made it to the classroom as my son was convinced that there would be no way the teacher would believe he made it, so a simpler electronic circuit was implemented that did the same(ish) thing.

Unfortunate yes, but it whetted my appetite and my love of electronics (which I hadn't used for 30 years) to see what else could be done here!

Now, whilst the rPi is a great little machine, the one thing I really didn't like about it (for what I was thinking about), was the operating system aspect of it. It needs to be powered up and down correctly, taking time to do so. It does a lot more than I had intentions for, so was a bit overkill. This is when I started looking around for something more appropriate, that was cheap and fun. Hence my foray into the land of Arduino and all its clones/sisters/relatives.

The Arduino seemed like the perfect board for me, programmed in C++ (which is nearly the 'C' I am familiar with); could be powered on and off at will without killing it; comes with a very enthusiastic user community and comprehensive/useful libraries for every sensor, component, display, lights and/or use I could envisage.

And so began the journey, ordered a Nano and Uno from Arduino then first step (the MCB equivalent of Hello World), Blink.ino...

From Blink to NeoPixels is a very small step technically, but a massive step in terms of inspiration and opportunity. Suddenly I was in a world of individually addressable colored lights and patterns and fades and motion, now what?

The Idea

Having messed around with NeoPixels for a while I started looking at what to do with them. I had bought an 8x8 NeoPixel matrix as well as strips and though, how can I make these move to music? Wouldn't it be cool to display a VU meter in NeoPixels. Quick search of Arduino, Instructables and Google provided plenty of inspiration, and provided a simple circuit and sketch which takes in line level audio signal and turns it into wavebands and numbers.

So I thought, wouldn't it be great to build a self contained speaker, which lit up in time with the music, with bespoke patterns that I could program. This was it, this is what I wanted to build, and so the journey began...

Health Warning

This project has been a labour of love, sweat and tears over a period of 6 months. It was undertaken to scratch an itch I had about MCB's and rPi. Throughout this project I have needed to learn new techniques, languages, tools, and technologies to name but a few below:

  • Arduino IDE / Libraries
  • NodeMCU
  • Raspbian
  • C++ / Python / Javascript
  • NodeRed
  • Mosquito / MQTT / JSON
  • Fabrication / Routers (scary high speed, sharp, noisy woodworking tool)

There is too much in this project to write up as a "recipe". Each step forward has often involved taking a half step backwards. Google / Instructable / etc. are all your friends here. Nothing I experienced, other than being a challenge to resolve, work through or around, rethink or redesign was impossible to overcome. I'm not saying it was easy, it wasn't, but then again if we wanted it easy, it would probably be cheaper to go and buy something ready-made off the shelf.

Supplies

To get going, some bits would be used later, others just to get familiar with the technology:

  • rPi 3B+
  • Arduino Nano and Uno
  • One down on its luck Ink Jet Printer
  • NeoPixel 8x8 matrix and 2m strip
  • Various beginners resistor, capacitor kit + starter breadboard and connection wires

Final Components List:

  • Light Control
  • 1 x Arduino Mega and NodeMCU combined (Wemos Mega Wifi)
  • Custom built audio analysers (PCB, capacitors, resistors + pair of chinese nano's)
  • 2m (120) 5v NeoPixel strip
  • 4 x 8x8 NeoPixel matrix
  • Player
  • 1 x Android Car Head Unit
  • 1 pair 40W car speakers
  • 1 x passive subwoofer
  • MQTT Control
  • rPi 3B+ running Raspbian, Mosquitto and NodeRed
  • Enclosure
  • 1 x APX Power Supply
  • Approx 2 sq meters 18mm MDF (scrap used for internals)
  • Approx 500x2000mm of 6mm crosscut flexiply
  • 5m of 15x10mm ruber strip (for edging)
  • 1 sq meter of 4mm polycarb sheet
  • 1 sq meter of mirror film

Plus:

- screws, nails, glue, silicon sealant, electrical connector blocks, sandpaper, varnish, heat shrink tube, etc.

Tools Used:

  • Soldering Iron & Solder
  • Screw Driver
  • Drill
  • Black and Decker vibrating saw (the best!!!)
  • Hot Glue Gun
  • Patience, blood, sweat and tears!

Step 1: Building the Audio Analysers

Arduino has a great FFT library example for taking an analogue signal and converting it to a DC spectrum. I wont pretend to understand how it works, that would require a level of maths that I do not have, however work it does and if you're interested there is plenty out in the t'internet to satisfy your curiosity.

This example sketch, plus a simple circuit below produced a nice steady stream of numbers.

Thank you Shajeeb (hackster.io) for the circuit and support.

Here is now when it all gets a bit chicken-and-egg. Whilst using the Serial Monitor to see what the FFT library is spitting out certainly gives an indication its doing something (of course plugged into an audio output channel), unless you can decipher these (ala watching the Matrix), it becomes very difficult to determine what it is actually generating.

Therefor I had to take the sketch to the next level and integrate the NeoPixel matrix (no pun intended) into the process in order to visualize what I was looking at. I did this by getting the FFT sketch to generate 8 bands of values, mapped between 0 and 7. Therefor each band could be displayed as a pixel in the respective column.

Now things started happening, I could see the music displayed crudely in front of me.

Next step, make it stereo, so:

  • Doubled up the circuit for left and right channel
  • Replaced my single proper shop-bought-from-Arduino Nano (must support Arduino/AdaFruit/etc as they do a great and wonderful job for all us hobbyists and education in general!), with 2 cheap Chinese knock offs from Wish.com (which worked perfectly btw!)
  • Bought 4 (8x8) matrixes, to allow 2 stereo 16 bands to be presented

Now we are cooking, 2 analyser circuits working in parallel, driving what looked like a reasonable representation of what I was listening to, i.e. the bass, mid and treble levels looked consistent, they dropped when the music quietened, raised and spread when it got going. I was happy...

Well not quite, the circuit I had soldered together on protoboard looked a bit nasty. Not to mention, I was chatting with a lad from work who told me about custom PCB printing, well stop me.....!!!! I wanted to have a go at that.

Now was the time to start learning something else new, so downloaded Fritzing (thank you guys, what a tool) and with a few hours invested I managed to recreate the circuit from Breadboard view, to Circuit View and finally into Gerber View! There are many providers out there for this type of service and I wont recommend one over the other, you pays your money, etc, but I was delighted with what I got back after uploading the files produced by Fritzing. All errors on the board were of my own making, and were limited to some dodgy screen printed labels, but the circuit literally worked first time, not one issue!

One lesson learned here when creating a custom PCB, try to consider how it will integrate with other things. I should have designed this as a shield, with headers that married up with an Arduino, it would have been much easier to accommodate. As it happened I "lucked out" and accidentally had 2 mounting holes in the PCB which "accidentally" lined up with 2 on the Arduino so, whilst not as neat, managed to get me out of an issue.

NOTE: As a related aside to the above lesson learned, plugging connector cables in and out of the Arduino headers tends to make them a bit "baggy". If I had created the PCB as a shield it would have reduced this issue and made everything much more robust.

Step Conclusion

So now I have a stereo analyser, nicely running on a custom built (purple) PCB, presenting values on a crude 8x32 [2x(8x16)] matrix.

Next step to add some smarts and make the display a bit more engaging.

Supplies and Tools

There are many components needed here, and perfectly described in the referenced in 32-Band Audio Spectrum Visualizer Analyzer.

In addition to this I used:

  • 2 x Arduino Nano clones
  • Customer built PCB
  • Soldering iron and multi-meter (to check for shorts/dry joints)
  • Audio cable (with one set of RCA connectors cut off to provide signal to board)

Step 2: Building the Lighting Controllers

Ok, so to get the information being analysed and generated on the VU Analysers I decided to pass this data over I2C. The Arduino (Mega) would act as the Master, and the 2 analysers would be slaves. I created a very simple 16 char protocol, which could be much more efficient I'm sure, however worked well and certainly did not impact performance.

Each VU analyser stores its last complete set of 16 byte/char values (character between 0 and 8) in an array, indicating level of each spectrum range, i.e. "8765432100000000" would describe a straight line drop from 8 to 0, then flat line at zero, indicating no "sound" in this spectrum. The Mega then, every 50ms or so, requested data from each analyser in turn. This request interrupts the analyser, to send the last complete buffer it has, then lets it continue on. This way I could be assured that the analyser would not send back half processed values.

These values (for left and right channels) are then stored and manipulated to determine how to represent these visually.

Link below to the analyser code.

The simplest to understand is displaying VU metre type displays. Each character in the analyser data maps directly to a value to be displayed, i.e. using the above example, in column 1 we display 8 lights, in column 2 we display 7, in 3 we display 6, etc, etc.

For the more creative patterns I got the Mega to do some maths on the raw data and aggregate/sum. This enabled non-VU patterns to use triggers, i.e. to set a threshold value above which lights would be triggered, everything under this threshold would be thrown away. The value above this threshold could also be used to change the intensity, speed and colour of the triggered lights, e.g. for a loud sound (with a value well above the threshold) we could specify it to be bright and fast, whereas a low quiet sound can generate and dull, slow light. You can see this in action in the attached videos.

So, in summary, the data retrieved from the analysers (16 bytes) per channel (left and right) could be used to directly generate data to be displayed in a VU type pattern, or summed and used to trigger lights to kick in only when a threshold exceeded, and the amount above this threshold used to vary the generated output.

The Mega effectively drives 2 separate NeoPixel light circuits.

  1. The Matrix 4x(8x8) panels
  2. The Strip (120) sequential lights

I used the excellent FastLED library to address and control each NeoPixel.

The Strip

The strip is the easiest to control and visualise and (certainly at this point in time) driven purely using trigger data.

I created a class (clsPixel) which would hold everything about a particular triggered value/event. E.g. Depending upon the value the clsPixel object determines how wide it is and how fast it should go. The louder the sound the bigger and faster the clsPixel travel. The clsPixel objects had intelligence in them to determine how (and more specifically where and when) they should displayed, and when they should die and make way for a new item. This was to stop the strip becoming overly congested and fully illuminated.

I then created an array of clsPixel objects called clsPixelBuffer. This array is populated with a new "Pixel" each time a value comes in to trigger it. This object controls adding and killing pixels and triggering them to move.

Please note, in this application the pixel is not a single LED.

Depending upon the selected pattern (which we'll discuss later how this works), certain rules are defined about how the pixel behaves when it reaches the end (or beginning) of the strip. E.g.

// Pixel actions (Strip)

  • const byte PIX_STOP = 0b00000001; // Stop pixel at the end... (Either end)
  • const byte PIX_LOOP = 0b00000010; // Go back to start/end loop
  • const byte PIX_BOUNCE = 0b00000100; // Reverse direction
  • const byte PIX_RANDOM = 0b00001000; // Randomly determine wether to bounce, loop (or stop)
  • const byte PIX_SLOWDOWN = 0b00010000; // Slow down
  • const byte PIX_FADE = 0b00100000; // Fade down
  • const byte PIX_SHRINK = 0b01000000; // Shrink
  • const byte PIX_BRIGHTEN = 0b10000000; // Increase intensity...

So for a pattern that is setup as PIX_BOUNCE & PIX_FADE a pixel will reverse direction and fade when it reaches each end stop. The conditions for it to die, in this case will be when the pixel fades to black, in which case it will vacate its slot and let a new pixel takes its place when a trigger received.

The Matrix

The matrix is not too difficult to understand, instead of delaing with absolute LEDs in the strip, it is easier/essential to work with rows and columns. Accordingly instead of direct access to turn LED's on, I wrote a simple wrapper function to translate a row/column into an absolute LED address, e.g.

inline void clsMatrixCtrl::setPixelVal(int pRow, int pCol, CRGB pPixel)
{
int idx = 0;
idx = pRow + (pCol * MATRIX_HEIGHT);
if (idx >= MATRIX_LEDS) {
error("Index out of range [%d][%d]=(%d/%d)", pRow, pCol, idx, MATRIX_LEDS);
}
else
leds[idx] = pPixel;
}

Again, in a similar way to the strip clsPixelBuffer, some of the matrix patterns work with triggers. Using the same clsPixel meant that again the intelligence of how to display the pixel in the matrix is handled automatically, so once it is created (and its parameters set by the selected pattern) it goes off on its merry way, until it sadly dies for whatever reason! :( However, don't be sad, a new one will be born the next time the audio triggers it.

Colour Selection

Each pixel has a colour, so to give the display some interest I generated a pseudo-random colour pallette based on the selected colour (discussed later). When the colour is changed a "suitable" set of colours are added to an array. As each pixel is created it selects a random colour from the pallette. So for example Rainbow pretty much covered the full colour spectrum. Therefor when a pixel is created it can essentially pick any colour at random. However for a Blue colour scheme, the colour pallette is seeded with only colours in the Blue Hue from say cyan to royal blue.

Colour and Strip/Matrix Pattern Selection

I originally enabled this control using an OLED display, 4 push buttons (SELECT, UP, DOWN, BACK) and a massive state-machine, which enabled user to walk through the menu system and select sub-menus, etc finally down to an endpoint to change a colour or pattern. This was very costly, from a memory perspective, and a bit frustrating to use as it wasn't very reactive, due in large to the time slot their pressing was given in the larger scheme on Arduino of reading analysers and doing the maths for controlling the NeoPixel strip and matrix(es).

So based on this fact and that I:

  1. Wanted to WiFi it!
  2. Wanted to control other devices (yet to be devised) in sync with the speaker
  3. Ran out of room in the sketch

decided to move all this functionality off of the Arduino, and therefor provide a bit more resource breathing space on it, and put it onto the rPI using NodeRed and Mosquito MQTT server (discussed later). This enable the Arduino code to simply react to pattern and colour changes triggered and controlled externally.

I also moved the threshold level setting, which was originally controlled using a potentiometer, off into rPI land.

Link below to the Audio Light Controller code.

Step 3: Adding the Audio Source

I never required pure audiophile quality sound, which was handy as this can be expensive in terms of components. Additionally at 50 (hrmmmm..) and a bit years old, my ears are not as sensitive as they once were, so high frequencies are a thing of the past for me. That said, I did want it to sound good, and I wanted it to be nice a bass(y) to work well with the boys music.

I went through a number of different options and trials here:

  • Using Volumio on the RPi - I tried and discounted this initially as I did not want to sacrifice my RPi and 7" touch screen to be just a music player. Additionally it needed a DAC shield to provide a reasonable sound so was getting a bit expensive. In hind sight (see adding WiFi section) it may have been the better option to use, as I could also have run the MQTT server on it, however my decision was no.
  • I also "borrowed" the Chromecast from our bedroom television. Whilst this not go down greatly with my better half, was quite a nice solution. I ordered a simple 7" LED screen and driver board which handled HDMI interface, but to extract the sound from the Chromecast also required a 3rd component HDMI splitter box which passed through the HDMI video signal and presented the audio on stereo RCA jacks. It allowed you to cast whatever you wanted from your phone (Spotify, YouTube, even Netflix) onto the LCD screen and hear it through the audio jacks (at this time wired into an external amp). This was going to be the solution except there was a problem. For some reason the sound would frequently drop out. I think it was down to the HDMI splitter box. After many hours trying to identify the issue, and many hours of listening to "when are you putting the Chromecast back on the tele" I decided that there were too many separate components in the signal chain (including my wife!) and wanted to simplify.

This led me to the final solution, to use a cheap Android car head unit. This contained everything I needed in a nice neat package:

  • Music (Spotify, Google Music, Soundcloud, etc)
  • Youtube and Netflix
  • Radio
  • Touch screen control
  • Bluetooth and WiFi
  • etc.

Coupled with some meaty car speakers could be a good solution. So I ordered a cheap Android 8.1 head unit from Wish and waited for it to arrive. I was not expecting greatness from this, however made sure it had an external amplifier connector which I could tap if the sound wasn't up to scratch. Additionally I ordered some cheap(ish) 6" speakers.

It all arrived, and after plugging it all together was pleasantly surprised, but not blown away, the bass was lacking and the head struggled producing a reasonable (and unreasonable) volume. I also needed to replace the standard desktop from the car-centric setup (speed, GPS, reversing camera, etc), to a more familiar mobile phone type interface.

The sound could be improved, so purchased a €25 2.1 external amplifier board to take the work away from the head, using it only as a sound source. Success, the sound improved dramatically and now, when plugged into a subwoofer I borrowed from the downstairs soundbar (the wife still hasn't noticed it gone although does keep asking "whats the matter with the sound?", "I don't know, age?..." I keep responding as my nose extends), get some serious volume and bass tones.

I also needed to be able to tap the audio signal between the head unit and the amplifier, to feed the Audio Analyser circuit. I started by putting a splitter on the audio out connector from the head unit, but I was hearing a ground loop hum. All the components where powered (covered later) by a re-purposed computer APX power supply. Additionally there was also common ground connections via the RCA cables connecting it all together which I think were causing the issue. Any the who, I had an old ground loop isolator sitting around (don't ask, I really don't throw anything away "in case I might need it one day", hence my box full of everything from 5 1/4" floppy drives (you never know).... to 64K memory expansion packs (you can never have enough memory right!) ;). So with one side of the splitter straight into the amp, and the other side of the splitter going through the isolator and into the Analsyer the hum disappeared,

Finally, the cheap Chinese speakers were bothering me. I knew that once they were mounted in the enclosure they would be a pain to replace, so decided that I would never be happy, and they would sit there snearing at me. So I bit the bullet and replaced them with a second hand pair of Pioneer's from eBay. These had much better sound and now I had a sonically very good 2.1 setup. I may use the Chinese speakers for a future project to build a separate subwoofer which will be needed once the penny drops and the wife, all of a sudden notices "wheres that big black box gone from the tele?".

One problem, the speaker holes I had originally cut were too big for the new speakers. I had to cut a new board with smaller holes and glue this (plus some silicon sealer and screws) behind the originals to get the new speakers to fit to frame.

Supplies and Tools

Ignoring all the trial and error, the final solution comprised:

  • Android car head unit
  • Pair of 5" Pioneer car speakers
  • 2.1 external audio board
  • Ground loop isolator box
  • RCA and speaker cables

Step 4: Wiring It All Together

I decided to replace my dedicated transformer (240V to 12VDC) and regulators which took the 12VDC down to the useable 5V (for Arduinos and NeoPixels) with a cannibalised desktop APX power supply. This was perfect as it safely took the 240 mains voltage down to 12V, 5V and 3.3V leads straight out of the box, has nice big capacitors protecting surges (especially for NeoPixels) and had a power button.

I cut off the connectors, which I think in hindsight I may have been better off trying to buy compatible connectors with fly leads, I could provide power to all components and have many other leads available for the future. Additionally it provided a common ground across everything.

One thing to consider with APX power supply is that you need to short the control wire down to ground in order for it to fire up. As a future improvement I may look to do this using Arduino, powered from the 5V standby cable, to enable it to be remotely powered on/off over WiFi.

I also found out at this point that breadboard patch leads are flaky at best. What was working one minute stopped working almost of its own volition. It took many hours of wiggling leads, especially after moving it from one place to another to find the offending connection. Eventually I took to hot gluing some of the connectors in place, especially around the matrix control lead.

I think if I as to do this again I would look at much more robust ways to confidently connect devices together.

Step 5: Adding WiFi Control

This was by far the biggest challenge and greatest reward. I wanted to replace the way I controlled the patterns and colours of the displayed lights remotely. I started by messing around with ESP32's however found programming them extremely fiddly. They required a specific USB/Serial adaptor and wiring to flash. They are not breadboard compatible so needs an adaptor. I figured life is too short for this kind of palaver!

I then went to his big brother the NodeMCU. Marginally more expensive (still pin money though), but a much more complete package and well worth the extra sheckles. Having eventually found a working example sketch I managed to get the NodeMCU onto the WiFi.

I then looked at my Raspberry PI to act as an MQTT server. MQTT is a common IBM protocol based on publish/subscribe principals. Any device can publish a topic to it, e.g. kitchen/light/status:on and any device can subscribe to this topic, so each time kitchen/light/status changes, the MQTT server will send out a message to it to tell it the new state. Its obviously a lot more complex than just that, especially at a protocol level.

MQTT servers are available in many variants, all however providing the same services (fundamentally). I could have created a cloud based MQTT server, meaning my device would connect to an internet service with a username and password and receive messages from there. This would also enable it to be controlled from anywhere in the world, which although I can see certain applications for, did not really jump out as a requirement for me since I wanted to see the patterns and colours whilst sitting in front of the speaker, not freak the family out by changing them whilst I was in Stockholm.

Additionally I wanted to understand it all, so installed Mosquito MQTT server onto the Pi. With very little work it fired up and with the use of MQTT Lens (free download) was able to test connection to it, publishing and subscribing. All worked very well.

Next step was to provide an interface to be able to turn lights on/off, change/randomise colours and patterns, set the sensitivity threshold, etc.

NodeRed, which comes pre-installed on Raspbian provides this functionality. Essentially you can create programs using drag and drop function blocks, that enable, specifically in this project case, the ability to publish and subscribe to MQTT messages, and also be able to set and display these using an inbuilt dashboard type service. It is reasonably simple to use, once you get the hang of it, and there's plenty of online help and support available. NodeRed also simplifies other interfaces, including Google/Alexis services for integrating voice control. So there is still much to explore here.

So finally with a bit of playing around I managed to create a workflow to handle selecting patterns and colours from drop down lists, and pass these as MQTT messages to Mosquito, who in turn pumped them out to NodeMCU who finally sent them to the Mega for interpretation and changing colour and selection values to control the lights.

So, this is the shorted stage (textually) but was by far and large the greatest in terms of time, effort and understanding. However it was the most satisfying (other than sanding which I have to say is now my number one love!) and opens up the most opportunities for me, including the world of WiFi, Bluetooth, IoT, MQTT which were all black arts (and still are but now I know enough to be dangerous!).

So trying to shrink everything and remove the rats nest of connections I discovered Wemos WiFi boards which combined Arduino Mega and NodeMCU on the same board (well nearly!). You still programme them separately by setting jumpers on the board to tell it you are flashing the NodeMCU or Mega, however it is still all done through the Arduino IDE, which is really nice. The Serial Port from the NodeMCU can also be directed into the Serial port (Hardware or Software 3) of the Mega, which takes way patch cables between the 2 devices. This simplified the hardware I required, including how to secure them within the enclosure as now all I required was my customer built analyser PCB, which conveniently had holes aligned to the Wemos mounting holes so using a few standoffs I was able to secure everything nicely.

Link below to the NodeMCU code.

Step 6: Building the Enclosure

A wise man once said, "change is the only constant in life" [Heraclitus, a Greek philosopher, at least thats what Google told me]. Whilst certainly true for how the electronics of this project developed, is not the case here as this is the only element in this project which has remained largely as originally envisaged.

At inception I was not clear on exactly which materials I would use however knew I didn't want a box. A box would have been much (much) easier, but then, wheres the challenge in that. I wanted to create something beautiful, tactile and would stand alone as a piece of furniture.

Frame

The framework is built using 3/4" MDF board, cut with jig saw and finished by my friend and neighbour on his belt sander. With all the parts sandwiched together this created a consistent square set of frame components. I glued all these together, however wanted all the joints to be supported with dowels. Without a proper dowel drilling rig I came up with a process of drilling a small pilot hole and dropping a long masonry nail into it, hammer end down/point out. I then lined up the 2 planes and gave them a tap, which left a pin prick where the corresponding dowel holes should be. It worked 95% of the time ("persuasion" needed to sometimes get the nails out of their holes), however I think I may buy a proper dowel jig if I were to do this again.

I bought 5m strip of 10x18mm rubber strip which I used to wrap the frame. This was to provide a good surface to bond the exterior to, and to ensure that once covered, the speaker enclosure parts were air tight.

I then mounted the speakers to the inside of the frames. This needed to be done as once the enclosure was covered there would be no way in, without cutting the back out and creating a removable cover.

I also had to accommodate the "x.1" (sub-woofer channel) of the amplifier. Whilst I could have run speaker wire from the sub-woofer straight into the amplifier board, i didn't want pressure on the board with hanging speaker cables (snag-able by running dogs and cats), not to mention the hassle of connecting the sub up in a confined space, so I added 2 speaker terminals to the back board, wired through the enclosure to pop out nicely for connection to the amp. This simplified connecting/disconnecting the sub-woofer.

Polycarbonate Front

Having read lots on the internet about working with acrylic/polycarbonate sheet I became unduly concerned about how I would work with this material. All (at least the references I found) stated its difficult to cut, it'll shatter if you're not careful, your electric tools will gum up as the "plastic" melts and bonds back to the line you're trying to cut! Accordingly I ordered 4mm polycarbonate sheet pre-cut to the required width, which I would then shape and cut the holes.

I needn't have worried, this material is a breeze to work, as long as you use a metal cutting blade in the jig saw its fine. Likewise drilling is easy and does not snap or shatter anything.

I had originally intended to use glass on the front, however to get a piece cut to the correct size and shape was prohibitively expensive. With hindsight now I would have gone with double the thickness sheet just to give it a bit more structural integrity.

Mirroring Polycarbonate

I bought some mirroring film from Bangood/Wish (not sure). With the help of my eldest son, who claimed to be an expert in this type of thing, based on his experience knackerising his car with sun visors, window and headlight tints we started. Well, I can tell you he is no expert!!! The first attempt was a bit of a disaster. We spent hours chasing air bubbles around the film, only for them to mysteriously disappear, and then appear at random intervals for the next 24 hours. We popped them with scalpels, squashed them, cut them and still they returned. Worse still around the edges, where I think we must have artificially/inconsistently stretched the film, creases started appearing. From the front side it looked a little better, however the creases looked like cracks in the polycarb.

Now, this is where adaption comes in. I decide, having been also interested in magic/infinity mirrors, that I could kill 2 birds with one stone. If I created a second cover, repeated the mirroring process, only better this time, I could use the first attempt underneath and this would give me the infinity mirror effect on the matrix lights (i.e. the display would appear to disappear off into the speaker to infinity.

Second go. This time we would try and apply it in a nice warm bath with Johnssons Baby bath to lubricate. This proved more successful, however we did start to doubt that there was any glue left on the film as it slipped about on the polycarb. Once we lifted from the bath, and started smoothing on a towel, the film was laying much easier and the bubbles coming out without too much pressure. Success!!!

Well nearly, I then found out that the dog had managed to leave some of his hairs on the towel which managed to get stuck between the film and the polycarb! Arghh!!! Well I decided it wasnt too bad and to push on, I may have a third go at some point, but for the time being it was good enough.

I also wasn't sure how much light would come through from the NeoPixels or how much of the channel would be visible when they were lit. I did not want to physically see any of the strip leds' or channel, just wanting to see them glow around the edge. Since the matrix NeoPixels were pushed up onto the back of the sheet (as intended) I wanted to see clearly their circles in the matrix.

After some playing around, to get the right effect, I removed the mirror film around the edge of the first sheet (the bubbly, cracked-looking mirror) and lightly sanded the polycarb to create a semi opaque filter. The second (reasonably good) sheet went out front. The end result being a nice glow for the strip lights around the edge, and a nice magic-mirror effect on the matrix.

Lesson Learned here: Make sure your working environment is spotlessly clean. Use plenty of water and baby bath to let the film float over the surface. Be gentle and work bubbles, etc out from the center. Do not believe number one son when he claims expertise in something!

Wrapping the enclosure

This was probably my favourite part of the build. I used 2m length of 6mm crosscut flexiply. This material is great in that it bends around curves, is easy to work and sand, and looks great with whatever stain, varnish or finish you want to apply. I chose clear super hard varnish as I really liked the colour and feel of the wood. I had originally considered staining but decided against it after I saw it sanded.

So to apply I simply cut 2 m strip, a little too long so would overlap when it got round to the origin again, but took off the excess easily with my new favourite tool, my Black and Decker vibrating saw. I secured the ply to the frame with a combination of nomorenails (other brands available!) and some small wood screws to take the tension. I was difficult at first due to trying to manage 2m's of flapping bendy wood, plus applying the glue bit by bit, plus trying to persuade the wood around the tight circumferences, and finally drilling and screwing at opportune distances to secure. From outside my house I would imagine it looked like I was wrestling with an alligator. There were also some twitchy moments when gently bending the ply around the ends created a sound like cracking wood. It didn't crack, just sounded a bit nasty.

Once dry I set about sanding everything. I never realised how enjoyable gently sanding could be, but I disappeared off into my head for a lovely hour and a half. A quick wipe down before I cut the hole in the top for the amp controls (again using my new best friend, Mr B&D).

Finally time to apply 5 coats of clear super hard varnish, sanding lightly between coats. It looks and feels great, even if I say so myself! :)

To Complete

I still need to seal the edges around the polycarb with black silicon. I will do this once I have completed everything as once its on, it will be annoyingly difficult to remove the front, for whatever reason.

Step 7: Lessons Learned - What I Would and Wouldn't Do Again!

This project, although having taken up swathes of my free time has been thoroughly enjoyable. Is the project finished, well no, probably not. There are still many things I add / improve or change, so this is still a work-in-progress, but the original objective of producing a standalone speaker, which sounds good and illuminates in time with the music is delivered.

Wish.com - Spend €20 on Wish.com for all your electronic components and turn every day into Christmas as package after package arrives randomly at your house. You never know when it will arrive and the daily anticipation waiting for the mail man to arrive is addictive!

Patience - (See Wish.com above). That aside, I was never a particularly patient person, however this project has taught me that. I took it one step at a time, learning new very enjoyable skills as I went. Savor it and put these into your mental tool-bag for re-use as your imagination/subconscious goes to work on all the endless possibles of how these can be applied to future projects (and Instructables)

Don't give up - There is no problem I came across that couldn't be worked out. Some were extremely frustrating (NodeMCU being a prime offender), however with a bit of lateral thinking and an army of like minded com-padres out in the ether, everything can be resolved.

Flash Memory - Arduinos have limitations, especially with memory. A number of times during this development I have had to migrate up to a bigger board (Nano -> Uno -> Mega). Initially I found this frustrating, however in hindsight I found it interesting. We have been spoilt over the years as computers have become bigger and faster and more powerful. Gone were the days of confining programmes to 64K of memory, which has resulted in bloatware. Whilst not a problem for PC's, is a problem for MCB's. This requires us to be efficient with code and memory. I found it refreshing and challenging having to consider these constraints and try to make everything as lean and efficient as possible. Often I would need to look at ways of removing/moving functionality to make space which I believe has resulted in a much more efficient set of code.

Connections - Molex jumper cables, whilst great for prototyping on breadboards, are not suitable for real world use. Plugging these in and out of the Arduino causes them to get baggy which results in them periodically disconnecting. I would thoroughly recommend learning how to crimp well and create bigger connectors, however this statement is very much do-what-I-say-not-what-I-do, as I am appalling at handling these tiny wires and crimp pins/plugs. Alternatively I would recommend protoboard with proper screw connectors strategically connected to full length header rails which make any external connection much more robust. Better still, customer design a PCB an all your problems go away! :)

Keep the prize in sight - It is very easy to keep thinking "Oh, I could do this now". This is great and to be encouraged, but if you are ever going to finish anything (at least in my case), you have to retain focus on the objective otherwise (again in my case) I would spiral off and end up with a motorized Mars lander which flashes its way around the Martian landscape to Spotify playing "Life on Mars", which may or may not be heard considering the obvious lack of atmosphere.

Black Box each problem/component - If you can understand/define a complex system into a set of smaller systems with distinct/defined inputs and or outputs, what happens inside can be largely ignored, unless you have a problem. In this case identifying where the problem is can be simplified by tracking through the process checking only these black box in/outs. Once the issue area is identified then is the time to roll up the sleeves, pull on the rubber gloves and start digging in. At least, works for me!

Applying Mirror Film is difficult to get right - At least for me (and my expert Son). Make sure everything is Intel clean-room clean, lots of soapy water to float the film and gently chase the bubbles. If you push too hard they only hide until you're not looking and will return, this time surrounded by well bonded film-to-surface.

Applying Silicon Sealant - use a finger dipped in soapy water to get a smooth finish.

Step 8: Conclusions and Next Steps

As you may have gathered up until now, this has been an academic study as much as a project. I have learned so much through this process, both in terms of what I would do differently given starting the process again, and what I can do to enhance/simplify.

From an audio perspective, the speaker actually performs well and sounds great. Better quality components would certainly help here, and I think a little more spent would give a slightly better product. That said I am happy, and everyone who has heard it in action (euphemism for loud!) has been impressed with its sonic quality. I also think the speaker cabinet shape/construction has helped, being both solid and airtight.

I am very pleased with the cabinet itself, I think it turned out well, looks great, feels great and is very robust. I am still not happy with the mirrored front panel. I will have another go at this, maybe even replace it with a white acrylic sheet. Until I have decided what I am going to do with it I need to leave the gaps around the edges un-filled, which is a bit of a distraction.

With respect to the electronics, I still have some work to do to make it more robust and easier to update. Accordingly the first thing I will do is to look at moving from Wemos board onto Particle boards. The main reason for this is:

  • Firstly, and probably most importantly, Particle allow sketches to be deployed remotely, meaning I don't need to faf around in the back of the speaker with USB cables (and dip switch settings) linked to my laptop every time I want to make a change.
  • Secondly, Particle seem to have a great MESH network capability, since that's their main selling point. I have not messed around with this yet, however have no doubt that it works well. Using a single Particle device to interface with my local MQTT server and act as a gateway, it will enable ALL Particle devices to safely/reliably receive MQTT/Mesh data.

This leads onto the next enhancement, adding other compatible lighting devices to the network, all controlled (colours/patterns) from rPI/MQTT. These may well include larger NeoPixel matrix displays, coloured surround/mood lighting, etc. Essentially anything that could be illuminated using NeoPixels can be coordinated and controlled centrally.

I have so many idea's buillding on MQTT control structure, just such little time.

Any-the-how, thank you all, who have made it this far for reading this Instructable. I hope you have enjoyed it, if so please give it a thumbs up and appreciate your feedback/comments.

Have a great time and keep making stuff!

Love xxx

Make it Glow Contest

Participated in the
Make it Glow Contest