True Charge Detection for Use with Custom Presets w/ or w/out Blade ID!

After not finding anything that really did what I needed, I’ve done some work on charge detection and wanted to share - hoping it will be considered for a future version of the OS.

’ve added a CHARGE_DETECT_PIN feature to ProffieOS that acts like a virtual button, similar to BLADE_DETECT_PIN, to detect when a saber is actively charging. It works with modules like the TP4056 or any other Li-Ion charger that provides a logic-level output when charging.

You can also use the built-in charger detection on Proffieboards or better (safer and better chargin) a pin that goes low when charging on an external charge module. This would be connected to any free pin and defined in your config file.

In my_config.h:

#define CHARGE_DETECT_PIN CHARGER_MONITOR  // pin 20 is CHARGER_MONITOR

Just add that or your actual charge detect pin from the external source once this logic updates I provide below are in place.


Key Benefits:

  • Lets users define a pin to trigger CHARGE_MODE.
  • Automatically switches to a dedicated preset bank when charging.
  • Integrates cleanly alongside existing blade detection logic including blade ID — still functions.

Example Presets and Blade Config

Preset definition:

Preset charge_detect_presets[] = {
  { "ChargeFont;common", "",
    StylePtr<Black>(),  // Main blade off
    StylePtr<Layers<
      Mix<
        SmoothStep<Scale<BatteryLevel, Int<0>, Int<32768>>, Int<1>>,
        Mix<BatteryLevel, Red, Green>,
        Black
      >
    >>(),  // Pixel switch or secondary blade
    "Charging"
  }
};

Blade config entry:

{ CHARGE_MODE, 
  WS281XBladePtr<16, blade3Pin, Color8::GRB, PowerPINS<bladePowerPin2, bladePowerPin3>>(), 
  WS281XBladePtr<6, blade2Pin, Color8::GRB, PowerPINS<bladePowerPin4>>(), 
  CONFIGARRAY(charge_detect_presets), "charge_save"
},

Since CHARGE_MODE is defined as 2000000000, it always ranks higher than NO_BLADE or any blade ID.


Code Changes (by file and location)

ProffieOS.ino – In Warmup() block (above BladeDetect.Warmup):

#ifdef CHARGE_DETECT_PIN
  ChargeDetect.Warmup();
#endif

ProffieOS.ino – Register virtual button (below BladeDetect):

#ifdef CHARGE_DETECT_PIN
LatchingButtonTemplate<FloatingButtonBase<CHARGE_DETECT_PIN>>
    ChargeDetect(BUTTON_CHARGE_DETECT, CHARGE_DETECT_PIN, "charge_detect");
#endif

events.h – Below BUTTON_BLADE_DETECT:

BUTTON_CHARGE_DETECT = 2048,

events.h – Below NO_BLADE:

#define CHARGE_MODE 2000000000 /* 2 billion */

prop_base.h – Near blade_detected_ flag:

#ifdef CHARGE_DETECT_PIN
  bool charge_detected_ = false;
#endif

prop_base.h – Inside id() before blade_detected_ section:

#ifdef CHARGE_DETECT_PIN
STDOUT << "CHARGE PIN READ: " << digitalRead(CHARGE_DETECT_PIN) << "\n";
  if (charge_detected_) {
    STDOUT << "CHARGING\n";
    ret += CHARGE_MODE;
  } else
#endif

saber_fett263_buttons.h – Before BLADE_DETECT_PIN section:

#ifdef CHARGE_DETECT_PIN
  case EVENTID(BUTTON_CHARGE_DETECT, EVENT_LATCH_ON, MODE_ANY_BUTTON | MODE_ON):
  case EVENTID(BUTTON_CHARGE_DETECT, EVENT_LATCH_ON, MODE_ANY_BUTTON | MODE_OFF):
    charge_detected_ = true;
    FindBladeAgain();
    SaberBase::DoBladeDetect(true);
    return true;

  case EVENTID(BUTTON_CHARGE_DETECT, EVENT_LATCH_OFF, MODE_ANY_BUTTON | MODE_ON):
  case EVENTID(BUTTON_CHARGE_DETECT, EVENT_LATCH_OFF, MODE_ANY_BUTTON | MODE_OFF):
    charge_detected_ = false;
    FindBladeAgain();
    SaberBase::DoBladeDetect(true);
    return true;
#endif

I’ve tested this on a Proffie v3.9 using a TP4056 module. Works smoothly with no conflicts. Screenshots of the changes are attached for reference.

If you have any questions or need more information, please let me know. I’m looking into making this a patch and will be doing the same for OS8 assuming it doesn’t make the cut yet.

Thanks!

1 Like

Interesting.

Some hilts already use 2b as a chassis-has-been-removed-from-hilt mode.
Maybe make this 900m instead.

Good to know! Thank you.

Just a quick follow-up and correction to my original post:

While the Proffieboard V3 does support USB charging at a low current (~450mA), the VBUS line (pin 20) can’t be read in firmware — it’s not connected to a GPIO. That means it can’t be used directly for charge detection as I had suggested.

The most reliable approach is still what I’ve implemented: using a separate charge module with its own dedicated charge detect line wired to a GPIO. I have my charge detect line wired to pin 7, defined like this:

#define CHARGE_DETECT_PIN 7

I also implemented profezzorn’s recommendation for the value for CHARGE_MODE in the events.h file:

#define CHARGE_MODE 900000000 /* 900 Million */
1 Like

Is there more info on this removal mode? That sounds super interesting.

There should be some threads around here about it, but it might require some spelunking, because the first two searches I tried did not find it.

Same. Couldn’t find it yet.