Hi Bill, I hope your mom is doing better and that it probably takes a lot of your time. So I know I had asked about this before and got a couple suggestions from you and other members. I wasn't able to express what I wanted to create adequately thus the responses I got were things I had already tried. Sooo..., I got an Open AI account and started to use chat GPT, a whole other lesson in communication. After much frustration and feeling like I just became 'Costello' in "Who's on First?" many times. I finally managed to get it to understand what I wanted and, with much trial and error it came up with this Python sim that does almost what I want. Near enough to call it success for now.
import matplotlib print("Using backend:", matplotlib.get_backend()) import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation # Constants NUM_ROWS, NUM_COLS = 16, 32 CENTER_ROW, CENTER_COL = NUM_ROWS // 2, NUM_COLS // 2 TOTAL_BRIGHTNESS = 10000 # Total desired brightness at peak MIN_BRIGHTNESS = 5 # Minimal brightness to show at the night phase # Initialize the LED matrix led_matrix = np.zeros((NUM_ROWS, NUM_COLS)) def calculate_brightness(frame, total_brightness): """Calculate the brightness distribution based on the frame number.""" time_of_day = frame % 1440 # Modulo 1440 to simulate a 24-hour cycle # Adjust these times to match your desired timings if time_of_day < 420 or time_of_day >= 1290: # Extended night phase current_brightness = MIN_BRIGHTNESS # Keep minimal brightness elif time_of_day < 720: # Sunrise from 0700 to 1200 current_brightness = (time_of_day - 420) / 300 * total_brightness # Gradual increase elif 720 <= time_of_day < 990: # Daylight from 1200 to 2130 current_brightness = total_brightness else: # Sunset from 2130 to 2150 current_brightness = (1290 - time_of_day) / 300 * total_brightness # Gradual decrease # Adjust the matrix values for row in range(NUM_ROWS): for col in range(NUM_COLS): distance = np.sqrt((CENTER_ROW - row) ** 2 + (CENTER_COL - col) ** 2) led_matrix[row, col] = current_brightness / (1 + distance) # Inverse distance weighting return led_matrix # Visualization setup fig, ax = plt.subplots() img = ax.imshow(led_matrix, cmap='hot', interpolation='nearest', vmin=0, vmax=255) time_text = ax.text(0.02, 0.95, '', transform=ax.transAxes, color='white') def update(frame): """Update function for the animation.""" brightness_matrix = calculate_brightness(frame, TOTAL_BRIGHTNESS) img.set_data(brightness_matrix) # Update the time display hours = (frame // 60) % 24 minutes = frame % 60 time_text.set_text(f'Time: {hours:02}:{minutes:02}') return img, time_text, # Create the animation ani = animation.FuncAnimation(fig, update, frames=1440, interval=100, blit=True, repeat=True) plt.show()
After using the LLM to do some analysis I decided to use an ESP32 WROVER E as the controller, I have DS3231RTC, on oled for display of time so I have a visual if the board hangs. The main code relies on 2 custom Libraries. One for the SSID info called connections, that I won't post as I got the idea from you. The second library I had Chat GPT write to allow for custom arrays. Mine uses 2 8x32 WS2812B rotated 180 in relation to ea other. The code allows for custom mapping of arrays and does the calcs.
#ifndef CUSTOM_MATRIX_H #define CUSTOM_MATRIX_H #include <FastLED.h> #define NUM_LEDS_PER_MATRIX 256 // Adjust according to your setup #define COLOR_ORDER GRB // GRB color order for WS2812B #define BRIGHTNESS 255 struct MatrixConfig { uint16_t pin; uint16_t numLEDs; bool rotate180; // Indicate if the matrix is rotated }; // Define matrix configurations const MatrixConfig matrixConfigs[] = { {5, NUM_LEDS_PER_MATRIX, false}, // First matrix, pin 5, no rotation {4, NUM_LEDS_PER_MATRIX, true} // Second matrix, pin 4, rotated }; CRGB leds_1[NUM_LEDS_PER_MATRIX]; CRGB leds_2[NUM_LEDS_PER_MATRIX]; void setupLEDs() { FastLED.addLeds<WS2812B, matrixConfigs[0].pin, COLOR_ORDER>(leds_1, matrixConfigs[0].numLEDs).setCorrection(TypicalLEDStrip); FastLED.addLeds<WS2812B, matrixConfigs[1].pin, COLOR_ORDER>(leds_2, matrixConfigs[1].numLEDs).setCorrection(TypicalLEDStrip); FastLED.setBrightness(BRIGHTNESS); } void updateLightingPattern(void * parameter) { for (;;) { // Implement lighting pattern updates here FastLED.show(); vTaskDelay(10 / portTICK_PERIOD_MS); } } #endif // CUSTOM_MATRIX_H
And this brings us to the main body of code. Doing this exercise has shown me what I was failing to communicate the first time. My thought was this, I have an array of, in this case, 512 individually addressable LEDS. Each of these LED can be controlled, in real use without burnout, in 195 cubed possible light/luminosity combinations TIMES 512 leds. This leads to a much richer possible combination of luminosity and palette. Unfortunately, that level of calculus is FAR FAR beyond my abilities.... And it seems my ability to communicate with Chat GPT, the more subtle effects I was looking for. I can't get a "blue" phase to represent the time when the blue waves are being scattered before and after sunrise/set without way too many LEDs lighting in the sim. Maybe you could fix it but I know my limits. I found that if I tried for any type of combination of cycles ended up with a dead period so this is one long cycle. It has a "test" loop that uses a boolean user variable to run off RTC or a 12 min "Sim" day. It uses both cores. based on these criteria I asked Chat GPT summarize
Sure, let’s review and confirm the features and functionalities that the code should include, based on our extensive discussion:
-
Dual-Core Operation:
- One core manages the OLED display and RTC to display the current time.
- The other core handles LED control for two matrices, ensuring independent and simultaneous operation.
-
LED Control:
- Two LED arrays, controlled by separate pins (Pin 5 and Pin 4).
- Custom LED mapping managed through a
CustomMatrix.h
library, allowing for future configurations of additional arrays with different setups. - Simulation of a 24-hour light cycle, with specified timings for sunrise, full daylight, sunset, and night.
- The ability to test the lighting pattern with a sped-up cycle (12-minute cycle simulating 24 hours).
-
Timekeeping:
- Use of an RTC (Real-Time Clock) for accurate time management.
- NTP (Network Time Protocol) integration for initial time setting or correction if the RTC has lost power or drifted.
- Automatic adjustment of the RTC if the time drifts by 5 seconds or more, either on board reset or after 100 cycles.
-
WiFi Connectivity:
- Connection to a WiFi network using credentials stored in the
connections.h
library. - This functionality is critical for NTP time synchronization.
- Connection to a WiFi network using credentials stored in the
-
OLED Display:
- Display of the current time for visual verification of system functionality.
- Useful for checking if the board is functioning correctly without needing to connect to a serial monitor.
-
User Variables and Configurability:
- Top of the code will include user-defined variables for easy configuration (e.g., LED brightness, test cycle duration).
- Comments explaining each variable’s purpose and impact on the system, ensuring clarity for future adjustments or expansions.
-
Libraries and Modular Code:
CustomMatrix.h
for custom LED matrix configuration, supporting different array orientations and connections.connections.h
for WiFi credentials, keeping sensitive information separate from the main program logic.
-
System Robustness and Debugging:
- Serial outputs for debugging and system status updates, especially during WiFi connection attempts and system initialization.
- Error handling for RTC failures and WiFi connectivity issues, preventing system hang-ups.
#include <Arduino.h> #include <FastLED.h> #include "CustomMatrix.h" #include "RTClib.h" #include <U8g2lib.h> #include <WiFi.h> #include "connections.h" // Definitions for LED pinouts and types #define LED_PIN_1 5 #define LED_PIN_2 4 #define COLOR_ORDER GRB #define CHIPSET WS2812B #define BRIGHTNESS 255 // Total number of LEDs per matrix const int totalLEDs = NUM_LEDS_PER_MATRIX; // Create LED arrays CRGB leds_1[totalLEDs]; CRGB leds_2[totalLEDs]; // OLED and RTC setup U8G2_SSD1306_128X64_NONAME_F_HW_I2C oled(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); RTC_DS3231 rtc; // Function prototypes void setupLEDs(); void displayTime(); void updateLightingPattern(); void connectToWiFi(); void setup() { Serial.begin(115200); connectToWiFi(); // Connect to WiFi network setupLEDs(); oled.begin(); oled.setFont(u8g2_font_ncenB08_tr); // RTC setup if (!rtc.begin()) { Serial.println("Couldn't find RTC"); while (1); } if (rtc.lostPower()) { Serial.println("RTC lost power, let's set the time!"); rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); } // Setup tasks on different cores xTaskCreatePinnedToCore( updateLightingPattern, /* Task function */ "updateLEDs", /* Name of the task */ 10000, /* Stack size in words */ NULL, /* Task input parameter */ 1, /* Priority of the task */ NULL, /* Task handle */ 0); /* Core where the task should run */ } void loop() { displayTime(); // Update the OLED with current time delay(1000); // Update every second } void setupLEDs() { FastLED.addLeds<CHIPSET, LED_PIN_1, COLOR_ORDER>(leds_1, totalLEDs).setCorrection(TypicalLEDStrip); FastLED.addLeds<CHIPSET, LED_PIN_2, COLOR_ORDER>(leds_2, totalLEDs).setCorrection(TypicalLEDStrip); FastLED.setBrightness(BRIGHTNESS); } void displayTime() { DateTime now = rtc.now(); oled.clearBuffer(); oled.setCursor(0, 10); oled.print("Time: "); oled.print(now.hour(), DEC); oled.print(':'); oled.print(now.minute(), DEC); oled.print(':'); oled.print(now.second(), DEC); oled.sendBuffer(); } void connectToWiFi() { WiFi.begin(WIFI_SSID, WIFI_PASSWORD); Serial.print("Connecting to WiFi.."); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nConnected to the WiFi network"); } void updateLightingPattern(void * parameter) { for (;;) { // Update your LED pattern here FastLED.show(); vTaskDelay(10 / portTICK_PERIOD_MS); // Update every 10 ms } }
Mine has 2 arrays, pins 4 and 5, I used wire wrapping on the board in the attached pics. I used a $20 toolbox to mount the 5V 80A power supply in, A generic dollar store picture frame to mount the array and a couple terminal strips to make it somewhat "modular" for placement and hook up. I am gong to add a version of code that will allow for this to be used as a main controller with peripherals running their own custom matrix and the sequence the second core runs. It may need tweaks as I got Chat GPT to make this an integrated package.
I hope this gives you a video, I can't do much in the way of financial support at the moment, this is justified as a "Business Expense" for "Livestock" so... while I put in the work I don't get to see it except in my store making the frogs happy. It's yours free of any encumbrance, but an honorable mention would be nice LOL.
The reason I went with using both cores is that I want to add future basic vivarium controls to this such as automated top up off the water reservoir, maybe a temp controlled vent fan, the setup means those can be added to the core controlling time and display etc and leave the second to handle the light cycle.
FMG, I can't seem to proof read, The first sentence should have an ..I know...inserted...
OK I must have had a dream where this complied correctly... Working on it.
Ok I have had one of the most "disturbing" things happen. I gave myself a false memory obviously. I have a VERY vivid memory of getting this to work JUST like I wanted, came in the next morning. made this post all happy with what I had done.... And that was clearly wrong... I'll fix it and resubmit the code...