Spoken “charging” prompts

If you don’t mind having your personal OS, I can think of several ways to customize it:
First you need to “declare” the new sound to your OS:
(keep the sound files names to 8 characters or less)

  • Method1. You can add it to sound/sound_library.h and add:
ADD_SL_SOUND(Charging, "charging"); // for charging.wav
ADD_SL_SOUND(DoneCharging, "doncharg"); // for doncharg.wav
  • Method2. You can customize the prop you are using:
    where the other “EFFECTs” are, add:
EFFECT(charging);
EFFECT(doncharg);
  • Method3. You can add it as a global effect for all of your ProffieOS by editing sound/effect.h (same code addition than Method2, just different file)

I am not sure which method is best for your case. I would probably go with method3. That is just to declare to ProffieOS that your new sounds “exist”.

To trigger the sounds, you can do:

  • Method1:
sound_library_v2.SayCharging(); // or sound_library.SayCharging(); (depending in which list you added it)
//or
sound_library_v2.SayDoneCharging();
  • Method2 & 3:
if (SFX_charging) {
  hybrid_font.PlayCommon(&SFX_charging);
} else { // the "else" is optional in case your wav file is missing
  beeper.Beep(0.5, 3000);
}
//or
if (SFX_doncharg) {
  hybrid_font.PlayCommon(&SFX_doncharg);
} else { // the "else" is optional in case your wav file is missing
  beeper.Beep(0.5, 3000);
}

Now the unknown to me is where to add code that would detect that you are charging or done charging? Probably in common/battery_monitor.h and/or the Loop() function of your prop.

2 Likes

I’ve just had a look. Still gotta do some detective work. For some reason arduino is being a pain arm so can’t test what I’m doing in the loop function just yet

On a proffieboard?
Or something else?

It’s entirely possible to do, but the Proffieboards don’t generally have the hardware for this.
(They may have it in the future though…)

I did just check what my voice pack says when charging. Mine just says it’s 100% when charging, but unplugged it tells me the actual percentage.

Don’t do this.
The sound library is a specific set of sounds, and adding new sounds to it requires updating the version, which is centrally managed. Forking it is not supported. Only add things to the sound library if you think you want to add it to ProffieOS proper, and be prepared for that to take a while.

Do this instead.

Yeah a proffie 3.9. I can check the battery percentage as it’s plugged in, check it again in 10 mins or so and it’ll go up a percent or two. 1 hour or so later a few more percent all the way to 100, I have read this isn’t the case, but is for me :laughing:

Edit: I’m wrong. I’m sure it did before. However, it isn’t, and now i feel stupid

I just created this feature as a new prop that you can include in your config file like so:

#ifdef CONFIG_PROP
#include "../props/saber_fett263_buttons.h"
#include "../props/saber_charging.h"
#endif

I’m using fett’s prop, but it doesn’t really matter which prop you’re using.

You have to add the new prop file to /ProffieOS/props/saber_charging.h

#ifndef PROPS_SABER_CHARGING_H
#define PROPS_SABER_CHARGING_H

// Standalone charging voice announcements — works with any prop file.
//
// Plays charging.wav when USB charging starts.
// Plays doncharg.wav when the battery is fully charged
// (charger stops while USB is still connected).
//
// Usage in config file:
//   #ifdef CONFIG_PROP
//   #include "../props/saber_fett263_buttons.h"  // or any other prop
//   #include "../props/saber_charging.h"
//   #endif
//
// Place charging.wav and/or doncharg.wav in your font directory or common/.
// Files are optional — missing ones are silently skipped.
//
// Requires Proffieboard V3 or later (chargeDetectPin).

#include "../sound/effect.h"
#include "../sound/hybrid_font.h"
#include "../common/looper.h"

EFFECT(charging);
EFFECT(doncharg);

class ChargingVoice : public Looper {
public:
  const char* name() override { return "ChargingVoice"; }

  void Loop() override {
#if PROFFIEBOARD_VERSION - 0 >= 3
    uint32_t now = millis();
    if (now - last_charge_check_ < 500) return;
    last_charge_check_ = now;

    bool charging_now = !digitalRead(chargeDetectPin);

    if (first_check_) {
      // Silently record the initial state so we only react to changes that
      // happen while the saber is already running — not to whatever the charger
      // pin reads at boot. When the kill switch is off and USB powers the board,
      // the charger pin is already asserted on startup even with no battery
      // connected; skipping the first transition prevents a false announcement.
      was_charging_ = charging_now;
      first_check_ = false;
      return;
    }

    if (charging_now != was_charging_) {
      if (charging_now) {
        // Charger became active while saber was already running — battery is present.
        if (SFX_charging) hybrid_font.PlayCommon(&SFX_charging);
      } else if (USBD_Connected()) {
        // Charger stopped but USB still present — battery is full.
        if (SFX_doncharg) hybrid_font.PlayCommon(&SFX_doncharg);
      }
      // USB simply unplugged — no sound.
      was_charging_ = charging_now;
    }
#endif
  }

private:
#if PROFFIEBOARD_VERSION - 0 >= 3
  bool was_charging_ = false;
  bool first_check_ = true;
  uint32_t last_charge_check_ = 0;
#endif
};

ChargingVoice charging_voice;

#endif  // PROPS_SABER_CHARGING_H

So when plugging in the charger it will say: ‘Charging Battery’.
And when unplugging the charger if the battery is full, it will say: ‘Battery Full’.

Sadly, I don’t think there’s a way to say ‘Battery Full’ as long as the usb is connected to the board.

I created two new voice files:

1 Like

You don. Would love to know how you figured this out. I’ll test it later. This was actually really fun so thank you for all your help! :slight_smile:

Getting pushed in the right direction by olivierflying747-8 and profezzorn helped a lot when checking how it’s done in existing prop files. Together with a pretty good instructions file I created for Claude Code AI to help with the implementation of this logic. Which I of course tested.

1 Like

This group is fantastic then. You don’t regularly get such support in these forums but I guess this is a bit more niche, so maybe a sprinkle more passion. I’ll test this out when I get home and see what we get.

If this works I’ll likely next try to tackle a way of accessing a kill switch externally. (Maybe magnetic reed switches?) but that’s a topic for another time :laughing:

1 Like

@joefirmager

All of the “Additional Voicepacks” have a Xeno counterpart that has charging wavs that match the character.

2 Likes

I love this group. You’re all great hahaha. Many thanks, will swap over to one of those

Ever since my first proffie, I’ve been using the Cal Kestis voice pack which I love! So definitely going to download those additional files.

A bit late to the party on this topic, but I have a prop wrapper I created to achieve exactly what was originally being described. My original experiments with charge detect had me forking the OS, but my current version doesn’t do that at all. I also don’t fork the Fett prop.

When I plug in USB it goes to the last preset which allows me to set specific lighting effects. That preset is also “hidden” in normal preset navigation. When the battery is full I get a sound from the SD card’s common folder I added with “Charge Complete.” Also, if I click the main power button while charging it announces the current battery level.

While the exact percent is not completely reliable while charging and charge full will bounce towards the top, it can be mitigated and get close enough to true 100%. I added some tuning numbers which I’ve experimented with so it doesn’t immediately flip to full when reading 100%.

You can check out my prop wrapper if you like. I have a chargebegin.wav and chargecomplete.wav there you can have if you like them. “You’ll need to have a hardware solution for a low signal when 5v present like any of the discussed options, but this is pretty straightforward with a transistor and a couple resistors.

2 Likes

Interesting, I’ll have a look what you did to get the battery level. Might even use this one instead