Components and supplies
ArduCam Mega
Arduino Plug and Make Kit
Arduino® UNO R4 WiFi
Tools and machines
Birdhouse
Apps and platforms
Arduino IoT Cloud
Replit
Project description
Code
ardulink.cpp
cpp
1/* 2 * This file is part of the Arducam SPI Camera project. 3 * 4 * Copyright 2021 Arducam Technology co., Ltd. All Rights Reserved. 5 * 6 * This work is licensed under the MIT license, see the file LICENSE for details. 7 * 8 */ 9#include "ArducamLink.h" 10#include "ArducamUart.h" 11 12ArducamLink::ArducamLink() {} 13 14ArducamLink::~ArducamLink() {} 15 16void ArducamLink::arducamUartBegin(uint32_t baudRate) 17{ 18 SerialBegin(baudRate); 19} 20 21void ArducamLink::reportVerInfo(Arducam_Mega* myCamera) 22{ 23 ArducamCamera* cameraInstance = myCamera->getCameraInstance(); 24 uint8_t headAndtail[] = {0xff, 0xaa, 0x03, 0xff, 0xbb}; 25 26 uint32_t len = 6; 27 arducamUartWriteBuff(&headAndtail[0], 3); 28 arducamUartWriteBuff((uint8_t*)&len, 4); 29 arducamUartWriteBuff(cameraInstance->verDateAndNumber, 4); 30 printf("\r\n"); 31 arducamUartWriteBuff(&headAndtail[3], 2); 32} 33 34void ArducamLink::reportSdkVerInfo(Arducam_Mega* myCamera) 35{ 36 ArducamCamera* cameraInstance = myCamera->getCameraInstance(); 37 uint8_t headAndtail[] = {0xff, 0xaa, 0x05, 0xff, 0xbb}; 38 39 uint32_t len = 6; 40 arducamUartWriteBuff(&headAndtail[0], 3); 41 arducamUartWriteBuff((uint8_t*)&len, 4); 42 arducamUartWriteBuff((uint8_t*)&cameraInstance->currentSDK->sdkVersion, 5); 43 printf("\r\n"); 44 arducamUartWriteBuff(&headAndtail[3], 2); 45} 46 47void ArducamLink::reportCameraInfo(Arducam_Mega* myCamera) 48{ 49 ArducamCamera* cameraInstance = myCamera->getCameraInstance(); 50 uint8_t headAndtail[] = {0xff, 0xaa, 0x02, 0xff, 0xbb}; 51 52 uint32_t len = 0; 53 char buff[400]; 54 arducamUartWriteBuff(&headAndtail[0], 3); 55 sprintf(buff, 56 "ReportCameraInfo\r\nCamera Type:%s\r\nCamera Support Resolution:%d\r\nCamera Support " 57 "specialeffects:%d\r\nCamera Support Focus:%d\r\nCamera Exposure Value Max:%ld\r\nCamera Exposure Value " 58 "Min:%d\r\nCamera Gain Value Max:%d\r\nCamera Gain Value Min:%d\r\nCamera Support Sharpness:%d\r\n", 59 cameraInstance->myCameraInfo.cameraId, cameraInstance->myCameraInfo.supportResolution, 60 cameraInstance->myCameraInfo.supportSpecialEffects, cameraInstance->myCameraInfo.supportFocus, 61 cameraInstance->myCameraInfo.exposureValueMax, cameraInstance->myCameraInfo.exposureValueMin, 62 cameraInstance->myCameraInfo.gainValueMax, cameraInstance->myCameraInfo.gainValueMin, 63 cameraInstance->myCameraInfo.supportSharpness); 64 len = strlen(buff); 65 arducamUartWriteBuff((uint8_t*)&len, 4); 66 printf(buff); 67 arducamUartWriteBuff(&headAndtail[3], 2); 68} 69 70void ArducamLink::cameraGetPicture(Arducam_Mega* myCamera) 71{ 72 ArducamCamera* cameraInstance = myCamera->getCameraInstance(); 73 uint8_t headAndtail[] = {0xff, 0xaa, 0x01, 0xff, 0xbb}; 74 uint8_t buff[READ_IMAGE_LENGTH] = {0}; 75 76 uint8_t rtLength = 0; 77 uint32_t len = myCamera->getTotalLength(); 78 arducamUartWriteBuff(&headAndtail[0], 3); 79 arducamUartWriteBuff((uint8_t*)(&len), 4); 80 arducamUartWrite(((cameraInstance->currentPictureMode & 0x0f) << 4) | 0x01); 81 while (myCamera->getReceivedLength()) { 82 rtLength = readBuff(cameraInstance, buff, READ_IMAGE_LENGTH); 83 arducamUartWriteBuff(buff, rtLength); 84 } 85 arducamUartWriteBuff(&headAndtail[3], 2); 86} 87 88void ArducamLink::send_data_pack(char cmd_type, char* msg) 89{ 90 uint8_t headAndtail[] = {0xff, 0xaa, 0x07, 0xff, 0xbb}; 91 headAndtail[2] = cmd_type; 92 uint32_t len = strlen(msg) + 2; 93 arducamUartWriteBuff(&headAndtail[0], 3); 94 arducamUartWriteBuff((uint8_t*)&len, 4); 95 printf(msg); 96 printf("\r\n"); 97 arducamUartWriteBuff(&headAndtail[3], 2); 98} 99 100uint8_t ArducamLink::uartCommandProcessing(Arducam_Mega* myCAM, uint8_t* commandBuff) 101{ 102 ArducamCamera* cameraInstance = myCAM->getCameraInstance(); 103 CamStatus state; 104 uint16_t gainValue = 0; 105 uint32_t exposureValue = 0; 106 uint32_t exposureLen1 = 0; 107 uint32_t exposureLen2 = 0; 108 uint32_t exposureLen3 = 0; 109 110 uint8_t cameraResolution = cameraInstance->currentPictureMode; 111 uint8_t cameraFarmat = cameraInstance->currentPixelFormat; 112 switch (commandBuff[0]) { 113 case SET_PICTURE_RESOLUTION: // Set Camera Resolution 114 cameraResolution = commandBuff[1] & 0x0f; 115 cameraFarmat = (commandBuff[1] & 0x70) >> 4; 116 myCAM->takePicture((CAM_IMAGE_MODE)cameraResolution, (CAM_IMAGE_PIX_FMT)cameraFarmat); 117 break; 118 case SET_VIDEO_RESOLUTION: // Set Video Resolution 119 cameraResolution = commandBuff[1] & 0x0f; 120 state = myCAM->startPreview((CAM_VIDEO_MODE)cameraResolution); 121 if (state == CAM_ERR_NO_CALLBACK) { 122 printf("callback function is not registered\n"); 123 } 124 break; 125 case SET_BRIGHTNESS: // Set brightness 126 myCAM->setBrightness((CAM_BRIGHTNESS_LEVEL)commandBuff[1]); 127 break; 128 case SET_CONTRAST: // Set Contrast 129 myCAM->setContrast((CAM_CONTRAST_LEVEL)commandBuff[1]); 130 break; 131 case SET_SATURATION: // Set saturation 132 myCAM->setSaturation((CAM_STAURATION_LEVEL)commandBuff[1]); 133 break; 134 case SET_EV: // Set EV 135 myCAM->setEV((CAM_EV_LEVEL)commandBuff[1]); 136 break; 137 case SET_WHITEBALANCE: // Set White balance 138 myCAM->setAutoWhiteBalanceMode((CAM_WHITE_BALANCE)commandBuff[1]); 139 break; 140 case SET_SPECIAL_EFFECTS: // Set Special effects 141 myCAM->setColorEffect((CAM_COLOR_FX)commandBuff[1]); 142 break; 143 case SET_FOCUS_CONTROL: // Focus Control 144 myCAM->setAutoFocus(commandBuff[1]); 145 if (commandBuff[1] == 0) { 146 myCAM->setAutoFocus(0x02); 147 } 148 break; 149 case SET_EXPOSUREANDGAIN_CONTROL: // exposure and Gain control 150 myCAM->setAutoExposure(commandBuff[1] & 0x01); 151 myCAM->setAutoISOSensitive(commandBuff[1] & 0x01); 152 break; 153 case SET_WHILEBALANCE_CONTROL: // while balance control 154 myCAM->setAutoWhiteBalance(commandBuff[1] & 0x01); 155 break; 156 case SET_SHARPNESS: 157 myCAM->setSharpness((CAM_SHARPNESS_LEVEL)commandBuff[1]); 158 break; 159 case SET_MANUAL_GAIN: // manual gain control 160 gainValue = (commandBuff[1] << 8) | commandBuff[2]; 161 myCAM->setISOSensitivity(gainValue); 162 break; 163 case SET_MANUAL_EXPOSURE: // manual exposure control 164 exposureLen1 = commandBuff[1]; 165 exposureLen2 = commandBuff[2]; 166 exposureLen3 = commandBuff[3]; 167 exposureValue = (exposureLen1 << 16) | (exposureLen2 << 8) | exposureLen3; 168 myCAM->setAbsoluteExposure(exposureValue); 169 break; 170 case GET_CAMERA_INFO: // Get Camera info 171 reportCameraInfo(myCAM); 172 break; 173 case TAKE_PICTURE: 174 myCAM->takePicture((CAM_IMAGE_MODE)cameraResolution, (CAM_IMAGE_PIX_FMT)cameraFarmat); 175 cameraGetPicture(myCAM); 176 break; 177 case DEBUG_WRITE_REGISTER: 178 myCAM->debugWriteRegister(commandBuff + 1); 179 break; 180 case STOP_STREAM: 181 myCAM->stopPreview(); 182 break; 183 case GET_FRM_VER_INFO: // Get Firmware version info 184 reportVerInfo(myCAM); 185 break; 186 case GET_SDK_VER_INFO: // Get sdk version info 187 reportSdkVerInfo(myCAM); 188 break; 189 case RESET_CAMERA: 190 myCAM->reset(); 191 case SET_IMAGE_QUALITY: 192 myCAM->setImageQuality((IMAGE_QUALITY)commandBuff[1]); 193 default: 194 break; 195 } 196 return CAM_ERR_SUCCESS; 197} 198 199void ArducamLink::arducamUartWrite(uint8_t data) 200{ 201 SerialWrite(data); 202 delayUs(12); 203} 204 205void ArducamLink::arducamUartWriteBuff(uint8_t* buff, uint16_t length) 206{ 207 // SerialWriteBuff(buff, length); 208 // delayUs(12); 209 for (uint16_t i = 0; i < length; i++) 210 arducamUartWrite(buff[i]); 211} 212 213void ArducamLink::printf(char* buff) 214{ 215 uint16_t len = strlen(buff); 216 // SerialPrintf(buff); 217 // delayUs(12); 218 arducamUartWriteBuff((uint8_t*)buff, len); 219} 220 221uint32_t ArducamLink::arducamUartAvailable(void) 222{ 223 return SerialAvailable(); 224} 225 226uint8_t ArducamLink::arducamUartRead(void) 227{ 228 return SerialRead(); 229} 230 231void ArducamLink::arducamFlush(void) 232{ 233 while (arducamUartAvailable()) { 234 arducamUartRead(); 235 } 236}
arducamlink.h
cpp
1/* 2 * This file is part of the Arducam SPI Camera project. 3 * 4 * Copyright 2021 Arducam Technology co., Ltd. All Rights Reserved. 5 * 6 * This work is licensed under the MIT license, see the file LICENSE for details. 7 * 8 */ 9#ifndef __ARDUCAMLINK_H 10#define __ARDUCAMLINK_H 11#include "Arducam_Mega.h" 12#include "stdint.h" 13 14#define RESET_CAMERA 0XFF 15#define SET_PICTURE_RESOLUTION 0X01 16#define SET_VIDEO_RESOLUTION 0X02 17#define SET_BRIGHTNESS 0X03 18#define SET_CONTRAST 0X04 19#define SET_SATURATION 0X05 20#define SET_EV 0X06 21#define SET_WHITEBALANCE 0X07 22#define SET_SPECIAL_EFFECTS 0X08 23#define SET_FOCUS_CONTROL 0X09 24#define SET_EXPOSUREANDGAIN_CONTROL 0X0A 25// #define SET_GAIN_CONTROL 0X0B 26#define SET_WHILEBALANCE_CONTROL 0X0C 27#define SET_MANUAL_GAIN 0X0D 28#define SET_MANUAL_EXPOSURE 0X0E 29#define GET_CAMERA_INFO 0X0F 30#define TAKE_PICTURE 0X10 31#define SET_SHARPNESS 0X11 32#define DEBUG_WRITE_REGISTER 0X12 33#define STOP_STREAM 0X21 34#define GET_FRM_VER_INFO 0X30 35#define GET_SDK_VER_INFO 0X40 36#define SET_IMAGE_QUALITY 0X50 37 38#define READ_IMAGE_LENGTH 255 39 40class ArducamLink 41{ 42 public: 43 uint8_t uartCommandProcessing(Arducam_Mega*, uint8_t*); 44 45 public: 46 ArducamLink(); 47 ~ArducamLink(); 48 void arducamUartBegin(uint32_t); 49 void reportCameraInfo(Arducam_Mega*); 50 void reportVerInfo(Arducam_Mega* myCamera); 51 void reportSdkVerInfo(Arducam_Mega* myCamera); 52 void cameraGetPicture(Arducam_Mega*); 53 void arducamFlush(void); 54 void send_data_pack(char cmd_type, char* msg); 55 56 public: 57 void printf(char* buff); 58 void arducamUartWrite(uint8_t); 59 void arducamUartWriteBuff(uint8_t*, uint16_t); 60 uint32_t arducamUartAvailable(void); 61 uint8_t arducamUartRead(void); 62}; 63 64#endif /*__ARDUCAMLINK_H*/
arducamuart.h
cpp
1#ifndef __ARDUCAM_SLOT_H 2#define __ARDUCAM_SLOT_H 3#include <Arduino.h> 4 5#define SerialBegin(baudRate) Serial.begin(baudRate) 6#define SerialWrite(ch) Serial.write(ch) 7#define SerialWriteBuff(buf, len) Serial.write(buf, len) 8#define SerialPrintf(str) Serial.print(str) 9#define SerialAvailable() Serial.available() 10#define SerialRead() Serial.read() 11#define delayUs(us) delayMicroseconds(us) 12#endif
smartbirdhouse.ino
csharp
1#include "arduino_secrets.h" 2#include "arduino_secrets.h" 3#include "thingProperties.h" 4#include "WiFiS3.h" 5#include "ArducamLink.h" 6#include "Arducam_Mega.h" 7#include "SPI.h" 8#include "Modulino.h" 9 10 11// Variable for the Modulino Movement 12ModulinoMovement movement; 13ModulinoPixels leds; 14 15ModulinoColor ledColor(0, 0, 100); 16 17const char* ssid = SECRET_SSID; 18const char* password = SECRET_OPTIONAL_PASS; 19 20// Add your Replit dev URL and remove trailing slash `/` from the server URL 21const char* server = "6c88af9f-3e0f-431b-882b-d8d0d90aa63e-00-389viub90f93v.spock.replit.dev"; 22const int serverPort = 443; // Use HTTPS (443) 23 24// Use WiFiSSLClient instead of WiFiClient 25WiFiSSLClient client; 26 27const int MEGA_CS = 7; 28Arducam_Mega myCAM(MEGA_CS); 29 30const uint16_t BUFFER_SIZE = 512; 31uint8_t imageBuffer[BUFFER_SIZE]; 32 33// Variables for the IMU readings 34float motion; 35 36void setup() { 37 // Initialize serial and wait for port to open: 38 Serial.begin(115200); 39 // This delay gives the chance to wait for a Serial Monitor without blocking if none is found 40 delay(1500); 41 SPI.begin(); 42 Modulino.begin(); 43 44 leds.begin(); 45 leds.clear(); 46 47 Serial.println("[INFO] Initializing Camera..."); 48 if (myCAM.begin() == CAM_ERR_SUCCESS) { 49 Serial.println(" Camera initialized successfully!"); 50 } else { 51 Serial.println(" Camera initialization failed!"); 52 while (1); 53 } 54 55 // Defined in thingProperties.h 56 initProperties(); 57 58 // Connect to Arduino IoT Cloud 59 ArduinoCloud.begin(ArduinoIoTPreferredConnection); 60 61 /* 62 The following function allows you to obtain more information 63 related to the state of network and IoT Cloud connection and errors 64 the higher number the more granular information you’ll get. 65 The default is 0 (only errors). 66 Maximum is 4 67 */ 68 setDebugMessageLevel(2); 69 ArduinoCloud.printDebugInfo(); 70 71 ledOn = false; 72 73 movement.begin(); 74 75 delay(1500); 76} 77 78void captureImage() { 79 // Capture Image 80 Serial.println("[INFO] Capturing Image..."); 81 if (myCAM.takePicture(CAM_IMAGE_MODE_QVGA, CAM_IMAGE_PIX_FMT_JPG) == CAM_ERR_SUCCESS) { 82 Serial.println("Image captured!"); 83 } else { 84 Serial.println("Failed to capture image."); 85 return; 86 } 87 uint32_t imageLength = myCAM.getTotalLength(); 88 Serial.print("Image Size: "); 89 Serial.println(imageLength); 90 if (imageLength == 0) { 91 Serial.println("WARNING: No image data found!"); 92 return; 93 } 94 // Send image directly to Replit server 95 sendImageToServer(imageLength); 96} 97 98void sendImageToServer(uint32_t imageLength) { 99 Serial.println("[INFO] Connecting to Replit Server..."); 100 101 if (!client.connect(server, serverPort)) { 102 Serial.println("Connection to Replit server failed!"); 103 return; 104 } 105 // Correct the HTTP request format 106 client.print("POST /upload HTTP/1.1\r\n"); 107 client.print("Host: "); 108 client.print(server); 109 client.print("\r\n"); 110 client.print("Content-Type: application/octet-stream\r\n"); 111 client.print("Transfer-Encoding: chunked\r\n"); 112 client.print("Connection: close\r\n"); // Ensure the connection closes after the request 113 client.print("\r\n"); 114 uint32_t bytesSent = 0; 115 uint32_t remainingBytes = imageLength; 116 const uint16_t BUFFER_SIZE = 50; 117 uint8_t imageBuffer[BUFFER_SIZE]; 118 Serial.println("[INFO] Starting Image Transmission..."); 119 120 while (remainingBytes > 0) { 121 uint16_t bytesToRead = (remainingBytes > BUFFER_SIZE) ? BUFFER_SIZE : remainingBytes; 122 // Read from camera FIFO buffer 123 uint16_t bytesRead = myCAM.readBuff(imageBuffer, bytesToRead); 124 if (bytesRead == 0) { 125 Serial.println("WARNING: No bytes read from camera! Retrying..."); 126 delay(50); 127 continue; 128 } 129 // Send chunk size in hex format with CRLF 130 char chunkSizeHex[10]; 131 sprintf(chunkSizeHex, "%X", bytesRead); 132 client.print(chunkSizeHex); 133 client.print("\r\n"); 134 // Send actual image chunk 135 client.write(imageBuffer, bytesRead); 136 client.print("\r\n"); 137 client.flush(); 138 bytesSent += bytesRead; 139 remainingBytes -= bytesRead; 140 Serial.print("[INFO] Sent "); 141 Serial.print(bytesRead); 142 Serial.println(" bytes"); 143 delay(10); 144 } 145 // End HTTP chunked transfer 146 client.print("0\r\n\r\n"); 147 client.flush(); 148 Serial.println("Image successfully sent to Replit server!"); 149 client.stop(); 150} 151 152void loop() { 153 ArduinoCloud.update(); 154 movement.update(); 155 // Variables get the IMU readings 156 motion = movement.getX(); 157 // If animal activity detected takes and image and sends it to the cloud 158 if(motion > 0.3){ 159 captureImage(); 160 } 161 updateLEDS(); 162} 163 164void updateLEDS() { 165 // Step 1: Reinitialize LED SPI control 166 leds.begin(); // Resets LED SPI config if needed 167 168 // Step 2: Update LED state based on current values 169 if (!ledOn) { 170 leds.clear(); 171 } else { 172 for (int i = 0; i < 8; i++) { 173 leds.set(i, ledColor, 100); 174 } 175 } 176 leds.show(); 177 178 // Step 3: Reinitialize the camera 179 delay(10); // Small delay just to be safe 180 myCAM.begin(); // Reclaim SPI for camera 181} 182 183void onLedOnChange() { 184 updateLEDS(); 185} 186 187void onLampColorChange() { 188 uint8_t r, g, b; 189 // Gets rgb value from the cloud and puts it in the local variable 190 lampColor.getValue().getRGB(r, g, b); 191 ModulinoColor ledsColor(r, g, b); 192 ledColor = ledsColor; 193 updateLEDS(); 194}
main.py
python
For use in replit
1from flask import Flask, request, send_from_directory, Response 2import os 3 4app = Flask(__name__) 5 6# Storage directory for images on Replit 7UPLOAD_FOLDER = "static" 8os.makedirs(UPLOAD_FOLDER, exist_ok=True) 9 10# Fixed image filename to ensure persistent URL 11IMAGE_FILENAME = "latest_image.jpg" 12 13 14@app.route('/') 15def home(): 16 return "Replit Image Server is running!" 17 18 19@app.route('/upload', methods=['POST']) 20def upload_image(): 21 """Receives raw JPEG data from Arduino, extracts and saves the image.""" 22 print("[INFO] Receiving Raw Image Data...") 23 24 raw_data = request.data 25 26 # Locate JPEG start and end markers 27 start_index = raw_data.find(b'\xFF\xD8') 28 end_index = raw_data.find(b'\xFF\xD9') 29 30 if start_index == -1 or end_index == -1: 31 print("ERROR: Invalid JPEG data received!") 32 return Response("Invalid image data", 33 status=400, 34 mimetype="text/plain") 35 36 end_index += 2 # Include the full JPEG end marker 37 jpeg_data = raw_data[start_index:end_index] 38 39 # Save the image 40 image_path = os.path.join(UPLOAD_FOLDER, IMAGE_FILENAME) 41 with open(image_path, "wb") as f: 42 f.write(jpeg_data) 43 44 print(f"Image saved on Replit: {image_path}") 45 46 # Return the persistent image URL 47 image_url = f"{request.host_url}image" 48 return Response(image_url, status=200, mimetype="text/plain") 49 50 51@app.route('/image', methods=['GET']) 52def serve_image(): 53 """Serves the latest uploaded image at a persistent URL.""" 54 return send_from_directory(UPLOAD_FOLDER, IMAGE_FILENAME) 55 56 57if __name__ == "__main__": 58 app.run(host="0.0.0.0", port=5000, debug=True)
Comments
Only logged in users can leave comments