Well. I tried this and it seems that the power up worked for a week, After that the system went to a stall mode, where the photon needs reset in order to work again.
So the fix… does not work. Or the issue might not be related to power. I have been having sunny days for the whole week. The lowest power logged it’s about 60% of the lipo battery according to the spark fun monitoring system.
I haven’t been able to keep the system working for more than 5 days now.
Code attached. Let me know if you catch something that I should be concerned with my code:
#include "LEDControl.h"
#include "SparkFunMAX17043/SparkFunMAX17043.h"
#include "SparkFun_Photon_Weather_Shield_Library/SparkFun_Photon_Weather_Shield_Library.h"
#include "math.h"
#define PIN_SOLARNRG A2
#define PIN_POWERALERT_ISR D6
#define PIN_PROGRAMMODE_ISR D4
#define version "2.0a"
float humidity = 0;
float tempc = 0;
float tempf = 0;
float dewtf = 0;
float dewtc = 0;
float pascals = 0;
float baroTempc = 0;
float baroInches = 0;
float altimeter = 0;
Weather sensor;
//OPTIONS
const int pulseLEDEverySeconds = 30;
const int pulseLEDDuration = 1;
const int reportToCloudEverySeconds = 59;
const int deepSleepForHours = 1;
const int lowPowerAlert = 30;
//STATION SETUP
const int station_elevation_m = 1638;
char WU_SERVER [] = "weatherstation.wunderground.com"; //Standard server - for sends once per minute or less
char WU_WEBPAGE [] = "GET /weatherstation/updateweatherstation.php?";
//Station Identification
char WU_ID [] = "xxx"; //Your station ID here
char WU_PASSWORD [] = "yyyy"; //your Weather Underground password here
TCPClient client;
//VARIABLE DECLARATIONS
unsigned long int pulseSeconds=0;
unsigned long int seconds=0;
//Battery Shield
float voltage = 0.0;
float soc = 0.0;
float solarNrg = 0.0;
float solarNrgRaw = 0.0;
bool hybernateMode=false;
bool alert = false;
bool programMode = false;
//SYSTEM_MODE(SEMI_AUTOMATIC);
Timer heartTimer(1000, heartBeat);
//BROWNOUT
void setBrowoutResetLevel() {
const uint8_t desiredBOR = OB_BOR_LEVEL2; //2 = 2.40~2.70 // 1 = 2.10~2.40 // 3 = 2.70~3.60
if(FLASH_OB_GetBOR() != desiredBOR) {
/* Steps from http://www.st.com/web/en/resource/technical/document/programming_manual/CD00233952.pdf */
/* See also https://github.com/spark/firmware/blob/aefb3342ed50314e502fc792f673af7a74f536f9/platform/MCU/STM32F2xx/STM32_StdPeriph_Driver/src/stm32f2xx_flash.c#L615 */
/* To run any operation on this sector, the option lock bit (OPTLOCK) in the Flash option control register (FLASH_OPTCR) must be cleared. */
FLASH_OB_Unlock();
/* Modifying user option bytes */
/* 1. Check that no Flash memory operation is ongoing by checking the BSY bit in the FLASH_SR register */
FLASH_WaitForLastOperation();
/* 2. Write the desired option value in the FLASH_OPTCR register */
FLASH_OB_BORConfig(desiredBOR);
/* 3. Set the option start bit (OPTSTRT) in the FLASH_OPTCR register */
FLASH_OB_Launch();
/* disable the FLASH option control register access (recommended to protect the Option Bytes against possible unwanted operations) */
FLASH_OB_Lock();
}
}
void heartBeat() {
if (seconds>=UINT_MAX) {seconds=0;}
if (pulseSeconds>=UINT_MAX) {seconds=0;}
seconds++;
pulseSeconds++;
}
//DUTY METHODS
void publishBatteryEvents()
{
String msg = String::format("{ \"SOLNRG\":%f, \"VTS\":%f, \"SOC\":%f, \"LOWP\":%d, \"HYBM\":%d}", solarNrg, voltage, soc, alert, hybernateMode);
Particle.publish("POWSTAT", msg);
}
void publishWeatherEvents()
{
String msg = String::format("{ \"TEMP\":%f, \"DEW\":%f, \"PASC\":%f, \"ALT\":%f, \"HUM\":%f}", tempc, dewtc, pascals, altimeter, humidity);
Particle.publish("WXSTAT", msg);
}
void publishToWunderground()
{
if (client.connect(WU_SERVER, 80)) {
client.print(WU_WEBPAGE);
client.print("ID=");
client.print(WU_ID);
client.print("&PASSWORD=");
client.print(WU_PASSWORD);
client.print("&dateutc=now"); //can use 'now' instead of time if sending in real time
client.print("&tempf=");
client.print(tempf);
client.print("&dewptf=");
client.print(dewtf);
client.print("&humidity=");
client.print(humidity);
client.print("&baromin=");
client.print(altimeter);
client.print("&action=updateraw"); //Standard update rate - for sending once a minute or less
client.println();
}
delay(1000);
client.stop();
}
// SHIELDS >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>
//BATTERY-POWER
void readBattery()
{
lipo.wake();
delay(300);
voltage = lipo.getVoltage();
soc = lipo.getSOC();
alert = lipo.getAlert(true);
solarNrgRaw = ((analogRead(PIN_SOLARNRG) * 3.0)/4095);
solarNrg = (100 / 3) * solarNrgRaw;
}
//WEATHER
void readWeather()
{
humidity = sensor.getRH();
tempf = 0.0;
float rawTempc = sensor.getTemp();
baroTempc = sensor.readBaroTemp();
tempc = (rawTempc+baroTempc)/2;
tempf = (tempc * 9)/5 + 32;
pascals = sensor.readPressure();
baroInches = pascals * 0.0002953;
dewtc = dewPoint(tempc, humidity);
dewtf = (dewtc * 9.0)/ 5.0 + 32.0;
altimeter = altimeterSetting(pascals);
}
double dewPoint(double celsius, double humidity)
{
// (1) Saturation Vapor Pressure = ESGG(T)
double RATIO = 373.15 / (273.15 + celsius);
double RHS = -7.90298 * (RATIO - 1);
RHS += 5.02808 * log10(RATIO);
RHS += -1.3816e-7 * (pow(10, (11.344 * (1 - 1/RATIO ))) - 1) ;
RHS += 8.1328e-3 * (pow(10, (-3.49149 * (RATIO - 1))) - 1) ;
RHS += log10(1013.246);
// factor -3 is to adjust units - Vapor Pressure SVP * humidity
double VP = pow(10, RHS - 3) * humidity;
// (2) DEWPOINT = F(Vapor Pressure)
double T = log(VP/0.61078); // temp var
return (241.88 * T) / (17.558 - T);
}
float altimeterSetting(float pascalsIn)
{
float pressure = pascalsIn;
pressure /= 100; //pressure is now in millibars
float part1 = pressure - 0.3; //Part 1 of formula
const float part2 = 8.42288 / 100000.0;
float part3 = pow((pressure - 0.3), 0.190284);
float part4 = (float)station_elevation_m / part3;
float part5 = (1.0 + (part2 * part4));
float part6 = pow(part5, (1.0/0.190284));
float altimeter_setting_pressure_mb = part1 * part6; //Output is now in adjusted millibars
float baroin = altimeter_setting_pressure_mb * 0.02953;
return baroin;
}
void setSafeMode() {
setLED(ORANGE);
programMode = true;
}
// >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>
// PHOTON METHODS
void setup()
{
//Protect for low voltage conditions.
setBrowoutResetLevel();
pinMode(PIN_SOLARNRG, INPUT);
pinMode(PIN_POWERALERT_ISR, INPUT_PULLUP);
pinMode(PIN_PROGRAMMODE_ISR, INPUT_PULLUP);
pinMode(D7, INPUT_PULLDOWN);
attachInterrupt(PIN_PROGRAMMODE_ISR, setSafeMode, FALLING);
Time.zone(-5);
Serial.begin(9600);
//BatteryShield
lipo.begin();
lipo.quickStart();
lipo.setThreshold(lowPowerAlert);
//WeatherShield
sensor.begin();
sensor.setModeBarometer();
sensor.setOversampleRate(100);
sensor.enableEventFlags();
RGB.control(true);
String bootStatusString;
String ip = WiFi.localIP();
Serial.println("*************************");
Serial.println(" WXMAN");
Serial.print("Version: ");
Serial.println(version);
Serial.println("By Lobo:Labs 2015");
Serial.println("System Ready......");
Serial.println("*************************");
bootStatusString = String::format("{\"VER\": \"%s\", \"RSSI\": %d, \"SSID\":\"%s\", \"IP\":\"%s\"}", version, WiFi.RSSI(), WiFi.SSID(), ip.c_str());
Serial.println(bootStatusString);
//waitUntil(Particle.connected);
Particle.publish("BOOT", bootStatusString);
readBattery();
readWeather();
delay(1000);
WiFi.off();
heartTimer.start();
}
void performReportDuties() {
setLED(WHITE);
if (!Particle.connected()) {
Serial.println("[Cloud] Connecting to cloud");
Particle.connect();
}
setLED(BLUE);
waitUntil(Particle.connected);
Serial.println("[Cloud] Transmitting Events...");
publishBatteryEvents();
delay(1500);
publishWeatherEvents();
delay(3000);
setLED(GREEN);
publishToWunderground();
delay(1500);
setLED(OFF);
if (soc<99) { WiFi.off(); } //Only shut down when not at full charge.. If at full chargo don't waste time.
}
void enterProgramMode() {
setLED(CYAN);
if (Particle.connected() == false) {
Particle.connect();
}
while (true) {
setLED(MAGENTA);
delay(1000);
Particle.process();
setLED(ORANGE);
delay(1000);
}
}
void timedEvents() {
// if (pulseSeconds==pulseLEDEverySeconds) { setLED(GREEN); }
// if (pulseSeconds>=pulseLEDEverySeconds+pulseLEDDuration) { setLED(OFF); pulseSeconds=0; }
if (seconds % 2 == 0) { //Read Values every 2 seconds.
readBattery();
readWeather();
}
if (programMode==true) {
programMode=false;
enterProgramMode();
}
if (seconds % reportToCloudEverySeconds == 0) {
hybernateMode = false;
if (soc<=60 && solarNrg <= 58) { hybernateMode = true; }
performReportDuties();
if (hybernateMode) {
setLED(RED);
lipo.sleep();
delay(1500);
if (soc>45) {
System.sleep(SLEEP_MODE_DEEP, 60*60*deepSleepForHours);
} else { //If battery very low... Sleep for longer!
System.sleep(SLEEP_MODE_DEEP, 60*60*(deepSleepForHours*2));
}
}
}
}
void loop() {
timedEvents();
}