Код: #include <Arduino.h> #include <ESP8266WiFi.h> #include <ESP8266mDNS.h> #include <WiFiUdp.h> #include <ArduinoOTA.h> #include <EEPROM.h> #include <SinricPro.h> #include <SinricProBlinds.h> #include <AccelStepper.h>
#include "credentials.h" // WIFI_SSID, WIFI_PASS, APP_KEY, APP_SECRET, BLINDS_ID
//#define LEFT_BLIND
#ifdef LEFT_BLIND #define IN1 D1 #define IN2 D3 #define IN3 D2 #define IN4 D4 #else #define IN1 D4 #define IN2 D2 #define IN3 D3 #define IN4 D1 #endif
#define BUTTON_UP_PIN D5 #define BUTTON_DOWN_PIN D6 #define LED_PIN D7 #define BUILTIN_LED D0 #define POTENTIOMETER A0
#define BAUD_RATE 115200 #define DEBOUNCE_TIME 300 #define EEPROM_SAVE_DELAY 3000 #define MAX_STEPS 500 #define MIN_STEPS 10 #define DEFAULT_STEPS 200 #define POTENTIOMETER_THRESHOLD 3 #define MAX_SPEED 800 #define ACCELERATION 500 #define POSITION_REPORT_INTERVAL 5000 #define POT_TIMEOUT 300000 // 5 минути
AccelStepper stepper(AccelStepper::FULL4WIRE, IN1, IN3, IN2, IN4); int blindsPosition = 0; int blindsTarget = 0; bool powerState = true; int stepsPerPercent = DEFAULT_STEPS; unsigned long lastPress = 0; bool stepsChanged = false; unsigned long stepsChangeTime = 0; int lastPotValue = -100; unsigned long lastPositionReport = 0; bool sinricProConnected = false; bool externalControl = false; unsigned long lastExternalControl = 0; const unsigned long EXTERNAL_CONTROL_TIMEOUT = 10000; int virtualPotPosition = 0; unsigned long lastPotMoveTime = 0;
void handleButtons(); void handlePotentiometer(); void loadStepsFromEEPROM(); void saveStepsToEEPROM(); void indicateFullRotations(); void handleMovement(); void reportPosition(); void calibrateStepper(); void setupWiFi(); void setupSinricPro(); void updateSinricPosition();
bool onPowerState(const String &deviceId, bool &state) { powerState = state; if (!powerState && stepper.isRunning()) stepper.stop(); return true; }
bool onRangeValue(const String &deviceId, int &position) { externalControl = true; lastExternalControl = millis(); blindsTarget = position;
if (millis() - lastPotMoveTime > POT_TIMEOUT) { virtualPotPosition = position; lastPotValue = position; } return true; }
bool onAdjustRangeValue(const String &deviceId, int &positionDelta) { externalControl = true; lastExternalControl = millis(); blindsTarget += positionDelta; positionDelta = blindsTarget;
if (millis() - lastPotMoveTime > POT_TIMEOUT) { virtualPotPosition = blindsTarget; lastPotValue = blindsTarget; } return true; }
void setupWiFi() { Serial.begin(BAUD_RATE); WiFi.begin(WIFI_SSID, WIFI_PASS); while (WiFi.status() != WL_CONNECTED) { delay(500); } ArduinoOTA.setHostname("SmartBlinds"); ArduinoOTA.begin(); }
void setupSinricPro() { SinricProBlinds &myBlinds = SinricPro[BLINDS_ID]; myBlinds.onPowerState(onPowerState); myBlinds.onRangeValue(onRangeValue); myBlinds.onAdjustRangeValue(onAdjustRangeValue); SinricPro.onConnected([]() { sinricProConnected = true; updateSinricPosition(); }); SinricPro.onDisconnected([]() { sinricProConnected = false; }); SinricPro.begin(APP_KEY, APP_SECRET); }
void setupPins() { pinMode(BUTTON_UP_PIN, INPUT_PULLUP); pinMode(BUTTON_DOWN_PIN, INPUT_PULLUP); pinMode(LED_PIN, OUTPUT); pinMode(BUILTIN_LED, OUTPUT); pinMode(POTENTIOMETER, INPUT); }
void loadStepsFromEEPROM() { EEPROM.begin(4); EEPROM.get(0, stepsPerPercent); EEPROM.end(); if(stepsPerPercent < MIN_STEPS || stepsPerPercent > MAX_STEPS) stepsPerPercent = DEFAULT_STEPS; }
void saveStepsToEEPROM() { EEPROM.begin(4); EEPROM.put(0, stepsPerPercent); EEPROM.commit(); EEPROM.end(); stepsChanged = false; }
void indicateFullRotations() { digitalWrite(LED_PIN, HIGH); delay(300); digitalWrite(LED_PIN, LOW); }
void handleButtons() { unsigned long currentMillis = millis(); if(currentMillis - lastPress < DEBOUNCE_TIME) return;
if(digitalRead(BUTTON_UP_PIN) == LOW) { stepsPerPercent = min(stepsPerPercent + 10, MAX_STEPS); stepsChanged = true; stepsChangeTime = currentMillis; lastPress = currentMillis; indicateFullRotations(); } if(digitalRead(BUTTON_DOWN_PIN) == LOW) { stepsPerPercent = max(stepsPerPercent - 10, MIN_STEPS); stepsChanged = true; stepsChangeTime = currentMillis; lastPress = currentMillis; indicateFullRotations(); } if(stepsChanged && (currentMillis - stepsChangeTime > EEPROM_SAVE_DELAY)) saveStepsToEEPROM(); }
// FIXED POTENTIOMETER HANDLING void handlePotentiometer() { static unsigned long lastPotRead = 0; unsigned long currentMillis = millis(); if (currentMillis - lastPotRead < 100) return; lastPotRead = currentMillis;
int potValue = analogRead(POTENTIOMETER); int mappedValue = map(potValue, 0, 1023, 0, 100);
// Ако разликата е значителна или сме близо до виртуалната позиция if (abs(mappedValue - lastPotValue) > POTENTIOMETER_THRESHOLD) { lastPotMoveTime = currentMillis; blindsTarget = mappedValue; virtualPotPosition = mappedValue; lastPotValue = mappedValue; } }
void updateSinricPosition() { if (!sinricProConnected) return; SinricProBlinds &myBlinds = SinricPro[BLINDS_ID]; myBlinds.sendRangeValueEvent(blindsPosition); lastPositionReport = millis(); }
void handleMovement() { static long targetSteps = 0; static int lastReportedPosition = -1; if (!powerState) { if (stepper.isRunning()) stepper.stop(); return; }
if (blindsTarget != blindsPosition) { targetSteps = (long)blindsTarget * stepsPerPercent; stepper.moveTo(targetSteps); } if (stepper.distanceToGo() != 0) stepper.run(); else if (blindsPosition != blindsTarget) { blindsPosition = blindsTarget; if (blindsPosition != lastReportedPosition) { updateSinricPosition(); lastReportedPosition = blindsPosition; } } }
void calibrateStepper() { stepper.setMaxSpeed(MAX_SPEED); stepper.setAcceleration(ACCELERATION); stepper.moveTo(100 * stepsPerPercent); while (stepper.distanceToGo() != 0) { stepper.run(); delay(1); } delay(1000); stepper.moveTo(0); while (stepper.distanceToGo() != 0) { stepper.run(); delay(1); } stepper.setCurrentPosition(0); blindsPosition = 0; blindsTarget = 0; }
void setup() { setupPins(); loadStepsFromEEPROM(); stepper.setMaxSpeed(MAX_SPEED); stepper.setAcceleration(ACCELERATION); setupWiFi(); setupSinricPro(); calibrateStepper(); }
void loop() { ArduinoOTA.handle(); SinricPro.handle(); handleButtons(); handlePotentiometer(); handleMovement(); if (sinricProConnected && (millis() - lastPositionReport > POSITION_REPORT_INTERVAL)) updateSinricPosition(); }
|