Pour téléverser le code depuis Arduino, la librairie ESP8266 ainsi que le plugin SPIFFS doivent être préalablement installés. Le code initialise le SPIFFS, indique les routes vers les librairies statiques stockées dans le SPIFFS, crée un réseau WIFI sans mot de passe, stocke et vérifie les bonnes réponses et joue la mélodie sur le piezo via la librairie “notes.h” qui converti chaque note en fréquence en Hz. Il est commenté ligne par ligne (en anglais)
/*Copyright 2019 Reso-nance Numérique <laurent@reso-nance.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
-------------- Pinout --------------
pin 12 (GPIO18) ------> Piezo +
(put a 220 Ohm resistor between piezo- and gnd)
this sketch needs at least 1M SPIFF (the code uses ~29ko of FLASH and SPIFFS files needs ~197ko)
*/
#include <ESP8266WiFi.h> // manage the softAP functionnality
#include <ESP8266WebServer.h> // self explanatory
#include <FS.h> // for the SPIFFS (SPI file system)
#include "pitches.h" // convert human readable musical notes into pitches in hertz
#define SERIAL_DEBUG
#define BUZZER_PIN D2
IPAddress apIP(10, 0, 0, 1); // Defining a static IP address: local & gateway
// Default IP in AP mode is 192.168.4.1
const char *ssid = "JoyeuxNoel";
// const char *password = "joyeuxnoel";
const String goodAnswers[]={"0", "2", "1", "3", "1", "3", "0", "1", "3", "0"}; // in the order of the questions
const unsigned int answerCount = 10; // since answers are stored as const Strings, we cannot use the sizeof(goodAnswers)/sizeof(String) trick here
int wish_melody[] = { // "we wish you a merry christmas" notes. One is off, to be corrected...
NOTE_B3, // theses notes will be converted to pitch in Hz by the pitches.h library
NOTE_F4, NOTE_F4, NOTE_G4, NOTE_F4, NOTE_E4,
NOTE_D4, NOTE_D4, NOTE_D4,
NOTE_G4, NOTE_G4, NOTE_A4, NOTE_G4, NOTE_F4,
NOTE_E4, NOTE_E4, NOTE_E4,
NOTE_A4, NOTE_A4, NOTE_B4, NOTE_A4, NOTE_G4,
NOTE_F4, NOTE_D4, NOTE_B3, NOTE_B3,
NOTE_D4, NOTE_G4, NOTE_E4,
NOTE_F4
};
int wish_tempo[] = {// relative note durations defining the rythme of the melody
4,
4, 8, 8, 8, 8,
4, 4, 4,
4, 8, 8, 8, 8,
4, 4, 4,
4, 8, 8, 8, 8,
4, 4, 8, 8,
4, 4, 4,
2
};
ESP8266WebServer server(80);
#ifdef SERIAL_DEBUG // I defined theses two functions to avoid using "#ifdef... #endif" each time
#define debugPrint(x) Serial.print (x)
#define debugPrintln(x) Serial.println (x)
#else
#define debugPrint(x)
#define debugPrintln(x)
#endif
void handleNotFound() {// 404 manager, no fancy html here, just plain text sent by the server
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();// the unreacheable address
message += "\nMethod: ";
message += ( server.method() == HTTP_GET ) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for ( uint8_t i = 0; i < server.args(); i++ ) {
message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n";
}
server.send ( 404, "text/plain", message );
}
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(BUZZER_PIN, LOW);
#ifdef SERIAL_DEBUG
Serial.begin(115200);
#endif
debugPrintln();
debugPrintln("Configuring access point...");
//set-up the custom IP address
WiFi.mode(WIFI_AP_STA);
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); // subnet FF FF FF 00 or 255.255.255.0
WiFi.softAP(ssid);
// WiFi.softAP(ssid, password); // we can add a password if needed
WiFi.hostname("quizz"); // on mac and linux clients, you may reach it by http://hostname.local
IPAddress myIP = WiFi.softAPIP();
debugPrint("AP IP address: ");
debugPrintln(myIP);
SPIFFS.begin(); // initiate the SPI filesystem
// server routes, much like PhP, each URL is linked to a function
server.onNotFound ( handleNotFound );
server.on("/", fileindex);
server.on("/index.html", fileindex);
server.on("/bootstrap.min.css", bootstrapCSS);
server.on("bootstrap.min.css", bootstrapCSS);
server.on("/popper.min.js", popper);
server.on("/bootstrap.min.js", bootstrapJS);
server.on("bootstrap.min.js", bootstrapJS);
server.on("jquery-3.3.1.min", jquery);
server.on("/jquery-3.3.1.min", jquery);
server.on("/bootstrap-theme.min.css", bootstrapThemeCSS);
server.on("bootstrap-theme.min.css", bootstrapThemeCSS);
server.on("/favicon.ico", favicon);
server.on("/verify", validateAnswers);
server.begin();
debugPrintln("HTTP server started");
}
void loop() {
server.handleClient();// shortest loop ever, aren't libraries a wonderful thing ?
}
void validateAnswers(){ // this function is called when the user click on the validate button on the UI
String questionsID[answerCount];// this array will contain the questions ID as Strings (ie : {"1", "2"...})
unsigned int validatedAnswers = 0;// this will increment each time an answer is counted as valid
for (unsigned int i=0; i<answerCount; i++) { // for each answer :
const String test = server.arg(String(i)); // create a string from the answer number since the data received in POST are always strings
if (test == goodAnswers[i]) validatedAnswers++; // good job
else debugPrintln("wrong answer : "+String(i)+" is "+test+" instead of "+goodAnswers[i]);
}
debugPrintln(String(validatedAnswers)+"/"+String(answerCount)+" good answers");
// now will contruct a String containing JSON data {"goodAnswers":"XX", "totalQuestions":"YY"}
String json = "{\"goodAnswers\":\""+String(validatedAnswers)+"\",\"totalQuestions\":\""+String(answerCount)+"\"}";
server.send(200, "application/json", json);// we send this json string back to the UI
if (validatedAnswers == answerCount) {// if every answer is correct
digitalWrite(LED_BUILTIN, LOW);// we turn the led ON
singWeWishYou(2); // play the melody twice
digitalWrite(LED_BUILTIN, HIGH);// and turn the led back off
}
else digitalWrite(LED_BUILTIN, HIGH);// else, we turn the led off, won't hurt if its already off.
}
void singWeWishYou(int loops) { // this function will play "we wish you a merry christmas" once on the buzzer
// iterate over the notes of the melody:
debugPrintln(" 'We wish you a Merry Christmas'");
int size = sizeof(wish_melody) / sizeof(int);
for (unsigned int i=0; i<loops; i++) {
for (int thisNote = 0; thisNote < size; thisNote++) {
// to calculate the note duration, take one second
// divided by the note type.
//e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
int noteDuration = 1000 / wish_tempo[thisNote];
tone(BUZZER_PIN,wish_melody[thisNote]);// the tone library is builtin to the ESP8266 and allow to play tone by PWM on a buzzer
// to distinguish the notes, set a minimum time between them.
// the note's duration + 30% seems to work well:
int pauseBetweenNotes = noteDuration * 1.30;
ESP.wdtFeed();// if we don't feed the infamous watchdog, it could reboot the ESP8266 on long routines.
delay(pauseBetweenNotes);
// stop the tone playing:
noTone(BUZZER_PIN);
}
}
}
// the functions below are routes to files stored in the SPIFFS
void fileindex()
{
File file = SPIFFS.open("/index.html", "r");
size_t sent = server.streamFile(file, "text/html");
}
// we have zipped the static library to save space on the ESP8266 flash
void bootstrapCSS()
{
File file = SPIFFS.open("/bootstrap.min.css.gz", "r");
size_t sent = server.streamFile(file, "text/css");
}
void bootstrapThemeCSS()
{
File file = SPIFFS.open("/bootstrap-theme.min.css.gz", "r");
size_t sent = server.streamFile(file, "text/css");
}
void popper()
{
File file = SPIFFS.open("/popper.min.js.gz", "r");
size_t sent = server.streamFile(file, "application/javascript");
}
void bootstrapJS()
{
File file = SPIFFS.open("/bootstrap.min.js.gz", "r");
size_t sent = server.streamFile(file, "application/javascript");
}
void jquery()
{
File file = SPIFFS.open("/jquery-3.3.1.min.gz", "r");
size_t sent = server.streamFile(file, "application/javascript");
}
void favicon()
{
File file = SPIFFS.open("/favicon.ico", "r");
size_t sent = server.streamFile(file, "image/x-icon");
}