Compare commits
No commits in common. "main" and "sparkle_arduino" have entirely different histories.
main
...
sparkle_ar
4
.github/workflows/arduino_cron.yml
vendored
|
|
@ -61,7 +61,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arduino-platform: ["cpb", "cpc", "cpx_ada", "esp32", "esp8266", "feather32u4", "feather_esp32c6", "feather_m0_express", "feather_m4_express", "feather_rp2040", "feather_rp2040_adalogger", "feather_rp2350", "flora", "fruit_jam_tinyusb", "funhouse", "gemma", "gemma_m0", "hallowing_m0", "hallowing_m4_tinyusb", "ledglasses_nrf52840", "magtag", "metro_m0", "metro_m0_tinyusb", "metro_m4", "metro_m4_tinyusb", "monster_m4sk", "monster_m4sk_tinyusb", "metro_rp2350", "neokeytrinkey_m0", "neotrellis_m4", "nrf52832", "nrf52840", "pixeltrinkey_m0", "protrinket_5v", "proxlighttrinkey_m0", "pybadge", "pycamera_s3", "pygamer", "pyportal", "qualia_s3_rgb666", "qt2040_trinkey", "qtpy_m0", "qtpy_esp32s2", "rotarytrinkey_m0", "sht4xtrinkey_m0", "slidetrinkey_m0", "trinket_5v", "trinket_m0", "uno"]
|
||||
arduino-platform: ["cpb", "cpc", "cpx_ada", "esp32", "esp8266", "feather32u4", "feather_esp32c6", "feather_m0_express", "feather_m4_express", "feather_rp2040", "feather_rp2040_adalogger", "flora", "funhouse", "gemma", "gemma_m0", "hallowing_m0", "hallowing_m4_tinyusb", "ledglasses_nrf52840", "magtag", "metro_m0", "metro_m0_tinyusb", "metro_m4", "metro_m4_tinyusb", "monster_m4sk", "monster_m4sk_tinyusb", "neokeytrinkey_m0", "neotrellis_m4", "nrf52832", "nrf52840", "pixeltrinkey_m0", "protrinket_5v", "proxlighttrinkey_m0", "pybadge", "pycamera_s3", "pygamer", "pyportal", "qualia_s3_rgb666", "qt2040_trinkey", "qtpy_m0", "qtpy_esp32s2", "rotarytrinkey_m0", "sht4xtrinkey_m0", "slidetrinkey_m0", "trinket_5v", "trinket_m0", "uno"]
|
||||
runs-on: ubuntu-latest
|
||||
if: needs.check-if-needed.outputs.answer == 'true'
|
||||
needs: check-if-needed
|
||||
|
|
@ -97,8 +97,6 @@ jobs:
|
|||
git clone --quiet https://github.com/adafruit/HID /home/runner/Arduino/libraries/HID_Project
|
||||
rm -rf /home/runner/Arduino/libraries/ArduinoHttpClient
|
||||
git clone --quiet https://github.com/arduino-libraries/ArduinoHttpClient.git /home/runner/Arduino/libraries/ArduinoHttpClient
|
||||
git clone --quiet https://github.com/pschatzmann/ESP32-A2DP /home/runner/Arduino/libraries/ESP32-A2DP
|
||||
git clone --quiet https://github.com/pschatzmann/arduino-audio-tools /home/runner/Arduino/libraries/arduino-audio-tools
|
||||
|
||||
- name: test platforms
|
||||
run: python3 ci/build_platform.py ${{ matrix.arduino-platform }}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import digitalio
|
|||
from rainbowio import colorwheel
|
||||
import keypad
|
||||
import displayio
|
||||
import i2cdisplaybus
|
||||
import busio
|
||||
import adafruit_seesaw.seesaw
|
||||
import adafruit_seesaw.neopixel
|
||||
|
|
@ -51,7 +50,7 @@ oled_reset = board.D13
|
|||
|
||||
i2c = board.STEMMA_I2C()
|
||||
# STEMMA OLED setup
|
||||
display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3D, reset=oled_reset)
|
||||
display_bus = displayio.I2CDisplay(i2c, device_address=0x3D, reset=oled_reset)
|
||||
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=64)
|
||||
|
||||
splash = displayio.Group()
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <Adafruit_MCP23X17.h>
|
||||
|
||||
#define NOID_1 0 // MCP23XXX pin LED is attached to
|
||||
#define NOID_2 4 // MCP23XXX pin LED is attached to
|
||||
|
||||
Adafruit_MCP23X17 mcp;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println("8 Channel Solenoid Driver Demo");
|
||||
if (!mcp.begin_I2C()) {
|
||||
Serial.println("Couldn't find MCP23017..");
|
||||
while (1);
|
||||
}
|
||||
mcp.pinMode(NOID_1, OUTPUT);
|
||||
mcp.pinMode(NOID_2, OUTPUT);
|
||||
|
||||
Serial.println("Found MCP23017, looping...");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Serial.println("Solenoid 1!");
|
||||
mcp.digitalWrite(NOID_1, HIGH);
|
||||
delay(500);
|
||||
mcp.digitalWrite(NOID_1, LOW);
|
||||
delay(500);
|
||||
Serial.println("Solenoid 2!");
|
||||
mcp.digitalWrite(NOID_2, HIGH);
|
||||
delay(500);
|
||||
mcp.digitalWrite(NOID_2, LOW);
|
||||
delay(500);
|
||||
Serial.println("Together!");
|
||||
mcp.digitalWrite(NOID_1, HIGH);
|
||||
mcp.digitalWrite(NOID_2, HIGH);
|
||||
delay(1000);
|
||||
mcp.digitalWrite(NOID_1, LOW);
|
||||
mcp.digitalWrite(NOID_2, LOW);
|
||||
delay(2000);
|
||||
Serial.println("Repeat!");
|
||||
Serial.println();
|
||||
delay(500);
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import time
|
||||
import board
|
||||
from adafruit_mcp230xx.mcp23017 import MCP23017
|
||||
|
||||
i2c = board.STEMMA_I2C()
|
||||
|
||||
mcp = MCP23017(i2c)
|
||||
|
||||
noid_1 = mcp.get_pin(0)
|
||||
noid_2 = mcp.get_pin(4)
|
||||
noid_1.switch_to_output(value=False)
|
||||
noid_2.switch_to_output(value=False)
|
||||
|
||||
while True:
|
||||
noid_1.value = True
|
||||
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
|
||||
time.sleep(0.2)
|
||||
noid_1.value = False
|
||||
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
|
||||
time.sleep(0.2)
|
||||
noid_2.value = True
|
||||
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
|
||||
time.sleep(0.2)
|
||||
noid_2.value = False
|
||||
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
|
||||
time.sleep(1)
|
||||
noid_1.value = True
|
||||
noid_2.value = True
|
||||
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
|
||||
time.sleep(1)
|
||||
noid_1.value = False
|
||||
noid_2.value = False
|
||||
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
|
||||
time.sleep(2)
|
||||
|
|
@ -11,7 +11,6 @@ import adafruit_ahtx0
|
|||
|
||||
# OLED
|
||||
import displayio
|
||||
import i2cdisplaybus
|
||||
import terminalio
|
||||
from adafruit_display_text import label
|
||||
import adafruit_displayio_ssd1306
|
||||
|
|
@ -26,7 +25,7 @@ aht20 = adafruit_ahtx0.AHTx0(i2c)
|
|||
|
||||
|
||||
#OLED
|
||||
display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3C)
|
||||
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)
|
||||
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32)
|
||||
|
||||
# Make the display context
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
# SPDX-FileCopyrightText: Copyright (c) 2025 Liz Clark for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
"""AS5600 Encoder"""
|
||||
import usb_hid
|
||||
import board
|
||||
from adafruit_hid.consumer_control import ConsumerControl
|
||||
from adafruit_hid.consumer_control_code import ConsumerControlCode
|
||||
import adafruit_as5600
|
||||
|
||||
i2c = board.STEMMA_I2C()
|
||||
sensor = adafruit_as5600.AS5600(i2c)
|
||||
enc_inc = ConsumerControlCode.VOLUME_INCREMENT
|
||||
enc_dec = ConsumerControlCode.VOLUME_DECREMENT
|
||||
cc = ConsumerControl(usb_hid.devices)
|
||||
|
||||
last_val = sensor.angle
|
||||
|
||||
THRESHOLD = sensor.max_angle // 2 # default max_angle is 4095
|
||||
# you can change the max_angle. ex: sensor.max_angle = 1000
|
||||
|
||||
MIN_CHANGE = 25 # minimum change to register as movement
|
||||
# increase to make less sensitive, decrease to make more sensitive
|
||||
|
||||
while True:
|
||||
enc_val = sensor.angle
|
||||
if abs(enc_val - last_val) >= MIN_CHANGE or abs(enc_val - last_val) > THRESHOLD:
|
||||
# Calculate the difference
|
||||
diff = enc_val - last_val
|
||||
# Check for wraparound
|
||||
if diff > THRESHOLD:
|
||||
# Wrapped from ~4095 to ~0 (actually turning backwards)
|
||||
cc.send(enc_dec)
|
||||
elif diff < -THRESHOLD:
|
||||
# Wrapped from ~0 to ~4095 (actually turning forwards)
|
||||
cc.send(enc_inc)
|
||||
elif diff > 0:
|
||||
# Normal forward rotation
|
||||
cc.send(enc_inc)
|
||||
else:
|
||||
# Normal backward rotation (diff < 0)
|
||||
cc.send(enc_dec)
|
||||
last_val = enc_val
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2025 Carter Nelson for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Basic ON/OFF control of DC motor via DRV8833
|
||||
|
||||
#define AIN1 5
|
||||
#define AIN2 6
|
||||
#define SLP 7
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Adafruit DRV8833 DC Motor Example - ON/OFF");
|
||||
|
||||
// configure pins
|
||||
pinMode(AIN1, OUTPUT);
|
||||
pinMode(AIN2, OUTPUT);
|
||||
pinMode(SLP, OUTPUT);
|
||||
|
||||
// enable DRV8833
|
||||
digitalWrite(SLP, HIGH);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
//
|
||||
// FORWARD
|
||||
//
|
||||
Serial.println("Forward");
|
||||
digitalWrite(AIN1, HIGH);
|
||||
digitalWrite(AIN2, LOW);
|
||||
delay(1000);
|
||||
|
||||
//
|
||||
// REVERSE
|
||||
//
|
||||
Serial.println("Reverse");
|
||||
digitalWrite(AIN1, LOW);
|
||||
digitalWrite(AIN2, HIGH);
|
||||
delay(1000);
|
||||
}
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2025 Carter Nelson for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// PWM speed control of DC motor via DRV8833
|
||||
|
||||
#define AIN1 5
|
||||
#define AIN2 6
|
||||
#define SLP 7
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Adafruit DRV8833 DC Motor Example - PWM");
|
||||
|
||||
// configure pins
|
||||
pinMode(AIN1, OUTPUT);
|
||||
pinMode(AIN2, OUTPUT);
|
||||
pinMode(SLP, OUTPUT);
|
||||
|
||||
// enable DRV8833
|
||||
digitalWrite(SLP, HIGH);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
//
|
||||
// FORWARD
|
||||
//
|
||||
Serial.println("Forward");
|
||||
digitalWrite(AIN2, LOW);
|
||||
// ramp speed up
|
||||
Serial.println(" ramping up");
|
||||
for (int duty_cycle=0; duty_cycle<256; duty_cycle++) {
|
||||
analogWrite(AIN1, duty_cycle);
|
||||
delay(10);
|
||||
}
|
||||
// ramp speed down
|
||||
Serial.println(" ramping down");
|
||||
for (int duty_cycle=255; duty_cycle>=0; duty_cycle--) {
|
||||
analogWrite(AIN1, duty_cycle);
|
||||
delay(10);
|
||||
}
|
||||
|
||||
//
|
||||
// REVERSE
|
||||
//
|
||||
Serial.println("Reverse");
|
||||
digitalWrite(AIN1, LOW);
|
||||
// ramp speed up
|
||||
Serial.println(" ramping up");
|
||||
for (int duty_cycle=0; duty_cycle<256; duty_cycle++) {
|
||||
analogWrite(AIN2, duty_cycle);
|
||||
delay(10);
|
||||
}
|
||||
// ramp speed down
|
||||
Serial.println(" ramping down");
|
||||
for (int duty_cycle=255; duty_cycle>=0; duty_cycle--) {
|
||||
analogWrite(AIN2, duty_cycle);
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2025 lady ada for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <Stepper.h>
|
||||
|
||||
// change this to the number of steps on your motor
|
||||
#define STEPS 200
|
||||
|
||||
// create an instance of the stepper class, specifying
|
||||
// the number of steps of the motor and the pins it's
|
||||
// attached to
|
||||
Stepper stepper(STEPS, 4, 5, 6, 7);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
Serial.println("Stepper test!");
|
||||
// set the speed of the motor to 30 RPMs
|
||||
stepper.setSpeed(60);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.println("Forward");
|
||||
stepper.step(STEPS);
|
||||
Serial.println("Backward");
|
||||
stepper.step(-STEPS);
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2025 Carter Nelson for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import time
|
||||
import board
|
||||
import digitalio
|
||||
|
||||
# Configure pins
|
||||
AIN1 = digitalio.DigitalInOut(board.D5)
|
||||
AIN2 = digitalio.DigitalInOut(board.D6)
|
||||
SLP = digitalio.DigitalInOut(board.D7)
|
||||
|
||||
AIN1.switch_to_output()
|
||||
AIN2.switch_to_output()
|
||||
SLP.switch_to_output()
|
||||
|
||||
# Enable DRV8833
|
||||
SLP.value = True
|
||||
|
||||
# Loop forever
|
||||
while True:
|
||||
#
|
||||
# FORWARD
|
||||
#
|
||||
print("Forward")
|
||||
AIN1.value = True
|
||||
AIN2.value = False
|
||||
time.sleep(1)
|
||||
|
||||
#
|
||||
# REVERSE
|
||||
#
|
||||
print("Reverse")
|
||||
AIN1.value = False
|
||||
AIN2.value = True
|
||||
time.sleep(1)
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2025 Carter Nelson for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import time
|
||||
import board
|
||||
import digitalio
|
||||
import pwmio
|
||||
|
||||
# Configure pins
|
||||
AIN1 = pwmio.PWMOut(board.D5, frequency=2000)
|
||||
AIN2 = pwmio.PWMOut(board.D6, frequency=2000)
|
||||
SLP = digitalio.DigitalInOut(board.D7)
|
||||
|
||||
SLP.switch_to_output()
|
||||
|
||||
# Enable DRV8833
|
||||
SLP.value = True
|
||||
|
||||
# Loop forever
|
||||
while True:
|
||||
#
|
||||
# FORWARD
|
||||
#
|
||||
print("Forward")
|
||||
AIN2.duty_cycle = 0
|
||||
print(" ramping up")
|
||||
for duty_cycle in range(0, 65536, 100):
|
||||
AIN1.duty_cycle = duty_cycle
|
||||
time.sleep(0.01)
|
||||
print(" ramping down")
|
||||
for duty_cycle in range(65535, -1, -100):
|
||||
AIN1.duty_cycle = duty_cycle
|
||||
time.sleep(0.01)
|
||||
|
||||
#
|
||||
# REVERSE
|
||||
#
|
||||
print("Reverse")
|
||||
AIN1.duty_cycle = 0
|
||||
print(" ramping up")
|
||||
for duty_cycle in range(0, 65536, 100):
|
||||
AIN2.duty_cycle = duty_cycle
|
||||
time.sleep(0.01)
|
||||
print(" ramping down")
|
||||
for duty_cycle in range(65535, -1, -100):
|
||||
AIN2.duty_cycle = duty_cycle
|
||||
time.sleep(0.01)
|
||||
|
|
@ -93,7 +93,7 @@ void disableInternalPower() {
|
|||
#endif
|
||||
|
||||
#if defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2)
|
||||
// turn off the I2C power by setting pin to rest state (off)
|
||||
// turn on the I2C power by setting pin to rest state (off)
|
||||
pinMode(PIN_I2C_POWER, INPUT);
|
||||
pinMode(NEOPIXEL_POWER, OUTPUT);
|
||||
digitalWrite(NEOPIXEL_POWER, LOW);
|
||||
|
|
|
|||
|
|
@ -109,32 +109,16 @@ void setup() {
|
|||
digitalWrite(ESP32_RESETN, HIGH);
|
||||
pixel.setPixelColor(0, 20, 20, 0); pixel.show();
|
||||
delay(100);
|
||||
|
||||
#if defined(LED_BUILTIN)
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
while (Serial.available()) {
|
||||
#if defined(ARDUINO_ARCH_RP2040) // Neopixel is blocking and this annoys esptool
|
||||
#if defined(LED_BUILTIN)
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
#else
|
||||
pixel.setPixelColor(0, 10, 0, 0); pixel.show();
|
||||
#endif
|
||||
SerialESP32.write(Serial.read());
|
||||
}
|
||||
|
||||
while (SerialESP32.available()) {
|
||||
#if defined(ARDUINO_ARCH_RP2040) // Neopixel is blocking and this annoys esptool
|
||||
#if defined(LED_BUILTIN)
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
#endif
|
||||
#else
|
||||
pixel.setPixelColor(0, 0, 0, 10); pixel.show();
|
||||
#endif
|
||||
Serial.write(SerialESP32.read());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,105 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2025 Limor Fried for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "config.h"
|
||||
#include <Adafruit_BME280.h>
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
|
||||
Adafruit_BME280 bme; // I2C
|
||||
|
||||
AdafruitIO_Feed *temperature = io.feed("temperature");
|
||||
AdafruitIO_Feed *humidity = io.feed("humidity");
|
||||
AdafruitIO_Feed *pressure = io.feed("pressure");
|
||||
float temp, humid, pres;
|
||||
|
||||
Adafruit_NeoPixel pixel(1, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
|
||||
// wait for serial monitor to open
|
||||
//while(! Serial);
|
||||
|
||||
// turn on neopixel
|
||||
pinMode(NEOPIXEL_POWER, OUTPUT);
|
||||
digitalWrite(NEOPIXEL_POWER, HIGH);
|
||||
pixel.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
|
||||
pixel.setBrightness(10); // not so bright
|
||||
|
||||
pixel.setPixelColor(0, 0xFF0000); // red
|
||||
pixel.show();
|
||||
|
||||
if (! bme.begin()) {
|
||||
Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
|
||||
deepSleep();
|
||||
}
|
||||
Serial.println("Found BME280");
|
||||
float temp = bme.readTemperature();
|
||||
float pres = bme.readPressure() / 100.0F;
|
||||
float hum = bme.readHumidity();
|
||||
// shhh time to close your eyes
|
||||
bme.setSampling(Adafruit_BME280::MODE_SLEEP,
|
||||
Adafruit_BME280::SAMPLING_X16, Adafruit_BME280::SAMPLING_X16, Adafruit_BME280::SAMPLING_X16,
|
||||
Adafruit_BME280::FILTER_OFF,
|
||||
Adafruit_BME280::STANDBY_MS_1000);
|
||||
|
||||
Serial.print("Connecting to Adafruit IO");
|
||||
|
||||
pixel.setPixelColor(0, 0xFFFF00); // yellow
|
||||
pixel.show();
|
||||
|
||||
// connect to io.adafruit.com
|
||||
io.connect();
|
||||
|
||||
// wait for a connection
|
||||
while(io.status() < AIO_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// we are connected
|
||||
pixel.setPixelColor(0, 0x00FF00); // green
|
||||
pixel.show();
|
||||
Serial.println();
|
||||
Serial.println(io.statusText());
|
||||
|
||||
io.run();
|
||||
|
||||
temp = temp * 9.0 / 5.0 + 32;
|
||||
Serial.print("Temperature = ");
|
||||
Serial.print(temp);
|
||||
Serial.println(" *F");
|
||||
temperature->save(temp);
|
||||
|
||||
Serial.print("Pressure = ");
|
||||
Serial.print(pres);
|
||||
Serial.println(" hPa");
|
||||
pressure->save(pres);
|
||||
|
||||
Serial.print("Humidity = ");
|
||||
Serial.print(hum);
|
||||
Serial.println(" %");
|
||||
humidity->save(hum);
|
||||
|
||||
Serial.println();
|
||||
|
||||
deepSleep();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// we never get here!
|
||||
}
|
||||
|
||||
|
||||
void deepSleep() {
|
||||
pinMode(NEOPIXEL_POWER, OUTPUT);
|
||||
digitalWrite(NEOPIXEL_POWER, LOW); // off
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
esp_sleep_enable_timer_wakeup(300000000); // 5 minutes
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2025 Limor Fried for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
#define IO_USERNAME "your-aio-username"
|
||||
#define IO_KEY "your-aio-token"
|
||||
#define WIFI_SSID "your-wifi-ssid"
|
||||
#define WIFI_PASS "your-wifi-pass"
|
||||
|
||||
#include "AdafruitIO_WiFi.h"
|
||||
AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS);
|
||||
|
|
@ -3,8 +3,6 @@
|
|||
"""
|
||||
CircuitPython Adafruit IO Example for BME280 and LC709203 Sensors
|
||||
"""
|
||||
|
||||
from os import getenv
|
||||
import time
|
||||
import ssl
|
||||
import alarm
|
||||
|
|
@ -16,21 +14,11 @@ import adafruit_requests
|
|||
from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError
|
||||
from adafruit_lc709203f import LC709203F, PackSize
|
||||
from adafruit_bme280 import basic as adafruit_bme280
|
||||
|
||||
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
|
||||
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
|
||||
aio_key = getenv("ADAFRUIT_AIO_KEY")
|
||||
|
||||
if None in [ssid, password, aio_username, aio_key]:
|
||||
raise RuntimeError(
|
||||
"WiFi and Adafruit IO settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum."
|
||||
)
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi and Adafruit IO credentials are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
|
||||
# Duration of sleep in seconds. Default is 600 seconds (10 minutes).
|
||||
# Feather will sleep for this duration between sensor readings / sending data to AdafruitIO
|
||||
|
|
@ -90,9 +78,9 @@ def send_io_data(feed, value):
|
|||
# Wi-Fi connections can have issues! This ensures the code will continue to run.
|
||||
try:
|
||||
# Connect to Wi-Fi
|
||||
wifi.radio.connect(ssid, password)
|
||||
print(f"Connected to {ssid}!")
|
||||
print(f"IP: {wifi.radio.ipv4_address}")
|
||||
wifi.radio.connect(secrets["ssid"], secrets["password"])
|
||||
print("Connected to {}!".format(secrets["ssid"]))
|
||||
print("IP:", wifi.radio.ipv4_address)
|
||||
|
||||
pool = socketpool.SocketPool(wifi.radio)
|
||||
requests = adafruit_requests.Session(pool, ssl.create_default_context())
|
||||
|
|
@ -102,6 +90,12 @@ except Exception as e: # pylint: disable=broad-except
|
|||
print(e)
|
||||
go_to_sleep(60)
|
||||
|
||||
# Set your Adafruit IO Username and Key in secrets.py
|
||||
# (visit io.adafruit.com if you need to create an account,
|
||||
# or if you need your Adafruit IO key.)
|
||||
aio_username = secrets["aio_username"]
|
||||
aio_key = secrets["aio_key"]
|
||||
|
||||
# Initialize an Adafruit IO HTTP API object
|
||||
io = IO_HTTP(aio_username, aio_key, requests)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ CircuitPython Simple Example for BME280 and LC709203 Sensors
|
|||
"""
|
||||
import time
|
||||
import board
|
||||
from adafruit_lc709203f import LC709203F, PackSize
|
||||
from adafruit_bme280 import basic as adafruit_bme280
|
||||
from adafruit_lc709203f import LC709203F, PackSize
|
||||
|
||||
# Create sensor objects, using the board's default I2C bus.
|
||||
i2c = board.I2C() # uses board.SCL and board.SDA
|
||||
|
|
|
|||
|
|
@ -1,110 +0,0 @@
|
|||
# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
"""
|
||||
CircuitPython example for deep sleep and BME280 sensor sending data
|
||||
to Adafruit IO.
|
||||
"""
|
||||
from os import getenv
|
||||
import time
|
||||
import alarm
|
||||
import board
|
||||
import digitalio
|
||||
import neopixel
|
||||
import wifi
|
||||
|
||||
from adafruit_bme280 import advanced as adafruit_bme280
|
||||
import adafruit_connection_manager
|
||||
import adafruit_requests
|
||||
from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError
|
||||
|
||||
|
||||
# enable power to NeoPixels.
|
||||
np_power = digitalio.DigitalInOut(board.NEOPIXEL_POWER)
|
||||
np_power.switch_to_output(value=True)
|
||||
|
||||
# standard LED
|
||||
builtin_led = digitalio.DigitalInOut(board.LED)
|
||||
builtin_led.switch_to_output(value=True)
|
||||
|
||||
# neopixel to use for status
|
||||
status_pixel = neopixel.NeoPixel(
|
||||
board.NEOPIXEL, 1, brightness=0.1, pixel_order=neopixel.GRB, auto_write=True
|
||||
)
|
||||
status_pixel[0] = 0xFF0000
|
||||
|
||||
# Create sensor object, using the board's default I2C bus.
|
||||
i2c = board.I2C() # uses board.SCL and board.SDA
|
||||
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c)
|
||||
print("Found BME280")
|
||||
# change this to match the location's pressure (hPa) at sea level
|
||||
bme280.sea_level_pressure = 1013.25
|
||||
|
||||
# temperature converted to F
|
||||
temperature = bme280.temperature * 9 / 5 + 32
|
||||
humidity = bme280.relative_humidity
|
||||
pressure = bme280.pressure
|
||||
print("\nTemperature: %0.1f F" % temperature)
|
||||
print("Humidity: %0.1f %%" % humidity)
|
||||
print("Pressure: %0.1f hPa" % pressure)
|
||||
|
||||
bme280.mode = adafruit_bme280.MODE_SLEEP
|
||||
bme280.overscan_temperature = adafruit_bme280.OVERSCAN_X16
|
||||
bme280.overscan_humidity = adafruit_bme280.OVERSCAN_X16
|
||||
bme280.overscan_pressure = adafruit_bme280.OVERSCAN_X16
|
||||
bme280.iir_filter = adafruit_bme280.IIR_FILTER_DISABLE
|
||||
bme280.standby_period = adafruit_bme280.STANDBY_TC_1000
|
||||
|
||||
# set status pixel to yellow
|
||||
status_pixel[0] = 0xFFFF00
|
||||
|
||||
print("Connecting to AdafruitIO")
|
||||
|
||||
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
|
||||
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
|
||||
ssid = getenv("WIFI_SSID")
|
||||
password = getenv("WIFI_PASSWORD")
|
||||
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
|
||||
aio_key = getenv("ADAFRUIT_AIO_KEY")
|
||||
|
||||
print("Connecting to %s" % ssid)
|
||||
wifi.radio.connect(ssid, password)
|
||||
print("Connected to %s!" % ssid)
|
||||
|
||||
# setup socket pool and requests session
|
||||
pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio)
|
||||
ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio)
|
||||
requests = adafruit_requests.Session(pool, ssl_context)
|
||||
|
||||
# Initialize an Adafruit IO HTTP API object
|
||||
io = IO_HTTP(aio_username, aio_key, requests)
|
||||
|
||||
# set status pixel to green
|
||||
status_pixel[0] = 0x00FF00
|
||||
|
||||
try:
|
||||
# Get the feeds from Adafruit IO
|
||||
temperature_feed = io.get_feed("temperature")
|
||||
humidity_feed = io.get_feed("humidity")
|
||||
pressure_feed = io.get_feed("pressure")
|
||||
|
||||
# send data to the feeds
|
||||
io.send_data(temperature_feed["key"], temperature)
|
||||
io.send_data(humidity_feed["key"], humidity)
|
||||
io.send_data(pressure_feed["key"], pressure)
|
||||
|
||||
except AdafruitIO_RequestError as e:
|
||||
print(e)
|
||||
print(
|
||||
"You must create feeds on AdafruitIO for: temperature, humidity, and pressure"
|
||||
)
|
||||
|
||||
# turn off the neopixel and builtin LED
|
||||
np_power.value = False
|
||||
builtin_led.value = False
|
||||
|
||||
# Create an alarm that will trigger 5 minutes from now.
|
||||
time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + (5 * 60))
|
||||
# Exit the program, and then deep sleep until the alarm wakes us.
|
||||
alarm.exit_and_deep_sleep_until_alarms(time_alarm)
|
||||
# Does not return, so we never get here.
|
||||
|
|
@ -3,8 +3,6 @@
|
|||
"""
|
||||
CircuitPython Adafruit IO Example for LC709203 Sensor
|
||||
"""
|
||||
|
||||
from os import getenv
|
||||
import time
|
||||
import ssl
|
||||
import alarm
|
||||
|
|
@ -15,21 +13,11 @@ import socketpool
|
|||
import adafruit_requests
|
||||
from adafruit_io.adafruit_io import IO_HTTP
|
||||
from adafruit_lc709203f import LC709203F, PackSize
|
||||
|
||||
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
|
||||
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
|
||||
aio_key = getenv("ADAFRUIT_AIO_KEY")
|
||||
|
||||
if None in [ssid, password, aio_username, aio_key]:
|
||||
raise RuntimeError(
|
||||
"WiFi and Adafruit IO settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum."
|
||||
)
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi and Adafruit IO credentials are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
|
||||
# Duration of sleep in seconds. Default is 600 seconds (10 minutes).
|
||||
# Feather will sleep for this duration between sensor readings / sending data to AdafruitIO
|
||||
|
|
@ -70,9 +58,9 @@ def send_io_data(feed, value):
|
|||
# Wi-Fi connections can have issues! This ensures the code will continue to run.
|
||||
try:
|
||||
# Connect to Wi-Fi
|
||||
wifi.radio.connect(ssid, password)
|
||||
print(f"Connected to {ssid}!")
|
||||
print(f"IP: {wifi.radio.ipv4_address}")
|
||||
wifi.radio.connect(secrets["ssid"], secrets["password"])
|
||||
print("Connected to {}!".format(secrets["ssid"]))
|
||||
print("IP:", wifi.radio.ipv4_address)
|
||||
|
||||
pool = socketpool.SocketPool(wifi.radio)
|
||||
requests = adafruit_requests.Session(pool, ssl.create_default_context())
|
||||
|
|
@ -82,6 +70,12 @@ except Exception as e: # pylint: disable=broad-except
|
|||
print(e)
|
||||
go_to_sleep(60)
|
||||
|
||||
# Set your Adafruit IO Username and Key in secrets.py
|
||||
# (visit io.adafruit.com if you need to create an account,
|
||||
# or if you need your Adafruit IO key.)
|
||||
aio_username = secrets["aio_username"]
|
||||
aio_key = secrets["aio_key"]
|
||||
|
||||
# Initialize an Adafruit IO HTTP API object
|
||||
io = IO_HTTP(aio_username, aio_key, requests)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@
|
|||
"""
|
||||
CircuitPython GitHub Stars viewer
|
||||
"""
|
||||
|
||||
from os import getenv
|
||||
import time
|
||||
import ssl
|
||||
import wifi
|
||||
|
|
@ -15,17 +13,12 @@ from adafruit_display_text import bitmap_label
|
|||
from adafruit_bitmap_font import bitmap_font
|
||||
import adafruit_requests
|
||||
|
||||
# Get WiFi details, ensure these are setup in settings.toml
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
|
||||
if None in [ssid, password]:
|
||||
raise RuntimeError(
|
||||
"WiFi settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"at a minimum."
|
||||
)
|
||||
# Get WiFi details secrets.py file
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi secrets are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
|
||||
display = board.DISPLAY
|
||||
|
||||
|
|
@ -45,10 +38,10 @@ group.append(text_area)
|
|||
display.root_group = group
|
||||
|
||||
# Connect to WiFi
|
||||
print(f"Connecting to {ssid}")
|
||||
wifi.radio.connect(ssid, password)
|
||||
print(f"Connected to {ssid}!")
|
||||
print(f"My IP address is {wifi.radio.ipv4_address}")
|
||||
print("Connecting to %s"%secrets["ssid"])
|
||||
wifi.radio.connect(secrets["ssid"], secrets["password"])
|
||||
print("Connected to %s!"%secrets["ssid"])
|
||||
print("My IP address is", wifi.radio.ipv4_address)
|
||||
|
||||
pool = socketpool.SocketPool(wifi.radio)
|
||||
requests = adafruit_requests.Session(pool, ssl.create_default_context())
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ LOOP = False # Update to True loop WAV playback. False plays once.
|
|||
|
||||
audio = audiobusio.I2SOut(board.A2, board.A1, board.A0)
|
||||
|
||||
with open("booploop.wav", "rb") as wave_file:
|
||||
with open("chikken.wav", "rb") as wave_file:
|
||||
wav = audiocore.WaveFile(wave_file)
|
||||
|
||||
print("Playing wav file!")
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from os import getenv
|
||||
import time
|
||||
import board
|
||||
import busio
|
||||
|
|
@ -23,23 +22,15 @@ USE_CELSIUS = False
|
|||
# Interval the sensor publishes to Adafruit IO, in minutes
|
||||
PUBLISH_INTERVAL = 10
|
||||
|
||||
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
|
||||
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
|
||||
aio_key = getenv("ADAFRUIT_AIO_KEY")
|
||||
|
||||
if None in [ssid, password, aio_username, aio_key]:
|
||||
raise RuntimeError(
|
||||
"WiFi and Adafruit IO settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum."
|
||||
)
|
||||
|
||||
### WiFi ###
|
||||
|
||||
# Get wifi details and more from a secrets.py file
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi secrets are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
|
||||
# AirLift FeatherWing
|
||||
esp32_cs = DigitalInOut(board.D13)
|
||||
esp32_reset = DigitalInOut(board.D12)
|
||||
|
|
@ -47,8 +38,8 @@ esp32_ready = DigitalInOut(board.D11)
|
|||
|
||||
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
|
||||
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
|
||||
status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2)
|
||||
wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel)
|
||||
status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2)
|
||||
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
|
||||
|
||||
# Connect to a PM2.5 sensor over UART
|
||||
reset_pin = None
|
||||
|
|
@ -151,7 +142,7 @@ def read_bme(is_celsius=False):
|
|||
|
||||
|
||||
# Create an instance of the Adafruit IO HTTP client
|
||||
io = IO_HTTP(aio_username, aio_key, wifi)
|
||||
io = IO_HTTP(secrets["aio_user"], secrets["aio_key"], wifi)
|
||||
|
||||
# Describes feeds used to hold Adafruit IO data
|
||||
feed_aqi = io.get_feed("air-quality-sensor.aqi")
|
||||
|
|
@ -159,11 +150,11 @@ feed_aqi_category = io.get_feed("air-quality-sensor.category")
|
|||
feed_humidity = io.get_feed("air-quality-sensor.humidity")
|
||||
feed_temperature = io.get_feed("air-quality-sensor.temperature")
|
||||
|
||||
# Set up location metadata from settings.toml file
|
||||
# Set up location metadata from secrets.py file
|
||||
location_metadata = {
|
||||
"lat": getenv("latitude"),
|
||||
"lon": getenv("longitude"),
|
||||
"ele": getenv("elevation"),
|
||||
"lat": secrets["latitude"],
|
||||
"lon": secrets["longitude"],
|
||||
"ele": secrets["elevation"],
|
||||
}
|
||||
|
||||
elapsed_minutes = 0
|
||||
|
|
|
|||
|
|
@ -14,20 +14,13 @@ from adafruit_esp32spi import adafruit_esp32spi_wifimanager
|
|||
|
||||
import adafruit_minimqtt.adafruit_minimqtt as MQTT
|
||||
|
||||
# Get WiFi details, ensure these are setup in settings.toml
|
||||
ssid = os.getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = os.getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
|
||||
if None in [ssid, password]:
|
||||
raise RuntimeError(
|
||||
"WiFi settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"at a minimum."
|
||||
)
|
||||
|
||||
### WiFi ###
|
||||
|
||||
secrets = {
|
||||
"ssid" : os.getenv("CIRCUITPY_WIFI_SSID"),
|
||||
"password" : os.getenv("CIRCUITPY_WIFI_PASSWORD"),
|
||||
}
|
||||
|
||||
# If you are using a board with pre-defined ESP32 Pins:
|
||||
esp32_cs = DigitalInOut(board.ESP_CS)
|
||||
esp32_ready = DigitalInOut(board.ESP_BUSY)
|
||||
|
|
@ -41,19 +34,19 @@ esp32_reset = DigitalInOut(board.ESP_RESET)
|
|||
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
|
||||
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
|
||||
"""Use below for Most Boards"""
|
||||
status_pixel = neopixel.NeoPixel(
|
||||
status_light = neopixel.NeoPixel(
|
||||
board.NEOPIXEL, 1, brightness=0.2
|
||||
) # Uncomment for Most Boards
|
||||
"""Uncomment below for ItsyBitsy M4"""
|
||||
# status_pixel = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
|
||||
# status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
|
||||
# Uncomment below for an externally defined RGB LED
|
||||
# import adafruit_rgbled
|
||||
# from adafruit_esp32spi import PWMOut
|
||||
# RED_LED = PWMOut.PWMOut(esp, 26)
|
||||
# GREEN_LED = PWMOut.PWMOut(esp, 27)
|
||||
# BLUE_LED = PWMOut.PWMOut(esp, 25)
|
||||
# status_pixel = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
|
||||
wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel)
|
||||
# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
|
||||
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
|
||||
|
||||
# Set up a pin for controlling the relay
|
||||
power_pin = DigitalInOut(board.D3)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from os import getenv
|
||||
import time
|
||||
import board
|
||||
import busio
|
||||
|
|
@ -15,21 +14,6 @@ from adafruit_esp32spi import adafruit_esp32spi_wifimanager
|
|||
|
||||
import adafruit_minimqtt.adafruit_minimqtt as MQTT
|
||||
|
||||
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
|
||||
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
|
||||
aio_key = getenv("ADAFRUIT_AIO_KEY")
|
||||
|
||||
if None in [ssid, password, aio_username, aio_key]:
|
||||
raise RuntimeError(
|
||||
"WiFi and Adafruit IO settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum."
|
||||
)
|
||||
|
||||
### Sensor Calibration ###
|
||||
# Appliance power LED's light level, in Lux
|
||||
APPLIANCE_ON_LUX = 30.0
|
||||
|
|
@ -38,6 +22,13 @@ SENSOR_READ_TIME = 10.0
|
|||
|
||||
### WiFi ###
|
||||
|
||||
# Get wifi details and more from a secrets.py file
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi secrets are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
|
||||
# If you are using a board with pre-defined ESP32 Pins:
|
||||
esp32_cs = DigitalInOut(board.ESP_CS)
|
||||
esp32_ready = DigitalInOut(board.ESP_BUSY)
|
||||
|
|
@ -51,19 +42,19 @@ esp32_reset = DigitalInOut(board.ESP_RESET)
|
|||
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
|
||||
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
|
||||
"""Use below for Most Boards"""
|
||||
status_pixel = neopixel.NeoPixel(
|
||||
status_light = neopixel.NeoPixel(
|
||||
board.NEOPIXEL, 1, brightness=0.2
|
||||
) # Uncomment for Most Boards
|
||||
"""Uncomment below for ItsyBitsy M4"""
|
||||
# status_pixel = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
|
||||
# status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
|
||||
# Uncomment below for an externally defined RGB LED
|
||||
# import adafruit_rgbled
|
||||
# from adafruit_esp32spi import PWMOut
|
||||
# RED_LED = PWMOut.PWMOut(esp, 26)
|
||||
# GREEN_LED = PWMOut.PWMOut(esp, 27)
|
||||
# BLUE_LED = PWMOut.PWMOut(esp, 25)
|
||||
# status_pixel = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
|
||||
wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel)
|
||||
# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
|
||||
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
|
||||
|
||||
# Set up a pin for controlling the relay
|
||||
power_pin = DigitalInOut(board.D3)
|
||||
|
|
@ -76,10 +67,10 @@ sensor = adafruit_bh1750.BH1750(i2c)
|
|||
|
||||
### Feeds ###
|
||||
# Set up a feed named Relay for subscribing to the relay feed on Adafruit IO
|
||||
feed_relay = f"{aio_username}/feeds/relay"
|
||||
feed_relay = secrets["aio_username"] + "/feeds/relay"
|
||||
|
||||
# Set up a feed named status for subscribing to the status feed on Adafruit IO
|
||||
feed_status = f"{aio_username}/feeds/status"
|
||||
feed_status = secrets["aio_username"] + "/feeds/status"
|
||||
|
||||
### Code ###
|
||||
|
||||
|
|
@ -131,8 +122,8 @@ ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp)
|
|||
# Set up a MiniMQTT Client
|
||||
client = MQTT.MQTT(
|
||||
broker="io.adafruit.com",
|
||||
username=aio_username,
|
||||
password=aio_key,
|
||||
username=secrets["aio_username"],
|
||||
password=secrets["aio_key"],
|
||||
socket_pool=pool,
|
||||
ssl_context=ssl_context,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
{
|
||||
"exportVersion": "1.0.0",
|
||||
"exportedBy": "tyeth_demo",
|
||||
"exportedAt": "2025-05-02T17:08:03.857Z",
|
||||
"exportedFromDevice": {
|
||||
"board": "rpi-pico-w",
|
||||
"firmwareVersion": "1.0.0-beta.100"
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"name": "Reed Switch",
|
||||
"pinName": "D13",
|
||||
"type": "reed_switch",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "INPUT",
|
||||
"period": 0,
|
||||
"pull": "UP",
|
||||
"isPin": true,
|
||||
"visualization": {
|
||||
"offLabel": "Open",
|
||||
"offIcon": "fa6:solid:door-open",
|
||||
"onLabel": "Closed",
|
||||
"onIcon": "fa6:regular:door-closed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from os import getenv
|
||||
import time
|
||||
import board
|
||||
import busio
|
||||
|
|
@ -14,23 +13,15 @@ import neopixel
|
|||
import adafruit_minimqtt.adafruit_minimqtt as MQTT
|
||||
from adafruit_io.adafruit_io import IO_MQTT
|
||||
|
||||
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
|
||||
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
|
||||
aio_key = getenv("ADAFRUIT_AIO_KEY")
|
||||
|
||||
if None in [ssid, password, aio_username, aio_key]:
|
||||
raise RuntimeError(
|
||||
"WiFi and Adafruit IO settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum."
|
||||
)
|
||||
|
||||
### WiFi ###
|
||||
|
||||
# Get wifi details and more from a secrets.py file
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi secrets are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
|
||||
# If you are using a board with pre-defined ESP32 Pins:
|
||||
esp32_cs = DigitalInOut(board.ESP_CS)
|
||||
esp32_ready = DigitalInOut(board.ESP_BUSY)
|
||||
|
|
@ -44,19 +35,19 @@ esp32_reset = DigitalInOut(board.ESP_RESET)
|
|||
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
|
||||
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
|
||||
"""Use below for Most Boards"""
|
||||
status_pixel = neopixel.NeoPixel(
|
||||
status_light = neopixel.NeoPixel(
|
||||
board.NEOPIXEL, 1, brightness=0.2
|
||||
) # Uncomment for Most Boards
|
||||
"""Uncomment below for ItsyBitsy M4"""
|
||||
# status_pixel = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
|
||||
# status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
|
||||
# Uncomment below for an externally defined RGB LED
|
||||
# import adafruit_rgbled
|
||||
# from adafruit_esp32spi import PWMOut
|
||||
# RED_LED = PWMOut.PWMOut(esp, 26)
|
||||
# GREEN_LED = PWMOut.PWMOut(esp, 27)
|
||||
# BLUE_LED = PWMOut.PWMOut(esp, 25)
|
||||
# status_pixel = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
|
||||
wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel)
|
||||
# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
|
||||
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
|
||||
|
||||
# Set up a pin for controlling the relay
|
||||
power_pin = DigitalInOut(board.D3)
|
||||
|
|
@ -98,11 +89,11 @@ def on_message(client, feed_id, payload):
|
|||
|
||||
def on_relay_msg(client, topic, message):
|
||||
# Method called whenever user/feeds/relay has a new value
|
||||
if message == "1":
|
||||
print("Received 1 - turning outlet ON")
|
||||
if message == "morning":
|
||||
print("Morning - turning outlet ON")
|
||||
power_pin.value = True
|
||||
elif message == "0":
|
||||
print("Received 0 - turning outlet OFF")
|
||||
elif message == "night":
|
||||
print("Night - turning outlet OFF")
|
||||
power_pin.value = False
|
||||
else:
|
||||
print("Unexpected value received on relay feed.")
|
||||
|
|
@ -119,8 +110,8 @@ ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp)
|
|||
# Initialize a new MQTT Client object
|
||||
mqtt_client = MQTT.MQTT(
|
||||
broker="io.adafruit.com",
|
||||
username=aio_username,
|
||||
password=aio_key,
|
||||
username=secrets["aio_username"],
|
||||
password=secrets["aio_key"],
|
||||
socket_pool=pool,
|
||||
ssl_context=ssl_context,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ while True:
|
|||
time.sleep(30)
|
||||
|
||||
# Stepper 1
|
||||
if not st1.is_alive() and int(stepper_start.value):
|
||||
if not st1.isAlive() and int(stepper_start.value):
|
||||
stepper_1_steps = aio.receive(feed_step_1_steps.key)
|
||||
stepper_1_steps = int(stepper_1_steps.value)
|
||||
if stepper_1_steps > 0: # stepper slider is set
|
||||
|
|
@ -125,7 +125,7 @@ while True:
|
|||
st1.start()
|
||||
|
||||
# Stepper 2
|
||||
if not st2.is_alive() and int(stepper_start.value):
|
||||
if not st2.isAlive() and int(stepper_start.value):
|
||||
stepper_2_steps = aio.receive(feed_step_2_steps.key)
|
||||
stepper_2_steps = int(stepper_2_steps.value)
|
||||
if stepper_2_steps > 0: # stepper slider is set
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
{
|
||||
"exportVersion": "1.0.0",
|
||||
"exportedBy": "tyeth",
|
||||
"exportedAt": "2025-06-10T18:13:03.071Z",
|
||||
"exportedFromDevice": {
|
||||
"board": "rpi-pico-w",
|
||||
"firmwareVersion": "1.0.0-beta.100"
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"name": "💦 Wee Button",
|
||||
"pinName": "D18",
|
||||
"type": "push_button",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "INPUT",
|
||||
"period": 0,
|
||||
"pull": "UP",
|
||||
"isPin": true
|
||||
},
|
||||
{
|
||||
"name": "💦 Wee LED",
|
||||
"pinName": "D2",
|
||||
"type": "led",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "OUTPUT",
|
||||
"isPin": true
|
||||
},
|
||||
{
|
||||
"name": "💩 Poo Button",
|
||||
"pinName": "D19",
|
||||
"type": "push_button",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "INPUT",
|
||||
"period": 0,
|
||||
"pull": "UP",
|
||||
"isPin": true
|
||||
},
|
||||
{
|
||||
"name": "💩 Poo LED",
|
||||
"pinName": "D3",
|
||||
"type": "led",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "OUTPUT",
|
||||
"isPin": true
|
||||
},
|
||||
{
|
||||
"name": "❌ Didn't Go Button",
|
||||
"pinName": "D20",
|
||||
"type": "push_button",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "INPUT",
|
||||
"period": 0,
|
||||
"pull": "UP",
|
||||
"isPin": true
|
||||
},
|
||||
{
|
||||
"name": "❌ Didn't Go LED",
|
||||
"pinName": "D4",
|
||||
"type": "led",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "OUTPUT",
|
||||
"isPin": true
|
||||
},
|
||||
{
|
||||
"name": "🔔 Tell Adult Button",
|
||||
"pinName": "D21",
|
||||
"type": "push_button",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "INPUT",
|
||||
"period": 0,
|
||||
"pull": "UP",
|
||||
"isPin": true
|
||||
},
|
||||
{
|
||||
"name": "🔔 Tell Adult LED",
|
||||
"pinName": "D5",
|
||||
"type": "led",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "OUTPUT",
|
||||
"isPin": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
<b>🌟 Daily Potty Training Report 🌟</b>
|
||||
Hi there! Here's how our little superstar did:
|
||||
---
|
||||
<b>🚽 Successful Wees: {{ vars.wee_progress }}</b>
|
||||
{% for i in (1..vars.wee_progress) %}💧{% endfor %}
|
||||
{% if vars.wee_progress <= 5 -%}
|
||||
Great start! Every success counts, and they're building good habits one wee at a time! 🌱
|
||||
{% elsif vars.wee_progress <= 15 -%}
|
||||
Fantastic progress! They're really getting the hang of this - keep up the amazing work! 🎯
|
||||
{% else -%}
|
||||
SUPERSTAR ALERT! 🌟 Absolutely crushing it with those wee successes! They're a potty champion! 🏆
|
||||
{% endif %}---
|
||||
|
||||
<b>💩 Successful Poos: {{ vars.poo_progress }}</b>
|
||||
{% for i in (1..vars.poo_progress) %}🟤{% endfor %}
|
||||
{% if vars.poo_progress == 0 -%}
|
||||
Poos can be tricky, but they're being so brave! Every try is a step forward! 💪
|
||||
{% elsif vars.poo_progress < 2 -%}
|
||||
Look at them go! They're becoming a real poo pro - that's awesome progress! 🎉
|
||||
{% else -%}
|
||||
POO CHAMPION! 🏅 They've mastered one of the trickiest parts - so proud! 🎊
|
||||
{% endif %}---
|
||||
|
||||
<b>🤝 Told an Adult: {{ vars.informed_progress }}</b>
|
||||
{% for i in (1..vars.informed_progress) %}🗣️{% endfor %}
|
||||
{% if vars.informed_progress <= 5 -%}
|
||||
Communication is key! Keep practicing saying when they need to go - They're doing great! 📢
|
||||
{% elsif vars.informed_progress <= 15 -%}
|
||||
Wonderful communication skills! They're really good at letting us know - that's so helpful! 👏
|
||||
{% else -%}
|
||||
COMMUNICATION SUPERSTAR! 🌟 They're amazing at telling adults - that's such a big kid skill! 🎯
|
||||
{% endif %}---
|
||||
|
||||
<b>👻 Nothing Happened: {{ vars.nothing_progress }}</b>
|
||||
{% for i in (1..vars.nothing_progress) %}⭕{% endfor %}
|
||||
{% if vars.nothing_progress <= 3 -%}
|
||||
That's okay! Trying is what matters, and their body will let them know when it's ready! 🌈
|
||||
{% else -%}
|
||||
So patient and persistent! Even when nothing happens, they keep trying - that's real determination! 💫
|
||||
{% endif %}---
|
||||
|
||||
<b>📊 Daily Summary:</b>
|
||||
{% capture total_tries -%}{{ vars.wee_progress | plus: vars.poo_progress | plus: vars.nothing_progress }}{% endcapture -%}
|
||||
{% capture successes -%}{{ vars.wee_progress | plus: vars.poo_progress }}{% endcapture -%}
|
||||
{% capture success_rate -%}{% if total_tries != "0" -%}{{ successes | times: 100 | divided_by: total_tries }}{% else -%}100{% endif -%}{% endcapture -%}
|
||||
{% capture bar_filled -%}{{ success_rate | divided_by: 10 }}{% endcapture -%}
|
||||
{% capture bar_empty -%}{{ 10 | minus: bar_filled }}{% endcapture -%}
|
||||
Total potty visits: {{ total_tries }}
|
||||
Success rate: {{ success_rate }}% [{%- for i in (1..bar_filled) -%}█{%- endfor -%}{%- for i in (1..bar_empty) -%}░{%- endfor -%}]
|
||||
{%- assign total_events = vars.wee_progress | plus: vars.poo_progress | plus: vars.nothing_progress | plus: vars.informed_progress -%}
|
||||
({{ total_events }} events today )
|
||||
{% if total_events <= 3 %}
|
||||
💝 <b>Today:</b> They're doing such a great job learning! Every day gets a little easier...
|
||||
{% elsif total_events <= 5 %}
|
||||
🌟 <b>Today:</b> Ayee! They're really getting the hang of this potty training thing! Keep it up!
|
||||
{% elsif total_events <= 8 %}
|
||||
🌟 <b>Today:</b> WOW! Look at all that practice! They're becoming such a potty expert.
|
||||
{% else %}
|
||||
🏆 <b>Today:</b> INCREDIBLE DAY! They're absolutely rocking this potty training journey! 🎊🎉
|
||||
{%- endif %}
|
||||
|
||||
Keep being awesome!
|
||||
With love and high-fives! 🙌
|
||||
---
|
||||
{%- assign event_mod = total_events | modulo: 3 %}
|
||||
{% if event_mod == 0 -%}
|
||||
<i>P.S. Remember: Every expert was once a beginner - they're doing brilliantly! 🌟</i>
|
||||
{% elsif event_mod == 1 -%}
|
||||
<i>P.S. Fun fact: Even superheroes had to learn to use the potty! 🦸</i>
|
||||
{% else -%}
|
||||
<i>P.S. Remember: accidents are just practice in disguise! They're doing amazingly! 💕</i>
|
||||
{% endif %}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
int sensorPin = A0; // select the input pin for the potentiometer
|
||||
int neoPixelPin = 4; // select the pin for the LED
|
||||
int sensorValue = 0; // variable to store the value coming from the sensor
|
||||
|
||||
int readings[10];
|
||||
size_t count = 0;
|
||||
|
||||
Adafruit_NeoPixel strip = Adafruit_NeoPixel(1, neoPixelPin, NEO_GRB + NEO_KHZ800);
|
||||
|
||||
// Insert an int value at index 0 of an int array, shifting all other elements up.
|
||||
// If the array already contains 'maxCount' elements, the last one is dropped.
|
||||
// 'count' is the number of valid elements currently stored in the array.
|
||||
void insert(int arr[], size_t maxCount, int value, size_t &count){
|
||||
// Determine how many elements we need to shift (cannot exceed the array bounds)
|
||||
size_t shiftCount = (count < maxCount) ? count : maxCount - 1;
|
||||
|
||||
// Shift elements up by one position
|
||||
for (size_t i = shiftCount; i > 0; --i) {
|
||||
arr[i] = arr[i - 1];
|
||||
}
|
||||
|
||||
// Insert the new value at the beginning
|
||||
arr[0] = value;
|
||||
|
||||
// Update the element count
|
||||
if (count < maxCount) {
|
||||
++count; // we added a new element
|
||||
} // else count stays the same – the last element was overwritten
|
||||
}
|
||||
|
||||
// Input an array of 10 or fewer int's, and a count of how many have values
|
||||
// Returns average of the values in the array.
|
||||
int average(int arr[], size_t count){
|
||||
int sum = 0;
|
||||
for(int i = 0; i < 10; i++){
|
||||
sum = sum + arr[i];
|
||||
}
|
||||
return sum / count;
|
||||
}
|
||||
|
||||
// Input a value 0 to 255 to get a color value.
|
||||
// The colours are a transition r - g - b - back to r.
|
||||
uint32_t Wheel(byte WheelPos) {
|
||||
WheelPos = 255 - WheelPos;
|
||||
if(WheelPos < 85) {
|
||||
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
|
||||
}
|
||||
if(WheelPos < 170) {
|
||||
WheelPos -= 85;
|
||||
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
|
||||
}
|
||||
WheelPos -= 170;
|
||||
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
strip.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
sensorValue = analogRead(sensorPin);
|
||||
insert(readings, 10, sensorValue, count);
|
||||
strip.setPixelColor(0, Wheel(average(readings, count) / 4));
|
||||
strip.show();
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
|
||||
# SPDX-License-Identifier: MIT
|
||||
"""
|
||||
NeoPot NeoPixel Rainbow Demo
|
||||
"""
|
||||
|
||||
import board
|
||||
import analogio
|
||||
import neopixel
|
||||
import rainbowio
|
||||
|
||||
analog_pin = analogio.AnalogIn(board.A0)
|
||||
knob_pixel = neopixel.NeoPixel(board.D4, 1, brightness=0.75, auto_write=True)
|
||||
|
||||
analog_smoothing_buffer = []
|
||||
|
||||
|
||||
def map_range(x, in_min, in_max, out_min, out_max):
|
||||
return (x - in_min) / (in_max - in_min) * out_max - out_min
|
||||
|
||||
|
||||
def average(values):
|
||||
if not values:
|
||||
return 0
|
||||
|
||||
return sum(values) / len(values)
|
||||
|
||||
|
||||
while True:
|
||||
analog_smoothing_buffer.insert(0, analog_pin.value)
|
||||
if len(analog_smoothing_buffer) >= 10:
|
||||
analog_smoothing_buffer.pop(-1)
|
||||
|
||||
knob_pixel[0] = rainbowio.colorwheel(
|
||||
map_range(average(analog_smoothing_buffer), 0, 65525, 0, 255)
|
||||
)
|
||||
|
|
@ -7,7 +7,6 @@ library example esp32spi_simpletest.py:
|
|||
https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI/
|
||||
blob/master/examples/esp32spi_simpletest.py '''
|
||||
|
||||
from os import getenv
|
||||
import board
|
||||
import busio
|
||||
from digitalio import DigitalInOut
|
||||
|
|
@ -15,17 +14,12 @@ import adafruit_connection_manager
|
|||
import adafruit_requests
|
||||
from adafruit_esp32spi import adafruit_esp32spi
|
||||
|
||||
# Get WiFi details, ensure these are setup in settings.toml
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
|
||||
if None in [ssid, password]:
|
||||
raise RuntimeError(
|
||||
"WiFi settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"at a minimum."
|
||||
)
|
||||
# Get wifi details and more from a secrets.py file
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi secrets are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
|
||||
print("Arduino Nano RP2040 Connect webclient test")
|
||||
|
||||
|
|
@ -52,16 +46,16 @@ print("Firmware vers.", esp.firmware_version)
|
|||
print("MAC addr:", [hex(i) for i in esp.MAC_address])
|
||||
|
||||
for ap in esp.scan_networks():
|
||||
print("\t%s\t\tRSSI: %d" % (str(ap.ssid, 'utf-8'), ap.rssi))
|
||||
print("\t%s\t\tRSSI: %d" % (str(ap['ssid'], 'utf-8'), ap['rssi']))
|
||||
|
||||
print("Connecting to AP...")
|
||||
while not esp.is_connected:
|
||||
try:
|
||||
esp.connect_AP(ssid, password)
|
||||
esp.connect_AP(secrets["ssid"], secrets["password"])
|
||||
except RuntimeError as e:
|
||||
print("could not connect to AP, retrying: ", e)
|
||||
continue
|
||||
print("Connected to", str(esp.ap_info.ssid, "utf-8"), "\tRSSI:", esp.ap_info.rssi)
|
||||
print("Connected to", str(esp.ssid, "utf-8"), "\tRSSI:", esp.rssi)
|
||||
print("My IP address is", esp.pretty_ip(esp.ip_address))
|
||||
|
||||
print(
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 2.2 KiB |
|
|
@ -1,161 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import os
|
||||
import time
|
||||
import ssl
|
||||
import board
|
||||
import wifi
|
||||
import socketpool
|
||||
import microcontroller
|
||||
import displayio
|
||||
from adafruit_display_text.bitmap_label import Label
|
||||
from adafruit_bitmap_font import bitmap_font
|
||||
import adafruit_imageload
|
||||
from fourwire import FourWire
|
||||
import adafruit_requests
|
||||
from adafruit_gc9a01a import GC9A01A
|
||||
from adafruit_ticks import ticks_ms, ticks_add, ticks_diff
|
||||
|
||||
cad_url = ("https://ssd-api.jpl.nasa.gov/cad.api?"
|
||||
"des=2024%20YR4&body=ALL&"
|
||||
"date-min=2030-01-01&date-max=2060-01-01")
|
||||
sentry_url = "https://ssd-api.jpl.nasa.gov/sentry.api?des=2024%20YR4"
|
||||
# connect to wifi
|
||||
try:
|
||||
wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD'))
|
||||
except TypeError:
|
||||
print("Could not find WiFi info. Check your settings.toml file!")
|
||||
raise
|
||||
context = ssl.create_default_context()
|
||||
with open("/ssd-api-jpl-nasa-gov-chain.pem", "rb") as certfile:
|
||||
context.load_verify_locations(cadata=certfile.read())
|
||||
|
||||
pool = socketpool.SocketPool(wifi.radio)
|
||||
requests = adafruit_requests.Session(pool, context)
|
||||
|
||||
spi = board.SPI()
|
||||
tft_cs = board.TX
|
||||
tft_dc = board.RX
|
||||
tft_reset = None
|
||||
|
||||
displayio.release_displays()
|
||||
|
||||
display_bus = FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_reset)
|
||||
display = GC9A01A(display_bus, width=240, height=240, auto_refresh=False)
|
||||
|
||||
main_group = displayio.Group()
|
||||
display.root_group = main_group
|
||||
|
||||
bitmap_bg, palette_bg = adafruit_imageload.load("/earth_bg.bmp",
|
||||
bitmap=displayio.Bitmap,
|
||||
palette=displayio.Palette)
|
||||
|
||||
grid_bg = displayio.TileGrid(bitmap_bg, pixel_shader=palette_bg)
|
||||
main_group.append(grid_bg)
|
||||
|
||||
font = bitmap_font.load_font('/Arial-14.bdf')
|
||||
name_area = Label(font, text="2024 YR4", color=0xFFFFFF, background_color=0x000000)
|
||||
name_area.anchored_position = (display.width / 2, 0)
|
||||
name_area.anchor_point = (0.5, 0.0)
|
||||
|
||||
date_area = Label(font, text="2032-12-22", color=0xFFFFFF, background_color=0x000000)
|
||||
date_area.anchored_position = (display.width / 2, name_area.height+10)
|
||||
date_area.anchor_point = (0.5, 0.0)
|
||||
|
||||
moon_area = Label(font, text="Moon: ", color=0xFFFFFF, background_color=0x000000)
|
||||
moon_area.anchored_position = (display.width / 2, name_area.height+10 + date_area.height+5)
|
||||
moon_area.anchor_point = (0.5, 0.0)
|
||||
|
||||
earth_area = Label(font, text="Earth: ", color=0xFFFFFF, background_color=0x000000)
|
||||
earth_area.anchored_position = (display.width / 2, name_area.height+10 +
|
||||
moon_area.height+5 +
|
||||
date_area.height + 5)
|
||||
earth_area.anchor_point = (0.5, 0.0)
|
||||
|
||||
impact_area = Label(font, text="Earth Impact: 0.0000%", color=0xFFFFFF, background_color=0x000000)
|
||||
impact_area.anchored_position = (display.width / 2, name_area.height+10 +
|
||||
moon_area.height+5 +
|
||||
earth_area.height + 5 +
|
||||
date_area.height + 5)
|
||||
impact_area.anchor_point = (0.5, 0.0)
|
||||
main_group.append(impact_area)
|
||||
main_group.append(earth_area)
|
||||
main_group.append(moon_area)
|
||||
main_group.append(date_area)
|
||||
main_group.append(name_area)
|
||||
|
||||
bit_asteroid, pal_asteroid = adafruit_imageload.load("/asteroid.bmp",
|
||||
bitmap=displayio.Bitmap,
|
||||
palette=displayio.Palette)
|
||||
|
||||
asteroid = displayio.TileGrid(bit_asteroid, pixel_shader=pal_asteroid,
|
||||
x = 25, y=100)
|
||||
pal_asteroid.make_transparent(0)
|
||||
main_group.append(asteroid)
|
||||
|
||||
def diagonal_travel(bitmap_object, start_x=-59, start_y=-59, end_x=240, end_y=240, delay=0.01):
|
||||
# Set initial position
|
||||
bitmap_object.x = start_x
|
||||
bitmap_object.y = start_y
|
||||
|
||||
# Calculate total movement distance
|
||||
distance_x = end_x - start_x
|
||||
distance_y = end_y - start_y
|
||||
|
||||
# Calculate number of steps (use the larger distance)
|
||||
steps = max(abs(distance_x), abs(distance_y)) // 1
|
||||
|
||||
# Calculate step size for each axis to maintain diagonal movement
|
||||
step_x = distance_x / steps
|
||||
step_y = distance_y / steps
|
||||
|
||||
# Animate the movement
|
||||
for i in range(steps + 1):
|
||||
# Update position
|
||||
bitmap_object.x = int(start_x + (step_x * i))
|
||||
bitmap_object.y = int(start_y + (step_y * i))
|
||||
display.refresh()
|
||||
# Pause to control animation speed
|
||||
time.sleep(delay)
|
||||
|
||||
def au_to_miles(au):
|
||||
# 1 AU = 92,955,807 miles
|
||||
miles_per_au = 92955807
|
||||
|
||||
return au * miles_per_au
|
||||
|
||||
timer_clock = ticks_ms()
|
||||
timer = 3600 * 1000
|
||||
first_run = True
|
||||
|
||||
while True:
|
||||
try:
|
||||
if first_run or ticks_diff(ticks_ms(), timer_clock) >= timer:
|
||||
sentry_response = requests.get(sentry_url)
|
||||
sentry_json = sentry_response.json()
|
||||
impact = sentry_json['summary']['ip']
|
||||
sentry_response.close()
|
||||
overall_ip = float(impact) * 100
|
||||
cad_response = requests.get(cad_url)
|
||||
cad_json = cad_response.json()
|
||||
earth_distance = au_to_miles(float(cad_json['data'][0][4]))
|
||||
earth_area.text = f"{cad_json['data'][0][10]}: {int(earth_distance)} mi"
|
||||
moon_distance = au_to_miles(float(cad_json['data'][1][4]))
|
||||
moon_area.text = f"{cad_json['data'][1][10]}: {int(moon_distance)} mi"
|
||||
date = cad_json['data'][0][3]
|
||||
date = date.split()
|
||||
date_area.text = f"{date[0]}"
|
||||
cad_response.close()
|
||||
impact_area.text = f"Earth Impact: {overall_ip:.4f}%"
|
||||
display.refresh()
|
||||
timer_clock = ticks_add(timer_clock, timer)
|
||||
diagonal_travel(asteroid, start_x=-45, start_y=300, end_x=300, end_y=-45)
|
||||
time.sleep(0.1)
|
||||
# pylint: disable=broad-except
|
||||
except Exception as e:
|
||||
print("Error:\n", str(e))
|
||||
print("Resetting microcontroller in 10 seconds")
|
||||
time.sleep(10)
|
||||
microcontroller.reset()
|
||||
|
Before Width: | Height: | Size: 57 KiB |
|
|
@ -1,109 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIHRjCCBS6gAwIBAgIQV82HcwAIb4tFlHpCQCtGuzANBgkqhkiG9w0BAQsFADBR
|
||||
MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSgwJgYDVQQD
|
||||
DB9FbnRydXN0IE9WIFRMUyBJc3N1aW5nIFJTQSBDQSAxMB4XDTI1MDIwNTE0MDkw
|
||||
MloXDTI2MDMwMzE0MTg1OFoweDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlm
|
||||
b3JuaWExETAPBgNVBAcMCFBhc2FkZW5hMSIwIAYDVQQKDBlKZXQgUHJvcHVsc2lv
|
||||
biBMYWJvcmF0b3J5MR0wGwYDVQQDDBRzc2QtYXBpLmpwbC5uYXNhLmdvdjCCASIw
|
||||
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKXzsG9/H8CQzmmu1vwdM1RYrziS
|
||||
8dzCuw2fqOJXfvOEB+jbZZGIPDvUXCqug0Gb+Z5MsbAdwxT8RsKRuWl/xgRZWr/Y
|
||||
mtafmEIf3QeKy3/Hu2uUS1GQjTkfmY/3cj6szXJDF4YAC3lngFVWftmGrXhA1Dmm
|
||||
WqApxguIf2XPjetKjcX1TMdC5XyQ/lsy/vJTX+S8G9HRk+OhO45kAf8AvVeCWCOa
|
||||
XQ7jpEVBd610RGgD972XNazhoYtL2QKBm6GrSkx1rW/7aiPU0QLbkCoTJIno1yHn
|
||||
nlYKVYWn0V1uG2vcuChhebX6WOHp7U6KAcaKVbTvaTxv8whi+t4gjcJRbgECAwEA
|
||||
AaOCAvEwggLtMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUaA1FyjXC55ob8LOE
|
||||
3dXafwuJwREwaAYIKwYBBQUHAQEEXDBaMDYGCCsGAQUFBzAChipodHRwOi8vY2Vy
|
||||
dC5zc2wuY29tL0VudHJ1c3QtT1ZUTFMtSS1SMS5jZXIwIAYIKwYBBQUHMAGGFGh0
|
||||
dHA6Ly9vY3Nwcy5zc2wuY29tMB8GA1UdEQQYMBaCFHNzZC1hcGkuanBsLm5hc2Eu
|
||||
Z292MCMGA1UdIAQcMBowCAYGZ4EMAQICMA4GDCsGAQQBgqkwAQMBAjAdBgNVHSUE
|
||||
FjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDov
|
||||
L2NybHMuc3NsLmNvbS9FbnRydXN0LU9WVExTLUktUjEuY3JsMB0GA1UdDgQWBBQ9
|
||||
28d7XB5zNhW4Z/FiFGVefv8TpDAOBgNVHQ8BAf8EBAMCBaAwggF/BgorBgEEAdZ5
|
||||
AgQCBIIBbwSCAWsBaQB3AJaXZL9VWJet90OHaDcIQnfp8DrV9qTzNm5GpD8PyqnG
|
||||
AAABlNZ6jp0AAAQDAEgwRgIhAM/xkbmguT7NTj3lc6p/F3Um9y7fDhYjzHhWvyDc
|
||||
HIaQAiEAmRCNTCoJAOFtiXFseiUANEn16Wr3rW5cAUiAJ3mQPewAdwDLOPcViXyE
|
||||
oURfW8Hd+8lu8ppZzUcKaQWFsMsUwxRY5wAAAZTWeo6SAAAEAwBIMEYCIQCExfjt
|
||||
QsfbwEpS8cI3YNcXOAW3fMiAh6vOW2wD88iruwIhALfInWVFlobCtQYXLtXq2iqe
|
||||
HO083hp/cD0oDIChPD9SAHUAZBHEbKQS7KeJHKICLgC8q08oB9QeNSer6v7VA8l9
|
||||
zfAAAAGU1nqOzgAABAMARjBEAiBTSQczvVZCJ41l+JiC9n8fOkuYNf8jQ1uG5rKy
|
||||
M/g6IwIgK7YZziGBfBHHKYR8e+IyitJktRevFehnGPEwbMNOO1wwDQYJKoZIhvcN
|
||||
AQELBQADggIBAGCVD/1ROYGTKPhFeDUFiPjW7JKagsmldnWdtYQ7ran5Ozd8Hkju
|
||||
XaEi/sDed8wHv1Bf8lesHd3dz2KlaefLVBknntOMSC7fxr7cvkHHgJyJbWtrOESF
|
||||
JTuy13CdbIHZTxSRtVErCqumUC4omAOfffoGEMlcKvLlIK1NtZTibPsmeUVceMjI
|
||||
1iZ6OeAOQfZHwlHk49r1zN2D41/5NOT6hpg1bP+rwp/ZhRpT0cB0Q+PBF/GeRCJp
|
||||
fyLWng/yfILPl2EZoo2RJ0FbdM7VhxGK9359CbKpIPDrZAqagTafEvzRoL9afBAo
|
||||
n/fht0RCmHiz56vmYo4a742Hwr1Hgempgx+UBlTluf7UGEJ3ju9JEgM/wY+Zc9wm
|
||||
HyBcQjzPFcDMGGJo/cQwPNYOI06LePpvGiWLe/8WvW+MSPk19JEQj4uOf02Yowzj
|
||||
1LXFvSzTase6AjrjiOPd57rgmwUKju+/ouX5qyOBbB4dKJ1Q7pOvb2wR+yF/2Mro
|
||||
YJS73WJVK64mk6aletwcL0uy+vZiZlesBWIiERPR915NiDEeEYSXYtmwu0XhiS8b
|
||||
jxpMbXIEuhRtA3c8WeqKCbuSnQs+8SMaYpHZ3QgwCreBWl25J5J4nPtW3tPgINkG
|
||||
gKDVZyGsOJE4t/sQs7zoQAf4rX7eY+U4w+6CIE7XAkACI7Mug6kXOJZJ
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO
|
||||
MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD
|
||||
DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX
|
||||
DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw
|
||||
b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC
|
||||
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP
|
||||
L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY
|
||||
t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins
|
||||
S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3
|
||||
PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO
|
||||
L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3
|
||||
R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w
|
||||
dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS
|
||||
+YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS
|
||||
d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG
|
||||
AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f
|
||||
gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j
|
||||
BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z
|
||||
NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt
|
||||
hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM
|
||||
QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf
|
||||
R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ
|
||||
DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW
|
||||
P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy
|
||||
lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq
|
||||
bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w
|
||||
AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q
|
||||
r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji
|
||||
Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU
|
||||
98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA=
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from os import getenv
|
||||
import time
|
||||
import json
|
||||
import board
|
||||
|
|
@ -39,20 +38,15 @@ nau7802 = NAU7802(board.STEMMA_I2C(), address=0x2A, active_channels=2)
|
|||
nau7802.gain = 128
|
||||
enabled = nau7802.enable(True)
|
||||
|
||||
# Get WiFi details, ensure these are setup in settings.toml
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
|
||||
if None in [ssid, password]:
|
||||
raise RuntimeError(
|
||||
"WiFi settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"at a minimum."
|
||||
)
|
||||
# Get wifi details and more from a secrets.py file
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi secrets are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
|
||||
print("Connecting to WiFi...")
|
||||
wifi.radio.connect(ssid, password)
|
||||
wifi.radio.connect(secrets["ssid"], secrets["password"])
|
||||
|
||||
print("Connected to WiFi!")
|
||||
# check system time
|
||||
|
|
@ -71,7 +65,7 @@ else:
|
|||
esp = None
|
||||
pool = socketpool.SocketPool(wifi.radio)
|
||||
device = IoTCentralDevice(
|
||||
pool, esp, getenv("id_scope"), getenv("device_id"), getenv("device_primary_key")
|
||||
pool, esp, secrets['id_scope'], secrets['device_id'], secrets['device_primary_key']
|
||||
)
|
||||
display.fill(0)
|
||||
display.print("DIALING*")
|
||||
|
|
@ -197,8 +191,6 @@ avg_oz = []
|
|||
values = []
|
||||
val_offset = 0
|
||||
avg_values = []
|
||||
the_ounces = 0
|
||||
the_grams = 0
|
||||
|
||||
# initial reading from the scale
|
||||
for w in range(5):
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2020 Phil Schatzmann
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/*
|
||||
Streaming Music from Bluetooth
|
||||
|
||||
Copyright (C) 2020 Phil Schatzmann
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// ==> Example which shows how to use the built in ESP32 I2S >= 3.0.0
|
||||
|
||||
#include "ESP_I2S.h"
|
||||
#include "BluetoothA2DPSink.h"
|
||||
|
||||
const uint8_t I2S_SCK = 8; /* Audio data bit clock */
|
||||
const uint8_t I2S_WS = 7; /* Audio data left and right clock */
|
||||
const uint8_t I2S_SDOUT = 14; /* ESP32 audio data output (to speakers) */
|
||||
I2SClass i2s;
|
||||
|
||||
BluetoothA2DPSink a2dp_sink(i2s);
|
||||
|
||||
void setup() {
|
||||
i2s.setPins(I2S_SCK, I2S_WS, I2S_SDOUT);
|
||||
if (!i2s.begin(I2S_MODE_STD, 44100, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO, I2S_STD_SLOT_BOTH)) {
|
||||
Serial.println("Failed to initialize I2S!");
|
||||
while (1); // do nothing
|
||||
}
|
||||
|
||||
a2dp_sink.start("Lumon Industries Speaker");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
}
|
||||
|
|
@ -1,730 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2025 John Park for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// made with assistance from Claude Sonnet 4
|
||||
//
|
||||
// Unified Bluetooth HID Bridge - BT Classic & BLE
|
||||
// put keyboard in pairing mode, then press reset or BOOT button
|
||||
// slow blinks mean scanning
|
||||
// fast blinks mean keyboard detected, press a keyboard key to connect
|
||||
|
||||
// === CONFIGURATION ===
|
||||
#define DEBUG_MODE false // Set to false to reduce serial output
|
||||
#define BLINK_MODE true // Set to false for solid LED (no keypress blinks)
|
||||
#define SCAN_MODE "Both" // Options: "BT_Classic", "BLE", "Both"
|
||||
|
||||
// Include both Bluetooth stacks
|
||||
extern "C" {
|
||||
#include "btstack.h"
|
||||
}
|
||||
#include <BluetoothHCI.h>
|
||||
#include <BluetoothHIDMaster.h>
|
||||
#include <Keyboard.h>
|
||||
#include <Mouse.h>
|
||||
|
||||
// Connection state management
|
||||
typedef enum {
|
||||
INIT,
|
||||
SCANNING_CLASSIC,
|
||||
CLASSIC_CONNECTING,
|
||||
CLASSIC_CONNECTED,
|
||||
SCANNING_BLE,
|
||||
BLE_CONNECTED,
|
||||
BOTH_FAILED,
|
||||
DISCONNECTED
|
||||
} connection_state_t;
|
||||
|
||||
connection_state_t connection_state = INIT;
|
||||
|
||||
// BT Classic components
|
||||
BluetoothHCI hci;
|
||||
bd_addr_t target_keyboard_addr;
|
||||
bool target_keyboard_found = false;
|
||||
uint16_t hid_control_cid = 0;
|
||||
uint16_t hid_interrupt_cid = 0;
|
||||
static btstack_packet_callback_registration_t hci_event_callback_registration;
|
||||
|
||||
// BLE components
|
||||
BluetoothHIDMaster ble_hid;
|
||||
HIDKeyStream keystream;
|
||||
|
||||
// Shared state tracking
|
||||
static uint8_t last_modifiers = 0;
|
||||
static uint8_t last_keys[6] = {0};
|
||||
bool keyPressed[256] = {0}; // Track which keys are currently pressed
|
||||
|
||||
// LED management
|
||||
unsigned long ledTimer = 0;
|
||||
bool ledState = false;
|
||||
unsigned long ledOffTime = 0;
|
||||
bool ledBlinking = false;
|
||||
int pairingBlinks = 0;
|
||||
unsigned long pairingBlinkTimer = 0;
|
||||
|
||||
// Timing management
|
||||
unsigned long lastScan = 0;
|
||||
unsigned long stateStartTime = 0;
|
||||
const unsigned long CLASSIC_SCAN_TIMEOUT = 10000; // 10 seconds
|
||||
const unsigned long BLE_SCAN_TIMEOUT = 15000; // 15 seconds
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(3000);
|
||||
|
||||
Serial.println("=== UNIFIED BLUETOOTH HID BRIDGE ===");
|
||||
Serial.printf("Scan mode: %s\n", SCAN_MODE);
|
||||
Serial.println("Put your Bluetooth device in pairing mode now");
|
||||
|
||||
// Initialize LED
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
Serial.println("LED initialized");
|
||||
|
||||
// Initialize USB HID
|
||||
Keyboard.begin();
|
||||
Mouse.begin();
|
||||
Serial.println("USB HID initialized");
|
||||
|
||||
// Start with LED blinking to show we're alive
|
||||
ledTimer = millis();
|
||||
ledState = true;
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
|
||||
Serial.println("Starting Bluetooth stack initialization...");
|
||||
|
||||
// Choose scan mode based on user setting
|
||||
if (strcmp(SCAN_MODE, "BT_Classic") == 0) {
|
||||
Serial.println("BT Classic only mode");
|
||||
connection_state = SCANNING_CLASSIC;
|
||||
stateStartTime = millis();
|
||||
initAndScanClassic();
|
||||
} else if (strcmp(SCAN_MODE, "BLE") == 0) {
|
||||
Serial.println("BLE only mode");
|
||||
connection_state = SCANNING_BLE;
|
||||
stateStartTime = millis();
|
||||
initAndScanBLE();
|
||||
} else {
|
||||
Serial.println("Both protocols mode - trying Classic first");
|
||||
connection_state = SCANNING_CLASSIC;
|
||||
stateStartTime = millis();
|
||||
initAndScanClassic();
|
||||
}
|
||||
}
|
||||
|
||||
void initAndScanClassic() {
|
||||
Serial.println("\n=== INITIALIZING BT CLASSIC STACK ===");
|
||||
|
||||
// Initialize HCI for Classic
|
||||
l2cap_init();
|
||||
sm_init();
|
||||
gap_set_default_link_policy_settings(LM_LINK_POLICY_ENABLE_SNIFF_MODE | LM_LINK_POLICY_ENABLE_ROLE_SWITCH);
|
||||
hci_set_master_slave_policy(HCI_ROLE_MASTER);
|
||||
hci_set_inquiry_mode(INQUIRY_MODE_RSSI_AND_EIR);
|
||||
|
||||
Serial.println("BTStack components initialized");
|
||||
|
||||
hci.install();
|
||||
hci.begin();
|
||||
Serial.println("HCI installed and started");
|
||||
|
||||
// Register BTStack event handler
|
||||
hci_event_callback_registration.callback = &classic_packet_handler;
|
||||
hci_add_event_handler(&hci_event_callback_registration);
|
||||
Serial.println("Event handler registered");
|
||||
|
||||
// Turn on Bluetooth
|
||||
hci_power_control(HCI_POWER_ON);
|
||||
Serial.println("Bluetooth power ON");
|
||||
|
||||
delay(2000); // Give it time to initialize
|
||||
|
||||
Serial.println("Starting BT Classic device scan...");
|
||||
scanForClassicDevices();
|
||||
}
|
||||
|
||||
void scanForClassicDevices() {
|
||||
Serial.println("Scanning for BT Classic devices...");
|
||||
|
||||
auto devices = hci.scan(BluetoothHCI::any_cod);
|
||||
|
||||
Serial.printf("Classic scan completed. Found %d devices:\n", devices.size());
|
||||
|
||||
if (devices.size() == 0) {
|
||||
Serial.println("No Classic devices found. Will try BLE after timeout.");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("Address | RSSI | Class | Name");
|
||||
Serial.println("------------------|------|----------|------------------");
|
||||
|
||||
for (auto device : devices) {
|
||||
uint32_t cod = device.deviceClass();
|
||||
uint8_t majorClass = (cod >> 8) & 0x1F;
|
||||
uint8_t minorClass = (cod >> 2) & 0x3F;
|
||||
|
||||
Serial.printf("%s | %4d | %08lx | %s",
|
||||
device.addressString(), device.rssi(), cod, device.name());
|
||||
|
||||
// Look for HID keyboards in Classic scan
|
||||
if (majorClass == 5 && (minorClass & 0x10)) { // HID Keyboard
|
||||
Serial.print(" [HID KEYBOARD] *** CONNECTING ***");
|
||||
|
||||
// We found a Classic keyboard!
|
||||
const char* addrStr = device.addressString();
|
||||
sscanf(addrStr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
|
||||
&target_keyboard_addr[0], &target_keyboard_addr[1], &target_keyboard_addr[2],
|
||||
&target_keyboard_addr[3], &target_keyboard_addr[4], &target_keyboard_addr[5]);
|
||||
target_keyboard_found = true;
|
||||
|
||||
Serial.printf("\nFound Classic HID keyboard: %s\n", device.name());
|
||||
Serial.printf("Address: %s\n", device.addressString());
|
||||
|
||||
// Start Classic connection
|
||||
connection_state = CLASSIC_CONNECTING;
|
||||
stateStartTime = millis();
|
||||
startClassicConnection();
|
||||
|
||||
Serial.println();
|
||||
return; // Exit the loop - we found our keyboard
|
||||
} else {
|
||||
// Show device type for debugging
|
||||
switch (majorClass) {
|
||||
case 1: Serial.print(" [Computer]"); break;
|
||||
case 2: Serial.print(" [Phone]"); break;
|
||||
case 3: Serial.print(" [Network]"); break;
|
||||
case 4: Serial.print(" [Audio/Video]"); break;
|
||||
case 5: Serial.print(" [HID Device]"); break;
|
||||
default: Serial.printf(" [Class:%d]", majorClass); break;
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
Serial.println("No HID keyboards found in Classic scan.");
|
||||
}
|
||||
|
||||
void fallbackToBLE() {
|
||||
Serial.println("\n=== FALLING BACK TO BLE ===");
|
||||
connection_state = SCANNING_BLE;
|
||||
stateStartTime = millis();
|
||||
initAndScanBLE();
|
||||
}
|
||||
|
||||
void initAndScanBLE() {
|
||||
Serial.println("Initializing BLE stack...");
|
||||
|
||||
// Setup the HID key to ASCII conversion
|
||||
keystream.begin();
|
||||
Serial.println("KeyStream initialized");
|
||||
|
||||
// Setup BLE callbacks
|
||||
setupBLECallbacks();
|
||||
Serial.println("BLE callbacks configured");
|
||||
|
||||
// Start BLE HID master
|
||||
ble_hid.begin(true);
|
||||
Serial.println("BLE HID master started");
|
||||
|
||||
// Start BLE connection attempt
|
||||
ble_hid.connectBLE();
|
||||
Serial.println("BLE connection initiated - waiting for device...");
|
||||
Serial.println("(BLE devices will be detected on first keypress)");
|
||||
}
|
||||
|
||||
void setupBLECallbacks() {
|
||||
// BLE Mouse callbacks
|
||||
ble_hid.onMouseMove([](void *cbdata, int dx, int dy, int dw) {
|
||||
(void) cbdata;
|
||||
if (DEBUG_MODE) {
|
||||
Serial.printf("BLE Mouse: X:%d Y:%d Wheel:%d\n", dx, dy, dw);
|
||||
}
|
||||
Mouse.move(dx, dy);
|
||||
if (dw != 0) Mouse.move(0, 0, dw);
|
||||
blinkOnActivity();
|
||||
});
|
||||
|
||||
ble_hid.onMouseButton([](void *cbdata, int butt, bool down) {
|
||||
(void) cbdata;
|
||||
if (DEBUG_MODE) {
|
||||
Serial.printf("BLE Mouse: Button %d %s\n", butt, down ? "DOWN" : "UP");
|
||||
}
|
||||
if (down) {
|
||||
if (butt == 1) Mouse.press(MOUSE_LEFT);
|
||||
else if (butt == 2) Mouse.press(MOUSE_RIGHT);
|
||||
else if (butt == 3) Mouse.press(MOUSE_MIDDLE);
|
||||
} else {
|
||||
if (butt == 1) Mouse.release(MOUSE_LEFT);
|
||||
else if (butt == 2) Mouse.release(MOUSE_RIGHT);
|
||||
else if (butt == 3) Mouse.release(MOUSE_MIDDLE);
|
||||
}
|
||||
blinkOnActivity();
|
||||
});
|
||||
|
||||
// BLE Keyboard callbacks
|
||||
ble_hid.onKeyDown([](void *cbdata, int key) {
|
||||
handleBLEKey(key, true);
|
||||
}, (void *)true);
|
||||
|
||||
ble_hid.onKeyUp([](void *cbdata, int key) {
|
||||
handleBLEKey(key, false);
|
||||
}, (void *)false);
|
||||
}
|
||||
|
||||
void startClassicConnection() {
|
||||
if (!target_keyboard_found) {
|
||||
Serial.println("ERROR: No Classic target keyboard found");
|
||||
fallbackToBLE();
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("=== STARTING CLASSIC HID CONNECTION ===");
|
||||
Serial.println("Creating L2CAP Control channel...");
|
||||
|
||||
// Create control channel first
|
||||
l2cap_create_channel(&classic_packet_handler, target_keyboard_addr, BLUETOOTH_PSM_HID_CONTROL,
|
||||
48, &hid_control_cid);
|
||||
}
|
||||
|
||||
void handleBLEKey(int key, bool state) {
|
||||
if (DEBUG_MODE) {
|
||||
Serial.printf("BLE Keyboard: %02x %s\n", key, state ? "DOWN" : "UP");
|
||||
}
|
||||
|
||||
if (key >= 256) return; // Bounds check
|
||||
|
||||
// Check if this is the first BLE key press (connection detection)
|
||||
if (connection_state == SCANNING_BLE) {
|
||||
Serial.printf("\n*** BLE KEYBOARD DETECTED ON FIRST KEYPRESS ***\n");
|
||||
Serial.printf("=== BLE DEVICE CONNECTED ===\n");
|
||||
Serial.printf("Ready to forward BLE input to USB.\n");
|
||||
Serial.printf("========================\n");
|
||||
|
||||
connection_state = BLE_CONNECTED;
|
||||
celebrationBlinks(8); // 4 blinks for BLE
|
||||
|
||||
// After celebration, LED will go solid (handled in LED patterns)
|
||||
}
|
||||
|
||||
// Forward the key to USB
|
||||
forwardBLEKeyToUSB(key, state);
|
||||
blinkOnActivity();
|
||||
}
|
||||
|
||||
void classic_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
|
||||
UNUSED(size);
|
||||
|
||||
if (packet_type == HCI_EVENT_PACKET) {
|
||||
uint8_t event = hci_event_packet_get_type(packet);
|
||||
|
||||
switch (event) {
|
||||
case BTSTACK_EVENT_STATE:
|
||||
if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING) {
|
||||
Serial.println("Classic BTstack ready");
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_CHANNEL_OPENED:
|
||||
{
|
||||
uint16_t cid = l2cap_event_channel_opened_get_local_cid(packet);
|
||||
uint16_t psm = l2cap_event_channel_opened_get_psm(packet);
|
||||
uint8_t status = l2cap_event_channel_opened_get_status(packet);
|
||||
|
||||
if (status) {
|
||||
Serial.printf("Classic L2CAP connection failed, status 0x%02x\n", status);
|
||||
handleClassicConnectionError(status);
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.printf("Classic L2CAP channel opened: CID=0x%04x, PSM=0x%04x\n", cid, psm);
|
||||
|
||||
if (psm == BLUETOOTH_PSM_HID_CONTROL) {
|
||||
hid_control_cid = cid;
|
||||
Serial.println("Classic HID Control channel established");
|
||||
Serial.println("Creating L2CAP Interrupt channel...");
|
||||
|
||||
// Create interrupt channel
|
||||
l2cap_create_channel(&classic_packet_handler, target_keyboard_addr, BLUETOOTH_PSM_HID_INTERRUPT,
|
||||
48, &hid_interrupt_cid);
|
||||
} else if (psm == BLUETOOTH_PSM_HID_INTERRUPT) {
|
||||
hid_interrupt_cid = cid;
|
||||
Serial.println("Classic HID Interrupt channel established");
|
||||
Serial.println("*** CLASSIC HID CONNECTION COMPLETE ***");
|
||||
connection_state = CLASSIC_CONNECTED;
|
||||
|
||||
celebrationBlinks(6); // 3 blinks for Classic
|
||||
|
||||
// After celebration, LED will go solid (handled in LED patterns)
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_CHANNEL_CLOSED:
|
||||
{
|
||||
uint16_t cid = l2cap_event_channel_closed_get_local_cid(packet);
|
||||
Serial.printf("Classic L2CAP channel closed: CID=0x%04x\n", cid);
|
||||
|
||||
if (cid == hid_control_cid) {
|
||||
hid_control_cid = 0;
|
||||
} else if (cid == hid_interrupt_cid) {
|
||||
hid_interrupt_cid = 0;
|
||||
}
|
||||
|
||||
if (hid_control_cid == 0 && hid_interrupt_cid == 0) {
|
||||
Serial.println("Classic HID connection lost.");
|
||||
connection_state = DISCONNECTED;
|
||||
target_keyboard_found = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (packet_type == L2CAP_DATA_PACKET) {
|
||||
// Classic HID input data
|
||||
if (channel == hid_interrupt_cid) {
|
||||
if (DEBUG_MODE) {
|
||||
Serial.printf("Classic HID Input Data (%d bytes): ", size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
Serial.printf("%02X ", packet[i]);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
processClassicHIDReport(packet, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleClassicConnectionError(uint8_t status) {
|
||||
Serial.printf("Classic connection failed with status 0x%02x - ", status);
|
||||
switch (status) {
|
||||
case 0x04: Serial.println("Page timeout"); break;
|
||||
case 0x05: Serial.println("Authentication failure"); break;
|
||||
case 0x08: Serial.println("Connection timeout"); break;
|
||||
default: Serial.printf("Error code 0x%02x\n", status); break;
|
||||
}
|
||||
|
||||
Serial.println("Trying BLE fallback...");
|
||||
fallbackToBLE();
|
||||
}
|
||||
|
||||
void processClassicHIDReport(uint8_t *report, uint16_t length) {
|
||||
if (length < 10) {
|
||||
Serial.printf("Invalid Classic HID report length: %d\n", length);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t modifiers = report[2];
|
||||
uint8_t *keys = &report[4];
|
||||
|
||||
// Forward to USB HID
|
||||
forwardClassicToUSB(modifiers, keys);
|
||||
blinkOnActivity();
|
||||
}
|
||||
|
||||
// Shared key mapping function
|
||||
uint8_t hidToUsbKey(uint8_t hidKey) {
|
||||
switch (hidKey) {
|
||||
// Letters
|
||||
case 0x04: return 'a'; case 0x05: return 'b'; case 0x06: return 'c'; case 0x07: return 'd';
|
||||
case 0x08: return 'e'; case 0x09: return 'f'; case 0x0A: return 'g'; case 0x0B: return 'h';
|
||||
case 0x0C: return 'i'; case 0x0D: return 'j'; case 0x0E: return 'k'; case 0x0F: return 'l';
|
||||
case 0x10: return 'm'; case 0x11: return 'n'; case 0x12: return 'o'; case 0x13: return 'p';
|
||||
case 0x14: return 'q'; case 0x15: return 'r'; case 0x16: return 's'; case 0x17: return 't';
|
||||
case 0x18: return 'u'; case 0x19: return 'v'; case 0x1A: return 'w'; case 0x1B: return 'x';
|
||||
case 0x1C: return 'y'; case 0x1D: return 'z';
|
||||
|
||||
// Numbers
|
||||
case 0x1E: return '1'; case 0x1F: return '2'; case 0x20: return '3'; case 0x21: return '4';
|
||||
case 0x22: return '5'; case 0x23: return '6'; case 0x24: return '7'; case 0x25: return '8';
|
||||
case 0x26: return '9'; case 0x27: return '0';
|
||||
|
||||
// Special keys
|
||||
case 0x28: return KEY_RETURN; case 0x29: return KEY_ESC;
|
||||
case 0x2A: return KEY_BACKSPACE; case 0x2B: return KEY_TAB;
|
||||
case 0x2C: return ' '; case 0x39: return KEY_CAPS_LOCK;
|
||||
|
||||
// Symbols
|
||||
case 0x2D: return '-'; case 0x2E: return '='; case 0x2F: return '['; case 0x30: return ']';
|
||||
case 0x31: return '\\'; case 0x33: return ';'; case 0x34: return '\''; case 0x35: return '`';
|
||||
case 0x36: return ','; case 0x37: return '.'; case 0x38: return '/';
|
||||
|
||||
// Function keys
|
||||
case 0x3A: return KEY_F1; case 0x3B: return KEY_F2; case 0x3C: return KEY_F3;
|
||||
case 0x3D: return KEY_F4; case 0x3E: return KEY_F5; case 0x3F: return KEY_F6;
|
||||
case 0x40: return KEY_F7; case 0x41: return KEY_F8; case 0x42: return KEY_F9;
|
||||
case 0x43: return KEY_F10; case 0x44: return KEY_F11; case 0x45: return KEY_F12;
|
||||
|
||||
// Arrow keys
|
||||
case 0x4F: return KEY_RIGHT_ARROW; case 0x50: return KEY_LEFT_ARROW;
|
||||
case 0x51: return KEY_DOWN_ARROW; case 0x52: return KEY_UP_ARROW;
|
||||
|
||||
// Navigation
|
||||
case 0x49: return KEY_INSERT; case 0x4A: return KEY_HOME;
|
||||
case 0x4B: return KEY_PAGE_UP; case 0x4C: return KEY_DELETE;
|
||||
case 0x4D: return KEY_END; case 0x4E: return KEY_PAGE_DOWN;
|
||||
|
||||
// Modifiers
|
||||
case 0xE0: return KEY_LEFT_CTRL; case 0xE1: return KEY_LEFT_SHIFT;
|
||||
case 0xE2: return KEY_LEFT_ALT; case 0xE3: return KEY_LEFT_GUI;
|
||||
case 0xE4: return KEY_RIGHT_CTRL; case 0xE5: return KEY_RIGHT_SHIFT;
|
||||
case 0xE6: return KEY_RIGHT_ALT; case 0xE7: return KEY_RIGHT_GUI;
|
||||
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void forwardClassicToUSB(uint8_t modifiers, uint8_t *keys) {
|
||||
// Handle modifier changes
|
||||
uint8_t modifier_changes = modifiers ^ last_modifiers;
|
||||
|
||||
// Process each modifier bit
|
||||
if (modifier_changes & 0x01) (modifiers & 0x01) ? Keyboard.press(KEY_LEFT_CTRL) : Keyboard.release(KEY_LEFT_CTRL);
|
||||
if (modifier_changes & 0x02) (modifiers & 0x02) ? Keyboard.press(KEY_LEFT_SHIFT) : Keyboard.release(KEY_LEFT_SHIFT);
|
||||
if (modifier_changes & 0x04) (modifiers & 0x04) ? Keyboard.press(KEY_LEFT_ALT) : Keyboard.release(KEY_LEFT_ALT);
|
||||
if (modifier_changes & 0x08) (modifiers & 0x08) ? Keyboard.press(KEY_LEFT_GUI) : Keyboard.release(KEY_LEFT_GUI);
|
||||
if (modifier_changes & 0x10) (modifiers & 0x10) ? Keyboard.press(KEY_RIGHT_CTRL) : Keyboard.release(KEY_RIGHT_CTRL);
|
||||
if (modifier_changes & 0x20) (modifiers & 0x20) ? Keyboard.press(KEY_RIGHT_SHIFT) : Keyboard.release(KEY_RIGHT_SHIFT);
|
||||
if (modifier_changes & 0x40) (modifiers & 0x40) ? Keyboard.press(KEY_RIGHT_ALT) : Keyboard.release(KEY_RIGHT_ALT);
|
||||
if (modifier_changes & 0x80) (modifiers & 0x80) ? Keyboard.press(KEY_RIGHT_GUI) : Keyboard.release(KEY_RIGHT_GUI);
|
||||
|
||||
// Handle key releases
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (last_keys[i] != 0) {
|
||||
bool still_pressed = false;
|
||||
for (int j = 0; j < 6; j++) {
|
||||
if (keys[j] == last_keys[i]) {
|
||||
still_pressed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!still_pressed) {
|
||||
uint8_t usb_key = hidToUsbKey(last_keys[i]);
|
||||
if (usb_key != 0) Keyboard.release(usb_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle key presses
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (keys[i] != 0) {
|
||||
bool already_pressed = false;
|
||||
for (int j = 0; j < 6; j++) {
|
||||
if (last_keys[j] == keys[i]) {
|
||||
already_pressed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!already_pressed) {
|
||||
uint8_t usb_key = hidToUsbKey(keys[i]);
|
||||
if (usb_key != 0) Keyboard.press(usb_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save current state
|
||||
last_modifiers = modifiers;
|
||||
memcpy(last_keys, keys, 6);
|
||||
}
|
||||
|
||||
void forwardBLEKeyToUSB(int key, bool state) {
|
||||
if (key >= 256) return;
|
||||
|
||||
bool isModifier = (key >= 0xE0 && key <= 0xE7);
|
||||
|
||||
if (isModifier) {
|
||||
uint8_t usbKey = hidToUsbKey(key);
|
||||
if (state) Keyboard.press(usbKey);
|
||||
else Keyboard.release(usbKey);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle regular keys
|
||||
uint8_t usbKey = hidToUsbKey(key);
|
||||
if (usbKey != 0) {
|
||||
if (state && !keyPressed[key]) {
|
||||
keyPressed[key] = true;
|
||||
Keyboard.press(usbKey);
|
||||
} else if (!state && keyPressed[key]) {
|
||||
keyPressed[key] = false;
|
||||
Keyboard.release(usbKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void celebrationBlinks(int count) {
|
||||
pairingBlinks = count;
|
||||
pairingBlinkTimer = millis();
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
}
|
||||
|
||||
void blinkOnActivity() {
|
||||
if (BLINK_MODE && pairingBlinks == 0 && (connection_state == CLASSIC_CONNECTED || connection_state == BLE_CONNECTED)) {
|
||||
digitalWrite(LED_BUILTIN, LOW); // Turn OFF briefly to show activity
|
||||
ledBlinking = true;
|
||||
ledOffTime = millis() + 50; // Stay off for 50ms
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
unsigned long currentTime = millis();
|
||||
|
||||
// Handle state timeouts
|
||||
handleStateTimeouts(currentTime);
|
||||
|
||||
// Handle LED patterns
|
||||
handleLEDPatterns(currentTime);
|
||||
|
||||
// Handle BOOTSEL button
|
||||
handleBootselButton();
|
||||
|
||||
delay(10);
|
||||
}
|
||||
|
||||
void handleStateTimeouts(unsigned long currentTime) {
|
||||
switch (connection_state) {
|
||||
case SCANNING_CLASSIC:
|
||||
if (currentTime - stateStartTime > CLASSIC_SCAN_TIMEOUT) {
|
||||
if (strcmp(SCAN_MODE, "BT_Classic") == 0) {
|
||||
Serial.println("Classic scan timeout - BT Classic only mode, retrying...");
|
||||
stateStartTime = currentTime;
|
||||
scanForClassicDevices(); // Retry Classic scan
|
||||
} else {
|
||||
Serial.println("Classic scan timeout - falling back to BLE");
|
||||
fallbackToBLE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SCANNING_BLE:
|
||||
if (currentTime - stateStartTime > BLE_SCAN_TIMEOUT) {
|
||||
if (strcmp(SCAN_MODE, "BLE") == 0) {
|
||||
Serial.println("BLE scan timeout - BLE only mode, retrying...");
|
||||
stateStartTime = currentTime;
|
||||
initAndScanBLE(); // Retry BLE scan
|
||||
} else {
|
||||
Serial.println("BLE scan timeout - restarting from Classic");
|
||||
connection_state = BOTH_FAILED;
|
||||
stateStartTime = currentTime;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BOTH_FAILED:
|
||||
if (currentTime - stateStartTime > 5000) { // Wait 5 seconds before retry
|
||||
Serial.println("Retrying scan sequence...");
|
||||
connection_state = SCANNING_CLASSIC;
|
||||
stateStartTime = currentTime;
|
||||
initAndScanClassic();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void handleLEDPatterns(unsigned long currentTime) {
|
||||
// Handle pairing celebration blinks first
|
||||
if (pairingBlinks > 0) {
|
||||
if (currentTime - pairingBlinkTimer >= 150) {
|
||||
pairingBlinks--;
|
||||
bool state = (pairingBlinks % 2 == 0);
|
||||
digitalWrite(LED_BUILTIN, state);
|
||||
pairingBlinkTimer = currentTime;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle activity blinks
|
||||
if (ledBlinking && currentTime >= ledOffTime) {
|
||||
digitalWrite(LED_BUILTIN, HIGH); // Turn back ON after brief off period
|
||||
ledBlinking = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle state-based LED patterns
|
||||
switch (connection_state) {
|
||||
case SCANNING_CLASSIC:
|
||||
case SCANNING_BLE:
|
||||
// Slow blink while scanning (1 second cycle)
|
||||
if (currentTime - ledTimer >= 1000) {
|
||||
ledState = !ledState;
|
||||
digitalWrite(LED_BUILTIN, ledState);
|
||||
ledTimer = currentTime;
|
||||
}
|
||||
break;
|
||||
|
||||
case CLASSIC_CONNECTING:
|
||||
// Fast blink while connecting - tells user to press a key
|
||||
if (currentTime - ledTimer >= 250) {
|
||||
ledState = !ledState;
|
||||
digitalWrite(LED_BUILTIN, ledState);
|
||||
ledTimer = currentTime;
|
||||
}
|
||||
break;
|
||||
|
||||
case CLASSIC_CONNECTED:
|
||||
case BLE_CONNECTED:
|
||||
// Solid ON while connected (unless doing activity blinks)
|
||||
if (!ledBlinking) {
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
}
|
||||
break;
|
||||
|
||||
case BOTH_FAILED:
|
||||
case DISCONNECTED:
|
||||
// Very slow pulse when failed/disconnected (2 second cycle)
|
||||
if (currentTime - ledTimer >= 2000) {
|
||||
ledState = !ledState;
|
||||
digitalWrite(LED_BUILTIN, ledState);
|
||||
ledTimer = currentTime;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void handleBootselButton() {
|
||||
if (BOOTSEL) {
|
||||
while (BOOTSEL) delay(1);
|
||||
|
||||
Serial.println("\nBOOTSEL pressed - restarting scan sequence");
|
||||
|
||||
// Clean up current connections
|
||||
if (connection_state == CLASSIC_CONNECTED) {
|
||||
if (hid_control_cid) l2cap_disconnect(hid_control_cid);
|
||||
if (hid_interrupt_cid) l2cap_disconnect(hid_interrupt_cid);
|
||||
} else if (connection_state == BLE_CONNECTED) {
|
||||
ble_hid.disconnect();
|
||||
ble_hid.clearPairing();
|
||||
}
|
||||
|
||||
// Reset all state
|
||||
Keyboard.releaseAll();
|
||||
Mouse.release(MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE);
|
||||
|
||||
for (int i = 0; i < 256; i++) keyPressed[i] = false;
|
||||
memset(last_keys, 0, 6);
|
||||
last_modifiers = 0;
|
||||
|
||||
target_keyboard_found = false;
|
||||
hid_control_cid = 0;
|
||||
hid_interrupt_cid = 0;
|
||||
pairingBlinks = 0;
|
||||
ledBlinking = false;
|
||||
|
||||
// Restart from appropriate scan mode
|
||||
if (strcmp(SCAN_MODE, "BT_Classic") == 0) {
|
||||
connection_state = SCANNING_CLASSIC;
|
||||
Serial.println("Restarting BT Classic scan...");
|
||||
initAndScanClassic();
|
||||
} else if (strcmp(SCAN_MODE, "BLE") == 0) {
|
||||
connection_state = SCANNING_BLE;
|
||||
Serial.println("Restarting BLE scan...");
|
||||
initAndScanBLE();
|
||||
} else {
|
||||
connection_state = SCANNING_CLASSIC;
|
||||
Serial.println("Restarting unified scan...");
|
||||
initAndScanClassic();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,17 +22,31 @@ clue.pixel.fill(0) # turn off NeoPixel
|
|||
clue_display = displayio.Group()
|
||||
|
||||
# draw the dry plant
|
||||
dry_plant_bmp = displayio.OnDiskBitmap("dry.bmp")
|
||||
dry_plant_file = open("dry.bmp", "rb")
|
||||
dry_plant_bmp = displayio.OnDiskBitmap(dry_plant_file)
|
||||
# CircuitPython 6 & 7 compatible
|
||||
dry_plant_sprite = displayio.TileGrid(
|
||||
dry_plant_bmp, pixel_shader=dry_plant_bmp.pixel_shader
|
||||
dry_plant_bmp,
|
||||
pixel_shader=getattr(dry_plant_bmp, "pixel_shader", displayio.ColorConverter()),
|
||||
)
|
||||
# CircuitPython 7 compatible
|
||||
# dry_plant_sprite = displayio.TileGrid(
|
||||
# dry_plant_bmp, pixel_shader=dry_plant_bmp.pixel_shader
|
||||
# )
|
||||
clue_display.append(dry_plant_sprite)
|
||||
|
||||
# draw the happy plant on top (so it can be moved out of the way when needed)
|
||||
happy_plant_bmp = displayio.OnDiskBitmap("happy.bmp")
|
||||
happy_plant_file = open("happy.bmp", "rb")
|
||||
happy_plant_bmp = displayio.OnDiskBitmap(happy_plant_file)
|
||||
# CircuitPython 6 & 7 compatible
|
||||
happy_plant_sprite = displayio.TileGrid(
|
||||
happy_plant_bmp, pixel_shader=happy_plant_bmp.pixel_shader
|
||||
happy_plant_bmp,
|
||||
pixel_shader=getattr(happy_plant_bmp, "pixel_shader", displayio.ColorConverter()),
|
||||
)
|
||||
# CircuitPython 7 compatible
|
||||
# happy_plant_sprite = displayio.TileGrid(
|
||||
# happy_plant_bmp, pixel_shader=happy_plant_bmp.pixel_shader
|
||||
# )
|
||||
clue_display.append(happy_plant_sprite)
|
||||
|
||||
# Create text
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import time
|
|||
import board
|
||||
import terminalio
|
||||
import displayio
|
||||
import i2cdisplaybus
|
||||
from digitalio import DigitalInOut
|
||||
from adafruit_mcp2515.canio import Message, RemoteTransmissionRequest
|
||||
from adafruit_mcp2515 import MCP2515 as CAN
|
||||
|
|
@ -16,7 +15,7 @@ displayio.release_displays()
|
|||
|
||||
i2c = board.STEMMA_I2C()
|
||||
# STEMMA OLED setup
|
||||
display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=0x3D, reset=None)
|
||||
display_bus = displayio.I2CDisplay(i2c, device_address=0x3D, reset=None)
|
||||
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=64)
|
||||
|
||||
cs = DigitalInOut(board.A3)
|
||||
|
|
|
|||
|
|
@ -1,2 +0,0 @@
|
|||
Files for the Adafruit Learning System guide Clue Coffee Scale
|
||||
https://learn.adafruit.com/clue-coffee-scale/overview
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
## CLUE Project Subdirectory
|
||||
|
||||
Adafruit Learning System Guides relating to the Adafruit CLUE learning boards should be
|
||||
placed in this folder (rather than the top level Learning System repo).
|
||||
|
||||
Please support Open Source software from Adafruit by buying Adafruit hardware
|
||||
0
CLUE/CLUE_Altimeter/code.py → CLUE_Altimeter/code.py
Normal file → Executable file
0
CLUE/CLUE_Altimeter/images/network23.bmp → CLUE_Altimeter/images/network23.bmp
Normal file → Executable file
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
0
CLUE/CLUE_BBQ/font/GothamBlack-25.bdf → CLUE_BBQ/font/GothamBlack-25.bdf
Normal file → Executable file
0
CLUE/CLUE_BBQ/font/GothamBlack-50.bdf → CLUE_BBQ/font/GothamBlack-50.bdf
Normal file → Executable file
0
CLUE/CLUE_BLE_Morse_Code/code.py → CLUE_BLE_Morse_Code/code.py
Normal file → Executable file
0
CLUE/CLUE_BLE_Morse_Code/morse_bg.bmp → CLUE_BLE_Morse_Code/morse_bg.bmp
Normal file → Executable file
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
0
CLUE/CLUE_Beacon/bg.bmp → CLUE_Beacon/bg.bmp
Normal file → Executable file
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
0
CLUE/CLUE_Beacon/cluebeacon.bmp → CLUE_Beacon/cluebeacon.bmp
Normal file → Executable file
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
|
|
@ -22,14 +22,32 @@ splash = displayio.Group()
|
|||
# bad egg
|
||||
BAD_EGG_FILENAME = "broken_egg.bmp"
|
||||
|
||||
begg_bmp = displayio.OnDiskBitmap(BAD_EGG_FILENAME)
|
||||
begg_sprite = displayio.TileGrid(begg_bmp, pixel_shader=begg_bmp.pixel_shader)
|
||||
# CircuitPython 6 & 7 compatible
|
||||
begg_file = open(BAD_EGG_FILENAME, "rb")
|
||||
begg_bmp = displayio.OnDiskBitmap(begg_file)
|
||||
begg_sprite = displayio.TileGrid(
|
||||
begg_bmp,
|
||||
pixel_shader=getattr(begg_bmp, 'pixel_shader', displayio.ColorConverter())
|
||||
)
|
||||
|
||||
# # CircuitPython 7+ compatible
|
||||
# begg_bmp = displayio.OnDiskBitmap(BAD_EGG_FILENAME)
|
||||
# begg_sprite = displayio.TileGrid(begg_bmp, pixel_shader=begg_bmp.pixel_shader)
|
||||
|
||||
# good egg
|
||||
GOOD_EGG_FILENAME = "good_egg.bmp"
|
||||
|
||||
gegg_bmp = displayio.OnDiskBitmap(GOOD_EGG_FILENAME)
|
||||
gegg_sprite = displayio.TileGrid(gegg_bmp, pixel_shader=gegg_bmp.pixel_shader)
|
||||
# CircuitPython 6 & 7 compatible
|
||||
gegg_file = open(GOOD_EGG_FILENAME, "rb")
|
||||
gegg_bmp = displayio.OnDiskBitmap(gegg_file)
|
||||
gegg_sprite = displayio.TileGrid(
|
||||
gegg_bmp,
|
||||
pixel_shader=getattr(gegg_bmp, 'pixel_shader', displayio.ColorConverter())
|
||||
)
|
||||
|
||||
# # CircuitPython 7+ compatible
|
||||
# gegg_bmp = displayio.OnDiskBitmap(GOOD_EGG_FILENAME)
|
||||
# gegg_sprite = displayio.TileGrid(gegg_bmp, pixel_shader=gegg_bmp.pixel_shader)
|
||||
|
||||
# draw the bad egg!
|
||||
splash.append(begg_sprite)
|
||||
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
|
|
@ -21,19 +21,39 @@ clue_display = displayio.Group()
|
|||
|
||||
# draw the background image
|
||||
WASH_ON_FILENAME = "wash_on.bmp"
|
||||
wash_on_bmp = displayio.OnDiskBitmap(WASH_ON_FILENAME)
|
||||
wash_on_sprite = displayio.TileGrid(wash_on_bmp, pixel_shader=wash_on_bmp.pixel_shader)
|
||||
|
||||
# CircuitPython 6 & 7 compatible
|
||||
wash_on_file = open(WASH_ON_FILENAME, "rb")
|
||||
wash_on_bmp = displayio.OnDiskBitmap(wash_on_file)
|
||||
wash_on_sprite = displayio.TileGrid(
|
||||
wash_on_bmp,
|
||||
pixel_shader=getattr(wash_on_bmp, 'pixel_shader', displayio.ColorConverter())
|
||||
)
|
||||
|
||||
# # CircuitPython 7+ compatible
|
||||
# wash_on_bmp = displayio.OnDiskBitmap(WASH_ON_FILENAME)
|
||||
# wash_on_sprite = displayio.TileGrid(wash_on_bmp, pixel_shader=wash_on_bmp.pixel_shader)
|
||||
|
||||
clue_display.append(wash_on_sprite)
|
||||
|
||||
# draw the foreground image
|
||||
WASH_OFF_FILENAME = "wash_off.bmp"
|
||||
|
||||
wash_off_bmp = displayio.OnDiskBitmap(WASH_OFF_FILENAME)
|
||||
wash_off_sprite = displayio.TileGrid(wash_off_bmp, pixel_shader=wash_off_bmp.pixel_shader)
|
||||
# CircuitPython 6 & 7 compatible
|
||||
wash_off_file = open(WASH_OFF_FILENAME, "rb")
|
||||
wash_off_bmp = displayio.OnDiskBitmap(wash_off_file)
|
||||
wash_off_sprite = displayio.TileGrid(
|
||||
wash_off_bmp,
|
||||
pixel_shader=getattr(wash_off_bmp, 'pixel_shader', displayio.ColorConverter())
|
||||
)
|
||||
|
||||
# # CircuitPython 7+ compatible
|
||||
# wash_off_bmp = displayio.OnDiskBitmap(WASH_OFF_FILENAME)
|
||||
# wash_off_sprite = displayio.TileGrid(wash_off_bmp, pixel_shader=wash_off_bmp.pixel_shader)
|
||||
|
||||
clue_display.append(wash_off_sprite)
|
||||
|
||||
|
||||
# Create text
|
||||
# first create the group
|
||||
text_group = displayio.Group()
|
||||
0
CLUE/CLUE_Hand_Wash_Timer/font/RacingSansOne-Regular-29.bdf → CLUE_Hand_Wash_Timer/font/RacingSansOne-Regular-29.bdf
Normal file → Executable file
0
CLUE/CLUE_Hand_Wash_Timer/font/RacingSansOne-Regular-38.bdf → CLUE_Hand_Wash_Timer/font/RacingSansOne-Regular-38.bdf
Normal file → Executable file
0
CLUE/CLUE_Hand_Wash_Timer/wash_off.bmp → CLUE_Hand_Wash_Timer/wash_off.bmp
Normal file → Executable file
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
0
CLUE/CLUE_Hand_Wash_Timer/wash_on.bmp → CLUE_Hand_Wash_Timer/wash_on.bmp
Normal file → Executable file
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
0
CLUE/CLUE_Light_Painter/bmp2led.py → CLUE_Light_Painter/bmp2led.py
Normal file → Executable file
|
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
0
CLUE/CLUE_Light_Painter/bmps-72px/rainbow.bmp → CLUE_Light_Painter/bmps-72px/rainbow.bmp
Normal file → Executable file
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
0
CLUE/CLUE_Light_Painter/bmps-72px/wales.bmp → CLUE_Light_Painter/bmps-72px/wales.bmp
Normal file → Executable file
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
0
CLUE/CLUE_Light_Painter/boot.py → CLUE_Light_Painter/boot.py
Normal file → Executable file
0
CLUE/CLUE_Light_Painter/code.py → CLUE_Light_Painter/code.py
Normal file → Executable file
0
CLUE/CLUE_Light_Painter/richbutton.py → CLUE_Light_Painter/richbutton.py
Normal file → Executable file
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 169 KiB |
|
Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 169 KiB |