Implemented recording audio with threshold and sending it to Rat

This commit is contained in:
Sviatoslav Tsariov Yurievich 2024-03-25 16:25:46 +03:00
parent 5d74460e65
commit c0bf4286d1
17 changed files with 704 additions and 332 deletions

View File

@ -19,3 +19,5 @@ board_build.partitions = no_ota.csv
lib_deps =
ottowinter/AsyncMqttClient-esphome@^0.8.6
arduino-libraries/Ethernet@^2.0.2
paulstoffregen/Time@^1.6.1
bblanchon/ArduinoJson@^6.21.3

View File

@ -1,84 +0,0 @@
#include "Audio.h"
Audio::Audio(MicType micType) {
wavData = new char*[wavDataSize/dividedWavDataSize];
for (int i = 0; i < wavDataSize/dividedWavDataSize; ++i) wavData[i] = new char[dividedWavDataSize];
i2s = new I2S(micType);
}
Audio::~Audio() {
for (int i = 0; i < wavDataSize/dividedWavDataSize; ++i) delete[] wavData[i];
delete[] wavData;
delete i2s;
}
void Audio::CreateWavHeader(byte* header, int waveDataSize){
header[0] = 'R';
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
unsigned int fileSizeMinus8 = waveDataSize + 44 - 8;
header[4] = (byte)(fileSizeMinus8 & 0xFF);
header[5] = (byte)((fileSizeMinus8 >> 8) & 0xFF);
header[6] = (byte)((fileSizeMinus8 >> 16) & 0xFF);
header[7] = (byte)((fileSizeMinus8 >> 24) & 0xFF);
header[8] = 'W';
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
header[12] = 'f';
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
header[16] = 0x10; // linear PCM
header[17] = 0x00;
header[18] = 0x00;
header[19] = 0x00;
header[20] = 0x01; // linear PCM
header[21] = 0x00;
header[22] = 0x01; // monoral
header[23] = 0x00;
header[24] = 0x80; // sampling rate 16000
header[25] = 0x3E;
header[26] = 0x00;
header[27] = 0x00;
header[28] = 0x00; // Byte/sec = 16000x2x1 = 32000
header[29] = 0x7D;
header[30] = 0x00;
header[31] = 0x00;
header[32] = 0x02; // 16bit monoral
header[33] = 0x00;
header[34] = 0x10; // 16bit
header[35] = 0x00;
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (byte)(waveDataSize & 0xFF);
header[41] = (byte)((waveDataSize >> 8) & 0xFF);
header[42] = (byte)((waveDataSize >> 16) & 0xFF);
header[43] = (byte)((waveDataSize >> 24) & 0xFF);
}
void Audio::Record() {
CreateWavHeader(paddedHeader, wavDataSize);
int bitBitPerSample = i2s->GetBitPerSample();
if (bitBitPerSample == 16) {
for (int j = 0; j < wavDataSize/dividedWavDataSize; ++j) {
i2s->Read(i2sBuffer, i2sBufferSize/2);
for (int i = 0; i < i2sBufferSize/8; ++i) {
wavData[j][2*i] = i2sBuffer[4*i + 2];
wavData[j][2*i + 1] = i2sBuffer[4*i + 3];
}
}
}
else if (bitBitPerSample == 32) {
for (int j = 0; j < wavDataSize/dividedWavDataSize; ++j) {
i2s->Read(i2sBuffer, i2sBufferSize);
for (int i = 0; i < i2sBufferSize/8; ++i) {
wavData[j][2*i] = i2sBuffer[8*i + 2] << 4;
wavData[j][2*i + 1] = i2sBuffer[8*i + 3] << 4;
}
}
}
}

View File

@ -1,26 +0,0 @@
#ifndef _AUDIO_H
#define _AUDIO_H
#include <Arduino.h>
#include "I2S.h"
// 16bit, monoral, 16000Hz, linear PCM
class Audio {
I2S* i2s;
static const int headerSize = 44;
static const int i2sBufferSize = 6000;
char i2sBuffer[i2sBufferSize];
void CreateWavHeader(byte* header, int waveDataSize);
public:
static const int wavDataSize = 90000; // It must be multiple of dividedWavDataSize. Recording time is about 1.9 second.
static const int dividedWavDataSize = i2sBufferSize/4;
char** wavData; // It's divided. Because large continuous memory area can't be allocated in esp32.
byte paddedHeader[headerSize + 4] = {0}; // The size must be multiple of 3 for Base64 encoding. Additional byte size must be even because wave data is 16bit.
Audio(MicType micType);
~Audio();
void Record();
};
#endif // _AUDIO_H

29
src/config/config.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include <Arduino.h>
#define ETH_MISO 19
#define ETH_MOSI 23
#define ETH_SCK 18
#define ETH_SS 5
#define SD_CS 5
#define SPI_MOSI 23
#define SPI_MISO 19
#define SPI_SCK 18
#define I2S_DOUT 25
#define I2S_BCLK 27
#define I2S_LRC 26
#define MYIPADDR 192,168,1,28
#define MYIPMASK 255,255,255,0
#define MYDNS 192,168,1,1
#define MYGW 192,168,1,1
#define MYMAC { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }
#define RAT_IP "192.168.1.173"
#define RAT_PORT 8081
// make it configurable with some panel
//#define NOISE_THRESHOLD 3000000
#define NOISE_THRESHOLD 10000000

83
src/domain/Recorder.cpp Normal file
View File

@ -0,0 +1,83 @@
#include "domain/Recorder.h"
#include "config/config.h"
#include "utils/Time.h"
Time& timeModule = Time::getInstance();
Recorder::Recorder(MicType micType, Http* http) {
_audio = new Audio(micType);
_http = http;
}
Recorder::~Recorder() {
delete _audio;
}
void Recorder::recordAudio() {
_ready();
if (_http->connect(RAT_IP, RAT_PORT)) {
Serial.println("========================================");
Serial.println("| RECORDING...");
_audio->record();
Serial.println("| Recording finished");
_transcribe();
} else {
Serial.println("| Connection failed");
}
}
void Recorder::_ready() {
_http->send("POST", "/ready", RAT_IP, RAT_PORT, "", "");
}
void Recorder::_transcribe() {
String payloadStart = _formPayloadStart();
String payloadEnd = _formPayloadEnd();
int audioLength = _audio->getSize();
int jsonLength = payloadStart.length() + audioLength + payloadEnd.length();
_http->printHeader("POST", "/save_audio", RAT_IP, "application/json");
_http->printContentLength(jsonLength);
this->_printContent(payloadStart, payloadEnd, _http->getClient());
}
void Recorder::_printContent(String payloadStart, String payloadEnd, Stream* stream) {
stream->print(payloadStart);
_audio->print(stream);
stream->print(payloadEnd);
_logContent(payloadStart, payloadEnd);
}
void Recorder::_logContent(String payloadStart, String payloadEnd) {
Serial.print("| ");
Serial.print(payloadStart);
Serial.print("...");
Serial.print(payloadEnd);
}
String Recorder::_formPayloadStart() {
String payloadStart = "";
payloadStart += "{\"audio\":{\"micros\":";
payloadStart += String(_audio->getStartMicros() - timeModule.getInitialMicros());
payloadStart += ",\"initialTime\":";
payloadStart += String(timeModule.getInitialTime());
payloadStart += ",\"content\":\"";
return payloadStart;
}
String Recorder::_formPayloadEnd() {
return "\"}}\r\n\r\n";
}
bool Recorder::isNoiseDetected(int threshold) {
return _audio->isNoiseDetected(threshold);
}

25
src/domain/Recorder.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include "infra/Audio.h"
#include "infra/Http.h"
class Recorder {
private:
Audio* _audio;
Http* _http;
void _ready();
void _transcribe();
void _printContent(String payloadStart, String payloadEnd, Stream* stream);
void _logContent(String payloadStart, String payloadEnd);
void _printAudio();
String _formPayloadStart();
String _formPayloadEnd();
public:
Recorder(MicType micType, Http* http);
~Recorder();
void recordAudio();
bool isNoiseDetected(int threshold);
};

123
src/infra/Audio.cpp Normal file
View File

@ -0,0 +1,123 @@
#include "infra/Audio.h"
#include <base64.h>
Audio::Audio(MicType micType) {
_wavData = new char*[_wavDataSize/_dividedWavDataSize];
for (int i = 0; i < _wavDataSize/_dividedWavDataSize; ++i) _wavData[i] = new char[_dividedWavDataSize];
i2s = new I2S(micType);
}
Audio::~Audio() {
for (int i = 0; i < _wavDataSize/_dividedWavDataSize; ++i) delete[] _wavData[i];
delete[] _wavData;
delete i2s;
}
void Audio::_createWavHeader(byte* header, int waveDataSize){
header[0] = 'R';
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
unsigned int fileSizeMinus8 = waveDataSize + 44 - 8;
header[4] = (byte)(fileSizeMinus8 & 0xFF);
header[5] = (byte)((fileSizeMinus8 >> 8) & 0xFF);
header[6] = (byte)((fileSizeMinus8 >> 16) & 0xFF);
header[7] = (byte)((fileSizeMinus8 >> 24) & 0xFF);
header[8] = 'W';
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
header[12] = 'f';
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
header[16] = 0x10; // linear PCM
header[17] = 0x00;
header[18] = 0x00;
header[19] = 0x00;
header[20] = 0x01; // linear PCM
header[21] = 0x00;
header[22] = 0x01; // monoral
header[23] = 0x00;
header[24] = 0x80; // sampling rate 16000
header[25] = 0x3E;
header[26] = 0x00;
header[27] = 0x00;
header[28] = 0x00; // Byte/sec = 16000x2x1 = 32000
header[29] = 0x7D;
header[30] = 0x00;
header[31] = 0x00;
header[32] = 0x02; // 16bit monoral
header[33] = 0x00;
header[34] = 0x10; // 16bit
header[35] = 0x00;
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (byte)(waveDataSize & 0xFF);
header[41] = (byte)((waveDataSize >> 8) & 0xFF);
header[42] = (byte)((waveDataSize >> 16) & 0xFF);
header[43] = (byte)((waveDataSize >> 24) & 0xFF);
}
char** Audio::record() {
_createWavHeader(_paddedHeader, _wavDataSize);
int bitBitPerSample = i2s->GetBitPerSample();
_startMicros = micros();
if (bitBitPerSample == 16) {
for (int j = 0; j < _wavDataSize/_dividedWavDataSize; ++j) {
i2s->Read(_i2sBuffer, _i2sBufferSize/2);
for (int i = 0; i < _i2sBufferSize/8; ++i) {
_wavData[j][2*i] = _i2sBuffer[4*i + 2];
_wavData[j][2*i + 1] = _i2sBuffer[4*i + 3];
}
}
}
else if (bitBitPerSample == 32) {
for (int j = 0; j < _wavDataSize/_dividedWavDataSize; ++j) {
i2s->Read(_i2sBuffer, _i2sBufferSize);
for (int i = 0; i < _i2sBufferSize/8; ++i) {
_wavData[j][2*i] = _i2sBuffer[8*i + 2] << 4;
_wavData[j][2*i + 1] = _i2sBuffer[8*i + 3] << 4;
}
}
}
return _wavData;
}
int Audio::getSize() {
return (_wavDataSize + sizeof(_paddedHeader)) * 4 / 3; // 4/3 is from base64 encoding
}
String Audio::print(Stream* stream) {
String enc = base64::encode(_paddedHeader, sizeof(_paddedHeader));
enc.replace("\n", "");
stream->print(enc);
for (int j = 0; j < _wavDataSize / _dividedWavDataSize; ++j) {
enc = base64::encode((byte*)_wavData[j], _dividedWavDataSize);
enc.replace("\n", "");
stream->print(enc);
}
return enc;
}
unsigned long Audio::getStartMicros() {
return _startMicros;
}
bool Audio::isNoiseDetected(int threshold) {
i2s->Read(_i2sBuffer2, _i2sBufferSize/2);
if (*(int*)_i2sBuffer2 > threshold || *(int*)_i2sBuffer2 < -threshold) {
Serial.print(*(int*)_i2sBuffer2);
Serial.print(" ");
return true;
} else {
return false;
}
}

36
src/infra/Audio.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef _AUDIO_H
#define _AUDIO_H
#include <Arduino.h>
#include "infra/I2S.h"
// 16bit, monoral, 16000Hz, linear PCM
class Audio {
private:
I2S* i2s;
static const int _headerSize = 44;
static const int _i2sBufferSize = 6000;
char _i2sBuffer[_i2sBufferSize];
char _i2sBuffer2[_i2sBufferSize];
static const int _wavDataSize = 90000; // It must be multiple of _dividedWavDataSize. Recording time is about 1.9 second.
static const int _dividedWavDataSize = _i2sBufferSize/4;
char** _wavData; // It's divided. Because large continuous memory area can't be allocated in esp32.
byte _paddedHeader[_headerSize + 4] = {0}; // The size must be multiple of 3 for Base64 encoding. Additional byte size must be even because wave data is 16bit.
unsigned long _startMicros = 0;
void _createWavHeader(byte* header, int waveDataSize);
public:
Audio(MicType micType);
~Audio();
char** record();
int getSize();
String print(Stream* stream);
unsigned long getStartMicros();
bool isNoiseDetected(int threshold);
};
#endif // _AUDIO_H

92
src/infra/Eth.cpp Normal file
View File

@ -0,0 +1,92 @@
#include <SPI.h>
#include "config/config.h"
#include "infra/Eth.h"
EthernetClient* Eth::getEthClient() {
return &_client;
}
void Eth::initEthernet() {
Serial.println("| Begin Ethernet");
Ethernet.init(5); // MKR ETH Shield
SPI.begin(ETH_SCK, ETH_MISO, ETH_MOSI, ETH_SS);
Serial.println("| SCK = " + String(ETH_SCK));
Serial.println("| MISO = " + String(ETH_MISO));
Serial.println("| MOSI = " + String(ETH_MOSI));
Serial.println("| SS = " + String(ETH_SS));
byte mac[] = MYMAC;
if (Ethernet.begin(mac)) { // Dynamic IP setup
Serial.println("| DHCP OK!");
} else {
Serial.println("| Failed to configure Ethernet using DHCP");
// Check for Ethernet hardware present
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("| Ethernet shield was not found. Sorry, can't run without hardware. :(");
while (true) {
delay(1); // do nothing, no point running without Ethernet hardware
}
}
if (Ethernet.linkStatus() == LinkOFF) {
Serial.println("| Ethernet cable is not connected.");
}
IPAddress ip(MYIPADDR);
IPAddress dns(MYDNS);
IPAddress gw(MYGW);
IPAddress sn(MYIPMASK);
Ethernet.begin(mac, ip, dns, gw, sn);
Serial.println("| STATIC OK!");
}
delay(5000);
Serial.print("| Local IP : ");
Serial.println(Ethernet.localIP());
Serial.print("| Subnet Mask : ");
Serial.println(Ethernet.subnetMask());
Serial.print("| Gateway IP : ");
Serial.println(Ethernet.gatewayIP());
Serial.print("| DNS Server : ");
Serial.println(Ethernet.dnsServerIP());
Serial.println("| Ethernet Successfully Initialized");
}
void Eth::readAndPrintData(bool printWebData) {
int len = _client.available();
if (len > 0) {
byte buffer[80];
if (len > 80) len = 80;
_client.read(buffer, len);
if (printWebData) {
Serial.write(buffer, len);
}
_byteCount = _byteCount + len;
}
}
void Eth::handleDisconnect(unsigned long beginMicros, unsigned long endMicros) {
if (!_client.connected() && !_disconnected) {
endMicros = micros();
Serial.println();
Serial.println("| disconnecting.");
_client.stop();
Serial.print("| Received ");
Serial.print(_byteCount);
Serial.print(" bytes in ");
float seconds = (float)(endMicros - beginMicros) / 1000000.0;
Serial.print(seconds, 4);
float rate = (float)_byteCount / seconds / 1000.0;
Serial.print(", rate = ");
Serial.print(rate);
Serial.print(" kbytes/second");
Serial.println();
_disconnected = true;
}
}

15
src/infra/Eth.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include <Ethernet.h>
class Eth {
EthernetClient _client;
unsigned long _byteCount = 0;
bool _disconnected = false;
public:
EthernetClient* getEthClient();
void initEthernet();
void readAndPrintData(bool printWebData);
void handleDisconnect(unsigned long beginMicros, unsigned long endMicros);
};

135
src/infra/Http.cpp Normal file
View File

@ -0,0 +1,135 @@
#include "infra/Http.h"
#include "infra/Eth.h"
#include "Http.h"
Http::Http(Eth* eth) {
_client = eth->getEthClient();
}
String Http::send(String method, String endpoint, String host, int port, String payload, String contentType) {
String body = "";
if (_client->connect(host.c_str(), port)) {
_logConnected(host, port);
this->sendRequest(method, endpoint, host, contentType, payload);
String response = this->readResponse();
body = Http::extractBody(response);
Serial.println("Response:");
Serial.println(response);
} else {
Serial.println("| Connection failed");
}
return body;
}
void Http::sendRequest(String method, String endpoint, String host, String contentType, String payload) {
this->printHeader(method, endpoint, host, contentType);
this->printPayload(payload);
}
void Http::printHeader(String method, String endpoint, String host, String contentType) {
_client->print(method);
_client->print(" ");
_client->print(endpoint);
_client->println(" HTTP/1.1");
_client->print("Host: ");
_client->println(host);
if (contentType != "") {
_client->print("Content-Type: ");
_client->println(contentType);
}
_logHeader(method, endpoint, host, contentType);
}
void Http::printPayload(String payload) {
if (payload != "") {
this->printContentLength(payload.length());
_client->println(payload);
} else {
_client->println();
}
_logPayload(payload);
}
void Http::printContentLength(int contentLength) {
_client->print("Content-Length: ");
_client->println(contentLength);
_client->println();
}
String Http::readResponse() {
String response = "";
while (_client->connected()) {
if (_client->available()) {
char c = _client->read();
response += c;
}
}
return response;
}
int Http::connect(const char *host, uint16_t port) {
return _client->connect(host, port);
}
void Http::stop() {
_client->stop();
Serial.println("| Disconnected from server");
}
EthernetClient* Http::getClient() {
return _client;
}
String Http::extractBody(String httpResponse) {
String body = "";
const char* bodyStart = strstr(httpResponse.c_str(), "\r\n\r\n");
if (bodyStart != NULL) {
body = bodyStart + 4;
} else {
Serial.println("| Body not found in response.");
}
return body;
}
void Http::_logConnected(String host, int port) {
Serial.println();
Serial.print("| Connected to server ");
Serial.print(host);
Serial.print(":");
Serial.println(port);
}
void Http::_logHeader(String method, String endpoint, String host, String contentType) {
Serial.println("========================================");
Serial.print("| ");
Serial.print(method);
Serial.print(" ");
Serial.print(host);
Serial.println(endpoint);
if (contentType && contentType != "") {
Serial.print("| Content-Type: ");
Serial.println(contentType);
}
}
void Http::_logPayload(String payload) {
if (payload && payload != "") {
Serial.println("| ");
Serial.println(payload);
}
}

32
src/infra/Http.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
#include <Arduino.h>
#include "infra/Eth.h"
class Http {
private:
EthernetClient* _client;
void _logHeader(String method, String endpoint, String host, String contentType);
void _logPayload(String payload);
void _logConnected(String host, int port);
public:
Http(Eth* eth);
String send(String method, String endpoint, String host, int port, String payload, String contentType);
void sendRequest(String method, String endpoint, String host, String contentType, String payload);
void printHeader(String method, String endpoint, String host, String contentType);
void printContentLength(int contentLength);
void printPayload(String payload);
String readResponse();
int connect(const char *host, uint16_t port);
void stop();
EthernetClient* getClient();
static String extractBody(String httpResponse);
};

View File

@ -1,4 +1,4 @@
#include "I2S.h"
#include "infra/I2S.h"
#define SAMPLE_RATE (16000)
#define PIN_I2S_BCLK (GPIO_NUM_26)
#define PIN_I2S_LRC (GPIO_NUM_25)

View File

@ -1,242 +1,61 @@
/*
Web client
This sketch connects to a test website (httpbin.org)
and try to do a GET request, the output is printed
on Serial
by Renzo Mischianti <www.mischianti.org>
https://www.mischianti.org
*/
#include <SPI.h>
#include <Ethernet.h>
#include <base64.h>
#include "Audio.h"
#include <ArduinoJson.h>
#define ETH_MISO 19
#define ETH_MOSI 23
#define ETH_SCK 18
#define ETH_SS 5
#include "config/config.h"
#include "utils/Time.h"
#include "infra/Audio.h"
#include "infra/Http.h"
#include "infra/Eth.h"
#define SD_CS 5
#define SPI_MOSI 23
#define SPI_MISO 19
#define SPI_SCK 18
#define I2S_DOUT 25
#define I2S_BCLK 27
#define I2S_LRC 26
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128); // numeric IP for Google (no DNS)
//char server[] = "www.google.com"; // name address for Google (using DNS)
char server[] = "httpbin.org"; // name address for Google (using DNS)
// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
// Set the static IP address to use if the DHCP fails to assign
#define MYIPADDR 192,168,1,28
#define MYIPMASK 255,255,255,0
#define MYDNS 192,168,1,1
#define MYGW 192,168,1,1
#include "domain/Recorder.h"
//#define ALTERNATE_PINS
// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;
// Variables to measure the speed
unsigned long beginMicros, endMicros;
unsigned long byteCount = 0;
bool printWebData = true; // set to false for better speed measurement
void PrintHttpBody2(Audio* audio)
{
String enc = base64::encode(audio->paddedHeader, sizeof(audio->paddedHeader));
enc.replace("\n", ""); // delete last "\n"
client.print(enc); // HttpBody2
char** wavData = audio->wavData;
for (int j = 0; j < audio->wavDataSize / audio->dividedWavDataSize; ++j) {
enc = base64::encode((byte*)wavData[j], audio->dividedWavDataSize);
enc.replace("\n", "");// delete last "\n"
client.print(enc); // HttpBody2
}
}
Eth eth;
EthernetClient* client = eth.getEthClient();
Http http(&eth);
void Transcribe(Audio* audio) {
String HttpBody1 = "{\"audio\":{\"content\":\"";
String HttpBody3 = "\"}}\r\n\r\n";
int httpBody2Length = (audio->wavDataSize + sizeof(audio->paddedHeader)) * 4 / 3; // 4/3 is from base64 encoding
String ContentLength = String(HttpBody1.length() + httpBody2Length + HttpBody3.length());
String HttpHeader;
// if (authentication == USE_APIKEY)
HttpHeader = String("POST /save_audio HTTP/1.1\r\nHost: 192.168.1.173\r\nContent-Type: application/json\r\nContent-Length: ") + ContentLength + String("\r\n\r\n");
// else if (authentication == USE_ACCESSTOKEN)
// HttpHeader = String("POST /v1beta1/speech:syncrecognize HTTP/1.1\r\nHost: speech.googleapis.com\r\nContent-Type: application/json\r\nAuthorization: Bearer ")
// + AccessToken + String("\r\nContent-Length: ") + ContentLength + String("\r\n\r\n");
client.print(HttpHeader);
client.print(HttpBody1);
PrintHttpBody2(audio);
client.print(HttpBody3);
for (int i = 0; i < httpBody2Length; i++) {
client.print(" ");
}
String My_Answer="";
Recorder* recorder;
Time timeService = Time::getInstance();
void setInitialTime() {
String response = http.send("GET", "/time", RAT_IP, RAT_PORT, "", "");
DynamicJsonDocument jsonDoc(1024);
DeserializationError error = deserializeJson(jsonDoc, response);
JsonVariant root = jsonDoc.as<JsonVariant>();
unsigned long currentTime = root["current_timestamp"].as<unsigned long>();
timeService.setInitialMicros(micros());
timeService.setInitialTime(currentTime);
}
void setup() {
Serial.begin(115200);
delay(1000);
eth.initEthernet();
Serial.begin(115200);
delay(1000);
Serial.println("Begin Ethernet");
Serial.println("COM0 setup OK!");
// You can use Ethernet.init(pin) to configure the CS pin
//Ethernet.init(10); // Most Arduino shields
Ethernet.init(5); // MKR ETH Shield
//Ethernet.init(0); // Teensy 2.0
//Ethernet.init(20); // Teensy++ 2.0
//Ethernet.init(15); // ESP8266 with Adafruit FeatherWing Ethernet
//Ethernet.init(33); // ESP32 with Adafruit FeatherWing Ethernet
SPI.begin(ETH_SCK, ETH_MISO, ETH_MOSI, ETH_SS);
//SCLK = 18;
//MISO = 19;
// MOSI = 23;
// SS = 5;
//vspi->begin();
//pinMode(LED_BUILTIN, OUTPUT);
//Serial.println("LED_BUILTIN = " + String(LED_BUILTIN));
Serial.println("SCK = " + String(ETH_SCK));
Serial.println("MISO = " + String(ETH_MISO));
Serial.println("MOSI = " + String(ETH_MOSI));
Serial.println("SS = " + String(ETH_SS));
if (Ethernet.begin(mac)) { // Dynamic IP setup
Serial.println("DHCP OK!");
}else{
Serial.println("Failed to configure Ethernet using DHCP");
// Check for Ethernet hardware present
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :(");
while (true) {
delay(1); // do nothing, no point running without Ethernet hardware
}
}
if (Ethernet.linkStatus() == LinkOFF) {
Serial.println("Ethernet cable is not connected.");
}
IPAddress ip(MYIPADDR);
IPAddress dns(MYDNS);
IPAddress gw(MYGW);
IPAddress sn(MYIPMASK);
Ethernet.begin(mac, ip, dns, gw, sn);
Serial.println("STATIC OK!");
}
delay(5000);
Serial.print("Local IP : ");
Serial.println(Ethernet.localIP());
Serial.print("Subnet Mask : ");
Serial.println(Ethernet.subnetMask());
Serial.print("Gateway IP : ");
Serial.println(Ethernet.gatewayIP());
Serial.print("DNS Server : ");
Serial.println(Ethernet.dnsServerIP());
Serial.println("Ethernet Successfully Initialized");
// if you get a connection, report back via serial:
/*if (client.connect(server, 80)) {
Serial.println("Connected!");
// Make a HTTP request:
client.println("GET /get HTTP/1.1");
client.println("Host: httpbin.org");
client.println("Connection: close");
client.println();
} else {
// if you didn't get a connection to the server:
Serial.println("1 connection failed");
}*/
if (client.connect("192.168.1.173", 5000)) {
Serial.println("Connected!");
// Make a HTTP request:
// client.println("GET /get HTTP/1.1");
// client.println("Host: 192.168.1.173");
// client.println("Connection: close");
// client.println();
Audio* audio = new Audio(ADMP441);
Serial.println("RECORDING");
audio->Record();
Serial.println("Recoding Complited Processing");
Transcribe(audio);
delete audio;
} else {
// if you didn't get a connection to the server:
Serial.println("connection failed");
}
setInitialTime();
recorder = new Recorder(ADMP441, &http);
beginMicros = micros();
}
void loop() {
// if there are incoming bytes available
// from the server, read them and print them:
int len = client.available();
if (len > 0) {
byte buffer[80];
if (len > 80) len = 80;
client.read(buffer, len);
if (printWebData) {
Serial.write(buffer, len); // show in the serial monitor (slows some boards)
}
byteCount = byteCount + len;
}
// if the server's disconnected, stop the client:
if (!client.connected()) {
endMicros = micros();
Serial.println();
Serial.println("disconnecting.");
client.stop();
Serial.print("Received ");
Serial.print(byteCount);
Serial.print(" bytes in ");
float seconds = (float)(endMicros - beginMicros) / 1000000.0;
Serial.print(seconds, 4);
float rate = (float)byteCount / seconds / 1000.0;
Serial.print(", rate = ");
Serial.print(rate);
Serial.print(" kbytes/second");
Serial.println();
// do nothing forevermore:
while (true) {
delay(1);
}
eth.readAndPrintData(true); // set to false for better speed measurement
if (recorder->isNoiseDetected(NOISE_THRESHOLD)) {
recorder->recordAudio();
}
//recorder->recordAudio();
//delay(15000);
//eth.handleDisconnect(beginMicros, micros());
}

69
src/utils/Time.cpp Normal file
View File

@ -0,0 +1,69 @@
#include <TimeLib.h>
#include "utils/time.h"
unsigned long Time::_initialTime = 0;
unsigned long Time::_initialMicros = 0;
Time::Time() {}
Time& Time::getInstance() {
static Time instance;
return instance;
}
void Time::setInitialTime(unsigned long time) {
_initialTime = time;
}
unsigned long Time::getInitialTime() const {
return _initialTime;
}
void Time::setInitialMicros(unsigned long time) {
_initialMicros = time;
}
unsigned long Time::getInitialMicros() const {
return _initialMicros;
}
unsigned long Time::getCurrentMillis() const {
return millis();
}
unsigned long Time::getCurrentTime() const {
return _initialTime + this->getCurrentMillis() / 1000;
}
unsigned long Time::getMillisDifference(unsigned long otherTimeMillis) const {
return millis() - otherTimeMillis;
}
String Time::getFormattedTime(unsigned long time) const {
time_t currentTime = _initialTime + time;
struct tm *timeStruct = gmtime(&currentTime);
char buffer[20];
snprintf(buffer, sizeof(buffer), "%04d-%02d-%02d %02d:%02d:%02d",
timeStruct->tm_year + 1900, timeStruct->tm_mon + 1, timeStruct->tm_mday,
timeStruct->tm_hour, timeStruct->tm_min, timeStruct->tm_sec);
return String(buffer);
}
String Time::getFormattedTimeAgo(unsigned long time) const {
time_t currentTime = _initialTime + time;
struct tm *timeStruct = gmtime(&currentTime);
if (timeStruct->tm_yday > 0) {
return String(timeStruct->tm_yday) + " days ago";
} else if (timeStruct->tm_hour > 0) {
return String(timeStruct->tm_hour) + " hours ago";
} else if (timeStruct->tm_min > 0) {
return String(timeStruct->tm_min) + " minutes ago";
} else {
return String(timeStruct->tm_sec) + " seconds ago";
}
}

22
src/utils/Time.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include <Arduino.h>
class Time {
public:
static Time& getInstance();
void setInitialTime(unsigned long time);
unsigned long getInitialTime() const;
void setInitialMicros(unsigned long time);
unsigned long getInitialMicros() const;
unsigned long getCurrentMillis() const;
unsigned long getCurrentTime() const;
unsigned long getMillisDifference(unsigned long otherTimeMillis) const;
String getFormattedTime(unsigned long timeMillis) const;
String getFormattedTimeAgo(unsigned long timeMillis) const;
private:
Time();
static unsigned long _initialTime;
static unsigned long _initialMicros;
};