#include "esp_camera.h" #include #include "esp_http_server.h" #include #include #include #include #include #include // WIFI const char* ssid = "SinceCats"; const char* password = "88888888"; // CAMERA PINS #define PWDN_GPIO_NUM -1 #define RESET_GPIO_NUM -1 #define XCLK_GPIO_NUM 15 #define SIOD_GPIO_NUM 4 #define SIOC_GPIO_NUM 5 #define Y9_GPIO_NUM 16 #define Y8_GPIO_NUM 17 #define Y7_GPIO_NUM 18 #define Y6_GPIO_NUM 12 #define Y5_GPIO_NUM 10 #define Y4_GPIO_NUM 8 #define Y3_GPIO_NUM 9 #define Y2_GPIO_NUM 11 #define VSYNC_GPIO_NUM 6 #define HREF_GPIO_NUM 7 #define PCLK_GPIO_NUM 13 // OLED #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); // SENSOR BH1750 lightMeter; // LED #define LED_PIN 21 #define LED_COUNT 8 Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800); // AHT20 #define AHT20_ADDR 0x38 float temperature = 0; float humidity = 0; // SERVO #define SERVO_PIN 47 Servo myServo; bool isMoving = false; bool isNight = false; unsigned long moveStart = 0; int servoDirection = 90; // STREAM static esp_err_t stream_handler(httpd_req_t *req) { camera_fb_t * fb = NULL; static const char* boundary = "\r\n--frame\r\n"; static const char* type = "multipart/x-mixed-replace;boundary=frame"; static const char* header = "Content-Type: image/jpeg\r\n" "Content-Length: %u\r\n\r\n"; httpd_resp_set_type(req, type); while (true) { fb = esp_camera_fb_get(); if (!fb) continue; httpd_resp_send_chunk(req, boundary, strlen(boundary)); char buf[64]; int hlen = snprintf(buf, sizeof(buf), header, fb->len); httpd_resp_send_chunk(req, buf, hlen); httpd_resp_send_chunk(req, (const char*)fb->buf, fb->len); esp_camera_fb_return(fb); delay(120); } return ESP_OK; } // SERVER httpd_handle_t server = NULL; void startServer() { httpd_config_t config = HTTPD_DEFAULT_CONFIG(); config.server_port = 80; httpd_start(&server, &config); httpd_uri_t uri = { .uri = "/stream", .method = HTTP_GET, .handler = stream_handler, .user_ctx = NULL }; httpd_register_uri_handler(server, &uri); } // CAMERA void initCamera() { 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.pixel_format = PIXFORMAT_JPEG; config.xclk_freq_hz = 20000000; config.frame_size = FRAMESIZE_QVGA; config.jpeg_quality = 18; config.fb_count = 1; if (esp_camera_init(&config) != ESP_OK) { Serial.println("Camera FAIL"); while (true); } sensor_t * s = esp_camera_sensor_get(); s->set_vflip(s, 1); s->set_brightness(s, 1); s->set_whitebal(s, 1); s->set_awb_gain(s, 1); s->set_exposure_ctrl(s, 1); s->set_gain_ctrl(s, 1); } // AHT20 bool readAHT20(float &temp, float &hum) { uint8_t cmd[3] = {0xAC, 0x33, 0x00}; Wire.beginTransmission(AHT20_ADDR); Wire.write(cmd, 3); if (Wire.endTransmission() != 0) return false; delay(80); Wire.requestFrom(AHT20_ADDR, 6); if (Wire.available() < 6) return false; uint8_t data[6]; for (int i = 0; i < 6; i++) { data[i] = Wire.read(); } uint32_t h = ((data[1] << 12) | (data[2] << 4) | (data[3] >> 4)); uint32_t t = ((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]; hum = (h * 100.0) / 1048576.0; temp = (t * 200.0 / 1048576.0) - 50; return true; } // SETUP void setup() { Serial.begin(115200); delay(2000); // CAMERA initCamera(); // WIFI WiFi.begin(ssid, password); WiFi.setSleep(false); while (WiFi.status() != WL_CONNECTED) { delay(300); Serial.print("."); } Serial.println("\nWiFi OK"); Serial.println(WiFi.localIP()); // I2C Wire.begin(1, 2); Wire.setClock(100000); // BH1750 lightMeter.begin(); // OLED if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println("OLED FAIL"); while (true); } display.clearDisplay(); display.setTextSize(1); display.setTextColor(SSD1306_WHITE); // SERVER startServer(); // SERVO myServo.attach(SERVO_PIN); myServo.write(92); // стоп delay(1000); myServo.detach(); Serial.println("SERVO READY"); strip.begin(); strip.show(); strip.setBrightness(80); Serial.println("OPEN /stream"); } void setStripColor(uint8_t r, uint8_t g, uint8_t b) { for (int i = 0; i < LED_COUNT; i++) { strip.setPixelColor(i, strip.Color(r, g, b)); } strip.show(); } // LOOP unsigned long last = 0; void loop() { static float lux = 0; // UPDATE if (millis() - last > 2000) { last = millis(); lux = lightMeter.readLightLevel(); readAHT20(temperature, humidity); Serial.println("----"); Serial.print("Lux: "); Serial.println(lux); Serial.print("Temp: "); Serial.println(temperature); Serial.print("Hum: "); Serial.println(humidity); display.clearDisplay(); display.setCursor(0, 0); display.print("Light: "); display.print(lux); display.println(" lx"); display.print("Temp: "); display.print(temperature); display.println(" C"); display.print("Hum: "); display.print(humidity); display.println(" %"); display.println(); display.print("MODE: "); display.println( isNight ? "NIGHT" : "DAY" ); display.display(); } // NIGHT if (lux < 200 && !isNight) { isNight = true; isMoving = true; moveStart = millis(); servoDirection = 30; } // DAY if (lux >= 200 && isNight) { isNight = false; isMoving = true; moveStart = millis(); servoDirection = 150; } // MOVE if (isMoving) { myServo.attach(SERVO_PIN); if (millis() - moveStart < 5000) { myServo.write(servoDirection); } else { myServo.write(92); // стоп delay(200); myServo.detach(); isMoving = false; } } // WS2812 if (isNight) { // НОЧЬ setStripColor(0, 0, 40); } else { // ДЕНЬ setStripColor(40, 25, 10); } delay(30); }