// // wirelessly connected cloud (based on a LPWAN, called ESP-NOW) // // // () performance, hosted by Vegetable Wife // @ 2025 Nov 10 ~ 11 // // // 2025 nov // // esp32 based radio streamer // //======================== #define MY_GROUP_ID (80000) #define MY_ID (MY_GROUP_ID + 1) #define MY_SIGN ("RADIOOOO") //======================== //======================== #define WIFI_SSID "Mullae 2F" #define WIFI_PASSWD "sfacsfac1!" // #define WIFI_CHANNEL 1 //======================= //arduino #include //message types #include "message.h" //espnow #include #include //task #include Scheduler runner; //screen #include #include #define MAKEPYTHON_ESP32_SDA 4 #define MAKEPYTHON_ESP32_SCL 5 #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); //-*-*-*-*-*-*-*-*-*-*-*-*- // my tasks // audio & sd & filesystem #include "Audio.h" #include "SPI.h" #include "SD.h" #include "FS.h" //sdcard #define SD_CS 22 #define SPI_MOSI 23 #define SPI_MISO 19 #define SPI_SCK 18 //digital i/o used (for) makerfabs audio v2.0 #define I2S_DOUT 27 #define I2S_BCLK 26 #define I2S_LRC 25 Audio audio; //screen task String screen_myid = "my_id:" + String(MY_ID); String screen_cmd = ""; String screen_radiolink = "_no station_"; // extern Task screen_cmd_notify_task; bool cmd_notify = false; bool cmd_notifying = false; void screen_cmd_notify() { if (screen_cmd_notify_task.isFirstIteration()) { cmd_notify = true; cmd_notifying=true; } else if (screen_cmd_notify_task.isLastIteration()) { cmd_notify = false; cmd_notifying=false; } else cmd_notify = !cmd_notify; } Task screen_cmd_notify_task(500, 10, &screen_cmd_notify, &runner, false); // extern Task screen_task; void screen() { //clear screen + a int line_step = 12; int line = 0; display.clearDisplay(); display.setTextColor(SSD1306_WHITE); display.setTextSize(1); //line0 - myid display.setCursor(0, line); display.println(screen_myid); line += line_step; //line1 - mode line (playing / stopped) + notify mark display.setCursor(0, line); if (audio.isRunning()) display.println("= playing ==="); else display.println("* stopped !:."); if (cmd_notify) { display.setCursor(120, line); display.println("*"); } line += line_step; //line2 - info display.setCursor(0, line); if (cmd_notifying) { display.println(screen_cmd.c_str()); //rf. last msg. } else { display.println(screen_radiolink.c_str()); //radiolink } line += line_step; // display.display(); // } Task screen_task(200, TASK_FOREVER, &screen, &runner, false); //radio # int radio_now = -1; //0~999 std::vector radio_list = { "http://radio.dianaband.in:8000/stream1", "http://radio.dianaband.in:8000/stream2", "http://radio.dianaband.in:8000/stream3", "http://radio.dianaband.in:8000/stream4", "http://radio.dianaband.in:8000/stream5", "http://radio.dianaband.in:8000/stream6" }; //on 'start' void radio_player_start() { //TEST Serial.println("tune-in: " + radio_list[radio_now]); screen_radiolink = radio_list[radio_now]; //start the radio streaming! audio.connecttohost(radio_list[radio_now].c_str()); delay(10); } Task radio_player_start_task(0, TASK_ONCE, &radio_player_start, &runner, false); //on 'stop' void radio_player_stop() { //stop the player. audio.stopSong(); } Task radio_player_stop_task(0, TASK_ONCE, &radio_player_stop, &runner, false); //*-*-*-*-*-*-*-*-*-*-*-*-* // extern Task hello_task; static int hello_delay = 0; void hello() { // byte mac[6]; WiFi.macAddress(mac); uint32_t mac32 = (((((mac[2] << 8) + mac[3]) << 8) + mac[4]) << 8) + mac[5]; // Hello hello(String(MY_SIGN), MY_ID, mac32); // the most basic 'hello' // and you can append some floats static int count = 0; count++; hello.h1 = (count % 1000); hello.h2 = radio_now; // hello.h3 = 0; // hello.h4 = 0; // uint8_t frm_size = sizeof(Hello) + 2; uint8_t frm[frm_size]; frm[0] = '{'; memcpy(frm + 1, (uint8_t *) &hello, sizeof(Hello)); frm[frm_size - 1] = '}'; // esp_now_send(NULL, frm, frm_size); // to all peers in the list. // // MONITORING_SERIAL.write(frm, frm_size); // MONITORING_SERIAL.println(" ==(esp_now_send/0)==> "); // if (hello_delay > 0) { if (hello_delay < 100) hello_delay = 100; hello_task.restartDelayed(hello_delay); } } Task hello_task(0, TASK_ONCE, &hello, &runner, false); //task #0 : blink led #define LED_PERIOD (11111) #define LED_ONTIME (1) #define LED_GAPTIME (222) #define LED_PIN 2 extern Task blink_task; void blink() { // static int count = 0; count++; // switch (count % 4) { case 0: digitalWrite(LED_PIN, LOW); // first ON blink_task.delay(LED_ONTIME); break; case 1: digitalWrite(LED_PIN, HIGH); // first OFF blink_task.delay(LED_GAPTIME); break; case 2: digitalWrite(LED_PIN, LOW); // second ON blink_task.delay(LED_ONTIME); break; case 3: digitalWrite(LED_PIN, HIGH); // second OFF blink_task.delay(LED_PERIOD - 2* LED_ONTIME - LED_GAPTIME); break; } } Task blink_task(0, TASK_FOREVER, &blink, &runner, true); // -> ENABLED, at start-up. // on 'Note' void onNoteHandler(Note & n) { //is it for me? if (n.id == MY_GROUP_ID || n.id == MY_ID) { // screen_cmd = n.to_string(); screen_cmd_notify_task.restart(); // if (n.velocity != 0 || n.onoff == 2) { audio.setVolume(n.velocity * 21 / 127.0); // 0...127 ==> 0...21 } // if (n.onoff == 1) { // filter out re-triggering same note while it is playing. if (!audio.isRunning() || radio_now != n.pitch) { radio_now = n.pitch; radio_player_start_task.restartDelayed(10); } } else if (n.onoff == 0) { radio_now = n.pitch; radio_player_stop_task.restartDelayed(10); } // } } // on 'receive' void onDataReceive(const esp_now_recv_info_t * esp_now_info, const uint8_t *incomingData, int len) { // // Serial.write(incomingData, len); // open => identify => use. if (incomingData[0] == '{' && incomingData[len - 1] == '}' && len == (sizeof(Hello) + 2)) { Hello hello(""); memcpy((uint8_t *) &hello, incomingData + 1, sizeof(Hello)); // Serial.println(hello.to_string()); } // open => identify => use. if (incomingData[0] == '[' && incomingData[len - 1] == ']' && len == (sizeof(Note) + 2)) { Note note; memcpy((uint8_t *) ¬e, incomingData + 1, sizeof(Note)); onNoteHandler(note); // Serial.println(note.to_string()); } } // on 'sent' void onDataSent(const uint8_t *mac_addr, esp_now_send_status_t sendStatus) { char buff[256] = ""; sprintf(buff, "Delivery failed! -> %02X:%02X:%02X:%02X:%02X:%02X", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); if (sendStatus != 0) Serial.println(buff); } // void setup() { //led pinMode(LED_PIN, OUTPUT); //serial Serial.begin(115200); delay(100); //screen Wire.begin(MAKEPYTHON_ESP32_SDA, MAKEPYTHON_ESP32_SCL); // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 Serial.println(F("SSD1306 allocation failed")); for (;;) ; // Don't proceed, loop forever } display.clearDisplay(); //audio(I2S) // audio.setInBufferSize(2048); audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); audio.setVolume(21); // 0...21 // audio.setVolume(14.88); // 90 * 21 / 127 == 14.88 // audio.connecttoFS(SD, filename.c_str()); //info Serial.println(); Serial.println(); Serial.println("\"hi, i m your postman.\""); Serial.println("-"); Serial.println("- my id: " + String(MY_ID) + ", gid: " + String(MY_GROUP_ID) + ", call me ==> \"" + String(MY_SIGN) + "\""); Serial.println("- mac address: " + WiFi.macAddress() + ", channel: " + String(WIFI_CHANNEL)); Serial.println("-"); //wifi - disable AP WiFiMode_t node_type = WIFI_STA; // WiFiMode_t node_type = WIFI_AP_STA; WiFi.setTxPower(WIFI_POWER_MINUS_1dBm); // Set WiFi RF power output to lowest level WiFi.mode(node_type); //wifi - establish connection int line_step = 12; int line = 0; display.clearDisplay(); display.setTextColor(SSD1306_WHITE); display.setTextSize(1); display.setCursor(0, line); display.println("wifi connecting.."); line += line_step; display.setCursor(0, line); display.println(WIFI_SSID); line += line_step; display.setCursor(0, line); display.println(WIFI_PASSWD); display.display(); delay(1000); WiFi.begin(WIFI_SSID, WIFI_PASSWD); while (!WiFi.isConnected()) { delay(10); } display.clearDisplay(); display.setCursor(0, 0); display.println("wifi connected!"); display.display(); delay(1000); // screen_task.restart(); //esp-now if (esp_now_init() != 0) { Serial.println("Error initializing ESP-NOW"); return; } esp_now_register_send_cb(onDataSent); esp_now_register_recv_cb(onDataReceive); // Serial.println("- ! (esp_now_add_peer) ==> add a 'broadcast peer' (FF:FF:FF:FF:FF:FF)."); uint8_t broadcastmac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; esp_now_peer_info_t peerInfo = {}; memcpy(peerInfo.peer_addr, broadcastmac, 6); peerInfo.channel = 0; peerInfo.encrypt = false; esp_now_add_peer(&peerInfo); Serial.println("-"); Serial.println("\".-.-.-. :)\""); Serial.println(); } void loop() { // audio.loop(); // runner.execute(); // }