diff --git a/platformio.ini b/platformio.ini index 66c171c..c956651 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,18 +8,22 @@ ; Please visit documentation for the other options and examples ; http://docs.platformio.org/page/projectconf.html -[env:esp32thing] -platform = https://github.com/platformio/platform-espressif32.git#feature/stage -;platform = espressif32 -board = esp32thing +[env:heltec_wifi_lora_32] +;platform = https://github.com/platformio/platform-espressif32.git#feature/stage +platform = espressif32 +board = heltec_wifi_lora_32 board_f_cpu = 240000000L board_f_flash = 80000000L framework = arduino -build_flags = -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG +build_flags = -DLOG_LOCAL_LEVEL=ESP_LOG_INFO lib_deps = ; Basecamp https://github.com/merlinschumacher/Basecamp.git u8g2 NTPClient +; ESP8266Audio +; https://github.com/earlephilhower/ESP8266Audio.git + https://github.com/h3ndrik/ESP8266Audio.git + https://github.com/Gianbacchio/ESP8266_Spiram.git lib_ignore = ESPAsyncTCP diff --git a/src/main.cpp b/src/main.cpp index 737b72a..0b9d01b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,6 +19,7 @@ #include #include "main.h" +#include "mp3.h" U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ 15, /* data=*/ 4, /* reset=*/ 16); @@ -29,8 +30,10 @@ WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, "de.pool.ntp.org", 3600, 60000); char timeStr[20]; +MP3 mp3; + //Variables for the sensor and the battery -static const int ResetPin = 35; +static const int ResetPin = 17; static const int SensorPin = 32; static const int BatteryPin = 34; int sensorValue = 0; @@ -47,16 +50,6 @@ String statusTopic; String batteryTopic; String batteryValueTopic; -// Reset the configuration to factory defaults (all empty) -void resetToFactoryDefaults() -{ - DEBUG_PRINTLN("Resetting to factory defaults"); - Configuration config(String{"/basecamp.json"}); - config.load(); - config.reset(); - config.save(); -} - void setup() { //configuration of the battery and sensor pins pinMode(ResetPin, INPUT_PULLDOWN); @@ -66,19 +59,9 @@ void setup() { //read the status of the doorsensor as soon as possible to determine the state that triggered it sensorValue = digitalRead(SensorPin); - bool resetPressed = (digitalRead(ResetPin) == HIGH); - if (resetPressed) - { - resetToFactoryDefaults(); - } - //Initialize Basecamp iot.begin(); - if (resetPressed) { - DEBUG_PRINTLN("**** CONFIG HAS BEEN MANUALLY RESET ****"); - } - u8g2.begin(); delay(50); u8g2.clearBuffer(); // clear the internal memory @@ -121,9 +104,12 @@ void setup() { timeClient.getFormattedTime().toCharArray(timeStr, 50); u8g2.clearBuffer(); // clear the internal memory u8g2.setFont(u8g2_font_ncenB08_tr); // choose a suitable font +// u8g2.setDrawColor(2); u8g2.drawStr(30, 30, timeStr); u8g2.drawStr(30, 50, ipStr); u8g2.sendBuffer(); + + mp3.begin(); } @@ -206,12 +192,23 @@ void suspendESP(uint16_t packetId) { } } + + void loop() { timeClient.update(); timeClient.getFormattedTime().toCharArray(timeStr, 50); - u8g2.drawStr(30, 30, timeStr); + u8g2.clearBuffer(); // clear the internal memory + + u8g2.setFont(u8g2_font_inb19_mf); + u8g2.drawStr(0, 20, timeStr); + char title1[32]; char title2[32]; + strncpy(title1, titleStr, 22); title1[22] = '\0'; + strncpy(title2, titleStr+22, 32); title2[31] = '\0'; + u8g2.setFont(u8g2_font_prospero_bold_nbp_tf); // choose a suitable font + u8g2.drawUTF8(0, 45, title1); + u8g2.drawUTF8(0, 55, title2); u8g2.sendBuffer(); - delay(1000); -} + delay(500); +} diff --git a/src/main.h b/src/main.h index a412623..67cbe65 100644 --- a/src/main.h +++ b/src/main.h @@ -1,3 +1,5 @@ +#include "driver/i2s.h" + void resetToFactoryDefaults(); void setup(); void onMqttConnect(bool sessionPresent); diff --git a/src/mp3.cpp b/src/mp3.cpp new file mode 100644 index 0000000..0e07be6 --- /dev/null +++ b/src/mp3.cpp @@ -0,0 +1,137 @@ +#include "mp3.h" + +#include +#include +#include "AudioFileSourceICYStream.h" +#include "AudioFileSourceBuffer.h" +#include "AudioGeneratorMP3.h" +#include "AudioOutputI2S.h" +//#include "driver/gpio.h" +//#include "driver/periph_ctrl.h" +//#include "soc/gpio_sig_map.h" + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "driver/i2s.h" +#include "esp_system.h" +#include + +char titleStr[64]; + +MP3::MP3() {} + +/*gpio_set_direction(GPIO_NUM_13,GPIO_MODE_OUTPUT); // GPIO_MODE_DEF_OUTPUT +gpio_set_direction(GPIO_NUM_12,GPIO_MODE_OUTPUT); +gpio_set_direction(GPIO_NUM_22,GPIO_MODE_OUTPUT); +gpio_matrix_out(13, I2S0O_BCK_OUT_IDX, 0, 0); +gpio_matrix_out(12, I2S0O_WS_OUT_IDX, 0, 0); +gpio_matrix_out(22, I2S0O_DATA_OUT0_IDX, 0, 0); +//periph_module_reset( PERIPH_I2S0_MODULE ); +periph_module_disable(PERIPH_I2S0_MODULE); +delay(100); +periph_module_enable(PERIPH_I2S0_MODULE);*/ + +void MP3::cTaskWrapper(void* parameters) { + static_cast(parameters)->mp3_decoder_task(NULL); +} + +void MP3::mp3_decoder_task(void *pvParameters) { + while(true) { + if (mp3->isRunning()) { + if (millis()-lastms > 1000) { + lastms = millis(); + Serial.printf("Running for %d ms...\n", lastms); + Serial.flush(); + } + if (!mp3->loop()) mp3->stop(); + } else { + Serial.printf("MP3 done\n"); + delay(1000); + } + vTaskDelay(10 / portTICK_PERIOD_MS); + } + vTaskDelete(NULL); +} + +bool MP3::begin() { + strcpy(titleStr, "StreamTitle"); + + // First, preallocate all the memory needed for the buffering and codecs, never to be freed + preallocateBuffer = malloc(preallocateBufferSize); + preallocateCodec = malloc(preallocateCodecSize); + if (!preallocateBuffer || !preallocateCodec) { + Serial.printf_P(PSTR("FATAL ERROR: Unable to preallocate %d bytes for app\n"), preallocateBufferSize+preallocateCodecSize); + return false; +} + + Serial.println("Starting mp3 playback"); + + file = new AudioFileSourceICYStream(URL); + file->RegisterMetadataCB(MDCallback, (void*)"ICY"); + buff = new AudioFileSourceBuffer(file, preallocateBuffer, preallocateBufferSize); + buff->RegisterStatusCB(StatusCallback, (void*)"buffer"); + out = new AudioOutputI2S(I2S_NUM_0, false); + out->SetPinout(12, 13, 23); + out->SetOutputModeMono(false); + out->SetRate(44100); + out->SetBitsPerSample(16); + out->SetChannels(2); + mp3 = new AudioGeneratorMP3(preallocateCodec, preallocateCodecSize); + mp3->RegisterStatusCB(StatusCallback, (void*)"mp3"); + mp3->begin(buff, out); + out->SetGain(1.0); + +/* +I2S0.clkm_conf.clka_en = 1; // was 0 +I2S0.clkm_conf.clkm_div_a = 1; // was 63; +I2S0.clkm_conf.clkm_div_b = 0; // was clkmDecimals; +I2S0.clkm_conf.clkm_div_num = 1; // was clkmInteger; + +// periph_module_enable(PERIPH_EMAC_MODULE); +// rtc_clk_apll_enable(1,0,73,7,8); +// i2s_set_clk((i2s_port_t)portNo, 44100, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_STEREO); + +i2s_set_clk(I2S_NUM, SAMPLE_RATE, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_STEREO); +*/ + +xTaskCreate( + &cTaskWrapper, /* Task function. */ + "audioTask", /* String with name of task. */ + 2048, /* Stack size in words. */ + this, /* Parameter passed as input of the task */ + tskIDLE_PRIORITY+1, /* Priority of the task. */ + &audioTaskHandle); /* Task handle. */ +} + + +// Called when a metadata event occurs (i.e. an ID3 tag, an ICY block, etc. +void MDCallback(void *cbData, const char *type, bool isUnicode, const char *string) +{ + const char *ptr = reinterpret_cast(cbData); + (void) isUnicode; // Punt this ball for now + // Note that the type and string may be in PROGMEM, so copy them to RAM for printf + char s1[32], s2[64]; + strncpy_P(s1, type, sizeof(s1)); + s1[sizeof(s1)-1]=0; + strncpy_P(s2, string, sizeof(s2)); + s2[sizeof(s2)-1]=0; + Serial.printf("METADATA(%s) '%s' = '%s'\n", ptr, s1, s2); + Serial.flush(); + if (strcmp("StreamTitle", type)==0) { + strncpy_P(titleStr, string, sizeof(titleStr)); + s2[sizeof(s2)-1]=0; + } +} + +// Called when there's a warning or error (like a buffer underflow or decode hiccup) +void StatusCallback(void *cbData, int code, const char *string) +{ + const char *ptr = reinterpret_cast(cbData); + // Note that the string may be in PROGMEM, so copy it to RAM for printf + char s1[64]; + strncpy_P(s1, string, sizeof(s1)); + s1[sizeof(s1)-1]=0; + Serial.printf("STATUS(%s) '%d' = '%s'\n", ptr, code, s1); + Serial.flush(); +} diff --git a/src/mp3.h b/src/mp3.h new file mode 100644 index 0000000..1ec1fd5 --- /dev/null +++ b/src/mp3.h @@ -0,0 +1,39 @@ +#ifndef _MP3_H +#define _MP3_H + +#include +#include +#include "AudioFileSourceICYStream.h" +#include "AudioFileSourceBuffer.h" +#include "AudioGeneratorMP3.h" +#include "AudioOutputI2S.h" + +void MDCallback(void *cbData, const char *type, bool isUnicode, const char *string); +void StatusCallback(void *cbData, int code, const char *string); +extern char titleStr[]; + +class MP3 { + public: + MP3(); + bool begin(void); + //const char *URL="http://streaming.shoutcast.com/80sPlanet?lang=en-US"; + const char *URL="http://swr-swr1-bw.cast.addradio.de/swr/swr1/bw/mp3/64/stream.mp3"; + private: + AudioGeneratorMP3 *mp3; + AudioFileSourceICYStream *file; + AudioFileSourceBuffer *buff; + AudioOutputI2S *out; + + TaskHandle_t audioTaskHandle; + void mp3_decoder_task(void*); + static void cTaskWrapper(void*); + + static constexpr int preallocateBufferSize = 5*1024; + static constexpr int preallocateCodecSize = 29192; // MP3 codec max mem needed + void *preallocateBuffer = NULL; + void *preallocateCodec = NULL; + + int lastms = 0; +}; + +#endif /* _MP3_H */ diff --git a/src/password.txt b/src/password.txt new file mode 100644 index 0000000..67fc4e5 --- /dev/null +++ b/src/password.txt @@ -0,0 +1,2 @@ +172.16.75.18 +esp32-node QXLhCf9yXE