Added Basic Home Assistant Control
Shade can be opened or closed via Home Assistant. Blynk and Home Assistant can now be enabled/disabled in the config. Config must be done in code or with Blynk.
This commit is contained in:
@@ -29,6 +29,8 @@ More features, like physical button control, will add a little bit to the cost b
|
||||
### Software
|
||||
* Blynk is used as a remote control for this project.
|
||||
|
||||
* Home Assistant is supported via [home-assistant-integration](https://github.com/dawidchyrzynski/arduino-home-assistant/blob/main/examples/fan/fan.ino).
|
||||
|
||||
* [AccelStepper (Fork)](https://github.com/waspinator/AccelStepper) is used to actually drive the motor. _(This version is available in the library manager.)_
|
||||
|
||||
* [CmdArduino](https://github.com/fakufaku/CmdArduino) is used for control of serial monitor. (A little library I really like.)
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
//Config stuff
|
||||
|
||||
//Friendly Name
|
||||
#define deviceName "Roller Shade"
|
||||
#define deviceName "Roller_Shade"
|
||||
|
||||
//Uncomment to enable wifi manager
|
||||
#define wifiManagerEnable
|
||||
|
||||
//Enable Blynk (Old Version)
|
||||
//#define Blynkenable
|
||||
#define Blynkenable
|
||||
#define rtcBlynk false
|
||||
|
||||
//Enable Home Assistant Integration (Displays as a fan)
|
||||
//Only Supports the shade and not light control
|
||||
#define HAenable
|
||||
|
||||
// Unique ID must be set!
|
||||
byte mac[] = {0x13, 0x10, 0xFA, 0x6E, 0x38, 0x4A};
|
||||
|
||||
//Home Assistant Config
|
||||
#define brokerAddress IPAddress(192,168,254,84) //MQTT Broker Address
|
||||
#define brokerUser "user" //Broker Username
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
bool isOpened = true;
|
||||
|
||||
void configSave() {
|
||||
//Position 400 is reserved for the blynk token
|
||||
@@ -178,11 +178,11 @@ void motorControl() {
|
||||
if (lastPosition < motorPos) {goDown = true;} else {goDown = false;}
|
||||
speedCheck();
|
||||
|
||||
if (motorPos == 1) {stepper.moveTo(shade[0]);}
|
||||
if (motorPos == 2) {stepper.moveTo(shade[1]);}
|
||||
if (motorPos == 3) {stepper.moveTo(shade[2]);}
|
||||
if (motorPos == 4) {stepper.moveTo(shade[3]);}
|
||||
if (motorPos == 5) {stepper.moveTo(shade[4]);}
|
||||
if (motorPos == 1) {stepper.moveTo(shade[0]); isOpened = true;}
|
||||
if (motorPos == 2) {stepper.moveTo(shade[1]); isOpened = false;}
|
||||
if (motorPos == 3) {stepper.moveTo(shade[2]); isOpened = false;}
|
||||
if (motorPos == 4) {stepper.moveTo(shade[3]); isOpened = false;}
|
||||
if (motorPos == 5) {stepper.moveTo(shade[4]); isOpened = false;}
|
||||
Serial.println(F("Blynk Move"));
|
||||
lastPosition = motorPos; //Before reseting motorPos, save a copy to lastPosition
|
||||
motorPos = 0; //Reset motorPos
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
void setupOTA() {
|
||||
ArduinoOTA.onError([](ota_error_t error) { ESP.restart(); });
|
||||
ArduinoOTA.setPassword("admin");
|
||||
ArduinoOTA.setHostname("Shade");
|
||||
ArduinoOTA.setHostname(deviceName);
|
||||
|
||||
|
||||
ArduinoOTA.onStart([]() {
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
/*Roller Shade Control
|
||||
* Created by: Cory McGahee
|
||||
* Free for non-commercial use only
|
||||
*
|
||||
* Home Assistant Code Based From:
|
||||
* https://github.com/dawidchyrzynski/arduino-home-assistant/blob/main/examples/fan/fan.ino
|
||||
*
|
||||
* Designed for use with my 3D printed roller shade.
|
||||
* https://www.thingiverse.com/thing:3628982
|
||||
*
|
||||
* Serial Commands
|
||||
* move <val> | Absolute move in steps
|
||||
* pos <val> | Move to set positions
|
||||
* rst | Reset home position to 0
|
||||
*/
|
||||
Created by: Cory McGahee
|
||||
Free for non-commercial use only
|
||||
|
||||
Home Assistant Code Based From:
|
||||
https://github.com/dawidchyrzynski/arduino-home-assistant/blob/main/examples/fan/fan.ino
|
||||
|
||||
Designed for use with my 3D printed roller shade.
|
||||
https://www.thingiverse.com/thing:3628982
|
||||
|
||||
Serial Commands
|
||||
move <val> | Absolute move in steps
|
||||
pos <val> | Move to set positions
|
||||
rst | Reset home position to 0
|
||||
*/
|
||||
|
||||
#define BLYNK_PRINT Serial
|
||||
|
||||
//version 3.0.0
|
||||
//Version
|
||||
#define softVersion "3.0.0"
|
||||
const int configVersion = 4;
|
||||
int safeConfigVersion = 3; //The oldest version of config that can
|
||||
//be updated from.
|
||||
//be updated from.
|
||||
|
||||
#include "structs.h"
|
||||
|
||||
@@ -27,22 +28,17 @@ bool firstRun = true;
|
||||
bool resetFlag = false;
|
||||
bool configLoadFlag = false;
|
||||
bool configSaveFlag = false;
|
||||
long currentDistance = 0;
|
||||
|
||||
#include <AccelStepper.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
long currentDistance = 0;
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#ifdef Blynkenable0
|
||||
#include <BlynkSimpleEsp8266.h>
|
||||
#endif
|
||||
//#ifdef Blynkenable
|
||||
#include <BlynkSimpleEsp8266.h>
|
||||
//#endif
|
||||
#include <Ethernet2.h>
|
||||
#include "config.h"
|
||||
|
||||
|
||||
|
||||
|
||||
//ArduinoOTA
|
||||
#include <ESP8266mDNS.h>
|
||||
#include <WiFiUdp.h>
|
||||
@@ -51,8 +47,15 @@ long currentDistance = 0;
|
||||
|
||||
//wifiManager
|
||||
#ifdef wifiManagerEnable
|
||||
#include <WiFiManager.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#include <WiFiManager.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAenable
|
||||
#include <ArduinoHA.h>
|
||||
WiFiClient client;
|
||||
HADevice device;
|
||||
HAMqtt mqtt(client, device);
|
||||
#endif
|
||||
|
||||
//FastLED Setup
|
||||
@@ -64,20 +67,21 @@ CRGB leds[NUM_LEDS];
|
||||
|
||||
|
||||
#if cmds //Enable cmdArduino
|
||||
#include <Cmd.h>
|
||||
#include <Cmd.h>
|
||||
#endif
|
||||
|
||||
byte lastPosition = 2; //Storing a starting value
|
||||
|
||||
//Configure AccelStepper
|
||||
#ifdef stepperMini
|
||||
AccelStepper stepper(ctrlType, mtrPin1,mtrPin2,mtrPin3,mtrPin4);
|
||||
#endif
|
||||
|
||||
#ifdef stepperNema
|
||||
AccelStepper stepper = AccelStepper(ctrlType, stepPin, dirPin);
|
||||
AccelStepper stepper(ctrlType, mtrPin1, mtrPin2, mtrPin3, mtrPin4);
|
||||
#endif
|
||||
|
||||
#ifdef stepperNema
|
||||
AccelStepper stepper = AccelStepper(ctrlType, stepPin, dirPin);
|
||||
#endif
|
||||
|
||||
unsigned long lastUp = 0; //Last mqtt push
|
||||
|
||||
long int stepPosition = 0;
|
||||
int connectAttempt = 0;
|
||||
@@ -96,8 +100,8 @@ byte ledMode = 0;
|
||||
bool pulse = false; //Basic effect
|
||||
|
||||
bool lightOn = false;
|
||||
bool lightOld = true;
|
||||
int currentColor[3] = {255,255,255};
|
||||
bool lightOld = true;
|
||||
int currentColor[3] = {255, 255, 255};
|
||||
int pulseSpeed = 2;
|
||||
|
||||
pwmStruct pwm = {
|
||||
@@ -109,93 +113,113 @@ pwmStruct pwm = {
|
||||
};
|
||||
|
||||
#ifdef Blynkenable
|
||||
#include "wifi.h"
|
||||
#include "wifi.h"
|
||||
#endif
|
||||
|
||||
#include "functions.h"
|
||||
|
||||
#ifdef HAenable
|
||||
HACover cover(deviceName);
|
||||
|
||||
void onCoverCommand(HACover::CoverCommand _cmd) {
|
||||
if (_cmd == HACover::CommandOpen) {
|
||||
//Serial.println("Command: Open");
|
||||
cover.setState(HACover::StateOpen, true);
|
||||
motorPos = 1; //Open Shade
|
||||
|
||||
} else if (_cmd == HACover::CommandClose) {
|
||||
//Serial.println("Command: Close");
|
||||
cover.setState(HACover::StateClosed, true);
|
||||
motorPos = 4; //Close Shade
|
||||
|
||||
}else if (_cmd == HACover::CommandStop) {
|
||||
//Serial.println("Command: Stop");
|
||||
cover.setState(HACover::StateStopped);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if buttonEnable //Enable physical buttons
|
||||
|
||||
#include <AnalogButtons.h>
|
||||
#include <AnalogButtons.h>
|
||||
|
||||
//Here we are setting up the fuctions that will be called via the physical buttons.
|
||||
void upClick() {
|
||||
Serial.println("Up Click");
|
||||
if (lastPosition > 1) {
|
||||
lastPosition--;
|
||||
motorPos = lastPosition;
|
||||
Serial.println(motorPos);
|
||||
ledTurn(0);
|
||||
} else {
|
||||
ledTurn(2);
|
||||
}
|
||||
//Here we are setting up the fuctions that will be called via the physical buttons.
|
||||
void upClick() {
|
||||
Serial.println("Up Click");
|
||||
if (lastPosition > 1) {
|
||||
lastPosition--;
|
||||
motorPos = lastPosition;
|
||||
Serial.println(motorPos);
|
||||
ledTurn(0);
|
||||
} else {
|
||||
ledTurn(2);
|
||||
}
|
||||
}
|
||||
|
||||
void upHold() {
|
||||
Serial.println("Up Hold");
|
||||
motorPos = 1;
|
||||
lastPosition = 1;
|
||||
ledTurn(1);
|
||||
}
|
||||
|
||||
void downClick() {
|
||||
Serial.println("Dn Click");
|
||||
if (lastPosition < 4) {
|
||||
lastPosition++;
|
||||
motorPos = lastPosition;
|
||||
Serial.println(motorPos);
|
||||
ledTurn(0);
|
||||
} else {
|
||||
ledTurn(2);
|
||||
}
|
||||
}
|
||||
|
||||
void downHold() {
|
||||
Serial.println("Dn Hold");
|
||||
motorPos = 4;
|
||||
lastPosition = 4;
|
||||
ledTurn(1);
|
||||
}
|
||||
|
||||
void resetClick() {
|
||||
Serial.println("Rst Click");
|
||||
|
||||
if (lightMode == 1) {
|
||||
lightOn = !lightOn;
|
||||
ledBrightness = ledButtonBrightness;
|
||||
}
|
||||
|
||||
void upHold() {
|
||||
Serial.println("Up Hold");
|
||||
motorPos = 1;
|
||||
lastPosition = 1;
|
||||
ledTurn(1);
|
||||
if (lightMode == 0) {
|
||||
pwm.on = !pwm.on;
|
||||
pwm.set = ledButtonBrightness;
|
||||
}
|
||||
|
||||
void downClick() {
|
||||
Serial.println("Dn Click");
|
||||
if (lastPosition < 4) {
|
||||
lastPosition++;
|
||||
motorPos = lastPosition;
|
||||
Serial.println(motorPos);
|
||||
ledTurn(0);
|
||||
} else {
|
||||
ledTurn(2);
|
||||
}
|
||||
}
|
||||
ledTurn(1);
|
||||
}
|
||||
|
||||
void downHold() {
|
||||
Serial.println("Dn Hold");
|
||||
motorPos = 4;
|
||||
lastPosition = 4;
|
||||
ledTurn(1);
|
||||
}
|
||||
void resetHold() {
|
||||
Serial.println("Rst Hold");
|
||||
stepper.setCurrentPosition(0);
|
||||
configSave();
|
||||
ledTurn(1);
|
||||
}
|
||||
|
||||
void resetClick() {
|
||||
Serial.println("Rst Click");
|
||||
//Create tha actual buttons
|
||||
AnalogButtons buttons(buttonPin, INPUT, buttonDebounce, buttonMargin);
|
||||
Button up = Button(upVal, &upClick, &upHold, 1000, 5000);
|
||||
Button down = Button(dnVal, &downClick, &downHold, 1000, 5000);
|
||||
Button rst = Button(rsVal, &resetClick, &resetHold, 2500, 5000);
|
||||
|
||||
if (lightMode == 1) {
|
||||
lightOn = !lightOn;
|
||||
ledBrightness = ledButtonBrightness;
|
||||
}
|
||||
|
||||
if (lightMode == 0) {
|
||||
pwm.on = !pwm.on;
|
||||
pwm.set = ledButtonBrightness;
|
||||
}
|
||||
|
||||
ledTurn(1);
|
||||
}
|
||||
|
||||
void resetHold() {
|
||||
Serial.println("Rst Hold");
|
||||
stepper.setCurrentPosition(0);
|
||||
configSave();
|
||||
ledTurn(1);
|
||||
}
|
||||
|
||||
//Create tha actual buttons
|
||||
AnalogButtons buttons(buttonPin, INPUT,buttonDebounce,buttonMargin);
|
||||
Button up = Button(upVal, &upClick, &upHold, 1000, 5000);
|
||||
Button down = Button(dnVal, &downClick, &downHold, 1000, 5000);
|
||||
Button rst = Button(rsVal, &resetClick, &resetHold, 2500, 5000);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef Blynkenable
|
||||
#if rtcBlynk //Enable the RTC feature from Blynk
|
||||
//Blynk RTC
|
||||
#include <WidgetRTC.h>
|
||||
WidgetRTC RTC;
|
||||
BlynkTimer timer1;
|
||||
#endif
|
||||
#if rtcBlynk //Enable the RTC feature from Blynk
|
||||
//Blynk RTC
|
||||
#include <WidgetRTC.h>
|
||||
WidgetRTC RTC;
|
||||
BlynkTimer timer1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "lightcontrol.h"
|
||||
@@ -204,68 +228,92 @@ void setup() {
|
||||
Serial.begin(74880);
|
||||
delay(50);
|
||||
|
||||
#ifdef wifiManagerEnable
|
||||
// WiFiManager intialization.
|
||||
WiFiManager wifi;
|
||||
#endif
|
||||
#ifdef HAenable
|
||||
WiFi.begin();
|
||||
WiFi.macAddress(mac);
|
||||
device.setUniqueId(mac, sizeof(mac));
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
analogWrite(PWM_PIN,0);
|
||||
|
||||
#ifdef wifiManagerEnable
|
||||
// WiFiManager intialization.
|
||||
WiFiManager wifi;
|
||||
#endif
|
||||
|
||||
|
||||
analogWrite(PWM_PIN, 0);
|
||||
|
||||
if (lightMode == 1) { //Use FastLED if selected
|
||||
FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS);
|
||||
FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS);
|
||||
}
|
||||
|
||||
pinMode(ledPin,OUTPUT);
|
||||
digitalWrite(ledPin,LOW);
|
||||
|
||||
#if buttonEnable
|
||||
buttons.add(up);
|
||||
buttons.add(down);
|
||||
buttons.add(rst);
|
||||
#endif
|
||||
pinMode(ledPin, OUTPUT);
|
||||
digitalWrite(ledPin, LOW);
|
||||
|
||||
#if cmds //Define our serial commands if enabled
|
||||
cmdInit(&Serial);
|
||||
cmdAdd("move",manualMove);
|
||||
cmdAdd("rst",homePos);
|
||||
cmdAdd("pos",pos);
|
||||
#endif
|
||||
#if buttonEnable
|
||||
buttons.add(up);
|
||||
buttons.add(down);
|
||||
buttons.add(rst);
|
||||
#endif
|
||||
|
||||
#ifdef wifiManagerEnable
|
||||
// Create AP, if necessary
|
||||
wifi.autoConnect(myHostName);
|
||||
|
||||
// Set WIFI module to STA mode
|
||||
WiFi.mode( WIFI_STA );
|
||||
#endif
|
||||
|
||||
#if cmds //Define our serial commands if enabled
|
||||
cmdInit(&Serial);
|
||||
cmdAdd("move", manualMove);
|
||||
cmdAdd("rst", homePos);
|
||||
cmdAdd("pos", pos);
|
||||
#endif
|
||||
|
||||
#ifdef Blynkenable
|
||||
blynkConfig();
|
||||
#endif
|
||||
#ifdef wifiManagerEnable
|
||||
// Create AP, if necessary
|
||||
wifi.autoConnect(myHostName);
|
||||
|
||||
// Set WIFI module to STA mode
|
||||
WiFi.mode( WIFI_STA );
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef Blynkenable
|
||||
blynkConfig();
|
||||
#endif
|
||||
setupOTA();
|
||||
|
||||
EEPROM.begin(eepromSize); //Initialize the EEPROM with our selected size
|
||||
|
||||
if (EEPROM.read(0) == 1 && returnConfigVersion() == configVersion) { //If flagged in EEPROM; we load our current position
|
||||
if (EEPROM.read(0) == 1 && returnConfigVersion() >= safeConfigVersion) { //If flagged in EEPROM; we load our current position
|
||||
configLoad();
|
||||
Serial.println("Pass Config Version Check");
|
||||
} else {
|
||||
Serial.println("Fail Config Version Check, Reseting To Default");
|
||||
configSave();
|
||||
|
||||
|
||||
}
|
||||
|
||||
#ifdef Blynkenable
|
||||
#if rtcBlynk
|
||||
//Using Blynk to get the time
|
||||
RTC.begin();
|
||||
setSyncInterval(blynkRtcInterval);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAenable
|
||||
device.setName(deviceName);
|
||||
device.setSoftwareVersion(softVersion);
|
||||
|
||||
cover.onCommand(onCoverCommand);
|
||||
mqtt.begin(brokerAddress, brokerUser, brokerPass);
|
||||
|
||||
/*
|
||||
if (lastPosition > 1) { //If down, set state as such.
|
||||
cover.setState(HACover::StateClosed, true);
|
||||
} else { //Else set as open
|
||||
cover.setState(HACover::StateOpen, true);
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef Blynkenable
|
||||
#if rtcBlynk
|
||||
//Using Blynk to get the time
|
||||
RTC.begin();
|
||||
setSyncInterval(blynkRtcInterval);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
stepper.setMaxSpeed(mSpeed.up);
|
||||
stepper.setAcceleration(mSpeed.accel);
|
||||
|
||||
@@ -273,8 +321,8 @@ void setup() {
|
||||
|
||||
motorOff();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Serial.print(F("Loaded | Position S|C : ")); Serial.print(savedPosition); Serial.print("|"); Serial.println(stepper.currentPosition());
|
||||
if (lightMode == 1) { //Use FastLED if selected
|
||||
FastLED.setBrightness(ledBrightness);
|
||||
@@ -284,31 +332,41 @@ void setup() {
|
||||
|
||||
|
||||
void loop() {
|
||||
#ifdef HAenable
|
||||
mqtt.loop();
|
||||
|
||||
if (millis() - lastUp > 3000) { //Send state every 3 seconds
|
||||
if (lastPosition > 1) { //If down, set state as such.
|
||||
cover.setPosition(0);
|
||||
} else { //Else set as open
|
||||
cover.setPosition(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
pwm.old = pwm.set;
|
||||
currentDistance = stepper.distanceToGo();
|
||||
|
||||
|
||||
if (ledFeedback == true) {
|
||||
ledFeedbackf();
|
||||
}
|
||||
|
||||
#if cmds
|
||||
cmdPoll();
|
||||
#endif
|
||||
|
||||
#if buttonEnable
|
||||
buttons.check(); //Check for button presses
|
||||
#endif
|
||||
#if cmds
|
||||
cmdPoll();
|
||||
#endif
|
||||
|
||||
#if buttonEnable
|
||||
buttons.check(); //Check for button presses
|
||||
#endif
|
||||
|
||||
|
||||
//If not moving, run extra features
|
||||
if (stepper.distanceToGo() == 0) {
|
||||
|
||||
#ifdef Blynkenable
|
||||
blynkRun(); //Only run blynk when the stepper is not active
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef Blynkenable
|
||||
blynkRun(); //Only run blynk when the stepper is not active
|
||||
#endif
|
||||
|
||||
if (setHome == true) {
|
||||
resetHold(); //Set current position as home
|
||||
setHome = false;
|
||||
@@ -320,38 +378,38 @@ void loop() {
|
||||
if (ledBrightness != pwm.old) {
|
||||
FastLED.setBrightness(ledBrightness);
|
||||
}
|
||||
|
||||
FastLED.show();
|
||||
}
|
||||
|
||||
if (lightMode == 0) {
|
||||
if (pwm.set != pwm.old) {
|
||||
analogWrite(PWM_PIN,pwm.set);
|
||||
pwm.old = pwm.set;
|
||||
FastLED.show();
|
||||
}
|
||||
|
||||
if (lightMode == 0) {
|
||||
if (pwm.set != pwm.old) {
|
||||
analogWrite(PWM_PIN, pwm.set);
|
||||
pwm.old = pwm.set;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef stepperNema
|
||||
brakeCheck();
|
||||
#endif
|
||||
|
||||
#ifdef stepperNema
|
||||
brakeCheck();
|
||||
#endif
|
||||
|
||||
stepper.run(); //AccelStepper runs here
|
||||
motorControl();
|
||||
ArduinoOTA.handle();
|
||||
|
||||
if (resetFlag == true) {
|
||||
ESP.reset();
|
||||
}
|
||||
|
||||
if (configLoadFlag == true) {
|
||||
configLoad();
|
||||
configLoadFlag = false;
|
||||
}
|
||||
|
||||
if (configSaveFlag == true) {
|
||||
configSave();
|
||||
configSaveFlag = false;
|
||||
}
|
||||
if (resetFlag == true) {
|
||||
ESP.reset();
|
||||
}
|
||||
|
||||
if (configLoadFlag == true) {
|
||||
configLoad();
|
||||
configLoadFlag = false;
|
||||
}
|
||||
|
||||
if (configSaveFlag == true) {
|
||||
configSave();
|
||||
configSaveFlag = false;
|
||||
}
|
||||
|
||||
} //END LOOP
|
||||
|
||||
Reference in New Issue
Block a user