今回は、お家でキャンプ気分シリーズの、スピンオフ編です。
焚き火を眺めてすごす、キャンプでの優雅な時間を、屋内でも楽しみたい!ということで、背が高いフロアランプを、カラーLEDを使って改造して、焚き火台風にしてみます。
焚き火とサウンドレベルメーター
アウトドアを楽しめない週末が続くと、いろいろな思いがこみ上げてきます。
- 殺風景な部屋に、フロアランプが欲しい!
- キャンプに行けないのであれば、部屋で焚き火気分を楽しめないかな?
- 外出できないのであれば、しばらく封印していたDIYでもやってみようか...
こんな妄想たちを、一気に実現するには、焚き火風のフロアランプを自作するしかない!と確信しました。
テーマパークの仕掛けで見かける、本物の炎のような、フェイクな焚き火です。
ファンの風によって布をチラつかせて、さらに光も当てることで、本物の焚き火と錯覚してしまう、あれですね。
購入した方が安くすみそうな気がしますが、自作もできそうな気がします。
しかし、構造を考えていて、音について悩みが生じます。
くつろぎの時間を過ごしたいところで、ファンの音に耐えられるだろうか?と。
テーマパークのような、他の音が存在する場所なら気にならないと思いますが、プライベートな部屋ではファンの音は雑音でしかありません。
ファンを使わずに炎のような光を実現するには、小さな光源がたくさん必要になりそう...と考えていて、それならLEDで表現してみましょう!と、コンセプトがみえてきました。
LEDの直接光では、炎のように見せるのは難しいと思われるので、日本の伝統的なフロアライト、行燈の中にLEDたちを閉じ込めてしまいます。
行燈の中に焚き火があっても、いいじゃない!
行燈をサウンド レベル メーターに!
不規則に揺らぐ焚き火の光は、見ていて飽きませんよね〜
あの揺らぎを人為的に表現するには、乱数発生プログラムを使ってLEDを不規則に光らせることが近道だと思いました。
...でも、それだけだと不規則すぎて面白くない気もします。
相変わらずの捻くれ者ぶりを発揮してしまったので、一週間ほど悩んでみました。
時間をかければ閃くこともあるようで、ふと音楽に合わせて光らせてみたら面白いのでは?と思いつきます。
行燈の中で、炎と、音楽に合わせて光が踊っているフロアーランプ!
これは欲しい!と納得できるアイデアが浮かんだので、さっそく制作に取り掛かります。
IKEAで行燈選び
アウトドアには行けない日が続いているものの、家具屋さんのIKEAが家の近くにあり、毎週末のように通って、気分転換をしています。
そんなIKEAには、今回の行燈サウンド レベル メーターの改造ベースにピッタリのフロアランプがあることを知っています。
フードの材質が紙なので、光の指向性があるLEDとの相性もバッチリです。
いつもIKEAでは散歩スピードでショールームを楽しんでいますが、今回は売り場に直行して、フロアランプを入手してきました。
Arduinoと接続するモジュール
フロアランプを、行燈風サウンド レベル メーターとして光らせるために、個別に制御できるRGB LEDのWS2812Bをを使います。
「〇〇番目のLEDさんは、△△色に光ってください〜」
という情報さえ流せば、その通りに光るので、多くのLEDを個別に光り方を変えるのに便利なものです。
1mあたりにWS2812Bが60m個並べられているカラーLEDテープを3mと、サウンドセンサーモジュール、そして可変抵抗(ボリューム)3個を入手しました。
以前に、可変抵抗1個を使ってナイトライダー風サウンド レベル メーターを作ったことがありますが、今回はフロアランプでもあるので、
の3項目を可変抵抗で選択できるように進化させます。
表示イメージとパターン
もともとは、「焚火 in 行燈」コンセプトで始めたプロジェクトですが、純粋にサウンド レベル メーター風のパターンも含めて、合計7種類の光らせ方を準備します。
① 行燈なので、まずは白色で光らせます。
写真は紫色のように写っていますが、実際には白色です。
② サウンドレベルのバーが立ちます。色は炎のように、赤とオレンジのグラデーションです。
③ サウンドレベルのバーが立ちます。色は可変抵抗で選択した単色です。
④ サウンドレベルのバーが立ちます。色は徐々に変化します。
⑤ 焚き火風に光らせます。色は、「赤、オレンジ、白色」の3色です。
⑥ 焚き火風に光らせます。色は、「青、水色、白色」の3色です。
⑦ 焚き火風に光らせます。色は、「可変抵抗で選択した色、白色」の2色です。
⑧ 焚き火風に光らせます。色は、「徐々に変化する色、白色」の2色です。
回路図
Fritzingで回路図を作成しました。
マイクモジュールは、MAX4466を搭載したものを使っています。
3個の可変抵抗(ボリューム)は、
- R1;光量
- R2;表示7パターンの切り替え
- R3;色
の調節(選択)をするために使います。
Arduinoのアナログ入力には、それぞれの可変抵抗から電圧で情報が送られます。
- 電圧; 0〜5V
- Arduinoの読み取り値; 0〜1023(整数)
0〜1023をArduinoのスケッチ(プログラム)で選択肢に置き換えれば、LEDの発光を調節できます。
今回は180個が繋がっているものを使うWS2812Bは、先程も簡単に紹介しましたが、それぞれのLEDが個別に信号処理して、色や光量を認識して発光するので、信号線1本と電源の、合計3本の電線を繋ぐだけで、自在に光を制御できる優れものです。
スケッチは、記事の最後に掲載しておきますね。
炎が踊るフロアーランプ
LEDの配置
LEDを、ランプ中心部の柱にどう配置するか?について、少し試行錯誤しました。
結論から言うと、縦に配置した方が、LEDの貼り付け作業も、炎やサウンドレベルメーターのスケッチ(プログラム)の作成も楽です。
私は4列で配置することにしました。
180個のWS2812Bテープなので、
「45行x4列 」
になる筈ですが、試行錯誤の段階でちょっとした事故があり、数セルが使えなくなってしまったので、やむなく43x 4の配置になりました。
ウエルカム点灯
電源投入時の動作は、3種類を仕込んでおきます。
- ランダム点滅(白色)
- 白色光を上下に一回走らせる
- レインボー色の光を上下に一回走らせる
静止画だと、どれだけ綺麗に光っているか?が伝わらないですが、光り方はメイキング動画でも、ご確認いただけます。
youtu.be
スケッチ(プログラム)
スケッチは、色々なパターンの光らせ方が準備されている、GitHubのFastLEDライブラリをベースにさせていただきます。
炎(fire)パターンは、派生バージョンも含めていくつか紹介されており、Fire2012WithPaletteの、炎を作成する部分のスケッチを使用させていただき、4列の炎専用に少し手を加えました。
もっと短いスケッチにできると思いますが、メモリー容量に余裕があるので良い!ということにして、同じ命令文が何度もでてきます。
#include "FastLED.h"
#define DATA_PIN 5
#define LED_TYPE WS2812
#define COLOR_ORDER GRB
#define HEIGHT 43
#define WIDTH 4
#define NUM_LEDS HEIGHT*WIDTH
#define MAX_BRIGHTNESS 90
#define MIN_BRIGHTNESS 5
#define lighting_PER_SECOND 30
CRGB leds[NUM_LEDS];
CRGBPalette16 gPal;
const int sampleWindow = 50;
unsigned int sample;
int SoundCenterAdjust = 0;
int SoundLevelAdjust = 6;
int BRIGHTNESS = 50;
int scaleVol = 230;
int SPARKING = 130;
int COOLING = 70;
int colorSelect;
int micPin = 2;
int blightPin = 3;
int selectPin = 4;
int colorPin = 5;
int val = 0;
int numLedsToLight = 0;
long numLedsToLightCal = 0;
bool welcomeLight = true;
bool gReverseDirection = false;
void setup() {
delay(3000);
FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
FastLED.setBrightness(BRIGHTNESS);
}
typedef void (*SimplePatternList[])();
SimplePatternList gPatterns = { allwhite, soundBarFire, soundBarSelect, soundBarRotate, fireRed, fireBlue, fireSelect, fireRotate};
uint8_t gCurrentPatternNumber = 0;
uint8_t gHue = 96;
void loop()
{
if (analogRead(blightPin) < 50) {
BRIGHTNESS = 0 ;
} else {
BRIGHTNESS = map(analogRead(blightPin), 50, 1024, MIN_BRIGHTNESS, MAX_BRIGHTNESS) ;
}
FastLED.setBrightness(BRIGHTNESS);
if (analogRead(colorPin) < 50) {
colorSelect = 0 ;
} else if (analogRead(colorPin) < 950) {
colorSelect = map(analogRead(colorPin), 50, 949, 0, 255) ;
} else {
colorSelect = 255;
}
val = analogRead(selectPin);
if (val < 130) {
gCurrentPatternNumber = 0;
} else if (val < 260){
gCurrentPatternNumber = 1;
} else if (val < 390){
gCurrentPatternNumber = 2;
} else if (val < 520){
gCurrentPatternNumber = 3;
} else if (val < 650){
gCurrentPatternNumber = 4;
} else if (val < 780){
gCurrentPatternNumber = 5;
} else if (val < 910){
gCurrentPatternNumber = 6;
} else {
gCurrentPatternNumber = 7;
}
gPatterns[gCurrentPatternNumber]();
if (welcomeLight == true) {
for(int led = 0; led < 150; led++) {
fadeToBlackBy( leds, NUM_LEDS, 100);
int pos = random16(NUM_LEDS);
leds[pos] += CRGB::White;
FastLED.show();
delay (100-led/2);
}
for(int led = 0; led < HEIGHT; led++) {
fadeToBlackBy( leds, NUM_LEDS, 100);
leds[led] += CRGB::White ;
leds[HEIGHT*2-1-led] += CRGB::White ;
leds[HEIGHT*2+led] += CRGB::White ;
leds[HEIGHT*4-1-led] += CRGB::White ;
FastLED.show();
delay (80);
}
for(int led = 0; led < HEIGHT; led++) {
fadeToBlackBy( leds, NUM_LEDS, 100);
leds[HEIGHT-1-led] += CRGB::White ;
leds[HEIGHT+led] += CRGB::White ;
leds[HEIGHT*3-1-led] += CRGB::White ;
leds[HEIGHT*3+led] += CRGB::White ;
FastLED.show();
delay (80);
}
for(int led = 0; led < HEIGHT; led++) {
fadeToBlackBy( leds, NUM_LEDS, 100);
leds[led] = CHSV(255*led/HEIGHT, 255, 255) ;
leds[HEIGHT*2-1-led] = CHSV(255*led/HEIGHT, 255, 255) ;
leds[HEIGHT*2+led] = CHSV(255*led/HEIGHT, 255, 255) ;
leds[HEIGHT*4-1-led] = CHSV(255*led/HEIGHT, 255, 255) ;
FastLED.show();
delay (80);
}
for(int led = 0; led < HEIGHT; led++) {
fadeToBlackBy( leds, NUM_LEDS, 100);
leds[HEIGHT-1-led] = CHSV(255*led/HEIGHT, 255, 255) ;
leds[HEIGHT+led] = CHSV(255*led/HEIGHT, 255, 255) ;
leds[HEIGHT*3-1-led] = CHSV(255*led/HEIGHT, 255, 255) ;
leds[HEIGHT*3+led] = CHSV(255*led/HEIGHT, 255, 255) ;
FastLED.show();
delay (80);
}
welcomeLight = false;
}else{
random16_add_entropy( random());
gPatterns[gCurrentPatternNumber]();
FastLED.show();
FastLED.delay(1000 / lighting_PER_SECOND);
EVERY_N_MILLISECONDS( 300 ) { gHue++; }
}
}
void fireRed()
{
gPal = CRGBPalette16( CRGB::Black, CRGB::Red, CRGB::Yellow, CRGB::White);
static uint8_t heat[NUM_LEDS];
for( int i = 0; i < NUM_LEDS; i++) {
heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / HEIGHT) + 2));
}
for( int k= HEIGHT - 1; k >= 2; k--) {
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
heat[2*HEIGHT-1-k] = (heat[2*HEIGHT-1-k + 1] + heat[2*HEIGHT-1-k + 2] + heat[2*HEIGHT-1-k + 2] ) / 3;
heat[2*HEIGHT+k] = (heat[2*HEIGHT+k - 1] + heat[2*HEIGHT+k - 2] + heat[2*HEIGHT+k - 2] ) / 3;
heat[4*HEIGHT-1-k] = (heat[4*HEIGHT-1-k + 1] + heat[4*HEIGHT-1-k + 2] + heat[4*HEIGHT-1-k + 2] ) / 3;
}
if( random8() < SPARKING ) {
int x = random8(19);
int y ;
if(x > 14){
y = 4*HEIGHT+14-x;
} else if(x > 9){
y = 2*HEIGHT-10+x;
} else if(x > 4){
y = 2*HEIGHT+4-x;
} else {
y = x;
}
heat[y] = qadd8( heat[y], random8(160,255) );
}
for( int j = 0; j < NUM_LEDS; j++) {
uint8_t colorindex = scale8( heat[j], scaleVol);
CRGB color = ColorFromPalette( gPal, colorindex);
int pixelnumber;
if( gReverseDirection ) {
if(j < HEIGHT){
pixelnumber = (HEIGHT-1) - j;
}else if(j < 2*HEIGHT){
pixelnumber = HEIGHT+j;
}else if(j < 3*HEIGHT){
pixelnumber = (3*HEIGHT-1) - j;
}else{
pixelnumber = 3*HEIGHT+j;
}
} else {
pixelnumber = j;
}
leds[pixelnumber] = color;
}
}
void fireRotate()
{
gPal = CRGBPalette16( CRGB::Black, CHSV( gHue, 255, 192), CRGB::White);
static uint8_t heat[NUM_LEDS];
for( int i = 0; i < NUM_LEDS; i++) {
heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / HEIGHT) + 2));
}
for( int k= HEIGHT - 1; k >= 2; k--) {
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
heat[2*HEIGHT-1-k] = (heat[2*HEIGHT-1-k + 1] + heat[2*HEIGHT-1-k + 2] + heat[2*HEIGHT-1-k + 2] ) / 3;
heat[2*HEIGHT+k] = (heat[2*HEIGHT+k - 1] + heat[2*HEIGHT+k - 2] + heat[2*HEIGHT+k - 2] ) / 3;
heat[4*HEIGHT-1-k] = (heat[4*HEIGHT-1-k + 1] + heat[4*HEIGHT-1-k + 2] + heat[4*HEIGHT-1-k + 2] ) / 3;
}
if( random8() < SPARKING ) {
int x = random8(19);
int y ;
if(x > 14){
y = 4*HEIGHT+14-x;
} else if(x > 9){
y = 2*HEIGHT-10+x;
} else if(x > 4){
y = 2*HEIGHT+4-x;
} else {
y = x;
}
heat[y] = qadd8( heat[y], random8(160,255) );
}
for( int j = 0; j < NUM_LEDS; j++) {
uint8_t colorindex = scale8( heat[j], scaleVol);
CRGB color = ColorFromPalette( gPal, colorindex);
int pixelnumber;
if( gReverseDirection ) {
if(j < HEIGHT){
pixelnumber = (HEIGHT-1) - j;
}else if(j < 2*HEIGHT){
pixelnumber = HEIGHT+j;
}else if(j < 3*HEIGHT){
pixelnumber = (3*HEIGHT-1) - j;
}else{
pixelnumber = 3*HEIGHT+j;
}
} else {
pixelnumber = j;
}
leds[pixelnumber] = color;
}
}
void fireBlue()
{
gPal = CRGBPalette16( CRGB::Black, CRGB::Blue, CRGB::Aqua, CRGB::White);
static uint8_t heat[NUM_LEDS];
for( int i = 0; i < NUM_LEDS; i++) {
heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / HEIGHT) + 2));
}
for( int k= HEIGHT - 1; k >= 2; k--) {
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
heat[2*HEIGHT-1-k] = (heat[2*HEIGHT-1-k + 1] + heat[2*HEIGHT-1-k + 2] + heat[2*HEIGHT-1-k + 2] ) / 3;
heat[2*HEIGHT+k] = (heat[2*HEIGHT+k - 1] + heat[2*HEIGHT+k - 2] + heat[2*HEIGHT+k - 2] ) / 3;
heat[4*HEIGHT-1-k] = (heat[4*HEIGHT-1-k + 1] + heat[4*HEIGHT-1-k + 2] + heat[4*HEIGHT-1-k + 2] ) / 3;
}
if( random8() < SPARKING ) {
int x = random8(19);
int y ;
if(x > 14){
y = 4*HEIGHT+14-x;
} else if(x > 9){
y = 2*HEIGHT-10+x;
} else if(x > 4){
y = 2*HEIGHT+4-x;
} else {
y = x;
}
heat[y] = qadd8( heat[y], random8(160,255) );
}
for( int j = 0; j < NUM_LEDS; j++) {
uint8_t colorindex = scale8( heat[j], scaleVol);
CRGB color = ColorFromPalette( gPal, colorindex);
int pixelnumber;
if( gReverseDirection ) {
if(j < HEIGHT){
pixelnumber = (HEIGHT-1) - j;
}else if(j < 2*HEIGHT){
pixelnumber = HEIGHT+j;
}else if(j < 3*HEIGHT){
pixelnumber = (3*HEIGHT-1) - j;
}else{
pixelnumber = 3*HEIGHT+j;
}
} else {
pixelnumber = j;
}
leds[pixelnumber] = color;
}
}
void fireSelect()
{
gPal = CRGBPalette16( CRGB::Black, CHSV( colorSelect, 255, 192), CRGB::White);
static uint8_t heat[NUM_LEDS];
for( int i = 0; i < NUM_LEDS; i++) {
heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / HEIGHT) + 2));
}
for( int k= HEIGHT - 1; k >= 2; k--) {
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
heat[2*HEIGHT-1-k] = (heat[2*HEIGHT-1-k + 1] + heat[2*HEIGHT-1-k + 2] + heat[2*HEIGHT-1-k + 2] ) / 3;
heat[2*HEIGHT+k] = (heat[2*HEIGHT+k - 1] + heat[2*HEIGHT+k - 2] + heat[2*HEIGHT+k - 2] ) / 3;
heat[4*HEIGHT-1-k] = (heat[4*HEIGHT-1-k + 1] + heat[4*HEIGHT-1-k + 2] + heat[4*HEIGHT-1-k + 2] ) / 3;
}
if( random8() < SPARKING ) {
int x = random8(19);
int y ;
if(x > 14){
y = 4*HEIGHT+14-x;
} else if(x > 9){
y = 2*HEIGHT-10+x;
} else if(x > 4){
y = 2*HEIGHT+4-x;
} else {
y = x;
}
heat[y] = qadd8( heat[y], random8(160,255) );
}
for( int j = 0; j < NUM_LEDS; j++) {
uint8_t colorindex = scale8( heat[j], scaleVol);
CRGB color = ColorFromPalette( gPal, colorindex);
int pixelnumber;
if( gReverseDirection ) {
if(j < HEIGHT){
pixelnumber = (HEIGHT-1) - j;
}else if(j < 2*HEIGHT){
pixelnumber = HEIGHT+j;
}else if(j < 3*HEIGHT){
pixelnumber = (3*HEIGHT-1) - j;
}else{
pixelnumber = 3*HEIGHT+j;
}
} else {
pixelnumber = j;
}
leds[pixelnumber] = color;
}
}
void soundBarFire()
{
unsigned long startMillis= millis();
unsigned int peakToPeak = 0;
unsigned int signalMax = 0;
unsigned int signalMin = 1024;
while (millis() - startMillis < sampleWindow)
{
sample = analogRead(micPin);
if (sample < 1024)
{
if (sample > signalMax)
{
signalMax = sample;
}
else if (sample < signalMin)
{
signalMin = sample;
}
}
}
peakToPeak = signalMax - signalMin ;
numLedsToLightCal = ((peakToPeak-SoundCenterAdjust)*HEIGHT*SoundLevelAdjust)/1024 ;
if(numLedsToLightCal >= HEIGHT){
numLedsToLight = HEIGHT;
}else {
numLedsToLight = numLedsToLightCal;
}
fadeToBlackBy( leds, NUM_LEDS, 200);
for(int led = 0; led < numLedsToLight; led++) {
leds[led] += CHSV( 2*(numLedsToLight-1-led), 255, 192);
}
for(int led = HEIGHT*2-numLedsToLight; led < HEIGHT*2; led++) {
leds[led] += CHSV( 2*(led-(HEIGHT*2-numLedsToLight)), 255, 192);
}
for(int led = HEIGHT*2; led < HEIGHT*2+numLedsToLight; led++) {
leds[led] += CHSV( 2*(HEIGHT*2+numLedsToLight-1-led), 255, 192);
}
for(int led = HEIGHT*4-numLedsToLight; led < HEIGHT*4; led++) {
leds[led] += CHSV( 2*(led-(HEIGHT*4-numLedsToLight)), 255, 192);
}
}
void soundBarSelect()
{
unsigned long startMillis= millis();
unsigned int peakToPeak = 0;
unsigned int signalMax = 0;
unsigned int signalMin = 1024;
while (millis() - startMillis < sampleWindow)
{
sample = analogRead(micPin);
if (sample < 1024)
{
if (sample > signalMax)
{
signalMax = sample;
}
else if (sample < signalMin)
{
signalMin = sample;
}
}
}
peakToPeak = signalMax - signalMin ;
numLedsToLightCal = ((peakToPeak-SoundCenterAdjust)*HEIGHT*SoundLevelAdjust)/1024 ;
if(numLedsToLightCal >= HEIGHT){
numLedsToLight = HEIGHT;
}else {
numLedsToLight = numLedsToLightCal;
}
fadeToBlackBy( leds, NUM_LEDS, 200);
for(int led = 0; led < numLedsToLight; led++) {
leds[led] += CHSV( colorSelect, 255, 192);
}
for(int led = HEIGHT*2-numLedsToLight; led < HEIGHT*2; led++) {
leds[led] += CHSV( colorSelect, 255, 192);
}
for(int led = HEIGHT*2; led < HEIGHT*2+numLedsToLight; led++) {
leds[led] += CHSV( colorSelect, 255, 192);
}
for(int led = HEIGHT*4-numLedsToLight; led < HEIGHT*4; led++) {
leds[led] += CHSV( colorSelect, 255, 192);
}
}
void soundBarRotate()
{
unsigned long startMillis= millis();
unsigned int peakToPeak = 0;
unsigned int signalMax = 0;
unsigned int signalMin = 1024;
while (millis() - startMillis < sampleWindow)
{
sample = analogRead(micPin);
if (sample < 1024)
{
if (sample > signalMax)
{
signalMax = sample;
}
else if (sample < signalMin)
{
signalMin = sample;
}
}
}
peakToPeak = signalMax - signalMin ;
numLedsToLightCal = ((peakToPeak-SoundCenterAdjust)*HEIGHT*SoundLevelAdjust)/1024 ;
if(numLedsToLightCal >= HEIGHT){
numLedsToLight = HEIGHT;
}else {
numLedsToLight = numLedsToLightCal;
}
fadeToBlackBy( leds, NUM_LEDS, 200);
for(int led = 0; led < numLedsToLight; led++) {
leds[led] += CHSV( gHue, 255, 192);
}
for(int led = HEIGHT*2-numLedsToLight; led < HEIGHT*2; led++) {
leds[led] += CHSV( gHue, 255, 192);
}
for(int led = HEIGHT*2; led < HEIGHT*2+numLedsToLight; led++) {
leds[led] += CHSV( gHue, 255, 192);
}
for(int led = HEIGHT*4-numLedsToLight; led < HEIGHT*4; led++) {
leds[led] += CHSV( gHue, 255, 192);
}
}
void allwhite()
{
fill_solid(leds, NUM_LEDS, CRGB::White);
}
今回は、フロアランプに焚火を仕込みましょう!というコンセプトで、お家ですごす時間を楽しくしてみました。
毎週末を使って、製作期間は一か月ほどかかりましたが、初めて見る人には「フロアランプが燃えている!」と思わせそうな完成度で、満足しています。
室内で焚火はできないアパート暮らしですが、お部屋に焚き火風の光があると、本当にキャンプしているような気分になって、うっとりと見入っています。