The NeoEyes NE101 is a low-power, AI-enabled vision camera designed for modern embedded applications. This compact module is built around the ESP32-S3 and a high-res OV5640 camera, this module delivers efficient image capture and lightweight vision capabilities at the edge. While it handles essential tasks like motion detection, snapshots, and basic image streaming
Let’s face it: most camera modules consume blindly and do little else. NeoEyes NE101? It doesn’t just snap pictures—it streams, serves, and responds. And it pulls all that off with typical active current draw in the range of 180–350 mA, depending on the use case (Wi-Fi streaming, flash enabled, or image capture). In deep sleep mode, it drops to <1 mA, making it suitable for battery-powered deployments.
🧃 Built around the ESP32-S3 with OV5640 camera, it’s a controller that works smarter—not harder.
Perfect for:
- 🚪 Smart security systems
- 📦 Delivery detection
- 🤖 Gesture interfaces
- ☁️ Real-time alerts through Telegram (because why not have a cam that DMs you?)
Here is the in-depth image
- 🧠 ESP32-S3 MCU - Dual-core Xtensa processor @240MHz with 16MB Flash and 8MB PSRAM
- 📸 OV5640 Camera Module - Supports up to 2592×1944 resolution with selectable 120° or 77° field of view and macro/normal focus options
- 💡 Warm Light Fill Flash - Integrated LED with photosensitive sensor for low-light image capture
- 🔘 One-Touch Snapshot Button - Manual trigger for instant image capture
- 📶 Wireless Communication - Built-in Wi-Fi (802.11b/g/n) and Bluetooth 5 (LE), Expandable with Cat-1 Cellular or Wi-Fi HaLow modules
- 🔋 Low-Power Design - Optimized for battery-powered deployments (4×AA batteries supported)
- 🌦️ Weatherproof Housing (IP67) - Durable enclosure for outdoor use in harsh environments
- 🔌Type-C Debug Port - For UART-based debugging and development
- 🔗 Expandable I/O Interfaces - Includes UART, I2C, GPIO, SPI, and external alarm/PIR input
- 🧰 Modular & Open Source - Swappable lenses, communication modules, and open SDK with MQTT support
- 🎯 NeoEyes NE101 Camera Module - Featuring a built-in low-power AI processor and OV5640 image sensor, with integrated PIR motion detection.
- 🔌 UVC-Compatible Camera Module - An additional camera for enhanced visual interfacing or dual-stream setups.
- 🧰 Mounting Hardware - Screws and brackets for secure installation into custom or ready-made enclosures.
- 🔋 Battery Pack - Supports Supports 4×AA batteries, enabling reliable off-grid or mobile operation.
Camera Configuration – CamThink NeoEyes NE101
The CamThink NeoEyes NE101 is equipped with a default OV5640 image sensor for onboard AI-based image processing
Along with a UVC-compatible camera module for basic visual interfacing.
Additionally, the development board includes a dedicated provision to connect an external UVC camera module.
For enhanced image quality and sharper visuals, users have the option to upgrade to this external UVC module—ideal for applications requiring higher-resolution output or dual-camera setups.
📡 Flexible Connectivity Beyond Wi-Fi
While CamThink NeoEyes NE101 comes with built-in Wi-Fi (802.11 b/g/n), its design doesn’t stop there. The system includes dedicated provisions for adding customizable, swappable communication modules—giving you the flexibility to choose what's best for your deployment environment.
Whether you're working in remote areas, industrial zones, or simply want more robust connectivity, you can expand NE101 with:
Cat-1 Cellular Modules Enable wide-area communication using LTE networks for real-time remote monitoring and alerts—without relying on local Wi-Fi infrastructure.
Wi-Fi HaLow Modules Ideal for long-range, low-power wireless communication in dense environments such as factories, farms, or smart cities.
This modular approach future-proofs your setup and unlocks advanced deployment options—whether you're off-grid, beyond traditional Wi-Fi reach, or integrating with enterprise IoT frameworks.
🚀 🛠️ Step-by-Step Guide: CamThink NeoEyes NE101 Telegram Security Camera 📸💬NeoEyes NE101 Hardware — All Set, All Secured 🔐📦One of the best things about the CamThink NeoEyes NE101 is that it arrives fully integrated — no breadboards, no tangled wires, no DIY enclosure drama. Everything is pre-connected and ready to roll, including:
- ✅ Camera + Dev Board pre-mounted
- 🔋 Battery system (4×AA) already in place for mobile deployment
- ☔ IP67-rated waterproof enclosure to handle rain, dust, and outdoor exposure
- 🧰 Mounting braces and screws included for quick installation on walls or brackets
- 🧠 Internal wiring is handled — no external cables to manage between board and camera
Just power it up, configure your capture settings, and your Telegram alerts are ready to go. It’s a true plug-and-protect device — field-ready right out of the box.
Telegram Bot ConfigurationSetting up Telegram alerts is easier than you'd think — no coding acrobatics required! Just follow these steps:
1.Create Your Bot
- Open Telegram and search for BotFather
- Use
/newbot
to create one and follow the prompts - Copy your Bot Token — it’s your bot’s secret handshake 🤖🔑
2.Get Your Chat ID
- Start a chat with your bot by clicking its link from BotFather
- Send any message (like "Hi!")
- Use this to check the status of the bot
https://api.telegram.org/bot<YourBotToken>/getUpdates
- Copy your Chat ID from the response from the Userinfo bot.
- Clone this project from the Git Repo.
- Update your code with your Wi-Fi SSID, password.
- Select the Board as ESP32S3 Dev Module.
- And flash the firmware to the NeoEyes NE101 and look at the serial monitor.
- NeoEyes NE101 will automatically connect to the WiFi and it will start serving the camera feed into the mentioned IP.
- Now you can be able to see the camera feed.
A static IP address ensures your NeoEyes NE101 always connects to the same IP on your network—no surprises, no guesswork. This is especially useful for a security camera setup, where you want reliable access to the live feed or endpoints for integration.
Here’s why it matters:
- 🔗 Consistent Access: No need to check or discover your camera’s IP each time—it stays fixed.
- 🌐 Remote Access & Port Forwarding: Static IPs make it easier to set up external access (like viewing your cam from the web).
- 🤖 Bot/Web Service Integration: If you’re using Telegram or MQTT, your bot knows exactly where to find the camera.
- 📁 Logging & Automation: Static IPs allow scripts and services to interact with the device reliably.
In short: it’s like giving your camera a permanent address in the local network so your Telegram alerts and web server never get lost in the crowd. 🏠📸
Just use this updated code to setup the Static IP address.
#include "esp_camera.h"
#include <WiFi.h>
// ===========================
// Enter your WiFi credentials
// ===========================
const char *ssid = "";
const char *password = "";
// ===========================
// Static IP Configuration
// ===========================
IPAddress local_IP(192, 168, 1, 184); // Set your desired IP
IPAddress gateway(192, 168, 1, 1); // Usually your router's IP
IPAddress subnet(255, 255, 255, 0); // Standard subnet mask
void startCameraServer();
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
// Open Camera Power
pinMode(3, OUTPUT);
digitalWrite(3, 1);
// Config Camera
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = 11;
config.pin_d1 = 9;
config.pin_d2 = 8;
config.pin_d3 = 10;
config.pin_d4 = 12;
config.pin_d5 = 18;
config.pin_d6 = 17;
config.pin_d7 = 16;
config.pin_xclk = 15;
config.pin_pclk = 13;
config.pin_vsync = 6;
config.pin_href = 7;
config.pin_sccb_sda = 4;
config.pin_sccb_scl = 5;
config.pin_pwdn = -1;
config.pin_reset = -1;
config.xclk_freq_hz = 20000000;
config.frame_size = FRAMESIZE_UXGA;
config.pixel_format = PIXFORMAT_JPEG; // For streaming
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.jpeg_quality = 12;
config.fb_count = 1;
// Adjust settings based on PSRAM availability
if (config.pixel_format == PIXFORMAT_JPEG) {
if (psramFound()) {
config.jpeg_quality = 10;
config.fb_count = 2;
config.grab_mode = CAMERA_GRAB_LATEST;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.fb_location = CAMERA_FB_IN_DRAM;
}
} else {
config.frame_size = FRAMESIZE_240X240;
#if CONFIG_IDF_TARGET_ESP32S3
config.fb_count = 2;
#endif
}
// Initialize the camera
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
// Camera sensor tweaks
sensor_t *s = esp_camera_sensor_get();
if (s->id.PID == OV5640_PID) {
s->set_vflip(s, 1);
s->set_brightness(s, 1);
s->set_saturation(s, -2);
}
// Initial frame size
if (config.pixel_format == PIXFORMAT_JPEG) {
s->set_framesize(s, FRAMESIZE_QVGA);
}
// Setup Wi-Fi with Static IP
WiFi.config(local_IP, gateway, subnet);
WiFi.begin(ssid, password);
WiFi.setSleep(false);
Serial.print("WiFi connecting");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
startCameraServer();
Serial.print("Camera Ready! Use 'http://");
Serial.print(WiFi.localIP());
Serial.println("' to connect");
}
void loop() {
delay(10000); // Keep alive
}
Telegram Image Posting
- Use HTTPS or a lightweight Telegram image upload library.
- Format the captured image (JPEG preferred) and encode it.
- Send a POST request to your bot’s API endpoint with the image and a caption
#include <Arduino.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_camera.h"
#include <UniversalTelegramBot.h>
#include <ArduinoJson.h>
// ===========================
// Enter your WiFi credentials
// ===========================
const char *ssid = "xxxxxx";
const char *password = "xxxxxx";
// Initialize Telegram BOT
String BOTtoken = "xxxxxxxxxxxxxxxxxxxxxxx"; // your Bot Token (Get from Botfather)
// Use @myidbot to find out the chat ID of an individual or a group
// Also note that you need to click "start" on a bot before it can
// message you
String CHAT_ID = "xxxxxxxxxx";
bool sendPhoto = false;
WiFiClientSecure clientTCP;
UniversalTelegramBot bot(BOTtoken, clientTCP);
#define FLASH_LED_PIN 4
bool flashState = LOW;
//Checks for new messages every 1 second.
int botRequestDelay = 1000;
unsigned long lastTimeBotRan;
void handleNewMessages(int numNewMessages) {
Serial.print("Handle New Messages: ");
Serial.println(numNewMessages);
for (int i = 0; i < numNewMessages; i++) {
String chat_id = String(bot.messages[i].chat_id);
if (chat_id != CHAT_ID) {
bot.sendMessage(chat_id, "Unauthorized user", "");
continue;
}
// Print the received message
String text = bot.messages[i].text;
Serial.println(text);
String from_name = bot.messages[i].from_name;
if (text == "/start") {
String welcome = "Welcome , " + from_name + "\n";
welcome += "Use the following commands to interact with the NeoEyes \n";
welcome += "/photo : takes a new photo\n";
bot.sendMessage(CHAT_ID, welcome, "");
}
if (text == "/photo") {
sendPhoto = true;
Serial.println("New photo request");
}
}
}
String sendPhotoTelegram() {
const char* myDomain = "api.telegram.org";
String getAll = "";
String getBody = "";
//Dispose first picture because of bad quality
camera_fb_t * fb = NULL;
fb = esp_camera_fb_get();
esp_camera_fb_return(fb); // dispose the buffered image
// Take a new photo
fb = NULL;
fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Camera capture failed");
delay(1000);
ESP.restart();
return "Camera capture failed";
}
Serial.println("Connect to " + String(myDomain));
if (clientTCP.connect(myDomain, 443)) {
Serial.println("Connection successful");
String head = "--RandomNerdTutorials\r\nContent-Disposition: form-data; name=\"chat_id\"; \r\n\r\n" + CHAT_ID + "\r\n--RandomNerdTutorials\r\nContent-Disposition: form-data; name=\"photo\"; filename=\"NE101-cam.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
String tail = "\r\n--RandomNerdTutorials--\r\n";
size_t imageLen = fb->len;
size_t extraLen = head.length() + tail.length();
size_t totalLen = imageLen + extraLen;
clientTCP.println("POST /bot"+BOTtoken+"/sendPhoto HTTP/1.1");
clientTCP.println("Host: " + String(myDomain));
clientTCP.println("Content-Length: " + String(totalLen));
clientTCP.println("Content-Type: multipart/form-data; boundary=RandomNerdTutorials");
clientTCP.println();
clientTCP.print(head);
uint8_t *fbBuf = fb->buf;
size_t fbLen = fb->len;
for (size_t n=0;n<fbLen;n=n+1024) {
if (n+1024<fbLen) {
clientTCP.write(fbBuf, 1024);
fbBuf += 1024;
}
else if (fbLen%1024>0) {
size_t remainder = fbLen%1024;
clientTCP.write(fbBuf, remainder);
}
}
clientTCP.print(tail);
esp_camera_fb_return(fb);
int waitTime = 10000; // timeout 10 seconds
long startTimer = millis();
boolean state = false;
while ((startTimer + waitTime) > millis()){
Serial.print(".");
delay(100);
while (clientTCP.available()) {
char c = clientTCP.read();
if (state==true) getBody += String(c);
if (c == '\n') {
if (getAll.length()==0) state=true;
getAll = "";
}
else if (c != '\r')
getAll += String(c);
startTimer = millis();
}
if (getBody.length()>0) break;
}
clientTCP.stop();
Serial.println(getBody);
}
else {
getBody="Connected to api.telegram.org failed.";
Serial.println("Connected to api.telegram.org failed.");
}
return getBody;
}
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
// Open Camera Power
pinMode(3, OUTPUT);
digitalWrite(3, 1);
// Config Camera
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = 11;
config.pin_d1 = 9;
config.pin_d2 = 8;
config.pin_d3 = 10;
config.pin_d4 = 12;
config.pin_d5 = 18;
config.pin_d6 = 17;
config.pin_d7 = 16;
config.pin_xclk = 15;
config.pin_pclk = 13;
config.pin_vsync = 6;
config.pin_href = 7;
config.pin_sccb_sda = 4;
config.pin_sccb_scl = 5;
config.pin_pwdn = -1;
config.pin_reset = -1;
config.xclk_freq_hz = 20000000;
config.frame_size = FRAMESIZE_UXGA;
config.pixel_format = PIXFORMAT_JPEG; // For streaming
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
config.fb_location = CAMERA_FB_IN_PSRAM;
config.jpeg_quality = 12;
config.fb_count = 1;
// Adjust settings based on PSRAM availability
if (config.pixel_format == PIXFORMAT_JPEG) {
if (psramFound()) {
config.jpeg_quality = 10;
config.fb_count = 2;
config.grab_mode = CAMERA_GRAB_LATEST;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.fb_location = CAMERA_FB_IN_DRAM;
}
} else {
config.frame_size = FRAMESIZE_240X240;
#if CONFIG_IDF_TARGET_ESP32S3
config.fb_count = 2;
#endif
}
// Initialize the camera
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
// Camera sensor tweaks
sensor_t *s = esp_camera_sensor_get();
if (s->id.PID == OV5640_PID) {
s->set_vflip(s, 1);
s->set_brightness(s, 1);
s->set_saturation(s, -2);
}
// Initial frame size
if (config.pixel_format == PIXFORMAT_JPEG) {
s->set_framesize(s, FRAMESIZE_QVGA);
}
WiFi.begin(ssid, password);
WiFi.setSleep(false);
Serial.print("WiFi connecting");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.print("Camera Ready! Use 'http://");
Serial.print(WiFi.localIP());
Serial.println("' to connect");
clientTCP.setCACert(TELEGRAM_CERTIFICATE_ROOT); // Add root certificate for api.telegram.org
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println();
}
void loop() {
if (sendPhoto) {
Serial.println("Preparing photo");
sendPhotoTelegram();
sendPhoto = false;
}
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
while (numNewMessages) {
Serial.println("got response");
handleNewMessages(numNewMessages);
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}
delay(2000);
}
From the Telegram Bot you can request for a new photo.
And you can be able to view the data in the Bot.
modify the camera settings to get a more better-quality image.
- 📸 Trigger NeoEyes NE101 to capture and send a snapshot using a physical button wired to a GPIO pin
- 🧪 Great for on-site testing — no need to use Telegram or a web interface
- 🕵️♂️ Can be embedded as a secret push-to-alert behind a wall or panel
- 🚪 Ideal for doorbell-style setups or panic triggers in remote locations
- 🔁 Works in tandem with Telegram commands — supports hybrid control
- 🛎️ Press the button → Snap a photo → Get a Telegram alert — simple and reliable
Here is the updated code snippet.
void loop() {
// 📲 Telegram command: /photo
if (sendPhoto) {
Serial.println("Preparing photo (Telegram command)");
sendPhotoTelegram();
sendPhoto = false;
delay(1000); // Optional cooldown
}
// 🛎️ Physical Button Press
static bool lastButtonState = HIGH;
bool currentButtonState = digitalRead(BUTTON_PIN);
// Detect falling edge (button press)
if (lastButtonState == HIGH && currentButtonState == LOW) {
Serial.println("Button pressed 📸 Sending photo...");
sendPhotoTelegram();
delay(1000); // Debounce + cooldown
}
lastButtonState = currentButtonState;
// 🔁 Check for new Telegram messages
if (millis() > lastTimeBotRan + botRequestDelay) {
int numNewMessages = bot.getUpdates(bot.last_message_received + 1);
while (numNewMessages) {
Serial.println("Telegram message received");
handleNewMessages(numNewMessages);
numNewMessages = bot.getUpdates(bot.last_message_received + 1);
}
lastTimeBotRan = millis();
}
}
Here is the serial terminal response
Assemble with the hardcase and battery pack, that's all now all set.
🔐 Real-World Use Cases for Telegram Alert System with NeoEyes NE101🏡 Edge AI Home Security Snap intruders, visitors, or even curious wildlife at your doorstep — and get instant Telegram alerts, even during heavy rain or intense heat. Thanks to its IP67-rated enclosure, NE101 doesn’t mind the weather... unlike some delivery guys.
📦Smart Package Watchdog Mounted near your front gate or mail zone, the camera sends a real-time snapshot as soon as a parcel arrives. No cloud required — just AI-powered detection and a friendly Telegram ping. “You’ve got mail... and a picture to prove it!”
🐾Outdoor Wildlife Tracker Deployed in gardens, farms, or forest edges, this low-power system captures motion-triggered snapshots of animals and sends them over Telegram — perfect for behavior monitoring, species logging, or surprise squirrel selfies. 🐿️📸
🔬 Remote Lab or Site Monitoring Installed at remote equipment stations, it can visually confirm sensor activity, relay images during alerts, and allow engineers or operators to act fast — all through your Telegram bot. No cloud, no fuss, just instant feedback.
🧭 Off-Grid Surveillance Running on AA batteries and protected from the elements, NE101 makes an ideal drop-and-forget surveillance node. Telegram ensures it doesn’t stay silent — it whispers AI-backed updates when it sees something important.
✅ Project Wrap-Up — Smart, Rugged, and Ready to Go 🚀This project turns the NeoEyes NE101 into a field-tested, low-power vision system that delivers real-time image alerts straight to your Telegram inbox. Whether triggered by a message or a physical button, it responds instantly — making it ideal for smart security, delivery tracking, or even wildlife observation.
Thanks to its IP67 weatherproof enclosure, built-in ESP32-S3, and pre-integrated components (camera, battery, fill light, mounting hardware), deployment is truly plug-and-protect. No fuss. No mess. Just results.
You’ve built a device that sees, thinks, and communicates — all without needing the cloud. Perfect for privacy-conscious makers, off-grid deployments, and edge AI use cases where speed and reliability matter.
And the best part? It’s expandable. Add PIR sensors, automate triggers, tweak camera settings, or integrate with additional services — this project isn’t just finished, it’s ready for its next chapter. 💡📸🔒
Comments