@@ -693,6 +693,8 @@ function parseInfo(i) {
693693// gId("filterVol").classList.add("hide"); hideModes(" ♪"); // hide volume reactive effects
694694// gId("filterFreq").classList.add("hide"); hideModes(" ♫"); // hide frequency reactive effects
695695// }
696+ // Check for version upgrades on page load
697+ checkVersionUpgrade ( i ) ;
696698}
697699
698700//https://stackoverflow.com/questions/2592092/executing-script-elements-inserted-with-innerhtml
@@ -3304,6 +3306,195 @@ function simplifyUI() {
33043306 gId ( "btns" ) . style . display = "none" ;
33053307}
33063308
3309+ // Version reporting feature
3310+ var versionCheckDone = false ;
3311+
3312+ function checkVersionUpgrade ( info ) {
3313+ // Only check once per page load
3314+ if ( versionCheckDone ) return ;
3315+ versionCheckDone = true ;
3316+
3317+ // Suppress feature if in AP mode (no internet connection available)
3318+ if ( info . wifi && info . wifi . ap ) return ;
3319+
3320+ // Fetch version-info.json using existing /edit endpoint
3321+ fetch ( getURL ( '/edit?func=edit&path=/version-info.json' ) , {
3322+ method : 'get'
3323+ } )
3324+ . then ( res => {
3325+ if ( res . status === 404 ) {
3326+ // File doesn't exist - first install, show install prompt
3327+ showVersionUpgradePrompt ( info , null , info . ver ) ;
3328+ return null ;
3329+ }
3330+ if ( ! res . ok ) {
3331+ throw new Error ( 'Failed to fetch version-info.json' ) ;
3332+ }
3333+ return res . json ( ) ;
3334+ } )
3335+ . then ( versionInfo => {
3336+ if ( ! versionInfo ) return ; // 404 case already handled
3337+
3338+ // Check if user opted out
3339+ if ( versionInfo . neverAsk ) return ;
3340+
3341+ // Check if version has changed
3342+ const currentVersion = info . ver ;
3343+ const storedVersion = versionInfo . version || '' ;
3344+
3345+ if ( storedVersion && storedVersion !== currentVersion ) {
3346+ // Version has changed, show upgrade prompt
3347+ showVersionUpgradePrompt ( info , storedVersion , currentVersion ) ;
3348+ } else if ( ! storedVersion ) {
3349+ // Empty version in file, show install prompt
3350+ showVersionUpgradePrompt ( info , null , currentVersion ) ;
3351+ }
3352+ } )
3353+ . catch ( e => {
3354+ console . log ( 'Failed to load version-info.json' , e ) ;
3355+ // On error, save current version for next time
3356+ if ( info && info . ver ) {
3357+ updateVersionInfo ( info . ver , false ) ;
3358+ }
3359+ } ) ;
3360+ }
3361+
3362+ function showVersionUpgradePrompt ( info , oldVersion , newVersion ) {
3363+ // Determine if this is an install or upgrade
3364+ const isInstall = ! oldVersion ;
3365+
3366+ // Create overlay and dialog
3367+ const overlay = d . createElement ( 'div' ) ;
3368+ overlay . id = 'versionUpgradeOverlay' ;
3369+ 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;' ;
3370+
3371+ const dialog = d . createElement ( 'div' ) ;
3372+ 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);' ;
3373+
3374+ // Build contextual message based on install vs upgrade
3375+ const title = isInstall
3376+ ? '🎉 Thank you for installing WLED!'
3377+ : '🎉 WLED Upgrade Detected!' ;
3378+
3379+ const description = isInstall
3380+ ? `You are now running WLED <strong style="text-wrap: nowrap">${ newVersion } </strong>.`
3381+ : `Your WLED has been upgraded from <strong style="text-wrap: nowrap">${ oldVersion } </strong> to <strong style="text-wrap: nowrap">${ newVersion } </strong>.` ;
3382+
3383+ 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.'
3384+
3385+ dialog . innerHTML = `
3386+ <h2 style="margin-top:0;color:var(--c-f);">${ title } </h2>
3387+ <p style="color:var(--c-f);">${ description } </p>
3388+ <p style="color:var(--c-f);">${ question } </p>
3389+ <p style="color:var(--c-f);font-size:0.9em;">
3390+ <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>
3391+ </p>
3392+ <div style="margin-top:20px;">
3393+ <button id="versionReportYes" class="btn">Yes</button>
3394+ <button id="versionReportNo" class="btn">Not Now</button>
3395+ <button id="versionReportNever" class="btn">Never Ask</button>
3396+ </div>
3397+ ` ;
3398+
3399+ overlay . appendChild ( dialog ) ;
3400+ d . body . appendChild ( overlay ) ;
3401+
3402+ // Add event listeners
3403+ gId ( 'versionReportYes' ) . addEventListener ( 'click' , ( ) => {
3404+ reportUpgradeEvent ( info , oldVersion ) ;
3405+ d . body . removeChild ( overlay ) ;
3406+ } ) ;
3407+
3408+ gId ( 'versionReportNo' ) . addEventListener ( 'click' , ( ) => {
3409+ // Don't update version, will ask again on next load
3410+ d . body . removeChild ( overlay ) ;
3411+ } ) ;
3412+
3413+ gId ( 'versionReportNever' ) . addEventListener ( 'click' , ( ) => {
3414+ updateVersionInfo ( newVersion , true ) ;
3415+ d . body . removeChild ( overlay ) ;
3416+ showToast ( 'You will not be asked again.' ) ;
3417+ } ) ;
3418+ }
3419+
3420+ function reportUpgradeEvent ( info , oldVersion ) {
3421+ showToast ( 'Reporting upgrade...' ) ;
3422+
3423+ // Fetch fresh data from /json/info endpoint as requested
3424+ fetch ( getURL ( '/json/info' ) , {
3425+ method : 'get'
3426+ } )
3427+ . then ( res => res . json ( ) )
3428+ . then ( infoData => {
3429+ // Map to UpgradeEventRequest structure per OpenAPI spec
3430+ // Required fields: deviceId, version, previousVersion, releaseName, chip, ledCount, isMatrix, bootloaderSHA256
3431+ const upgradeData = {
3432+ deviceId : infoData . deviceId , // Use anonymous unique device ID
3433+ version : infoData . ver || '' , // Current version string
3434+ previousVersion : oldVersion || '' , // Previous version from version-info.json
3435+ releaseName : infoData . release || '' , // Release name (e.g., "WLED 0.15.0")
3436+ chip : infoData . arch || '' , // Chip architecture (esp32, esp8266, etc)
3437+ ledCount : infoData . leds ? infoData . leds . count : 0 , // Number of LEDs
3438+ isMatrix : ! ! ( infoData . leds && infoData . leds . matrix ) , // Whether it's a 2D matrix setup
3439+ bootloaderSHA256 : infoData . bootloaderSHA256 || '' , // Bootloader SHA256 hash
3440+ brand : infoData . brand , // Device brand (always present)
3441+ product : infoData . product , // Product name (always present)
3442+ flashSize : infoData . flash // Flash size (always present)
3443+ } ;
3444+
3445+ // Add optional fields if available
3446+ if ( infoData . psram !== undefined ) upgradeData . psramSize = infoData . psram ;
3447+ // Note: partitionSizes not currently available in /json/info endpoint
3448+
3449+ // Make AJAX call to postUpgradeEvent API
3450+ return fetch ( 'https://usage.wled.me/api/usage/upgrade' , {
3451+ method : 'POST' ,
3452+ headers : {
3453+ 'Content-Type' : 'application/json'
3454+ } ,
3455+ body : JSON . stringify ( upgradeData )
3456+ } ) ;
3457+ } )
3458+ . then ( res => {
3459+ if ( res . ok ) {
3460+ showToast ( 'Thank you for reporting!' ) ;
3461+ updateVersionInfo ( info . ver , false ) ;
3462+ } else {
3463+ showToast ( 'Report failed. Please try again later.' , true ) ;
3464+ // Do NOT update version info on failure - user will be prompted again
3465+ }
3466+ } )
3467+ . catch ( e => {
3468+ console . log ( 'Failed to report upgrade' , e ) ;
3469+ showToast ( 'Report failed. Please try again later.' , true ) ;
3470+ // Do NOT update version info on error - user will be prompted again
3471+ } ) ;
3472+ }
3473+
3474+ function updateVersionInfo ( version , neverAsk ) {
3475+ const versionInfo = {
3476+ version : version ,
3477+ neverAsk : neverAsk
3478+ } ;
3479+
3480+ // Create a Blob with JSON content and use /upload endpoint
3481+ const blob = new Blob ( [ JSON . stringify ( versionInfo ) ] , { type : 'application/json' } ) ;
3482+ const formData = new FormData ( ) ;
3483+ formData . append ( 'data' , blob , 'version-info.json' ) ;
3484+
3485+ fetch ( getURL ( '/upload' ) , {
3486+ method : 'POST' ,
3487+ body : formData
3488+ } )
3489+ . then ( res => res . text ( ) )
3490+ . then ( data => {
3491+ console . log ( 'Version info updated' , data ) ;
3492+ } )
3493+ . catch ( e => {
3494+ console . log ( 'Failed to update version-info.json' , e ) ;
3495+ } ) ;
3496+ }
3497+
33073498size ( ) ;
33083499_C . style . setProperty ( '--n' , N ) ;
33093500
0 commit comments