├── README.md └── Tally.ino /README.md: -------------------------------------------------------------------------------- 1 | # ATEM Tally Controller 2 | 3 | * Download the required libraries into your Arduino libraries folder 4 | * Define the things at the top of the arduino project file, they are commented inline 5 | * Compile and install on an M5 StickC! 6 | 7 | ## Features 8 | 9 | * Short-press the side button to update the orientation of the display 10 | * Long-press the side button to change the camera number 11 | * Press the front button to cut to that camera 12 | 13 | ## Video 14 | 15 | Here's the livestream where I put this together! 16 | 17 | https://youtu.be/W94MAU-42R8 18 | -------------------------------------------------------------------------------- /Tally.ino: -------------------------------------------------------------------------------- 1 | // http://librarymanager/All#M5StickC https://github.com/m5stack/M5StickC 2 | #include 3 | #include 4 | 5 | // Download these from here 6 | // https://github.com/kasperskaarhoj/SKAARHOJ-Open-Engineering/tree/master/ArduinoLibs 7 | #include 8 | #include 9 | #include 10 | 11 | // Define the IP address of your ATEM switcher 12 | IPAddress switcherIp(10, 11, 200, 1); 13 | 14 | // Put your wifi SSID and password here 15 | const char* ssid = ""; 16 | const char* password = ""; 17 | 18 | // Set this to 1 if you want the orientation to update automatically 19 | #define AUTOUPDATE_ORIENTATION 0 20 | 21 | // You can customize the red/green/grey if you want 22 | // http://www.barth-dev.de/online/rgb565-color-picker/ 23 | #define GRAY 0x0841 // 8 8 8 24 | #define GREEN 0x0400 // 0 128 0 25 | #define RED 0xF800 // 255 0 0 26 | 27 | 28 | 29 | ///////////////////////////////////////////////////////////// 30 | // You probably don't need to change things below this line 31 | #define LED_PIN 10 32 | 33 | ATEMstd AtemSwitcher; 34 | 35 | int orientation = 0; 36 | int orientationPrevious = 0; 37 | int orientationMillisPrevious = millis(); 38 | int buttonBMillis = 0; 39 | 40 | int cameraNumber = 1; 41 | 42 | int previewTallyPrevious = 1; 43 | int programTallyPrevious = 1; 44 | int cameraNumberPrevious = cameraNumber; 45 | 46 | void setup() { 47 | Serial.begin(9600); 48 | 49 | WiFi.begin(ssid, password); 50 | while (WiFi.status() != WL_CONNECTED) { 51 | delay(500); 52 | Serial.println("Connecting to WiFi.."); 53 | } 54 | Serial.println("Connected to the WiFi network"); 55 | 56 | // 初期化 57 | M5.begin(); 58 | M5.MPU6886.Init(); 59 | M5.Lcd.setRotation(orientation); 60 | 61 | pinMode(LED_PIN, OUTPUT); 62 | digitalWrite(LED_PIN, HIGH); 63 | 64 | AtemSwitcher.begin(switcherIp); 65 | AtemSwitcher.serialOutput(0x80); 66 | AtemSwitcher.connect(); 67 | 68 | // GPIO初期化 69 | pinMode(26, INPUT); // PIN (INPUT, OUTPUT, ANALOG)無線利用時にはANALOG利用不可, DAC出力可 70 | pinMode(36, INPUT); // PIN (INPUT, , ANALOG)入力専用、INPUT_PULLUP等も不可 71 | pinMode( 0, INPUT); // PIN (INPUT, OUTPUT, )外部回路でプルアップ済み 72 | pinMode(32, INPUT); // GROVE(INPUT, OUTPUT, ANALOG) 73 | pinMode(33, INPUT); // GROVE(INPUT, OUTPUT, ANALOG) 74 | } 75 | 76 | void setOrientation() { 77 | float accX = 0, accY = 0, accZ = 0; 78 | M5.MPU6886.getAccelData(&accX, &accY, &accZ); 79 | //Serial.printf("%.2f %.2f %.2f \n",accX * 1000, accY * 1000, accZ * 1000); 80 | 81 | if (accZ < .9) { 82 | if (accX > .6) { 83 | orientation = 1; 84 | } else if (accX < .4 && accX > -.5) { 85 | if (accY > 0) { 86 | orientation = 0; 87 | } else { 88 | orientation = 2; 89 | } 90 | } else { 91 | orientation = 3; 92 | } 93 | } 94 | 95 | if (orientation != orientationPrevious) { 96 | Serial.printf("Orientation changed to %d\n", orientation); 97 | M5.Lcd.setRotation(orientation); 98 | } 99 | } 100 | 101 | 102 | void loop() { 103 | // ボタンの状態更新 104 | M5.update(); 105 | 106 | if (AUTOUPDATE_ORIENTATION) { 107 | if (orientationMillisPrevious + 500 < millis()) { 108 | setOrientation(); 109 | orientationMillisPrevious = millis(); 110 | } 111 | } 112 | 113 | if (M5.BtnA.wasPressed()) { 114 | AtemSwitcher.changeProgramInput(cameraNumber); 115 | } 116 | if (M5.BtnB.wasPressed()) { 117 | setOrientation(); 118 | buttonBMillis = millis(); 119 | } 120 | 121 | if (M5.BtnB.isPressed() && buttonBMillis != 0 && buttonBMillis < millis() - 500) { 122 | Serial.println("Changing camera number"); 123 | cameraNumber = (cameraNumber % 4) + 1; 124 | Serial.printf("New camera number: %d\n", cameraNumber); 125 | 126 | buttonBMillis = 0; 127 | } 128 | 129 | // Check for packets, respond to them etc. Keeping the connection alive! 130 | AtemSwitcher.runLoop(); 131 | 132 | int programTally = AtemSwitcher.getProgramTally(cameraNumber); 133 | int previewTally = AtemSwitcher.getPreviewTally(cameraNumber); 134 | 135 | if ((orientation != orientationPrevious) || (cameraNumber != cameraNumberPrevious) || (programTallyPrevious != programTally) || (previewTallyPrevious != previewTally)) { // changed? 136 | if (programTally && !previewTally) { // only program 137 | drawLabel(RED, BLACK, LOW); 138 | } else if (programTally && previewTally) { // program AND preview 139 | drawLabel(RED, GREEN, LOW); 140 | } else if (previewTally && !programTally) { // only preview 141 | drawLabel(GREEN, BLACK, HIGH); 142 | } else if (!previewTally || !programTally) { // neither 143 | drawLabel(BLACK, GRAY, HIGH); 144 | } 145 | } 146 | 147 | programTallyPrevious = programTally; 148 | previewTallyPrevious = previewTally; 149 | cameraNumberPrevious = cameraNumber; 150 | orientationPrevious = orientation; 151 | } 152 | 153 | void drawLabel(unsigned long int screenColor, unsigned long int labelColor, bool ledValue) { 154 | digitalWrite(LED_PIN, ledValue); 155 | M5.Lcd.fillScreen(screenColor); 156 | M5.Lcd.setTextColor(labelColor, screenColor); 157 | drawStringInCenter(String(cameraNumber), 8); 158 | } 159 | 160 | void drawStringInCenter(String input, int font) { 161 | int datumPrevious = M5.Lcd.getTextDatum(); 162 | M5.Lcd.setTextDatum(MC_DATUM); 163 | M5.Lcd.drawString(input, M5.Lcd.width() / 2, M5.Lcd.height() / 2, font); 164 | M5.Lcd.setTextDatum(datumPrevious); 165 | } 166 | 167 | --------------------------------------------------------------------------------