@@ -688,6 +688,8 @@ function parseInfo(i) {
688688// gId("filterVol").classList.add("hide"); hideModes(" ♪"); // hide volume reactive effects
689689// gId("filterFreq").classList.add("hide"); hideModes(" ♫"); // hide frequency reactive effects
690690// }
691+ // Check for version upgrades on page load
692+ checkVersionUpgrade ( i ) ;
691693}
692694
693695//https://stackoverflow.com/questions/2592092/executing-script-elements-inserted-with-innerhtml
@@ -3248,6 +3250,195 @@ function simplifyUI() {
32483250 gId ( "btns" ) . style . display = "none" ;
32493251}
32503252
3253+ // Version reporting feature
3254+ var versionCheckDone = false ;
3255+
3256+ function checkVersionUpgrade ( info ) {
3257+ // Only check once per page load
3258+ if ( versionCheckDone ) return ;
3259+ versionCheckDone = true ;
3260+
3261+ // Suppress feature if in AP mode (no internet connection available)
3262+ if ( info . wifi && info . wifi . ap ) return ;
3263+
3264+ // Fetch version-info.json using existing /edit endpoint
3265+ fetch ( getURL ( '/edit?func=edit&path=/version-info.json' ) , {
3266+ method : 'get'
3267+ } )
3268+ . then ( res => {
3269+ if ( res . status === 404 ) {
3270+ // File doesn't exist - first install, show install prompt
3271+ showVersionUpgradePrompt ( info , null , info . ver ) ;
3272+ return null ;
3273+ }
3274+ if ( ! res . ok ) {
3275+ throw new Error ( 'Failed to fetch version-info.json' ) ;
3276+ }
3277+ return res . json ( ) ;
3278+ } )
3279+ . then ( versionInfo => {
3280+ if ( ! versionInfo ) return ; // 404 case already handled
3281+
3282+ // Check if user opted out
3283+ if ( versionInfo . neverAsk ) return ;
3284+
3285+ // Check if version has changed
3286+ const currentVersion = info . ver ;
3287+ const storedVersion = versionInfo . version || '' ;
3288+
3289+ if ( storedVersion && storedVersion !== currentVersion ) {
3290+ // Version has changed, show upgrade prompt
3291+ showVersionUpgradePrompt ( info , storedVersion , currentVersion ) ;
3292+ } else if ( ! storedVersion ) {
3293+ // Empty version in file, show install prompt
3294+ showVersionUpgradePrompt ( info , null , currentVersion ) ;
3295+ }
3296+ } )
3297+ . catch ( e => {
3298+ console . log ( 'Failed to load version-info.json' , e ) ;
3299+ // On error, save current version for next time
3300+ if ( info && info . ver ) {
3301+ updateVersionInfo ( info . ver , false ) ;
3302+ }
3303+ } ) ;
3304+ }
3305+
3306+ function showVersionUpgradePrompt ( info , oldVersion , newVersion ) {
3307+ // Determine if this is an install or upgrade
3308+ const isInstall = ! oldVersion ;
3309+
3310+ // Create overlay and dialog
3311+ const overlay = d . createElement ( 'div' ) ;
3312+ overlay . id = 'versionUpgradeOverlay' ;
3313+ overlay . style . cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.7);z-index:10000;display:flex;align-items:center;justify-content:center;' ;
3314+
3315+ const dialog = d . createElement ( 'div' ) ;
3316+ dialog . style . cssText = 'background:var(--c-1);border-radius:10px;padding:25px;max-width:500px;margin:20px;box-shadow:0 4px 6px rgba(0,0,0,0.3);' ;
3317+
3318+ // Build contextual message based on install vs upgrade
3319+ const title = isInstall
3320+ ? '🎉 Thank you for installing WLED!'
3321+ : '🎉 WLED Upgrade Detected!' ;
3322+
3323+ const description = isInstall
3324+ ? `You are now running WLED <strong style="text-wrap: nowrap">${ newVersion } </strong>.`
3325+ : `Your WLED has been upgraded from <strong style="text-wrap: nowrap">${ oldVersion } </strong> to <strong style="text-wrap: nowrap">${ newVersion } </strong>.` ;
3326+
3327+ const question = 'Help make WLED better with a one-time hardware report? It includes only device details like chip type, LED count, etc. — never personal data or your activities.'
3328+
3329+ dialog . innerHTML = `
3330+ <h2 style="margin-top:0;color:var(--c-f);">${ title } </h2>
3331+ <p style="color:var(--c-f);">${ description } </p>
3332+ <p style="color:var(--c-f);">${ question } </p>
3333+ <p style="color:var(--c-f);font-size:0.9em;">
3334+ <a href="https://kno.wled.ge/about/privacy-policy/" target="_blank" style="color:var(--c-6);">Learn more about what data is collected and why</a>
3335+ </p>
3336+ <div style="margin-top:20px;">
3337+ <button id="versionReportYes" class="btn">Yes</button>
3338+ <button id="versionReportNo" class="btn">Not Now</button>
3339+ <button id="versionReportNever" class="btn">Never Ask</button>
3340+ </div>
3341+ ` ;
3342+
3343+ overlay . appendChild ( dialog ) ;
3344+ d . body . appendChild ( overlay ) ;
3345+
3346+ // Add event listeners
3347+ gId ( 'versionReportYes' ) . addEventListener ( 'click' , ( ) => {
3348+ reportUpgradeEvent ( info , oldVersion ) ;
3349+ d . body . removeChild ( overlay ) ;
3350+ } ) ;
3351+
3352+ gId ( 'versionReportNo' ) . addEventListener ( 'click' , ( ) => {
3353+ // Don't update version, will ask again on next load
3354+ d . body . removeChild ( overlay ) ;
3355+ } ) ;
3356+
3357+ gId ( 'versionReportNever' ) . addEventListener ( 'click' , ( ) => {
3358+ updateVersionInfo ( newVersion , true ) ;
3359+ d . body . removeChild ( overlay ) ;
3360+ showToast ( 'You will not be asked again.' ) ;
3361+ } ) ;
3362+ }
3363+
3364+ function reportUpgradeEvent ( info , oldVersion ) {
3365+ showToast ( 'Reporting upgrade...' ) ;
3366+
3367+ // Fetch fresh data from /json/info endpoint as requested
3368+ fetch ( getURL ( '/json/info' ) , {
3369+ method : 'get'
3370+ } )
3371+ . then ( res => res . json ( ) )
3372+ . then ( infoData => {
3373+ // Map to UpgradeEventRequest structure per OpenAPI spec
3374+ // Required fields: deviceId, version, previousVersion, releaseName, chip, ledCount, isMatrix, bootloaderSHA256
3375+ const upgradeData = {
3376+ deviceId : infoData . deviceId , // Use anonymous unique device ID
3377+ version : infoData . ver || '' , // Current version string
3378+ previousVersion : oldVersion || '' , // Previous version from version-info.json
3379+ releaseName : infoData . release || '' , // Release name (e.g., "WLED 0.15.0")
3380+ chip : infoData . arch || '' , // Chip architecture (esp32, esp8266, etc)
3381+ ledCount : infoData . leds ? infoData . leds . count : 0 , // Number of LEDs
3382+ isMatrix : ! ! ( infoData . leds && infoData . leds . matrix ) , // Whether it's a 2D matrix setup
3383+ bootloaderSHA256 : infoData . bootloaderSHA256 || '' , // Bootloader SHA256 hash
3384+ brand : infoData . brand , // Device brand (always present)
3385+ product : infoData . product , // Product name (always present)
3386+ flashSize : infoData . flash // Flash size (always present)
3387+ } ;
3388+
3389+ // Add optional fields if available
3390+ if ( infoData . psram !== undefined ) upgradeData . psramSize = infoData . psram ;
3391+ // Note: partitionSizes not currently available in /json/info endpoint
3392+
3393+ // Make AJAX call to postUpgradeEvent API
3394+ return fetch ( 'https://usage.wled.me/api/usage/upgrade' , {
3395+ method : 'POST' ,
3396+ headers : {
3397+ 'Content-Type' : 'application/json'
3398+ } ,
3399+ body : JSON . stringify ( upgradeData )
3400+ } ) ;
3401+ } )
3402+ . then ( res => {
3403+ if ( res . ok ) {
3404+ showToast ( 'Thank you for reporting!' ) ;
3405+ updateVersionInfo ( info . ver , false ) ;
3406+ } else {
3407+ showToast ( 'Report failed. Please try again later.' , true ) ;
3408+ // Do NOT update version info on failure - user will be prompted again
3409+ }
3410+ } )
3411+ . catch ( e => {
3412+ console . log ( 'Failed to report upgrade' , e ) ;
3413+ showToast ( 'Report failed. Please try again later.' , true ) ;
3414+ // Do NOT update version info on error - user will be prompted again
3415+ } ) ;
3416+ }
3417+
3418+ function updateVersionInfo ( version , neverAsk ) {
3419+ const versionInfo = {
3420+ version : version ,
3421+ neverAsk : neverAsk
3422+ } ;
3423+
3424+ // Create a Blob with JSON content and use /upload endpoint
3425+ const blob = new Blob ( [ JSON . stringify ( versionInfo ) ] , { type : 'application/json' } ) ;
3426+ const formData = new FormData ( ) ;
3427+ formData . append ( 'data' , blob , 'version-info.json' ) ;
3428+
3429+ fetch ( getURL ( '/upload' ) , {
3430+ method : 'POST' ,
3431+ body : formData
3432+ } )
3433+ . then ( res => res . text ( ) )
3434+ . then ( data => {
3435+ console . log ( 'Version info updated' , data ) ;
3436+ } )
3437+ . catch ( e => {
3438+ console . log ( 'Failed to update version-info.json' , e ) ;
3439+ } ) ;
3440+ }
3441+
32513442size ( ) ;
32523443_C . style . setProperty ( '--n' , N ) ;
32533444
0 commit comments