Last active
December 13, 2017 17:41
-
-
Save kordless/f228d45495652a066d695de5905e5c79 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "shieldrelay.h" | |
#define relay1 D3 | |
#define relay2 D4 | |
#define relay3 D5 | |
#define relay4 D6 | |
#define relay5 D0 | |
#define relay6 D1 | |
bool relays[7] = {false,false,false,false,false,false,false}; | |
RelayShield::RelayShield(){ | |
} | |
void RelayShield::begin(){ | |
pinMode(relay1, OUTPUT); | |
pinMode(relay2, OUTPUT); | |
pinMode(relay3, OUTPUT); | |
pinMode(relay4, OUTPUT); | |
pinMode(relay5, OUTPUT); | |
pinMode(relay6, OUTPUT); | |
digitalWrite(relay5, HIGH); | |
digitalWrite(relay6, HIGH); | |
} | |
void RelayShield::on(uint8_t i){ | |
switch(i){ | |
case 1: | |
digitalWrite(relay1, HIGH); | |
relays[1] = true; | |
break; | |
case 2: | |
digitalWrite(relay2, HIGH); | |
relays[2] = true; | |
break; | |
case 3: | |
digitalWrite(relay3, HIGH); | |
relays[3] = true; | |
break; | |
case 4: | |
digitalWrite(relay4, HIGH); | |
relays[4] = true; | |
break; | |
case 5: | |
digitalWrite(relay5, LOW); | |
relays[5] = true; | |
break; | |
case 6: | |
digitalWrite(relay6, LOW); | |
relays[6] = true; | |
break; | |
} | |
} | |
void RelayShield::off(uint8_t i){ | |
switch(i){ | |
case 1: | |
digitalWrite(relay1, LOW); | |
relays[1] = false; | |
break; | |
case 2: | |
digitalWrite(relay2, LOW); | |
relays[2] = false; | |
break; | |
case 3: | |
digitalWrite(relay3, LOW); | |
relays[3] = false; | |
break; | |
case 4: | |
digitalWrite(relay4, LOW); | |
relays[4] = false; | |
break; | |
case 5: | |
digitalWrite(relay5, HIGH); | |
relays[5] = false; | |
break; | |
case 6: | |
digitalWrite(relay6, HIGH); | |
relays[6] = false; | |
break; | |
} | |
} | |
bool RelayShield::isOn(uint8_t i){ | |
return relays[i]; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "application.h" | |
#ifndef RelayShield_h | |
#define RelayShield_h | |
class RelayShield { | |
public: | |
RelayShield(); | |
void | |
begin(void), | |
on(uint8_t i), | |
off(uint8_t i); | |
bool | |
isOn(uint8_t i); | |
private: | |
}; | |
#endif RelayShield_h |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This #include statement was automatically added by the Particle IDE. | |
#include "shieldrelay.h" | |
#include "Particle.h" | |
#include "neopixel.h" | |
SYSTEM_MODE(AUTOMATIC); | |
// analog inputs | |
#define BUTTON_PIN A0 | |
#define IR_PIN A1 | |
#define MULTI_VOLT_PIN A2 | |
#define BATTERY_VOLT_PIN A3 | |
#define BATTERY_TEMP_PIN A4 | |
// pixel strip | |
#define PIXEL_PIN D2 | |
#define PIXEL_COUNT 8 | |
#define PIXEL_TYPE SK6812RGBW | |
RelayShield myRelays; | |
// sensors | |
int irsensor; | |
int irs_array[20]; | |
int inverter; | |
int button; | |
int capvolt; | |
int cv_array[20]; | |
int solvolt; | |
int batvolt; | |
int bv_array[20]; | |
int batterytemp; | |
// variables | |
int inverter_timer = 0; | |
int led_timer = 0; // guide light | |
int global_timer = 1000; // time starts at 1K | |
int used_timer = 0; // boolean | |
int dt = 300; // delay | |
int threshold = 2000; // ir threshold | |
int mode = 0; | |
int shutdown = 0; | |
String kordsbarn = String(""); | |
// name of device | |
String myname = ""; | |
// functions | |
int switchMode(String command); | |
// pixel strip setup | |
uint32_t Wheel(byte WheelPos); | |
Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE); | |
void colorAll(uint32_t c, uint8_t wait); | |
void colorWipe(uint32_t c, uint8_t wait); | |
void rainbow(uint8_t wait); | |
// timer handler (runs once per second:1s) | |
int ct_period = 1000; | |
void check_timers() { | |
if (inverter_timer == 0) { | |
inverter = 0; | |
myRelays.off(6); | |
} else { | |
inverter_timer--; | |
} | |
if (led_timer == 0) { | |
} else if (led_timer == 1) { | |
colorBar(8, 0, 0, 0); // turn off guide light | |
} else { | |
led_timer--; | |
} | |
global_timer++; | |
if (global_timer == 87400) { // ~1day | |
global_timer = 1000; | |
} | |
used_timer = 0; | |
} | |
int ss_period = 300000; // 5 minutes | |
void scan_sensors() { | |
// every five minutes (300s) run sensor sweep | |
Particle.publish("kordsbarn", String("voltage input scan")); | |
// grab current state | |
int relaythree = myRelays.isOn(3); | |
int relayfour = myRelays.isOn(4); | |
int relayfive = myRelays.isOn(5); | |
// get solar volts | |
myRelays.on(3); // turn solar on | |
myRelays.off(4); | |
myRelays.off(5); | |
delay(1500); // wait a moment for relay to settle | |
solvolt = analogRead(MULTI_VOLT_PIN); | |
myRelays.off(3); // turn solar off | |
myRelays.on(4); // turn caps on | |
delay(1500); // wait a moment for relay to settle | |
capvolt = analogRead(MULTI_VOLT_PIN); | |
for (int i=0; i<20; i++) { // overload the caps averaging | |
cv_array[i] = capvolt; | |
} | |
delay(200); | |
// return relays to previous states | |
if (relaythree) { | |
myRelays.on(3); | |
} else { | |
myRelays.off(3); | |
} | |
if (relayfour) { | |
myRelays.on(4); | |
} else { | |
myRelays.off(4); | |
} | |
if (!relayfive) { | |
myRelays.off(5); | |
} else { | |
myRelays.on(5); | |
} | |
Particle.publish("kordsbarn", String("scan complete")); | |
} | |
int rs_period = 1200000; // 20 minutes | |
void reset_upload() { | |
// all off defaults solar --> charger (cross wired) | |
if (myRelays.isOn(3)) { | |
Particle.publish("kordsbarn", "solar offline"); | |
} else if (myRelays.isOn(4)) { | |
Particle.publish("kordsbarn", "caps offline"); | |
} else if (myRelays.isOn(5)) { | |
Particle.publish("kordsbarn", "charger offline"); | |
} | |
myRelays.off(3); | |
myRelays.off(4); | |
myRelays.off(5); | |
} | |
// timers | |
Timer check(ct_period, check_timers); | |
Timer scan(ss_period, scan_sensors); | |
Timer rst(rs_period, reset_upload); | |
void setup() | |
{ | |
// cloud vars | |
// curl https://api.particle.io/v1/devices/<device_id>/<variable>?access_token=<access_token> | |
Particle.variable("batvolt", batvolt); | |
Particle.variable("capvolt", capvolt); | |
Particle.variable("solvolt", solvolt); | |
Particle.variable("irsensor", irsensor); | |
Particle.variable("button", button); | |
Particle.variable("mode", mode); | |
Particle.variable("inverter", inverter); | |
Particle.variable("shutdown", shutdown); | |
Particle.variable("batterytemp", batterytemp); | |
Particle.variable("invtimer", inverter_timer); | |
Particle.variable("kordsbarn", kordsbarn); | |
// cloud functions | |
Particle.function("command", switchMode); | |
// relay start | |
myRelays.begin(); | |
// pixel strip start | |
strip.begin(); | |
strip.show(); // Initialize all pixels to 'off' | |
// log some stuff | |
Particle.subscribe("particle/device/name", handler); | |
Particle.publish("particle/device/name"); | |
// start timers | |
check.start(); | |
scan.start(); | |
rst.start(); | |
// relays | |
myRelays.off(3); | |
myRelays.off(4); | |
myRelays.off(5); | |
myRelays.off(6); | |
} | |
void loop() | |
{ | |
// shutdown inverter check | |
if (shutdown) { | |
inverter = 0; | |
} | |
// voltage inputs | |
int multivolt = 0; | |
// sample sensors | |
irsensor = analogRead(IR_PIN); | |
batvolt = analogRead(BATTERY_VOLT_PIN); | |
batterytemp = analogRead(BATTERY_TEMP_PIN); | |
// figure out which voltage we're reading | |
multivolt = analogRead(MULTI_VOLT_PIN); | |
if (myRelays.isOn(3)) { | |
if (myRelays.isOn(4)) { | |
// caps and solar connected | |
capvolt = multivolt; | |
} else { | |
// solar only | |
solvolt = multivolt; | |
} | |
} else { | |
if (myRelays.isOn(4)) { | |
capvolt = multivolt; | |
} else { | |
// nothing connected to sensor | |
} | |
} | |
// sensor smoothing | |
int i = global_timer%20; | |
irs_array[i] = irsensor; | |
bv_array[i] = batvolt; | |
cv_array[i] = capvolt; | |
// no smoothing needed on solar? why? | |
irsensor = batvolt = capvolt = 0; // short circuit | |
// sample and reload | |
for (int i=0; i<20; i++) { | |
irsensor+=irs_array[i]; | |
batvolt+=bv_array[i]; | |
capvolt+=cv_array[i]; | |
} | |
irsensor = irsensor/20; | |
capvolt = capvolt/20; | |
batvolt = batvolt/20; | |
// | |
// from here | |
// capvolt, batvolt, irsensor & solvolt are treated as truths | |
// they may not, however, be consider absolutely true | |
// TODO: provide idea of "truth" via fuzzy logic | |
// EXAMPLE: irsensor triggers randomly | |
// check if solar upload to caps is done | |
if (myRelays.isOn(3) && myRelays.isOn(4) && !myRelays.isOn(5)) { | |
colorBar(calcLeds(multivolt), 0, 0, 200); | |
if (capvolt > 2175) { | |
Particle.publish("kordsbarn", String("caps upload to battery")); | |
myRelays.on(5); | |
} | |
if ((capvolt - 50) < batvolt) { | |
myRelays.off(5); | |
} | |
} | |
// read remaining sensors | |
button = analogRead(BUTTON_PIN); | |
// IR sensor sensing | |
if(irsensor > threshold) { | |
Particle.publish("kordsbarn", String("irsensor trigger")); | |
Particle.publish("kordsbarn", String(irsensor)); | |
// turn on guide light | |
if (inverter == 0) { | |
if (!shutdown) { | |
myRelays.on(6); | |
Particle.publish("kordsbarn", String("inverter online")); | |
inverter = 1; | |
led_timer = 10; // led timer units is seconds | |
colorBar(8, 200, 200, 200); // turn on white light | |
} else { | |
myRelays.off(6); | |
Particle.publish("kordsbarn", String("inverter offline")); | |
inverter = 0; | |
led_timer = 10; | |
colorBar(8, 150, 0, 0); | |
} | |
} | |
inverter_timer = 60; // inverter timer units is seconds | |
} | |
// button on off | |
if (button < 50) { | |
if (shutdown) { | |
colorBar(4, 50, 0, 0); // turn on white light | |
delay(1000); | |
shutdown = 0; | |
colorBar(4, 0, 0, 0); // turn on white light | |
} else { | |
colorBar(4, 0, 0, 50); // turn on white light | |
delay(1000); | |
shutdown = 1; | |
colorBar(4, 0, 0, 0); // turn on white light | |
} | |
} | |
// power warn if less than 70% | |
if(batvolt < 2748) { | |
} | |
// sleep for a bit | |
delay(dt); | |
String output = String("{\"bv\": ") + | |
String(batvolt) + | |
String(", \"cv\": ") + | |
String(capvolt) + | |
String(", \"sv\": ") + | |
String(solvolt) + | |
String(", \"mo\": ") + | |
String(mode) + | |
String(", \"bt\": ") + | |
String(batterytemp) + | |
String(", \"ir\": ") + | |
String(irsensor) + | |
String(", \"iv\": ") + | |
String(inverter) + | |
String(", \"sd\": ") + | |
String(shutdown) + | |
String("}"); | |
kordsbarn = output; | |
// push stats event (consider dt affects this) | |
int period = 30; // every 5 seconds | |
if ( ( global_timer % period ) == 0 && used_timer == 0) { | |
used_timer = 1; | |
Particle.publish("kordsbarn", output); | |
} | |
} | |
int calcLeds(int volts) { | |
int numLeds = 0; | |
if (volts < 1700) { | |
numLeds = 0; | |
} else if (volts < 1775) { | |
numLeds = 1; | |
} else if (volts < 1850) { | |
numLeds = 2; | |
} else if (volts < 1925) { | |
numLeds = 3; | |
} else if (volts < 2000) { | |
numLeds = 4; | |
} else if (volts < 2075) { | |
numLeds = 5; | |
} else if (volts < 2150) { | |
numLeds = 6; | |
} else if (volts < 2200) { | |
numLeds = 7; | |
} else { | |
numLeds = 8; | |
} | |
return numLeds; | |
} | |
int switchMode(String command) | |
{ | |
if (command == "off") { | |
mode = 0; | |
return mode; | |
} | |
if (command == "caps") { | |
if (myRelays.isOn(4)) { | |
myRelays.off(4); | |
Particle.publish("kordsbarn", "caps offline"); | |
} else { | |
myRelays.on(4); | |
Particle.publish("kordsbarn", "caps online"); | |
} | |
return myRelays.isOn(4); | |
} | |
if (command == "solar") { | |
if (myRelays.isOn(3)) { | |
myRelays.off(3); | |
Particle.publish("kordsbarn", "solar offline"); | |
} else { | |
myRelays.on(3); | |
Particle.publish("kordsbarn", "solar online"); | |
} | |
return myRelays.isOn(3); | |
} | |
if (command == "charger") { | |
if (myRelays.isOn(5)) { | |
myRelays.off(5); | |
Particle.publish("kordsbarn", "charger offline"); | |
} else { | |
myRelays.on(5); | |
Particle.publish("kordsbarn", "charger online"); | |
} | |
return myRelays.isOn(5); | |
} | |
if (command == "scan") { | |
scan_sensors(); | |
} | |
if (command == "inverter") { | |
if (!inverter) { | |
inverter_timer = 60; | |
inverter = 1; | |
myRelays.on(6); | |
} else { | |
myRelays.off(6); | |
inverter = 0; | |
inverter_timer = 0; | |
} | |
return inverter; | |
} | |
if (command == "shutdown") { | |
if (shutdown) { | |
shutdown = 0; | |
} else { | |
shutdown = 1; | |
} | |
return shutdown; | |
} | |
} | |
void rainbow(uint8_t wait) { | |
uint16_t i, j; | |
for(j=0; j<256; j++) { | |
for(i=0; i<strip.numPixels(); i++) { | |
strip.setPixelColor(i, Wheel((i+j) & 255)); | |
} | |
strip.show(); | |
delay(wait); | |
} | |
} | |
// show a bar | |
void colorBar(int num2light, int r, int g, int b) { | |
for(uint16_t i=0; i<strip.numPixels(); i++) { | |
if (i<num2light) { | |
// turn on | |
strip.setPixelColor(i, strip.Color(r, g, b)); | |
} else { | |
// turn off | |
strip.setPixelColor(i, strip.Color(0, 0, 0)); | |
} | |
} | |
strip.show(); | |
} | |
// Fill the dots one after the other with a color, wait (ms) after each one | |
void colorWipe(uint32_t c, uint8_t wait) { | |
for(uint16_t i=0; i<strip.numPixels(); i++) { | |
strip.setPixelColor(i, c); | |
strip.show(); | |
delay(wait); | |
} | |
} | |
// Set all pixels in the strip to a solid color, then wait (ms) | |
void colorAll(uint32_t c, uint8_t wait) { | |
uint16_t i; | |
for(i=0; i<strip.numPixels(); i++) { | |
strip.setPixelColor(i, c); | |
} | |
strip.show(); | |
delay(wait); | |
} | |
// Input a value 0 to 255 to get a color value. | |
// The colours are a transition r - g - b - back to r. | |
uint32_t Wheel(byte WheelPos) { | |
if(WheelPos < 85) { | |
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); | |
} else if(WheelPos < 170) { | |
WheelPos -= 85; | |
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); | |
} else { | |
WheelPos -= 170; | |
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); | |
} | |
} | |
void handler(const char *topic, const char *data) { | |
myname = String(data); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment