if [ -f /tmp/update/pre_update.sh ]; then echo "Running pre-update script..." >> $UPDATE_LOG sh /tmp/update/pre_update.sh >> $UPDATE_LOG 2>&1 fi
cat > /etc/systemd/system/cvte-update.service << EOF [Unit] Description=CVTE MSD338 OTA Update Service After=network.target
[Service] Type=simple User=root ExecStart=/usr/bin/python3 /usr/local/bin/update_service.py Restart=on-failure RestartSec=10 cvte msd338 512m smart tv update download
[Install] WantedBy=multi-user.target EOF
# update_gui.py import lvgl as lv import threading from update_manager import CVTEUpdateManagerclass UpdateGUI: def init(self): self.update_manager = CVTEUpdateManager() self.current_screen = None self.progress_bar = None self.status_label = None if [ -f /tmp/update/pre_update
def create_update_screen(self): """Create the main update screen""" self.current_screen = lv.obj() # Title title = lv.label(self.current_screen) title.set_text("System Update") title.align(lv.ALIGN.TOP_MID, 0, 20) # Current version info version_label = lv.label(self.current_screen) version_label.set_text(f"Current Version: self.update_manager.current_version") version_label.align(lv.ALIGN.TOP_LEFT, 20, 80) # Check update button check_btn = lv.btn(self.current_screen) check_btn.align(lv.ALIGN.TOP_MID, 0, 150) check_label = lv.label(check_btn) check_label.set_text("Check for Updates") check_btn.add_event_cb(self._on_check_update, lv.EVENT.CLICKED, None) # Progress bar (initially hidden) self.progress_bar = lv.bar(self.current_screen) self.progress_bar.set_size(400, 20) self.progress_bar.align(lv.ALIGN.CENTER, 0, 0) self.progress_bar.add_flag(lv.obj.FLAG.HIDDEN) # Status label self.status_label = lv.label(self.current_screen) self.status_label.align(lv.ALIGN.BOTTOM_MID, 0, -20) self.status_label.set_text("Ready") lv.scr_load(self.current_screen) def _on_check_update(self, e): """Handle check update button click""" # Disable button during check btn = e.get_target() btn.add_state(lv.STATE.DISABLED) # Run check in background thread thread = threading.Thread(target=self._check_update_thread) thread.start() def _check_update_thread(self): """Background thread for checking updates""" self.status_label.set_text("Checking for updates...") update_info = self.update_manager.check_for_updates() if update_info: lv.event_send(self.current_screen, lv.EVENT.USER, update_info) self._show_update_dialog(update_info) else: self.status_label.set_text("No updates available") # Re-enable button after 2 seconds lv.timer_create(self._reenable_check_button, 2000, None) def _show_update_dialog(self, update_info): """Show update information dialog""" dialog = lv.obj(self.current_screen) dialog.set_size(500, 400) dialog.center() dialog.add_flag(lv.obj.FLAG.HIDDEN) # Dialog title title = lv.label(dialog) title.set_text(f"Update Available: vupdate_info['version']") title.align(lv.ALIGN.TOP_MID, 0, 10) # Changelog changelog = lv.label(dialog) changelog.set_text(f"Changes:\nupdate_info['changelog']") changelog.set_width(460) changelog.align(lv.ALIGN.TOP_LEFT, 20, 60) # Size info size_label = lv.label(dialog) size_label.set_text(f"Size: update_info['size_mb']:.1f MB") size_label.align(lv.ALIGN.BOTTOM_LEFT, 20, -60) # Download button download_btn = lv.btn(dialog) download_btn.set_size(150, 40) download_btn.align(lv.ALIGN.BOTTOM_RIGHT, -20, -20) download_label = lv.label(download_btn) download_label.set_text("Download") # Cancel button cancel_btn = lv.btn(dialog) cancel_btn.set_size(100, 40) cancel_btn.align(lv.ALIGN.BOTTOM_RIGHT, -190, -20) cancel_label = lv.label(cancel_btn) cancel_label.set_text("Cancel") # Event handlers download_btn.add_event_cb( lambda e: self._start_download(update_info, dialog), lv.EVENT.CLICKED, None ) cancel_btn.add_event_cb( lambda e: dialog.add_flag(lv.obj.FLAG.HIDDEN), lv.EVENT.CLICKED, None ) dialog.clear_flag(lv.obj.FLAG.HIDDEN) def _start_download(self, update_info, dialog): """Start the download process""" dialog.add_flag(lv.obj.FLAG.HIDDEN) # Show progress bar self.progress_bar.clear_flag(lv.obj.FLAG.HIDDEN) self.progress_bar.set_value(0, lv.ANIM.ON) self.status_label.set_text("Downloading update...") # Start download in background thread thread = threading.Thread(target=self._download_thread, args=(update_info,)) thread.start() def _download_thread(self, update_info): """Background download thread""" def update_progress(progress): lv.event_send(self.progress_bar, lv.EVENT.VALUE_CHANGED, int(progress)) self.progress_bar.set_value(int(progress), lv.ANIM.ON) try: self.update_manager.download_update(update_info, update_progress) # Show install prompt lv.timer_create(self._show_install_prompt, 100, None) except Exception as e: lv.timer_create(lambda t: self.status_label.set_text(f"Download failed: e"), 100, None) self.progress_bar.add_flag(lv.obj.FLAG.HIDDEN) def _show_install_prompt(self, timer): """Show install now prompt""" self.progress_bar.add_flag(lv.obj.FLAG.HIDDEN) dialog = lv.obj(self.current_screen) dialog.set_size(400, 200) dialog.center() # Message msg = lv.label(dialog) msg.set_text("Update downloaded successfully!\nInstall now?") msg.align(lv.ALIGN.TOP_MID, 0, 30) # Install button install_btn = lv.btn(dialog) install_btn.set_size(120, 40) install_btn.align(lv.ALIGN.BOTTOM_LEFT, 30, -30) install_label = lv.label(install_btn) install_label.set_text("Install Now") # Later button later_btn = lv.btn(dialog) later_btn.set_size(120, 40) later_btn.align(lv.ALIGN.BOTTOM_RIGHT, -30, -30) later_label = lv.label(later_btn) later_label.set_text("Later") install_btn.add_event_cb(lambda e: self._install_update(dialog), lv.EVENT.CLICKED, None) later_btn.add_event_cb(lambda e: dialog.add_flag(lv.obj.FLAG.HIDDEN), lv.EVENT.CLICKED, None) def _install_update(self, dialog): """Install the downloaded update""" dialog.add_flag(lv.obj.FLAG.HIDDEN) self.status_label.set_text("Installing update, TV will reboot...") # Apply update in background threading.Thread(target=self._install_thread).start() def _install_thread(self): """Background installation thread""" try: self.update_manager.apply_update() except Exception as e: lv.timer_create(lambda t: self.status_label.set_text(f"Installation failed: e"), 100, None)
Downloading the correct file is the most challenging aspect of this process due to the lack of a centralized official portal for CVTE OEM boards.