Boron Solar Charging with 1.5.0-rc1

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 https://voltaicsystems.com/3-5-watt-panel/ which I believe is 550mA peak current. My battery is this 6600 mAH from Adafruit: https://www.adafruit.com/product/353. 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:

setup(){
  conf.powerSourceMaxCurrent(550) // 3.5 Watt Voltaic provides 550 mA max
      .powerSourceMinVoltage(5080)  
      .batteryChargeCurrent(1024)
      .batteryChargeVoltage(4208);
  System.setPowerConfiguration(conf);

//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) {
      Log.info("Battery charge disabled: Hot/cold");
      chargeDisabled = true;
    }
  }                     
  else {
    pmic.enableCharging();
    if (chargeDisabled) {
      Log.info("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.
    image
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.
image
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

@jgskarda,

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?

Thanks,

Chip

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. https://docs.particle.io/reference/device-os/firmware/boron/#power-manager 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. https://www.ti.com/lit/ds/symlink/bq24195.pdf?ts=1607315588178&ref_url=https%3A%2F%2Fwww.google.com%2F

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:

@jgskarda,

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.

Thanks,

Chip

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:https://github.com/particle-iot/app-notes/tree/master/AN023-Watchdog-Timers 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

@jgskarda,

OK, I understand what you mean by 75% now, makes sense.

Here is a rough outline of my approach - in case it helps or if you or anyone else has a suggestion for improvement. :wink:

  • I use 1800-2000mAH batteries which are good for 4-5 days of normal operations
  • My devices generally get a good 8 hours of deep sleep (ā€œEnableā€ pin) at night, waking only to pet the watchdog every hour.
  • During the day, they ā€œnapā€ (stop mode sleep) except to handle the following: 1) hardware interrupt from sensors, 2) hourly connect / report via Webhook to Ubidots, 3) Stay awake for 90 seconds at the top of the hour for updates / interaction. This is called ā€œlow power modeā€ and it is the default behavior.
  • I can take the devices out of ā€œlow power modeā€ to ā€œnormal operationsā€ when I want to monitor / interact with the device using the particle variables and functions. The device will go back to ā€œlow-powerā€ model automatically after a while or if the battery level is low.
  • Finally, there is a ā€œlow batteryā€ mode when the device goes into battery preservation mode - currently set at 20@ charge.

I have also switched over to the new watchdog / clock approach outlined in AN023 - very happy with them so far.

Thanks,

Chip

1 Like

Good stuff. Thanks for sharing! A few thoughts/comments/questions:

Is this needed when using the internal watchdog? I thought you need to turn off the external watchdog when in sleep mode per AN023 having a max watchdog of 124 seconds. I.e. use
ab1805.stopWDT(); and ab1805.resumeWDT(); correct?

  • Nice. I might steal this. :slight_smile:

Can you elaborate on this difference. Is low power mode stop mode but with wake on cellular giving you an opportunity to wake it up during that 90 second window? I.e. something like this:

SystemSleepConfiguration config;
config.mode(SystemSleepMode::STOP)
      .network(NETWORK_INTERFACE_CELLULAR)
      .flag(SystemSleepFlag::WAIT_CLOUD)
      .duration(90sec);

Finally, here is what I came up with to mount the solar panel. Works well for me to clamp the bracket to nearly anything and then adjust the solar panel based on time of the year and where the sun is in the sky. It's nothing more than a 3D printed bracket to attach the solar panel to with a 1/4" 20 threaded inserts bought from McMasterCarr and then a camera bracket that has 1/4" 20 threads on one end and a clamp on the other that I bought from Amazon: https://www.amazon.com/dp/B07GWJJ6Y4?ref_=plp_pc_dp_A28B5OQ36AG7GY_B07GWJJ6Y4&m=A3IAUEKUWSUBUS :

I am still waiting on a sunny day here in WI to really see what this solar panel can do. Hopefully tomorrow. The setting of .powerSourceMinVoltage(5080) does seem to keep the device in the "charging" state vs flickering back/forth between modes at least. It's just not making much progress yet on increasing battery percentage due to full cloud cover today. That said, I am currently keeping the device in normal operation mode (no sleep/stop/hibernate) just for this testing vs sleeping/waking like I normally do. So I'm probably consuming whatever power the solar panel can generate on a cloudy day.

Thanks for the dialog and for sharing your project. I love the bracket. I simply use the $4.00 one from Voltaic but yours is more adjustable and looks great.

I see you are 3D printing the bracket. Can you share what filament you are using? I am interested in learning how well these parts will stand up to UV light over a few years.

As for your questions:

You are correct, with the new AB1805, I could simply sleep for the full 8 hours. Here is the thing, when the device is in ā€œEnableā€ sleep, the only way to get it back is to unplug the DC-In and the LiPO battery which is a pain in my setup. If the device wakes for 90 seconds each our and does not turn on the cellular radio, it does not make much of a difference in the battery life. It would make it easier for me to help park personnel recover the device if needed (ā€œwait till the top of the hour and when you see the white light, press the user buttonā€).

The difference between ā€œlow power modeā€ and ā€œnormal operationsā€. Is two fold:
First, low power mode only connects to Particle at the top of the hour. Normal operations is constantly connected to Particle.
Second, low power mode sleeps (STOP mode) between sensor interrupts while normal operations is awake and in the Idle state between interrupts.
Normal operations allows me to monitor the device in real time and interact with it via the Particle console.

Finally, I have not played with the network interface cellular state but am interested in doing so. My concern is that it will significantly degrade battery life but the ability to poll devices at any time, not just the 90 second communication window, could be a game changer.

Thanks,

Chip

1 Like

I am printing in PETG. I've been told it should hold up really well in outdoor applications just don't use PLA. I'm a bit skeptical myself but we will see. I didn't realize Voltaic one was $4. That will probably be a better option for me for if/when I have a permanent installations. I'm not 100% sure what will happen after a year or two and if it gets a heavy wet snow on it. Just was my quick/easy way to mount it for testing and I already use those camera brackets for something else.

That is very cleaver! I like what you did there. I'm contemplating how to best conserve battery when readings are not needed from the device as well. This is very much dependent upon the current temperature. I.e. when it's freezing cold outside, it doesn't need to report very often. But when it's warmer (above freezing) then it needs to report quite often. I was contemplating having the cloud dynamically change the sleep duration based on the hourly weather forecast in that area or waking up and check to see what the temperature is and if still freezing cold, sleep another hour. etc. then fall back asleep. So far I didn't consider entering EN sleep mode but maybe something I could consider. Overall, I am sure I am overcompensating for a little sloppiness in minimizing power consumption by having a 6600mAH battery and a solar panel but I might be better off with techniques like this!

Something related I was considering was add an ability to enter "Stay Awake mode". What I mean by that is the webbook response from a publish event would send back a configuration parameter called StayAwakeFlag. Essentially I could flip this flag to true in my database, the status of this flag is sent back to the device after each publish event. Then each time the device publishes new data, I can tell it to stay awake or not. The device publishes new data, waits a few seconds for that response and then immediately falls back asleep if the flag is still false OR stay awake if the flag is true. My initial thought is have the database only allow that to be true for 1 hour and after an hour it would auto set the flag back to false. It sounds good on paper/in my head at least. :slight_smile: We will see how it actually plays out in the coming weeks as I update the web app, DB and device code to test it out. If the device was still healthy/able to occasionally talk to the cloud, you could then enter this mode yourself without having to bother the park rangers.

1 Like

Well today was finally a nice sunny day! And Iā€™ll just say I am quite impressed with how much I got out of the Voltaic 3.5W 6V. Looks like from about 8:00 AM to ~ 4:00 PM it charged my 6600 mAh battery from ~2% --> ~80% in the 8 hours of sun today (obviously slower during the beginning of day and end of day). This was with the device in ā€œnormalā€ operation mode the entire time and not even in stop/sleep mode. I kept it that way so I could keep taking readings throughout the day to see how itā€™s doing. I suspect I would of had another 5-8% if the device was sleeping. Overall, Iā€™m very impressed and happy with this!

If Iā€™m thinking about it correctly, say I charged 80% of a 6600 mAh battery I stored away 5280 mAh in ~ an 8 hour period. So on average: 660 mAh battery capacity per hour of charging. I.e. averaged 660 mA charge current into a 3.7 V nominal battery. This is 2.442 average watts from that 3.5 watt peak Solar panel. ~70% efficiency on average throughout the day. Overall, Iā€™m very happy with that! Thanks everyone for sharing the settings and the guidance here. Always appreciated. Iā€™ll still implement the sleep cycles, and dynamically change charging parameters as discussed earlier but Iā€™m quite please with this early test. I was getting nearly 1 week of battery life when keeping the device awake the entire time before a solar panel and roughly 3-4 weeks when using a sleep/wake cycle so Solar panel makes a huge difference! Just 1.5 days of sun during this a time period like this would charge it right back up! This is great!

1 Like

Finally got around to implementing the cloud control of solar charging (along with other configuration parameters). Here was my approach in case anyone has some other suggestion or can use it. There is quite a bit here but figured Iā€™d share for any feedback in my approach and maybe someone can use it as well.

Within the Boron:

Initialize values:

//Configuration parameters: -Initialized here
//After initialization, this should be set via PUB/SUB method on some frequency
int16_t config_mode = 1; //Mode - 1:Cellular All-in-on only, 2:Cellular+Lora Gateway, 3:Remote Lora Node
int16_t config_slpInterval_Min = 5;  //Time between taking sensor readings when powered (sec)
int16_t config_rptTime_Min = 20;  //Time between reporting readings to the cloud when not powered
int16_t config_vitalsTime_Min = 120; //Time between publishing vitals
int16_t config_stayAwake_flag = 1; //Duration of time to stay awake. 1 = forever, 0 = immediatly sleep
int16_t config_powerSourceMaxCurrent = 900; //Set maximum current the power source can provide. The default is 900 mA.
int16_t config_powerSourceMinVoltage = 3880; //Set minimum voltage required for VIN to be used. The default is 3880 (3.88 volts).
int16_t config_batteryChargeCurrent = 896; //Sets the battery charge current.The default is 896 mA.
int16_t config_batteryChargeVoltage = 4112; //Sets the battery charge termination voltage. The default is 4112 (4.112V).
int16_t config_indexNum = 0; //Index number of current configuration (0-255)

#define configPtID_mode "1"
#define configPtID_slpInterval_Min "2"
#define configPtID_rptTime_Min "3"
#define configPtID_vitalsTime_Min "4"
#define configPtID_stayAwake_flag "5"
#define configPtID_powerSourceMaxCurrent "6"
#define configPtID_powerSourceMinVoltage "7"
#define configPtID_batteryChargeCurrent "8"
#define configPtID_batteryChargeVoltage "9"
#define configPtID_indexNum "255"

In setup() load the default upon first poweron (we donā€™t know if itā€™s solar or mains power yet):

  //Initalize default power configuration for USB charging
  System.setPowerConfiguration(SystemPowerConfiguration());  // To restore the default configuration

Handle the subscription back from each publish event:

void subscriptionHandler(const char *event, const char *data)
{
  Log.info("New Subscription Event: %s",event);
  Log.info("With Data: %s", data);

  jsonParser.clear();
  jsonParser.addString(data);
  jsonParser.parse();

  bool newPmicCongig_rx = false;
  int intValue;

  //Update device sleep, wake, vitals, stayawayke configuration
  if (jsonParser.getOuterValueByKey(configPtID_mode, intValue)) config_mode = intValue;
  if (jsonParser.getOuterValueByKey(configPtID_slpInterval_Min, intValue)) config_slpInterval_Min = intValue;
  if (jsonParser.getOuterValueByKey(configPtID_rptTime_Min, intValue)) config_rptTime_Min = intValue;
  if (jsonParser.getOuterValueByKey(configPtID_vitalsTime_Min, intValue)) config_vitalsTime_Min = intValue;
  if (jsonParser.getOuterValueByKey(configPtID_stayAwake_flag, intValue)) config_stayAwake_flag = intValue;

  //Update PMIC Configuration:
  if (jsonParser.getOuterValueByKey(configPtID_powerSourceMaxCurrent, intValue)) {
      if (config_powerSourceMaxCurrent != intValue){
        config_powerSourceMaxCurrent = intValue;
        newPmicCongig_rx = true;
      } 
  }
  if (jsonParser.getOuterValueByKey(configPtID_powerSourceMinVoltage, intValue)) {
      if (config_powerSourceMinVoltage != intValue){
        config_powerSourceMinVoltage = intValue;
        newPmicCongig_rx = true;
      }
  }
  if (jsonParser.getOuterValueByKey(configPtID_batteryChargeCurrent, intValue)) {
      if (config_batteryChargeCurrent != intValue){
        config_batteryChargeCurrent = intValue;
        newPmicCongig_rx = true;
      }
  }
  if (jsonParser.getOuterValueByKey(configPtID_batteryChargeVoltage, intValue)) {
    if (config_batteryChargeVoltage != intValue){
      config_batteryChargeVoltage = intValue;
      newPmicCongig_rx = true;
    }
  }

  //Update Configuration index Number so cloud knows if it needs to send a new config
  if (jsonParser.getOuterValueByKey(configPtID_indexNum, intValue)) config_indexNum = intValue;

  //update PMIC Config if needed:
  if(newPmicCongig_rx) {
    Log.info("new PMIC Config Rx - Call function");
    pmicConfig();
  }
  pubSub_ResponseRx = true;
}

Update battery configuration if it changes. Only allow going to Solar Config if battery source is greater than 70 percent.

void pmicConfig(){

  Log.info("Check PMIC Config");
  PMIC power(true);
  if (power.getInputCurrentLimit() != config_powerSourceMaxCurrent || power.getInputVoltageLimit() != config_powerSourceMinVoltage || power.getChargeCurrentValue() != config_batteryChargeCurrent || power.getChargeVoltageValue() != config_batteryChargeVoltage) 
  {
    
    Log.info("Current PMIC settings is Different than Config");
    
    //If power source min voltag is greater than 3880 only allow setting it to a higher value if current battery charge level is greater than 70%. This is to ensure the device is adequatly charged before switching to Solar functionality and no longer chargable via USB. 
    if (System.batteryCharge() > 70 || config_powerSourceMinVoltage <= 4000 )
    { 
      Log.info("Battery is greater than 70 Perct or power source min voltage <= 4000 accept new config");
      SystemPowerConfiguration conf;
      conf.powerSourceMaxCurrent(config_powerSourceMaxCurrent)
          .powerSourceMinVoltage(config_powerSourceMinVoltage) //3880 for USB, 5080 for Solar
          .batteryChargeCurrent(config_batteryChargeCurrent)
          .batteryChargeVoltage(config_batteryChargeVoltage)
          .feature(SystemPowerFeature::USE_VIN_SETTINGS_WITH_USB_HOST);
      int res = System.setPowerConfiguration(conf);
      Log.info("setPowerConfiguration1=%d", res);
    } 
  }

  //If power source min voltag is greater than 3880 and we are low on battery charge, then set powerSourceMinVoltage to 3880 to ensure the device is capable of USB charging.
  if(power.getInputVoltageLimit() > 3880 && System.batteryCharge() < 10) 
  {
    Log.info("Battery is less than 10 perc and currently configured for greater than 3.880 volts. Use Defaults");
    int res = System.setPowerConfiguration(SystemPowerConfiguration());  // To restore the default configuration
    Log.info("setPowerConfiguration2=%d", res);
  }
}

Something I donā€™t show here is when publishing an event, I also include what the current ā€œconfig_indexNumā€.

Within the Python function that I use to processes the data from the publish event, IF the config_indexNum does not equal the config_indexNum reported by the device, it assembles the JSON response of all configuration parameters to send as a response that is handled by the subscriptionHandler()

    response_msg = {"0":1}

    if "configIndex" in msg['data']:
        if (int(msg['data']['configIndex']) != device.device_settings.config_indexNum):
            response_msg = {
                str(configPtID.mode):device.device_settings.config_mode,
                str(configPtID.slpInterval_Min):device.device_settings.config_slpInterval_Min,
                str(configPtID.rptTime_Min):device.device_settings.config_rptTime_Min,
                str(configPtID.vitalsTime_Min):device.device_settings.config_vitalsTime_Min,
                str(configPtID.stayAwake_flag):device.device_settings.config_stayAwake_flag,
                str(configPtID.powerSourceMaxCurrent):device.device_settings.config_powerSourceMaxCurrent,
                str(configPtID.powerSourceMinVoltage):device.device_settings.config_powerSourceMinVoltage,
                str(configPtID.batteryChargeCurrent):device.device_settings.config_batteryChargeCurrent,
                str(configPtID.batteryChargeVoltage):device.device_settings.config_batteryChargeVoltage,
                str(configPtID.indexNum):device.device_settings.config_indexNum
            }

    return func.HttpResponse(json.dumps(response_msg))

(Something not shown here is the webhook configuration within the Particle Console but thatā€™s pretty straightforward).

So now, each time I want to send a new configuration to the device, I just update the values and increment the config_indexNum in SQL. The next time the device publishes, it receives a response with the new configuration and settings are updated.

Iā€™m sure I could clean this up a bit or maybe there are prettier ways to write this but itā€™s functional for me. :slight_smile: What I like about this, is I an also use the ā€œstayAwakeā€ flag, change the slpInterval, reportInterval, vitalsInterval at anytime and those settings are updated the next time the device wakes up and connects to the cloud.

@chipmc - This might be an alternative to consider rather than having a park ranger having to be at the device at a specific time if they need to wake it up for you. Although it does require more of a personalized backend to process the particle webhooks as well as a SQL (or some other DB). I did still use your approach of waking up the device at a specific Time of Day rather than just sleeping for x minutes. This way I know when to expect new data from the device. I just combined both concepts into one.

1 Like

@jgskarda,

Thank you for sharing. This is an excellent approach and it solves many issues associated with configuration of a large number of ā€œsleepyā€ devices.

Thank you for sharing. I think I will use this with the new Particle API event on Ubidots as I donā€™t currently use a custom back-end.

Thanks,

Chip