Skip to content

Instantly share code, notes, and snippets.

@kordless
Last active December 13, 2017 17:41
Show Gist options
  • Save kordless/f228d45495652a066d695de5905e5c79 to your computer and use it in GitHub Desktop.
Save kordless/f228d45495652a066d695de5905e5c79 to your computer and use it in GitHub Desktop.
#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];
}
#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 #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