Web improvements, NFC config
This commit is contained in:
parent
a3be4cbb3c
commit
578281d9d1
|
|
@ -111,14 +111,23 @@ Place these sounds in the folder `system` on the SD card:
|
|||
sleep.mp3 will be played just before the timed shutdown, start.mp3 will be played if the box started and initialized successfully.
|
||||
|
||||
|
||||
## Battery Voltage
|
||||
|
||||
The battery voltage is measured by the ADC of pin 13. A voltage divider halves the voltage so that the pin can not be overloaded (max 3.3V).
|
||||
The voltage divider consists of two 100kOHM resistors, the voltage is measured between them. One side is connected to the battery and the other to ground.
|
||||
Pin 13s ADC (ADC2) can not be used while WIFI is on... damn.
|
||||
|
||||
## TODOs
|
||||
|
||||
* Card Reader with SPI. Configure hspi, second SPI channel? Or does SD Card + RFID run at the same channel?
|
||||
|
||||

|
||||
|
||||
|
||||
## Schematic without modules
|
||||
|
||||
### Charging circuit
|
||||
|
||||
https://ww1.microchip.com/downloads/en/AppNotes/01149c.pdf
|
||||
MCP73837 ?
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ const char index_html[] PROGMEM = R"rawliteral(
|
|||
<body>
|
||||
<h1>HannaBox</h1>
|
||||
<span id="state"></span><br/><br/>
|
||||
<span id="voltage"></span><br/>
|
||||
<span id="uid"></span><br/>
|
||||
|
||||
<div>
|
||||
<button class="prev-button" onclick="simpleGetCall('prev');""></button>
|
||||
|
|
@ -16,16 +18,17 @@ const char index_html[] PROGMEM = R"rawliteral(
|
|||
<button class="next-button" onclick="simpleGetCall('next');"></button><br/><br/>
|
||||
</div>
|
||||
<div class="slidecontainer">
|
||||
<label for="progress" id="progressLabel"></label>
|
||||
|
||||
<input name="progress" type="range" min="0" max="100" value="0" class="slider" id="progressSlider"
|
||||
onmouseup="postValue('progress',document.getElementById('progressSlider').value);"
|
||||
ontouchend="postValue('progress',document.getElementById('progressSlider').value);">
|
||||
onchange="postValue('progress',document.getElementById('progressSlider').value);lastChange = Date.now()"
|
||||
>
|
||||
<label for="progress" id="progressLabel"></label>
|
||||
</div>
|
||||
<div class="slidecontainer">
|
||||
<label for="volume">Vol</label>
|
||||
<div class="slidecontainer">
|
||||
<input name="volume" type="range" min="0" max="15" value="7" class="slider" id="volumeSlider"
|
||||
onmouseup="postValue('volume',document.getElementById('volumeSlider').value);"
|
||||
ontouchend="postValue('volume',document.getElementById('volumeSlider').value);">
|
||||
onchange="postValue('volume',document.getElementById('volumeSlider').value);lastChange = Date.now()"
|
||||
>
|
||||
<label for="volume">Vol</label>
|
||||
</div>
|
||||
<!--
|
||||
<button onmouseup="simpleGetCall('stop');" ontouchend="simpleGetCall('stop');">Stop</button>
|
||||
|
|
@ -42,6 +45,8 @@ const char index_html[] PROGMEM = R"rawliteral(
|
|||
// Get the <li> elements
|
||||
var liElements = document.querySelectorAll('ul li');
|
||||
|
||||
var lastChange = 0;
|
||||
|
||||
// Add click event listener to each <li> element
|
||||
liElements.forEach(function(li) {
|
||||
li.addEventListener('click', function() {
|
||||
|
|
@ -81,6 +86,8 @@ const char index_html[] PROGMEM = R"rawliteral(
|
|||
function displayState(state) {
|
||||
document.getElementById("state").innerHTML = state['title'];
|
||||
document.getElementById("progressLabel").innerHTML = state['time'];
|
||||
document.getElementById("voltage").innerHTML = state['voltage']+' mV';
|
||||
document.getElementById("uid").innerHTML = 'Last NFC ID: '+state['uid'];
|
||||
var elements = document.getElementsByClassName('play-button');
|
||||
var btn = elements[0];
|
||||
|
||||
|
|
@ -89,12 +96,16 @@ const char index_html[] PROGMEM = R"rawliteral(
|
|||
} else {
|
||||
btn.classList.remove('paused');
|
||||
}
|
||||
var progress = document.getElementById('progressSlider');
|
||||
progress.value = state['time'];
|
||||
progress.max = state['length'];
|
||||
|
||||
if (Date.now()-lastChange>1200) {
|
||||
var progress = document.getElementById('progressSlider');
|
||||
progress.value = state['time'];
|
||||
progress.max = state['length'];
|
||||
|
||||
var volume = document.getElementById('volumeSlider');
|
||||
volume.value = state['volume'];
|
||||
}
|
||||
|
||||
var volume = document.getElementById('volumeSlider');
|
||||
volume.value = state['volume'];
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -65,4 +65,8 @@ li {
|
|||
box-shadow: -10px 0 0 0 darkgrey;
|
||||
}
|
||||
|
||||
.slider {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
)rawliteral";
|
||||
|
|
@ -52,6 +52,7 @@ void writeFile(fs::FS &fs, const char * path, const char * message){
|
|||
file.close();
|
||||
}
|
||||
|
||||
|
||||
unsigned long lastStart = 0;
|
||||
|
||||
unsigned long lastInteraction = 0;
|
||||
|
|
@ -64,12 +65,20 @@ boolean continuousMode = false;
|
|||
|
||||
uint8_t buttontoignore = 0;
|
||||
|
||||
uint32_t lastVoltage = 0;
|
||||
|
||||
const int startDelay = 250;
|
||||
|
||||
String lastUid = "";
|
||||
|
||||
const String sleep_sound = "sleep.mp3";
|
||||
|
||||
const String startup_sound = "start.mp3";
|
||||
|
||||
const String mapping_file = "/mapping.txt";
|
||||
|
||||
std::map<String, String> rfid_map;
|
||||
|
||||
/*
|
||||
const long sleepMessageDelay = 28000;
|
||||
|
||||
|
|
|
|||
120
src/main.cpp
120
src/main.cpp
|
|
@ -31,6 +31,8 @@
|
|||
|
||||
#define CS_SDCARD 22
|
||||
|
||||
#define BAT_VOLTAGE_PIN 13
|
||||
|
||||
#define RFID_LOOP_INTERVAL 25
|
||||
|
||||
#include "globals.h"
|
||||
|
|
@ -75,9 +77,12 @@ bool asyncNext = false;
|
|||
|
||||
bool asyncPrev = false;
|
||||
|
||||
/*
|
||||
std::map<String, String> rfid_map{{"67 152 204 14", "01-The_Box_Tops-The_Letter.mp3"},
|
||||
{"67 175 148 160", "068-Der_Schatz_im_Bergsee"}};
|
||||
|
||||
*/
|
||||
|
||||
void activateSD()
|
||||
{
|
||||
digitalWrite(CS_SDCARD, LOW);
|
||||
|
|
@ -98,6 +103,12 @@ void deactivateRFID()
|
|||
digitalWrite(CS_RFID, HIGH);
|
||||
}
|
||||
|
||||
uint32_t getBatteryVoltageMv() {
|
||||
uint32_t voltage = analogReadMilliVolts(BAT_VOLTAGE_PIN);
|
||||
return voltage*2;//*2 because of the voltage divider.
|
||||
}
|
||||
|
||||
|
||||
void playSongByName(String song)
|
||||
{
|
||||
currentNode = rootNode.advanceToMP3(&song);
|
||||
|
|
@ -117,10 +128,14 @@ void playSongByPath(String path)
|
|||
|
||||
void playSongByRFID(String id)
|
||||
{
|
||||
String song = rfid_map[id];
|
||||
auto songit = rfid_map.find(id);
|
||||
if (songit==rfid_map.end()) {
|
||||
Serial.println("song for uid not found.");
|
||||
return;
|
||||
}
|
||||
Serial.println("searching for ");
|
||||
Serial.println(song);
|
||||
playSongByName(song);
|
||||
Serial.println(songit->second);
|
||||
playSongByName(songit->second);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -200,11 +215,41 @@ String getState()
|
|||
jsonState["time"] = audio.getAudioCurrentTime();
|
||||
jsonState["volume"] = audio.getVolume();
|
||||
jsonState["length"] = audio.getAudioFileDuration();
|
||||
jsonState["voltage"] = lastVoltage;
|
||||
jsonState["uid"] = lastUid;
|
||||
String output;
|
||||
serializeJson(jsonState, output);
|
||||
jsonState.clear();
|
||||
jsonState.garbageCollect();
|
||||
return output;
|
||||
}
|
||||
|
||||
std::map<String, String> readDataFromFile(const char *filename) {
|
||||
|
||||
File file = SD.open(filename);
|
||||
|
||||
if (file) {
|
||||
while (file.available()) {
|
||||
// Read key and value from the file
|
||||
String line = file.readStringUntil('\n');
|
||||
int separatorIndex = line.indexOf('=');
|
||||
if (separatorIndex != -1) {
|
||||
// Extract key and value
|
||||
String key = line.substring(0, separatorIndex).c_str();
|
||||
String value = line.substring(separatorIndex + 1).c_str();
|
||||
// Add key-value pair to the map
|
||||
rfid_map[key] = value;
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
} else {
|
||||
Serial.print("Error opening file ");
|
||||
Serial.println(filename);
|
||||
}
|
||||
|
||||
return rfid_map;
|
||||
}
|
||||
|
||||
String processor(const String &var)
|
||||
{
|
||||
if (var == "DIRECTORY")
|
||||
|
|
@ -273,56 +318,13 @@ void IRAM_ATTR rfid_interrupt()
|
|||
void readRFID()
|
||||
{
|
||||
rfid.PICC_ReadCardSerial();
|
||||
Serial.print("Tag UID: ");
|
||||
String uidString = getRFIDString(rfid.uid.uidByte);
|
||||
Serial.println(uidString);
|
||||
Serial.print("Card UID: ");
|
||||
lastUid = getRFIDString(rfid.uid.uidByte);
|
||||
Serial.println(lastUid);
|
||||
//rfid.PICC_DumpDetailsToSerial(&(rfid.uid));
|
||||
|
||||
|
||||
// Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
|
||||
MFRC522::MIFARE_Key key;
|
||||
for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;
|
||||
|
||||
//some variables we need
|
||||
byte buffer[42]; //data transfer buffer (16+2 bytes data+CRC)
|
||||
byte size = sizeof(buffer);
|
||||
|
||||
uint8_t pageAddr = 0x05; //In this example we will write/read 16 bytes (page 6,7,8 and 9).
|
||||
//Ultraligth mem = 16 pages. 4 bytes per page.
|
||||
//Pages 0 to 4 are for special functions.
|
||||
|
||||
MFRC522::StatusCode status;
|
||||
|
||||
rfid.PICC_DumpDetailsToSerial(&(rfid.uid));
|
||||
|
||||
//------------------------------------------- GET FIRST NAME
|
||||
/*
|
||||
status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 4, &key, &(rfid.uid)); //line 834 of MFRC522.cpp file
|
||||
if (status != MFRC522::STATUS_OK) {
|
||||
Serial.print(F("Authentication failed: "));
|
||||
Serial.println(rfid.GetStatusCodeName(status));
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("Auth");
|
||||
*/
|
||||
|
||||
// works only with mifare ultralight:
|
||||
status = rfid.MIFARE_Read(pageAddr, buffer, &size);
|
||||
if (status != MFRC522::STATUS_OK) {
|
||||
Serial.print(F("Reading failed: "));
|
||||
Serial.println(rfid.GetStatusCodeName(status));
|
||||
return;
|
||||
}
|
||||
|
||||
//Dump a byte array to Serial
|
||||
for (byte i = 0; i < size; i++) {
|
||||
Serial.write(buffer[i]);
|
||||
}
|
||||
Serial.println();
|
||||
// ------------------------------
|
||||
rfid.PICC_HaltA();
|
||||
|
||||
playSongByRFID(uidString);
|
||||
playSongByRFID(lastUid);
|
||||
lastInteraction = millis();
|
||||
}
|
||||
|
||||
|
|
@ -361,6 +363,8 @@ void setup()
|
|||
rootNode.buildDirectoryTree("/");
|
||||
rootNode.printDirectoryTree();
|
||||
|
||||
readDataFromFile(mapping_file.c_str());
|
||||
|
||||
deactivateSD();
|
||||
activateRFID();
|
||||
Serial.println("RFID");
|
||||
|
|
@ -384,11 +388,19 @@ void setup()
|
|||
|
||||
Serial.println("Audio initialized.");
|
||||
|
||||
lastVoltage = getBatteryVoltageMv();
|
||||
|
||||
Serial.print("Battery Voltage in mV: ");
|
||||
Serial.println(lastVoltage);
|
||||
|
||||
// first parameter is name of access point, second is the password
|
||||
AsyncWiFiManager wifiManager(&server, &dns);
|
||||
|
||||
wifiManager.setTimeout(180);
|
||||
|
||||
Serial.println("Deactivating Brownout detector...");
|
||||
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
|
||||
|
||||
if (wifiManager.autoConnect("HannaBox"))
|
||||
{
|
||||
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
|
||||
|
|
@ -438,6 +450,9 @@ void setup()
|
|||
Serial.println("Wifi timed out. Fallback no Wifi.");
|
||||
}
|
||||
|
||||
Serial.println("Activating Brownout detector...");
|
||||
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1); //enable brownout detector
|
||||
|
||||
xTaskCreatePinnedToCore(
|
||||
loop2, /* Function to implement the task */
|
||||
"RFIDTask", /* Name of the task */
|
||||
|
|
@ -459,7 +474,6 @@ void named_song_action(AsyncWebServerRequest *request)
|
|||
for (int i = 0; i < params; i++)
|
||||
{
|
||||
AsyncWebParameter *p = request->getParam(i);
|
||||
Serial.printf("POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
||||
if (p->name() == "title")
|
||||
{
|
||||
playSongByName(p->value());
|
||||
|
|
@ -477,7 +491,6 @@ void progress_action(AsyncWebServerRequest *request)
|
|||
for (int i = 0; i < params; i++)
|
||||
{
|
||||
AsyncWebParameter *p = request->getParam(i);
|
||||
Serial.printf("POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
||||
if (p->name() == "value")
|
||||
{
|
||||
audio.setAudioPlayPosition(atoi(p->value().c_str()));
|
||||
|
|
@ -495,7 +508,6 @@ void volume_action(AsyncWebServerRequest *request)
|
|||
for (int i = 0; i < params; i++)
|
||||
{
|
||||
AsyncWebParameter *p = request->getParam(i);
|
||||
Serial.printf("POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
||||
if (p->name() == "value")
|
||||
{
|
||||
audio.setVolume(atoi(p->value().c_str()));
|
||||
|
|
|
|||
Loading…
Reference in New Issue