{"id":4314,"date":"2023-05-28T12:00:53","date_gmt":"2023-05-28T19:00:53","guid":{"rendered":"https:\/\/www.cloudacm.com\/?p=4314"},"modified":"2023-04-23T00:42:07","modified_gmt":"2023-04-23T07:42:07","slug":"domed-esp32-cam","status":"publish","type":"post","link":"https:\/\/www.cloudacm.com\/?p=4314","title":{"rendered":"Domed ESP32-Cam"},"content":{"rendered":"<p>This post will demonstrate how to build an outdoor domed camera using the ESP32-Cam module and various inexpensive parts.\u00a0 One of the limitations of the OV2640 camera module included with the ESP32-Cam is its low quality, especially in low light conditions.\u00a0 Attempts at adjusting the light sensitivity levels in software can only go so far, see the earlier post <a href=\"https:\/\/www.cloudacm.com\/?p=3986\">https:\/\/www.cloudacm.com\/?p=3986<\/a> regarding those attempts.<\/p>\n<p>This post will focus more on hardware modifications to improve the image quality and for its use in an outdoor setting.\u00a0 This video was the inspiration of the work demonstrated in this post.<\/p>\n<p><iframe loading=\"lazy\" title=\"Give a proper lens to your 7$ ESP32-CAM!!!\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/QIC6FtiUrOU?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/p>\n<p>Here are the parts list of items and their costs.<\/p>\n<ul>\n<li>6 count of ESP32 Cam Modules with OV2640 camera sensors and USB to serial connector: $40<\/li>\n<li>6 count dummy security cameras: $22<\/li>\n<li>5 count IR cut lens filter M12 mount: $12<\/li>\n<li>1 count 1.8mm 180 degree M12 CCTV lens: $12<\/li>\n<li>3 count Matek Micro BEC 6-30V to 5V step down regulator: $15<\/li>\n<li>Total cost for a single camera is just shy of $30<\/li>\n<\/ul>\n<p>The first step is to remove the stock lens from the OV2640 camera sensor.\u00a0 Using forceps and some firm movement, the lens will rotate off the sensor housing without the need to cut at the cement. The M12 mount has an IR cut lens filter with a sliding window that can be set to either IR filter or no IR filter, it was set to no IR filter.\u00a0 Next, the M12 mount and sensor housing are joined together with hot glue.\u00a0 The control wires can be removed from the M12 mount, these aren&#8217;t used in this project.\u00a0 Next, the CCTV M12 lens is screwed on the M12 mount.<\/p>\n<p><a href=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ModifiedCameraSensor.jpeg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-4321 size-full\" src=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ModifiedCameraSensor.jpeg\" alt=\"\" width=\"563\" height=\"542\" srcset=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ModifiedCameraSensor.jpeg 563w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ModifiedCameraSensor-300x289.jpeg 300w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ModifiedCameraSensor-280x270.jpeg 280w\" sizes=\"auto, (max-width: 563px) 100vw, 563px\" \/><\/a><\/p>\n<p>The modified camera sensor is then ready to be attached to the ESP32-Cam module.\u00a0 Once the data cable is attached, hot glue was used to fasten the housing to the module.\u00a0 With the included USB to serial mounting board, the ESP32-Cam can be started and the focus can be adjusted from the live stream.\u00a0 The lens threading then can be hot glued to prevent any movement, causing the camera to go out of focus.<\/p>\n<p><a href=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ModifiedESP32-Cam.jpeg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-4323 size-full\" src=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ModifiedESP32-Cam.jpeg\" alt=\"\" width=\"569\" height=\"481\" srcset=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ModifiedESP32-Cam.jpeg 569w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ModifiedESP32-Cam-300x254.jpeg 300w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ModifiedESP32-Cam-319x270.jpeg 319w\" sizes=\"auto, (max-width: 569px) 100vw, 569px\" \/><\/a><\/p>\n<p>Now the camera can be field tested to determine the angle and tilt.<\/p>\n<p><a href=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ModifiedESP32-Cam_FieldTest.jpeg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-4325 size-full\" src=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ModifiedESP32-Cam_FieldTest.jpeg\" alt=\"\" width=\"605\" height=\"340\" srcset=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ModifiedESP32-Cam_FieldTest.jpeg 605w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ModifiedESP32-Cam_FieldTest-300x169.jpeg 300w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ModifiedESP32-Cam_FieldTest-480x270.jpeg 480w\" sizes=\"auto, (max-width: 605px) 100vw, 605px\" \/><\/a><\/p>\n<p>With the old camera removed, the 12V connector can be repurposed.\u00a0 This will be soldered to the input voltage and ground pads of the Mateksys voltage regulator.\u00a0 In addition to this the output 5 volt and ground leads are soldered to the regulator pads.\u00a0 This is then mounted inside the back plate of the dummy camera enclosure.<\/p>\n<p><a href=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/BackPlateMounting.jpeg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-4327 size-full\" src=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/BackPlateMounting.jpeg\" alt=\"\" width=\"745\" height=\"497\" srcset=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/BackPlateMounting.jpeg 745w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/BackPlateMounting-300x200.jpeg 300w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/BackPlateMounting-405x270.jpeg 405w\" sizes=\"auto, (max-width: 745px) 100vw, 745px\" \/><\/a><\/p>\n<p>The 12V connector is fed through the back battery compartment.<\/p>\n<p><a href=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/BackPlateMounting12VConnector.jpeg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-4329 size-full\" src=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/BackPlateMounting12VConnector.jpeg\" alt=\"\" width=\"560\" height=\"671\" srcset=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/BackPlateMounting12VConnector.jpeg 560w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/BackPlateMounting12VConnector-250x300.jpeg 250w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/BackPlateMounting12VConnector-225x270.jpeg 225w\" sizes=\"auto, (max-width: 560px) 100vw, 560px\" \/><\/a><\/p>\n<p>Now the ESP32-Cam module can be attached to the 5V and ground.\u00a0 Based on the needed tilt and angle, shims can be used with hot glue to mount the camera to the back plate.<\/p>\n<figure id=\"attachment_4332\" aria-describedby=\"caption-attachment-4332\" style=\"width: 667px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamBackPlate.jpeg\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-4332 size-full\" src=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamBackPlate.jpeg\" alt=\"\" width=\"667\" height=\"375\" srcset=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamBackPlate.jpeg 667w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamBackPlate-300x169.jpeg 300w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamBackPlate-480x270.jpeg 480w\" sizes=\"auto, (max-width: 667px) 100vw, 667px\" \/><\/a><figcaption id=\"caption-attachment-4332\" class=\"wp-caption-text\">Screenshot<\/figcaption><\/figure>\n<p>The dummy camera has a clear dome and covered dome included with it.\u00a0 Some painters tape was used to locate where the ESP32 lens center point is so that the dome covering could be adjusted.\u00a0 Once aligned, the dome covering was hot glued to the clear dome.\u00a0 The back plate is then ready to be reattached to the dome covering.<\/p>\n<p><a href=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamEnclosure.jpeg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-4334 size-full\" src=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamEnclosure.jpeg\" alt=\"\" width=\"746\" height=\"509\" srcset=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamEnclosure.jpeg 746w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamEnclosure-300x205.jpeg 300w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamEnclosure-396x270.jpeg 396w\" sizes=\"auto, (max-width: 746px) 100vw, 746px\" \/><\/a><\/p>\n<p>Using a template of the back plate mounting holes, screws were placed and the camera was attached to the existing power supply then mounted.<\/p>\n<p><a href=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamMounting.jpeg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-4336 size-full\" src=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamMounting.jpeg\" alt=\"\" width=\"780\" height=\"478\" srcset=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamMounting.jpeg 780w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamMounting-300x184.jpeg 300w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamMounting-768x471.jpeg 768w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamMounting-441x270.jpeg 441w\" sizes=\"auto, (max-width: 780px) 100vw, 780px\" \/><\/a><\/p>\n<p>Now the camera is ready for use.<\/p>\n<p><a href=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamView.jpeg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-4337 size-full\" src=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamView.jpeg\" alt=\"\" width=\"732\" height=\"504\" srcset=\"https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamView.jpeg 732w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamView-300x207.jpeg 300w, https:\/\/www.cloudacm.com\/wp-content\/uploads\/2023\/05\/ESP32-CamView-392x270.jpeg 392w\" sizes=\"auto, (max-width: 732px) 100vw, 732px\" \/><\/a><\/p>\n<p>Here is the code used for this camera.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\">\/\/ Declarations and Variables\r\n\r\n#include \"src\/OV2640.h\"\r\n#include &lt;WiFi.h&gt;\r\n#include &lt;WebServer.h&gt;\r\n#include &lt;WiFiClient.h&gt;\r\n#include &lt;PubSubClient.h&gt;\r\n\r\n\r\n#define ENABLE_WEBSERVER\r\n\r\n#define CAMERA_MODEL_AI_THINKER\r\n\r\n#include \"camera_pins.h\"\r\n\r\nOV2640 cam;\r\n\r\nconst char* mqtt_server = \"mqtt_broker_here\";     \/\/ Put your MQTT Broker here\r\nconst char* ssid =     \"ssid_here\";               \/\/ Put your SSID here\r\nconst char* password = \"wifi_password_here\";           \/\/ Put your PASSWORD here\r\n\r\nWiFiClient espClient;\r\nPubSubClient client(espClient);\r\nlong lastMsg = 0;\r\nchar msg[50];\r\nint value = 0;\r\nint up = 1;\r\n\r\n\/\/ Web Server Function\r\n\r\n#ifdef ENABLE_WEBSERVER\r\n\r\nWebServer server(80);\r\n\r\nvoid handle_jpg_stream(void)\r\n{\r\n    WiFiClient client = server.client();\r\n    String response = \"HTTP\/1.1 200 OK\\r\\n\";\r\n    response += \"Content-Type: multipart\/x-mixed-replace; boundary=frame\\r\\n\\r\\n\";\r\n    server.sendContent(response);\r\n\r\n    while (1)\r\n    {\r\n        cam.run();\r\n        if (!client.connected())\r\n            break;\r\n        response = \"--frame\\r\\n\";\r\n        response += \"Content-Type: image\/jpeg\\r\\n\\r\\n\";\r\n        server.sendContent(response);\r\n\r\n        client.write((char *)cam.getfb(), cam.getSize());\r\n        server.sendContent(\"\\r\\n\");\r\n        if (!client.connected())\r\n            break;\r\n    }\r\n}\r\n\r\nvoid handle_jpg(void)\r\n{\r\n    WiFiClient client = server.client();\r\n\r\n    cam.run();\r\n    if (!client.connected())\r\n    {\r\n        return;\r\n    }\r\n    String response = \"HTTP\/1.1 200 OK\\r\\n\";\r\n    response += \"Content-disposition: inline; filename=capture.jpg\\r\\n\";\r\n    response += \"Content-type: image\/jpeg\\r\\n\\r\\n\";\r\n    server.sendContent(response);\r\n    client.write((char *)cam.getfb(), cam.getSize());\r\n}\r\n\r\nvoid handleNotFound()\r\n{\r\n    String message = \"Server is running!\\n\\n\";\r\n    message += \"URI: \";\r\n    message += server.uri();\r\n    message += \"\\nMethod: \";\r\n    message += (server.method() == HTTP_GET) ? \"GET\" : \"POST\";\r\n    message += \"\\nArguments: \";\r\n    message += server.args();\r\n    message += \"\\n\";\r\n    server.send(200, \"text\/plain\", message);\r\n}\r\n#endif\r\n\r\n\r\n\r\n\/\/ MQTT Functions\r\n\r\nvoid callback(char* topic, byte* message, unsigned int length) {\r\n  String messageTemp;\r\n  \r\n  for (int i = 0; i &lt; length; i++) {\r\n    messageTemp += (char)message[i];\r\n  }\r\n\r\n\/***\r\n  \/\/ Feel free to add more if statements to control more GPIOs with MQTT\r\n\r\n  \/\/ If a message is received on the topic esp32\/output, you check if the message is either \"on\" or \"off\". \r\n  \/\/ Changes the output state according to the message\r\n  if (String(topic) == \"Domed_ESP32-Cam\/Manual\") {\r\n    if(messageTemp == \"On\"){\r\n      Manual_State = HIGH; \/\/ The ESP32-Cam Built in LED is a inversed, LOW = On and HIGH = Off\r\n    }\r\n    else if(messageTemp == \"Off\"){\r\n      Manual_State = LOW; \/\/ The ESP32-Cam Built in LED is a inversed, LOW = On and HIGH = Off\r\n    }\r\n  }\r\n  else if (String(topic) == \"Domed_ESP32-Cam\/Override\") {\r\n    if(messageTemp == \"On\"){\r\n      Override_State = HIGH; \/\/ The ESP32-Cam Built in LED is a inversed, LOW = On and HIGH = Off\r\n    }\r\n    else if(messageTemp == \"Off\"){\r\n      Override_State = LOW; \/\/ The ESP32-Cam Built in LED is a inversed, LOW = On and HIGH = Off\r\n    }\r\n  }\r\n***\/\r\n\r\n  \r\n}\r\n\r\nvoid reconnect() {\r\n  \/\/ Loop until we're reconnected\r\n  while (!client.connected()) {\r\n    \/\/ Attempt to connect\r\n    if (client.connect(\"Domed_ESP32-Cam\")) {\r\n      \/\/ Subscribe\r\n      \/\/ Do you not subscribe to my methods?\r\n      \/\/ # for everything, or Domed_ESP32-Cam\/LED for just the LED\r\n      client.subscribe(\"Domed_ESP32-Cam\/#\");\r\n    } else {\r\n      \/\/ Wait 5 seconds before retrying\r\n      delay(5000);\r\n    }\r\n  }\r\n}\r\n\r\n\r\n\r\n\/\/ Setup Function\r\n\r\nvoid setup()\r\n{\r\n\r\n    client.setServer(mqtt_server, 1883);\r\n    client.setCallback(callback);\r\n\r\n    camera_config_t config;\r\n    config.ledc_channel = LEDC_CHANNEL_0;\r\n    config.ledc_timer = LEDC_TIMER_0;\r\n    config.pin_d0 = Y2_GPIO_NUM;\r\n    config.pin_d1 = Y3_GPIO_NUM;\r\n    config.pin_d2 = Y4_GPIO_NUM;\r\n    config.pin_d3 = Y5_GPIO_NUM;\r\n    config.pin_d4 = Y6_GPIO_NUM;\r\n    config.pin_d5 = Y7_GPIO_NUM;\r\n    config.pin_d6 = Y8_GPIO_NUM;\r\n    config.pin_d7 = Y9_GPIO_NUM;\r\n    config.pin_xclk = XCLK_GPIO_NUM;\r\n    config.pin_pclk = PCLK_GPIO_NUM;\r\n    config.pin_vsync = VSYNC_GPIO_NUM;\r\n    config.pin_href = HREF_GPIO_NUM;\r\n    config.pin_sscb_sda = SIOD_GPIO_NUM;\r\n    config.pin_sscb_scl = SIOC_GPIO_NUM;\r\n    config.pin_pwdn = PWDN_GPIO_NUM;\r\n    config.pin_reset = RESET_GPIO_NUM;\r\n    config.xclk_freq_hz = 20000000;\r\n    config.pixel_format = PIXFORMAT_JPEG;\r\n    config.frame_size = FRAMESIZE_SVGA;\r\n    config.jpeg_quality = 10; \r\n    config.fb_count = 1;       \r\n  \r\n    cam.init(config);\r\n\r\n   sensor_t * s = esp_camera_sensor_get();\r\n\r\n   s-&gt;set_vflip(s, 1);          \/\/ 0 = disable , 1 = enable\r\n   s-&gt;set_hmirror(s, 1);        \/\/ 0 = disable , 1 = enable\r\n\r\n\/* see https:\/\/randomnerdtutorials.com\/esp32-cam-ov2640-camera-settings\/\r\n\r\nsensor_t * s = esp_camera_sensor_get();\r\n\r\ns-&gt;set_brightness(s, 0);     \/\/ -2 to 2\r\ns-&gt;set_contrast(s, 0);       \/\/ -2 to 2\r\ns-&gt;set_saturation(s, 0);     \/\/ -2 to 2\r\ns-&gt;set_special_effect(s, 0); \/\/ 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia)\r\ns-&gt;set_whitebal(s, 1);       \/\/ 0 = disable , 1 = enable\r\ns-&gt;set_awb_gain(s, 1);       \/\/ 0 = disable , 1 = enable\r\ns-&gt;set_wb_mode(s, 0);        \/\/ 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)\r\ns-&gt;set_exposure_ctrl(s, 1);  \/\/ 0 = disable , 1 = enable\r\ns-&gt;set_aec2(s, 0);           \/\/ 0 = disable , 1 = enable\r\ns-&gt;set_ae_level(s, 0);       \/\/ -2 to 2\r\ns-&gt;set_aec_value(s, 300);    \/\/ 0 to 1200\r\ns-&gt;set_gain_ctrl(s, 1);      \/\/ 0 = disable , 1 = enable\r\ns-&gt;set_agc_gain(s, 0);       \/\/ 0 to 30\r\ns-&gt;set_gainceiling(s, (gainceiling_t)0);  \/\/ 0 to 6\r\ns-&gt;set_bpc(s, 0);            \/\/ 0 = disable , 1 = enable\r\ns-&gt;set_wpc(s, 1);            \/\/ 0 = disable , 1 = enable\r\ns-&gt;set_raw_gma(s, 1);        \/\/ 0 = disable , 1 = enable\r\ns-&gt;set_lenc(s, 1);           \/\/ 0 = disable , 1 = enable\r\ns-&gt;set_hmirror(s, 0);        \/\/ 0 = disable , 1 = enable\r\ns-&gt;set_vflip(s, 0);          \/\/ 0 = disable , 1 = enable\r\ns-&gt;set_dcw(s, 1);            \/\/ 0 = disable , 1 = enable\r\ns-&gt;set_colorbar(s, 0);       \/\/ 0 = disable , 1 = enable\r\n\r\nThe frame size can be set to one of these options:\r\n\r\nFRAMESIZE_UXGA (1600 x 1200)\r\nFRAMESIZE_QVGA (320 x 240)\r\nFRAMESIZE_CIF (352 x 288)\r\nFRAMESIZE_VGA (640 x 480)\r\nFRAMESIZE_SVGA (800 x 600)\r\nFRAMESIZE_XGA (1024 x 768)\r\nFRAMESIZE_SXGA (1280 x 1024)\r\n\r\n*\/    \r\n    IPAddress ip;\r\n\r\n    WiFi.mode(WIFI_STA);\r\n    WiFi.begin(ssid, password);\r\n    while (WiFi.status() != WL_CONNECTED)\r\n    {\r\n        delay(500);\r\n    }\r\n    ip = WiFi.localIP();\r\n\r\n#ifdef ENABLE_WEBSERVER\r\n    server.on(\"\/\", HTTP_GET, handle_jpg_stream);\r\n    server.on(\"\/jpg\", HTTP_GET, handle_jpg);\r\n    server.onNotFound(handleNotFound);\r\n    server.begin();\r\n#endif\r\n\r\n}\r\n\/***\r\nCStreamer *streamer;\r\nCRtspSession *session;\r\n***\/\r\n\r\n\r\n\/\/ Main Loop Function\r\n\r\nvoid loop()\r\n{\r\n  \r\n  if (!client.connected()) {\r\n    reconnect();\r\n  }\r\n  client.loop();\r\n\r\n  \r\n\r\n\r\n  long now = millis();\r\n  if (now - lastMsg &gt; 5000) {\r\n    lastMsg = now;\r\n\r\n    client.publish(\"Domed_ESP32-Cam\/Firmware\", \"Domed_ESP32-Cam_ver2\");     \r\n    String StringUptime = String(millis());\r\n    client.publish(\"Domed_ESP32-Cam\/Uptime\", StringUptime.c_str());\r\n    String StringHWAddress = String(WiFi.macAddress());\r\n    client.publish(\"Domed_ESP32-Cam\/HWAddress\", StringHWAddress.c_str());   \r\n    String StringWifiSignal = String(WiFi.RSSI());\r\n    client.publish(\"Domed_ESP32-Cam\/WifiSignal\",StringWifiSignal.c_str());   \r\n\r\n\r\n  }\r\n  \r\n  server.handleClient();\r\n\r\n}<\/pre>\n<p>It nice to see an even less expensive alternative to unmodified factory firmware cameras.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post will demonstrate how to build an outdoor domed camera using the ESP32-Cam module and various inexpensive parts.\u00a0 One of the limitations of the OV2640 camera module included with the ESP32-Cam is its low quality, especially in low light conditions.\u00a0 Attempts at adjusting the light sensitivity levels in software can only go so far, see the earlier post https:\/\/www.cloudacm.com\/?p=3986 regarding those attempts. This post will focus more on hardware modifications to improve the image quality and for its use&#8230;<\/p>\n<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/www.cloudacm.com\/?p=4314\"> Read More<span class=\"screen-reader-text\">  Read More<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-4314","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts\/4314","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4314"}],"version-history":[{"count":24,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts\/4314\/revisions"}],"predecessor-version":[{"id":4358,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=\/wp\/v2\/posts\/4314\/revisions\/4358"}],"wp:attachment":[{"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4314"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4314"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cloudacm.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4314"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}