top of page

Week 6: Merge of Motor Code with App Data & Testing

Vasyl

The motor functionality was added to the received phone app data. The motor was set up to turn in approximately 20 degrees at a time depending on the input received from the user. The manual mode open blinds from closed position to 100 degrees (letting in maximum amount of light to the room), meanwhile, the custom mode will set the blinds to specific blinds angle. The addition of the motor to the Arduino code is shown below.

After connecting the Arduino Nano to the blinds, phone app was used to communicate to the blinds. The connection was established and the manual mode was tested. The blinds were set in the closed position before starting the test, when the "DOWN" button was pressed, the blinds opened, but with a much larger angle then anticipated. This was corrected by adjusting the steps per revolution, which fixed the large angle incrementation. Unfortunately, when the "UP" button was pressed, the blinds did not close by 20 degrees but opened by another 20 degrees. After many attempts to rectify this issue, it was deemed that current set up of the code should be reworked in the way the current angle of the blinds is not calculated by angle of blinds, but position of the blinds (0-6). This way when calculating the new angle of the blinds, the negative step can be taken into account.

Unfortunately due to this set back, the CUSTOM mode was not tested since angle of the blinds is being taken into account the same way. Once the MANUAL mode is working, the CUSTOM mode can be tested. Currently the new fix is applied to 50% of the code and further testing will be conducted as soon as Wednesday.

Jordan and I ran into issue with boost converter not working correctly and sending too much current to the motor. It should be noted that pins 8, 9 on Arduino were always ON after first signal was sent to the motor module. This caused the motor to get hot and these pins staying high will be addressed in the code.




#include <Arduino.h>

#include <TimeLib.h>

#include <Stepper.h>

#include <SoftwareSerial.h>


// Define Bluetooth RX and TX pins

const int BT_RX = 2; // Bluetooth TX to Arduino RX

const int BT_TX = 3; // Bluetooth RX to Arduino TX


SoftwareSerial BTSerial(BT_RX, BT_TX);


enum BlindsMode { A, M, C };

BlindsMode currentMode = A;

String currentLumenRange = "A5"; // Default lumen for AUTO mode


int blindsAngle = 0; // 0 = fully closed, 100 = fully open (degrees)

const int angleStep = 20; // step size of increment

const int maxBlindsAngle = 100; // max blinds angle


//motor stuff

const int stepsPerRevolution = 1024; // change this to fit the number of steps per revolution

const int rolePerMinute = 10; // Adjustable range of 28BYJ-48 stepper is 0~17 rpm


// initialize the stepper library on pins 8 through 11:

Stepper myStepper(stepsPerRevolution, 8, 10, 9, 11);


const int stepsPerDegree = stepsPerRevolution / 360;

const int stepsPerRotation = stepsPerDegree * 1000;

//end motor stuff


//initialize manual mode max timers, count of timers, and struct to store incomming timers

const int maxTimers = 10; // Maximum number of timers we can store

int timerCount = 0; // Number of timers currently stored

struct Timer {

int startHour;

int startMinute;

int endHour;

int endMinute;

int angle;

};


Timer customTimers[maxTimers]; // Array to store multiple custom mode timers


void setup() {

Serial.begin(9600);

BTSerial.begin(9600);


Serial.println("Waiting for time data from Bluetooth...");


//motor stuff

myStepper.setSpeed(rolePerMinute);

}


void loop() {

if (BTSerial.available()) {

String data = BTSerial.readStringUntil('\n');


//print to COM incomming data from bluetooth

Serial.print("Received data: ");

Serial.println(data); // Print the raw data received


if (data.startsWith("T:")) {

// Format: T:HH:MM:SS

String timeString = data.substring(2);

int hour, minute, second;

if (sscanf(timeString.c_str(), "%d:%d:%d", &hour, &minute, &second) == 3) {

setTime(hour, minute, second, day(), month(), year());

Serial.print("Time set to: ");

Serial.println(timeString);

} else {

Serial.println("Invalid time format received.");

}

} else if (data.startsWith("MODE:")) {

// Format: MODE:A/M/C

String modeString = data.substring(5);

if (modeString == "A") {

currentMode = A;

Serial.println("Mode set to AUTOMATIC");

} else if (modeString == "M") {

currentMode = M;

Serial.println("Mode set to MANUAL");

} else if (modeString == "C") {

currentMode = C;

Serial.println("Mode set to CUSTOM");

} else {

Serial.println("Invalid mode received.");

}

} else if (data.startsWith("L:")) { //AUTO mode

// Format: L:A1 - L:A6

String lumenRange = data.substring(2);

if (lumenRange == "A1" || lumenRange == "A2" || lumenRange == "A3" ||

lumenRange == "A4" || lumenRange == "A5" || lumenRange == "A6") {

currentLumenRange = lumenRange;

Serial.print("Lumen range set to: ");

Serial.println(currentLumenRange);

} else {

Serial.println("Invalid lumen range received.");

}

} else if (data.startsWith("M:")) { //manual mode

// Format: M:U or M:D this is manual mode up/ down received from App

String blindsCommand = data.substring(2);

if (blindsCommand == "D") { //to open blinds

moveBlindsByStep(angleStep);

} else if (blindsCommand == "U") { //to close blinds

moveBlindsByStep(0-angleStep);

} else {

Serial.println("Invalid blinds command received.");

}

} else if (data.startsWith("C:")) { //custom mode

// Format: C:hh:mm,hh:mm,angle,C:hh:mm,hh:mm,angle,...,

clearTimers(); // Clear existing timers before adding new ones

parseTimers(data);

printTimers(); // Print currently saved timers

}

}


// Which mode is used

switch (currentMode) {

case A:

// Automatic mode

handleAutomaticMode();

break;

case M:

// Manual mode behavior

handleManualMode();

break;

case C:

// Custom mode behavior

handleCustomMode();

break;

}


delay(1); // Adjust as needed

}


// automatic mode

void handleAutomaticMode() {

Serial.print("Running in AUTOMATIC mode with lumen range: ");

Serial.println(currentLumenRange);

int currentLumens = readLumensSensor(); // function reading lumens


if (currentLumenRange == "A1" && currentLumens >= 0 && currentLumens < 300) {

// lumen range A1 (0-300)

Serial.println("Adjusting blinds for lumen range A1 (0-300)");

adjustBlindsForLumens(currentLumens);

} else if (currentLumenRange == "A2" && currentLumens >= 300 && currentLumens < 600) {

// lumen range A2 (300-600)

Serial.println("Adjusting blinds for lumen range A2 (300-600)");

adjustBlindsForLumens(currentLumens);

} else if (currentLumenRange == "A3" && currentLumens >= 600 && currentLumens < 900) {

// lumen range A3 (600-900)

Serial.println("Adjusting blinds for lumen range A3 (600-900)");

adjustBlindsForLumens(currentLumens);

} else if (currentLumenRange == "A4" && currentLumens >= 900 && currentLumens < 1200) {

// lumen range A4 (900-1200)

Serial.println("Adjusting blinds for lumen range A4 (900-1200)");

adjustBlindsForLumens(currentLumens);

} else if (currentLumenRange == "A5" && currentLumens >= 1200 && currentLumens < 1500) {

// lumen range A5 (1200-1500)

Serial.println("Adjusting blinds for lumen range A5 (1200-1500)");

adjustBlindsForLumens(currentLumens);

} else if (currentLumenRange == "A6" && currentLumens >= 1500 && currentLumens < 1800) {

// lumen range A6 (1500-1800)

Serial.println("Adjusting blinds for lumen range A6 (1500-1800)");

adjustBlindsForLumens(currentLumens);

} else {

Serial.println("Current lumens not within the specified range.");

}

} //end AUTO


//manual mode selected

void handleManualMode() {

// manual mode

Serial.println("Running in MANUAL mode...");

} //end manual


//custom mode selected

void handleCustomMode() {

Serial.println("Running in CUSTOM mode...");


// Check the current time against custom mode timers

int currentHour = hour();

int currentMinute = minute();


Timer* latestTimer = nullptr;


//loop through all the timers to see if any of them match

for (int i = 0; i < timerCount; i++) {

if (isTimeWithinRange(currentHour, currentMinute, customTimers[i].startHour, customTimers[i].startMinute, customTimers[i].endHour, customTimers[i].endMinute)) {

latestTimer = &customTimers[i]; // Use the latest timer within range

}

}

if (latestTimer != nullptr) {

moveBlindsToAngle(latestTimer->angle);

}

} //end custom


//display time in COM

void digitalClockDisplay() {

Serial.print(hour());

printDigits(minute());

printDigits(second());

Serial.println();

}


//if time is under 10, add 0 before that value

void printDigits(int digits) {

Serial.print(":");

if (digits < 10)

Serial.print('0');

Serial.print(digits);

}


//reading sensors

int readLumensSensor() {

// function to read lumens from a sensor

// sensor reading code

return analogRead(A0); // Example analog read

}


//adjusting blinds based on read lumens in AUTO mode

void adjustBlindsForLumens(int lumens) {

// function to adjust blinds based on lumens

// actual motor code

Serial.print("Adjusting blinds for lumens: ");

Serial.println(lumens);

}


//move blinds by step, used for MANUAL mode

void moveBlindsByStep(int angleStep) {

int newAngle = blindsAngle + angleStep;

newAngle = constrain(newAngle, 0, maxBlindsAngle);

if (angleStep < 0)

moveBlinds(-angleStep);

else if (angleStep > 0)

moveBlinds(angleStep);

}


//move blinds to angle, used for CUSTOM mode

void moveBlindsToAngle(int angle) {

int steps = (angle) * stepsPerDegree;

myStepper.step(steps);

blindsAngle = angle;

}


//adjusting blinds by angle of 20*

void moveBlinds(int angle) {

int steps = angle * stepsPerDegree;

myStepper.step(steps);

blindsAngle = angle;

//print blinds angle to screen

Serial.print("Moving blinds to angle: ");

Serial.println(angle);

}


//check if current time in range of timers

bool isTimeWithinRange(int currentHour, int currentMinute, int startHour, int startMinute, int endHour, int endMinute) {

if (startHour < endHour || (startHour == endHour && startMinute < endMinute)) {

// Normal time range

return (currentHour > startHour || (currentHour == startHour && currentMinute >= startMinute)) &&

(currentHour < endHour || (currentHour == endHour && currentMinute <= endMinute));

} else {

// Overnight time range

return (currentHour > startHour || (currentHour == startHour && currentMinute >= startMinute)) ||

(currentHour < endHour || (currentHour == endHour && currentMinute <= endMinute));

}

}


//clear CUSTOM mode data

void clearTimers() {

timerCount = 0; // Reset timer count to clear current timers

}


//seperating input data for Custom Mode, where C: is detected for custom mode and ',' end marker

void parseTimers(String data) {

int timerIndex = 0;

int startIndex = 0;

int endIndex = data.indexOf(',');


while (endIndex != -1 && timerIndex < maxTimers) {

String timerString = data.substring(startIndex, endIndex);

Serial.print("Received timer string: ");

Serial.println(timerString); // Print the raw timer string received


int startHour, startMinute, endHour, endMinute, angle;

if (sscanf(timerString.c_str(), "C:%d:%d-%d:%d-%d", &startHour, &startMinute, &endHour, &endMinute, &angle) == 5) {

customTimers[timerCount] = {startHour, startMinute, endHour, endMinute, angle};

timerCount++;

Serial.print("Timer added: ");

Serial.println(timerString);

} else {

Serial.println("Invalid timer format received.");

}


//start reading next timer received and skip ','

startIndex = endIndex + 1;

endIndex = data.indexOf(',', startIndex);

timerIndex++;

}

} // end Custom Parsing data


//printing current timers to COM

void printTimers() {

Serial.println("Currently saved timers:");

for (int i = 0; i < timerCount; i++) {

Serial.print("Timer ");

Serial.print(i + 1);

Serial.print(": ");

Serial.print(customTimers[i].startHour);

Serial.print(":");

Serial.print(customTimers[i].startMinute);

Serial.print(" - ");

Serial.print(customTimers[i].endHour);

Serial.print(":");

Serial.print(customTimers[i].endMinute);

Serial.print(" Angle: ");

Serial.println(customTimers[i].angle);

}

}



7 views0 comments

Recent Posts

See All

Week 8

Had the Flu from Tuesday to Saturday. Vasyl ordered and delivered a new solar panel, charge controller and battery for me to implement...

Comments


bottom of page