From 9972cb5bea14ce0be0227487a53ecf6aa52b1e8c Mon Sep 17 00:00:00 2001 From: Finn Christiansen Date: Mon, 9 Jun 2025 21:42:35 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=89=20First=20WIP-prototype=20of=20ESP?= =?UTF-8?q?32=20based=20nightlight?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 6 ++ CMakeLists.txt | 6 ++ dependencies.lock | 21 +++++++ main/CMakeLists.txt | 2 + main/idf_component.yml | 17 ++++++ main/nightlight.c | 136 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 188 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 dependencies.lock create mode 100644 main/CMakeLists.txt create mode 100644 main/idf_component.yml create mode 100644 main/nightlight.c diff --git a/.gitignore b/.gitignore index ead248a..8e61225 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,9 @@ build/ sdkconfig sdkconfig.old +# added +managed_components/ +dependencies.lock + +# customn +tags diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b3dc25c --- /dev/null +++ b/CMakeLists.txt @@ -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) diff --git a/dependencies.lock b/dependencies.lock new file mode 100644 index 0000000..2809c39 --- /dev/null +++ b/dependencies.lock @@ -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 diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt new file mode 100644 index 0000000..b472ea7 --- /dev/null +++ b/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "nightlight.c" + INCLUDE_DIRS ".") diff --git a/main/idf_component.yml b/main/idf_component.yml new file mode 100644 index 0000000..520288e --- /dev/null +++ b/main/idf_component.yml @@ -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 diff --git a/main/nightlight.c b/main/nightlight.c new file mode 100644 index 0000000..9d9ba39 --- /dev/null +++ b/main/nightlight.c @@ -0,0 +1,136 @@ +#include +#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 +}