├── assets ├── pcb01.png ├── pcb02.png ├── pcb03.png ├── live01.jpg ├── live02.jpg ├── schematic.png ├── wireframe.png ├── lado_comtampa.png ├── lado_semtampa.png ├── teclado_frente.png └── Teclado_traseira.png ├── 3d Files ├── CaixaFinal.stl └── TampaFinal.stl ├── .gitignore ├── .vscode └── extensions.json ├── test └── README ├── platformio.ini ├── lib └── README ├── include └── README ├── .travis.yml ├── src └── main.cpp └── README.md /assets/pcb01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kadu/arduino_stream_deck/HEAD/assets/pcb01.png -------------------------------------------------------------------------------- /assets/pcb02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kadu/arduino_stream_deck/HEAD/assets/pcb02.png -------------------------------------------------------------------------------- /assets/pcb03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kadu/arduino_stream_deck/HEAD/assets/pcb03.png -------------------------------------------------------------------------------- /assets/live01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kadu/arduino_stream_deck/HEAD/assets/live01.jpg -------------------------------------------------------------------------------- /assets/live02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kadu/arduino_stream_deck/HEAD/assets/live02.jpg -------------------------------------------------------------------------------- /assets/schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kadu/arduino_stream_deck/HEAD/assets/schematic.png -------------------------------------------------------------------------------- /assets/wireframe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kadu/arduino_stream_deck/HEAD/assets/wireframe.png -------------------------------------------------------------------------------- /3d Files/CaixaFinal.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kadu/arduino_stream_deck/HEAD/3d Files/CaixaFinal.stl -------------------------------------------------------------------------------- /3d Files/TampaFinal.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kadu/arduino_stream_deck/HEAD/3d Files/TampaFinal.stl -------------------------------------------------------------------------------- /assets/lado_comtampa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kadu/arduino_stream_deck/HEAD/assets/lado_comtampa.png -------------------------------------------------------------------------------- /assets/lado_semtampa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kadu/arduino_stream_deck/HEAD/assets/lado_semtampa.png -------------------------------------------------------------------------------- /assets/teclado_frente.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kadu/arduino_stream_deck/HEAD/assets/teclado_frente.png -------------------------------------------------------------------------------- /assets/Teclado_traseira.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kadu/arduino_stream_deck/HEAD/assets/Teclado_traseira.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:node32s] 12 | platform = espressif32 13 | board = node32s 14 | framework = arduino 15 | monitor_speed = 115200 16 | board_build.partitions = no_ota.csv 17 | ; upload_speed = 921600 18 | lib_deps = 19 | adafruit/Adafruit NeoPixel @ ^1.7.0 20 | t-vk/ESP32 BLE Keyboard @ ^0.2.2 21 | mathertel/OneButton @ 0.0.0-alpha+sha.eb583d713a -------------------------------------------------------------------------------- /lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Continuous Integration (CI) is the practice, in software 2 | # engineering, of merging all developer working copies with a shared mainline 3 | # several times a day < https://docs.platformio.org/page/ci/index.html > 4 | # 5 | # Documentation: 6 | # 7 | # * Travis CI Embedded Builds with PlatformIO 8 | # < https://docs.travis-ci.com/user/integration/platformio/ > 9 | # 10 | # * PlatformIO integration with Travis CI 11 | # < https://docs.platformio.org/page/ci/travis.html > 12 | # 13 | # * User Guide for `platformio ci` command 14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html > 15 | # 16 | # 17 | # Please choose one of the following templates (proposed below) and uncomment 18 | # it (remove "# " before each line) or use own configuration according to the 19 | # Travis CI documentation (see above). 20 | # 21 | 22 | 23 | # 24 | # Template #1: General project. Test it using existing `platformio.ini`. 25 | # 26 | 27 | # language: python 28 | # python: 29 | # - "2.7" 30 | # 31 | # sudo: false 32 | # cache: 33 | # directories: 34 | # - "~/.platformio" 35 | # 36 | # install: 37 | # - pip install -U platformio 38 | # - platformio update 39 | # 40 | # script: 41 | # - platformio run 42 | 43 | 44 | # 45 | # Template #2: The project is intended to be used as a library with examples. 46 | # 47 | 48 | # language: python 49 | # python: 50 | # - "2.7" 51 | # 52 | # sudo: false 53 | # cache: 54 | # directories: 55 | # - "~/.platformio" 56 | # 57 | # env: 58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c 59 | # - PLATFORMIO_CI_SRC=examples/file.ino 60 | # - PLATFORMIO_CI_SRC=path/to/test/directory 61 | # 62 | # install: 63 | # - pip install -U platformio 64 | # - platformio update 65 | # 66 | # script: 67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N 68 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define btn1 23 8 | #define btn2 22 9 | #define btn3 21 10 | #define btn4 19 11 | #define btn5 18 12 | #define btn6 17 13 | #define btn7 16 14 | #define btn8 25 15 | #define btn9 26 16 | #define NUM_LEDS 27 17 | 18 | #define NUMPIXELS 2 19 | Adafruit_NeoPixel pixels(NUMPIXELS, NUM_LEDS, NEO_GRB + NEO_KHZ800); 20 | BleKeyboard bleKeyboard("StreamDeckBLE", "http://kaduzi.us", 100); 21 | OneButton button_1(btn1, true); 22 | OneButton button_2(btn2); 23 | OneButton button_3(btn3); 24 | OneButton button_4(btn4); 25 | OneButton button_5(btn5); 26 | OneButton button_6(btn6); 27 | OneButton button_7(btn7); 28 | OneButton button_8(btn8); 29 | OneButton button_9(btn9); 30 | 31 | void sendCommand(uint8_t LETTER) { 32 | pixels.setPixelColor(1, pixels.Color(0,0,255)); 33 | pixels.show(); 34 | bleKeyboard.press(KEY_RIGHT_CTRL); 35 | bleKeyboard.press(KEY_RIGHT_ALT); 36 | bleKeyboard.press(KEY_RIGHT_SHIFT); 37 | bleKeyboard.press(LETTER); 38 | 39 | delay(50); 40 | bleKeyboard.releaseAll(); 41 | pixels.setPixelColor(1, pixels.Color(0,0,0)); 42 | pixels.show(); 43 | Serial.println("Sended " + LETTER); 44 | } 45 | 46 | void btn1_function() { 47 | sendCommand('Z'); 48 | } 49 | 50 | void btn2_function() { 51 | sendCommand('Y'); 52 | } 53 | 54 | void btn3_function() { 55 | sendCommand('W'); 56 | } 57 | 58 | void btn4_function() { 59 | sendCommand('X'); 60 | } 61 | 62 | void btn5_function() { 63 | sendCommand('V'); 64 | } 65 | 66 | void btn6_function() { 67 | sendCommand('U'); 68 | } 69 | 70 | void btn7_function() { 71 | sendCommand('T'); 72 | } 73 | 74 | void btn8_function() { 75 | sendCommand('S'); 76 | } 77 | 78 | void btn9_function() { 79 | sendCommand('R'); 80 | } 81 | 82 | void setup() { 83 | WiFi.disconnect(true); // Disconnect from the network 84 | WiFi.mode(WIFI_OFF); // Switch WiFi off 85 | delay(12); 86 | bleKeyboard.begin(); 87 | 88 | button_1.attachClick(btn1_function); 89 | button_2.attachClick(btn2_function); 90 | button_3.attachClick(btn3_function); 91 | button_4.attachClick(btn4_function); 92 | button_5.attachClick(btn5_function); 93 | button_6.attachClick(btn6_function); 94 | button_7.attachClick(btn7_function); 95 | button_8.attachClick(btn8_function); 96 | button_9.attachClick(btn9_function); 97 | 98 | button_1.setClickTicks(200); 99 | button_2.setClickTicks(200); 100 | button_3.setClickTicks(200); 101 | button_4.setClickTicks(200); 102 | button_5.setClickTicks(200); 103 | button_6.setClickTicks(200); 104 | button_7.setClickTicks(200); 105 | button_8.setClickTicks(200); 106 | button_9.setClickTicks(200); 107 | 108 | pixels.begin(); 109 | pixels.clear(); 110 | pixels.setBrightness(20); 111 | pixels.show(); 112 | } 113 | 114 | void loop() { 115 | if(bleKeyboard.isConnected()) { 116 | pixels.setPixelColor(0, pixels.Color(0,255,0)); 117 | pixels.show(); 118 | } else { 119 | pixels.setPixelColor(0, pixels.Color(255,0,0)); 120 | pixels.show(); 121 | } 122 | 123 | button_1.tick(); 124 | button_2.tick(); 125 | button_3.tick(); 126 | button_4.tick(); 127 | button_5.tick(); 128 | button_6.tick(); 129 | button_7.tick(); 130 | button_8.tick(); 131 | button_9.tick(); 132 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # StreamDeck BLE 2 | 3 | During my firsts lives on twitch, I saw some streamers using cool hardware that with just some clicks on little screens can command all the live scenes, open and close programs, and other things, the name of this tech gadget, Elgato StreamDeck, here in Brazil it is so expensive that made me think how can I do the same without this keyboard, with a quick google search a lot of results are point to Arduino versions, someone more simple, others with OLED screens and almost same functionality that the original. 4 | 5 | In my streams, I talk about IoT, Home Automation, Arduino, Electronics, and related things, in this moment I think, why do I not develop my own Stream Deck in my stream? Here we are, this is a result of some nights with friends talking about how cool will be to have a BLE keyboard that controls OBS. 6 | 7 | **Let's share!** 8 | 9 | The first version that I made fail badly (img1), I've used an Arduino Leonardo to send commands, using only one analog pin. My circuit sometimes sends the wrong value to the computer, and I lost some records because of that. After saw another twitch streamer (https://www.twitch.tv/tearing5) using the ESP32 as a Bluetooth keyboard I have the idea to create a simple node32s shield, with some buttons and RGB Leds (why not?) that send keystrokes to my computer. 10 | 11 | 12 | 13 | - Here is the schematic that I've created 14 | 15 | ![Schematic](assets/schematic.png "Schematic") 16 | 17 | - Here is the board that I made and send to JLCPCB to create my Board 18 | 19 | ![PCB](assets/pcb01.png "PCB") 20 | 21 | ![PCB](assets/pcb02.png "PCB") 22 | 23 | ![PCB](assets/pcb03.png "PCB") 24 | 25 | - And here are the board :D 26 | 27 | ![Real PCB 01](assets/live01.jpg "Real Life 01") 28 | 29 | ![Real PCB 02](assets/live02.jpg "Real Life 02") 30 | 31 | **Show me "the code"** 32 | 33 | The hardware part is a NODE32S as an MCU, and my PCB acting like an Arduino shield over it. 34 | 35 | I've used 3 libraries 36 | - Adafruit NeoPixel - that brings RGB to life! 37 | - ESP32 BLE Keyboard - abstract all BLE stuff 38 | - OneButton - help with buttons 39 | 40 | You can get the code here 41 | 42 | **Configuration** 43 | 44 | The "StreamDeck BLE" act as a BLE keyboard and has 9 buttons, each one sends a keystroke to the computer (CTRL+ALT+SHIFT+[LETTER]). 45 | 46 | LETTERS: 47 | | Button | Letter | 48 | |----|----| 49 | | 01 | Z | 50 | | 02 | Y | 51 | | 03 | W | 52 | | 04 | X | 53 | | 05 | V | 54 | | 06 | U | 55 | | 07 | T | 56 | | 08 | S | 57 | | 09 | R | 58 | 59 | **How to USE** 60 | 61 | Just connect on "StreamDeckBLE" on your Bluetooth, go to OBS Settings -> Hot Keys, and press each button wherever you want 62 | 63 | **BE HAPPY** 64 | 65 | https://oshwlab.com/nicodemosbr/streamdeck_ble 66 | 67 | **3D Case** 68 | 69 | To create this 3D case I had to win several battles, it was hours and hours fighting with myself and Fusion 360. But I got the help of knights who joined me and helped me build this case. Here is my thanks to @Leo_Churrasqueiro, a brilliant warrior who detached from several moments helping me in the battle, and to @psampaiobh who made excellent Fusion 360 tutorials that served as a tips guide and helped me better understand this 360-head Hydra ;) 70 | 71 | And a special thanks to all that guys that were in twitch chat helping us! 72 | 73 | We have some pictures of this battle: 74 | ![Wireframe](assets/wireframe.png "Wireframe") 75 | 76 | ![With lid](assets/lado_comtampa.png "With lid") 77 | ![Without lid](assets/lado_semtampa.png "Without lid") 78 | 79 | and now, the "printed version" 80 | 81 | ![3d case 01](assets/teclado_frente.png "3D Case") 82 | ![3d case 02](assets/Teclado_traseira.png "3D Case") 83 | 84 | We decided to have a 18650 battery on it, and for this, we use these components: 85 | - MT3608 - Step UP Conversor 86 | - TP4056 - Single Cell Li-ion battery charger 87 | - Button Switch. 88 | 89 | Is possible to use TP4056 with step up on IT, but will need some hack on the printed case. --------------------------------------------------------------------------------