Merge branch 'mdev' into Platform_upgrade

This commit is contained in:
Frank
2023-12-10 17:36:43 +01:00
6 changed files with 151 additions and 43 deletions

View File

@@ -56,7 +56,7 @@
// auto-off feature
#ifndef USERMOD_BATTERY_AUTO_OFF_ENABLED
#define USERMOD_BATTERY_AUTO_OFF_ENABLED true
#define USERMOD_BATTERY_AUTO_OFF_ENABLED false
#endif
#ifndef USERMOD_BATTERY_AUTO_OFF_THRESHOLD
@@ -78,4 +78,4 @@
#ifndef USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION
#define USERMOD_BATTERY_LOW_POWER_INDICATOR_DURATION 5
#endif
#endif

View File

@@ -91,8 +91,15 @@
#define PLOT_FLUSH()
#endif
// audiosync constants
#define AUDIOSYNC_NONE 0x00 // UDP sound sync off
#define AUDIOSYNC_SEND 0x01 // UDP sound sync - send mode
#define AUDIOSYNC_REC 0x02 // UDP sound sync - receiver mode
#define AUDIOSYNC_REC_PLUS 0x06 // UDP sound sync - receiver + local mode (uses local input if no receiving udp sound)
#define AUDIOSYNC_IDLE_MS 2500 // timeout for "receiver idle" (milliseconds)
static volatile bool disableSoundProcessing = false; // if true, sound processing (FFT, filters, AGC) will be suspended. "volatile" as its shared between tasks.
static uint8_t audioSyncEnabled = 0; // bit field: bit 0 - send, bit 1 - receive (config value)
static uint8_t audioSyncEnabled = AUDIOSYNC_NONE; // bit field: bit 0 - send, bit 1 - receive, bit 2 - use local if not receiving
static bool udpSyncConnected = false; // UDP connection status -> true if connected to multicast group
#define NUM_GEQ_CHANNELS 16 // number of frequency channels. Don't change !!
@@ -116,7 +123,7 @@ static float FFT_Magnitude = 0.0f; // FFT: volume (magnitude) of pe
static bool samplePeak = false; // Boolean flag for peak - used in effects. Responding routine may reset this flag. Auto-reset after strip.getMinShowDelay()
static bool udpSamplePeak = false; // Boolean flag for peak. Set at the same time as samplePeak, but reset by transmitAudioData
static unsigned long timeOfPeak = 0; // time of last sample peak detection.
volatile bool haveNewFFTResult = false; // flag to directly inform UDP sound sender when new FFT results are availeable (to reduce latency). Flag is reset at next UDP send
volatile bool haveNewFFTResult = false; // flag to directly inform UDP sound sender when new FFT results are available (to reduce latency). Flag is reset at next UDP send
static uint8_t fftResult[NUM_GEQ_CHANNELS]= {0}; // Our calculated freq. channel result table to be used by effects
static float fftCalc[NUM_GEQ_CHANNELS] = {0.0f}; // Try and normalize fftBin values to a max of 4096, so that 4096/16 = 256. (also used by dynamics limiter)
@@ -449,7 +456,7 @@ void FFTcode(void * parameter)
// taskYIELD(), yield(), vTaskDelay() and esp_task_wdt_feed() didn't seem to work.
// Don't run FFT computing code if we're in Receive mode or in realtime mode
if (disableSoundProcessing || (audioSyncEnabled & 0x02)) {
if (disableSoundProcessing || (audioSyncEnabled == AUDIOSYNC_REC)) {
isFirstRun = false;
vTaskDelayUntil( &xLastWakeTime, xFrequency); // release CPU, and let I2S fill its buffers
continue;
@@ -919,7 +926,7 @@ static void autoResetPeak(void) {
uint16_t MinShowDelay = MAX(50, strip.getMinShowDelay()); // Fixes private class variable compiler error. Unsure if this is the correct way of fixing the root problem. -THATDONFC
if (millis() - timeOfPeak > MinShowDelay) { // Auto-reset of samplePeak after a complete frame has passed.
samplePeak = false;
if (audioSyncEnabled == 0) udpSamplePeak = false; // this is normally reset by transmitAudioData
if (audioSyncEnabled == AUDIOSYNC_NONE) udpSamplePeak = false; // this is normally reset by transmitAudioData
}
}
@@ -1067,7 +1074,7 @@ class AudioReactive : public Usermod {
////////////////////
void logAudio()
{
if (disableSoundProcessing && (!udpSyncConnected || ((audioSyncEnabled & 0x02) == 0))) return; // no audio available
if (disableSoundProcessing && (!udpSyncConnected || ((audioSyncEnabled & AUDIOSYNC_REC) == 0))) return; // no audio available
#ifdef MIC_LOGGER
// Debugging functions for audio input and sound processing. Comment out the values you want to see
PLOT_PRINT("volumeSmth:"); PLOT_PRINT(volumeSmth + 256.0f); PLOT_PRINT("\t"); // +256 to move above other lines
@@ -1487,7 +1494,7 @@ class AudioReactive : public Usermod {
// necessary as we also want to transmit in "AP Mode", but the standard "connected()" callback only reacts on STA connection
static unsigned long last_connection_attempt = 0;
if ((audioSyncPort <= 0) || ((audioSyncEnabled & 0x03) == 0)) return; // Sound Sync not enabled
if ((audioSyncPort <= 0) || (audioSyncEnabled == AUDIOSYNC_NONE)) return; // Sound Sync not enabled
if (!(apActive || WLED_CONNECTED || interfacesInited)) {
if (udpSyncConnected) {
udpSyncConnected = false;
@@ -1892,7 +1899,7 @@ class AudioReactive : public Usermod {
DEBUGSR_PRINTLN(F("AR connected(): old UDP connection closed."));
}
if (audioSyncPort > 0 && (audioSyncEnabled & 0x03)) {
if ((audioSyncPort > 0) && (audioSyncEnabled > AUDIOSYNC_NONE)) {
#ifdef ARDUINO_ARCH_ESP32
udpSyncConnected = fftUdp.beginMulticast(IPAddress(239, 0, 0, 1), audioSyncPort);
#else
@@ -1935,6 +1942,17 @@ class AudioReactive : public Usermod {
// We cannot wait indefinitely before processing audio data
if (strip.isServicing() && (millis() - lastUMRun < 2)) return; // WLEDMM isServicing() is the critical part (be nice, but not too nice)
// sound sync "receive or local"
bool useNetworkAudio = false;
if (audioSyncEnabled > AUDIOSYNC_SEND) { // we are in "receive" or "receive+local" mode
if (udpSyncConnected && ((millis() - last_UDPTime) <= AUDIOSYNC_IDLE_MS))
useNetworkAudio = true;
else
useNetworkAudio = false;
if (audioSyncEnabled == AUDIOSYNC_REC)
useNetworkAudio = true; // don't fall back to local audio in standard "receive mode"
}
// suspend local sound processing when "real time mode" is active (E131, UDP, ADALIGHT, ARTNET)
if ( (realtimeOverride == REALTIME_OVERRIDE_NONE) // please add other overrides here if needed
&&( (realtimeMode == REALTIME_MODE_GENERIC)
@@ -1944,27 +1962,32 @@ class AudioReactive : public Usermod {
||(realtimeMode == REALTIME_MODE_ARTNET) ) ) // please add other modes here if needed
{
#ifdef WLED_DEBUG
if ((disableSoundProcessing == false) && (audioSyncEnabled == 0)) { // we just switched to "disabled"
if ((disableSoundProcessing == false) && (audioSyncEnabled < AUDIOSYNC_REC)) { // we just switched to "disabled"
DEBUG_PRINTLN("[AR userLoop] realtime mode active - audio processing suspended.");
DEBUG_PRINTF( " RealtimeMode = %d; RealtimeOverride = %d\n", int(realtimeMode), int(realtimeOverride));
}
#endif
disableSoundProcessing = true;
useNetworkAudio = false;
} else {
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DEBUG)
if ((disableSoundProcessing == true) && (audioSyncEnabled == 0) && audioSource->isInitialized()) { // we just switched to "enabled"
if ((disableSoundProcessing == true) && (audioSyncEnabled < AUDIOSYNC_REC) && audioSource->isInitialized()) { // we just switched to "enabled"
DEBUG_PRINTLN("[AR userLoop] realtime mode ended - audio processing resumed.");
DEBUG_PRINTF( " RealtimeMode = %d; RealtimeOverride = %d\n", int(realtimeMode), int(realtimeOverride));
}
#endif
if ((disableSoundProcessing == true) && (audioSyncEnabled == 0)) lastUMRun = millis(); // just left "realtime mode" - update timekeeping
if ((disableSoundProcessing == true) && (audioSyncEnabled < AUDIOSYNC_REC)) lastUMRun = millis(); // just left "realtime mode" - update timekeeping
disableSoundProcessing = false;
}
if (audioSyncEnabled & 0x02) disableSoundProcessing = true; // make sure everything is disabled IF in audio Receive mode
if (audioSyncEnabled & 0x01) disableSoundProcessing = false; // keep running audio IF we're in audio Transmit mode
if (audioSyncEnabled == AUDIOSYNC_REC) disableSoundProcessing = true; // make sure everything is disabled IF in audio Receive mode
if (audioSyncEnabled & AUDIOSYNC_SEND) disableSoundProcessing = false; // keep running audio IF we're in audio Transmit mode
#ifdef ARDUINO_ARCH_ESP32
if (!audioSource->isInitialized()) disableSoundProcessing = true; // no audio source
if (!audioSource->isInitialized()) { // no audio source
disableSoundProcessing = true;
if (audioSyncEnabled > AUDIOSYNC_SEND) useNetworkAudio = true;
}
if ((audioSyncEnabled == AUDIOSYNC_REC_PLUS) && useNetworkAudio) disableSoundProcessing = true; // UDP sound receiving - disable local audio
#ifdef SR_DEBUG
// debug info in case that task stack usage changes
@@ -1977,7 +2000,7 @@ class AudioReactive : public Usermod {
#endif
// Only run the sampling code IF we're not in Receive mode or realtime mode
if (!(audioSyncEnabled & 0x02) && !disableSoundProcessing) {
if ((audioSyncEnabled != AUDIOSYNC_REC) && !disableSoundProcessing && !useNetworkAudio) {
if (soundAgc > AGC_NUM_PRESETS) soundAgc = 0; // make sure that AGC preset is valid (to avoid array bounds violation)
unsigned long t_now = millis(); // remember current time
@@ -1987,7 +2010,7 @@ class AudioReactive : public Usermod {
#if defined(SR_DEBUG)
// complain when audio userloop has been delayed for long time. Currently we need userloop running between 500 and 1500 times per second.
// softhack007 disabled temporarily - avoid serial console spam with MANY LEDs and low FPS
//if ((userloopDelay > /*23*/ 65) && !disableSoundProcessing && (audioSyncEnabled == 0)) {
//if ((userloopDelay > /*23*/ 65) && !disableSoundProcessing && (audioSyncEnabled == AUDIOSYNC_NONE)) {
//DEBUG_PRINTF("[AR userLoop] hiccup detected -> was inactive for last %d millis!\n", userloopDelay);
//}
#endif
@@ -2034,28 +2057,33 @@ class AudioReactive : public Usermod {
connectUDPSoundSync(); // ensure we have a connection - if needed
// UDP Microphone Sync - receive mode
if ((audioSyncEnabled & 0x02) && udpSyncConnected) {
if ((audioSyncEnabled & AUDIOSYNC_REC) && udpSyncConnected) {
// Only run the audio listener code if we're in Receive mode
static float syncVolumeSmth = 0;
bool have_new_sample = false;
if (millis() - lastTime > delayMs) {
have_new_sample = receiveAudioData();
if (have_new_sample) last_UDPTime = millis();
if (have_new_sample) {
last_UDPTime = millis();
useNetworkAudio = true; // UDP input arrived - use it
}
lastTime = millis();
} else {
#ifdef ARDUINO_ARCH_ESP32
fftUdp.flush(); // WLEDMM: Flush this if we haven't read it. Does not work on 8266.
#endif
}
if (have_new_sample) syncVolumeSmth = volumeSmth; // remember received sample
else volumeSmth = syncVolumeSmth; // restore originally received sample for next run of dynamics limiter
limitSampleDynamics(); // run dynamics limiter on received volumeSmth, to hide jumps and hickups
limitGEQDynamics(have_new_sample); // WLEDMM experimental: smooth FFT (GEQ) samples
if (useNetworkAudio) {
if (have_new_sample) syncVolumeSmth = volumeSmth; // remember received sample
else volumeSmth = syncVolumeSmth; // restore originally received sample for next run of dynamics limiter
limitSampleDynamics(); // run dynamics limiter on received volumeSmth, to hide jumps and hickups
limitGEQDynamics(have_new_sample); // WLEDMM experimental: smooth FFT (GEQ) samples
}
} else {
receivedFormat = 0;
}
if ( (audioSyncEnabled & 0x02) // receive mode
if ( (audioSyncEnabled & AUDIOSYNC_REC) // receive mode
&& udpSyncConnected // connected
&& (receivedFormat > 0) // we actually received something in the past
&& ((millis() - last_UDPTime) > 25000)) { // close connection after 25sec idle
@@ -2102,9 +2130,9 @@ class AudioReactive : public Usermod {
#ifdef ARDUINO_ARCH_ESP32
//UDP Microphone Sync - transmit mode
#if defined(WLEDMM_FASTPATH)
if ((audioSyncEnabled & 0x01) && (haveNewFFTResult || (millis() - lastTime > 24))) { // fastpath: send data once results are ready, or each 25ms as fallback (max sampling time is 23ms)
if ((audioSyncEnabled & AUDIOSYNC_SEND) && (haveNewFFTResult || (millis() - lastTime > 24))) { // fastpath: send data once results are ready, or each 25ms as fallback (max sampling time is 23ms)
#else
if ((audioSyncEnabled & 0x01) && (millis() - lastTime > 20)) { // standard: send data each 20ms
if ((audioSyncEnabled & AUDIOSYNC_SEND) && (millis() - lastTime > 20)) { // standard: send data each 20ms
#endif
haveNewFFTResult = false; // reset notification
// Only run the transmit code IF we're in Transmit mode
@@ -2256,7 +2284,15 @@ class AudioReactive : public Usermod {
infoArr.add(uiDomString);
if (enabled) {
bool audioSyncIDLE = false; // true if sound sync is not receiving
#ifdef ARDUINO_ARCH_ESP32
// audio sync status
if ((audioSyncEnabled & AUDIOSYNC_REC) && (!udpSyncConnected || (millis() - last_UDPTime > AUDIOSYNC_IDLE_MS))) // connected and nothing received in 2.5sec
audioSyncIDLE = true;
if ((audioSource == nullptr) || (!audioSource->isInitialized())) // local audio not configured
audioSyncIDLE = false;
// Input Level Slider
if (disableSoundProcessing == false) { // only show slider when audio processing is running
if (soundAgc > 0) {
@@ -2283,11 +2319,11 @@ class AudioReactive : public Usermod {
// The following can be used for troubleshooting user errors and is so not enclosed in #ifdef WLED_DEBUG
// current Audio input
infoArr = user.createNestedArray(F("Audio Source"));
if (audioSyncEnabled & 0x02) {
if ((audioSyncEnabled == AUDIOSYNC_REC) || (!audioSyncIDLE && (audioSyncEnabled == AUDIOSYNC_REC_PLUS))){
// UDP sound sync - receive mode
infoArr.add(F("UDP sound sync"));
if (udpSyncConnected) {
if (millis() - last_UDPTime < 2500)
if (millis() - last_UDPTime < AUDIOSYNC_IDLE_MS)
infoArr.add(F(" - receiving"));
else
infoArr.add(F(" - idle"));
@@ -2335,13 +2371,13 @@ class AudioReactive : public Usermod {
}
// AGC or manual Gain
if ((soundAgc==0) && (disableSoundProcessing == false) && !(audioSyncEnabled & 0x02)) {
if ((soundAgc == 0) && (disableSoundProcessing == false) && !(audioSyncEnabled == AUDIOSYNC_REC)) {
infoArr = user.createNestedArray(F("Manual Gain"));
float myGain = ((float)sampleGain/40.0f * (float)inputLevel/128.0f) + 1.0f/16.0f; // non-AGC gain from presets
infoArr.add(roundf(myGain*100.0f) / 100.0f);
infoArr.add("x");
}
if (soundAgc && (disableSoundProcessing == false) && !(audioSyncEnabled & 0x02)) {
if ((soundAgc > 0) && (disableSoundProcessing == false) && !(audioSyncEnabled == AUDIOSYNC_REC)) {
infoArr = user.createNestedArray(F("AGC Gain"));
infoArr.add(roundf(multAgc*100.0f) / 100.0f);
infoArr.add("x");
@@ -2350,16 +2386,18 @@ class AudioReactive : public Usermod {
// UDP Sound Sync status
infoArr = user.createNestedArray(F("UDP Sound Sync"));
if (audioSyncEnabled) {
if (audioSyncEnabled & 0x01) {
if (audioSyncEnabled & AUDIOSYNC_SEND) {
infoArr.add(F("send mode"));
if ((udpSyncConnected) && (millis() - lastTime < 2500)) infoArr.add(F(" v2"));
} else if (audioSyncEnabled & 0x02) {
if ((udpSyncConnected) && (millis() - lastTime < AUDIOSYNC_IDLE_MS)) infoArr.add(F(" v2"));
} else if (audioSyncEnabled == AUDIOSYNC_REC) {
infoArr.add(F("receive mode"));
} else if (audioSyncEnabled == AUDIOSYNC_REC_PLUS) {
infoArr.add(F("receive+local mode"));
}
} else
infoArr.add("off");
if (audioSyncEnabled && !udpSyncConnected) infoArr.add(" <i>(unconnected)</i>");
if (audioSyncEnabled && udpSyncConnected && (millis() - last_UDPTime < 2500)) {
if (audioSyncEnabled && udpSyncConnected && (millis() - last_UDPTime < AUDIOSYNC_IDLE_MS)) {
if (receivedFormat == 1) infoArr.add(F(" v1"));
if (receivedFormat == 2) infoArr.add(F(" v2"));
}
@@ -2751,11 +2789,14 @@ class AudioReactive : public Usermod {
oappend(SET_F("addInfo('AudioReactive:frequency:profile',1,'☾');"));
#endif
oappend(SET_F("dd=addDropdown('AudioReactive','sync:mode');"));
oappend(SET_F("addOption(dd,'Off',0);"));
oappend(SET_F("addOption(dd,'Off',0);")); // AUDIOSYNC_NONE
#ifdef ARDUINO_ARCH_ESP32
oappend(SET_F("addOption(dd,'Send',1);"));
oappend(SET_F("addOption(dd,'Send',1);")); // AUDIOSYNC_SEND
#endif
oappend(SET_F("addOption(dd,'Receive',2);")); // AUDIOSYNC_REC
#ifdef ARDUINO_ARCH_ESP32
oappend(SET_F("addOption(dd,'Receive or Local',6);")); // AUDIOSYNC_REC_PLUS
#endif
oappend(SET_F("addOption(dd,'Receive',2);"));
oappend(SET_F("addInfo('AudioReactive:sync:mode',1,'<br> Sync audio data with other WLEDs');"));
oappend(SET_F("addInfo('AudioReactive:digitalmic:type',1,'<i>requires reboot!</i>');")); // 0 is field type, 1 is actual field

View File

@@ -1922,6 +1922,71 @@ uint16_t mode_pride_2015(void) {
static const char _data_FX_MODE_PRIDE_2015[] PROGMEM = "Pride 2015@!;;";
//////////////////////
// PARTYJERK //
//////////////////////
// by @tonyxforce
// NB: This effects expects a palette that starts with black and then ramps up brightness.
// Currently works best with the "color gradient" and the "colors 1&2" palettes
uint16_t mode_partyjerk() {
if (SEGENV.call == 0) {
SEGMENT.fill(BLACK); // clear LEDs
SEGENV.aux0 = 0;
SEGENV.aux1 = 0;
SEGENV.step = 0;
}
/*
* use of persistent variables:
* aux0: hueDelay
* aux1: hue
* step: pos
*/
um_data_t *um_data;
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
// add support for no audio
um_data = simulateSound(SEGMENT.soundSim);
}
float volumeSmth = *(float*) um_data->u_data[0];
SEGENV.aux0++;
if (SEGENV.aux1 > 254) {
SEGENV.aux1 = 0;
}
if (SEGENV.aux0 > map(SEGMENT.custom1, 0, 255, 0, 14)) {
SEGENV.aux0 = 0;
SEGENV.aux1++;
}
uint_fast32_t speed = 0;
uint16_t counter = 0;
if (volumeSmth * 2 > (255 - SEGMENT.intensity)) {
speed = SEGMENT.speed * map(SEGMENT.custom2, 0, 255, 0, 100);
} else {
speed = SEGMENT.speed;
};
SEGENV.step += speed;
counter = SEGENV.step >> 8;
for (unsigned i = 0; i < SEGLEN; i++) {
uint8_t colorIndex = ((i * 255) / SEGLEN) - counter;
uint32_t paletteColor = SEGMENT.color_from_palette(colorIndex, false, PALETTE_MOVING_WRAP, 255);
uint8_t r = R(paletteColor);
uint8_t g = G(paletteColor);
uint8_t b = B(paletteColor);
uint8_t activeColor = max(r, max(g, b));
CRGB rgb(CHSV(SEGENV.aux1, 255, activeColor));
SEGMENT.setPixelColor((uint16_t)i, rgb.r, rgb.g, rgb.b);
};
return FRAMETIME;
} // mode_partyjerk()
static const char _data_FX_MODE_PARTYJERK[] PROGMEM = "Party jerk@Effect speed,Sensitivity,Color change speed,Effect speed active multiplier;!,!;!;1v;c1=8,c2=48,m12=0,si=0";
//eight colored dots, weaving in and out of sync with each other
uint16_t mode_juggle(void) {
if (SEGLEN == 1) return mode_static();
@@ -8235,6 +8300,7 @@ void WS2812FX::setupEffectData() {
// --- 1D audio effects ---
addEffect(FX_MODE_PIXELS, &mode_pixels, _data_FX_MODE_PIXELS);
addEffect(FX_MODE_PIXELWAVE, &mode_pixelwave, _data_FX_MODE_PIXELWAVE);
addEffect(FX_MODE_PARTYJERK, &mode_partyjerk, _data_FX_MODE_PARTYJERK);
addEffect(FX_MODE_JUGGLES, &mode_juggles, _data_FX_MODE_JUGGLES);
addEffect(FX_MODE_MATRIPIX, &mode_matripix, _data_FX_MODE_MATRIPIX);
addEffect(FX_MODE_GRAVIMETER, &mode_gravimeter, _data_FX_MODE_GRAVIMETER);

View File

@@ -334,8 +334,9 @@ void strip_wait_until_idle(String whoCalledMe); // WLEDMM implemented in FX_fcn.
#define FX_MODE_ROCKTAVES 185
#define FX_MODE_2DAKEMI 186
#define FX_MODE_ARTIFX 187 //WLEDMM ARTIFX
#define FX_MODE_PARTYJERK 188
#define MODE_COUNT 188
#define MODE_COUNT 189
typedef enum mapping1D2D {
M12_Pixels = 0,
@@ -397,7 +398,7 @@ typedef struct Segment {
uint16_t aux0; // custom var
uint16_t aux1; // custom var
byte* data = nullptr; // effect data pointer // WLEDMM initialize to nullptr
CRGB* ledsrgb = nullptr; // local leds[] array (may be a pointer to global) //WLEDMM rename to ledsrgb to search on them (temp?), and initialilize to nullptr
CRGB* ledsrgb = nullptr; // local leds[] array (may be a pointer to global) //WLEDMM rename to ledsrgb to search on them (temp?), and initialize to nullptr
size_t ledsrgbSize; //WLEDMM
static CRGB *_globalLeds; // global leds[] array
static uint16_t maxWidth, maxHeight; // these define matrix width & height (max. segment dimensions)

View File

@@ -225,7 +225,7 @@ void registerUsermods()
*/
//usermods.add(new MyExampleUsermod());
#ifdef USERMOD_BATTERY
usermods.add(new UsermodBattery("Battery", true));
usermods.add(new UsermodBattery("Battery", false)); // WLEDMM
#endif
#ifdef USERMOD_DALLASTEMPERATURE
@@ -293,7 +293,7 @@ void registerUsermods()
#endif
#ifdef USERMOD_RTC
usermods.add(new RTCUsermod("RTC", true));
usermods.add(new RTCUsermod("RTC", false)); //WLEDMM
#endif
#ifdef USERMOD_ELEKSTUBE_IPS
@@ -385,7 +385,7 @@ void registerUsermods()
#endif
#ifdef USERMOD_MCUTEMP
usermods.add(new mcuTemp("MCUTemp", true));
usermods.add(new mcuTemp("MCUTemp", false));
#endif
//#ifdef USERMOD_INTERNAL_TEMPERATURE

View File

@@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2311290
#define VERSION 2312050
//WLEDMM + Moustachauve/Wled-Native
// You can define custom product info from build flags.