Hackster is hosting Hackster Holidays, Ep. 4: Livestream & Giveaway Drawing. Start streaming on Wednesday!Stream Hackster Holidays, Ep. 4 on Wednesday!
James OoiBenji Ooi
Published

Sunkeeper

Vitamin D decreases susceptibility to COVID-19. Humans make Vitamin D via sun exposure. Sunkeeper measures how much sun you have absorbed.

BeginnerFull instructions provided2 hours1,336
Sunkeeper

Things used in this project

Hardware components

Seeed Studio Seeeduino Xiao
×1
Photo resistor
Photo resistor
×1
Resistor 5kOhm
×1
Resistor 220 ohm
Resistor 220 ohm
×3
5 mm LED: Red
5 mm LED: Red
×1
5 mm LED: Green
5 mm LED: Green
×1
LED, Blue
LED, Blue
×1
3.7v 1500mAh LiPo rechargeable battery with JST connector
×1
Mini PCB
×1
20 AWG insulated wire
×1

Software apps and online services

Arduino IDE
Arduino IDE
You also need this file to work with the Seeeduino Xiao in the Arduino IDE: https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Solder Wire, Lead Free
Solder Wire, Lead Free

Story

Read more

Schematics

Sunkeeper Schematic Diagram

Use this wiring diagram to see how to connect the components to the PCB and battery.

Code

Sunkeeper Seeeduino Xiao Code

C/C++
Open in Arduino IDE and upload to Seeeduino Xiao through the USB-C port.
/**********************************************************/
int tim = 500;  //the value of delay time
// initialize the library with the numbers of the interface pins

int lightPin=4;
int lightOnPin=6;
int IntensityPin=9;
int EnoughPin=10;
int ExcessPin=7;
unsigned long lastmillisgreen=millis();
unsigned long lastmillisred=millis();
unsigned long lastmillisblue=millis();
unsigned long lastmillisTL=millis();
float interval=500;


int lightVal;
float dl=500.0;
float M=10000.0;
float Rp;
float L;   // light intensity, unknown units, so calibrated empirically
float PL;  // percent of max brightness
float Vao;
float tdelta;  // time for a loop in minutes
float TL=0.0;  // total BSM (bright sunlight minutes) absorbed
float SL=0.0;  // current cumulative sunload
float maxbright=46.0;  // empirically derived maximum value of L representing bright sunlight (calibrated in northern NJ, USA)
float enoughthresh=15; //fifteen minutes of bright sunlight min. per day is recommended

// because sunburn is not a matter of how much sun you get throughout the day but rather exceeding your body's ability to handle sun exposure,
// we attempt to model your body's ability to handle damage by assuming that the "sun load" born by your body decays exponentially with the time since the sun was absorbed.
// we assume a halflife of 30 minutes, meaning the load born by your body after 30 minutes of exposure is half what it was at the outset
// sunloadmax = 21 = (1 - exp(-r*30))/r is about the load born by your body after 30 minutes of maximum sun exposure
float r = .0231; // r=ln(2)/30 means for the purpose of sunburn, the sun has a halflife of 30 minutes, so the skin will have repaired half the sun damage in 30 minutes
float lambda = .97716; // exp(-r)
float sunloadmax = 21;

float VCC = 3.3;  // seeeduino xiao HIGH voltage
float greeninterval = 5000.0;  // starting value
float redinterval = 1000*24*60*60.0;

void blinkpin(int pin, int d) {
  digitalWrite(pin,HIGH);
  delay(d);
  digitalWrite(pin,LOW);
  delay(d);
}

void setup() {
  // put your setup code here, to run once:

pinMode(lightPin,INPUT);
pinMode(lightOnPin,OUTPUT);
pinMode(EnoughPin,OUTPUT);
pinMode(IntensityPin,OUTPUT);
pinMode(ExcessPin,OUTPUT);
Serial.begin(9600);
digitalWrite(lightOnPin,HIGH);
}

void loop() {
  Serial.println("Start:");
  unsigned long beginloop = millis();
  // put your main code here, to run repeatedly:
  digitalWrite(IntensityPin,LOW);
  if (greeninterval>0)
    digitalWrite(EnoughPin,LOW);
  if (redinterval>0)
    digitalWrite(ExcessPin,LOW);
  lightVal=analogRead(lightPin);
  Vao=(lightVal/1023.0)*VCC;
  Rp=((VCC*5.0/Vao)-5.0)*1000.0;
  L=M/Rp;
  PL=L/maxbright;  
       
  tdelta = (millis()-lastmillisTL)/(1000.0*60.0); // time elapsed in minutes
  lastmillisTL = millis();
  if (PL<0.25){
    PL = 0; // if the light is this low you are probably indoors, so don't register anything
  }
  TL=TL+PL*tdelta;  // counting up total BSM in minutes
  SL = SL * (pow(lambda,tdelta)) + PL*tdelta;  // accumulating sunload units and decaying them

  Serial.println(lightVal);
  Serial.println(Vao);
  Serial.println(Rp);
  Serial.println(TL);
  Serial.println(SL);
  Serial.println(millis());
  
  if (TL/enoughthresh>.02) {
    greeninterval = 100/(TL/enoughthresh);
  }
  // otherwise flash every 5 seconds to show device is on

  if (TL>=enoughthresh) {
    greeninterval = -1;
  }
  // stay on continuously to show enough BSMs achieved for the day
  
  if (SL/sunloadmax>.02) {
    redinterval = 100/(SL/sunloadmax);
  }
  else
    redinterval = 1000*24*60*60.0;  // don't flash red LED unless over 2% of sunloadmax

  if (SL>=sunloadmax) {
    redinterval = -1;
  }
  
  if (millis()-lastmillisgreen>=greeninterval) {
    digitalWrite(EnoughPin,HIGH);
    lastmillisgreen=millis();
    delay(10);
  }
    
  if (millis()-lastmillisred>=redinterval) {
    digitalWrite(ExcessPin,HIGH);
    lastmillisred=millis();
    delay(10);
  }

  if (PL>0.25){
    if (millis()-lastmillisblue>=100/PL) {
      digitalWrite(IntensityPin,HIGH);
      lastmillisblue=millis();
      delay(10);
    }
   }
   if ((millis()-beginloop)>1000*60*60*24) {
      TL=0;
      greeninterval = 5000;
   }
}

Credits

James Ooi

James Ooi

2 projects • 2 followers
Benji Ooi

Benji Ooi

1 project • 1 follower

Comments