Added POV image effect

Setup is really easy, after first boot and WiFi/LEDs setup:
go to wled.local/edit and upload a couple image to WLed's filesystem.
Only PNG is supported right now, further support for GIF is planned.
The image should be as wide as the 1D segment you want to apply to.

When done, go to the Effect page on the UI, select "POV Image" effect.

You could also update the image with a post to the JSON-API like this:
curl -X POST http://[wled]/json/state -d '{"seg":{"id":0,"fx":114,"f":"/axel.png"}}'

The segment should move at around 120RPM (that's 2revolutions per seconds) for an image to showup.
More informations and pictures here : https://lumina.toys
This commit is contained in:
Arthur Suzuki 2023-11-22 02:36:06 +01:00
parent d2401a212a
commit ed5eb28228
No known key found for this signature in database
GPG Key ID: 7558BEE2BEEEBCAA
4 changed files with 98 additions and 0 deletions

View File

@ -29,6 +29,8 @@ lib_deps = ${esp8266.lib_deps}
; ;gmag11/QuickESPNow @ ~0.7.0 # will also load QuickDebug ; ;gmag11/QuickESPNow @ ~0.7.0 # will also load QuickDebug
; https://github.com/blazoncek/QuickESPNow.git#optional-debug ;; exludes debug library ; https://github.com/blazoncek/QuickESPNow.git#optional-debug ;; exludes debug library
; ${esp32.AR_lib_deps} ;; used for USERMOD_AUDIOREACTIVE ; ${esp32.AR_lib_deps} ;; used for USERMOD_AUDIOREACTIVE
; bitbank2/PNGdec@^1.0.1 ;; used for POV display uncomment following
build_unflags = ${common.build_unflags} build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags} build_flags = ${common.build_flags} ${esp8266.build_flags}
; ;
@ -152,6 +154,8 @@ build_flags = ${common.build_flags} ${esp8266.build_flags}
; -D TACHO_PIN=33 ; -D TACHO_PIN=33
; -D PWM_PIN=32 ; -D PWM_PIN=32
; ;
; Use POV Display usermod
; -D USERMOD_POV_DISPLAY
; Use built-in or custom LED as a status indicator (assumes LED is connected to GPIO16) ; Use built-in or custom LED as a status indicator (assumes LED is connected to GPIO16)
; -D STATUSLED=16 ; -D STATUSLED=16
; ;

View File

@ -0,0 +1,85 @@
#pragma once
#include "wled.h"
#include <PNGdec.h>
void * openFile(const char *filename, int32_t *size) {
f = WLED_FS.open(filename);
*size = f.size();
return &f;
}
void closeFile(void *handle) {
if (f) f.close();
}
int32_t readFile(PNGFILE *pFile, uint8_t *pBuf, int32_t iLen)
{
int32_t iBytesRead;
iBytesRead = iLen;
File *f = static_cast<File *>(pFile->fHandle);
// Note: If you read a file all the way to the last byte, seek() stops working
if ((pFile->iSize - pFile->iPos) < iLen)
iBytesRead = pFile->iSize - pFile->iPos - 1; // <-- ugly work-around
if (iBytesRead <= 0)
return 0;
iBytesRead = (int32_t)f->read(pBuf, iBytesRead);
pFile->iPos = f->position();
return iBytesRead;
}
int32_t seekFile(PNGFILE *pFile, int32_t iPosition)
{
int i = micros();
File *f = static_cast<File *>(pFile->fHandle);
f->seek(iPosition);
pFile->iPos = (int32_t)f->position();
i = micros() - i;
return pFile->iPos;
}
void draw(PNGDRAW *pDraw) {
uint16_t usPixels[SEGLEN];
png.getLineAsRGB565(pDraw, usPixels, PNG_RGB565_LITTLE_ENDIAN, 0xffffffff);
for(int x=0; x < SEGLEN; x++) {
uint16_t color = usPixels[x];
byte r = ((color >> 11) & 0x1F);
byte g = ((color >> 5) & 0x3F);
byte b = (color & 0x1F);
SEGMENT.setPixelColor(x, RGBW32(r,g,b,0));
}
strip.show();
}
uint16_t mode_pov_image(void) {
const char * filepath = SEGMENT.name;
int rc = png.open(filepath, openFile, closeFile, readFile, seekFile, draw);
if (rc == PNG_SUCCESS) {
rc = png.decode(NULL, 0);
png.close();
return FRAMETIME;
}
return FRAMETIME;
}
class PovDisplayUsermod : public Usermod
{
public:
static const char _data_FX_MODE_POV_IMAGE[] PROGMEM = "POV Image@!;;;1";
PNG png;
File f;
void setup() {
strip.addEffect(255, &mode_pov_image, _data_FX_MODE_POV_IMAGE);
}
void loop() {
}
uint16_t getId()
{
return USERMOD_ID_POV_DISPLAY;
}
void connected() {}
};

View File

@ -200,6 +200,7 @@
#define USERMOD_ID_INA226 50 //Usermod "usermod_ina226.h" #define USERMOD_ID_INA226 50 //Usermod "usermod_ina226.h"
#define USERMOD_ID_AHT10 51 //Usermod "usermod_aht10.h" #define USERMOD_ID_AHT10 51 //Usermod "usermod_aht10.h"
#define USERMOD_ID_LD2410 52 //Usermod "usermod_ld2410.h" #define USERMOD_ID_LD2410 52 //Usermod "usermod_ld2410.h"
#define USERMOD_ID_POV_DISPLAY 53 //Usermod "usermod_pov_display.h"
//Access point behavior //Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot

View File

@ -210,6 +210,10 @@
#include "../usermods/LDR_Dusk_Dawn_v2/usermod_LDR_Dusk_Dawn_v2.h" #include "../usermods/LDR_Dusk_Dawn_v2/usermod_LDR_Dusk_Dawn_v2.h"
#endif #endif
#ifdef USERMOD_POV_DISPLAY
#include "../usermods/pov_display/usermod_pov_display.h"
#endif
#ifdef USERMOD_STAIRCASE_WIPE #ifdef USERMOD_STAIRCASE_WIPE
#include "../usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h" #include "../usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h"
#endif #endif
@ -454,4 +458,8 @@ void registerUsermods()
#ifdef USERMOD_LD2410 #ifdef USERMOD_LD2410
usermods.add(new LD2410Usermod()); usermods.add(new LD2410Usermod());
#endif #endif
#ifdef USERMOD_POV_DISPLAY
usermods.add(new PovDisplayUsermod());
#endif
} }