|
| 1 | +# SPDX-FileCopyrightText: 2022 Kattni Rembor for Adafruit Industries |
| 2 | +# |
| 3 | +# SPDX-License-Identifier: MIT |
| 4 | + |
| 5 | +"""CircuitPython WiFi Mailbox Notifier""" |
| 6 | + |
| 7 | +import time |
| 8 | +import ssl |
| 9 | +import alarm |
| 10 | +import board |
| 11 | +import digitalio |
| 12 | +import analogio |
| 13 | +import wifi |
| 14 | +import socketpool |
| 15 | +import microcontroller |
| 16 | +import adafruit_requests |
| 17 | +from adafruit_io.adafruit_io import IO_HTTP |
| 18 | + |
| 19 | +# Get WiFi/Adafruit IO details from secrets.py |
| 20 | +try: |
| 21 | + from secrets import secrets |
| 22 | +except ImportError: |
| 23 | + print("Please create secrets.py and add your WiFi and AIO credentials there!") |
| 24 | + raise |
| 25 | + |
| 26 | +# Update to True if you want metadata sent to Adafruit IO. Defaults to False. |
| 27 | +METADATA = False |
| 28 | + |
| 29 | +# Initialise metadata. |
| 30 | +if alarm.wake_alarm: |
| 31 | + print("Awake", alarm.wake_alarm) |
| 32 | + # Increment wake count by 1. |
| 33 | + alarm.sleep_memory[0] += 1 |
| 34 | +else: |
| 35 | + print("No wake up alarm") |
| 36 | + # Set wake count to 0. |
| 37 | + alarm.sleep_memory[0] = 0 |
| 38 | + # Set error count to 0. |
| 39 | + alarm.sleep_memory[2] = 0 |
| 40 | + |
| 41 | +# Set up battery monitoring. |
| 42 | +voltage_pin = analogio.AnalogIn(board.VOLTAGE_MONITOR) |
| 43 | +# Take the raw voltage pin value, and convert it to voltage. |
| 44 | +voltage = ((voltage_pin.value * 2) * 3.3) / 65536 |
| 45 | + |
| 46 | +# Set up red LED. |
| 47 | +led = digitalio.DigitalInOut(board.LED) |
| 48 | +led.switch_to_output() |
| 49 | + |
| 50 | +# Set up the alarm pin. |
| 51 | +switch_pin = digitalio.DigitalInOut(board.D27) |
| 52 | +switch_pin.pull = digitalio.Pull.UP |
| 53 | + |
| 54 | + |
| 55 | +# Send the data. Requires a feed name and a value to send. |
| 56 | +def send_io_data(feed, value): |
| 57 | + """ |
| 58 | + Send data to Adafruit IO. |
| 59 | +
|
| 60 | + Provide an Adafruit IO feed name, and the value you wish to send. |
| 61 | + """ |
| 62 | + return io.send_data(feed["key"], value) |
| 63 | + |
| 64 | + |
| 65 | +# Print wake count to serial console. |
| 66 | +print("Wake count:", alarm.sleep_memory[0]) |
| 67 | + |
| 68 | +# Connect to WiFi |
| 69 | +try: |
| 70 | + wifi.radio.connect(secrets["ssid"], secrets["password"]) |
| 71 | + print("Connected to {}!".format(secrets["ssid"])) |
| 72 | + print("IP:", wifi.radio.ipv4_address) |
| 73 | + |
| 74 | + pool = socketpool.SocketPool(wifi.radio) |
| 75 | + requests = adafruit_requests.Session(pool, ssl.create_default_context()) |
| 76 | +# WiFi connectivity fails with error messages, not specific errors, so this except is broad. |
| 77 | +except Exception as e: # pylint: disable=broad-except |
| 78 | + print("Failed to connect to WiFi. Error:", e, "\nBoard will hard reset in 30 seconds.") |
| 79 | + time.sleep(30) |
| 80 | + microcontroller.reset() |
| 81 | + |
| 82 | +# Set your Adafruit IO Username and Key in secrets.py |
| 83 | +# (visit io.adafruit.com if you need to create an account, |
| 84 | +# or if you need your Adafruit IO key.) |
| 85 | +aio_username = secrets["aio_username"] |
| 86 | +aio_key = secrets["aio_key"] |
| 87 | + |
| 88 | +# Initialize an Adafruit IO HTTP API object |
| 89 | +io = IO_HTTP(aio_username, aio_key, requests) |
| 90 | + |
| 91 | +# Print battery voltage to the serial console. Not necessary for Adafruit IO. |
| 92 | +print(f"Current battery voltage: {voltage:.2f}") |
| 93 | + |
| 94 | +# No data has been sent yet, so the send-count is 0. |
| 95 | +alarm.sleep_memory[1] = 0 |
| 96 | + |
| 97 | +# Turn on the LED to indicate data is being sent. |
| 98 | +led.value = True |
| 99 | + |
| 100 | +# While the switch is open... |
| 101 | +while not switch_pin.value: |
| 102 | + # Adafruit IO sending can run into issues if the network fails! |
| 103 | + # This ensures the code will continue to run. |
| 104 | + try: |
| 105 | + # Send data to Adafruit IO |
| 106 | + print("Sending new mail alert and battery voltage to Adafruit IO.") |
| 107 | + send_io_data(io.create_and_get_feed("new-mail"), "New mail!") |
| 108 | + send_io_data(io.create_and_get_feed("battery-voltage"), f"{voltage:.2f}V") |
| 109 | + print("Data sent!") |
| 110 | + if METADATA: |
| 111 | + print("Sending metadata to AdafruitIO.") |
| 112 | + # The number of times the board has awakened in the current cycle. |
| 113 | + send_io_data(io.create_and_get_feed("wake-count"), alarm.sleep_memory[0]) |
| 114 | + # The number of times the mailbox/battery data has been sent. |
| 115 | + send_io_data(io.create_and_get_feed("send-count"), alarm.sleep_memory[1]) |
| 116 | + # The number of Adafruit IO errors that has occurred. |
| 117 | + send_io_data(io.create_and_get_feed("error-count"), alarm.sleep_memory[2]) |
| 118 | + print("Metadata sent!") |
| 119 | + time.sleep(30) # Delay included to avoid data limit throttling on Adafruit IO. |
| 120 | + alarm.sleep_memory[1] += 1 # Increment data send count by 1. |
| 121 | + led.value = False # Turn off the LED to indicate data sending is complete. |
| 122 | + |
| 123 | + # Adafruit IO can fail with multiple errors depending on the situation, so this except is broad. |
| 124 | + except Exception as e: # pylint: disable=broad-except |
| 125 | + print("Failed to send to Adafruit IO. Error:", e, "\nBoard will hard reset in 30 seconds.") |
| 126 | + alarm.sleep_memory[2] += 1 # Increment error count by one. |
| 127 | + time.sleep(30) |
| 128 | + microcontroller.reset() |
| 129 | + |
| 130 | +# Deinitialise the alarm pin. |
| 131 | +switch_pin.deinit() |
| 132 | + |
| 133 | +# Turn off the NeoPixel/I2C power for deep sleep. |
| 134 | +power_pin = digitalio.DigitalInOut(board.NEOPIXEL_I2C_POWER) |
| 135 | +power_pin.switch_to_output(False) |
| 136 | + |
| 137 | +# Turn off LED for deep sleep. |
| 138 | +led.value = False |
| 139 | + |
| 140 | +# Create an alarm on pin D27. |
| 141 | +pin_alarm = alarm.pin.PinAlarm(pin=board.D27, value=False, pull=True) |
| 142 | + |
| 143 | +print("Entering deep sleep.") |
| 144 | + |
| 145 | +# Exit and set the alarm. |
| 146 | +alarm.exit_and_deep_sleep_until_alarms(pin_alarm) |
0 commit comments