Asaf Matan
Published © GPL3+

Shouting Rock

Hacked artificial outdoor Shouting Rock, controlled by HomeAssistant MQTT automation.

IntermediateFull instructions provided5 hours185
Shouting Rock

Things used in this project

Hardware components

Adafruit 4W 4OHM Speaker
×1
Seeed Studio XIAO_ESP32C3
×1
DFPlayer - A Mini MP3 Player
DFRobot DFPlayer - A Mini MP3 Player
×1
Adafruit USB Type A to Type C Cable - approx 1 meter / 3 ft long
×1
15cm x 15cm x 3mm Plywood For Small Speaker Holder
×1
Artificial Rock + 10W speaker
×1

Software apps and online services

Arduino IDE
Arduino IDE
Onshape
Lightburn

Hand tools and fabrication machines

Ortur Laser Master 3

Story

Read more

Custom parts and enclosures

Speaker Holder

Adaptor to small speaker dxf file

Speaker Holder Drawing

Schematics

Shouting Rock Speaker

Shouting Rock Speaker schematics

Shouting Rock Wiring

Shouting Rock Fritzing Breadboard Wiring

Shouting Rock Schematics

Shouting Rock Fritzing Schematics

Code

Shouting Rock Arduino Sketch

C/C++
Arduino ino file
/***************************************************
DFPlayer - A Mini MP3 Player For Arduino
 <https://www.dfrobot.com/index.php?route=product/product&product_id=1121>

 ***************************************************
 This example is based on the function of library for DFPlayer by 
 [Angelo qiao](Angelo.qiao@dfrobot.com)

 GNU Lesser General Public License.
 See <http://www.gnu.org/licenses></http:> for details.
 All above must be included in any redistribution
 ****************************************************/

#include "Arduino.h"
#include <HardwareSerial.h>
#include "DFRobotDFPlayerMini.h"
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
#include "WiFi.h"

#define MQTT_SERVER      "a.b.c.d"
#define MQTT_SERVERPORT  1883
#define MQTT_USERNAME    "XXXXX"
#define MQTT_KEY         "YYYYY"

// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
Adafruit_MQTT_Client *mqtt; 

const char* wifi_ssid     = "SSID";
const char* wifi_password = "PASS";

/****************************** Feeds ***************************************/
// Setup a feed called 'gps' for subscribing to changes.
// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname>
Adafruit_MQTT_Subscribe *body;
// Create an ESP8266 WiFiClient class to connect to the MQTT server.
WiFiClient client;

//Define two Serial devices mapped to the two internal UARTs
HardwareSerial MySerial0(0);
DFRobotDFPlayerMini myDFPlayer;
char last_str[64]="";

void printDetail(uint8_t type, int value);

void setup()
{
  // Configure MySerial0 on pins TX=6 and RX=7 (-1, -1 means use the default)
  MySerial0.begin(9600, SERIAL_8N1, -1, -1);  
  Serial.begin(115200);

  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));

  WiFi.begin(wifi_ssid, wifi_password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }


  mqtt = new Adafruit_MQTT_Client (&client, MQTT_SERVER, MQTT_SERVERPORT, MQTT_USERNAME, MQTT_USERNAME, MQTT_KEY); 
  body = new Adafruit_MQTT_Subscribe(mqtt, "/speaking_stone/");
  
  // listen for events on the weather feed
  mqtt->subscribe(body);

  // connect to MQTT server
  mqtt_connect();

 
  if (!myDFPlayer.begin(MySerial0)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while(true);
  }
  Serial.println(F("DFPlayer Mini online."));


  myDFPlayer.volume(20);  //Set volume value. From 0 to 30
}

void loop()
{
  Adafruit_MQTT_Subscribe *subscription;
  
  
  // ping adafruit io a few times to make sure we remain connected
  // Serial.println("Ping");
  if(! mqtt->ping(3)) 
  {
     // reconnect to adafruit io
     Serial.println("Reconnect");
     if(! mqtt->connected())
     {
       Serial.println("Connect");
       mqtt_connect();
     }
  }
  
  if (subscription = mqtt->readSubscription(1000)) 
  {
      Serial.print(F("GotSomething\n"));
      // we only care about the 
      if (subscription == body) 
      {
        char * orig_str  = (char*)body->lastread;
        myDFPlayer.play(1);
        if (myDFPlayer.available()) 
        {
           printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states.
        }

        Serial.println(orig_str);
      }  
  }
}


// connect to adafruit io via MQTT
void mqtt_connect() {

  int8_t ret;

  while ((ret = mqtt->connect()) != 0) {

    switch (ret) {
      case 1: Serial.println(F("Wrong protocol")); break;
      case 2: Serial.println(F("ID rejected")); break;
      case 3: Serial.println(F("Server unavail")); break;
      case 4: Serial.println(F("Bad user/pass")); break;
      case 5: Serial.println(F("Not authed")); break;
      case 6: Serial.println(F("Failed to subscribe")); break;
      default: Serial.println(F("Connection failed")); break;
    }

    if(ret >= 0)
      mqtt->disconnect();

    Serial.println(F("Retrying connection..."));
    delay(5000);

  }

  Serial.println(F("mqtt Connected!"));
}


void printDetail(uint8_t type, int value){
  switch (type) {
    case TimeOut:
      Serial.println(F("Time Out!"));
      break;
    case WrongStack:
      Serial.println(F("Stack Wrong!"));
      break;
    case DFPlayerCardInserted:
      Serial.println(F("Card Inserted!"));
      break;
    case DFPlayerCardRemoved:
      Serial.println(F("Card Removed!"));
      break;
    case DFPlayerCardOnline:
      Serial.println(F("Card Online!"));
      break;
    case DFPlayerPlayFinished:
      Serial.print(F("Number:"));
      Serial.print(value);
      Serial.println(F(" Play Finished!"));
      break;
    case DFPlayerError:
      Serial.print(F("DFPlayerError:"));
      switch (value) {
        case Busy:
          Serial.println(F("Card not found"));
          break;
        case Sleeping:
          Serial.println(F("Sleeping"));
          break;
        case SerialWrongStack:
          Serial.println(F("Get Wrong Stack"));
          break;
        case CheckSumNotMatch:
          Serial.println(F("Check Sum Not Match"));
          break;
        case FileIndexOut:
          Serial.println(F("File Index Out of Bound"));
          break;
        case FileMismatch:
          Serial.println(F("Cannot Find File"));
          break;
        case Advertise:
          Serial.println(F("In Advertise"));
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }
}

Home Assistant Automation

YAML
Home Assistant Automation YAML file
alias: speaking_stone
description: ""
trigger:
  - type: motion
    platform: device
    device_id: 9991aecc03c14973b05c8e881b0e574f
    entity_id: binary_sensor.front_door_motion
    domain: binary_sensor
    for:
      hours: 0
      minutes: 0
      seconds: 0
condition:
  - condition: state
    entity_id: binary_sensor.jewish_calendar_issur_melacha_in_effect
    state: "off"
  - condition: time
    before: "20:00:00"
    after: "08:00:00"
action:
  - service: mqtt.publish
    data:
      topic: /speaking_stone/
      qos: "0"
      payload: play
      retain: false
mode: single

Credits

Asaf Matan

Asaf Matan

6 projects • 3 followers
⚡Hightech geek ⭐ Fusing hardware, software and Judaica or... Maker! 💫 Home automation expert

Comments