Boron Solar Charging with 1.5.0-rc1


Thanks for reposting!
It would be great is someone with the knowledge would make a tutorial on Boron with solar. There are a lot of different postings and confusing info.
Options I would like to see covered:

  • Small solar panels in mostly sleep mode.
  • Larger solar panels always on.
  • Solar and USB charge option. (For a device the user also can charge)

I agree, but that’s harder to do than it sounds.
A few new features have been introduced into the DeviceOS, which obviously change the operating characteristics. As these new features mature, previous tests might not be valid.

IMO, a detailed guide would only be 100% accurate until the next firmware update.

I’ve been impressed with how well the community shares individual experiences. But even a small change in the install/operation of a Solar Powered Boron can make a difference between users.

The Community could decide on a couple of the most popular use-cases and maintain 1 thread with results as the firmware matures.

I’d think a good starting point would be Voltaic Panels (1W, 2W, 3.5W) using the USB connector w/ Stop and Hibernate Sleep Modes.
Then cheap panels (0.5W, 1W, etc) landed on Vusb w/ the same Sleep Modes.
Once you add using the EN Pin to those cases, you already have a fairly large Matrix of results to maintain/update.

I agree with the idea of a Standardized Code Framework that we can all use as a Base, or Starting Point, to track the changes over time. That would make peer review easier as we share results for each use-case.

Update for firmware 1.5.1 with the new API

Testing 2W Voltaic Panel in Full Sunlight on the USB Connector as per original post.
Using “Mode 1” in my code, which is the new API (not direct PMIC Calls)
Using a discharged 5Ah Li-Po @ 3.8V, not the 2Ah in the original picture
The INA219 shows 1.5W (from 2W rated panel) being pushed into the Li-Po…360+ mA.
I’m very pleased with this result.

Enable charging and disable charging PMIC calls (OLED buttons B & C) are working as expected.
SOC is updating as expected.
DPDM is working, even after cycling (Shading) the Solar Panel repeatedly.

Slightly modified code, but no major changes:

I’ll let it cook for a while.


I just realized a slight issue with 1.5.1 concerning my post directly above this one.
I set the max charging current to 1024 mA with conf.batteryChargeCurrent(1024).
System Power Manager didn’t obey this setting, since the “mostly” discharged Li-Po (at 3.8V resting, 5,000 mAh rated) was being charged at 1450 mA (40% higher than setpoint) for a considerable amount of time until the CV portion of the charge profile.

Relevant Code from link:

STARTUP( selectMode() );

void selectMode()  {
  // (1) API MODE
  if (myTestMode == 1) {
    .feature(SystemPowerFeature::USE_VIN_SETTINGS_WITH_USB_HOST) ;

The Power Source was the 2W Voltaic Solar Panel on the Boron USB connector.
Charging Current was measured by INA219 feather from the (+) Li-Po conductor.

I love the higher charging current, but this could be a problem for someone using smaller capacity Li-Po’s (charging at a much higher rate than the API setpoint). Mainly, I wonder what I’ve done wrong for the API settings to not be obeyed.

The Good News on 1.5.1 using the new API:

  1. Disabling Charging by calling ``pmic.disableCharging();` (button “B”) appears to work 100% of the time. Tested fine throughout the entire Voltage Range of the Charging Cycle.

  2. Re-Enable Charging (button “C”) seems to work ~95% of the time. I haven’t collected enough data to characterize the conditions when this fails. But when it does fail to resume charging, calling pmic.enableCharging(); once or twice More (button “C”) seems to work. That makes me think that locking the PMIC call (per other forum posts) may be the answer when using the new API.

However- the ~5% “failure” has only appeared towards the end of the Charging Profile, although all conditions to allow charging are met (as far as I know). When this “failure” occurs, I can briefly cover the Solar Panel to force a Li-Po Source ONLY, and the Boron will usually resume charging when the Panel begins producing current again. So there’s a good chance the PMIC is operating correctly and I’m just forgetting something from the datasheet that happens towards the end of the charge profile. I’m leaning towards this not actually being a bug/issue.

I haven’t been able to reproduce the charging issues others have mentioned with 1.5.x.
Since my test rig is running Manual Mode (no modem) and no Sleep, those problems are likely related to how the PMIC is managed by the System Power Manager during/after Sleep events ?
Even if the Modem gets in a funny power state, that shouldn’t impact the PMIC performance.

The only issue in regards to Solar Charging on 1.5.1 (without SLEEP) that I’ve seen so far is the charging current can be higher than the API set-point when using a Solar Panel (current producing) during DPDM operation (vary the Current to maintain min V across Panel) while charging a “discharged” Li-Po during the CC (Constant Current) phase of the PMIC’s charge profile. That’s a pretty specific circumstance that’s easily mitigated by proper Panel and Li-Po selection.

[EDIT] - I spoke too soon. The API wont obey the charge termination voltage, in my code .
Charging stops at 4.10 - 4.11 V even with my .batteryChargeVoltage(4208) call in a Startup Macro. The Boron still operates at the default 4112 mV setting.

The call for .powerSourceMinVoltage(5080) does work perfectly when using the USB Connector with my Startup Macro. The PMIC maintains the current to prevent the Panel Voltage from collapsing. The 5080 setting could just be persisting from previous User Firmware Flashes ?
But the other (3) parameters are having problems for me:

  • .powerSourceMaxCurrent(900)
  • .batteryChargeCurrent(1024)
  • .batteryChargeVoltage(4208)

So I removed .feature(SystemPowerFeature::USE_VIN_SETTINGS_WITH_USB_HOST) ; which could likely be the culprit. No Luck.
I also tried to restore the default configuration prior to making Changes. No Luck

void selectMode()  {
  // (1) API MODE
  // Added 05/10/20
    System.setPowerConfiguration(SystemPowerConfiguration());  // To restore the default configuration before making changes

  if (myTestMode == 1) {
  //  .feature(SystemPowerFeature::USE_VIN_SETTINGS_WITH_USB_HOST) ;  // removed 05/10/20

I now realize that my previous charging results are Invalid due to using the USE_VIN_SETTINGS_WITH_USB_HOST feature, but I must still be missing something important with the New API calls.

Any Suggestions ?

UPDATE for Device OS 2.0.0.rc-1 , Boron LTE

Using the same bench setup as the Original Post.
The LED Test Light Stand at the current configuration produces 119 mA @ 5.08V (606 mW) using the Voltaic 2W panel placed at a repeatable position. So 606 mW is the available Solar power for the tests below.

Using the USB Connector for Solar Input results in the following entering the 2aH Li-Po @ 3.95V:

Awake            116 mA     458 mW
Stop             122 mA     482 mW
EN Pin           122 mA     482 mW
Stop w/ Network  
Hibernate        123 mA     483 mW

That’s ~80% of the available panel power being stored into the Li-Po… not bad.
All modes maintained the Solar Panel at ~5.04 V, so DPM still works.

3 of the 4 modes handled the Cycling of the Solar Panel Output to simulate Clouds.
Hibernate Sleep will wake the Boron LTE when the Solar Panel Cycles (not good).
DPM also gets wonky after a Cloud wakes the Boron from Hibernate.

A side note: using Stop Sleep with Network Standby results in 10mA of sleep current (seems too high). If your external watchdog performs an EN Pin Shutdown during this, the PMIC will have problems with DPM. I realize that’s an edge-case.

I also tested a 6V DC Power Supply using the same API settings for comparison:

*6V PowerSupply  255 mA    1060 mW

Power Configuration settings used for all tests:


Solar Charging through the USB connector w/ 2.0.0.rc-1 appears good so far, but there are still some quirks with this release that need investigation prior to official roll-out.

Particle only gets 1-shot at the initial LTS release.
I’d recommend more physical testing prior to leaving Release Candidate Status.
For the past 2 years, I’ve tried to get Gen3 hardware to pass Validation Testing (prior to a 2-week Trial) so I could use Gen3 in Industrial Environments.
I have high hopes for LTS 2.0.0, but it’s still not ready due to a lack of physical testing(IMHO).

I’m going to perform detailed testing for Stop Mode and EN Pin Shutdown, mainly to stress test the API and PMIC as a Li-Po nears the termination voltage under different operating conditions w/ DeviceOS 2.0.0.rc-1. I hope Particle will do the same :sunglasses:

I know that not everyone is concerned with Solar Recharging, but we’ve seen in the past that some of the issues discovered in Solar Tests also show up with a Boron on AC/DC power supply.

Cheers !


I have a TI BQ4050 battery management chip that communicates over i2C like the PMIC chip on the Boron.

The Bq4050 communicated fine on the Photon but not on the Gen3 devices unless I put the BQ4050 chip into 400khz I2C mode to be able to read the chip correctly as some other guy told me to try this after having the exact same issue.

I’m not sure what is going on or if the TI PMIC chip also was or is having issues communicating over I2C. I

m not sure if Particle has made communication changes for the PMIC in the HAL but something looks to be different as far as I2C communication with TI Smbus chips from my and others experience which were not there on the Photon and Electron.

Just to add a casual observation. I have a Xenon running with a solar panel charging the battery and it will have been out there for 2 months on Friday. While it did have some sort of hangup and needed a poke last week, it has otherwise been fine.

What I did notice is the battery charge started at 4.04 vaults. Over the first 3 weeks, that gradually reduced down to 3.98v. (I only ever trust the battery level reading at night when there is no power being generated by the solar cell.) After that, the battery power stopped going down, making the graph I output rather dull.

3.98v seems to be the spot where it will not charge the battery any higher. I have seen this with both a 3.7v LiPo and an 18650.

2 months of running and seemingly stopped using battery power is pretty impressive. I take a few readings then deep sleep for 5 minutes to conserve battery life.

That charge voltage is normal for the PMIC on the Boron.

Particle sets the charging voltage on the low side for safety and it’s fine.

It can be raised but I wouldn’t mess with that after my own testing.

1 Like

@chipmc, @RWB, @Rftop, etc. Anyone willing to share their complete/ideal solar charging settings including temperature on/off charging? or maybe methods to change charge parameters dynamically? I’ve been spending the last few hours poking around forums and VS Code trying to put together some bits/pieces from this thread and a few other threads but wondering if anyone has something more “complete” or some guidance to offer from what I’m starting with? I am using a 3.5 W Voltaic solar panel which I believe is 550mA peak current. My battery is this 6600 mAH from Adafruit: The Solar Panel goes right into VIN with a 470 uF capacitor. I’d like some flexibility to change the charge rate and these settings dynamically, as sometimes it will be constant 5V power from a USB charger source, other times it could be a Solar Panel like this and even others a 12V DC battery. I’m still working out details on how to easily configure that for different scenarios (likely a subscriptionHandler to pass back configuration parameters after a publish event for things like this) but for now mostly focusing on ideal settings for a solar panel use case.

Right now I’m thinking something like this:

  conf.powerSourceMaxCurrent(550) // 3.5 Watt Voltaic provides 550 mA max

//blah blah blah more setup stuff here

void loop()
  int tempF = ReadTemp("cmd")/10;
  if (tempF <= 32 || tempF >= 110) { //If outside of safe lipo charging temp disable charging
    pmic.disableCharging(); // Disable Charging if temp is too low or too high
    if (!chargeDisabled) {"Battery charge disabled: Hot/cold");
      chargeDisabled = true;
  else {
    if (chargeDisabled) {"Battery charge Enabled again");
      chargeDisabled = false;

//blah blah blah more loop stuff here

Any thoughts or guidance will be appreciated. Pending a sunny day above 32 degrees tomorrow I hope to do some testing as well and will report back what I learn.

I only have a couple minutes right now, but here are a few thoughts:

  • You should decide if you’ll use 1.5 firmware or LTS 2.0.x .
  • Don’t check temps and/or call pmic.enableCharging every trip through loop()
  • The main change from Solar to a 5V source is lowering powerSourceMinVoltage(5080)
  • You can leave MaxCurrent and ChargeCurrent Higher than you expect. The MinVoltage becomes the limiting condition for the PMIC anyway.
  • There are a few posts about “locking” the PMIC thread/call when you make changes to the parameters to prevent System Manager from interfering.
  • All of my tests have better luck using the USB connector verses Vin. Voltaic has a nice adapter for $6 if your panel didn’t ship with one.
1 Like

@Rftop Thanks for the info/feedback. Very much appreciated! A few things:

  • I’d like to use LTS 2.0.0 - I actually just went to it on my main device I use for development since it just was released. I’m hoping I’m not missing out on core functionality but can still leverage the stability of an LTS release.
  • Agreed on not checking temps all the time and updating PMIC.enaableCharging every time. Was just my quick/dirty way to test this for immediate results. Instead I’ll have the if statement and the PMIC.enablecharging right within my readTemp() function I think. This function gets called every 5 minutes or at times even 20 or 60 minutes. When 20 or 60 minutes charging will already be disabled as it only enters this mode of long durations between readings when its below freezing anyhow
  • PowerSourceMinVoltage(5080) is the key variable is great to know when used with solar charging. Since I was going to use VIN for all 3 scenarios (5V USB, Solar Panel, 12 VDC), wouldn’t setting this to 5080 (i.e. 5.080 volts) essentially prevent it from charging at all when using a 5V USB wall charger? In the docs is says “Normally, if a USB host is detected, the power limit settings will be determined by DPDM, the negotiation between the USB host and the PMIC to determine…” I assume this negotiation only occurs when plugged into a PC and not a simple USB Wall plug, or stand alone USB Power Bank people use for their phones? I’ll have to do some testing to understand this better. Can you elaborate on why 5.080 vs say 4.900? I’m wondering if I should be just below 5V given my use case?
  • I originally used the USB connector instead of Vin. The main reasons that drove me to VIN was just improved PCB Layout/enclosure design and I didn’t like the fact having a loose connector like that. It limited the enclosure design a bit and secondly, was hoping to have a single plug external to the enclosure that could accept different cords based on power source. I.e. one cord would have a USB plug on it, the next cord would have alligator clips to go to a battery, and the 3rd cord would be an adapter from the Voltaic solar panel plug to the plug I use on my enclosure. Per other forums, I can’t have 12V DC on the USB Connector, only VIN. Thus I’m using VIN. Hope to do some more testing/learning today and will share back my thoughts.

If you have anything to add in the meantime, let me know! This community is great by the way!

Correct…very few “wall” chargers can maintain 5.0V at a decent amperage.
But the 5.080V setting will allow the PMIC to use the most Power from the 6V Voltaic Solar Panel.
The MinVoltage is the main change required when swapping sources.

I ran a trial and made a post somewhere on this forum. Seems like there was maybe a 10 - 15% difference (in mAh stored in the Li-Po) between the two setpoints for a 2W Voltaic Panel…(without looking it up). For Solar Installs, you want MinVoltage set as close as possible to the Panel’s Voltage produced at the Peak Current published by the Panel Manufacturer, which is 6.5V for your 3.5W Panel.
But 5.080V is the closest option we have for the PMIC for DPDM to work it’s magic with a Solar Source.

1 Like

Alright… too busy with other things to test yet and report back yet. In the meantime, I did have a question though… is there any possible way to read back the voltage at VIN. I see there is a function: power.getInputVoltageLimit() any chance there is a way to read the actual voltage not just the limit: power.getInputVoltage() or would this have to be done via Analog Input GPIO and some voltage divider of some sort? Since you can set the limit, I assume the PMIC has smarts in it that it reads the actual voltage. If I could read the actual input voltage from PMIC, I could possibly determine what power source is connected. One of my use cases involves monitoring something remotely that is powered from 12VDC deep cell battery. I was very happy to find out I can also power the Boron from the same 12VDC rather than trying to step down the voltage to 5V. In this use case, it would be nice to know what the charge is of the 12VDC deep cell battery connected to VIN so I would know the available power remaining in the external battery that powers both the Boron and this other thing. I wonder if there was a way to do this using the Power Manager API. Any guess if this is possible? Would this take some custom C++/I2C commands rather than using the easy button of something like power.getInputVoltage() or is it not possible at all and only possible through GPIO pins?

As of now, I’m thinking I’d configure a power source from the front end web app. This setting would be sent to the device via a webhook response via pub/sub event. Either way, I already do portions of this to dynamically change the sleep/wake time so shouldn’t be too bad. The “gotcha” in this approach is if I select Solar and let the device completely die, plugging it into a USB wall charger won’t recover it. So I’m thinking once the battery is say less than 10%, it would go back to the default PowerSourceMinVoltage(3880). It would then charge at least enough via USB to connect to the cloud to then allow changing the configuration based on the value set in the web app.

You bring up a good point.
Then when the Li-Po Voltage gets low, automatically prepare the Boron to Mothball itself into Hibernate with PowerSourceMinVoltage(3880) for Solar and 12V sources.

A “Dead” 12V source would still provide a voltage, but no current to allow the PMIC to maintain the backup Li-Po. The Li-Po would drain, then you enter the failsafe Hibernate Mode.

A 5V Install would already have PowerSourceMinVoltage(3880).
Your Code wouldn’t care which of the (3) Power Sources used for each install.
As you said, you can define that with a Webhook… which basically only really needs to change powerSourceMinVoltage. Then monitor the Li-Po as the failsafe.

1 Like


Going this thread late but would agree with everything that @Rftop said.

I use the same panel as you (Voltaic 3.5W 6V) and put a 470uF cap on DC-In. All this works well. I have the same settings as you but left the MaxCurrent at 900 because, as @Rftop points out, the Min voltage is the key setting.

I did want to pick up on something you said about disabling charging when the temperature is too low. I though this functionality would be added to the Power Configuration API. Without it, you still have to run the older PMIC commands as well as the New API. Was I mistaken that this was supposed to get fixed?



1 Like

Thanks for confirming @chipmc - I am not 100% sure if the new Power Configuration API has a disable charging. Searching through the docs it doesn’t appear like it was included in the API yet. In the sample code I used (which I think I copied from a different post of yours), I did confirm it enables/disables charging like it should using pmic.disableCharging() and pmic.enableCharging() based on the temperature reading.

As for reading the voltage input from the PMIC, I did dig through the datasheet of the bq24195. Page 26 lists the available registers and nothing is mentioned as it pertains to input voltage. Oh well, it was worth a shot. It looks like if I wanted to measure that voltage of the 12VDC batter, I’ll have to do use a GPIO pin and knock a 12V DC voltage down to at least 3.3.

So given the information from both @Rftop and confirmed by @chipmc. I think I now have the info I need. Thank you both very much! Always appreciated!

I just need to take some time to go program the webbook to dynamically change .powerSourceMinVoltage(5080) based on cloud configuration and then to Mothball itself into Hibernate mode with setting back to .powerSourceMinVoltage(3880) once below x% battery percent. Right now, I’m thinking of having the default config first initialized during setup() be .powerSourceMinVoltage(3880). The cloud configuration would only be allowed to set it to .powerSourceMinVoltage(5080) IF the current battery percentage is above say 75%. This way, if the battery ever dies when configured as a Solar Panel mode, it can be recharged via standard USB to near full battery before it can be set back to Solar Panel mode. Thanks again! I’ll report back my further learnings and code snippets I used for this hopefully in the next few days. Hoping for a sunny day tomorrow! :slight_smile:


Just a thought on your last paragraph. There may well be times when the charge level will drop significantly below 75% say after a longish cold snap or a significant period of cloud cover (pesky hurricanes). Unless you want to physically “rescue” your devices, you may well want to keep the minimum voltage setting to facilitate solar charging. In my use case, I can’t easily physically visit my sensors so what I have done is introduce a “low battery” state to my finite state machine. In this state, the device uses the “enable” pin to achieve the lowest power usage and it only wakes to periodically check the battery level. With this protection in place, I have not yet had a battery go completely dead in normal operations.

The case you described where a USB charger can charge the device despite the higher minimum voltage setting is enabled by default as long as your charger uses the DPDM pins to signal its intent to charge your device.

I realize that the pmic.disableCharging() function does work as expected but, I was hoping I could make a clean break with pmic once the new power configuration API was fully deployed.



1 Like

@jgskarda a behavior that I have noticed and take advantage of is that even if you set PowerSourceMinVoltage(5080) and have a device go down requiring a physical intervention with USB charging I just throw the device in Safe Mode which will then utilize the default PowerSourceMinVoltage setting allowing me to USB charge.

1 Like
  • Very good to know. That’s a good fallback for sure. Thanks!

yeah agreed. What I’m actually thinking is the entry condition to initially set .powerSourceMinVoltage(5080) is >75% battery charge and solar charge configured from the webhook response. It would stay with that configuration until the battery was say less than 5%/near dead, just before entering mothball mode. This way the Solar Panel can use the full battery capacity rather than only 25% of it. Hope that makes sense.

[quote=“chipmc, post:52, topic:54680”]
With this protection in place, I have not yet had a battery go completely dead in normal operations.
[/quote] - Fantastic to hear. Looking forward to trying out this Solar Panel in a long term situation! Would be a bit easier. What’s your wake/sleep duration and how many maH battery do you have? I was running a 6600 mAh battery in a wake every 5 minutes to take readings/fall back asleep and then wake every 20 minutes, take readings, turn on cellular/particle.connect() and publish all of the readings to the cloud then fall back asleep. The power hungry part is connecting to the cloud to publish the data. Was getting 2-5 weeks out of it with this config based on signal strength (i think it takes longer to connect each time with weaker signal thus consuming more power). Would be great to get at least 8 weeks or even better increase the frequency at which it can publishes data. Very curious on what results you’ve found. By the way… I also 3D printed a bracket to mount the 3.5W solar panel and use a adjustable camera bracket from Amazon. This way I can easily clamp it on anything and then adjust it very easily. When I get around to it, I’ll post it to the other post with a picture. Would be curious what your using as a bracket as well for our panel.

Now that I updated my board based on the discussion from your carrier board that mentioned this: I received my boards back and everything seems to work perfectly with that watchdog, sleep and system reset using .EN functionality outlined in the application note. So I think I can also use the .EN PIN if needed for the mothball mode to sleep with very little power consumption. Although I’m hoping I can get by without the complexity of using .EN pin.

1 Like