#include <MD_MAX72xx.h>
#include <SPI.h>
#include <WiFi.h>
#include <esp_now.h>
#define MAX_DEVICES 4
#define CLK_PIN 18
#define DATA_PIN 23
#define CS_PIN 5
#define BTN_HOME 12
#define BTN_AWAY 14
MD_MAX72XX mx = MD_MAX72XX(MD_MAX72XX::FC16_HW, DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES);
int scoreHome = 0;
int scoreAway = 0;
unsigned long btnHomePressed = 0;
unsigned long btnAwayPressed = 0;
bool btnHomeLong = false;
bool btnAwayLong = false;
//für Display Abschaltung nach einer Stunde..
unsigned long lastActivityTime = 0;
bool displayOn = true;
// Zeichensatz (Ziffern 0–9), Zeilenweise definiert: digits[Ziffer][Zeile][Spalte]
const uint8_t digits[10][8][4] = {
{ // 0
{0,1,1,0},
{1,0,0,1},
{1,0,0,1},
{1,0,0,1},
{1,0,0,1},
{1,0,0,1},
{1,0,0,1},
{0,1,1,0}
},
{ // 1
{0,0,1,0},
{0,1,1,0},
{1,0,1,0},
{0,0,1,0},
{0,0,1,0},
{0,0,1,0},
{0,0,1,0},
{1,1,1,1}
},
{ // 2
{0,1,1,0},
{1,0,0,1},
{0,0,0,1},
{0,0,1,0},
{0,1,0,0},
{1,0,0,0},
{1,0,0,0},
{1,1,1,1}
},
{ // 3
{1,1,1,0},
{0,0,0,1},
{0,0,0,1},
{0,1,1,0},
{0,0,0,1},
{0,0,0,1},
{0,0,0,1},
{1,1,1,0}
},
{ // 4
{0,0,1,0},
{0,1,1,0},
{1,0,1,0},
{1,0,1,0},
{1,1,1,1},
{0,0,1,0},
{0,0,1,0},
{0,0,1,0}
},
{ // 5
{1,1,1,1},
{1,0,0,0},
{1,0,0,0},
{1,1,1,0},
{0,0,0,1},
{0,0,0,1},
{1,0,0,1},
{0,1,1,0}
},
{ // 6
{0,1,1,0},
{1,0,0,1},
{1,0,0,0},
{1,1,1,0},
{1,0,0,1},
{1,0,0,1},
{1,0,0,1},
{0,1,1,0}
},
{ // 7
{1,1,1,1},
{0,0,0,1},
{0,0,1,0},
{0,0,1,0},
{0,1,0,0},
{0,1,0,0},
{1,0,0,0},
{1,0,0,0}
},
{ // 8
{0,1,1,0},
{1,0,0,1},
{1,0,0,1},
{0,1,1,0},
{1,0,0,1},
{1,0,0,1},
{1,0,0,1},
{0,1,1,0}
},
{ // 9
{0,1,1,0},
{1,0,0,1},
{1,0,0,1},
{0,1,1,1},
{0,0,0,1},
{0,0,0,1},
{1,0,0,1},
{0,1,1,0}
}
};
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
esp_now_init();
esp_now_peer_info_t peerInfo = {};
memset(peerInfo.peer_addr, 0xFF, 6);
peerInfo.channel = 1;
esp_now_add_peer(&peerInfo);
mx.begin();
mx.control(MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
mx.clear();
pinMode(BTN_HOME, INPUT_PULLUP);
pinMode(BTN_AWAY, INPUT_PULLUP);
showScore();
}
void loop() {
bool homePressed = digitalRead(BTN_HOME) == LOW;
bool awayPressed = digitalRead(BTN_AWAY) == LOW;
// Home Button
if (homePressed && !btnHomeLong) {
if (btnHomePressed == 0) btnHomePressed = millis();
else if (millis() - btnHomePressed > 5000) {
scoreHome = 0;
btnHomeLong = true;
showScore();
}
} else if (!homePressed) {
if (!btnHomeLong && btnHomePressed != 0) {
scoreHome++;
showScore();
}
btnHomePressed = 0;
btnHomeLong = false;
}
// Away Button
if (awayPressed && !btnAwayLong) {
if (btnAwayPressed == 0) btnAwayPressed = millis();
else if (millis() - btnAwayPressed > 5000) {
scoreAway = 0;
btnAwayLong = true;
showScore();
}
} else if (!awayPressed) {
if (!btnAwayLong && btnAwayPressed != 0) {
scoreAway++;
showScore();
}
btnAwayPressed = 0;
btnAwayLong = false;
}
// 👇 Display ausschalten nach 1 Stunde (3600000 ms)
if (displayOn && millis() - lastActivityTime > 3600000) { //3600000
mx.clear();
mx.update();
displayOn = false;
}
delay(50);
}
const uint8_t colMap[32] = {
24,25,26,27,28,29,30,31, // Home-Zehner
16,17,18,19,20,21,22,23, // Home-Einer
8, 9,10,11,12,13,14,15, // Away-Zehner
0, 1, 2, 3, 4, 5, 6, 7 // Away-Einer
};
void drawDigit(uint8_t digit, uint8_t digitOffset) {
// digitOffset in Anzahl Digit-Gruppen: 0 (HomeZehner), 1 (HomeEiner), 2 (AwayZehner), 3 (AwayEiner)
for (uint8_t row = 0; row < 8; row++) {
for (uint8_t col = 0; col < 4; col++) {
if (digits[digit][row][col]) {
uint8_t mappedCol = colMap[digitOffset + col];
mx.setPoint(row, mappedCol, true);
}
}
}
}
void showScore() {
lastActivityTime = millis(); //für Abschaltung Display
displayOn = true;
sendScore();
mx.clear();
uint8_t z4 = scoreHome / 10;
uint8_t z3 = scoreHome % 10;
uint8_t z2 = scoreAway / 10;
uint8_t z1 = scoreAway % 10;
drawDigit(z2, 22);
drawDigit(z1, 28);
drawDigit(z4, 2);
drawDigit(z3, 8);
mx.update();
}
uint8_t broadcastAddress[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
void sendScore() {
int scoreData[2] = { scoreHome, scoreAway };
esp_now_send(broadcastAddress, (uint8_t*)scoreData, sizeof(scoreData));
Serial.printf("📤 Sende Score: Heim=%d, Gast=%d\n", scoreHome, scoreAway);
}