mirror of
https://github.com/Crocmagnon/buzzer.git
synced 2025-04-21 08:55:27 +02:00
275 lines
6.3 KiB
C++
275 lines
6.3 KiB
C++
#include <Arduino.h>
|
|
#include <ESPAsyncWebServer.h>
|
|
#include <SPIFFS.h>
|
|
#include <AsyncJson.h>
|
|
#include <Audio.h>
|
|
#include <SPI.h>
|
|
#include <Wire.h>
|
|
#include <Adafruit_GFX.h>
|
|
#include <Adafruit_SSD1306.h>
|
|
|
|
// Toggle on to switch to AP mode.
|
|
// Leave commented for wifi station mode.
|
|
//#define B_WIFI_AP
|
|
|
|
#ifdef B_WIFI_AP
|
|
#include "creds_ap.h"
|
|
#else
|
|
#include "creds.h"
|
|
#endif
|
|
|
|
#define I2S_DOUT 32
|
|
#define I2S_BCLK 25
|
|
#define I2S_LRC 27
|
|
|
|
#define SPI_MISO 18
|
|
#define SPI_MOSI 19
|
|
#define SPI_SCK 23
|
|
#define SD_CS 5
|
|
|
|
#define LED 2
|
|
#define BUTTON 4
|
|
|
|
#define SSD1306_NO_SPLASH
|
|
#define SCREEN_WIDTH 128
|
|
#define SCREEN_HEIGHT 64
|
|
#define OLED_RESET -1
|
|
#define SCREEN_ADDRESS 0x3C
|
|
|
|
#define SCREEN_MSG_X 0
|
|
#define SCREEN_MSG_Y 24
|
|
|
|
#define VOLUME_MIN 0
|
|
#define VOLUME_MAX 21
|
|
|
|
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
|
|
|
String selectedFile = "";
|
|
|
|
AsyncWebServer server(80);
|
|
Audio audio;
|
|
|
|
byte buttonLastState = HIGH;
|
|
byte currentVolume = 2;
|
|
|
|
bool fileIsValid(String fileName) {
|
|
return !fileName.startsWith(".") && (fileName.endsWith(".mp3") || fileName.endsWith(".aac") || fileName.endsWith(".wav"));
|
|
}
|
|
|
|
void clearMessageArea() {
|
|
display.fillRect(SCREEN_MSG_X, SCREEN_MSG_Y, SCREEN_WIDTH - SCREEN_MSG_X, SCREEN_HEIGHT - SCREEN_MSG_Y, BLACK);
|
|
display.setCursor(SCREEN_MSG_X, SCREEN_MSG_Y);
|
|
}
|
|
|
|
void displayText(String text) {
|
|
clearMessageArea();
|
|
display.println(text);
|
|
display.display();
|
|
}
|
|
|
|
void play()
|
|
{
|
|
String path = "/" + selectedFile;
|
|
Serial.println("Playing file: " + path);
|
|
audio.connecttoFS(SD, path.c_str());
|
|
}
|
|
|
|
void onStop(AsyncWebServerRequest *request)
|
|
{
|
|
audio.stopSong();
|
|
request->send(200);
|
|
}
|
|
|
|
void onPlay(AsyncWebServerRequest *request)
|
|
{
|
|
play();
|
|
request->send(200);
|
|
}
|
|
|
|
void onStatus(AsyncWebServerRequest *request)
|
|
{
|
|
Serial.println("Status");
|
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
|
|
|
DynamicJsonDocument root(256);
|
|
root["selectedFile"] = selectedFile;
|
|
JsonArray files = root.createNestedArray("files");
|
|
File music = SD.open("/");
|
|
File file = music.openNextFile();
|
|
while (file)
|
|
{
|
|
String fileName = file.name();
|
|
if (fileIsValid(fileName))
|
|
files.add(fileName);
|
|
file.close();
|
|
file = music.openNextFile();
|
|
}
|
|
|
|
JsonObject volume = root.createNestedObject("volume");
|
|
volume["current"] = currentVolume;
|
|
volume["canDecrease"] = currentVolume > 0;
|
|
volume["canIncrease"] = currentVolume < 21;
|
|
|
|
serializeJson(root, *response);
|
|
|
|
request->send(response);
|
|
}
|
|
|
|
void onSelectFile(AsyncWebServerRequest *request)
|
|
{
|
|
Serial.print("Select file: ");
|
|
if (request->hasParam("fileName", true))
|
|
{
|
|
selectedFile = request->getParam("fileName", true)->value();
|
|
Serial.print(selectedFile);
|
|
displayText("Selectionne : " + selectedFile);
|
|
}
|
|
Serial.println();
|
|
onStatus(request);
|
|
}
|
|
|
|
void onChangeVolume(AsyncWebServerRequest *request)
|
|
{
|
|
Serial.print("Volume: ");
|
|
if (request->hasParam("modifier", true))
|
|
{
|
|
String s_modifier = request->getParam("modifier", true)->value();
|
|
int modifier = s_modifier.toInt();
|
|
currentVolume += modifier;
|
|
if (currentVolume > VOLUME_MAX)
|
|
currentVolume = VOLUME_MAX;
|
|
else if (currentVolume < VOLUME_MIN)
|
|
currentVolume = VOLUME_MIN;
|
|
audio.setVolume(currentVolume);
|
|
Serial.print(currentVolume);
|
|
clearMessageArea();
|
|
display.print("Volume : ");
|
|
display.println(currentVolume);
|
|
display.display();
|
|
}
|
|
Serial.println();
|
|
onStatus(request);
|
|
}
|
|
|
|
void setup()
|
|
{
|
|
// Setup serial
|
|
Serial.begin(115200);
|
|
pinMode(LED, OUTPUT);
|
|
digitalWrite(LED, LOW);
|
|
|
|
// Screen
|
|
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
|
|
{
|
|
Serial.println(F("SSD1306 allocation failed"));
|
|
return;
|
|
}
|
|
display.clearDisplay();
|
|
display.setTextSize(1);
|
|
display.setTextColor(WHITE, BLACK);
|
|
display.setCursor(0, 0);
|
|
display.println("Chargement...");
|
|
display.display();
|
|
|
|
pinMode(BUTTON, INPUT_PULLUP);
|
|
|
|
// Setup SPIFFS
|
|
if (!SPIFFS.begin())
|
|
{
|
|
Serial.println("SPIFFS error. Exiting.");
|
|
display.println("Impossible d'acceder aux fichiers...");
|
|
display.display();
|
|
return;
|
|
}
|
|
|
|
pinMode(SD_CS, OUTPUT);
|
|
digitalWrite(SD_CS, HIGH);
|
|
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
|
|
|
|
if(!SD.begin(SD_CS))
|
|
{
|
|
Serial.println("Error talking to SD card!");
|
|
display.println("Impossible d'acceder a la carte SD...");
|
|
display.display();
|
|
return;
|
|
}
|
|
|
|
File root = SD.open("/");
|
|
File file = root.openNextFile();
|
|
while (file)
|
|
{
|
|
String fileName = file.name();
|
|
if (fileIsValid(fileName))
|
|
{
|
|
selectedFile = fileName;
|
|
Serial.println("Selected " + fileName);
|
|
display.println("Selectionne : " + fileName);
|
|
display.display();
|
|
break;
|
|
}
|
|
file.close();
|
|
file = root.openNextFile();
|
|
}
|
|
|
|
display.clearDisplay();
|
|
display.setCursor(0, 0);
|
|
// Wifi
|
|
#ifdef B_WIFI_AP
|
|
Serial.println("Setting up AP...");
|
|
WiFi.softAP(ssid, password);
|
|
String wifiIP = WiFi.softAPIP().toString();
|
|
String wifiMode = "AP";
|
|
display.print("Wifi: ");
|
|
display.println(ssid);
|
|
display.print("Pass: ");
|
|
display.println(password);
|
|
#else
|
|
Serial.print("Connecting to wifi...");
|
|
WiFi.begin(ssid, password);
|
|
while (WiFi.status() != WL_CONNECTED)
|
|
{
|
|
Serial.print(".");
|
|
delay(500);
|
|
}
|
|
Serial.println();
|
|
String wifiIP = WiFi.localIP().toString();
|
|
String wifiMode = "client";
|
|
#endif
|
|
String wifiMessage = wifiMode + " IP: " + wifiIP;
|
|
Serial.println(wifiMessage);
|
|
display.print("IP: ");
|
|
display.println(wifiIP);
|
|
display.display();
|
|
|
|
// Server
|
|
server.on("/play", HTTP_GET, onPlay);
|
|
server.on("/stop", HTTP_GET, onStop);
|
|
server.on("/status", HTTP_GET, onStatus);
|
|
server.on("/select-file", HTTP_POST, onSelectFile);
|
|
server.on("/change-volume", HTTP_POST, onChangeVolume);
|
|
server.onNotFound([](AsyncWebServerRequest *request)
|
|
{ request->send(404); });
|
|
server.serveStatic("/", SPIFFS, "/www/").setDefaultFile("index.html");
|
|
server.begin();
|
|
|
|
Serial.println("Server ready!");
|
|
clearMessageArea();
|
|
display.println("Pret !");
|
|
display.display();
|
|
|
|
// Audio
|
|
audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
|
|
audio.setVolume(currentVolume);
|
|
|
|
// Setup is done, light up the LED
|
|
digitalWrite(LED, HIGH);
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
byte buttonCurrentState = digitalRead(BUTTON);
|
|
if (buttonCurrentState == LOW && buttonLastState == HIGH)
|
|
play();
|
|
buttonLastState = buttonCurrentState;
|
|
audio.loop();
|
|
}
|