메뉴 전체보기

회원메뉴

PrismCube — 날씨에 반응하는 앰비언트 라이트 큐브 > 게시판

본문 바로가기

쇼핑몰 검색

NO. 3569
제목 : PrismCube — 날씨에 반응하는 앰비언트 라이트 큐브
2026-10-13 10:35

소개: PrismCube — 날씨에 반응하는 앰비언트 라이트 큐브


소개: PrismCube — 날씨에 반응하는 앰비언트 라이트 큐브


대부분의 기상 기기는 밖의 날씨 상황을 알려줄 뿐입니다. PrismCube는 그 날씨를 직접 느끼게 해줍니다.

PrismCube는 실시간 날씨를 생동감 넘치는 빛의 경험으로 변환해 주는 미니멀한 분위기형 날씨 디스플레이입니다. 화면에 일기 예보를 표시하는 대신, 맑고 푸른 오후와 황금빛 노을부터 가랑비, 짙은 안개, 그리고 격렬한 뇌우에 이르기까지 변화하는 하늘에 맞춰 끊임없이 변하는 부드럽게 확산되는 빛 하나로 분위기를 표현합니다.

공간에 자연스럽게 어우러지도록 설계된 PrismCube는 거의 아무런 조작도 필요하지 않습니다. 전원을 연결하기만 하면 자동으로 Wi-Fi에 연결되어 실시간 기상 데이터를 가져오고, 하루 종일 조명 상태를 상황에 맞게 조절합니다. 버튼도, 화면도, 확인할 앱도 없습니다. 유일한 상호작용은 큐브를 뒤집어 생동감 넘치는 ‘레인보우 모드’를 활성화한 뒤, 다시 똑바로 세우면 날씨 시각화 모드로 매끄럽게 돌아가는 것뿐입니다.

각 기상 조건에 하나의 색상만 할당하는 기존의 날씨 디스플레이와 달리, PrismCube는 시간이 지남에 따라 자연스럽게 변화하는 정교하게 제작된 색상 팔레트를 통해 하늘의 느낌을 재현합니다. 모든 색상 전환은 자연에서 빛이 움직이는 방식에서 영감을 받아, 단순히 정보를 표시하는 것을 넘어 차분하고 몰입감 있는 경험을 선사합니다.

Waveshare ESP32-S3 Matrix 개발 보드를 기반으로 제작된 PrismCube는 임베디드 시스템, IoT, 세심한 제품 디자인을 결합하여 컴팩트한 데스크톱용 기기로 탄생했습니다. 외장은 Autodesk Fusion 360을 통해 정교하게 설계되었으며, 미학, 빛의 확산, 기능성을 조화롭게 균형 잡음으로써 어떤 작업 공간에도 잘 어울리는 깔끔하고 현대적인 형태를 완성했습니다.

PrismCube는 단순한 날씨 기기가 아닙니다. 빛을 통해 실내로 가져온 하늘의 작은 조각입니다.

NextPCB 제공

하드웨어 프로젝트를 진행하는 데는 비용이 많이 들 수 있지만, NextPCB는 메이커, 스타트업, 엔지니어들이 더 쉽게 프로젝트를 진행할 수 있도록 돕습니다. 지금 10개 이하 주문 시 전문 턴키 PCB 조립 서비스를 최대 200달러 할인된 가격에 이용하실 수 있습니다.

PCB 제조와 부품 조달부터 전체 조립 및 테스트에 이르기까지, NextPCB는 신뢰할 수 있는 품질과 신속한 서비스로 모든 과정을 한 곳에서 처리해 드립니다. IoT 기기, 로봇 공학 프로젝트, 맞춤형 전자 제품을 제작하든 상관없이, 이 혜택은 비용을 절약하면서 전문적인 시제품을 제작할 수 있는 훌륭한 방법입니다.

제 링크를 통해 직접 이용해 보시고, PCBA 주문 시 $200 할인을 받아보세요!




STEP 1. 준비물


준비물


준비물


준비물


구성 요소
  1. Waveshare ESP32-S3 Matrix
  2. USB-C 케이블
도구
  1. Bambulab 3D 프린터
  2. PLA 필라멘트 (검정색 및 무광 흰색)
  3. 펜치
  4. 초강력 접착제
소프트웨어
  1. 아두이노 IDE
  2. 오토데스크 퓨전 360
  3. OpenWeatherMap (무료 API 계정)
GitHub
  1. 저장소




STEP 2. 인클로저 설계


인클로저 설계


먼저 Autodesk Fusion 360에서 전체 케이스를 설계했는데, 디자인을 콤팩트하고 조립하기 쉽게 만들었으며 Waveshare ESP32-S3 Matrix 보드에 최적화했습니다.

부드럽고 균일한 빛을 내기 위해, 일반적인 평면 디퓨저 대신 리소페인에서 영감을 받은 디퓨저를 사용했습니다. 두께를 다양하게 조절함으로써 빛이 표면 전체에 더 고르게 퍼지게 되어, 눈에 띄는 LED 핫스팟을 줄이고 훨씬 더 부드러운 분위기 효과를 연출할 수 있습니다.




STEP 3. 인클로저 3D 프린팅


인클로저 3D 프린팅


인클로저 3D 프린팅


설계가 완료된 후, PLA 필라멘트를 사용하여 모든 부품을 출력했습니다. 디퓨저에는 벽 두께 0.8mm의 무광 흰색 PLA를 사용했습니다. 이를 통해 리토페인 효과를 유지하면서도 빛을 탁월하게 확산시켜, 표면 전체에 부드럽고 균일한 빛을 발산합니다.

하우징에는 벽 두께 3mm의 블랙 PLA를 사용하여, 깔끔하고 미니멀한 외관을 유지하면서도 케이스에 충분한 강성과 내구성을 부여했습니다.




STEP 4. 하드웨어 조립


하드웨어 조립


하드웨어 조립


Waveshare ESP32-S3 매트릭스 보드를 3D 프린팅으로 제작된 케이스에 조심스럽게 끼워 넣으세요. 이때 보드가 케이스와 수평을 이루고, LED 매트릭스가 전면 개구부와 일직선이 되도록 주의하십시오. 보드와 케이스 사이의 틈이 없도록 꼭 맞아야 하므로, 설치 시 과도한 힘을 가하지 마십시오. 모든 부분이 정렬되면 가장자리 주변에 아주 소량의 초강력 접착제를 발라 보드를 제자리에 고정하십시오.




STEP 5. 디퓨저 설치하기


디퓨저 설치하기


디퓨저 설치하기


3D 프린팅으로 제작한 디퓨저를 LED 매트릭스 위에 올려놓고, 보드에 압력이 가해지지 않도록 인클로저 내부에 고르게 위치하도록 합니다. 정렬 상태가 만족스러우면 가장자리 주변에 아주 소량의 슈퍼 접착제를 발라 고정합니다.




STEP 6. OpenWeatherMap API 키


OpenWeatherMap API 키


OpenWeatherMap API 키


PrismCube는 OpenWeatherMap을 사용하여 실시간 기상 데이터를 가져옵니다. 펌웨어를 설정하기 전에 무료 API 키가 필요합니다.

OpenWeatherMap 웹사이트를 방문하여 무료 계정을 생성하세요. 이메일 주소를 확인한 후 ‘My API Keys’ 페이지를 열면, 계정에 대해 이미 생성된 기본 API 키를 확인할 수 있습니다. 이 키를 사용하거나 원한다면 새 키를 생성할 수도 있습니다. API 키를 잘 보관해 두세요. 다음 단계에서 Config.h를 설정할 때 필요하게 됩니다.

참고: 새 API 키가 활성화되는 데 몇 분 정도 걸릴 수 있습니다. 펌웨어를 업로드한 직후 PrismCube가 기상 데이터를 가져오지 못한다면, 잠시 기다렸다가 다시 시도해 보세요.




STEP 7. 펌웨어 구성 (Config.h)


펌웨어를 업로드하기 전에, 사용자의 환경에 맞게 PrismCube를 설정해야 합니다. 간편하게 설정할 수 있도록, 사용자가 편집할 수 있는 모든 설정은 Config.h라는 단일 파일에 저장되어 있습니다. 다른 Wi-Fi 네트워크에 연결하거나, 사용자 지정 기상 위치를 사용하거나, 조명 동작을 조정하는 경우 등, 일반적으로 수정해야 할 파일은 이 파일뿐입니다.

Wi-Fi 및 날씨 설정

먼저 Wi-Fi 접속 정보와 OpenWeatherMap API 키를 입력하세요.

#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"

#define OWM_API_KEY "YOUR_OPENWEATHERMAP_API_KEY"

다음으로, PrismCube가 실시간 날씨 업데이트에 사용할 위치를 설정하세요. 도시 이름 대신 위도와 경도를 사용하는 것이 더 정확하고 오해의 소지를 피할 수 있으므로 권장합니다.

#define OWM_USE_LATLON 1

#define OWM_LAT 34.0522
#define OWM_LON -118.2437

펌웨어는 10분마다 자동으로 새로운 기상 정보를 확인하므로, 반응 속도와 네트워크 사용량 간의 균형을 잘 맞춥니다.

하드웨어 구성 확인

Waveshare ESP32-S3 Matrix 보드를 사용하는 경우, 이 섹션에서 아무것도 변경할 필요가 없습니다.

#define LED_DATA_PIN 14
#define LED_COUNT 64

#define IMU_SDA_PIN 11
#define IMU_SCL_PIN 12

이 값들은 보드 내장 8×8 RGB LED 매트릭스와 내장된 QMI8658 IMU를 정의합니다.

PrismCube 사용자 지정

또한 PrismCube의 동작 방식을 제어하는 여러 설정도 확인할 수 있습니다.

#define BRIGHTNESS_DAY 235
#define BRIGHTNESS_EVENING 153
#define BRIGHTNESS_NIGHT 45

#define BRIGHTNESS_MAX_CAP 235

최대 밝기는 일상적인 사용에 충분한 밝기를 유지하면서도 발열을 줄이기 위해, 최대값인 255 대신 의도적으로 235로 제한되어 있습니다.

각 날씨 분위기의 느낌을 맞춤 설정하고 싶다면 애니메이션 타이밍도 조정할 수 있습니다.

#define CYCLE_CLEAR_MS 16000
#define CYCLE_STORM_MS 7000
#define CYCLE_FOG_MS 24000

마지막으로, 자동 무지개 감지 및 디버깅과 같은 기능을 위한 몇 가지 선택적 설정이 있습니다. 기본값은 이미 일반적인 사용에 맞게 조정되어 있으므로, 대부분의 제작자는 이를 변경할 필요가 없습니다.




STEP 8. 컬러 엔진 (PaletteEngine.h)


기본 설정이 완료되었으니, 이제 PrismCube의 개성을 만들어내는 부분을 살펴볼 차례입니다. 팔레트 엔진은 원시 기상 데이터를 조명 경험으로 변환하는 역할을 합니다. 이 엔진은 LED에 무엇을 표시할지 결정하는 대신, 날씨가 어떤 느낌을 주는지 결정합니다 느낌을 세심하게 설계된 색상 팔레트와 애니메이션을 통해 전달할지 결정합니다.

날씨 분위기 정의하기

가장 먼저 보게 될 것은 WeatherMood 열거형입니다.

enum class WeatherMood {
CLEAR, PARTLY_CLOUDY, CLOUDY, LIGHT_RAIN, RAIN, THUNDERSTORM,
FOG, SNOW, SUNRISE, SUNSET, NIGHT, RAINBOW_SPECIAL
};

펌웨어 전반에 걸쳐 날씨 상태 ID를 직접 다루기보다는, 모든 것이 먼저 이러한 미리 정의된 분위기 중 하나로 변환됩니다. 이를 통해 나머지 코드가 훨씬 깔끔해질 뿐만 아니라, 나중에 자신만의 날씨 효과를 쉽게 추가할 수도 있습니다.

색상 팔레트 생성

각 분위기는 Palette3이라는 간단한 구조를 사용하여 정의됩니다.

struct Palette3 {
CRGB top, mid, bottom;
uint16_t fadeMs;
uint16_t cycleMs;
bool rainbowWash = false;
};

변수 이름이 top, mid, 그리고 bottom으로되어 있지만, 이는 LED 매트릭스의 서로 다른 영역을 나타내는 것은 아닙니다. 케이스에 반투명 디퓨저가 사용되기 때문에 64개의 LED가 모두 하나의 빛점으로 자연스럽게 어우러집니다. 대신, 이 세 가지 색상은 빛이 시간이 지남에 따라 이동하는 경로를 나타내며, 한 색상에서 다음 색상으로 부드럽게 전환된 후 다시 반복됩니다.

표시할 분위기 결정하기

새로운 기상 데이터가 수신될 때마다 펌웨어는 decideMood()를 호출합니다.

inline WeatherMood PaletteEngine::decideMood(const WeatherState& w) {
if (!w.valid) return WeatherMood::CLEAR;

if (w.sunrise > 0 && w.sunset > 0) {
time_t now = time(nullptr);
const time_t window = 35 * 60;

if (now > 1700000000) {
if (llabs((long long)now - (long long)w.sunrise) < window) return WeatherMood::SUNRISE;
if (llabs((long long)now - (long long)w.sunset) < window) return WeatherMood::SUNSET;
if (!w.isDaytime) return WeatherMood::NIGHT;
}
}

if (looksLikeRainbowConditions(w)) return WeatherMood::RAINBOW_SPECIAL;

int id = w.conditionId;

if (id >= 200 && id <= 232) return WeatherMood::THUNDERSTORM;
if (id >= 300 && id <= 321) return WeatherMood::LIGHT_RAIN;
if (id >= 500 && id <= 531) return WeatherMood::RAIN;
if (id >= 600 && id <= 622) return WeatherMood::SNOW;
if (id >= 701 && id <= 781) return WeatherMood::FOG;
if (id == 800) return WeatherMood::CLEAR;
if (id == 801 || id == 802) return WeatherMood::PARTLY_CLOUDY;
if (id == 803 || id == 804) return WeatherMood::CLOUDY;

return WeatherMood::CLEAR;
}

이러한 확인 순서는 의도된 것입니다. 일출, 일몰, 그리고 야간 조건이 먼저 평가되고, 그다음 자동 무지개 조건이 평가된 후, 마지막으로 OpenWeatherMap에서 반환된 기상 조건 ID가 확인됩니다. 이를 통해 큐브는 항상 가장 의미 있는 시각적 경험을 표시합니다. 예를 들어 일몰 중에 가랑비가 내리고 있더라도 PrismCube는 즉시 비 팔레트로 전환하는 대신 일몰 색상을 우선합니다.

무지개 조건 감지

제가 자연스럽게 구현하고 싶었던 기능 중 하나는 ‘무지개 모드’였습니다. 수동으로 활성화할 필요 없이, 펌웨어가 실제 무지개가 나타날 가능성이 높은 기상 조건을 자동으로 감지합니다.

inline bool PaletteEngine::looksLikeRainbowConditions(const WeatherState& w) {
if (!w.valid || !w.isDaytime) return false;

bool lightRain =
(w.conditionId >= 300 && w.conditionId <= 321) ||
(w.conditionId == 500);

return lightRain && w.cloudsPct <= RAINBOW_AUTO_CLOUD_MAX;
}

논리는 간단합니다. 낮 시간대이고, 가랑비가 내리며, 구름량이 햇빛이 비칠 만큼 충분히 낮다면 PrismCube는 자동으로 Rainbow Special 색상 팔레트로 전환됩니다. 또한 큐브를 뒤집기만 하면 언제든지 수동으로 동일한 팔레트를 활성화할 수 있습니다. 거주 지역에서 레인보우 모드가 더 자주 또는 덜 자주 작동하도록 하려면 RAINBOW_AUTO_CLOUD_MAX 값을 자유롭게 조정해 보세요.

각 기상 팔레트 구성

분위기가 선택되면 펌웨어는 해당 팔레트를 불러옵니다.

case WeatherMood::RAIN:
p.top = CRGB(0x2E, 0x5D, 0x9E);
p.mid = CRGB(0x3E, 0x9B, 0xB8);
p.bottom = CRGB(0x1D, 0x3E, 0x6B);
p.fadeMs = FADE_RAIN_MS;
p.cycleMs = CYCLE_RAIN_MS;
p.rainbowWash = true;
break;

case WeatherMood::THUNDERSTORM:
p.top = CRGB(0x1A, 0x0F, 0x33);
p.mid = CRGB(0x2B, 0x16, 0x50);
p.bottom = CRGB(0x14, 0x0A, 0x24);
p.fadeMs = FADE_STORM_MS;
p.cycleMs = CYCLE_STORM_MS;
p.stormFlicker = true;
break;

모든 날씨 분위기는 세 가지 색상, 전환 속도, 주기 지속 시간, 그리고 선택적 시각 효과라는 동일한 구조를 따릅니다. 이를 통해 애니메이션 로직을 변경하지 않고도 PrismCube의 외관을 쉽게 맞춤 설정할 수 있습니다. 더 따뜻한 일몰, 더 밝은 비 오는 날, 혹은 더 극적인 폭풍을 원하신다면, 이곳이 프로젝트를 개인화하기에 가장 적합한 곳입니다.

은은한 온도 색조 추가

마지막으로, 모든 팔레트에는 현재 온도에 따른 미세한 색상 조정이 적용됩니다.

static CRGB tintForTemp(CRGB c, float tempC) {
if (tempC <= 10.0f) {
c.b = qadd8(c.b, 12);
c.g = qadd8(c.g, 4);
}
else if (tempC >= 32.0f) {
c.r = qadd8(c.r, 14);
c.g = qadd8(c.g, 6);
}

return c;
}

전체 팔레트를 변경하는 대신, 이 함수는 추운 날씨의 색상을 파란색 쪽으로, 따뜻한 날씨의 색상을 호박색 쪽으로 약간 조정할 뿐입니다. 색조는 날씨 팔레트가 선택된 후에 적용되므로, 원래 분위기는 그대로 유지하면서 실외 온도를 미묘하게 반영합니다.




STEP 9. 색상 애니메이션 적용 (GradientAnimator.h)


GradientAnimator는 선택된 색상 팔레트를 부드럽고 연속적인 애니메이션으로 변환하는 역할을 합니다. 이 모듈은 LED를 직접 제어하는 유일한 모듈로, 모든 전환이 갑작스럽지 않고 부드럽고 자연스럽게 느껴지도록 보장합니다.

컬러 여정 만들기

애니메이션은 sampleJourney() 함수로 시작됩니다.

inline CRGB GradientAnimator::sampleJourney(const Palette3& p, unsigned long nowMs) {
uint16_t cycle = (p.cycleMs > 0) ? p.cycleMs : 1;

float phase = (float)(nowMs % cycle) / (float)cycle;

int seg = (int)(phase * 3.0f);
if (seg > 2) seg = 2;

float local = easeInOut(phase * 3.0f - seg);

CRGB stops[3] = { p.top, p.mid, p.bottom };

return lerpColor(stops[seg], stops[(seg + 1) % 3], local);
}

이 함수는 세 가지 색상을 순간적으로 전환하는 대신, 색상들을 부드럽게 혼합합니다. 애니메이션은 팔레트를 다음과 같은 순서로 순환합니다: 상단 → 중간 → 하단 → 상단

이동은 선형적이지 않고 이즈(ease) 효과가 적용되므로, 각 새로운 색조에 도달하기 전에 색상이 자연스럽게 속도를 늦추며, 큐브에 차분하게 숨 쉬는 듯한 느낌을 줍니다.

기상 조건 전환

날씨가 바뀔 때마다 펌웨어는 새로운 팔레트를 불러옵니다. setTarget()은 새로운 색상으로 바로 전환하는 대신 부드러운 크로스페이드를 생성합니다.

inline void GradientAnimator::setTarget(const Palette3& target) {

unsigned long now = millis();

if (!_hasRendered) {
_active = target;
_hasRendered = true;
_fading = false;
return;
}

_fadeFromColor = sampleJourney(_active, now);

_active = target;
_fadeStartMs = now;
_fadeDurationMs = target.fadeMs;
_fading = true;
}

날씨가 바뀌는 정확히 그 순간에 현재 색상이 샘플링된다는 점에 유의하세요. 이는 큐브가 애니메이션을 처음부터 다시 시작하는 대신 항상 현재 보이는 색상에서 페이드 아웃되므로, 모든 전환이 매끄럽게 느껴지게 합니다. 이러한 전환이 진행되는 동안 호흡 효과는 잠시 줄어들어 크로스페이드가 부드럽고 자연스럽게 유지된 후, 서서히 원래 상태로 돌아옵니다.

애니메이션 렌더링

활성 색상이 계산되면 render() 함수가 LED를 업데이트합니다.

inline void GradientAnimator::render() {

if (!_leds || _count == 0) return;

unsigned long nowMs = millis();

CRGB journey = sampleJourney(_active, nowMs);

// ...렌더링 코드...
}

모든 프레임은 동일한 순서를 따릅니다: 현재 팔레트를 샘플링하고, 날씨 전환이 진행 중이라면 부드럽게 블렌딩하며, 호흡 효과를 적용하고, 번개나 무지개 빛과 같은 선택적 효과를 추가하고, 감마 보정을 적용하고, 밝기를 조정한 뒤, 마지막으로 64개의 모든 LED에 동일한 색상을 전송합니다.

보드에는 8×8 LED 매트릭스가 탑재되어 있지만, 반투명 디퓨저가 모든 LED를 하나의 부드러운 빛점으로 자연스럽게 혼합합니다. 그렇기 때문에 전체 매트릭스는 항상 정밀하게 계산된 단일 색상을 표시합니다. LED가 업데이트되기 전, 최종 색상도 미세한 변동을 제거하기 위해 부드럽게 보정되어 애니메이션이 안정적이고 유동적으로 유지됩니다. 번개 효과는 의도적으로 이 스무딩 과정을 거치지 않아, 각 섬광이 선명하고 순간적으로 나타납니다.

색상을 자연스럽게 보이게 하기

LED로 색상을 전송하기 전에 PrismCube는 감마 보정을 적용합니다.

inline CRGB GradientAnimator::gammaCorrect(CRGB c) {

auto videoScale = [](uint8_t x) -> uint8_t {

uint8_t r = ((uint16_t)x * x) >> 8;

return (x && !r) ? 1 : r;

};

return CRGB(
videoScale(c.r),
videoScale(c.g),
videoScale(c.b)
);
}

LED 밝기는 우리 눈으로 선형적으로 인식되지 않습니다. 감마 보정을 하지 않으면 낮은 밝기 수준이 종종 흐릿하거나 고르지 않게 보입니다. 이 보정을 적용하면 특히 야간 애니메이션이나 느린 호흡 효과에서 훨씬 더 부드러운 페이드 효과를 얻을 수 있습니다.




STEP 10. 실시간 기상 데이터 가져오기 (WeatherManager.h)


WeatherManager는 Wi-Fi 및 OpenWeatherMap과 관련된 모든 작업을 처리하며, 온라인 기상 데이터를 펌웨어의 다른 부분이 이해할 수 있는 간단한 WeatherState 구조체로 변환합니다.

Wi-Fi 연결

첫 번째 작업은 Config.h에 저장된 인증 정보를 사용하여 PrismCube를 Wi-Fi 네트워크에 연결하는 것입니다.

WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

시작 과정에서 펌웨어는 지속적으로 연결을 시도합니다. 연결이 완료되면 시스템 시간을 자동으로 동기화하고 실시간 기상 데이터를 요청할 준비를 합니다. Wi-Fi를 사용할 수 없는 경우, PrismCube는 완전히 중지되지 않고 백그라운드에서 재연결을 계속 시도하며 작동을 유지합니다.

날씨 데이터 요청

연결이 완료되면 펌웨어는 OpenWeatherMap API에 요청을 보냅니다.

http.begin(url);
int httpCode = http.GET();

이 요청에는 사용자가 설정한 위치와 API 키가 포함되며, 최신 기상 정보가 JSON 형식으로 반환됩니다. 응답 속도와 네트워크 사용량 간의 균형을 맞추기 위해 PrismCube는 10분마다 새로운 기상 정보를 확인하며, 이는 OpenWeatherMap의 업데이트 주기와도 일치합니다.

응답 파싱

응답을 수신한 후, ArduinoJson은 PrismCube에 필요한 정보만 추출합니다.

WeatherState state;

state.conditionId = ...
state.tempC = ...
state.cloudsPct = ...
state.sunrise = ...
state.sunset = ...

펌웨어는 전체 JSON 응답을 저장하는 대신, 기상 상태, 기온, 구름 덮임률, 일출, 일몰, 현재 낮인지 여부 등 컬러 엔진에 필요한 값만 저장합니다. 어떤 필드라도 사용할 수 없는 경우, 펌웨어가 안정적으로 작동할 수 있도록 안전한 기본값이 사용됩니다.

컬러 엔진으로 날씨 정보 전달

WeatherState 구조체가 채워지면, 이 구조체는 팔레트 엔진으로 전달되며, 여기서 현재 조건은 PrismCube의 미리 정의된 날씨 분위기 중 하나로 변환됩니다. 이 시점부터 펌웨어의 나머지 부분은 전적으로 WeatherState를 기반으로 작동하며, 네트워킹 코드와 애니메이션 시스템을 분리하여 관리합니다.




STEP 11. 방향 감지 (IMUHandler.h)


PrismCube는 버튼이나 터치스크린을 사용하지 않습니다. 대신 내장된 QMI8658 6축 IMU를 통해 큐브의 배치 상태를 감지합니다. 사용자는 큐브를 뒤집기만 하면 레인보우 모드를 활성화할 수 있습니다.

IMU 초기화

큐브가 시작되면 펌웨어가 IMU를 초기화하고 정지 위치를 자동으로 보정합니다.

bool IMUHandler::begin() {

if (!_imu.begin()) return false;

calibrate();

return true;
}

보정 과정에서 펌웨어는 큐브가 정상적으로 정지해 있는 동안 중력의 방향을 기록합니다. 이 값은 향후 모든 방향 감지에 사용되는 기준이 되어, 펌웨어가 고정된 축 값에 의존하지 않고도 안정적으로 작동할 수 있게 해줍니다.

센서 읽기

IMU는 X, Y, Z 축을 따라 가속도를 지속적으로 측정합니다.

_imu.readAcceleration(&_ax, &_ay, &_az);

펌웨어는 모든 움직임에 즉시 반응하기보다는 센서 측정값을 지속적으로 업데이트하며, 큐브가 안정된 위치에 정착했는지 확인합니다.

방향 감지

PrismCube는 단일 축이 특정 값에 도달했는지 확인하는 대신, 현재 중력 벡터를 시작 시점에 캡처된 보정된 기준값과 비교합니다.

CubeOrientation IMUHandler::orientation() const {

return _orientation;

}

큐브가 새로운 위치에 잠시 머무르면 방향이 자동으로 업데이트됩니다. 이 접근 방식은 보드 리비전이나 조립 공차의 차이로 인해 IMU의 정렬이 약간 변경되더라도 감지 정확도를 훨씬 더 높여줍니다.

레인보우 모드 활성화

방향성이 변경되면 메인 펌웨어는 큐브가 거꾸로 뒤집혀 있는지 여부를 간단히 확인합니다.

if (imu.orientation() == CubeOrientation::UPSIDE_DOWN) {
rainbowForced = true;
}
else {
rainbowForced = false;
}

큐브를 똑바로 세우면 실시간 날씨가 표시됩니다. 약 1초 동안 거꾸로 뒤집으면 부드럽게 레인보우 모드로 전환됩니다. 다시 똑바로 세우면 자동으로 현재 날씨로 돌아갑니다.

안정적이고 신뢰할 수 있는 감지

큐브를 집어 들 때 의도치 않게 모드가 변경되는 것을 방지하기 위해, 펌웨어는 큐브가 잠시 동안 안정된 상태를 유지한 후에만 새로운 방향을 인식합니다. 이러한 필터링 기능을 통해 오작동을 방지하고 자연스러운 상호작용을 제공하여, 큐브가 의도적인 움직임에만 반응하도록 합니다.




STEP 12. 자동 밝기 조절 (BrightnessController.h)


PrismCube는 하루 종일 밝기를 자동으로 조절하여, 낮에는 충분히 밝게 유지하면서도 저녁과 밤에는 눈이 편안하도록 해줍니다. 이 모든 과정은 백그라운드에서 자동으로 이루어지므로, 큐브가 작동 중일 때는 별도로 설정할 필요가 없습니다.

목표 밝기 선택

펌웨어는 먼저 현재 시간을 기준으로 적절한 밝기를 결정합니다.

if (!weather.isDaytime)
_target = BRIGHTNESS_NIGHT;
else if (weather.isGoldenHour)
_target = BRIGHTNESS_EVENING;
else
_target = BRIGHTNESS_DAY;

새로운 날씨 정보가 수신될 때마다 목표 밝기가 자동으로 업데이트되어, PrismCube가 주간, 일몰, 야간 사이에서 자연스럽게 전환될 수 있습니다.

부드러운 밝기 전환

새로운 밝기 수준으로 바로 전환하는 대신, 펌웨어는 목표 값을 향해 점진적으로 이동합니다.

float step = BRIGHTNESS_CHANGE_PER_SEC * dt;

if (_current < _target)
_current = min(_current + step, _target);
else
_current = max(_current - step, _target);

전환이 프레임 수 대신 경과 시간(dt)에 따라 결정되기 때문에, 메인 루프가 얼마나 빠르게 실행되든 상관없이 밝기 변화가 부드럽고 일관되게 유지됩니다.

LED 보호

밝기 값을 애니메이션 엔진으로 전송하기 전에, 펌웨어는 최종 안전 제한을 적용합니다.

_current = min(_current, (float)BRIGHTNESS_MAX_CAP);

이를 통해 LED 매트릭스가 Config.h에 정의된 최대 밝기를 절대 초과하지 않도록 보장함으로써, 일상적인 사용에 밝고 편안한 디스플레이를 제공하면서도 발열을 줄이는 데 도움이 됩니다.




STEP 13. 메인 스케치 (PrismCube.ino)


모든 개별 모듈이 완성되었으므로, 메인 스케치는 단순히 이 모든 것을 하나로 통합하는 역할을 합니다. PrismCube.ino는 그 자체로 복잡한 논리를 포함하기보다는 각 모듈을 올바른 순서대로 조정하여, 이들이 하나의 시스템으로 함께 작동할 수 있도록 합니다.

시스템 초기화

PrismCube가 시작되면 메인 루프로 진입하기 전에 모든 모듈을 초기화합니다.

void setup() {

weather.begin();
imu.begin();
brightnessCtl.begin();

animator.begin(leds, LED_COUNT);

}

IMU가 초기화된 후, 펌웨어는 센서가 안정화될 시간을 잠시 준 다음 방향을 보고합니다.

if (imu.begin()) {
for (int i = 0; i < 6; i++) {
imu.loop();
delay(40);
}

Serial.printf("%-14s%s\n",
"Orientation",
orientationLabel(imu.orientation()));
}

이렇게 하면 처음 보고되는 방향이 안정화되도록 보장하며, 시작 직후 발생하는 잘못된 측정값을 방지할 수 있습니다.

비차단 메인 루프

초기화가 완료되면 펌웨어는 각 모듈을 지속적으로 업데이트합니다.

void loop() {

weather.loop();
imu.loop();
brightnessCtl.loop(weather.state());

applyMoodIfChanged();

animator.setBrightness(brightnessCtl.currentBrightness());
animator.render();

FastLED.show();

}

각 모듈은 필요한 작업만 수행한 후 즉시 반환됩니다. 예를 들어, 날씨 관리자는 10분마다 OpenWeatherMap에 접속하는 반면, 애니메이션과 IMU는 매 루프마다 원활하게 업데이트를 계속합니다. 메인 루프를 차단하는 요소가 없기 때문에 PrismCube는 부드러운 애니메이션을 유지하면서도 반응성을 잃지 않습니다.

디버깅 용이화

개발 및 테스트를 용이하게 하기 위해, 펌웨어는 원시 숫자 대신 읽기 쉬운 이름을 출력합니다.

const char* moodName(WeatherMood m);
const char* orientationLabel(CubeOrientation o);

Mood = 5와 같은 값을 표시하는 대신, 시리얼 모니터에는 ‘Thunderstorm’, ‘Rainbow Special’ 또는 ‘Top Up(Weather Mode)’과 같은 설명적인 이름이 표시되어 펌웨어가 무엇을 수행하고 있는지 훨씬 쉽게 이해할 수 있습니다.

DEBUG_VERBOSE가 활성화되면, PrismCube는 계산된 LED 색상과 감마 보정 및 밝기 조정 후 LED로 전송되는 최종 색상을 모두 표시할 수도 있습니다. 이를 통해 개발 과정에서 애니메이션이 의도한 대로 정확히 동작하는지 확인하기가 훨씬 쉬워집니다.




STEP 14. 펌웨어 업로드


펌웨어를 업로드하기 전에, 몇 가지 라이브러리를 설치하고 Waveshare ESP32-S3 Matrix 보드에 맞게 Arduino IDE를 설정해야 합니다.

필요한 라이브러리 설치

'스케치' → '라이브러리 포함' → '라이브러리 관리...'를 열고 다음 라이브러리를 설치하십시오:

  1. FastLED
  2. ArduinoJson
중요: 버전 7.x 대신 ArduinoJson 6.21.x를 사용하십시오. 펌웨어는 6.x API를 사용하며, ArduinoJson 7을 사용하면 프로젝트가 올바르게 컴파일되지 않습니다.

WiFi.h, HTTPClient.h, Wire.h, time.h와 같은 나머지 라이브러리는 ESP32 보드 패키지에 포함되어 있으므로 별도로 설치할 필요가 없습니다.

Arduino IDE 설정

USB-C 케이블을 사용하여 PrismCube를 컴퓨터에 연결한 다음, 다음을 선택하십시오: 도구 → 보드 → ESP32 → Waveshare ESP32-S3-Matrix

Waveshare 보드가 목록에 없으면, Config.h에서 모든 하드웨어 핀이 수동으로 구성되어 있으므로 단순히 ESP32S3 Dev Module을 선택하면 됩니다. 다음으로, 도구 → 포트에서 올바른 시리얼 포트를 선택합니다. 업로드하기 전에 다음 설정을 확인하십시오:

  1. 부팅 시 USB CDC: 사용
  2. 파티션 구성: Huge APP (3MB, OTA 미지원/1MB SPIFFS)
  3. 플래시 크기: 4MB (32Mb)
  4. 플래시 모드: QIO 80MHz
  5. CPU 주파수: 240MHz (WiFi)
  6. PSRAM: 비활성화됨
  7. 코어 디버그 레벨: 없음
펌웨어 업로드

모든 설정이 완료되면 ‘업로드’를 클릭합니다. 펌웨어가 성공적으로 업로드된 후, 시리얼 모니터를 열어 보드가 Wi-Fi에 연결되고 실시간 기상 데이터를 수신하기 시작하는지 확인합니다.




STEP 15. 테스트


테스트


PrismCube의 전원을 켜고 부팅이 완료될 때까지 잠시 기다리세요. 기기가 자동으로 Wi-Fi 네트워크에 연결되어 최신 날씨 데이터를 가져온 후, 이에 맞는 조명 효과를 표시하기 시작할 것입니다. 첫 번째 날씨 애니메이션으로의 전환은 순간적으로 이루어지지 않고 부드럽고 점진적으로 진행되어야 합니다.

큐브의 색상을 설정하신 위치의 현재 날씨와 비교해 보세요. 표시되는 색상은 전반적인 분위기를 반영해야 합니다. 예를 들어, 맑은 하늘에서는 부드러운 파란색과 따뜻한 황금색 톤이 나타나고, 비나 뇌우가 내릴 때는 차가운 파란색이나 짙은 보라색 음영으로 바뀌어야 합니다. 애니메이션은 정지된 상태로 머무르지 않고 지속적으로 변화해야 합니다.

마지막으로, 큐브를 거꾸로 뒤집어 약 1초 동안 가만히 두십시오. 그러면 더 생동감 넘치는 색상 애니메이션이 적용된 ‘무지개 모드’로 부드럽게 전환되어야 합니다. 다시 똑바로 세우면 자동으로 실시간 날씨 표시로 돌아와야 합니다.




STEP 16. 날씨의 기분을 이해하기


PrismCube는 각 기상 조건에 단일 색상을 할당하지 않습니다. 대신, 모든 기상 유형은 세 가지 색조 사이에서 서서히 변화하는 정교하게 설계된 색상 팔레트로 표현되어, 하늘을 더욱 자연스럽고 차분하게 묘사합니다.

또한 각 분위기마다 고유한 애니메이션 속도가 적용됩니다. 잔잔한 날씨는 천천히 변화하는 반면, 뇌우와 같은 역동적인 기상 조건은 분위기를 더 잘 반영하기 위해 더 빠르게 애니메이션이 진행됩니다.

  1. ☀ 맑고 은은함: 흰색 → 하늘색 → 따뜻한 금색
  2. 🌤 부분적으로 흐림: 흰색 → 하늘색 → 은은한 호박색
  3. ☁ 흐림: 차가운 흰색 → 은색 → 밝은 회색
  4. 🌦 가랑비: 옅은 파랑 → 파랑 → 은은한 시안
  5. 🌧 비: 진한 파란색 → 시안색 → 짙은 네이비
  6. ⛈ 뇌우: 인디고 → 보라색 → 번개가 치는 검은색에 가까운 색
  7. 🌫 안개: 은은한 회색 → 파스텔 보라색 → 파스텔 민트색
  8. ❄ 눈: 밝은 흰색 → 얼음 같은 파란색 → 차가운 파란색
  9. 🌅 일출: 보라색 → 분홍색 → 주황색
  10. 🌇 일몰: 진한 보라색 → 마젠타 → 불타는 듯한 주황색
  11. 🌙 밤: 짙은 인디고 → 짙은 바이올렛 → 거의 검은색
  12. 🌈 무지개 모드: 무지개 효과

PrismCube는 색상이 순간적으로 바뀌는 대신, 각 색상 팔레트를 부드러운 전환 효과로 연속적으로 혼합하여 정적인 디스플레이가 아닌 생동감 넘치는 빛의 느낌을 선사합니다. 날씨가 바뀔 때마다 큐브는 새로운 분위기로 부드럽게 변하며, 모든 전환이 매끄럽고 자연스럽게 느껴집니다.

그 결과, 단순히 날씨를 표시하는 데 그치지 않고 빛을 통해 밖의 분위기를 조용히 담아내는 데스크톱 동반자가 탄생했습니다.




STEP 17. 마무리 말


PrismCube는 ‘날씨 정보를 화면에 표시하는 대신 빛을 통해 직접 체험할 수 있다면 어떨까?’라는 단순한 아이디어에서 시작되었습니다. 단순한 개념으로 시작된 이 프로젝트는 점차 산업 디자인, 임베디드 시스템, IoT, 그리고 세심하게 고안된 상호작용 기능을 하나로 결합한 완성도 높은 데스크톱용 기기로 발전했습니다.

이 프로젝트를 현실로 만들어가는 과정은 정말로 보람찬 경험이었습니다. Autodesk Fusion 360을 이용한 외장 설계부터 펌웨어 개발, 조명 효과와 사용자 경험의 세밀한 다듬기에 이르기까지, 모든 단계에서 새로운 도전과 귀중한 배움의 기회가 있었습니다. 이 프로젝트는 저의 비전과 디자인 철학을 반영하고 있지만, 개발 과정 전반에 걸쳐 훌륭한 팀의 지원과 협력이 없었다면 불가능했을 것입니다.

이 가이드가 여러분이 나만의 PrismCube를 제작하는 데 도움이 되고, 여러분만의 아이디어를 실험해 볼 수 있는 계기가 되기를 바랍니다. 색상 팔레트를 맞춤 설정하든, 새로운 날씨 모드를 만들든, 추가 기능으로 펌웨어를 확장하든, 여러분이 어떤 방향으로 발전시켜 나갈지 정말 기대됩니다.

이 여정을 함께해 주시고 지켜봐 주셔서 감사합니다. 직접 PrismCube를 제작하신다면, 댓글을 통해 결과물이나 개선 사항을 자유롭게 공유해 주세요. 여러분의 결과물은 향후 프로젝트 버전에 영감을 주고, 커뮤니티의 다른 메이커들에게도 도움이 될 것입니다.

즐거운 제작 되세요!


원문: https://www.instructables.com/PrismCube-a-Weather-Reactive-Ambient-Light-Cube/

좋아요 0
게시판

회사명 공방유니언 주소 각 공방 주소 참조
사업자 등록번호 0000 대표 공방유니언 전화 019-60105846 팩스 0000 이메일 gongbangunion@gmail.com
통신판매업신고번호 0000 개인정보관리책임자 공방유니언
Copyright © 2017 공방유니언. All Rights Reserved.