1+ # SPDX-FileCopyrightText: 2023 Brent Rubell for Adafruit Industries
2+ #
3+ # An open-source IoT doorbell with the Adafruit MEMENTO camera and Adafruit IO
4+ #
5+ # SPDX-License-Identifier: Unlicense
6+ import time
7+ import binascii
8+ import digitalio
9+ import bitmaptools
10+ import displayio
11+ import gifio
12+ import pwmio
13+ import ulab .numpy as np
14+ import adafruit_pycamera
15+ import os
16+ import board
17+ import busio
18+ import wifi
19+ import ssl
20+ import socketpool
21+ import adafruit_requests
22+ from adafruit_io .adafruit_io import IO_HTTP , AdafruitIO_RequestError
23+ from adafruit_debouncer import Debouncer
24+
25+ print ("CircuitPython Doorbell Camera" )
26+
27+ ### WiFi ###
28+ # Add settings.toml to your filesystem CIRCUITPY_WIFI_SSID and CIRCUITPY_WIFI_PASSWORD keys
29+ # with your WiFi credentials. DO NOT share that file or commit it into Git or other
30+ # source control.
31+
32+ # Set your Adafruit IO Username, Key and Port in settings.toml
33+ # (visit io.adafruit.com if you need to create an account,
34+ # or if you need your Adafruit IO key.)
35+ aio_username = os .getenv ("ADAFRUIT_AIO_USERNAME" )
36+ aio_key = os .getenv ("ADAFRUIT_AIO_KEY" )
37+
38+ print (f"Connecting to { os .getenv ('CIRCUITPY_WIFI_SSID' )} " )
39+ wifi .radio .connect (
40+ os .getenv ("CIRCUITPY_WIFI_SSID" ), os .getenv ("CIRCUITPY_WIFI_PASSWORD" )
41+ )
42+ print (f"Connected to { os .getenv ('CIRCUITPY_WIFI_SSID' )} !" )
43+
44+ pool = socketpool .SocketPool (wifi .radio )
45+ requests = adafruit_requests .Session (pool , ssl .create_default_context ())
46+
47+ # Initialize an Adafruit IO HTTP API object
48+ io = IO_HTTP (os .getenv ("ADAFRUIT_AIO_USERNAME" ), os .getenv ("ADAFRUIT_AIO_KEY" ), requests )
49+
50+ # Adafruit IO feed configuration
51+ try :
52+ # Get the 'camera' feed from Adafruit IO
53+ feed_camera = io .get_feed ("camera" )
54+ except AdafruitIO_RequestError :
55+ # If no 'camera' feed exists, create one
56+ feed_camera = io .create_new_feed ("camera" )
57+
58+ # Initialize memento camera
59+ pycam = adafruit_pycamera .PyCamera ()
60+ # Turn off TFT backlight
61+ pycam .display .brightness = 0.0
62+ # Deinitialize the MEMENTO's NeoPixels
63+ # Why? The pixels use board.A1 and we want to use it to control the doorbell LED
64+ pycam .pixels .deinit ()
65+
66+ # Set up the button
67+ pin_button = digitalio .DigitalInOut (board .A0 )
68+ pin_button .direction = digitalio .Direction .INPUT
69+ pin_button .pull = digitalio .Pull .UP
70+
71+ # Set up the button's LED
72+ led = digitalio .DigitalInOut (board .A1 )
73+ led .direction = digitalio .Direction .OUTPUT
74+ led .value = True
75+ print ("Doorbell ready to be pressed!" )
76+
77+ def capture_send_image ():
78+ """Captures an image and send it to Adafruit IO."""
79+ # Force autofocus and capture a JPEG image
80+ pycam .autofocus ()
81+ jpeg = pycam .capture_into_jpeg ()
82+ print ("Captured image!" )
83+ if jpeg is not None :
84+ # Encode JPEG data into base64 for sending to Adafruit IO
85+ print ("Encoding image..." )
86+ encoded_data = binascii .b2a_base64 (jpeg ).strip ()
87+ # Send encoded_data to Adafruit IO camera feed
88+ print ("Sending image to Adafruit IO..." )
89+ io .send_data (feed_camera ["key" ], encoded_data )
90+ print ("Sent image to IO!" )
91+ else :
92+ print ("ERROR: JPEG frame capture failed!" )
93+ print ("DONE, waiting for next press.." )
94+ # Turn the LED on to signal that the doorbell is ready to be pressed again
95+ led .value = True
96+
97+
98+
99+ while True :
100+ # Wait until the doorbell is pressed
101+ if not pin_button .value :
102+ print ("Doorbell pressed!" )
103+ # Turn the doorbell LED off to signal that it has been pressed
104+ led .value = False
105+ # Play a doorbell tone using the speaker
106+ pycam .tone (95 , 0.5 )
107+ pycam .tone (70 , 0.5 )
108+ capture_send_image ()
109+ time .sleep (0.01 )
0 commit comments