/*
Loft ladder contoller Copywrite 2012 Daniel Allport and LazyLoft / automAttic
Copywrite Daniel Allport 2012
RELAY MODULE:
When the jumper is shorted, the relay and the input share the same VCC, and when it is open,
a separate power supply must be provided to the JD-VCC jumper to power the relay coil and
optocoupler output.
*/
#define BLYNK_TEMPLATE_ID "TMPLlZkRZJGA"
#define BLYNK_DEVICE_NAME "Lazy Loft"
#define BLYNK_AUTH_TOKEN "cGlnHuD78Zw56Y31yGELMrxs5oVbniov"
#define BOARD_VENDOR "ICG"
#define BLYNK_FIRMWARE_VERSION "20.1"
#define BLYNK_PRINT Serial
#include <SPI.h>
#include <EEPROM.h>
#include <WiFi.h>
#include <WiFiClient.h>
//#include <BlynkSimpleEsp32.h>
#include <RBD_Timer.h>
//#include <RBD_Light.h>
#include <RBD_Button.h>
//#include <arduino-timer.h>
//#include <arduino.h>
#include <BlinkControl.h>
#include <Shifty.h>
//#include <ezLED.h>
#include <WS2812FX.h>
#define LED_PIN 18 //led strip
#define LED_COUNT 30
#define buzzer_pin 13
#define hatch_up_sw 26 // RED COM is WHITE
#define steps_up_sw 25 //RED
#define hatch_dn_sw 33 // BLACK
#define steps_dn_sw 32 //BLU
#define hatch_up 22
#define hatch_down 19
#define steps_up 23
#define steps_down 15
#define resetSw 5
WS2812FX ws2812fx_v1 = WS2812FX(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800,1,1);
WS2812FX ws2812fx_v2 = WS2812FX(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800,1,1);
WS2812FX ws2812fx_p = WS2812FX(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800,1,1);
String states;
bool closeComplete = false;
bool openComplete = false;
int runMode = 1; // 1 = push to run 0 is auto
int buzzerMode = 1; // buzzer control
int lightMode = 1; // strip light
BlinkControl LEDR(12);
BlinkControl LEDG(14);
BlinkControl LEDB(27);
RBD::Button localOpen(16); // INPUT_PULLUP by default
RBD::Button localClose(17);
RBD::Timer autoOpenTimer(100);
RBD::Timer autoCloseTimer(100);
//--------------------- variable initial states----------------------//
bool y = false;
bool x = false;
int stopped;
int locked = 0; // variable for app to disable local control of hatch from switch
int hatch_is_down = 0;
int hatch_is_up = 0;
int steps_are_up = 0;
int steps_are_down = 0;
String info;
int appOpen = 0;
int appClose = 0;
SimpleTimer timer;
char auth[] = BLYNK_AUTH_TOKEN;
char ssid[] = "4G";
char pass[] = "Verify123!";
BLYNK_WRITE(V0) //-----------------------------------------------------------------
{ // Open button
int value = param.asInt();
if (value == 1)
{
Blynk.setProperty(V1, "isDisabled", true);
Blynk.setProperty(V4, "isDisabled", true);
appOpen = 1;
ledDownRoutine(1);
}
if (value == 0)
{
Blynk.setProperty(V1, "isDisabled", false);
Blynk.setProperty(V4, "isDisabled", false);
appOpen = 0;
ledDownRoutine(0);
}
}
BLYNK_WRITE(V1)
{ // Close button
int pinValue = param.asInt();
if (pinValue == 1)
{
Blynk.setProperty(V0, "isDisabled", true);
Blynk.setProperty(V4, "isDisabled", true);
appClose = 1;
ledUpRoutine(1);
}
if (pinValue == 0)
{
Blynk.setProperty(V0, "isDisabled", false);
Blynk.setProperty(V4, "isDisabled", false);
appClose = 0;
ledUpRoutine(0);
}
}
BLYNK_WRITE(V4)
{ // lock
int bValue = param.asInt();
if (bValue == 1)
{
stopped = 1;
locked = 1;
Blynk.setProperty(V0, "isDisabled", true);
Blynk.setProperty(V1, "isDisabled", true);
Blynk.setProperty(V10, "isDisabled", true);
}
else if (bValue == 0)
{
locked = 0;
Blynk.setProperty(V0, "isDisabled", false);
Blynk.setProperty(V1, "isDisabled", false);
Blynk.setProperty(V10, "isDisabled", false);
}
}
BLYNK_WRITE(V10)
{ // Stop button
int pinValue = param.asInt();
if (pinValue == 1)
{
stopped = 1;
Blynk.setProperty(V0, "isDisabled", true);
Blynk.setProperty(V1, "isDisabled", true);
Blynk.setProperty(V4, "isDisabled", true);
}
else if (pinValue == 0)
{
stopped = 0;
Blynk.setProperty(V0, "isDisabled", false);
Blynk.setProperty(V1, "isDisabled", false);
Blynk.setProperty(V4, "isDisabled", false);
}
}
BLYNK_WRITE(V11)
{ // mode select
int v11Value = param.asInt();
if (v11Value == 0) // auto
{
runMode = 1; //
}
if (v11Value == 1) //PTR
{
runMode = 0; //
}
}
BLYNK_WRITE(V12)
{ // buzzer mode select
int v12Value = param.asInt();
if (v12Value == 1)
{
buzzerMode = 1; // buzzer on
}
if (v12Value == 0)
{
buzzerMode = 0; // buzzer off
}
}
BLYNK_WRITE(V13)
{ // light mode select
int v13Value = param.asInt();
if (v13Value == 1)
{
lightMode = 1; // light on
}
if (v13Value == 0)
{
lightMode = 0; // light off
}
}
// BLYNK_WRITE(V6) //-----------------------------------------------------------------
// { // HU
// int value = param.asInt();
// if (value == 1)
// {
// Blynk.setProperty(V7, "isDisabled", true);
// Blynk.setProperty(V8, "isDisabled", true);
// Blynk.setProperty(V9, "isDisabled", true);
// digitalWrite(hatch_up, HIGH);
// }
// if (value == 0)
// {
// Blynk.setProperty(V7, "isDisabled", false);
// Blynk.setProperty(V8, "isDisabled", false);
// Blynk.setProperty(V9, "isDisabled", false);
// digitalWrite(hatch_up, LOW);
// }
// }
// BLYNK_WRITE(V7) //-----------------------------------------------------------------
// { //HD
// int value = param.asInt();
// if (value == 1)
// {
// Blynk.setProperty(V6, "isDisabled", true);
// Blynk.setProperty(V8, "isDisabled", true);
// Blynk.setProperty(V9, "isDisabled", true);
// digitalWrite(hatch_down, HIGH);
// }
// if (value == 0)
// {
// Blynk.setProperty(V6, "isDisabled", false);
// Blynk.setProperty(V8, "isDisabled", false);
// Blynk.setProperty(V9, "isDisabled", false);
// digitalWrite(hatch_down, LOW);
// }
// }
// BLYNK_WRITE(V8) //-----------------------------------------------------------------
// { // SU
// int value = param.asInt();
// if (value == 1)
// {
// Blynk.setProperty(V6, "isDisabled", true);
// Blynk.setProperty(V7, "isDisabled", true);
// Blynk.setProperty(V9, "isDisabled", true);
// digitalWrite(steps_up, HIGH);
// }
// if (value == 0)
// {
// Blynk.setProperty(V6, "isDisabled", false);
// Blynk.setProperty(V7, "isDisabled", false);
// Blynk.setProperty(V9, "isDisabled", false);
// digitalWrite(steps_up, LOW);
// }
// }
// BLYNK_WRITE(V9) //-----------------------------------------------------------------
// { // SD
// int value = param.asInt();
// if (value == 1)
// {
// Blynk.setProperty(V6, "isDisabled", true);
// Blynk.setProperty(V7, "isDisabled", true);
// Blynk.setProperty(V8, "isDisabled", true);
// digitalWrite(steps_down, HIGH);
// }
// if (value == 0)
// {
// Blynk.setProperty(V6, "isDisabled", false);
// Blynk.setProperty(V7, "isDisabled", false);
// Blynk.setProperty(V8, "isDisabled", false);
// digitalWrite(steps_down, LOW);
// }
// }
BLYNK_CONNECTED() //-----------------------------------------------------------------
{
Blynk.syncVirtual(V0, V1, V4, V5, V10, V11, V12, V13);
}
// int stateCheck()
// {
// switch (val)
// {
// case 3730 ... 3770: return 1; break; //HU + SU OPEN 200
// case 3280 ... 3320: return 2; break; //HD + SU OPEN
// case 2980 ... 3020: return 3; break; // HU + HD + SU OPEN
// case 2740 ... 2780: return 4; break;
// default: return 0; break;
// }
// }
/* ========================================================================
// Resistance Readings
case Hu Hd Su Sd | ohm---------------------- |Total R | Reading Val RNG--min---------max
1 0 0 0 0 | 150 470 100 330 | 1050 | 1840 1820 1860
2 0 0 1 0 | 150 470 0 330 | 950 | 1940 1920 1960
3 0 1 0 0 | 150 0 100 330 | 580 | 2000 1980 2020
4 0 1 1 0 | 150 0 0 330 | 480 | 2120 2100 2140
5 0 0 0 1 | 150 470 100 0 | 720 | 2220 2200 2240
6 0 0 1 1 | 150 470 0 0 | 620 | 2360 2340 2380
7 1 0 0 0 | 0 470 100 330 | 900 | 2425 2405 2445
8 0 1 0 1 | 150 0 100 0 | 250 | 2440 2420 2460
9 1 0 1 0 | 0 470 0 330 | 800 | 2610 2590 2630
10 0 1 1 1 | 150 0 0 0 | 150 | 2620 2600 2640
11 1 1 0 0 | 0 0 100 330 | 430 | 2700 2680 2720
12 1 1 1 0 | 0 0 0 330 | 330 | 2910 2890 2930
13 1 0 0 1 | 0 470 100 0 | 570 | 3135 3115 3155
14 1 0 1 1 | 0 470 0 0 | 470 | 3500 3480 3520
15 1 1 0 1 | 0 0 100 0 | 100 | 3700 680 720
16 1 1 1 1 | 0 0 0 0 | 0 | 4095 4075 4115
*/
// if (val >=175 && val <=225)
// {
// Serial.println(" Steps | Hatch ");
// Serial.println(" /\\ | \\/ | /\\ | \\/");
// Serial.println(" 0 | 0 | 0 | 0");
// led_g.pattern(1, 2, SPEED_FAST);
// return 1;
// }
// else if(val >=255 && val <= 350)
// {
// Serial.println("steps closed hatch open");
// Serial.println(" Steps | Hatch ");
// Serial.println(" /\\ | \\/ | /\\ | \\/");
// Serial.println(" 0 | 0 | 0 | 0");
// led_g.pattern(1, 3, SPEED_FAST);
// return 2;
// }
// else if(val >=400 && val <= 480)
// {
// Serial.println("steps open hatch open");
// Serial.println(" Steps | Hatch ");
// Serial.println(" /\\ | \\/ | /\\ | \\/");
// Serial.println(" 0 | 0 | 0 | 0");
// led_g.pattern(1, 4, SPEED_FAST);
// return 3;
// }
// else if(val >=550 && val <= 700)
// {
// Serial.println("steps open hatch open");
// Serial.println(" Steps | Hatch ");
// Serial.println(" /\\ | \\/ | /\\ | \\/");
// Serial.println(" 0 | 0 | 0 | 0");
// led_g.pattern(1, 4, SPEED_FAST);
// return 4;
// }
// else (val <= 50 || value >=800)
// {
// Serial.println("No sensors connected sensor range <50 or >800");
// Serial.println(" Steps | Hatch ");
// Serial.println(" /\\ | \\/ | /\\ | \\/");
// Serial.println(" 0 | 0 | 0 | 0");
// led_g.pattern(1, 1, SPEED_FAST);
// return 0;
// }
// }
void ledDownRoutine(int z)
{
if (z = 1)
{
myCustomShow();
}
else if (z = 0)
{
ws2812fx_p.stop();
}
}
void ledUpRoutine(int z)
{
if (z = 1)
{
myCustomShowReverse();
}
else if (z = 0)
{
ws2812fx_p.stop();
}
}
void hatchDownStart() //-----------------------------------------------------------------
{
if (x)
{
stopped = 1;
Blynk.setProperty(V0, "isDisabled", true); // close disabled
LEDB.on();
LEDR.on();
LEDG.on();
LEDG.blink1();
x = false;
info = "hatch down";
}
digitalWrite(hatch_down, LOW);
}
// void hatchDownStop()
// {
// if (x)
// {
// LEDB.on();
// LEDR.on();
// LEDG.on();
// info = "hatch down stop";
// }
// x = true;
// digitalWrite(hatch_down, HIGH);
// }
void hatchUpStart()
{
if (x)
{
stopped = 1;
LEDB.on();
LEDR.on();
LEDG.on();
LEDR.blink2();
info = "hatch up";
x = false;
}
digitalWrite(hatch_up, LOW);
}
// void hatchUpStop()
// {
// LEDB.on();
// LEDR.on();
// LEDG.on();
// digitalWrite(hatch_up, HIGH);
// info = "hatch up stop";
// x = true;
// }
void stepsDownStart()
{
if (x)
{
stopped = 1;
info = "steps down start";
LEDB.on();
LEDR.on();
LEDG.on();
LEDG.blink2();
x = false;
}
digitalWrite(steps_down, LOW);
}
// void stepsDownStop()
// {
// LEDB.on();
// LEDR.on();
// LEDG.on();
// digitalWrite(steps_down, HIGH);
// info = "steps down stop";
// x = true;
// }
void stepsUpStart()
{
if (x)
{
stopped = 1;
Blynk.setProperty(V1, "isDisabled", true); // open disabled
LEDB.on();
LEDR.on();
LEDG.on();
LEDR.blink2();
info = "steps up start";
x = false;
}
digitalWrite(steps_up, LOW);
}
// void stepsUpStop()
// {
// LEDB.on();
// LEDR.on();
// LEDG.on();
// digitalWrite(steps_up, HIGH);
// x = true;
// info = "steps up stop";
// }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% START OPEN/CLOSE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//******************************* OPEN *******************************
// switches are Normally open
// HIGH IS open
// LOW IS closed
void open() //-----------------------------------------------------------------
{
// hatch down open and steps up closed
if (digitalRead(hatch_dn_sw) == HIGH && digitalRead(steps_up_sw) == LOW)
{
hatchDownStart();
}
else if (digitalRead(hatch_dn_sw) == LOW and digitalRead(steps_dn_sw) == HIGH)
{
hatch_is_down = true;
stepsDownStart();
}
else if (digitalRead(hatch_dn_sw) == LOW and digitalRead(steps_dn_sw) == LOW)
{
steps_are_down = true;
stopped = 1;
info = "open complete";
openComplete = true;
}
else
{
LEDB.on();
LEDR.on();
LEDG.on();
LEDG.fastBlinking();
info = "ERROR 393";
}
}
void close() //-----------------------------------------------------------------
{
// steps up open and hatch down is closed
if (digitalRead(steps_up_sw) == HIGH && digitalRead(hatch_dn_sw) == LOW)
{
stepsUpStart();
Serial.println("hatch down switch closed");
}
// steps up closed and hatch up open
else if (digitalRead(steps_up_sw) == LOW and digitalRead(hatch_up_sw) == HIGH)
{
steps_are_up = true;
hatchUpStart();
Serial.println("steps up switch closed");
}
// steps up closed and hatch up closed
else if (digitalRead(steps_up_sw) == LOW and digitalRead(hatch_up_sw) == LOW)
{
hatch_is_up = true;
stopped = 1;
Serial.println("hatch down switch closed");
info = "close complete";
Serial.println("Close finished");
closeComplete = true;
}
else
{
LEDB.on();
LEDR.on();
LEDG.on();
LEDB.fastBlinking();
info = "ERROR 439";
}
}
void myCustomShow(void) {
// get pointers to all the pixel data arrays
uint8_t *pixels_v1 = ws2812fx_v1.getPixels();
uint8_t *pixels_v2 = ws2812fx_v2.getPixels();
uint8_t *pixels_p = ws2812fx_p.getPixels();
// blend the pixel data from the virtual strips and save it
// to the physical strip
for (uint16_t i=0; i < ws2812fx_p.getNumBytes(); i++) {
pixels_p[i] = (pixels_v1[i] / 2) + (pixels_v2[i] / 2);
}
// Call the physical strip's show() function.
// Note: the virtual strip's show() functions are never called.
ws2812fx_p.Adafruit_NeoPixel::show();
}
void myCustomShowReverse(void) {
// get pointers to all the pixel data arrays
uint8_t *pixels_v1 = ws2812fx_v1.getPixels();
uint8_t *pixels_v2 = ws2812fx_v2.getPixels();
uint8_t *pixels_p = ws2812fx_p.getPixels();
// blend the pixel data from the virtual strips and save it
// to the physical strip
for (uint16_t i=0; i < ws2812fx_p.getNumBytes(); i++) {
pixels_p[i] = (pixels_v1[i] / 2) + (pixels_v2[i] / 2);
}
// Call the physical strip's show() function.
// Note: the virtual strip's show() functions are never called.
ws2812fx_p.Adafruit_NeoPixel::show();
}
void shortTimer() //-----------------------------------------------------------------
{
if (locked == 1)
{
LEDB.on();
LEDR.on();
LEDG.on();
LEDB.fastBlinking();
info = "locked";
}
else
{
control();
ws2812fx_v1.service();
ws2812fx_v2.service();
info = "Ready:";
}
}
void longTimer()
{
Blynk.virtualWrite(V2, info);
Blynk.virtualWrite(V5, states);
digitalRead(steps_dn_sw) == HIGH ? states = "SD:1 " : states = "SD:0";
digitalRead(steps_up_sw) == HIGH ? states.concat(" SU:1 ") : states.concat(" SU:0 ");
digitalRead(hatch_up_sw) == HIGH ? states.concat(" HU:1 ") : states.concat(" HU:0 ");
digitalRead(hatch_dn_sw) == HIGH ? states.concat(" HD:1 ") : states.concat(" HD:0 ");
stopped == 1 ? states.concat(" STP:1 ") : states.concat(" STP:0 ");
runMode == 0 ? states.concat(" Mode:PTR ") : states.concat(" Mode:Auto ");
}
void autoOpen()
{
if (!openComplete && !stopped)
{
if (autoOpenTimer.isStopped() || autoOpenTimer.isExpired())
{
autoOpenTimer.restart();
}
//Blynk.virtualWrite(V0, HIGH);
open();
}
else if (openComplete)
{
//Blynk.virtualWrite(V0, LOW);
//autoOpenTimer.stop();
stopped = 1;
}
}
void autoClose()
{
if (!closeComplete && !stopped)
{
if (autoCloseTimer.isStopped() || autoCloseTimer.isExpired())
{
autoCloseTimer.restart();
}
//Blynk.virtualWrite(V1, HIGH);
close();
}
else if (closeComplete)
{
//Blynk.virtualWrite(V1, LOW);
//autoCloseTimer.stop();
stopped = 1;
}
}
bool stop()
{
digitalWrite(steps_up, HIGH);
digitalWrite(steps_down, HIGH);
digitalWrite(hatch_up, HIGH);
digitalWrite(hatch_down, HIGH);
Blynk.virtualWrite(V0, LOW);
Blynk.virtualWrite(V1, LOW);
x = true;
info = "Stopped";
}
void setup() //-----------------------------------------------------------------
{
Serial.begin(115200);
delay(500);
Blynk.begin(auth, ssid, pass);
timer.setInterval(200L, shortTimer);
timer.setInterval(1000L, longTimer);
LEDR.begin();
LEDG.begin();
LEDB.begin();
LEDB.on();
LEDR.on();
LEDG.on();
states = "";
localOpen.setDebounceTimeout(50);
localClose.setDebounceTimeout(50);
pinMode(hatch_down, OUTPUT);
pinMode(hatch_up, OUTPUT);
pinMode(steps_down, OUTPUT);
pinMode(steps_up, OUTPUT);
pinMode(buzzer_pin, OUTPUT); //active piezo 5v type
pinMode(resetSw, INPUT_PULLUP);
pinMode(hatch_up_sw, INPUT_PULLUP);
pinMode(steps_up_sw, INPUT_PULLUP);
pinMode(steps_dn_sw, INPUT_PULLUP);
pinMode(hatch_dn_sw, INPUT_PULLUP);
//----------- SAFETY set all outputs to off ---------------
digitalWrite(buzzer_pin, HIGH);
digitalWrite(hatch_down, HIGH);
digitalWrite(hatch_up, HIGH);
digitalWrite(steps_down, HIGH);
digitalWrite(steps_up, HIGH);
Blynk.virtualWrite(V10, HIGH);
stopped = 1;
ws2812fx_v1.init();
ws2812fx_v1.setBrightness(64);
ws2812fx_v1.setSegment(0, 0, LED_COUNT-1, FX_MODE_RAINBOW_CYCLE, BLACK, 1000, NO_OPTIONS);
ws2812fx_v1.start();
ws2812fx_v2.init();
ws2812fx_v2.setBrightness(255);
ws2812fx_v2.setSegment(0, 0, LED_COUNT-1, FX_MODE_LARSON_SCANNER, WHITE, 5000, NO_OPTIONS);
ws2812fx_v2.start();
// Initialize the physical strip. Since the physical strip gets
// it's data from the virtual strips, no need to initialize segments.
ws2812fx_p.init();
// Config custom show() functions for the virtual strips, so their
// pixel data gets merged and copied to the physical strip.
ws2812fx_v1.setCustomShow(myCustomShow);
ws2812fx_v2.setCustomShow(myCustomShow);
Serial.println("Waiting for operate request...");
info = "Starting ...";
delay(750);
}
void control()
{
if (runMode == 1)//auto
{
if (appOpen == 1 || (localOpen.onPressed() && !locked))
{
info = "Auto Opening";
autoOpen();
}
else if (appClose == 1 || (localClose.onPressed() && !locked))
{
info = "Auto Closing";
autoClose();
}
}
else if (runMode == 0)//PTR
{
if (appOpen == 1 || (localOpen.isPressed() && !locked))
{
info = "PTR Opening";
open();
}
else if (appClose == 1 || (localClose.isPressed() && !locked))
{
close();
info = "PTR Closing";
}
}
else
{
info = "Ready...";
}
}
void loop() //-----------------------------------------------------------------
{
Blynk.run();
timer.run();
LEDR.loop();
LEDG.loop();
LEDB.loop();
if (stopped)
{
stop();
}
else if (stopped == 0)
{
}
}