├── LICENSE ├── README.md └── core2atem.ino /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Aaron Parecki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # M5 Core2 ATEM Controller 2 | 3 | A mini ATEM controller using an M5Stack Core2. 4 | 5 | Provides 4 camera buttons with tally indicators, and 4 macro buttons. 6 | 7 | You'll need to download the required libraries (Skaarhoj and M5) into your Arduino libraries folder in order to compile this. 8 | 9 | Define your ATEM's IP address and your wifi info at the top of the file. 10 | 11 | ## Video 12 | 13 | Watch the "build with me" video where I built this live! 14 | 15 | https://youtu.be/7tZVQeAdCbA 16 | 17 | Check out this much more complete fork of this project! 18 | 19 | https://github.com/helo-head/Tally-Core2 20 | 21 | -------------------------------------------------------------------------------- /core2atem.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // Download these from here 7 | // https://github.com/kasperskaarhoj/SKAARHOJ-Open-Engineering/tree/master/ArduinoLibs 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | // Define the IP address of your ATEM switcher 14 | IPAddress switcherIp(10, 11, 200, 9); 15 | 16 | // Put your wifi SSID and password here 17 | const char* ssid = ""; 18 | const char* password = ""; 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | #define CAMERA_OFF 0 28 | #define CAMERA_PREVIEW 1 29 | #define CAMERA_PROGRAM 2 30 | 31 | #define CAMERA_BUTTON_Y 42 32 | #define MACRO_BUTTON_Y 150 33 | 34 | ATEMstd AtemSwitcher; 35 | 36 | 37 | TouchButton c1 = TouchButton(2, CAMERA_BUTTON_Y, 72, 72, "c1"); 38 | TouchButton c2 = TouchButton(2+72, CAMERA_BUTTON_Y, 72, 72, "c2"); 39 | TouchButton c3 = TouchButton(2+72+72, CAMERA_BUTTON_Y, 72, 72, "c3"); 40 | TouchButton c4 = TouchButton(2+72+72+72, CAMERA_BUTTON_Y, 72, 72, "c4"); 41 | 42 | 43 | TouchButton b1 = TouchButton(2, MACRO_BUTTON_Y, 72, 72, "b1"); 44 | TouchButton b2 = TouchButton(2+72, MACRO_BUTTON_Y, 72, 72, "b2"); 45 | TouchButton b3 = TouchButton(2+72+72, MACRO_BUTTON_Y, 72, 72, "b3"); 46 | TouchButton b4 = TouchButton(2+72+72+72, MACRO_BUTTON_Y, 72, 72, "b4"); 47 | 48 | 49 | void buttonWasPressed(TouchEvent& e) { 50 | TouchButton& b = *e.button; 51 | 52 | char buttonType = b.name[0]; 53 | int buttonNumber = b.name[1]-'0'; 54 | 55 | if(buttonType == 'c') { 56 | AtemSwitcher.changeProgramInput(buttonNumber); 57 | } else { 58 | drawButton(buttonNumber, b.isPressed(), false); 59 | AtemSwitcher.setMacroAction(buttonNumber-1, 0); 60 | } 61 | } 62 | 63 | void drawCameraButton(int buttonNumber, int state) { 64 | int font = 1; 65 | M5.Lcd.setTextSize(8); 66 | 67 | M5.Lcd.setTextColor(state == CAMERA_OFF ? WHITE : BLACK); 68 | 69 | int buttonColor; 70 | switch(state) { 71 | case CAMERA_OFF: 72 | buttonColor = TFT_DARKGREY; break; 73 | case CAMERA_PREVIEW: 74 | buttonColor = TFT_GREEN; break; 75 | case CAMERA_PROGRAM: 76 | buttonColor = TFT_RED; break; 77 | } 78 | 79 | //char* cameraName = AtemSwitcher.getInputShortName(buttonNumber-1); 80 | 81 | switch(buttonNumber) { 82 | case 1: 83 | M5.Lcd.fillRoundRect(2, CAMERA_BUTTON_Y, 72, 72, 6, buttonColor); 84 | M5.Lcd.drawCentreString("1", 2+2+(72/2), 42+10, font); 85 | break; 86 | case 2: 87 | M5.Lcd.fillRoundRect(2+72+2, CAMERA_BUTTON_Y, 72, 72, 6, buttonColor); 88 | M5.Lcd.drawCentreString("2", 2+2+72+2+(72/2), 42+10, font); 89 | break; 90 | case 3: 91 | M5.Lcd.fillRoundRect(2+72+2+72+2, CAMERA_BUTTON_Y, 72, 72, 6, buttonColor); 92 | M5.Lcd.drawCentreString("3", 2+2+72+2+72+2+(72/2), 42+10, font); 93 | break; 94 | case 4: 95 | M5.Lcd.fillRoundRect(2+72+2+72+2+72+2, CAMERA_BUTTON_Y, 72, 72, 6, buttonColor); 96 | M5.Lcd.drawCentreString("4", 2+2+72+2+72+2+72+2+(72/2), 42+10, font); 97 | break; 98 | } 99 | } 100 | 101 | void drawButton(int buttonNumber, bool isPressed, bool isRunning) { 102 | int font = 1; 103 | M5.Lcd.setTextSize(8); 104 | 105 | M5.Lcd.setTextColor(isPressed || isRunning ? BLACK : WHITE); 106 | 107 | int buttonColor = isPressed ? WHITE : (isRunning ? TFT_RED : TFT_DARKGREY); 108 | 109 | switch(buttonNumber) { 110 | case 1: 111 | M5.Lcd.fillRoundRect(2, MACRO_BUTTON_Y, 72, 72, 6, buttonColor); 112 | M5.Lcd.drawCentreString("1", 2+2+(72/2), MACRO_BUTTON_Y+10, font); 113 | break; 114 | case 2: 115 | M5.Lcd.fillRoundRect(2+72+2, MACRO_BUTTON_Y, 72, 72, 6, buttonColor); 116 | M5.Lcd.drawCentreString("2", 2+2+72+2+(72/2), MACRO_BUTTON_Y+10, font); 117 | break; 118 | case 3: 119 | M5.Lcd.fillRoundRect(2+72+2+72+2, MACRO_BUTTON_Y, 72, 72, 6, buttonColor); 120 | M5.Lcd.drawCentreString("3", 2+2+72+2+72+2+(72/2), MACRO_BUTTON_Y+10, font); 121 | break; 122 | case 4: 123 | M5.Lcd.fillRoundRect(2+72+2+72+2+72+2, MACRO_BUTTON_Y, 72, 72, 6, buttonColor); 124 | M5.Lcd.drawCentreString("4", 2+2+72+2+72+2+72+2+(72/2), MACRO_BUTTON_Y+10, font); 125 | break; 126 | } 127 | } 128 | 129 | void setupButtons() { 130 | M5.Touch.addHandler(buttonWasPressed, TE_BTNONLY + TE_TOUCH + TE_RELEASE); 131 | 132 | M5.Lcd.fillScreen(BLACK); 133 | 134 | M5.Lcd.setTextSize(2); 135 | M5.Lcd.setTextColor(WHITE); 136 | M5.Lcd.drawString("CAMERAS", 6, CAMERA_BUTTON_Y-20, 1); 137 | M5.Lcd.drawString("MACROS", 6, MACRO_BUTTON_Y-20, 1); 138 | 139 | drawButton(1, false, false); 140 | drawButton(2, false, false); 141 | drawButton(3, false, false); 142 | drawButton(4, false, false); 143 | 144 | drawCameraButton(1, CAMERA_OFF); 145 | drawCameraButton(2, CAMERA_OFF); 146 | drawCameraButton(3, CAMERA_OFF); 147 | drawCameraButton(4, CAMERA_OFF); 148 | } 149 | 150 | void setup() { 151 | M5.begin(true, true, false, true); 152 | 153 | Serial.begin(115200); 154 | 155 | Serial.println("About to connect to wifi"); 156 | WiFi.begin(ssid, password); 157 | 158 | while (WiFi.status() != WL_CONNECTED) { 159 | delay(500); 160 | Serial.println("Connecting to WiFi.."); 161 | } 162 | Serial.println("Connected to the WiFi network"); 163 | 164 | AtemSwitcher.begin(switcherIp); 165 | AtemSwitcher.serialOutput(0x80); 166 | AtemSwitcher.connect(); 167 | 168 | setupButtons(); 169 | } 170 | 171 | int currentRunningMacro = -1; 172 | int tallyStates[4]; 173 | 174 | void loop() { 175 | // TouchPoint_t pos= M5.Touch.getPressPoint(); 176 | 177 | /* 178 | // Bottom buttons 179 | if(pos.y > 240) { 180 | if(pos.x < 109) // Left 181 | M5.Lcd.setTextColor(RED); 182 | else if(pos.x > 218) // Middle 183 | M5.Lcd.setTextColor(BLUE); 184 | else if(pos.x >= 109 && pos.x <= 218) // Right 185 | M5.Lcd.setTextColor(GREEN); 186 | } 187 | */ 188 | 189 | M5.update(); 190 | AtemSwitcher.runLoop(); 191 | 192 | if(AtemSwitcher.getMacroRunStatusState() && 0x01 == 1) { 193 | int index = AtemSwitcher.getMacroRunStatusIndex(); 194 | if(index != currentRunningMacro) { 195 | drawButton(index + 1, false, true); 196 | } 197 | currentRunningMacro = index; 198 | } else { 199 | if(currentRunningMacro > -1) { 200 | drawButton(currentRunningMacro + 1, false, false); 201 | currentRunningMacro = -1; 202 | } 203 | } 204 | 205 | for(int i=1; i<=4; i++) { 206 | int currentTallyState = AtemSwitcher.getProgramTally(i) ? CAMERA_PROGRAM : (AtemSwitcher.getPreviewTally(i) ? CAMERA_PREVIEW : CAMERA_OFF); 207 | 208 | if(currentTallyState != tallyStates[i-1]) { 209 | drawCameraButton(i, currentTallyState); 210 | } 211 | 212 | tallyStates[i-1] = currentTallyState; 213 | } 214 | 215 | } 216 | --------------------------------------------------------------------------------