Electron Solar Kit Charging Indicator?

Hi folks,

Anyone know how to tell if the solar shield, panel, and battery are successfully charging? When plugged into USB, there is a red led that lights up, but when on solar alone there is none. I imagine that’s to save energy, but how would I tell if everything is working?

Using a volt meter I see about 5 volts at the JST on the shield coming from the panel, and about 4 volts at the JST for the battery, and a little less than 4 volts at the JST connector going into the Electron, but that doesn’t necessarily tell me that the battery is charging. Any recommendations beyond what I’ve tried?

Edit: Using librato graphs to monitor the battery voltage and light level for 24 hours.

1 Like

Yes this was so that the Shield could have the absolute lowest current draw and most efficient charging when the electron is off.

There is a /CHRG pin from the solar charging chip that connects to the Electron D5. If you set pinMode(D5, INPUT_PULLUP); you can read this pin… essentially if it’s LOW it’s charging. You may not need the INPUT_PULLUP if we stuffed the 10k on-board pull-ups that I’m seeing on the schematic.

If you want this indication when the Electron is OFF, it gets a little messier and we’ll have to review the best way to do this for you.

From the datasheet:

CHRG (Pin 4): Open-Collector Charger Status Output; typically pulled up through a resistor to a reference volt- age. This status pin can be pulled up to voltages as high as VIN when disabled, and can sink currents up to 10mA when enabled. During a battery charging cycle, if required charge current is greater than 1/10 of the programmed maximum current (C/10), CHRG is pulled low. A tem- perature fault also causes this pin to be pulled low. After C/10 charge termination or, if the internal timer is used for termination and charge current is less than C/10, the CHRG pin remains high-impedance.

Likewise there is a /FAULT output connected to D6

FAULT (Pin 5): Open-Collector Charger Status Output; typically pulled up through a resistor to a reference voltage. This status pin can be pulled up to voltages as high as VIN when disabled, and can sink currents up to 10mA when enabled. This pin indicates fault conditions during a battery charging cycle. A temperature fault causes this pin to be pulled low. If the internal timer is used for termina- tion, a bad battery fault also causes this pin to be pulled low. If no fault conditions exist, the FAULT pin remains high-impedance.


Thanks for the useful info on D5, that can be a very useful trigger to determine when to be awake and when to sleep. By the way, does pressing the ‘mode’ button turn the Electron off, or just turn off the breathing LED?

After running for 24 hours and using the Fuel Gauge library to poll the battery while measuring the ambient light using an LDR, it appears the system is charging. Looks like I need to put it to sleep between publish events or it will only last a day or two (it was abnormally sunny today).

Note: the chart above was captured with local time settings, but during export Librato recreated the chart for export using UTC, it should be to the left by about 5 hours. I’ve notified them of the issue.

There is an RTC on the Solar Shield that will manage powering down the Electron at super low quiescent currents for periods of time, so you shouldn’t need to actively monitor these signals unless you are awake and want to do something with it.

A double tap of the MODE button will completely power off the cellular modem, disable logic, and put the STM32F2 into Deep Sleep (Standby Mode). This is the lowest powered state of the Electron by itself. A press of the RESET button (or active LOW signal on RST pin) or active HIGH signal on WKP pin will wake the Electron. In contrast, the Solar Shield removes all power to the Li+ input of the Electron to further reduce current consumption.

This is a good idea for power consumption, however please note that currently sleeping and waking will cause a re-handshake with the server so it will consume more data than if you just left the Electron awake. The next Electron firmware release will resolve this issue and Stop mode sleep will reduce current to around 4mA average (non-official, don’t build a cellular rocket with this number) with no re-handshake data penalty when you wake (assuming you still have a PDP context… this varies but may expire in as little as an hour, up to 8 hours).


I had no idea there was an RTC on the shield, that is super useful!

The more I learn about this little board the more impressive it becomes. It’s clear a lot of thought has gone into it. Thanks again for answering all my questions. In return, I offer more graphs. The X-axis is still not accurate as far as time (capture in local time, export in UTC), Librato says they have no fix for this yet, but maybe some day if enough people request a fix, hint hint.

As far as the graph, you’ll notice that the slope of battery discharge is much less steep the second day, that is due to the fantastically easy to use Deep Sleep Mode, nothing more than System.sleep(SLEEP_MODE_DEEP, 600). Its a good thing I added that since it was rainy all day and I don’t think the battery would have lasted with the cell chip running at 180ma all day and night. Also interesting is the approximately 1% battery life consumption and corresponding voltage drop when pushing a firmware update over the air as the chip goes to max power.

Data consumption is now the question. I’d love to get more granularity on my data usage. First 24 hours showed 0.11 MB with one OTA firmware update, second 24 hours showed I’m at 0.70 (with a second OTA firmware update). It will be nice when the next update rolls out and I don’t have to re-handshake with the tower every ten minutes. Thanks for automating the reconnection upon wakeup, by the way.

Can I turn off the breathing RGB LED within a sketch to further reduce power consumption? It is only blinking for about 10 seconds as I reconnect and publish events, but still, it doesn’t need to be since I can monitor based on the published events.

I would advise leaving it on since it consumes very little current with 1000 ohm series resistors (in comparison to the run current), but if you want to check out all of the fancy things you can do, Docs are here:

1 Like

It’s certainly handy to have an on board RGB LED. Glad I can turn it off though if need be.

Day three shows continual voltage drop, even though I’m in deep sleep for 59 out of 60 total minutes of each hour. It’s been overcast and raining for two of the three days. I seem to lose about 12% of my battery every 24 hours when I don’t have sufficient sun to run the board as well as charge it even though I’ve got the panel angled at the appropriate angle for my lat/long and time of year. Friday may bring more sun which I’ll be in desperate need of since I’ll have about 5% battery remaining. Saturday and Sunday look sunny, so if I make it to Friday I may be in the clear :wink:

Which sleep mode are you using?


Deep Sleep was working perfectly fine and reliably for me but you couldn’t wake from any pins with the deep sleep.

The System.Sleep with pin wakeup is where I can’t get the publish working reliably.

I just wanted to let you know that in Deep Sleep mode the cellular modem stays powered on, to get the lowest power consumption you have to turn it off. See below:

From this thread Electron data usage

1 Like

Huh. I was under the impression that it turned everything off based on the reference for System.sleep(SLEEP_MODE_DEEP):

“System.sleep(SLEEP_MODE_DEEP, long seconds) can be used to put the entire device into a deep sleep
mode. In this particular mode, the device shuts down the network subsystem and puts the microcontroller in a stand-by mode. When the device awakens from deep sleep, it will reset and run all user code from the beginning with no values being maintained in memory from before the deep sleep. As such, it is recommended that deep sleep be called only after all user code has completed. The Standby mode is used to achieve the lowest power consumption. After entering Standby mode, the SRAM and register contents are lost except for registers in the backup domain. The device will automatically wake up and reestablish the Wi-Fi connection after the specified number of seconds.”

I assumed network subsystem to include the modem but maybe that’s for the photon. I’ll try Cellular.off() and see what happens. Do you have to re-enable the modem or does it power back up after sleep? @BDub @RWB

Yea I figured Deep Sleep put everything to sleep also :smiley:

From my testing you do have to power the modem back up after wakeup. Then you have to call connect, and then particle connect but if I remember correctly the publishes would not show up after powering up the cellular modem after having turned it off before sleeping.

Maybe @Bdub can commend on why Deep Sleep does not turn off the cellular module.

Do you have the code you used to reconnect everything? I wonder if that is still required though, since @BDub said they created an auto-reconnect sequence in a recent firmware update.

Edit: Reading a little more about Cellular.off() and Cellular.on() it sounds like as long as I’m in automatic mode (default) when the device ‘starts up’ it should automatically turn on and reconnect. I’m hoping the ‘start up’ includes waking from deep sleep, vs a complete power off type reset.

Edit2: Seems to have worked. I just gave it a solid 40 seconds of non-blocking delay to reconnect and publish, seems to have come back up, turned on the modem, re-handshaked with the tower, published data, turned modem off and gone back to sleep.

When I used Cellular.off() before deep sleep things did not go well when the Electron woke up. I got different LED colors.

I had to Cellular.on , then Cellular.connect() or something similar, Particle.connect(), and then wait for Particle.connected(), for the whole startup to go as normal. Even then the publishes would not show up. I gave up and figured I would just compile locally and add Bdub’s new code to fix the regular sleep + wake from time or pin feature.

It did all that without calling any reconnect functions. This must be what @BDub meant with a new reconnect sequence instituted in a recent firmware update.

If you want more control, you can apparently change ‘modes’ to semi-automatic, or manual control. Automatic is default.

I’ll post another graph after 24 hours and we can compare discharge rates over three days between: CPU running, CPU sleeping, CPU and modem sleeping.

Sorry, so what code is working for you now? Are you calling cellular.off() before sleep and then waking up in automatic mode without any problems?

Can you post the code you are talking about.

Also do you ever see the battery SOC ever go up to 100%? Mine maxes out at like 86% and the full charge voltage only goes up to 4.01 volts or something. I plan to raise the charging voltage and see if that helps, I think the default is 4.11 which is good if the included battery sees temps above 45C. The fuel gauge will not show 100% until the voltage is above 4.2v which is the normal recommended charge voltage for a lipo.

I’m calling Cellular.off() right before sleep, no problems at all. I just have to make sure to give a nice long millis() delay when it wakes up to reconnect everything. You could also maybe do an if statement to check if it is connected before moving into the publish events. That would work too I’m sure, and be more tolerant.

Here’s what I hacked together:

 #define publish_delay 40000
 FuelGauge fuel;
 const int voltOut = A5;
 const int ldrPin = A0;
 const int ledPin = 7;

 void setup() {
 pinMode(voltOut, OUTPUT); //supply 3.3v at pin A5
 pinMode(ldrPin, INPUT); //assign A0 as an input
 pinMode(ledPin, OUTPUT);
digitalWrite(voltOut, HIGH); //initialize A5 at 3.3v


void loop() {
unsigned long now = millis(); //this shouldn't be blocking like delay() is, allows reconnection and should allow me to   reflash during this window too.

if (now < publish_delay) {
    // it hasn't been 40 seconds yet...
int value = (analogRead(A0) / 10); 
float voltage = fuel.getVCell();
int SoC = fuel.getSoC();
Particle.publish("librato_A0", String(value), 60, PRIVATE);
Particle.publish( "librato_voltage", String(voltage), 60, PRIVATE);
Particle.publish( "librato_SoC", String(SoC), 60, PRIVATE);
now = 0;
System.sleep(SLEEP_MODE_DEEP,900); //sleep for 15 minutes

I’ve never gotten there since I’ve had the thing running for a few days straight and its been rainy. My code hasn’t been optimized to save enough battery yet to allow it to recover. Hopefully using the Cellular.off() function you mentioned, plus the System.sleep(SLEEP_MODE_DEEP) will be the ticket.

I’ll give that a try.

I was trying to use the Particle.connected(); instead of a delay to get all future publishes to show up but only the first publish worked. I tried the delays like you also but that didn’t get the publishes consistently showing up either.

I think the best way to use the Particle.connected(); function is to put the code you want to run into a if statement.

if (Particle.connected()) {



I’ve used it like that on the Photon successfully but I’m no expert on this either so.

I just need to learn how to install the CLI and use the latest firmware to fix the normal system.sleep() function where you can wake from Pin also.

Good luck.

I’ll have to look at the Particle.connected() function it will probably do what I need.

Maybe if you post the code you’re having trouble with some folks can take a look and try to figure out what’s not working for you with the publish events.

Deep sleep works fine for me. Turning off the cellular modem is what caused problems but its working for you so that’s good news.

I want the System.sleep so I can wake from Pin also. So my next task is to get the Local programming setup so I can get that working now.

I would like to see your graph of how the different sleep modes affect your power usage over time.