/* IOM_UNO_ShedV1 Effects required All effects must use millis() because decoder/button instructions can be received variable glow for ash pit Coal fill shovel sound Workshop effects Pit lights...neopixels Shed lights...neopixels Arc welders plus sync flashing...LEDS Random workshop sounds Sound on Card 01 grinder 37 seconds 02 big arc welder 7 seconds 03 small arc weld 8 seconds 04 drill/machine 11 secnods 05 file 5 seconds 06 grinder 4 seconds 07 light hammer 4 seconds 08 hacksaw 4 secs 09 big machine 28 secs...could repeat 10 another big machine 11 secs to end 11 tool box 3 secs 12 seagulls boats 8m 48 secs 13 waterfall 3m 19 could repeat 14 single whistle 15 short whistle.horn 16 guard whistle 17 birds/country side 1m 50 18 short whistle 19 double short whistle 20 hydraulics 2m 33 21 ship/boat big horn 22 coaling 21 sec repeatable pins 2 required for DCC decoder script 3 software serial...MP3 player 4 software serial...MP3 player 5 Neopixels 6 arc welder */ //Serial UART WAV/MP3 player #include "SoftwareSerial.h" #define ARDUINO_RX 4//should connect to TX of the Serial MP3 Player module #define ARDUINO_TX 3//connect to RX of the module SoftwareSerial myMP3(ARDUINO_RX, ARDUINO_TX); byte sendBuffer[6]; //buffer that will be used to store commands before sending //Neopixels #include "Adafruit_NeoPixel.h" // Which pin on the Arduino is connected to the NeoPixels? #define neoPin 5 // How many NeoPixels are attached to the Arduino? #define NUMPIXELS 16 // 16 on my test strip Adafruit_NeoPixel pixels(NUMPIXELS, neoPin, NEO_GRB + NEO_KHZ800); //Arc Welder variables const int arcPin = 6;//arc welder Digital Pin int arcWeldState; unsigned long arcWeldSoundTimer; unsigned long arkEndFlashTimer; unsigned long arkFlashTimer; int arcSoundCounter; //Ash pit variables unsigned long ashSoundTimer; int ashSoundCounter; //4 neopixels for ash effects...each to operate independently unsigned long ashNeoPixelTimer[4]; int ashNeoPixelCounter[4] = {251, 251, 251, 251}; //values required for them to start //Other sound variables unsigned long soundChange; unsigned long soundEnd; int soundVolume; int soundStart; int playThisSound; void setup() { Serial.begin(9600); Serial.println("IOM_UNO_ShedV1..."); //serial mp3 player myMP3.begin(9600); delay(500);//allow everything to settle down //first we need to select the TF Card selectTFCard(); delay(100); playSound(19);//double whistle test on start up delay(3000); //neopixels pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) pixels.clear(); // Set all pixel colors to 'off' pixels.show(); for (int q = 0; q < 16; q++) { //pixel test pixels.setPixelColor(q, pixels.Color(0, 0 , 150)); //green pixels.show(); delay(100); } pixels.clear(); // Set all pixel colors to 'off' pixels.show(); //arc welder pinMode(arcPin, OUTPUT); digitalWrite(arcPin, HIGH); delay(500); digitalWrite(arcPin, LOW); } void loop() { //ashpit();//triggered sound backgroundSound(); } ////////////////////////SerialWav.ino////////////////////////////////////// //Serial UART commands //Manual says the code for this is 7E 03 35 01 EF so load into buffer array void selectTFCard(){ sendBuffer[0] = 0x7E; sendBuffer[1] = 0x03; sendBuffer[2] = 0x35; sendBuffer[3] = 0x01; sendBuffer[4] = 0xEF; sendUARTCommand(); } void playSound(byte songNumber){ sendBuffer[0] = 0x7E; sendBuffer[1] = 0x04; sendBuffer[2] = 0x41; sendBuffer[3] = 0x00; sendBuffer[4] = songNumber; sendBuffer[5] = 0xEF; sendUARTCommand(); } //play a sound at a set volume, only seems to apply to root directory files void playSoundAtVolume(byte volume,byte songNumber){ sendBuffer[0] = 0x7E; sendBuffer[1] = 0x04; sendBuffer[2] = 0x31; sendBuffer[3] = volume; sendBuffer[4] = songNumber; sendBuffer[5] = 0xEF; sendUARTCommand(); } //loop sound 7E 04 33 00 01 EF void repeatSound(byte songNumber){ sendBuffer[0] = 0x7E; sendBuffer[1] = 0x04; sendBuffer[2] = 0x33; sendBuffer[3] = 0x00; sendBuffer[4] = songNumber; sendBuffer[5] = 0xEF; sendUARTCommand(); } //set the playback volume 7E 03 31 0F EF = set volume to 0x0F = 15 void setplayVolume(byte volume){ sendBuffer[0] = 0x7E; sendBuffer[1] = 0x03; sendBuffer[2] = 0x31; sendBuffer[3] = volume; sendBuffer[4] = 0xEF; sendUARTCommand(); } //stop the current track playing void stopSound(){ sendBuffer[0] = 0x7E; sendBuffer[1] = 0x02; sendBuffer[2] = 0x0E; sendBuffer[3] = 0xEF; sendUARTCommand(); } void sendUARTCommand(){ int q; for(q=0;q < sendBuffer[1] + 2;q++){ myMP3.write(sendBuffer[q]); } Serial.println("Commands Sent"); for(q=0;q < sendBuffer[1] + 2;q++){ Serial.println(sendBuffer[q],HEX); } delay(25);//stops odd commands being missed } //////////////////////////////sounds.ino////////////////////////////////// //sound functions void backgroundSound(){ if(soundStart < 1 || millis() < soundEnd){ switch(playThisSound){ case 1 ... 2: arcWeld(); break; case 3: grinderSound(); break; case 4 ... 5: drillSound(); break; case 6 ... 9: fileSound(); break; case 10 ... 12: hammerSound(); break; case 13: bigMachineSound(); break; case 14 ... 16: toolboxSound(); break; case 17://triggered sound ashpit(); break; default: break; } } if(millis() > soundEnd){ playThisSound = random(30);//increase this value to get more time without sounds //playThisSound = random(14,18);//increase this value to get more time without sounds Serial.print("playThisSound: "); Serial.println(playThisSound); soundStart = 0; digitalWrite(arcPin, LOW); if(playThisSound > 17){//don't want it to be able to opick track 17 soundEnd = millis() + random(2000,20000);//take a 10 second break from playing sounds } } } void toolboxSound(){ if(soundStart < 1){ soundStart = 1; soundVolume = 15; playSoundAtVolume(soundVolume, 11); //drill 4 seconds soundChange = millis() + 4000; soundEnd = millis() + 4000; } } void bigMachineSound(){ if(soundStart < 1){ soundStart = 1; soundVolume = 15; playSoundAtVolume(soundVolume, 9); // 28 seconds soundChange = millis() + 24000; soundEnd = millis() + 28000; } if(millis() > soundChange && millis() < soundEnd){ soundChange = millis() + 500; soundVolume -=1; if(soundVolume < 0){ soundVolume = 0; } setplayVolume(soundVolume); } } void hammerSound(){ if(soundStart < 1){ soundStart = 1; soundVolume = 15; playSoundAtVolume(soundVolume, 7); //drill 4 seconds soundChange = millis() + 5000; soundEnd = millis() + 5000; } } void fileSound(){ if(soundStart < 1){ soundStart = 1; soundVolume = 15; playSoundAtVolume(soundVolume, 5); //drill 5 seconds soundChange = millis() + 5000; soundEnd = millis() + 5000; } } void drillSound(){ if(soundStart < 1){ soundStart = 1; soundVolume = 15; playSoundAtVolume(soundVolume, 4); //drill 11 seconds soundChange = millis() + 11000; soundEnd = millis() + 11000; } } void grinderSound(){ if(soundStart < 1){ soundStart = 1; soundVolume = 15; playSoundAtVolume(soundVolume, 1); //grinder 37 seconds soundChange = millis() + 32000; soundEnd = millis() + 37000; } if(millis() > soundChange && millis() < soundEnd){ soundChange = millis() + 500; soundVolume -=1; if(soundVolume < 0){ soundVolume = 0; } setplayVolume(soundVolume); } } void arcWeld() { if(soundStart < 1){ soundStart = 1; soundEnd = millis() + 40000; arcSoundCounter = 0; } if (millis() > arcWeldSoundTimer && arcSoundCounter < 5) { playSoundAtVolume(15, 2); arkEndFlashTimer = millis() + 7000;//resets the flash timer arcSoundCounter++; arcWeldSoundTimer = millis() + random(7000, 10000); } if (millis() < arkEndFlashTimer) { if (millis() > arkFlashTimer) { arkFlashTimer = millis() + random(10, 40); //next change state if (arcWeldState > 0) { arcWeldState = 0; digitalWrite(arcPin, LOW); } else { arcWeldState = 1; digitalWrite(arcPin, HIGH); } } } else { digitalWrite(arcPin, LOW); } } //handles 4 neopixels for falling ash plus coal filling sound void ashpit() { int q; if (millis() > ashSoundTimer && ashSoundCounter < 20) { soundStart = 1; playSoundAtVolume(15, 22); ashSoundCounter++; ashSoundTimer = millis() + random(21000, 30000); soundEnd = ashSoundTimer + 5000; } if(ashSoundCounter == 20 && soundStart > 0){ soundStart = 0; soundEnd = millis() + 5000; pixels.clear(); pixels.show(); } //cycle through the neopixels if (ashNeoPixelCounter[0] == 0 && ashSoundCounter < 10) { for (q = 0; q < 4; q++) { ashNeoPixelCounter[q] = 251; ashNeoPixelTimer[q] = millis() + random(1000, 1200); } } if (ashSoundCounter > 15) { //All ash should be cold by now for (q = 0; q < 4; q++) { pixels.setPixelColor(q, pixels.Color(0, 0, 0)); pixels.show(); } } for (q = 0; q < 4; q++) { if (millis() > ashNeoPixelTimer[q] && ashNeoPixelCounter[q] > -1) { switch (ashNeoPixelCounter[q]) { case 0 ... 24: pixels.setPixelColor(q, pixels.Color(ashNeoPixelCounter[q], 0, 0)); //red break; case 25 ... 49: pixels.setPixelColor(q, pixels.Color(ashNeoPixelCounter[q], 1, 0)); //red break; case 50 ... 74: pixels.setPixelColor(q, pixels.Color(ashNeoPixelCounter[q], 2, 0)); //red break; case 75 ... 99: pixels.setPixelColor(q, pixels.Color(ashNeoPixelCounter[q], 3, 0)); //red break; case 100 ... 124: pixels.setPixelColor(q, pixels.Color(ashNeoPixelCounter[q], 4, 0)); //red break; case 125 ... 149: pixels.setPixelColor(q, pixels.Color(ashNeoPixelCounter[q], 5, 0)); //red break; case 150 ... 174: pixels.setPixelColor(q, pixels.Color(ashNeoPixelCounter[q], 6, 0)); //red break; case 175 ... 199: pixels.setPixelColor(q, pixels.Color(ashNeoPixelCounter[q], 7, 0)); //red break; case 200 ... 224: pixels.setPixelColor(q, pixels.Color(ashNeoPixelCounter[q], 8, 0)); //red break; case 225 ... 250: pixels.setPixelColor(q, pixels.Color(ashNeoPixelCounter[q], 9, 0)); //red break; default: pixels.setPixelColor(q, pixels.Color(0, 0, 0)); //red break; } if (random(0, 10) > 7) { pixels.setPixelColor(q, pixels.Color(0, 0, 0)); //red } pixels.show(); ashNeoPixelCounter[q]--; ashNeoPixelTimer[q] = millis() + random(5, 50); } } }