🎉 First WIP-prototype of ESP32 based nightlight

This commit is contained in:
Finn Christiansen 2025-06-09 21:42:35 +02:00
parent 43bbdcc34f
commit 9972cb5bea
6 changed files with 188 additions and 0 deletions

6
.gitignore vendored
View file

@ -6,3 +6,9 @@ build/
sdkconfig
sdkconfig.old
# added
managed_components/
dependencies.lock
# customn
tags

6
CMakeLists.txt Normal file
View file

@ -0,0 +1,6 @@
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(nightlight)

21
dependencies.lock Normal file
View file

@ -0,0 +1,21 @@
dependencies:
espressif/led_strip:
component_hash: b578eb926d9f6402fd45398b53c9bd5d1b7a15c1b2974d25aa3088e6c79b0b4c
dependencies:
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
version: 3.0.1
idf:
source:
type: idf
version: 5.4.1
direct_dependencies:
- espressif/led_strip
- idf
manifest_hash: a51dc977be7137e0c5d12a067d1d573535d49f17e9bfa487be8f8b97cf684d41
target: esp32c3
version: 2.0.0

2
main/CMakeLists.txt Normal file
View file

@ -0,0 +1,2 @@
idf_component_register(SRCS "nightlight.c"
INCLUDE_DIRS ".")

17
main/idf_component.yml Normal file
View file

@ -0,0 +1,17 @@
## IDF Component Manager Manifest File
dependencies:
## Required IDF version
idf:
version: '>=4.1.0'
# # Put list of dependencies here
# # For components maintained by Espressif:
# component: "~1.0.0"
# # For 3rd party components:
# username/component: ">=1.0.0,<2.0.0"
# username2/component2:
# version: "~1.0.0"
# # For transient dependencies `public` flag can be set.
# # `public` flag doesn't have an effect dependencies of the `main` component.
# # All dependencies of `main` are public by default.
# public: true
espressif/led_strip: ^3.0.1

136
main/nightlight.c Normal file
View file

@ -0,0 +1,136 @@
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "led_strip.h"
#define LED_STRIP_PIN 2 // WS281x
#define PIR_PIN 3 // AM312 or other 3,7V compatible PIR sensors
#define LIGHT_SENSOR_PIN 4 // Digitale light sensor
#define NUM_LEDS 15 // Number of LEDs on LED strip
#define TIMEOUT_MS 10000 // Inactivity timeout (10 seconds)
static const char *TAG = "NIGHTLIGHT";
led_strip_handle_t strip;
TimerHandle_t off_timer;
TaskHandle_t led_task_handle = NULL;
// Turn off all LEDs
void turn_off_leds()
{
for (int i = 0; i < NUM_LEDS; i++) {
led_strip_set_pixel(strip, i, 0, 0, 0);
led_strip_refresh(strip);
vTaskDelay(pdMS_TO_TICKS(100));
}
ESP_LOGI(TAG, "LEDs turned OFF");
}
// Turn on LEDs
void turn_on_leds()
{
for (int i = 0; i < NUM_LEDS; i++) {
led_strip_set_pixel(strip, i, 255, 7, 0); // red
led_strip_refresh(strip);
vTaskDelay(pdMS_TO_TICKS(100));
}
ESP_LOGI(TAG, "LEDs turned ON");
}
// Timer callback: turns off LED if no motion is detected
void off_timer_callback(TimerHandle_t xTimer)
{
if (gpio_get_level(PIR_PIN) == 1) {
ESP_LOGI(TAG, "Motion still detected. Resetting off timer.");
xTimerReset(off_timer, 0);
} else {
// No motion detected, it's safe to turn off LEDs
turn_off_leds();
}
}
// PIR interrupt handler notifies LED task handler
void IRAM_ATTR pir_isr_handler(void *arg)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(led_task_handle, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
// LED task
void led_task(void *arg)
{
while (1) {
// wait for motion
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
ESP_LOGI(TAG, "Motion detected!");
// Reset off timer and turn on LEDs
xTimerReset(off_timer, 0);
// TODO: check light sensor GPIO value
turn_on_leds();
}
}
void app_main(void)
{
ESP_LOGI(TAG, "Nightlight initializing...");
// Initialize LED strip
led_strip_config_t strip_config = {
.strip_gpio_num = LED_STRIP_PIN,
.max_leds = NUM_LEDS,
.flags.invert_out = false,
};
led_strip_rmt_config_t rmt_config = {
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = 10 * 1000 * 1000, // 10MHz
.mem_block_symbols = 64,
.flags.with_dma = false,
};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &strip));
ESP_ERROR_CHECK(led_strip_clear(strip));
ESP_LOGI(TAG, "LED strip initialized");
// Configure PIR sensor GPIO
gpio_config_t pir_conf = {
.intr_type = GPIO_INTR_POSEDGE,
.mode = GPIO_MODE_INPUT,
.pull_down_en = GPIO_PULLDOWN_ENABLE,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pin_bit_mask = (1ULL << PIR_PIN)
};
ESP_ERROR_CHECK(gpio_config(&pir_conf));
ESP_LOGI(TAG, "GPIO config for PIR sensor initialized");
// Configure light sensor GPIO
gpio_config_t light_conf = {
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.pin_bit_mask = (1ULL << LIGHT_SENSOR_PIN)
};
ESP_ERROR_CHECK(gpio_config(&light_conf));
ESP_LOGI(TAG, "GPIO config for light sensor initialized");
ESP_ERROR_CHECK(gpio_install_isr_service(0));
ESP_ERROR_CHECK(gpio_isr_handler_add(PIR_PIN, pir_isr_handler, NULL));
// Timer setup
off_timer = xTimerCreate("off_timer", pdMS_TO_TICKS(TIMEOUT_MS), pdFALSE, NULL, off_timer_callback);
// LED task setup
xTaskCreate(led_task, "led_task", 2048, NULL, 10, &led_task_handle);
ESP_LOGI(TAG, "System initialized.");
vTaskSuspend(NULL); // Suspend main task
}