Hardware components | ||||||
![]()  | 
  | × | 1 | |||
![]()  | 
  | × | 1 | |||
![]()  | 
  | × | 1 | |||
![]()  | 
  | × | 1 | |||
![]()  | 
  | × | 1 | |||
![]()  | 
  | × | 1 | |||
![]()  | 
  | × | 1 | |||
![]()  | 
  | × | 1 | |||
Software apps and online services | ||||||
  | ||||||
Hand tools and fabrication machines | ||||||
![]()  | 
  | |||||
![]()  | 
  | |||||
![]()  | 
  | |||||
![]()  | 
  | |||||
My journey through coding started with a love of computers, a fascination with typing, and the sound of the keys, a love for technology and the world around me. I've also always loved rubber duckies, I've collected them throughout the years, and their connection to coding, and programming drew me in the software engineering even more, so I bring to you Papa duckie, the duckie to rule all the the rubber duckies, and have the power to control the classroom and even brighten up peoples day with his music and song!
Papa duckie is a remote controller duckie that is meant to be a programmer's best friend, the ruler of all duckies, able to play music to cheer you up and help you through the hardest coding challenges, with the ability to turn on and off any gadgets that help make your work environment more friendly.
The biggest challenges for me were designing the duckie himself in SolidWorks, and wiring the duckie, not only because of his shape but using multiple breadboxes is different from using just one. My third challenge was utilizing items we haven't covered in class. I feel like this project was super valuable, it taught me a lot about persevering through challenges, especially with a deadline in mind, but also, problem solving and pushing myself to find the answer, the skills I have gained making Papa duckie are both symbolic to me and life changing I am super proud of what I was able to accomplish and look forward to making more!
I'm back with more knowledge and better ways of handling some things so expect to see Papa duckie's code refactored in the near future! Always striving to better myself and learn more.
Firstly, I gave him a make over!
From this:
To this!
UPDATED fritzing

/*
 * Project PapaDuck refactored
 * Author: Jamie Dowden-Duarte
 * Date: 10/24/25
 * For comprehensive documentation and examples, please visit:
 * https://docs.particle.io/firmware/best-practices/firmware-template/
 */
#include "Particle.h"
#include "IoTClassroom_CNM.h"
#include "math.h"
#include "neopixel.h"
#include "Adafruit_ssd1306.h"
#include "Adafruit_BME280.h"
#include "Encoder.h"
#include "DFRobotDFPlayerMini.h"
SYSTEM_MODE(MANUAL);
const int PIXELCOUNT = 12, OLED_RESET = -1, HEXADDRESS = 0X76;
const int SEALEVELPRESSURE_HPA = 1013.25, DEG = 0XB0, PERCENT = 0X25;
const int PINA = D4, PINB = D5, PBUTTON = D3, ESWTCH = D15, p2Button = D13;
const int HUES[] = {1, 2, 3, 4, 5, 6};
const int WEMOS[] = {0, 1, 2, 3, 4, 5};
const int SATURATION = 255;
const int MAXENCPOS = 96, MAXBRITE = 255, MAXVOLUME = 30;
bool wemowrite, buttonState, switchState, player, status, playSong;
unsigned long lastUpdateTime = 0, currentTime;
float temp = 0.0, volume;
int color = rainbow[0], hue = HueRainbow[color % 7];
int i, timer, wemo, huey, brightness, position, lastpos;
bool onOff, playPause;
#define WIDTH 59
#define HEIGHT 64
const unsigned char duckie[] PROGMEM = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x07, 0xFC, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x0C, 0x07, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x30, 0x01, 0x80, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x60, 0x00, 0xC0, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00,
    0x00, 0x01, 0x80, 0x00, 0x30, 0x00, 0x00, 0x00,
    0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
    0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
    0x00, 0x01, 0x06, 0x00, 0x10, 0x00, 0x00, 0x00,
    0x00, 0x01, 0x0F, 0x00, 0x10, 0x00, 0x00, 0x00,
    0x00, 0x03, 0xC7, 0x00, 0x10, 0x00, 0x00, 0x00,
    0x00, 0x06, 0x60, 0x00, 0x10, 0x00, 0x00, 0x00,
    0x00, 0x0C, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00,
    0x00, 0x08, 0x10, 0x00, 0x20, 0x00, 0x00, 0x00,
    0x00, 0x06, 0x60, 0x00, 0x61, 0xC0, 0x00, 0x00,
    0x00, 0x03, 0xE0, 0x00, 0xC3, 0x60, 0x00, 0x00,
    0x00, 0x00, 0x30, 0x01, 0xDE, 0x30, 0x00, 0x00,
    0x00, 0x00, 0x60, 0x03, 0xF0, 0x18, 0x00, 0x00,
    0x00, 0x00, 0xC0, 0x00, 0x00, 0x08, 0x00, 0x00,
    0x00, 0x00, 0x80, 0x00, 0x00, 0x0C, 0x00, 0x00,
    0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
    0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
    0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
    0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
    0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
    0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
    0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
    0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
    0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,
    0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
    0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
    0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
    0x00, 0x03, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
    0x00, 0x01, 0x80, 0x00, 0x00, 0x30, 0x00, 0x00,
    0x00, 0x00, 0xE0, 0x00, 0x00, 0x60, 0x00, 0x00,
    0x00, 0x00, 0x30, 0x00, 0x03, 0x80, 0x00, 0x00,
    0x00, 0x00, 0x0E, 0x00, 0x1E, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x03, 0xFF, 0xF0, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0,
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0};
Adafruit_NeoPixel pixel(PIXELCOUNT, SPI1, WS2812B);
Adafruit_SSD1306 display(OLED_RESET);
Adafruit_BME280 bme; // I2C
Button pushButton(PBUTTON);
Button pushButton2(p2Button);
Button encoderSwitch(ESWTCH);
Encoder encoder(PINA, PINB);
DFRobotDFPlayerMini duckiePlayer;
void setup()
{
  Serial.begin(9600);
  waitFor(Serial.isConnected, 1000);
  Serial1.begin(9600);
  WiFi.on();
  WiFi.clearCredentials();
  WiFi.setCredentials("IoTNetwork");
  WiFi.connect();
  while (WiFi.connecting())
  {
    Serial.printf(".");
  }
  Serial.printf("\n\n");
  pixel.begin();
  pixel.setBrightness(10);
  pixel.show();
  status = bme.begin(HEXADDRESS);
  if (!status)
  {
    Serial.printf("BME at address %i failed to start\n", HEXADDRESS);
  }
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.drawBitmap(0, 0, duckie, 128, 64, WHITE);
  if (!duckiePlayer.begin(Serial1))
  { // Use softwareSerial to communicate with mp3.
    Serial.printf("Unable to begin:\n");
    Serial.printf("1.Please recheck the connection!\n");
    Serial.printf("2.Please insert the SD card!\n");
    while (true)
      ;
  }
  Serial.printf("DFPlayer Mini online.\n");
  Wire.begin();
  Serial.println("Ready to go");
}
void loop()
{
  currentTime = millis();
  // Update temperature every minute
  // if (currentTime >= 60000){
  lastUpdateTime = currentTime;
  temp = bme.readTemperature();
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(10, 0);
  display.print("Temp: ");
  display.print(temp);
  display.print(DEG);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(12, 28);
  display.println("Papa Duck");
  display.display();
  // }
  // Cycle through colors on NeoPixels
  for (int i = 0; i < PIXELCOUNT; i++)
  {
    color = i % 7;
    pixel.setPixelColor(i, rainbow[color]);
    pixel.show();
    color++;
  }
  if (pushButton.isClicked())
  {
    onOff = !onOff;
    setHue(HUES[hue], onOff, HueRainbow[color % 7], brightness, SATURATION);
    duckiePlayer.volume(volume);
    if (onOff)
    {
      duckiePlayer.play();
    }
    else
    {
      duckiePlayer.stop();
    }
  }
  position = encoder.read(); // 0-96 encoder positions, 0-255 brightness
  if (encoder.read() > 95)
  {
    encoder.write(position = 95);
  }
  if (encoder.read() < 0)
  {
    encoder.write(position = 0);
  }
  if (position != lastpos)
  {
    // Serial.printf("Encoder position %i\n", position);
    brightness = position * (MAXBRITE / MAXENCPOS);
    volume = position * (MAXVOLUME / MAXENCPOS);
    // Serial.printf("Turning on Hue# %i\n", hue);
    setHue(HUES[hue], onOff, HueRainbow[color % 7], brightness, SATURATION);
    duckiePlayer.volume(volume);
    lastpos = position;
  }
  if (pushButton.isClicked())
  {
    color++;
    for (hue = 1; hue <= 6; hue++)
    {
      setHue(HUES[hue], onOff, HueRainbow[color % 7], brightness, SATURATION);
    }
  }
  if (pushButton2.isClicked())
  {
    onOff = !onOff;
    Serial.printf("onOff %i\n", onOff);
    for (wemo = 0; wemo <= 6; wemo++)
    {
      if (onOff)
      {
        Serial.printf("Turning on Wemo# %i\n", wemo);
        wemoWrite(WEMOS[wemo], HIGH);
      }
      else
      {
        Serial.printf("Turning off Wemo# %i\n", wemo);
        wemoWrite(WEMOS[wemo], LOW);
      }
    }
  }
}
/*
 * Project PapaDuck
 * Author: Jamie Gavina
 * Date: 10-29-2024
 * For comprehensive documentation and examples, please visit:
 * https://docs.particle.io/firmware/best-practices/firmware-template/
 */
// demensions of box 4 long X2.5 tall inch,3 inch wide hole for plug
#include "Particle.h"
#include "Colors.h"
#include "math.h"
#include "neopixel.h"
#include "Adafruit_ssd1306.h"
#include "Adafruit_BME280.h"
#include "Wire.h"
#include "Button.h"
#include "wemo.h"
#include "Encoder.h"
#include "hue.h"
#include "DFRobotDFPlayerMini.h"
SYSTEM_MODE(MANUAL);
const int PIXELCOUNT = 12;
const int OLED_RESET = -1;
const int HEXADDRESS = 0X76;
const int SEALEVELPRESSURE_HPA = 1013.25;
const int DEG = 0XB0;
const int PERCENT = 0X25;
int color = rainbow[0];
const int WEMO5 = 5;
const int WEMO4 = 4;
const int WEMO3 = 3;
const int WEMO2 = 2;
const int WEMO1 = 1;
const int WEMO0 = 0;
bool wemowrite;
bool buttonState;
unsigned long lastUpdateTime = 0;
float temp = 0.0;
const int PINA = D4;
const int PINB = D5;
const int HUE6 = 6;
const int HUE5 = 5;
const int HUE4 = 4;
const int HUE3 = 3;
const int HUE2 = 2;
const int HUE1 = 1;
int hue = HueRainbow[color % 7];
bool switchState;
int i, timer;
bool player, status;
Adafruit_NeoPixel pixel(PIXELCOUNT, SPI1, WS2812B);
Adafruit_SSD1306 display(OLED_RESET);
Adafruit_BME280 bme; // I2C
Button pushButton(D3);
Button encoderSwitch(D15);
Encoder encoder(PINA, PINB);
DFRobotDFPlayerMini myMp3Player;
void onOff();
void hueOnOff();
void setup()
{
  Serial.begin(9600);
  waitFor(Serial.isConnected, 1000);
  Serial1.begin(9600);
  delay(1000);
  Serial.printf("DFRobot DFPlayer Mini Demo\n");
  Serial.printf("Initializing DFPlayer ... (May take 3~5 seconds)\n");
  if (!myMp3Player.begin(Serial1))
  { // Use softwareSerial to communicate with mp3.
    Serial.printf("Unable to begin:\n");
    Serial.printf("1.Please recheck the connection!\n");
    Serial.printf("2.Please insert the SD card!\n");
    while (true)
      ;
  }
  Serial.printf("DFPlayer Mini online.\n");
  Wire.begin();
  Serial.println("Ready to go");
  WiFi.on();
  WiFi.clearCredentials();
  WiFi.setCredentials("IoTNetwork");
  WiFi.connect();
  while (WiFi.connecting())
  {
    Serial.printf(".");
  }
  Serial.printf("\n\n");
  pixel.begin();
  pixel.setBrightness(10);
  pixel.show();
  bool status = bme.begin(HEXADDRESS);
  if (!status)
  {
    Serial.printf("BME at address %i failed to start\n", HEXADDRESS);
  }
  Serial.printf("DFRobot DFPlayer Mini Demo \nInitializing DFPlayer ... (May take 3~5 seconds)\n");
  status = myMp3Player.begin(Serial1, false);
  Serial.printf("Status = %i\n", status);
  if (!status)
  {
    Serial.printf("Unable to begin:\n");
    Serial.printf("1.Please recheck the connection!\n");
    Serial.printf("2.Please insert the SD card!\n");
    while (true)
      ;
  }
  Serial.printf("DFPlayer Mini online.\n");
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
}
void loop()
{
  unsigned long currentMillis = millis();
  // Update temperature every minute
  if (currentMillis - lastUpdateTime >= 60000)
  {
    lastUpdateTime = currentMillis;
    temp = bme.readTemperature();
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(10, 0);
    display.print("Temp: ");
    display.print(temp);
    display.write(DEG);
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(12, 28);
    display.println("Papa Duck");
    display.display();
  }
  // Cycle through colors on NeoPixels
  for (int i = 0; i < PIXELCOUNT; i++)
  {
    pixel.setPixelColor(i, color);
    color++;
    pixel.show();
  }
  delay(50); // Adjust speed of color change
  if (pushButton.isClicked())
  {
    buttonState = !buttonState;
  }
  onOff();
  if (encoderSwitch.isClicked())
  {
    switchState = !switchState;
  }
  hueOnOff();
}
void onOff()
{
  if (buttonState == TRUE)
  {
    wemoWrite(WEMO0, LOW);
    wemoWrite(WEMO1, LOW);
    wemoWrite(WEMO2, LOW);
    wemoWrite(WEMO3, LOW);
    wemoWrite(WEMO4, LOW);
    wemoWrite(WEMO5, LOW);
  }
  else
  {
    wemoWrite(WEMO0, HIGH);
    wemoWrite(WEMO1, HIGH);
    wemoWrite(WEMO2, HIGH);
    wemoWrite(WEMO3, HIGH);
    wemoWrite(WEMO4, HIGH);
    wemoWrite(WEMO5, HIGH);
  }
}
void hueOnOff()
{
  if (switchState == TRUE)
  {
    setHue(HUE1, false, HueRainbow[color % 7], random(32, 255), 160);
    setHue(HUE2, false, HueRainbow[color % 7], random(32, 255), 160);
    setHue(HUE3, false, HueRainbow[color % 7], random(32, 255), 160);
    setHue(HUE4, false, HueRainbow[color % 7], random(32, 255), 160);
    setHue(HUE5, false, HueRainbow[color % 7], random(32, 255), 160);
    setHue(HUE6, false, HueRainbow[color % 7], random(32, 255), 160);
    myMp3Player.stop();
    myMp3Player.volume(0);
  }
  else
  {
    setHue(HUE1, true, HueRainbow[color % 7], random(32, 255), 255);
    setHue(HUE2, true, HueRainbow[color % 7], random(32, 255), 255);
    setHue(HUE3, true, HueRainbow[color % 7], random(32, 255), 255);
    setHue(HUE4, true, HueRainbow[color % 7], random(32, 255), 255);
    setHue(HUE5, true, HueRainbow[color % 7], random(32, 255), 160);
    setHue(HUE6, true, HueRainbow[color % 7], random(32, 255), 160);
    hue++;
    myMp3Player.loop(1);
    myMp3Player.volume(10);
  }
}


























Comments