ESP32-Grow-Cam um über Daisy-Chain die Lampe zu steuern

Ja, es geht hier um Cannabis und einer ESP32-Cam (mit OV5640) die über Daisy-Chain (wird so von den Herstellen genannt) die LED-Grow-Lampe zu steuern. Um Energie zu sparen und da es ein Kamera ist, auch noch alle Zeit lang ein Foto machen. Daraus kann man dann einen Zeitrafferfilm machen.

Inzwischen ist noch ein DHT22 hinzu gekommen, um die Temperatur und Luftfeuchtigkeit zu messen und dokumentieren.

Um genügend Pins frei zu haben wird die SD-Karte im 1-Bit-Modus betrieben.

Da die Kamera, wenn alles angeschlossen ist, nicht bootet. Was ganz normal ist, da einige Pins zum booten bestimmte zustände (High/Low) haben müssen. Hier habe ich einfach einen "CD4066B CMOS Quad Bilateral Switch" genommen. Der soll, jetzt noch nicht im Programm und auch nicht in der Schaltung, dann die Signale als erstes im Frei geben (DHT22 und DAC anschließen) kurz warten und dann das Programm ausführen.

#include "esp_camera.h"
#include "FS.h"
#include "SD_MMC.h"
#include <WiFi.h>
#include <WebServer.h>
#include <EEPROM.h>
#include <Wire.h>
#include <DHTesp.h>  // DHT22 Bibliothek

// WiFi credentials
const char* ssid = "XXXXXXXXXX";
const char* password = "XXXXXXXXXXXX";

// WebServer
WebServer server(80);

// Camera settings
#define PWDN_GPIO_NUM    32
#define RESET_GPIO_NUM   -1
#define XCLK_GPIO_NUM    0
#define SIOD_GPIO_NUM    26
#define SIOC_GPIO_NUM    27
#define Y9_GPIO_NUM      35
#define Y8_GPIO_NUM      34
#define Y7_GPIO_NUM      39
#define Y6_GPIO_NUM      36
#define Y5_GPIO_NUM      21
#define Y4_GPIO_NUM      19
#define Y3_GPIO_NUM      18
#define Y2_GPIO_NUM      5
#define VSYNC_GPIO_NUM   25
#define HREF_GPIO_NUM    23
#define PCLK_GPIO_NUM    22

// DHT22 Einstellungen
#define DHTPIN 16  // Verwende GPIO 4 für den DHT22 ist aber auch Flashlight, das sollte abgeklebt oder ausgelötet werden. Oder GPIO 16, hier Bootbedingung beachten.
DHTesp dht;  // DHT22 (Temperatur- und Luftfeuchtigkeitsmodul) Bibliothek

// I2C Einstellungen für PCF8591
#define SDA_PIN 12  // GPIO 12 für SDA nutzbar da SD-Karte im 1-Bit modus läuft
#define SCL_PIN 13  // GPIO 13 für SCL nutzbar da SD-Karte im 1-Bit modus läuft
#define PCF8591_I2C_ADDRESS 0x48  // Standardadresse über jumper setzbar
int analogOutput = 0;  // Initalisierung des analogen Ausgangs
float analogPercent = 0;  // Prozentskalierung

// Timers und SD-Karte
unsigned long lastPictureTime = 0;
int pictureInterval = 900000;  // Standart minutes (900000 ms)
int pictureCounter = 0;
String lastImagePath = "";

// EEPROM Einstellungen um den Analogwert zu speichern (damit nach neustart nicht wieder auf 0 steht)
#define EEPROM_SIZE 1

// Funktion zur Konfiguration der Kamera
void startCameraServer() {
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sccb_sda = SIOD_GPIO_NUM;
  config.pin_sccb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;

  if (psramFound()) {
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }
}

// Foto aufnehmen und auf SD-Karte speichern
void captureAndSavePicture() {
  camera_fb_t *fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("Camera capture failed");
    return;
  }

  // Einzigartiger Benennung der Bilder
  String path = "/picture" + String(pictureCounter++) + ".jpg";
  Serial.println("Saving picture to: " + path);

  // Öffne die Datei im Schreibmodus
  File file = SD_MMC.open(path.c_str(), FILE_WRITE);
  if (!file) {
    Serial.println("Failed to open file in writing mode");
    esp_camera_fb_return(fb);  // Gib den Framebuffer sofort frei, wenn das Speichern fehlschlägt
    return;
  }

  // Schreibe das Bild in die Datei
  file.write(fb->buf, fb->len);
  file.close(); // Schließe die Datei nach dem Schreiben
  esp_camera_fb_return(fb); // Gib den Framebuffer nach dem Schreiben frei

//  delay(100);  // Kurze Verzögerung für das Dateisystem

  lastImagePath = path; // Setze den Pfad für das neueste Bild
  Serial.println("Picture saved: " + path);
}

// WebServer Hauptseite
void handleRoot() {
  String html = "<html><body>";
  html += "<h1>ESP32-CAM</h1>";

  // Zeige das letzte Bild
  if (lastImagePath != "") {
    html += "<h2>Last Image</h2>";
    //html += "<img src=\"/image?path=" + lastImagePath + "\" width=\"320\">"; // Bildpfad mit neuer Route
    html += "<img src=\"/image?path=" + lastImagePath + "&timestamp=" + String(millis()) + "\" width=\"320\">"; 
  }

  // Schaltfläche zur manuellen Bildaufnahme
  html += "<button onclick=\"takePicture()\">Manuelles Bild aufnehmen</button>";
  
  html += "<script>";
  html += "function takePicture() {";
  html += "  fetch('/capture').then(response => {";
  html += "    if (response.ok) {";
  html += "      alert('Bild wurde aufgenommen!');";
  html += "      setTimeout(() => location.reload(), 500);"; // Seite neu laden nach 500ms, um das neue Bild anzuzeigen
  html += "    } else {";
  html += "      alert('Fehler beim Aufnehmen des Bildes.');";
  html += "    }";
  html += "  });";
  html += "}";
  html += "</script>";

  // Intervall Einstellungen
  html += "<h2>Set Picture Interval (min)</h2>";
  html += "<form action=\"/setinterval\" method=\"POST\">";
  html += "<input type=\"number\" name=\"interval\" min=\"15\" max=\"120\" step=\"15\" value=\"" + String(pictureInterval / 60000) + "\">";
  html += "<input type=\"submit\" value=\"Set Interval\">";
  html += "</form>";

  // Analoger Ausgang
  html += "<h2>Analog Output (" + String(analogPercent) + "%)</h2>";
  html += "<form action=\"/setanalog\" method=\"POST\">";
  html += "<input type=\"range\" name=\"analog\" min=\"0\" max=\"100\" step=\"1\" value=\"" + String(analogPercent) + "\">";
  html += "<input type=\"submit\" value=\"Set Value\">";
  html += "</form>";

  // DHT22 Datenanzeige
  TempAndHumidity data = dht.getTempAndHumidity();
  html += "<h2>Temperature: " + String(data.temperature) + " °C</h2>";
  html += "<h2>Humidity: " + String(data.humidity) + " %</h2>";

  html += "</body></html>";
  server.send(200, "text/html", html);
}

// Funktion des intervall Schalters
void handleSetInterval() {
  if (server.hasArg("interval")) {
    pictureInterval = server.arg("interval").toInt() * 60000; // convert to ms
    lastPictureTime = millis();  // reset timer
  }
  server.sendHeader("Location", "/");
  server.send(303);
}

// Funktion für den analog Ausgng
void handleSetAnalog() {
  if (server.hasArg("analog")) {
    analogPercent = server.arg("analog").toFloat();
    analogOutput = map(analogPercent, 0, 100, 0, 255);  // scale to 8-bit

    // Senden der DAC Daten zum PCF8591
    Wire.beginTransmission(PCF8591_I2C_ADDRESS);
    Wire.write(0x40);  // Byte zur Konfiguration des analogen Ausgangs
    Wire.write(analogOutput);  // DAC Ausgangs Daten (0-255)
    Wire.endTransmission();

    EEPROM.write(0, analogOutput);
    EEPROM.commit();
  }
  server.sendHeader("Location", "/");
  server.send(303);
}

void handleCapture() {
  captureAndSavePicture();  // Bild aufnehmen und speichern
  lastImagePath = "/picture" + String(pictureCounter - 1) + ".jpg";  // Aktualisiere Pfad für das letzte Bild
  server.send(200, "text/plain", "Bild aufgenommen");
}

void setup() {
  Serial.begin(19200);

  // Initialisierung EEPROM
  EEPROM.begin(EEPROM_SIZE);
  analogOutput = EEPROM.read(0);
  analogPercent = map(analogOutput, 0, 255, 0, 100);

  // Initialisierung der I2C pins zur Kommunikation
  Wire.begin(SDA_PIN, SCL_PIN);  // Setze I2C auf die Pins die oben gesetzt wurden (SDA und SCL)

  // Schreibe gesetzte DAC Daten in den EEPROM speicher
  Wire.beginTransmission(PCF8591_I2C_ADDRESS);
  Wire.write(0x40);  // Byte zur Konfiguration des analogen Ausgangs
  Wire.write(analogOutput);
  Wire.endTransmission();

  // Initialisiere den DHT22 Sensor
  dht.setup(DHTPIN, DHTesp::DHT22);  // Initialisiere DHT22

  // Initialisiere die SD-Karte im 1-Bit Modus
  if (!SD_MMC.begin("/sdcard", true)) {  // 1-Bit Modus aktivieren
    Serial.println("SD Card Mount Failed");
    return;
  }

  // Initialisiere Kamera
  startCameraServer();

  // Mit W-LAN verbinden
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }

  // Ausgabe der IP-Adresse im Seriellen Monitor
  Serial.println("Connected to WiFi. IP address: ");
  Serial.println(WiFi.localIP());

  // Starte den WebServer
  server.on("/", handleRoot);
  server.on("/setinterval", HTTP_POST, handleSetInterval);
  server.on("/setanalog", HTTP_POST, handleSetAnalog);
  server.on("/capture", HTTP_GET, handleCapture);  // Neue Route für manuelle Bildaufnahme
  server.on("/image", HTTP_GET, []() {
    if (server.hasArg("path")) {
      String path = server.arg("path");
      File file = SD_MMC.open(path);
      if (!file) {
        server.send(404, "text/plain", "Bild nicht gefunden.");
        return;
      }
      server.streamFile(file, "image/jpeg");
      file.close();
      } else {
        server.send(400, "text/plain", "Pfad fehlt.");
        }
      });
  server.begin();

  // Initialisierung Bildaufnahme
  captureAndSavePicture();
}

void loop() {
  server.handleClient();

  // Fotoaufnahme intervall Steuerung
  if (millis() - lastPictureTime > pictureInterval) {
    captureAndSavePicture();
    lastPictureTime = millis();
  }
}

Wie bekomme ich es hin, das die Schaltfläche für die manuelle Aufnahme unter dem Bild ist? Und ja, ich muss noch den Pfad für das letzte Bild speichern, damit sie beim neustart nicht wieder bei 0 beginnt.

Hilfe ist definitv erwünscht! Bin SEHR bald 50 Jahre alt und hatte über 25Jahre nichts mehr mit Programmieren zu tun. Fast alles per Copy and Paste :face_with_hand_over_mouth:

1 Like

Für die, die sich auch daran veruchen wollen, hier mal die Verdrahtung.

@thirty-thirty Wir haben ähnliche ziele ESP32-Dev als Grow-Computer darum verknüpfe ich das mal.

1 Like

Dein Button wird doch im (html)String ganz oben eingefügt? Dann pack in nach unten.

Im englischen Teil des Forum müssen die Beiträge und Diskussionen in englischer Sprache verfasst werden.
Deswegen wurde diese Diskussion in den deutschen Teil des Forums verschoben.

mfg ein Moderator.

1 Like

Und Du glaubst wir sind jünger?? Das war für mich schon einige Jahre her.
Grüße Uwe

Aber meine letzten Berührungen mit Arduino und Atmel sind über 20 Jahre her. Deswegen tue ich mir da sehr schwer. Die Cam läuft immer noch nicht. Ich bekomme immer nur veraltete Bilder (wohl ein Puffer Problem in meinem Code) und das Booten der Cam läuft auch nicht so wie es soll. Aber nur wenn alles angeschlossen ist. Ich lasse zur Zeit nur mit einem ESP32-1732S019 nur die Analoge Spannung ausgeben und steuere mein Licht damit.

Da ich jetzt noch ein Möglichkeit gefunden habe das ganze ohne PCF8591 zu realisieren, warte ich nur noch bis mein jetziger Grow zu ende ist und mache mich dann ans umschreiben.

Hier mal der zur Zeitige Code:

#include "WiFi.h"
#include <WebServer.h>
#include <EEPROM.h>
#include <Wire.h>
#include "DHT.h"

// WiFi credentials
const char* ssid = "SSID";
const char* password = "W-LAN Passwort";

// WebServer
WebServer server(80);

// Den benötigten Sensor definieren, die ander auskommentieren
// #define DHTTYPE DHT11   // DHT 11
// #define DHTTYPE DHT21   // DHT 21 (AM2301)
// #define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321

// DHT Sensor
// #define DHTPin 38
// DHT dht(DHTPin, DHTTYPE);

// float Temperature;
// float Humidity;

// I2C Einstellungen für PCF8591
#define SDA_PIN 4
#define SCL_PIN 5
#define PCF8591_I2C_ADDRESS 0x48

int analogOutput = 0;  
float analogPercent = 0;  

// EEPROM Einstellungen
#define EEPROM_SIZE 1

// WebServer Hauptseite
void handleRoot() {
  String html = "<html><body>";
  html += "<h1>ESP32-Daisy_Chain</h1>";
  html += "<br><br>"; 

  // Analoger Ausgang
  html += "<h2>Analog Output (" + String(analogPercent) + "%)</h2>";
  html += "<form action=\"/setanalog\" method=\"POST\">";
  html += "<input type=\"range\" name=\"analog\" min=\"0\" max=\"100\" step=\"1\" value=\"" + String(analogPercent) + "\">";
  html += "<input type=\"submit\" value=\"Set Value\">";
  html += "</form>";

  // DHT22 Datenanzeige
//  Temperature = dht.readTemperature();
//  Humidity = dht.readHumidity();
//  html += "<h2>Temperature: " + String(Temperature) + " °C</h2>";
//  html += "<h2>Humidity: " + String(Humidity) + " % RLF</h2>";

  html += "</body></html>";
  server.send(200, "text/html", html);
}

// Funktion für den analogen Ausgang
void handleSetAnalog() {
  if (server.hasArg("analog")) {
    analogPercent = server.arg("analog").toFloat();
    analogOutput = map(analogPercent, 0, 100, 0, 255);

    // Senden der DAC Daten zum PCF8591
    Wire.beginTransmission(PCF8591_I2C_ADDRESS);
    Wire.write(0x40);
    Wire.write(analogOutput);
    Wire.endTransmission();

    EEPROM.write(0, analogOutput);
    EEPROM.commit();
  }
  server.sendHeader("Location", "/");
  server.send(303);
}

void setup() {
  Serial.begin(115200);

  // Initialisierung EEPROM
  EEPROM.begin(EEPROM_SIZE);
  analogOutput = EEPROM.read(0);
  analogPercent = map(analogOutput, 0, 255, 0, 100);

  // Initialisierung der I2C-Pins
  Wire.begin(SDA_PIN, SCL_PIN);

  // Schreibe gespeicherte DAC-Daten in den PCF8591
  Wire.beginTransmission(PCF8591_I2C_ADDRESS);
  Wire.write(0x40);
  Wire.write(analogOutput);
  Wire.endTransmission();

  // Initialisiere den DHT22 Sensor
//  dht.begin();

  // Mit W-LAN verbinden
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }

  Serial.println("Connected to WiFi. IP address: ");
  Serial.println(WiFi.localIP());

  // Starte den WebServer
  server.on("/", handleRoot);
  server.on("/setanalog", HTTP_POST, handleSetAnalog);
  
  server.begin();
}

void loop() {
  server.handleClient();  // WebServer-Anfragen verarbeiten
}

Hier der test Code für Analoge Spannung ohne PCF8591 (wohl ein Standart-Programm):

void setup() {
  //setup on pin 18 with frequency 312500 Hz
  sigmaDeltaAttach(16, 312500);
  //set pin 18 to off
  sigmaDeltaWrite(16, 0);
}

void loop() {
  //slowly ramp-up the value
  //will overflow at 256
  static uint8_t i = 0;
  sigmaDeltaWrite(16, i++);
  delay(2000);
}

Den DHT22 wollte ich dann auch wieder mit rein nehmen und mir Temp, RLF und VPD anzeigen zu lassen.

Habe auch versucht mehrer Bilder zu machen und mit Zeitstempel abspeichern zu lassen, auf SD und dann auf Fritzbox. Immernoch das Problem das immer das vorletzte Bild aus dem Cam-Buffer geholt wird.

Bei dem versuch mit MPEG war es ein Standbild in Videoform. Aber ich bin auch erst wieder am reinkommen und leider habe ich auch nicht so viel Zeit dafür wie ich möchte und bräuchte!

#include "esp_camera.h"
#include <WiFi.h>
#include "ESP32_FTPClient.h"
#include <NTPClient.h>
#include <WiFiUdp.h>

// Kamera-Pin-Konfiguration (AI-Thinker-Modell)
#define PWDN_GPIO_NUM  32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM  0
#define SIOD_GPIO_NUM  26
#define SIOC_GPIO_NUM  27

#define Y9_GPIO_NUM    35
#define Y8_GPIO_NUM    34
#define Y7_GPIO_NUM    39
#define Y6_GPIO_NUM    36
#define Y5_GPIO_NUM    21
#define Y4_GPIO_NUM    19
#define Y3_GPIO_NUM    18
#define Y2_GPIO_NUM     5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM  23
#define PCLK_GPIO_NUM  22

// 4 for flash led or 33 for normal led
#define LED_GPIO_NUM   4

// WLAN-Zugangsdaten
const char* ssid = "SSID";
const char* password = "W-Lan Passwort";

// FTP-Zugangsdaten
char ftp_server[] = "192.168.178.1"; // IP-Adresse der Fritzbox
char ftp_user[] = "Fritzbox-Benutzer";
char ftp_pass[] = "Benutzerpasswort";
char ftp_path[] = "/";

// NTP-Client initialisieren
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 3600, 60000); // Zeitzone +1 (3600 Sekunden)

// FTP-Client initialisieren
ESP32_FTPClient ftp(ftp_server, ftp_user, ftp_pass);

void setup() {
  Serial.begin(115200);

  // WLAN-Verbindung herstellen
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWLAN verbunden!");

  // Zeit einmalig synchronisieren
  syncTime();

  // Kamera initialisieren
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;

  if (psramFound()) {
    config.frame_size = FRAMESIZE_VGA; // 640x480
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_VGA; // 640x480
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

  // Kamera starten
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Kamera-Initialisierung fehlgeschlagen: 0x%x\n", err);
    return;
  }
  Serial.println("Kamera bereit!");
}

void loop() {
  static unsigned long last_cycle = 0;
  if (millis() - last_cycle > 10 * 1000) { // Alle 10 Minuten
    last_cycle = millis();

    // Zeit synchronisieren
    syncTime();

    // Einzelnes Bild aufnehmen und mehrfach hochladen
    testFTPConnection();
  }
}

void syncTime() {
  Serial.println("Synchronisiere Zeit...");
  if (!timeClient.update()) {
    Serial.println("Fehler: Zeit konnte nicht synchronisiert werden!");
  } else {
    Serial.printf("Zeit synchronisiert: %lu\n", timeClient.getEpochTime());
  }
}

void testFTPConnection() {
  // Einzelnes Bild aufnehmen
  camera_fb_t* fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("Fehler: Kein Bild aufgenommen");
    return;
  }

  // Zeit abrufen und Dateinamen erstellen
  int currentEpoch = timeClient.getEpochTime();
  if (currentEpoch <= 0) {
    Serial.println("Fehler: Keine gültige Zeit verfügbar!");
    esp_camera_fb_return(fb);
    return;
  }

  struct tm* timeinfo = localtime((time_t*)&currentEpoch);
  char filename[64];
  snprintf(filename, sizeof(filename), "%04d%02d%02d_%02d%02d%02d.jpg",
           timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday,
           timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);

  Serial.printf("Bild aufgenommen: %s, Größe: %d Bytes\n", filename, fb->len);

  // FTP-Verbindung testen
  ftp.OpenConnection();
  delay(8000);
  ftp.ChangeWorkDir(ftp_path);

  for (int i = 0; i < 5; i++) {
    char testFilename[64];
    snprintf(testFilename, sizeof(testFilename), "test_%d_%s", i, filename);

    Serial.printf("Hochladen von Datei: %s\n", testFilename);
    ftp.InitFile("TYPE I");
    ftp.NewFile(testFilename);
    ftp.WriteData(fb->buf, fb->len);
    Serial.printf("Datei %s hochgeladen\n", testFilename);
  }

  ftp.CloseConnection();
  esp_camera_fb_return(fb);
}

Ja geht mir auch so

Da mit will ich mich auch noch auseinander setzen. Es müsste sich ja eigentlich um ein PWM Signal handeln. Wenn ich da was rauskriege werde ich das hier und auf github veröffentlichen.

Für mich ist der Umgang mit Microcontroller völliges Neuland habe an die zehn Bücher gekauft um in dieses Thema (mit 43 Jahren) reinzukommen.

Nein, das ist eine normale analoge Spannung von 0 - 10 V. Vor 2022 gab es noch verschiedene Arten, aber inzwischen sind alle gleich. Aber das kann man auch mit einem PWM-Signal und einen Passfilter realisieren.

Meine Steuerung mit dem ESP32-1732S019 läuft einwandfrei. Funktioniert an meiner Viparspectra sowie an MarsHydro, Spiderfarmer und Philson. An mehr habe ich es noch nicht getestet.

Kleiner Hinweis noch. Bei z.B. Viparspectra habe ich die P2000 da ist es egal auf welchem Kanal die Spannung ist (es reicht einer) und die ganze Lampe wird heller und dunkeler, genau so bei der XS-Serie. Bei der XS Pro- und der KS-Serie kann man mit einem Kanal das Veggi-Spektrum und mit dem anderen Kanal das Blüte-Spektrum unterschiedlich steuern. [Da muss man aber erst einmal einen Growshop finden, der einem das Testen lässt.] Allerdings bezieht sich das wissen auf die 2023'er Versionen. Ob es da Änderungen gibt, weiß ich nicht.

1 Like

Hätte ich nicht gedacht werde ich gleich mal messen gehen! Danke.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.