Credit where credit is due. I got the basic design and the wiring diagram from Donny Terek over at Instructables. You can find the wiring diagram with the needed BOM lower down in this post. This is no "how to" post, rather more a build log.


Bill of Materials

  1. TPA3116 Bluetooth Amplifier
  2. Tang Bang W5-1138SMF 5-1/4" Subwoofer
  3. Fountek FE85 3" Speaker (2EA)
  4. 5.5mm x 2.1mm DC Input Jack
  5. 16mm Push Button
  6. 6S Battery Capacity Indicator
  7. 6S BMS Board
  8. 18650 Cells (6EA)
  9. Green 3mm LED
  10. 3.5mm AUX Input Jack (additional info down below [*])
  11. 3 Ohm 10W Resistor (2EA)
  12. 12uF 100V Capacitor (2EA)
  13. 100 uF 100V Capacitor (2EA)
  14. 0.50 mH Inductor Coil (2EA)

WiringDiagram


Woodworking Part
I assembled the outer shell/box from 12mm MDF Wood. Before glueing everything together I went ahead and layouted every side of the speakerbox.

  1. Front Side:
    host all three speakers - the subwoofer ind the middle, and the two toners in either corner of panel.

    IMG_20200709_163337

  2. Right Side:
    fits the sub pipe, nothing more

    IMG_20200717_103440

  3. Top Side:
    has a cutout for the volume, treble, bass etc. knobs. They all sit in a custom made brass plate with laser etching

    IMG_20200717_105338 IMG_20200717_110832 IMG_20200717_112814 IMG_20200720_125349 IMG_20200717_101624 IMG_20200720_115624 IMG_20200720_121051 IMG_20200720_121749 IMG_20200717_181519 IMG_20200717_181525

  4. Back Side:
    contains the voltmeter, powerswitch, DC jack, AUX jack and the togglebutton for the voltmeter. Those also sit in a custom made brass plate.

    IMG_20200720_132542 IMG_20200820_132731


Assembly and modification of the Wood parts

I´ll approach this part alá "a picture is worth a thousand words"

IMG_20200716_120150 IMG_20200720_192307 IMG_20200721_122702 IMG_20200721_123417 IMG_20200721_123424 IMG_20200721_140257 IMG_20200721_185420 IMG_20200723_110540 IMG_20200723_112108 IMG_20200723_112114


Electric/Battery

Yes I know you shouldn't solder batteries, but it was my only choice, as I don't own a spot welder. I used the six 18650 batteries, the BMS board and a lot of kapton tape to assemble my 24V recharable battery.

IMG_20200710_140912 IMG_20200716_110406 IMG_20200716_110411 IMG_20200717_160210 IMG_20200723_113751 IMG_20200723_135559 IMG_20200726_162141 IMG_20200726_162153 IMG_20200730_180314

Speaker test


Leather wrapping

I bought some fake leather to use on my speaker which I glued with wood glue to the MDF

IMG_20200823_155345 IMG_20200823_155956 IMG_20200827_143441 IMG_20200827_144228


3D CAD and printing The Subpipe the speaker grills and the "top seam cover" was designed in Fusion360 and printed on my Prusa 3D printer. The parts got the usual finish e.g: sanding, putty, primer, painting.

BluetoothSpeaker_SubPipe BluetoothSpeaker_SubwooferGrill BluetoothSpeaker_TopCover BluetoothSpeaker_SpeakerGrill


Finished product

IMG_20200828_174548 IMG_20200828_174612 IMG_20200828_174620 IMG_20200828_174633 IMG_20200828_174644 IMG_20201227_170728 IMG_20210110_121204

SPM was built out of a necessarity. As a hobbyist 3D printer you accumulate a lot of 3D models which can get messy really fast. With SPM you have all your 3D models and a preview of them all in one place.


Features

  • 3D preview of any *.stl and *.obj file
  • Open a *.stl file in your prefered silcer with one click
  • Set up to 8 booksmark directories, which you can open with one click
  • Treeview of your selected directory
  • Open file, rename file, open folder, move folder, create folder, delete file, unzip file

Settings
Set the most common slicers in the settings to be able to open the *.obj and *.stl with a click of a button.

SPM_Settings


Bookmarks
You can assign up to 8 bookmarks. This could be a path to your files on an external HDD, or a direct path to a network share.

SPM_Booksmarks SPM_NewBookmarks


Rightclick menu
Simply right click the tree view to open up the context menu.

SPM_rightclickmenu


Overview
On the left-hand side you have your tree view which shows all your files from the set path in your settings. Right above the tree view is a simple search field, which highlights partial and/or full matches to your search string. In the middle top of the window is a quick folder creation tool. Just drag and drop any *.obj or *.stl in there to quickly copy it to your file path, which you set. Just below that tool is a quick text preview window, nothing special. The most prominent window on the right is the preview window for your 3D models.

SPM_overview

Why buy a case when you can print one?


Features

  • Prints without any support
  • Fits one HDD and one SSD
  • Build for an ITX motherboard and low profile CPU Fan

The whole case, which consists off of three parts, weighs a little bit over 600g. I printed it on my Prusa i3 MK3s with 0,3mm layer height and it took ~11 hours total. For the mesh I used a little trick and just used infill in the slicer. So no top or bottom layers and just 3 layers high in total.

3DCase_1 3DCase_2 3DCase_3 3DCase_4 3DCase_5

Im using this project to get my feet wet with hardware programing/designing. The macropad is only a precursor to a fully fletched 105 key Keyboard


To-Do list

  1. Design the PCB
  2. Gather all electronic components
  3. Get the PCB manufactured
  4. Design the faceplate/shell for the macropad
  5. Solder the Switches and Diodes
  6. Assemble everything
  7. Write the C# companion program

Features

  • Fully customizable via C# companion program
  • Works without the companion program with OBS etc. just assign the F13-F24 buttons to the desired function

Update 26.02.2021
I designed the PCB in Autodesk Fusion Eagle and send it to JLCPCB to get them manufactured. They did a fantastic job but I screwed up. I got the PCB after 8 business days from China to Germany only to discover that I designed my switchmatrix completly wrong.

20KeyPCBRev1 20KeyTestfit 20KeyDiodeFitting 20KeyArduinoTestfit 1N4148Diode


Update 10.03.2021
I made the decision to switch away from a switchmatrix - for now - and downgrade to 12 keys so that my arduino could handle all inputs via its own pin. Simultaneously I scouted the internet for some cherry keycaps but could not found any. Almost everything was sold out or really overpriced. So I went ahead and printed my own keycaps with my Anycubic Photon SLA printer.

CherryMXTestprint CherryMXTestfit


Update 22.03.2021
Time to design a new 3D model in Fusion360 and send it to my FDM printer.

MacroPad_Fusion360 MacrokeypadShellRev1


Update 24.03.2021
Revision 2 of the Macro keypad - this time only with 12 keys.
I went ahead and completely redesigned the PCB in Eagle. I changed the Arduino footprint to a genuine Arduino micro, because the "3rd party" Arduino could not handle the keystrokes that well. Also, I removed the 1N4148 Diodes because they are not longer needed in a configuration where each switch has its own input.

MarcoPad_Boardview MarcoPad_Schematic 12KeyMacroPad


Update 29.03.2021
Time to test fit the keys and keycaps I finally found online, while I wait for the PCB.

12KeyTestfit 12KeyTestfitKeycaps


Update 10.04.2021
I received the second revision of my PCB, and this time, everything looked fine. Rev. 2 comes with rounded corners and Ø3,2mm mounting holes.
So I went ahead and printed the two necessary parts. The outer shell and the keygrid.
The fit-check for the arduino looked good, so I soldered it in place. After all this, it was time to assemble everything and give it a function test - which looked promising.

12KeyRev2 KeyGridTopSide KeyGridBottomSide ArduinoFitCheck MacroPadAssembled


Update 17.04.2021
The interface between the Macropad (Hardware) and the C# program (Software) was handled by an Arduino Micro. The software for the arduino was written by David Madison over at partsnotincluded.com. I just modified it to fit my hardware setup.

/*
 *  Project     'Stream Cheap' Mini Macro Keyboard
 *  @author     David Madison
 *  @link       partsnotincluded.com/electronics/diy-stream-deck-mini-macro-keyboard
 *  @license    MIT - Copyright (c) 2018 David Madison
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */

// Key definitions
#define BUTTON_KEY1 KEY_F13
#define BUTTON_KEY2 KEY_F14
#define BUTTON_KEY3 KEY_F15
#define BUTTON_KEY4 KEY_F16
#define BUTTON_KEY5 KEY_F17
#define BUTTON_KEY6 KEY_F18
#define BUTTON_KEY7 KEY_F19
#define BUTTON_KEY8 KEY_F20
#define BUTTON_KEY9 KEY_F21
#define BUTTON_KEY10 KEY_F22
#define BUTTON_KEY11 KEY_F23
#define BUTTON_KEY12 KEY_F24

// Pin definitions
#define BUTTON_PIN1 2
#define BUTTON_PIN2 3
#define BUTTON_PIN3 4
#define BUTTON_PIN4 5
#define BUTTON_PIN5 6
#define BUTTON_PIN6 7
#define BUTTON_PIN7 8
#define BUTTON_PIN8 9
#define BUTTON_PIN9 10
#define BUTTON_PIN10 11
#define BUTTON_PIN11 12
#define BUTTON_PIN12 13
// ---------------------------------

#include "Keyboard.h"

// Button helper class for handling press/release and debouncing
class button {
  public:
  const char key;
  const uint8_t pin;

  button(uint8_t k, uint8_t p) : key(k), pin(p){}

  void press(boolean state){
    if(state == pressed || (millis() - lastPressed  <= debounceTime)){
      return; // Nothing to see here, folks
    }

    lastPressed = millis();

    //state ? Keyboard.press(KEY_LEFT_SHIFT) : Keyboard.release(KEY_LEFT_SHIFT);
    state ? Keyboard.press(key) : Keyboard.release(key); 
    pressed = state;
  }

  void update(){
    press(!digitalRead(pin));
  }

  private:
  const unsigned long debounceTime = 100;
  unsigned long lastPressed = 0;
  boolean pressed = 0;
} ;

// Button objects, organized in array
button buttons[] = {
  {BUTTON_KEY1, BUTTON_PIN1},
  {BUTTON_KEY2, BUTTON_PIN2},
  {BUTTON_KEY3, BUTTON_PIN3},
  {BUTTON_KEY4, BUTTON_PIN4},
  {BUTTON_KEY5, BUTTON_PIN5},
  {BUTTON_KEY6, BUTTON_PIN6},
  {BUTTON_KEY7, BUTTON_PIN7},
  {BUTTON_KEY8, BUTTON_PIN8},
  {BUTTON_KEY9, BUTTON_PIN9},
  {BUTTON_KEY10, BUTTON_PIN10},
  {BUTTON_KEY11, BUTTON_PIN11},
  {BUTTON_KEY12, BUTTON_PIN12},

};

const uint8_t NumButtons = sizeof(buttons) / sizeof(button);
const uint8_t ledPin = 17;

void setup() { 
  // Safety check. Ground pin #1 (RX) to cancel keyboard inputs.
  pinMode(1, INPUT_PULLUP);
  if(!digitalRead(1)){
    failsafe();
  }

  // Set LEDs Off. Active low.
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
  TXLED0;

  for(int i = 0; i < NumButtons; i++){
    pinMode(buttons[i].pin, INPUT_PULLUP);
  }
}

void loop() {
  for(int i = 0; i < NumButtons; i++){
    buttons[i].update();
  }
}

void failsafe(){
  for(;;){} // Just going to hang out here for awhile :D
}

Update 22.04.2021
Time for the C# program. My feature list consisted of:

  • Global hotkeys - usable on the desktop and in games.
  • A small history window, so you know which button you pressed.
  • Each button should be colorable individually.
  • A resizeable preview window - which has no function - and can be used as a cheat sheet.
  • The user should decide which function each hotkey has. Either a combination of up to 4 button (CRTL, SHIFT, ALT + any other button on the keyboard), or use a hotkey button to launch programs.
  • The program should be launchable with a argument. In this case -mini. Just append it to the shortcut and it will launch in the system tray ("C:/User/Program.exe - mini").
  • Hide the names of the *.exe files.
  • Program has darkmode enabled by default.

This is MacroPad.
Written in C# without any external libraries. I just had to use two hooks into the user32.dll to receive my hotkeys.

[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifers, int vlc);

With these two hook I could simply register as many hotkeys as I want. In my case - 12. RegisterHotKey(this.Handle, _CTRL_F13, 0, (int)Keys.F13); Now I used a simple switch case to test which key was pressed by the user and perform the hotkey/program, which was determined by the user.

 if (m.Msg == 0x0312)
                {
                    int _hotkey = m.WParam.ToInt32();
                    switch (_hotkey)
                    {
                        case 13:
                            //F13 was pressed
                            break;
                        case 14:
                            //F14 was pressed
                            break;

The program lauch was as easy as.

Process.Start(_programpath defined by the user_);

The hotkeys were handled by.

SendKeys.Send();

MacropadOverview MacroPadHotkey MacroPadCustomize

SimpleColorPicker will help you to get every RGB or HEX value of a color from everywhere on your screen. Yes everywhere. No need to take a screenshot or save the image.


Features

  • Control the program with hotkeys
    [CRTL+1] to save color.
    [CRTL+2] to stop picking.
    [CRTL+3] to resume picking.

  • Copy either the last picked RGB or the HEX value with a click of a button.


Program screenshot:

SimpleColorPicker

Help screenshot:

SimpleColorPickerHelper


Snippet for the colorpicking:

Bitmap BMP = new Bitmap(1, 1);
            Graphics GFX = Graphics.FromImage(BMP);
            GFX.CopyFromScreen(new Point(MousePosition.X, MousePosition.Y), new Point(0, 0), BMP.Size);
            Color Pixel = BMP.GetPixel(0, 0);