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:
mrcory
2022-08-26 17:59:00 -04:00
parent a3d64f7043
commit 28e25b66bc
5 changed files with 260 additions and 197 deletions
+2
View File
@@ -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.)
+5 -2
View File
@@ -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
+6 -6
View File
@@ -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 -1
View File
@@ -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([]() {
+246 -188
View File
@@ -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