Аналоговая RGB-полоска с эффектом затухания и NodeMCU

У меня есть аналоговая или немая RGB-лента, которой я управляю с помощью HTTP-команд. Я хочу иметь возможность заставить ленту плавно переходить от одного цвета к другому при вызове http://XX.XXXXX/fade. Я хочу, чтобы это происходило бесконечно, пока не будет установлен другой цвет или она не включится или не выключится. Я пробовал сделать это с помощью цикла while, но больше не могу изменить состояние света с плавного затухания. Кто-нибудь знает, как это сделать? Я приведу ссылку на свой код ниже.

//NodeMCU RGB-Controller for Homebridge & HomeKit (Siri)

#include <ESP8266WiFi.h>

#include <DNSServer.h>
#include <ESP8266WebServer.h>

#define redPin 13 //D7 - Red channel
#define grnPin 12 //D6 - Green channel
#define bluPin 14 //D5 - Blue channel

#define max(a,b) ((a)>(b)?(a):(b))

WiFiServer server(80); //Set server port

String readString;           //String to hold incoming request
String hexString = "FFFFFF"; //Define inititial color here (hex value), 080100 would be a calm warmtone i.e.

int state;

bool fading;

int r;
int g;
int b;

float R;
float G;
float B;

int x;
int V;

///// WiFi SETTINGS - Replace with your values /////////////////
const char* ssid = "SSID";
const char* password = "PASSWORD";
IPAddress ip(XX,X,X,XXX);      // set a fixed IP for the NodeMCU
IPAddress gateway(XX.X.X.X);  // Your router IP
IPAddress subnet(XXX.XXX.XXX.X); // Subnet mask
////////////////////////////////////////////////////////////////////

void WiFiStart() {
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  WiFi.config(ip, gateway, subnet); //Set a fixed IP. You can comment this out and set it in your router instead.
  while (WiFi.status() != WL_CONNECTED) {
    delay(100);
    Serial.print("_");
  }
  Serial.println();
  Serial.println("Done");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  Serial.println("");

  server.begin();                   
}

void allOff() {
  state = 0;
  for (float fade = 1.0; fade >= 0.0; fade -= 0.01) {
    analogWrite(redPin, map((r * fade), 0, 255, 0, 1023));
    analogWrite(grnPin, map((g * fade), 0, 255, 0, 1023));
    analogWrite(bluPin, map((b * fade), 0, 255, 0, 1023));
    delay(2);
  }
  // Set r/g/b to 0 so fade in is possible
  r = 0;
  b = 0;
  g = 0;
}

//Write requested hex-color to the pins
void setHex() {
  const float STEPS = 100; // Change number of steps while fading (lower is faster)
  // Save old values of r/g/b
  byte oldR = r;
  byte oldG = g;
  byte oldB = b;
  long number = (long) strtol( &hexString[0], NULL, 16);
  r = number >> 16;
  g = number >> 8 & 0xFF;
  b = number & 0xFF;
  float deltaR = (r - oldR) / STEPS;
  float deltaG = (g - oldG) / STEPS;
  float deltaB = (b - oldB) / STEPS;
  // Fade to new colour
  for (float f = 0; f < STEPS; f++) {
    analogWrite(redPin, map((oldR + (deltaR * f)), 0, 255, 0, 1023));
    analogWrite(grnPin, map((oldG + (deltaG * f)), 0, 255, 0, 1023));
    analogWrite(bluPin, map((oldB + (deltaB * f)), 0, 255, 0, 1023));
    delay(2);
  }
  state = 1;
}

//Compute current brightness value
void getV() {
  R = roundf(r/2.55);  //was (r/10.23);
  G = roundf(g/2.55);  //was (g/10.23);
  B = roundf(b/2.55);  //was (b/10.23);
  x = max(R,G);
  V = max(x, B);
}

//For serial debugging only
void showValues() {
  Serial.print("Status on/off: ");
  Serial.println(state);
  Serial.print("RGB color: ");
  Serial.print(r);
  Serial.print(".");
  Serial.print(g);
  Serial.print(".");
  Serial.println(b);
  Serial.print("Hex color: ");
  Serial.println(hexString);
  getV();
  Serial.print("Brightness: ");
  Serial.println(V);
  Serial.println("");
}

void setup() {
  Serial.begin(9600);
  delay(1);
  pinMode(redPin, OUTPUT);
  pinMode(grnPin, OUTPUT);
  pinMode(bluPin, OUTPUT);
  WiFi.mode(WIFI_STA);
  WiFiStart();
  setHex();
}

void loop() {
  WiFiClient client = server.available();

  if (!client) {
    return;
  }

  while(client.connected() && !client.available()) {
    delay(1);
  }

  //Respond on certain Homebridge HTTP requests
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        if (readString.length() < 100) {
          readString += c;
        } 
        if (c == '\n') {
          Serial.print("Request: ");
          Serial.println(readString);

          //Send reponse
          client.println("HTTP/1.1 200 OK"); 
          client.println("Content-Type: text/html");
          client.println();

          //On
          if(readString.indexOf("on") >0) {
            setHex();
            showValues();
            fading = false;
          }

          //Off
          if(readString.indexOf("off") >0) {
            allOff();
            showValues();
            fading = false;
          }

          //Fade
          if(readString.indexOf("fade") >0) {
            fade();
            fading = true;
          }

          //Set color
          if(readString.indexOf("set") >0) {
            hexString = "";
            hexString = (readString.substring(9,15));
            setHex();
            showValues();
            fading = false;
          }

          //Status on/off
          if(readString.indexOf("status") >0) {
          client.println(state);
          }

          //Status color (hex)
          if(readString.indexOf("color") >0) {
          client.println(hexString);
          }

          //Status brightness (%)
          if(readString.indexOf("bright") >0) {
          getV();
          client.println(V);
          }

          delay(1);
          client.stop();
          readString="";
        }
      }
    }
  }
}

void fade() {
  while(fading == true){
    hexString = "000000";
    setHex();
    hexString = "FFFFFF";
    setHex();
    hexString = "FF0000";
    setHex();
    hexString = "008000";
    setHex();
    hexString = "0000FF";
    setHex();
    hexString = "FFFF00";
    setHex();
    hexString = "1E1E1E";
    setHex();
   }
 }

, 👍0


1 ответ


Лучший ответ:

0

Переменная fading не может измениться, как только вы находитесь в этом цикле while, поскольку ваш код этого не делает, и вы также не используете прерывания (и я не знаю, поддерживает ли это библиотека). Таким образом, Arduino навсегда застревает в этом цикле и не будет реагировать ни на какие взаимодействия, кроме сброса.

По сути, у вас есть 2 варианта (не считая использования гипотетической возможности прерывания библиотеки Wifi, поскольку я недостаточно знаю об этой библиотеке):

  1. Добавление кода Wifi в цикл while: Вы можете просто добавить код, который отслеживает интерфейс Wifi в цикл while и установить переменную fading соответственно. Это самый простой в программировании вариант.
  2. Перепишите свой код (особенно функцию fade()) так, чтобы он был неблокирующим, то есть он не будет блокировать выполнение другого кода, а будет делать что-то только тогда, когда это нужно, а в противном случае вернётся из функции. Этого можно добиться, используя функцию millis(), которая возвращает миллисекунды с момента последнего запуска/сброса для использования в качестве источника времени. Обратитесь к примеру BlinkWithoutDelay в Arduino IDE. Также вы можете поискать в Google millis(); есть множество руководств. При написании неблокирующего кода вы также можете реализовать конечный автомат (FSM). Это проще, чем кажется. По сути, вы определяете простую переменную, которая задаёт ваше текущее состояние (например, состояния fading, off, specific_color, ...). В вашей функции loop() вы создаете оператор switch(state_variable){ case, где вы вставляете код для каждого состояния в его собственном case. За пределами оператора switch вы можете проверить интерфейс Wifi и установить переменную состояния соответствующим образом. Если все написано неблокируемым, то это должно работать как по волшебству.
,