adding moon phase clock & bluetooth speaker
CircuitPython code for moon phase clock and arduino code for bluetooth lumon speaker
This commit is contained in:
parent
a216a61a40
commit
1e54149f1a
3 changed files with 202 additions and 0 deletions
0
Bluetooth_Lumon_Speaker/.esp32.test.only
Normal file
0
Bluetooth_Lumon_Speaker/.esp32.test.only
Normal file
44
Bluetooth_Lumon_Speaker/Bluetooth_Lumon_Speaker.ino
Normal file
44
Bluetooth_Lumon_Speaker/Bluetooth_Lumon_Speaker.ino
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// SPDX-FileCopyrightText: 2020 Phil Schatzmann
|
||||
//
|
||||
// SPDX-License-Identifier: GNU General Public License
|
||||
|
||||
/*
|
||||
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() {
|
||||
}
|
||||
158
QT_Py/NeoPixel_Moon_Phase_Clock/code.py
Normal file
158
QT_Py/NeoPixel_Moon_Phase_Clock/code.py
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
# 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 neopixel
|
||||
import adafruit_requests
|
||||
from adafruit_ticks import ticks_ms, ticks_add, ticks_diff
|
||||
|
||||
# FarmSense API for moon phase
|
||||
# https://www.farmsense.net/api/astro-widgets/
|
||||
url = "https://api.farmsense.net/v1/moonphases/?d="
|
||||
# Adafruit IO time server for UNIX time, no API key needed
|
||||
time_url = "https://io.adafruit.com/api/v2/time/seconds"
|
||||
# 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
|
||||
pool = socketpool.SocketPool(wifi.radio)
|
||||
requests = adafruit_requests.Session(pool, ssl.create_default_context())
|
||||
|
||||
# neopixels, 49 total
|
||||
OFF = (0, 0, 0)
|
||||
ON = (255, 255, 255)
|
||||
pixel_pin = board.A3
|
||||
num_pixels = 49
|
||||
pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.1, auto_write=False)
|
||||
pixels.fill(0)
|
||||
|
||||
# phases of the moon
|
||||
NEW_MOON = 0
|
||||
WAXING_CRESCENT = 1
|
||||
FIRST_QUARTER = 2
|
||||
WAXING_GIBBOUS = 3
|
||||
FULL_MOON = 4
|
||||
WANING_GIBBOUS = 5
|
||||
THIRD_QUARTER = 6
|
||||
WANING_CRESCENT = 7
|
||||
# strings that match return from API
|
||||
phase_names = ["New Moon", "Waxing Crescent", "First Quarter", "Waxing Gibbous",
|
||||
"Full Moon", "Waning Gibbous", "Third Quarter", "Waning Crescent"]
|
||||
|
||||
# functions for each moon phase to light up based on neopixel orientation
|
||||
def set_new_moon():
|
||||
pixels.fill(OFF)
|
||||
pixels.show()
|
||||
|
||||
def set_waxing_crescent():
|
||||
pixels.fill(OFF)
|
||||
for i in range(31, 44):
|
||||
pixels[i] = ON
|
||||
pixels.show()
|
||||
|
||||
def set_first_quarter():
|
||||
pixels.fill(OFF)
|
||||
for i in range(24, 49):
|
||||
pixels[i] = ON
|
||||
pixels.show()
|
||||
|
||||
def set_waxing_gibbous():
|
||||
pixels.fill(OFF)
|
||||
for i in range(0, 4):
|
||||
pixels[i] = ON
|
||||
for i in range(18, 49):
|
||||
pixels[i] = ON
|
||||
pixels.show()
|
||||
|
||||
def set_full_moon():
|
||||
pixels.fill(ON)
|
||||
pixels.show()
|
||||
|
||||
def set_waning_gibbous():
|
||||
pixels.fill(OFF)
|
||||
for i in range(0, 30):
|
||||
pixels[i] = ON
|
||||
for i in range(44, 49):
|
||||
pixels[i] = ON
|
||||
pixels.show()
|
||||
|
||||
def set_third_quarter():
|
||||
pixels.fill(OFF)
|
||||
for i in range(0, 24):
|
||||
pixels[i] = ON
|
||||
pixels.show()
|
||||
|
||||
def set_waning_crescent():
|
||||
pixels.fill(OFF)
|
||||
for i in range(5, 18):
|
||||
pixels[i] = ON
|
||||
pixels.show()
|
||||
|
||||
# match functions with phases
|
||||
phase_functions = {
|
||||
NEW_MOON: set_new_moon,
|
||||
WAXING_CRESCENT: set_waxing_crescent,
|
||||
FIRST_QUARTER: set_first_quarter,
|
||||
WAXING_GIBBOUS: set_waxing_gibbous,
|
||||
FULL_MOON: set_full_moon,
|
||||
WANING_GIBBOUS: set_waning_gibbous,
|
||||
THIRD_QUARTER: set_third_quarter,
|
||||
WANING_CRESCENT: set_waning_crescent
|
||||
}
|
||||
|
||||
# test function, runs through all 8 in order
|
||||
def demo_all_phases(delay=1):
|
||||
for phase in range(8):
|
||||
print(f"Setting phase: {phase_names[phase]}")
|
||||
phase_functions[phase]()
|
||||
time.sleep(delay)
|
||||
demo_all_phases()
|
||||
|
||||
# takes response from API, matches to function, runs function
|
||||
def set_moon_phase(phase):
|
||||
phase_lower = phase.lower()
|
||||
for i, name in enumerate(phase_names):
|
||||
if phase_lower == name.lower():
|
||||
phase_functions[i]()
|
||||
print(f"Moon phase set to: {name}")
|
||||
|
||||
# time keeping, fetches API every 6 hours
|
||||
timer_clock = ticks_ms()
|
||||
timer = (6 * 3600) * 1000
|
||||
first_run = True
|
||||
|
||||
while True:
|
||||
try:
|
||||
if first_run or ticks_diff(ticks_ms(), timer_clock) >= timer:
|
||||
# get unix time
|
||||
unix_time = requests.get(time_url)
|
||||
# update farmsense request with UNIX time
|
||||
url = f"https://api.farmsense.net/v1/moonphases/?d={unix_time.text}"
|
||||
# get the JSON response
|
||||
response = requests.get(url)
|
||||
json_response = response.json()
|
||||
# isolate phase info
|
||||
print("-" * 40)
|
||||
print(json_response[0]['Phase'])
|
||||
print("-" * 40)
|
||||
# run function to update neopixels with current phase
|
||||
set_moon_phase(json_response[0]['Phase'])
|
||||
response.close()
|
||||
time.sleep(1)
|
||||
first_run = False
|
||||
# reset clock
|
||||
timer_clock = ticks_add(timer_clock, timer)
|
||||
# pylint: disable=broad-except
|
||||
except Exception as e:
|
||||
print("Error:\n", str(e))
|
||||
print("Resetting microcontroller in 10 seconds")
|
||||
time.sleep(10)
|
||||
microcontroller.reset()
|
||||
Loading…
Reference in a new issue