Generated reference
This page is hand-kept and says what members mean. The exact list of every property, method and signal with its types is generated from the C++ and cannot go stale: Service API Reference (docs/api/, checked by tst_apidocs). When the two disagree, the generated one is right.
How managers reach QML
Every manager is a QObject member of AppCore (src/appcore.{h,cpp}), set as a context property by src/main.cpp, and QML reaches it by that name: mediaManager.next_track(), settingsManager.themeSetting, obdManager.onRpmChanged. Other context values are screenAutoScale (float, short screen edge / 720 clamped to 0.4–3.0), isAndroid (bool, true only in the Android build), wikiViewerAvailable (bool: an embedded web viewer is available), and wikiHomeUrl (QUrl: the wiki entry point). The qmlRegisterType'd OCTAVE.AndroidAuto.EmbeddedDhuItem and the QML singletons (OBDParameterModel, WidgetCatalog, …) are documented in Components, not here.

Context property registry

17 QObject context properties, plus the dhuCapture sub-object and the developer-only perfMonitor. The scalar context values are described above.

QML nameClass & fileNotes
settingsManagerSettingsManager — src/managers/settingsmanager.h
assetStoreAssetStore — src/util/assetstore.hLocal URLs for bundled assets, with APK extraction on Android
clockClock — src/managers/clock.h
diagnosticsManagerDiagnosticsManager — src/managers/diagnosticsmanager.h
networkManagerNetworkManager — src/managers/networkmanager.h
volumeControllerVolumeController — src/managers/volumecontroller.h
mediaManagerMediaManager — src/managers/mediamanager.h
audioAnalyzerAudioAnalyzer — src/managers/audioanalyzer.h
obdManagerOBDManager — src/managers/obdmanager.h
obdAdapterFinderOBDAdapterFinder — src/managers/obdadapterfinder.hsupported is true on desktop Linux only (phase 1)
parameterCatalogParameterCatalog — src/managers/parametercatalog.hTitle / unit / range / kind of every OBD PID and IMU reading
nowPlayingNowPlaying — src/managers/nowplaying.hWhat is playing and its controls, phone or local
paramStoreParameterStore — src/managers/parameterstore.hLatest value of every OBD PID and IMU reading, one notifying key per id
shiftLightManagerShiftLightManager — src/managers/shiftlightmanager.hRPM shift light: active flag and flash phase
tripRecorderTripRecorder — src/managers/triprecorder.hBlack box: every drive into SQLite + CSV / JSON files
esp32VolumeManagerESP32VolumeManager — src/managers/esp32volumemanager.hMobile builds register a stub (see the section)
berryIMUBerryIMUManager — src/managers/berryimumanager.hAndroid build uses a QtSensors implementation
gestureSensorGestureManager — src/managers/gesturemanager.hMobile builds register a stub (see the section)
androidAutoManagerAndroidAutoManager — src/managers/androidautomanager.hMobile builds register a stub (see the section)
dhuCaptureDhuCapture — src/managers/androidautomanager.hNot registered directly; reached via androidAutoManager.dhuCapture
airPlayManagerAirPlayManager — src/managers/airplaymanager.havailable false without the AirPlay receiver (Linux only so far)
phoneMirrorManagerPhoneMirrorManager — src/managers/phonemirrormanager.hMobile builds register a stub (see the section)
dashboardManagerDashboardManager — src/managers/dashboardmanager.h
frontendManagerFrontendManager — src/managers/frontendmanager.h
perfMonitorPerfMonitor — src/dev/perfmonitor.hOnly with --profile, in OCTAVE_DEV_TOOLS builds; registered by OctaveDev::Runtime

Reading this page

  • Properties are Q_PROPERTY declarations. Almost all are read-only from QML; call the matching save_* / set* slot to change them. Notify signal is what a QML binding or on<Name>Changed handler listens to.
  • Invokables & Slots are Q_INVOKABLE methods and public slots. Signatures show the C++ parameter types without const / &. QVariantList / QStringList arrive in QML as JS arrays, QVariantMap as objects.
  • Signals list the payload the QML handler receives.
  • Android marks members that only do something on Android.
  • Where the class has a separate mobile (Q_OS_MOBILE) stub, the info box at the top of the section lists what the stub lacks.

SettingsManager — settingsManager

src/managers/settingsmanager.h — QML context property settingsManager

Central settings store. Persists settingsConfigure.json in the OS config dir (writes are debounced; flushPendingSave() forces them). Settings with a dedicated property follow a triple: a read-only Q_PROPERTY, a <name>Changed signal and a save_<snake_name>() slot. Types and defaults for every key are in the Settings Reference.

Properties

PropertyTypeAccessNotify signalDescription
deviceNameQStringread-onlydeviceNameChangedName shown on the home screen / About page — Settings Reference
fontSettingQStringread-onlyfontSettingChangedUI font family (default "GoogleSans Regular"; a stored legacy "Google Sans" is migrated at load) — Settings Reference
themeSettingQStringread-onlythemeSettingChangedActive theme name (built-in or custom) — Settings Reference
uiScalefloatread-onlyuiScaleChangedGlobal UI scale factor multiplied with screenAutoScale — Settings Reference
colorTransitionMsintread-onlycolorTransitionMsChangedDuration of theme colour transitions in ms (registry slider 0–2000, step 50) — Settings Reference
songLengthTransitionboolread-onlysongLengthTransitionChangedSpread the album-art colour transition over the length of the song — Settings Reference
showClockboolread-onlyshowClockChangedShow the clock in the bottom bar — Settings Reference
clockFormat24Hourboolread-onlyclockFormatChanged24-hour clock (notify signal is clockFormatChanged) — Settings Reference
clockShowSecondsboolread-onlyclockShowSecondsChangedShow seconds in the clock (Clock re-evaluates every second) — Settings Reference
clockSizeintread-onlyclockSizeChangedClock font size in px — Settings Reference
clockSizeAutoboolread-onlyclockSizeAutoChangedFit the clock to its nav bar slot instead of using clockSize
backgroundGridQStringread-onlybackgroundGridChangedAlbum-art background tiling: "Normal", "2x2", "4x4" — Settings Reference
screenWidthintread-onlyscreenWidthChangedWindow width (windowed mode) — Settings Reference
screenHeightintread-onlyscreenHeightChangedWindow height (windowed mode) — Settings Reference
backgroundBlurRadiusintread-onlybackgroundBlurRadiusChangedBlur radius applied to the album-art background — Settings Reference
bottomBarOrientationQStringread-onlybottomBarOrientationChangedNavigation bar placement: "bottom" / "side" — Settings Reference
showBottomBarMediaControlsboolread-onlyshowBottomBarMediaControlsChangedShow play/skip controls in the bottom bar — Settings Reference
settingsLayoutStyleQStringread-onlysettingsLayoutStyleChangedWhich Settings*Layout.qml renders the menu: "Carousel", "Sidebar", "Hub", "Dashboard" — Settings Reference
albumArtColorsQVariantMapread-onlyalbumArtColorsChangedThe last extracted album-art palette as a theme object, empty when unset (stored as a JSON string; written by the media managers via set_album_art_colors) — Settings Reference
settingsMenuVisibilityQStringread-onlysettingsMenuVisibilityChangedJSON map of settings section id → visible (displaySettings, mediaSettings, obdSettings, accessoriesSettings, deviceSettings, about; a section missing from the file counts as visible) — Settings Reference
startUpVolumefloatread-onlystartUpVolumeChangedLinear gain applied at launch (0–1; default 0.1) — Settings Reference
currentVolumeintread-onlycurrentVolumeChangedLive volume percent (0–100); set only through volumeController.applyVolume() — Settings Reference
mediaFolderQStringread-onlymediaFolderChangedRoot folder of the local music library — Settings Reference
autoPlayOnStartupboolread-onlyautoPlayOnStartupChangedResume playback automatically at launch — Settings Reference
persistShuffleStateboolread-onlypersistShuffleStateChangedRemember shuffle across restarts — Settings Reference
lastShuffleStateboolread-onlylastShuffleStateChangedShuffle state saved whenever it changes — Settings Reference
lastPlayedSongQStringread-onlylastPlayedSongChangedFilename to resume — Settings Reference
lastPlayedPositionintread-onlylastPlayedPositionChangedResume position in ms — Settings Reference
lastPlayedPlaylistQStringread-onlylastPlayedPlaylistChangedPlaylist to resume — Settings Reference
musicButtonDefaultPageQStringread-onlymusicButtonDefaultPageChangedView the music nav button opens: "mediaRoom" / "mediaPlayer" — Settings Reference
returnToLibraryAfterSelectionboolread-onlyreturnToLibraryAfterSelectionChangedKeep the library open after selecting a track; false opens Now Playing — Settings Reference
showWaveformVisualizerboolread-onlyshowWaveformVisualizerChangedShow the FFT waveform on the player — Settings Reference
show3DButtonTiltboolread-onlyshow3DButtonTiltChanged3D tilt effect on buttons — Settings Reference
show3DAlbumPreviewboolread-onlyshow3DAlbumPreviewChangedShow previous/next album art side cards — Settings Reference
roundedAlbumArtboolread-onlyroundedAlbumArtChangedRound the album-art corners — Settings Reference
albumArtCornerRadiusintread-onlyalbumArtCornerRadiusChangedCorner radius in px when roundedAlbumArt is on — Settings Reference
showAlbumArtShadowboolread-onlyshowAlbumArtShadowChangedDrop shadow under album art — Settings Reference
vinylRecordModeboolread-onlyvinylRecordModeChangedSpin the album art like a record — Settings Reference
audioOutputDeviceQStringread-onlyaudioOutputDeviceChangedThe audio output picked in Settings > Media (a QAudioDevice id); empty = the system default — Settings Reference
albumArtTransitionQStringread-onlyalbumArtTransitionChangedTrack-change animation ("Crossfade", "Slide", "Vinyl Lift", "Flip", "Coverflow", …) — Settings Reference
backgroundOverlayOpacityintread-onlybackgroundOverlayOpacityChangedOpacity (0–100) of the dark overlay on the background — Settings Reference
sideCardOpacitydoubleread-onlysideCardOpacityChangedOpacity of the 3D side cards — Settings Reference
sideCardAngleintread-onlysideCardAngleChangedRotation angle of the 3D side cards — Settings Reference
buttonTiltDurationintread-onlybuttonTiltDurationChangedButton tilt animation duration in ms — Settings Reference
textScrollSpeedintread-onlytextScrollSpeedChangedMarquee scroll speed for long titles — Settings Reference
obdBluetoothPortQStringread-onlyobdBluetoothPortChangedOBD adapter identifier: serial port / COM port / /dev path, or BLE MAC on Android — Settings Reference
obdSavedAdaptersQVariantListread-onlyobdSavedAdaptersChangedRemembered {name, mac} adapters (stored as a JSON string), most recent first — Settings Reference
obdFastModeboolread-onlyobdFastModeChangedAdapter fast-mode option, applied at the next connection; on-screen demand independently selects the PIDs — Settings Reference
obdCardStyleCircularboolread-onlyobdCardStyleCircularChangedCircular gauges instead of square cards on the OBD parameter grid (default false)
gaugeTempUnit, gaugeSpeedUnitQStringread-onlygaugeTempUnitChanged, gaugeSpeedUnitChangedUnits the gauges and dashboards show: "C" | "F" (default C), "mph" | "km/h" (default mph); ParameterCatalog converts
obdAutoReconnectAttemptsintread-onlyobdAutoReconnectAttemptsChangedMax automatic reconnect attempts before giving up — Settings Reference
fuelTankCapacityfloatread-onlyfuelTankCapacityChangedLegacy tank-capacity setting in gallons; no current consumer uses it — Settings Reference
homeOBDParametersQVariantListread-onlyhomeOBDParametersChangedOrdered list of PID ids shown on the home screen — Settings Reference
maxHomeObdParametersintconstant—Most home-screen OBD cards (8)
customThemesQVariantListread-onlycustomThemesChangedNames of user-saved themes — Settings Reference
customThemeDataQVariantMapread-onlycustomThemesChangedEvery saved custom theme, name → theme object, as on disk; Main.qml assigns it to Style.customThemes
directoryHistoryQVariantListread-onlydirectoryHistoryChangedRecently used media folders (max 10) — Settings Reference
windowStateQStringread-onlywindowStateChanged"windowed" / "fullscreen" / "maximized" — Settings Reference
lastSettingsSectionQStringread-onlylastSettingsSectionChangedSettings section to reopen (e.g. "mediaSettings") — Settings Reference
androidAutoEnabledboolread-onlyandroidAutoEnabledChangedShow the Android Auto page — Settings Reference
phoneMirrorEnabledboolread-onlyphoneMirrorEnabledChangedShow the Phone Mirror page — Settings Reference
scrcpyDisplaySizeQStringread-onlyscrcpyDisplaySizeChangedVirtual display "WxH" or "auto" for mirroring; "" mirrors the phone screen — Settings Reference
scrcpyAudioGaindoubleread-onlyscrcpyAudioGainChangedLinear gain applied to phone audio before OCTAVE volume — Settings Reference
scrcpyAudioDuckEnabledboolread-onlyscrcpyAudioDuckEnabledChangedDuck local media while the phone produces sound — Settings Reference
scrcpyAudioDuckLeveldoubleread-onlyscrcpyAudioDuckLevelChangedDuck factor (linear, e.g. 0.1 = -20 dB) — Settings Reference
scrcpyAudioGainDb, scrcpyAudioDuckLevelDbdoubleread-onlyscrcpyAudioGainChanged, scrcpyAudioDuckLevelChangedThe same two levels in dB (20 log10; silence −120), as the Phone Audio sliders show them
scrcpyPhoneScreenOffboolread-onlyscrcpyPhoneScreenOffChangedKeep the handset panel dark while mirroring — Settings Reference
scrcpyDisplayDpiintread-onlyscrcpyDisplayDpiChangedVirtual display density, 0 = auto — Settings Reference
scrcpyBitRateUsb, scrcpyBitRateWifiintread-onlyscrcpyBitRateUsbChanged, scrcpyBitRateWifiChangedMirror video bit rate per link, Mbps — Settings Reference
scrcpyAutoWifiboolread-onlyscrcpyAutoWifiChangedEnable adb over Wi-Fi on a USB phone — Settings Reference
scrcpyBitRateAutoboolread-onlyscrcpyBitRateAutoChangedAdaptive mirror bit rate — Settings Reference
scrcpyWirelessAddressQStringread-onlyscrcpyWirelessAddressChangedPhone last connected over Wi-Fi — Settings Reference
esp32VolumeEnabledboolread-onlyesp32VolumeEnabledChangedEnable the ESP32 rotary knob — Settings Reference
esp32VolumePortQStringread-onlyesp32VolumePortChangedSerial port of the ESP32 (default "" = auto-select the ESP32-S3 at startup) — Settings Reference
esp32VolumeStepSizedoubleread-onlyesp32VolumeStepSizeChangedVolume percent per encoder tick (float, default 1.0; fractional steps such as 0.25 persist) — Settings Reference
esp32AutoReconnectboolread-onlyesp32AutoReconnectChangedReconnect automatically when the knob is unplugged/replugged — Settings Reference
esp32LedSleepEnabledboolread-onlyesp32LedSleepEnabledChangedLet the knob LED sleep when idle — Settings Reference
esp32LedColorModeQStringread-onlyesp32LedColorModeChanged"theme" / "static" LED colour source — Settings Reference
esp32LedStaticColorQStringread-onlyesp32LedStaticColorChangedHex colour used when esp32LedColorMode is static — Settings Reference
imuEnabledboolread-onlyimuEnabledChangedEnable the BerryIMU sensor — Settings Reference
sensorEmitRateintread-onlysensorEmitRateChangedIMU emit rate in Hz (10–120, default 60); BerryIMUManager follows it — Settings Reference
sensorDecimalPlacesintread-onlysensorDecimalPlacesChangedSensors page precision, 0–4 (default 1)
sensorTempUnitQStringread-onlysensorTempUnitChanged"F" (default) or "C"
sensorAltitudeUnitQStringread-onlysensorAltitudeUnitChanged"m" (default) or "ft"
sensorCardsQVariantMapread-onlysensorCardsChangedWhich Sensors page readouts show: Pitch, Roll, Heading, GForce, Altitude, Temperature → bool (saved as sensorShow<card>)
gestureSensorEnabledboolread-onlygestureSensorEnabledChangedEnable the PAJ7620U2 gesture sensor — Settings Reference
gestureVolumeStepintread-onlygestureVolumeStepChangedVolume percent per volume gesture — Settings Reference
gestureCooldownintread-onlygestureCooldownChangedMinimum ms between accepted gestures — Settings Reference
pinnedSettingsQVariantListread-onlypinnedSettingsChangedSetting ids pinned to the Quick Panel — Settings Reference

Invokables & Slots

SignatureReturnsDescription
save_device_name(QString name)voidSave deviceName, then emit deviceNameChanged
save_font_setting(QString font)voidSave fontSetting, then emit fontSettingChanged
save_theme_setting(QString theme)voidSave themeSetting, then emit themeSettingChanged
save_ui_scale(float scale)voidSave uiScale, then emit uiScaleChanged
save_color_transition_ms(int ms)voidSave colorTransitionMs, then emit colorTransitionMsChanged
save_song_length_transition(bool enabled)voidSave songLengthTransition, then emit songLengthTransitionChanged
save_show_clock(bool show)voidSave showClock, then emit showClockChanged
save_clock_format(bool is24hour)voidSave clockFormat24Hour, then emit clockFormatChanged
save_clock_show_seconds(bool show)voidSave clockShowSeconds, then emit clockShowSecondsChanged
save_clock_size(int size)voidSave clockSize, then emit clockSizeChanged
save_clock_size_auto(bool autoSize)voidPersist clockSizeAuto, then emit clockSizeAutoChanged
save_background_grid(QString grid)voidSave backgroundGrid, then emit backgroundGridChanged
save_screen_width(int width)voidSave screenWidth clamped to 400–7680 (kMin/kMaxScreenWidth), then emit screenWidthChanged; an unchanged value does nothing
save_screen_height(int height)voidSave screenHeight clamped to 300–4320, then emit screenHeightChanged; an unchanged value does nothing
save_background_blur_radius(int radius)voidSave backgroundBlurRadius, then emit backgroundBlurRadiusChanged
save_bottom_bar_orientation(QString orientation)voidSave bottomBarOrientation, then emit bottomBarOrientationChanged
save_show_bottom_bar_media_controls(bool show)voidSave showBottomBarMediaControls, then emit showBottomBarMediaControlsChanged
save_settings_layout_style(QString style)voidSave settingsLayoutStyle, then emit settingsLayoutStyleChanged
set_album_art_colors(QString colorsJson)voidCache the latest extracted palette JSON so the theme survives a restart
save_start_volume(float volume)voidSave startUpVolume, then emit startUpVolumeChanged
setCurrentVolume(int volume)voidStore the live volume percent and emit currentVolumeChanged (not written to disk). Call volumeController.applyVolume() instead of this from QML
save_media_folder(QString folderPath)voidSave mediaFolder, then emit mediaFolderChanged
save_media_folder_url(QUrl url)boolSave a picked folder: file:// or an Android external-storage content:// tree mapped to its /storage path (src/util/pathurl.h); false, nothing saved, when it can't be a path
save_auto_play_on_startup(bool enabled)voidSave autoPlayOnStartup, then emit autoPlayOnStartupChanged
save_persist_shuffle_state(bool enabled)voidSave persistShuffleState, then emit persistShuffleStateChanged
save_last_shuffle_state(bool enabled)voidSave lastShuffleState, then emit lastShuffleStateChanged
save_last_played_song(QString filename)voidSave lastPlayedSong, then emit lastPlayedSongChanged
save_last_played_position(int positionMs)voidSave lastPlayedPosition, then emit lastPlayedPositionChanged
save_last_played_playlist(QString playlistName)voidSave lastPlayedPlaylist, then emit lastPlayedPlaylistChanged
save_playback_state(QString song, int positionMs, QString playlist)voidWrite song, position (ms) and playlist in one disk write for resume-on-launch
save_music_button_default_page(QString page)voidSave musicButtonDefaultPage, then emit musicButtonDefaultPageChanged
save_return_to_library_after_selection(bool returnToLibrary)voidSave returnToLibraryAfterSelection, then emit returnToLibraryAfterSelectionChanged
save_show_waveform_visualizer(bool enabled)voidSave showWaveformVisualizer, then emit showWaveformVisualizerChanged
save_show_3d_button_tilt(bool enabled)voidSave show3DButtonTilt, then emit show3DButtonTiltChanged
save_show_3d_album_preview(bool enabled)voidSave show3DAlbumPreview, then emit show3DAlbumPreviewChanged
save_rounded_album_art(bool enabled)voidSave roundedAlbumArt, then emit roundedAlbumArtChanged
save_album_art_corner_radius(int radius)voidSave albumArtCornerRadius, then emit albumArtCornerRadiusChanged
save_show_album_art_shadow(bool enabled)voidSave showAlbumArtShadow, then emit showAlbumArtShadowChanged
save_vinyl_record_mode(bool enabled)voidSave vinylRecordMode, then emit vinylRecordModeChanged
save_audio_output_device(QString id)voidSave audioOutputDevice (any id up to 512 characters, kept while unplugged; empty = system default), then emit audioOutputDeviceChanged
save_album_art_transition(QString transition)voidSave albumArtTransition, then emit albumArtTransitionChanged
save_background_overlay_opacity(int opacity)voidSave backgroundOverlayOpacity, then emit backgroundOverlayOpacityChanged
save_side_card_opacity(double opacity)voidSave sideCardOpacity, then emit sideCardOpacityChanged
save_side_card_angle(int angle)voidSave sideCardAngle, then emit sideCardAngleChanged
save_button_tilt_duration(int duration)voidSave buttonTiltDuration, then emit buttonTiltDurationChanged
save_text_scroll_speed(int speed)voidSave textScrollSpeed, then emit textScrollSpeedChanged
save_obd_bluetooth_port(QString port)voidSave obdBluetoothPort, then emit obdBluetoothPortChanged
add_obd_saved_adapter(QString name, QString mac)voidUpsert a {name, mac} entry (MAC upper-cased) at the front of obdSavedAdapters
remove_obd_saved_adapter(QString mac)voidDrop the entry with this MAC from obdSavedAdapters
save_obd_fast_mode(bool enabled)voidSave obdFastMode, then emit obdFastModeChanged
save_obd_card_style_circular(bool circular)voidSave obdCardStyleCircular, then emit obdCardStyleCircularChanged
save_gauge_temp_unit(QString unit), save_gauge_speed_unit(QString unit)voidSave a gauge unit (other values ignored), then emit its notify
save_obd_auto_reconnect_attempts(int attempts)voidSave obdAutoReconnectAttempts, then emit obdAutoReconnectAttemptsChanged
save_fuel_tank_capacity(float capacity)voidSave fuelTankCapacity, then emit fuelTankCapacityChanged
save_obd_parameter_enabled(QString parameter, bool enabled)voidLegacy per-PID enable flag, kept for settings-file compatibility; writes are debounced (800 ms) then obdParametersChanged fires. No longer drives polling (see obdManager.setParameterDemand)
save_supported_obd_parameters(QVariantList parameters)voidStore the PID list found by the last vehicle scan; emits supportedOBDParametersChanged
save_home_obd_parameters(QVariantList parameters)voidStore the ordered home-screen PID list (deduplicated, capped at 8); emits homeOBDParametersChanged
add_home_obd_parameter(QString id, int index = -1)boolInsert at index (-1 = end); false if already there or the grid is full
remove_home_obd_parameter(QString id)boolRemove a card; false if it isn't there
move_home_obd_parameter(int from, int to)boolMove a card; the ones in between shift (past the end = last)
save_to_directory_history(QString folderPath)voidPrepend a folder to directoryHistory (deduplicated, capped at 10)
remove_from_directory_history(QString folderPath)voidRemove a folder from directoryHistory
save_custom_theme(QString name, QVariantMap theme, QString albumArtSource)voidStore a theme object under name; optional albumArtSource records the art the palette came from. Emits customThemesChanged
delete_custom_theme(QString name)voidDelete a custom theme by name
save_window_state(QString state)voidPersist the window mode; ignores values other than windowed / fullscreen / maximized
set_last_settings_section(QString section)voidPersist which settings section was open; accepts the six current section ids (displaySettings, mediaSettings, obdSettings, accessoriesSettings, deviceSettings, about) plus the legacy androidAutoSettings / phoneMirrorSettings / volumeKnobSettings / gestureSensorSettings; anything else is ignored
save_settings_section_visibility(QString section, bool visible)voidShow/hide one settings section in the hub; emits settingsMenuVisibilityChanged
save_android_auto_enabled(bool enabled)voidSave androidAutoEnabled, then emit androidAutoEnabledChanged
save_phone_mirror_enabled(bool enabled)voidSave phoneMirrorEnabled, then emit phoneMirrorEnabledChanged
save_scrcpy_display_size(QString size)voidSave scrcpyDisplaySize, then emit scrcpyDisplaySizeChanged
save_scrcpy_audio_gain(double gain)voidSave scrcpyAudioGain, then emit scrcpyAudioGainChanged
save_scrcpy_audio_duck_enabled(bool enabled)voidSave scrcpyAudioDuckEnabled, then emit scrcpyAudioDuckEnabledChanged
save_scrcpy_audio_duck_level(double level)voidSave scrcpyAudioDuckLevel, then emit scrcpyAudioDuckLevelChanged
save_scrcpy_audio_gain_db(double db), save_scrcpy_audio_duck_level_db(double db)voidSave from dB (clamped to −12…+18 and −40…−6, kAudio*Db); the linear factor is what's stored
save_scrcpy_phone_screen_off(bool off)voidSave scrcpyPhoneScreenOff, then emit scrcpyPhoneScreenOffChanged
save_scrcpy_display_dpi(int dpi), save_scrcpy_bit_rate_usb(int mbps), save_scrcpy_bit_rate_wifi(int mbps), save_scrcpy_auto_wifi(bool enabled), save_scrcpy_bit_rate_auto(bool enabled)voidClamp and persist scrcpyDisplayDpi / scrcpyBitRateUsb / scrcpyBitRateWifi / scrcpyAutoWifi, then emit the matching changed signal
save_scrcpy_wireless_address(QString address)voidPersist scrcpyWirelessAddress (trimmed; no-op when unchanged), then emit scrcpyWirelessAddressChanged
save_esp32_volume_enabled(bool enabled)voidSave esp32VolumeEnabled, then emit esp32VolumeEnabledChanged
save_esp32_volume_port(QString port)voidSave esp32VolumePort, then emit esp32VolumePortChanged
save_esp32_volume_step_size(double stepSize)voidSave esp32VolumeStepSize, then emit esp32VolumeStepSizeChanged
save_esp32_auto_reconnect(bool enabled)voidSave esp32AutoReconnect, then emit esp32AutoReconnectChanged
save_esp32_led_sleep_enabled(bool enabled)voidSave esp32LedSleepEnabled, then emit esp32LedSleepEnabledChanged
save_esp32_led_color_mode(QString mode)voidSave esp32LedColorMode, then emit esp32LedColorModeChanged
save_esp32_led_static_color(QString color)voidSave esp32LedStaticColor, then emit esp32LedStaticColorChanged
save_imu_enabled(bool enabled)voidSave imuEnabled, then emit imuEnabledChanged
save_sensor_emit_rate(int hz)voidSave sensorEmitRate clamped to 10–120, then emit sensorEmitRateChanged (BerryIMUManager follows it)
save_sensor_decimal_places(int places), save_sensor_temp_unit(QString unit), save_sensor_altitude_unit(QString unit)voidSave and notify; places clamp to 0–4, a unit other than F/C or m/ft is ignored
save_sensor_card_visible(QString card, bool visible)voidShow or hide one Sensors page readout (an unknown card name is ignored); emits sensorCardsChanged
save_gesture_sensor_enabled(bool enabled)voidSave gestureSensorEnabled, then emit gestureSensorEnabledChanged
save_gesture_action(QString gesture, QString action)voidMap one gesture (e.g. "RIGHT") to an action (e.g. "next_track"); emits gestureMappingChanged
save_gesture_mapping(QVariantMap mapping)voidReplace the whole gesture → action map
reset_gesture_mapping()voidRestore the default gesture map
save_gesture_volume_step(int step)voidSave gestureVolumeStep, then emit gestureVolumeStepChanged
save_gesture_cooldown(int ms)voidSave gestureCooldown, then emit gestureCooldownChanged
toggle_pin_setting(QString settingId)voidPin/unpin a registry setting id on the Quick Panel; emits pinnedSettingsChanged
reset_to_defaults()voidWrite the factory defaults, reload every cached member from them exactly as the constructor does (populateMembers()) and emit every property signal
save_setting(QString key, QVariant value)voidGeneric write of any key; emits genericSettingChanged(key) (typed properties are not refreshed)
get_setting(QString key)QVariantRaw value of any key (undefined when missing); use get_setting_with_default() for a fallback
get_setting_with_default(QString key, QVariant defaultValue)QVariantRaw value of any key, or defaultValue when missing
get_obd_parameter_enabled(QString parameter, bool defaultVal)boolLegacy per-PID enable flag (default true when never set); no longer drives polling
get_supported_obd_parameters()QVariantListPID list saved by the last vehicle scan
get_directory_history()QVariantListSame list as the directoryHistory property
get_home_obd_parameters()QVariantListSame list as the homeOBDParameters property
get_auto_play_on_startup()boolReturns the current autoPlayOnStartup value (same as the property)
get_persist_shuffle_state()boolReturns the current persistShuffleState value (same as the property)
get_last_shuffle_state()boolReturns the current lastShuffleState value (same as the property)
get_last_played_song()QStringReturns the current lastPlayedSong value (same as the property)
get_last_played_position()intReturns the current lastPlayedPosition value (same as the property)
get_last_played_playlist()QStringReturns the current lastPlayedPlaylist value (same as the property)
get_last_settings_section()QStringReturns the current lastSettingsSection value (same as the property)
get_window_state()QStringReturns the current windowState value (same as the property)
get_music_button_default_page()QStringReturns the current musicButtonDefaultPage value (same as the property)
get_return_to_library_after_selection()boolReturns the current returnToLibraryAfterSelection value (same as the property)
flushPendingSave()voidWrite any coalesced (debounced) settings change to disk now; called at shutdown
get_android_auto_enabled()boolReturns the current androidAutoEnabled value (same as the property)
get_phone_mirror_enabled()boolReturns the current phoneMirrorEnabled value (same as the property)
get_scrcpy_display_size()QStringReturns the current scrcpyDisplaySize value (same as the property)
get_scrcpy_audio_gain()doubleReturns the current scrcpyAudioGain value (same as the property)
get_scrcpy_audio_duck_enabled()boolReturns the current scrcpyAudioDuckEnabled value (same as the property)
get_scrcpy_audio_duck_level()doubleReturns the current scrcpyAudioDuckLevel value (same as the property)
get_scrcpy_phone_screen_off()boolReturns the current scrcpyPhoneScreenOff value (same as the property)
get_scrcpy_display_dpi(), get_scrcpy_bit_rate_usb(), get_scrcpy_bit_rate_wifi(), get_scrcpy_auto_wifi(), get_scrcpy_bit_rate_auto()int (dpi, bit rates) / bool (auto Wi-Fi, auto bit rate)Return the current values (same as the properties)
get_scrcpy_wireless_address()QStringReturns the current scrcpyWirelessAddress value (same as the property)
get_esp32_volume_enabled()boolReturns the current esp32VolumeEnabled value (same as the property)
get_esp32_volume_port()QStringReturns the current esp32VolumePort value (same as the property)
get_esp32_volume_step_size()doubleReturns the current esp32VolumeStepSize value (same as the property)
get_esp32_auto_reconnect()boolReturns the current esp32AutoReconnect value (same as the property)
get_esp32_led_sleep_enabled()boolReturns the current esp32LedSleepEnabled value (same as the property)
get_esp32_led_color_mode()QStringReturns the current esp32LedColorMode value (same as the property)
get_esp32_led_static_color()QStringReturns the current esp32LedStaticColor value (same as the property)
get_show_waveform_visualizer()boolReturns the current showWaveformVisualizer value (same as the property)
get_imu_enabled()boolReturns the current imuEnabled value (same as the property)
get_gesture_sensor_enabled()boolReturns the current gestureSensorEnabled value (same as the property)
get_gesture_mapping()QStringGesture → action map as a JSON string
get_gesture_mapping_dict()QVariantMapGesture → action map as a JS object
is_setting_pinned(QString settingId)boolTrue if the id is in pinnedSettings
get_settings_registry()QStringJSON of the full settings registry (id, label, type, section, …) that drives the dynamic settings UI
get_pinned_settings_metadata()QStringJSON array of registry entries for every pinned setting
get_settings_menu_visibility()QStringSame JSON as the settingsMenuVisibility property
is_settings_section_visible(QString section)boolVisibility of one settings section (default true)
get_git_commit_hash()QStringShort HEAD hash of the checkout; packaged builds fall back to the hash baked in by CMake ("unknown" only when neither exists)
get_git_commit_date()QStringCommit date of HEAD
get_git_commit_message()QStringCommit subject of HEAD

Signals

SignalDescription
deviceNameChanged(QString value)Emitted after deviceName is saved
fontSettingChanged(QString value)Emitted after fontSetting is saved
themeSettingChanged(QString value)Emitted after themeSetting is saved
uiScaleChanged(float value)Emitted after uiScale is saved
colorTransitionMsChanged(int value)Emitted after colorTransitionMs is saved
songLengthTransitionChanged(bool value)Emitted after songLengthTransition is saved
showClockChanged(bool value)Emitted after showClock is saved
clockFormatChanged(bool value)Notify for clockFormat24Hour
clockShowSecondsChanged(bool value)Emitted after clockShowSeconds is saved
clockSizeChanged(int value)Emitted after clockSize is saved
clockSizeAutoChanged(bool value)Emitted after clockSizeAuto is saved
backgroundGridChanged(QString value)Emitted after backgroundGrid is saved
screenWidthChanged(int value)Emitted after screenWidth is saved
screenHeightChanged(int value)Emitted after screenHeight is saved
backgroundBlurRadiusChanged(int value)Emitted after backgroundBlurRadius is saved
bottomBarOrientationChanged(QString value)Emitted after bottomBarOrientation is saved
showBottomBarMediaControlsChanged(bool value)Emitted after showBottomBarMediaControls is saved
settingsLayoutStyleChanged(QString value)Emitted after settingsLayoutStyle is saved
albumArtColorsChanged()Emitted after albumArtColors is saved
settingsMenuVisibilityChanged()A settings section was shown/hidden
startUpVolumeChanged(QString value)Notify for startUpVolume; carries the value as a string (QString::number(volume)) although the property is float
currentVolumeChanged(int value)Emitted after currentVolume is saved
mediaFolderChanged(QString value)Emitted after mediaFolder is saved
autoPlayOnStartupChanged(bool value)Emitted after autoPlayOnStartup is saved
persistShuffleStateChanged(bool value)Emitted after persistShuffleState is saved
lastShuffleStateChanged(bool value)Emitted after lastShuffleState is saved
lastPlayedSongChanged(QString value)Emitted after lastPlayedSong is saved
lastPlayedPositionChanged(int value)Emitted after lastPlayedPosition is saved
lastPlayedPlaylistChanged(QString value)Emitted after lastPlayedPlaylist is saved
musicButtonDefaultPageChanged(QString value)Emitted after musicButtonDefaultPage is saved
returnToLibraryAfterSelectionChanged(bool value)Emitted after returnToLibraryAfterSelection is saved
showWaveformVisualizerChanged(bool value)Emitted after showWaveformVisualizer is saved
show3DButtonTiltChanged(bool value)Emitted after show3DButtonTilt is saved
show3DAlbumPreviewChanged(bool value)Emitted after show3DAlbumPreview is saved
roundedAlbumArtChanged(bool value)Emitted after roundedAlbumArt is saved
albumArtCornerRadiusChanged(int value)Emitted after albumArtCornerRadius is saved
showAlbumArtShadowChanged(bool value)Emitted after showAlbumArtShadow is saved
vinylRecordModeChanged(bool value)Emitted after vinylRecordMode is saved
audioOutputDeviceChanged(QString value)Emitted after audioOutputDevice is saved
albumArtTransitionChanged(QString value)Emitted after albumArtTransition is saved
backgroundOverlayOpacityChanged(int value)Emitted after backgroundOverlayOpacity is saved
sideCardOpacityChanged(double value)Emitted after sideCardOpacity is saved
sideCardAngleChanged(int value)Emitted after sideCardAngle is saved
buttonTiltDurationChanged(int value)Emitted after buttonTiltDuration is saved
textScrollSpeedChanged(int value)Emitted after textScrollSpeed is saved
obdBluetoothPortChanged(QString value)Emitted after obdBluetoothPort is saved
obdSavedAdaptersChanged()Emitted after obdSavedAdapters is saved
obdFastModeChanged(bool value)Emitted after obdFastMode is saved
obdAutoReconnectAttemptsChanged(int value)Emitted after obdAutoReconnectAttempts is saved
fuelTankCapacityChanged(float value)Emitted after fuelTankCapacity is saved
obdParametersChanged()The per-PID enabled map changed (debounced after save_obd_parameter_enabled)
homeOBDParametersChanged()Home-screen PID list changed
supportedOBDParametersChanged()Vehicle-scan PID list changed
directoryHistoryChanged()Recent folders list changed
customThemesChanged()A custom theme was saved or deleted
windowStateChanged(QString value)Emitted after windowState is saved
lastSettingsSectionChanged(QString value)Emitted after lastSettingsSection is saved
androidAutoEnabledChanged(bool value)Emitted after androidAutoEnabled is saved
phoneMirrorEnabledChanged(bool value)Emitted after phoneMirrorEnabled is saved
scrcpyDisplaySizeChanged(QString value)Emitted after scrcpyDisplaySize is saved
scrcpyAudioGainChanged(double value)Emitted after scrcpyAudioGain is saved
scrcpyAudioDuckEnabledChanged(bool value)Emitted after scrcpyAudioDuckEnabled is saved
scrcpyAudioDuckLevelChanged(double value)Emitted after scrcpyAudioDuckLevel is saved
scrcpyPhoneScreenOffChanged(bool value)Emitted after scrcpyPhoneScreenOff is saved
scrcpyDisplayDpiChanged(int), scrcpyBitRateUsbChanged(int), scrcpyBitRateWifiChanged(int), scrcpyAutoWifiChanged(bool), scrcpyBitRateAutoChanged(bool)Emitted after the matching setting is saved
scrcpyWirelessAddressChanged(QString value)Emitted after scrcpyWirelessAddress is saved
esp32VolumeEnabledChanged(bool value)Emitted after esp32VolumeEnabled is saved
esp32VolumePortChanged(QString value)Emitted after esp32VolumePort is saved
esp32VolumeStepSizeChanged(double value)Emitted after esp32VolumeStepSize is saved
esp32AutoReconnectChanged(bool value)Emitted after esp32AutoReconnect is saved
esp32LedSleepEnabledChanged(bool value)Emitted after esp32LedSleepEnabled is saved
esp32LedColorModeChanged(QString value)Emitted after esp32LedColorMode is saved
esp32LedStaticColorChanged(QString value)Emitted after esp32LedStaticColor is saved
imuEnabledChanged(bool value)Emitted after imuEnabled is saved
gestureSensorEnabledChanged(bool value)Emitted after gestureSensorEnabled is saved
gestureMappingChanged()Gesture → action map changed
gestureVolumeStepChanged(int value)Emitted after gestureVolumeStep is saved
gestureCooldownChanged(int value)Emitted after gestureCooldown is saved
pinnedSettingsChanged()Quick Panel pins changed
genericSettingChanged(QString key)Emitted by save_setting(key) with the key that was written

AssetStore — assetStore

src/util/assetstore.{h,cpp}. Supplies filesystem URLs for assets that external loaders such as Assimp cannot read from an Android APK.

SignatureReturnsDescription
localUrl(QString relativePath)QUrlResolve a path under frontend/assets/. Android copies it to AppDataLocation/asset-cache/ when absent or a different size; desktop returns the source file URL. Empty input or any .. returns an empty URL. Android also returns an empty URL if extraction fails; desktop can return a URL for a missing file.

Clock — clock

src/managers/clock.h — QML context property clock

Formats the bottom-bar clock from the current time and the clock settings.

Invokables & Slots

SignatureReturnsDescription
update_time()voidForce a re-evaluation now (the timer calls this every second)

Signals

SignalDescription
timeChanged(QString timeStr)New formatted time text. Evaluated every second by a QTimer, emitted only when the text changes (once a minute without seconds). Honours settingsManager.clockFormat24Hour / clockShowSeconds; emits "" once when showClock turns off. The same text is readable as the time property, which this signal notifies

DiagnosticsManager — diagnosticsManager

src/managers/diagnosticsmanager.h — QML context property diagnosticsManager

Field diagnostics behind Settings → Device → Diagnostics: read the recent log and get the log files off the head unit without a laptop.

Properties

PropertyTypeAccessNotify signalDescription
logDirQStringread-only, constant—<app data dir>/logs
appVersionQStringread-only, constant—App version (CMake PROJECT_VERSION)
backendNameQStringread-only, constant—Always "C++"; included in the clipboard / export header
deviceInfoQStringread-only, constant—OS, architecture and host name summary
lastExportPathQStringread-onlylastExportPathChangedFolder the last exportLogs() wrote ("" until it has run)
canOpenFolderboolread-only, constant—Desktop true, mobile false (no file manager to open)

Invokables & Slots

SignatureReturnsDescription
recentLogLines(int maxLines)QStringTail of the main log followed by the error log (last 256 KB read); default 200 lines
copyLogsToClipboard(int maxLines)boolHeader (version, backendName, device, time) plus recentLogLines() onto the clipboard; default 400 lines
exportLogs()QStringCopy every octave*.log* file plus device-info.txt into <Downloads>/OCTAVE-logs-<timestamp>/ (Android: /storage/emulated/0/Download). Returns the folder, "" on failure
openLogFolder()boolDesktop: open the log folder in the OS file manager
licenseText(QString name)QStringFull text of LICENSE or NOTICE (compiled-in resources); "" for any other name

Signals

SignalDescription
lastExportPathChanged()After a successful exportLogs()

NetworkManager — networkManager

src/managers/networkmanager.h — QML context property networkManager

WiFi / internet status, GitHub update check and git-based self-update. All probes run asynchronously.

Properties

PropertyTypeAccessNotify signalDescription
networkNameQStringread-onlynetworkNameChangedCurrent WiFi SSID / interface name
isConnectedboolread-onlyisConnectedChangedInternet reachability; polled every 30 s online, backing off to 2 min after repeated misses
updateStatusQStringread-onlyupdateStatusChangedResult of checkForUpdates(): "checking", "up-to-date", "update-available", "ahead", "diverged" or "error" ("" before the first check)
updateMessageQStringread-onlyupdateMessageChangedHuman-readable update status line
remoteCommitQStringread-onlyremoteCommitChangedShort hash of the newest commit on the GitHub main branch
remoteCommitMsgQStringread-onlyremoteCommitMsgChangedSubject of that remote commit
workingTreeDirtyboolread-onlyworkingTreeDirtyChangedTrue when the checkout has uncommitted changes; the UI hides self-update because it hard-resets the tree
selfUpdateStatusQStringread-onlyselfUpdateStatusChangedState of applySelfUpdate(): "idle", "fetching", "restart-required" or "error"
selfUpdateMessageQStringread-onlyselfUpdateMessageChangedProgress / result text of the self-update
canSelfUpdateboolread-onlycanSelfUpdateChangedTrue when running from a git checkout with git available

Invokables & Slots

SignatureReturnsDescription
refreshNetwork()voidRe-probe connectivity and network name now
checkForUpdates()voidQuery the GitHub API for the latest main commit and compare with local HEAD (same / behind / ahead / diverged)
applySelfUpdate()voidgit fetch + git reset --hard origin/main (+ cmake configure + build), with rollback on failure; refuses when the tree is dirty
restartApp()voidRelaunch the app with the same arguments and quit
shutdown_device()voidQuit OCTAVE and power the OS off (systemctl poweroff / sudo shutdown / shutdown /s)
cleanup()voidStop timers and kill any running git process (called at exit)

Signals

SignalDescription
networkNameChanged(QString name)Notify for networkName
isConnectedChanged(bool connected)Notify for isConnected
updateStatusChanged(QString status)Notify for updateStatus
updateMessageChanged(QString message)Notify for updateMessage
remoteCommitChanged(QString commit)Notify for remoteCommit
remoteCommitMsgChanged(QString msg)Notify for remoteCommitMsg
workingTreeDirtyChanged(bool dirty)Notify for workingTreeDirty
selfUpdateStatusChanged(QString status)Notify for selfUpdateStatus
selfUpdateMessageChanged(QString message)Notify for selfUpdateMessage
canSelfUpdateChanged(bool canUpdate)Notify for canSelfUpdate

VolumeController — volumeController

src/managers/volumecontroller.h — QML context property volumeController

The single entry point for volume and mute. Every slider, knob and gesture calls applyVolume(percent) or toggleMute(); the quadratic curve and its inverse live here (toLinear / toPercent), and UIs bind to percent / muted / effectivelyMuted without doing curve math. Rules (tests/cpp/tst_volumecontroller.cpp): raising the volume while muted unmutes, from any input (judged on the request, so “up” at 100 % counts); a UI that echoes percentChanged back into applyVolume does not re-dispatch; lowering or re-applying the same level stays muted; the mute toggle at 0 % restores the startup volume and unmutes instead of toggling; presses within 150 ms are ignored. Mute is in memory only.

Properties

PropertyTypeAccessNotify signalDescription
percentintread-onlypercentChangedThe live volume 0–100 (also settingsManager.currentVolume). Sliders bind to this
mutedboolread/writemutedChangedMute flag; main.cpp forwards it to mediaManager.setMuted, phoneMirrorManager.setMuted and the ESP32 mute LED
effectivelyMutedboolread-onlyeffectivelyMutedChangedmuted or percent == 0: what the mute icons show

Invokables & Slots

SignatureReturnsDescription
applyVolume(int percent)voidClamp to 0–100, store in percent and settingsManager.currentVolume, compute the quadratic-curve linear value and fan it out to every output: media and phone mirror take the linear value, the ESP32 LED ring takes the percent. Dispatched via volumeApplied. If the percent went up while muted, also unmutes
toLinear(float percent)floatPure curve math ((percent/100)^2) for QML previews; does not dispatch
toPercent(float linear)intThe inverse (round(sqrt(linear) * 100)), e.g. for the startup volume setting, which is stored linear. toPercentStatic is the inline C++ form SettingsManager uses
setMuted(bool muted)voidMute or unmute without touching the level
toggleMute()voidThe mute button (screen, ESP32 knob, gesture, command server). At 0 % restores toPercent(startUpVolume) and unmutes; otherwise flips. 150 ms debounce

Signals

SignalDescription
percentChanged(int percent), mutedChanged(bool muted), effectivelyMutedChanged()Property notifies; volumeApplied still fires on every applyVolume() except an echo of percentChanged, percentChanged only on a real change
volumeApplied(int percent, float linear)After every applyVolume(): clamped percent and the linear 0–1 value. main.cpp connects it to mediaManager.setVolume(linear), phoneMirrorManager.setVolume(linear) and esp32VolumeManager.send_volume_update(percent)

MediaManager — mediaManager

src/managers/mediamanager.h — QML context property mediaManager

Local playback (MP3 / M4A / MP4 / FLAC / OGG / OPUS / WAV) via QMediaPlayer: library scanning, playlists as sub-folders, tag metadata (TagLib — title / artist / album for every format, WAV via its ID3 chunk), cover extraction (MP3, M4A/MP4, FLAC, Ogg Vorbis and Opus; WAV has no art), palette extraction and playback-resume state.

Invokables & Slots

SignatureReturnsDescription
connect_settings_manager(QObject *)voidNo-op; the SettingsManager is wired with setSettingsManager() in src/appcore.cpp
_save_playback_state()voidWrite song / position / playlist to settings now (Main.qml calls it on close)
_clear_temp_files()voidDelete the extracted cover-art temp files
flush_metadata_store()voidWrite the persistent tag cache (<appdata>/metadata_cache.json) if it changed; called at shutdown
play_file(QString filename)voidPlay a file from the current playlist by filename (initialises the shuffled/ordered queue on first call)
next_track()voidSkip to the next track in the queue
previous_track()voidGo to the previous track
pause()voidPause playback
toggle_play()voidPlay/pause; starts the first track if nothing is loaded
setMuted(bool muted)voidFollows volumeController.mutedChanged (wired in src/appcore.cpp); call volumeController.toggleMute() from QML
toggle_shuffle()voidToggle shuffle and rebuild the queue
setVolume(float volume)voidSet the linear output volume 0.0–1.0 (called by VolumeController, not QML)
setDucking(float factor)voidTemporarily attenuate the output (1.0 = none, 0.1 = -20 dB) while the mirrored phone makes sound; independent of the user volume
set_position(int positionMs)voidSeek to a position in ms
extract_colors_from_image(QString imagePath)voidExtract an Album Art Capture palette from a local path or file:// URL, including phone album art
extract_colors_from_album_art(QString filename)voidRun the palette extraction for a file; the result goes to settingsManager.set_album_art_colors (or albumColorsExtracted without a settings manager)
scan_library(bool resetDisplayNames)voidRescan the library root for audio files and playlists; resetDisplayNames also rebuilds cleaned display names
set_library_root(QString path)voidPoint the library at another folder (must exist) and rescan
strip_filenames()voidRename files in the library to cleaned display names (progress via scanProgress)
select_playlist(QString name)voidMake a playlist (sub-folder or "All Music") the active song list
create_playlist(QString name)boolCreate a playlist sub-folder; false if it exists or the name is invalid
delete_playlist(QString name)boolDelete a playlist sub-folder and its files
move_song_to_playlist(QString filename, QString targetPlaylist)boolMove a file into another playlist folder
delete_song(QString filename)boolDelete a file from disk and the library; emits songDeleted
play_file_at_path(QString filePath)boolRescan, select the playlist containing the absolute path and play it
invalidate_stats_cache()voidForce the album / artist / total-duration stats to be recomputed on next read
get_media_files(bool emitSignal)QStringListFilenames in the library; emitSignal=false suppresses the mediaListChanged emit
get_formatted_duration(QString filename)QStringTrack duration as M:SS (reads tags on demand)
get_band(QString filename)QStringArtist from tags
get_album(QString filename)QStringAlbum from tags
get_album_art(QString filename)QStringfile:// URL of the extracted cover (cached per album), "" if none
get_current_file()QStringFilename of the current track
get_next_track_name()QStringFilename that next_track() would play
get_previous_track_name()QStringFilename that previous_track() would play
get_next_track_album_art()QStringCover URL of the next track
get_previous_track_album_art()QStringCover URL of the previous track
get_neighbor_album_arts()QStringList[previousArt, nextArt] for the 3D side cards
is_playing()boolCurrently playing
is_paused()boolCurrently paused
get_duration()floatDuration in ms of the current track
get_position()floatPosition in ms
is_muted()boolMirror of volumeController.muted
getVolume()floatLinear output volume 0.0–1.0
is_shuffled()boolShuffle state
get_playlist_names()QStringListAll playlist names including the combined "All Music"
get_current_playlist_name()QStringActive playlist name
get_current_song_list()QStringListFilenames of the active playlist in queue order
get_movable_playlist_names()QStringListPlaylist names excluding "All Music" (targets for move_song_to_playlist)
get_song_playlist_name(QString filename)QStringPlaylist folder the file actually lives in (not "All Music"); empty if unknown
get_song_file_path(QString filename)QStringAbsolute path for a filename in the library ("" if unknown)
get_full_file_path(QString filename)QStringAbsolute path, but only when the file exists on disk
get_display_name(QString filename)QStringCleaned display name (tags/stripped filename) for a file
get_default_media_dir()QStringThe default music folder for this OS
get_media_folder_name()QStringBasename of the current media folder
pick_browser_library()boolBrowser demo: opens the browser's folder picker and makes the folder picked the library for the visit (true); elsewhere false, so the caller opens a folder dialog
get_total_duration()QStringTotal library duration, formatted
get_album_count()intUnique album count
get_artist_count()intUnique artist count
sort_media_files(QString sortColumn, bool ascending)QStringListReturn the active list sorted by "title", "artist" or "album"

Signals

SignalDescription
playbackStateChanged(int state)QMediaPlayer playback state as an int: 0 stopped, 1 playing, 2 paused (forwarded from QMediaPlayer::playbackStateChanged)
playStateChanged(bool playing)true when playing, false on pause/stop
currentMediaChanged(QString filename)Filename of the track that just started
mediaListChanged(QStringList files)The visible song list (current playlist) was replaced
durationChanged(qint64 durationMs)Track length in ms became known
positionChanged(qint64 positionMs)Playback position in ms (100 ms timer)
metadataChanged(QString title, QString artist, QString album)Title / artist / album of the current track loaded from tags
durationFormatChanged(QString formatted)Duration formatted as M:SS
volumeChanged(float volume)Linear output volume 0.0–1.0
shuffleStateChanged(bool shuffled)Shuffle toggled
totalDurationChanged(QString formatted)Library total duration recalculated (formatted string)
albumCountChanged(int count)Unique album count recalculated
artistCountChanged(int count)Unique artist count recalculated
playlistsChanged()Playlist (sub-folder) set changed after a scan / create / delete
currentPlaylistChanged(QString name)Active playlist name changed
scanProgress(QString message)Terminal-style progress line during library scans, filename stripping and errors
albumColorsExtracted(QString jsonColors)JSON palette extracted from the current album art, emitted only when no SettingsManager is wired (tests); the app's path is settingsManager.albumArtColors
songDeleted(QString filename)A file was removed by delete_song()
audioOutputsChanged()The output list or the output in use changed; notify of the read-only properties audioOutputs (QVariantList of {id, name, isDefault}) and currentAudioOutput (QString, the name of the output playing)

AudioAnalyzer — audioAnalyzer

src/managers/audioanalyzer.h — QML context property audioAnalyzer

Pre-computes FFT bar levels for the waveform visualizer and replays them at the playback position. It decodes to 8 kHz mono and bin the 0–4 kHz magnitudes into 96 logarithmic bands, each at least one FFT bin wide (the first bands are linear until the log curve overtakes them, so no bar is permanently 0).

Properties

PropertyTypeAccessNotify signalDescription
levelsQVariantListread-onlyfftDataChangedThe current 96 bar levels (0–8)
numBarsintconstant—96

Invokables & Slots

SignatureReturnsDescription
setViewActive(bool active)voidA view showing the bars is on screen: the QML UI's consumer, setDemand("view", active). Nothing runs and no file is decoded while no consumer wants the bars
setDemand(QString consumer, bool wanted)voidA frontend's bars are on screen under its own consumer name; runs while any consumer wants them; released when its service connection closes
setPlaying(bool), setLocalFile(QString path), setPosition(qint64 ms)voidWhat is playing, fed by main.cpp from nowPlaying.playing, MediaManager::currentMediaChanged and MediaManager::positionChanged (local bars change at that 100 ms rate)
analyze_file(QString filePath)voidDecode a file and pre-compute FFT levels in 100 ms chunks off the GUI thread (QtConcurrent / ThreadPoolExecutor); a file requested mid-analysis is queued
update_position(float positionSeconds)voidSelect the chunk for a playback position (seconds) and emit fftDataChanged when active
set_active(bool active)voidEnable/disable emission; disabling emits a row of zeros to clear the visualizer
get_current_levels()QVariantListLast emitted bar levels
get_num_bars()intNumber of bars (96)
set_live(bool live)voidSwitch between file analysis and live phone PCM (main.cpp, from nowPlaying.source); resets the live buffers on a mode change
update_live()voidPublish spectrum levels for the phone audio currently being heard; run by the analyzer's own 50 ms timer while live and shown
feed_live_pcm(QByteArray pcm, int bufferedMs)voidSlot connected in main.cpp. Receives s16le 48 kHz stereo PCM handed to the output sink and its queued delay from PhoneMirrorManager.audioPlayed
is_analyzed()boolTrue when FFT data for the current file is ready
clear()voidDrop the pre-computed data and reset the levels

Signals

SignalDescription
fftDataChanged(QVariantList levels)96 bar levels (ints 0–8) for the current playback position
analysisComplete()FFT pre-computation of the requested file finished
analysisStarted()FFT pre-computation started

OBDManager — obdManager

src/managers/obdmanager.h — QML context property obdManager

OBD-II diagnostics over an ELM327 adapter: USB / Bluetooth serial on desktop (worker thread), BLE GATT on Android. Base parameters have named signals; extended multi-value parameters use obdParameterChanged(QString, float). PID numbers, command names and decoders come from ELM327Protocol::buildPidTable(), which carries all 82 mode-01 commands plus ELM_VOLTAGE; polling is demand-driven: only the PIDs that registered consumers (dashboard, Parameter Cards, Home, editor, settings list) ask for via setParameterDemand() are polled, plus an RPM heartbeat, filtered to what this session's scan found. Changes apply on a live connection without reconnecting (the worker's poll list is swapped via updatePidsToWatch(), on Android via rebuildAndroidPollList()). See OBD Manager → Which PIDs Get Polled.

Mobile / build-variant differences
On Android the same class bypasses the serial worker and talks BLE through OctaveOBDBridge.java (JNI); the QML-facing API is identical. Connect chains the 0100 through 01C0 supported-PID bitmaps so default PIDs above 0x20 (fuel level, module voltage, oil temperature) and the multi-value PIDs are polled, the first poll slot reads the VIN, and the bridge requests BLUETOOTH_CONNECT on the first Connect tap (the former requestAndroidBluetoothPermission() helper is gone).

Properties

PropertyTypeAccessNotify signalDescription
connectedboolread-onlyconnectionStatusChangedTrue while the adapter is connected and initialised
connectionStatusQStringread-onlyconnectionStatusChangedLast connectionStatusChanged value ("Disconnected" initially; "Connecting", "Connected", "No Vehicle", "Reconnecting", "Connection Failed", "Stale Connection", "Device Lost", "Error", …); cached from the signal
connectionStateConnectionStateread-onlyconnectionStatusChangedDisconnected / Connecting / Connected / NoVehicle / Failed, classified from connectionStatus (OBDManager::stateFor); QML: import OCTAVE.OBD 1.0, OBDManager.Connecting
connectionDetailQStringread-onlyconnectionStatusDetailChangedLast connectionStatusDetailChanged message, bound by the Connection card
connectionProgressintread-onlyconnectionProgressChangedLast connectionProgressChanged percent (0–100)
connectionLogQStringListread-onlyconnectionLogChangedThe last 60 connection log lines, oldest first; OBDHome and the OBD settings page bind it (clearConnectionLog() empties it)
availableAdaptersQVariantListread-onlyavailableAdaptersChangedRich [{name, identifier, kind}, …] list bound by the OBD settings page; kind is ble, serial-rfcomm, serial-usb, com, tty or serial. On Android the list is the phone's bonded devices from OctaveOBDBridge.bondedDevices(), named "<name> · <MAC>"; it stays empty until BLUETOOTH_CONNECT is granted, which the bridge requests on the first Connect tap
vinQStringread-onlyvinChanged17-character VIN read at connect (Mode 09 PID 02); "" when the vehicle reports none
vehicleMakeQStringread-onlyvinChangedManufacturer decoded from the VIN's WMI; "" if unknown
vehicleModelYearintread-onlyvinChangedModel year from VIN position 10; 0 if unknown
vehicleSupportedParametersQStringListread-onlyvehicleSupportedParametersChangedThis session's scan result in catalog ids (base commands + multi-value signals, plus any alias whose target is in it, e.g. IGNITION_TIMING with TIMING_ADVANCE); [] until the scan finishes and again after disconnect. Never loaded from the persisted supportedOBDParameters
vehicleScanCompleteboolread-onlyvehicleSupportedParametersChangedTrue once this session's scan finished (even with an empty result); false while disconnected

Invokables & Slots

SignatureReturnsDescription
isConnected()boolProperty getter for connected
is_connected()boolsnake_case alias of isConnected() used by the QML
connect_obd()voidStart a connection attempt (named to avoid QObject::connect)
reconnect()voidTear down and reconnect, resetting the attempt counter
force_connect()voidReset the attempt counter, clear any wedged in-progress flag and connect now
close()voidDisconnect, stop scanning/watchdog timers and suppress auto-reconnect
reset_connection()voidAlias of force_connect()
get_connection_status()QStringSame value as the connectionStatus property — the connectionStatusChanged vocabulary; the settings-page status dot keys its colour map on it
getConnectionStatus()QStringcamelCase alias backing the connectionStatus property
refresh_ports()voidRun the port discovery sweep now
get_available_ports()QVariantListSweep and return the plain port list
scan()voidTrigger a discovery sweep (alias of refresh_ports); the name QML uses
availableAdapters()QVariantListGetter for the availableAdapters property
connect_to_adapter(QString identifier)voidSingle entry point of the OBD settings page: normalise the identifier (MAC / /dev path / COM), save it, rfcomm bind on Linux when given a MAC, then force_connect()
connect_direct(QString mac, int channel = 1)voidLinux: connect over a direct Bluetooth RFCOMM socket; saves rfcomm://<MAC>[/<channel>] as the OBD port and goes through connect_to_adapter() (no bind)
platform_hint()QString"linux" / "macos" / "windows" / "android" / "ios"; drives hint copy only, never structural branching
setParameterDemand(QString consumer, QStringList paramIds)voidReplace one consumer's wanted parameter ids (empty list removes it). The poll set is the union of all consumers, filtered to vehicleSupportedParameters, plus the RPM heartbeat (ELM_VOLTAGE if the car has no RPM); BerryIMU and unknown ids are ignored. Debounced 250 ms, applied live
setBackgroundDemand(QString consumer, QStringList paramIds)voidLow-priority demand: same rules minus the heartbeat and the foreground PIDs, polled one PID per pass of the foreground list (OBDManager::backgroundPidsToWatch()). Used by TripRecorder for its sweep
scan_vehicle()voidProbe every known PID on the worker thread (Android: answer from the supported-PID bitmaps read at connect time); progress via scanProgressChanged/scanOutputChanged, result via scanCompleteChanged
is_scanning()boolA vehicle scan is running
get_all_parameter_names()QStringListEvery single-value PID command name (COOLANT_TEMP, RPM, …), sorted, from the decoder table; multi-value ids are not included
get_supported_commands()QVariantListPID names found by the last scan
enable_scanned_parameters(QVariantList paramNames)voidSet the legacy per-PID enable keys for a list of PID names (no longer affects polling)
enable_all_supported()voidSet the legacy per-PID enable keys for every PID the last scan found (no longer affects polling)
enter_diagnostic_mode()voidPause live polling so DTC commands get the bus
exit_diagnostic_mode()voidResume live polling (after a short delay)
is_diagnostic_mode()boolDiagnostic mode active
read_dtc()voidRead stored DTCs (Mode 03) → dtcCodesChanged, dtcCountChanged. This and the four DTC / status / freeze-frame slots below run on the desktop worker thread; on Android (no worker) they log once and return
read_current_dtc()voidRead pending DTCs (Mode 07)
read_status()voidRead MIL state and DTC count (Mode 01 PID 01) → milStatusChanged, dtcCountChanged
clear_dtc()voidClear codes (Mode 04) → dtcClearResult
read_freeze_frame()voidRead freeze frame 0 (Mode 02): the code that stored it and its recorded values → freezeFrameChanged
read_vin()voidRead the VIN again (Mode 09 PID 02) → vinChanged; runs on Android too (next poll slot)
get_dtc_codes()QVariantListLast DTC list
get_dtc_count()intLast DTC count
get_mil_status()boolLast MIL state
get_freeze_frame()QVariantListLast freeze-frame list
coolantTemp()floatLast value of the coolantTemp PID (0 until read)
voltage()floatLast value of the voltage PID (0 until read)
engineLoad()floatLast value of the engineLoad PID (0 until read)
throttlePosition()floatLast value of the throttlePosition PID (0 until read)
intakeTemp()floatLast value of the intakeTemp PID (0 until read)
timingAdvance()floatLast value of the timingAdvance PID (0 until read)
massAirFlow()floatLast value of the massAirFlow PID (0 until read)
speedMPH()floatLast value of the speedMPH PID (0 until read)
rpm()floatLast value of the rpm PID (0 until read)
airFuelRatio()floatLast value of the airFuelRatio PID (0 until read)
fuelLevel()floatLast value of the fuelLevel PID (0 until read)
intakeManifoldPressure()floatLast value of the intakeManifoldPressure PID (0 until read)
shortTermFuelTrim()floatLast value of the shortTermFuelTrim PID (0 until read)
longTermFuelTrim()floatLast value of the longTermFuelTrim PID (0 until read)
oxygenSensorVoltage()floatLast value of the oxygenSensorVoltage PID (0 until read)
fuelPressure()floatLast value of the fuelPressure PID (0 until read)
engineOilTemp()floatLast value of the engineOilTemp PID (0 until read)
ignitionTiming()floatLast value of the ignitionTiming PID (0 until read)
refresh_values()voidRe-emit the current value of every watched PID (no-op when disconnected); the home screen calls it after homeOBDParametersChanged
open_bluetooth_settings()voidDesktop: no-op. Android: opens the system Bluetooth settings
set_target_address(QString address)voidPersist the identifier as obdBluetoothPort; the saved-port watcher then reconnects
set_auto_reconnect(bool enabled)voidDeprecated no-op — use settingsManager.obdAutoReconnectAttempts
set_connection_timeout(int timeoutSeconds)voidConnection timeout in seconds (clamped 5–60); it also bounds the vehicle-verify RPM request after ELM327 init (no obdConnectionTimeout settings key exists)
check_device_presence()boolCheck whether the configured port exists; emits devicePresenceChanged

Signals

SignalDescription
coolantTempChanged(float value)Coolant Temp — Mode 1 PID 0x05 (°C)
voltageChanged(float value)Control Module Voltage — Mode 1 PID 0x42 (V)
engineLoadChanged(float value)Engine Load — Mode 1 PID 0x04 (%)
throttlePositionChanged(float value)Throttle Position — Mode 1 PID 0x11 (%)
intakeAirTempChanged(float value)Intake Air Temp — Mode 1 PID 0x0F (°C)
timingAdvanceChanged(float value)Timing Advance — Mode 1 PID 0x0E (°)
massAirFlowChanged(float value)MAF — Mode 1 PID 0x10 (g/s)
speedMPHChanged(float value)Speed — Mode 1 PID 0x0D (mph)
rpmChanged(float value)RPM — Mode 1 PID 0x0C (rpm)
airFuelRatioChanged(float value)Air/Fuel Ratio — Mode 1 PID 0x44: commanded equivalence ratio (lambda) × 14.7
fuelLevelChanged(float value)Fuel Level — Mode 1 PID 0x2F (%)
intakeManifoldPressureChanged(float value)Intake Manifold Pressure — Mode 1 PID 0x0B (kPa)
shortTermFuelTrimChanged(float value)Short Term Fuel Trim 1 — Mode 1 PID 0x06 (%)
longTermFuelTrimChanged(float value)Long Term Fuel Trim 1 — Mode 1 PID 0x07 (%)
oxygenSensorVoltageChanged(float value)O2 Sensor B1S1 — Mode 1 PID 0x14 (V)
fuelPressureChanged(float value)Fuel Pressure — Mode 1 PID 0x0A (kPa)
engineOilTempChanged(float value)Oil Temp — Mode 1 PID 0x5C (°C)
ignitionTimingChanged(float value)Same value as timingAdvanceChanged (both are emitted from PID 0x0E)
runTimeChanged(float value)Run Time — Mode 1 PID 0x1F (s)
distanceWithMILChanged(float value)Distance w/ MIL — Mode 1 PID 0x21 (km)
fuelRailPressureChanged(float value)Fuel Rail Pressure (vac) — Mode 1 PID 0x22 (kPa)
fuelRailPressureDirectChanged(float value)Fuel Rail Pressure (direct) — Mode 1 PID 0x23 (kPa)
barometricPressureChanged(float value)Barometric Pressure — Mode 1 PID 0x33 (kPa)
ambientAirTempChanged(float value)Ambient Air Temp — Mode 1 PID 0x46 (°C)
relativeThrottlePosChanged(float value)Relative Throttle Pos — Mode 1 PID 0x45 (%)
absoluteThrottlePosBChanged(float value)Throttle Pos B — Mode 1 PID 0x47 (%)
acceleratorPosChanged(float value)Accelerator Pos D — Mode 1 PID 0x49 (%)
catalystTempB1S1Changed(float value)Catalyst Temp B1S1 — Mode 1 PID 0x3C (°C)
catalystTempB1S2Changed(float value)Catalyst Temp B1S2 — Mode 1 PID 0x3E (°C)
evapVaporPressureChanged(float value)Evap Vapor Pressure — Mode 1 PID 0x32
shortFuelTrim2Changed(float value)Short Fuel Trim 2 — Mode 1 PID 0x08 (%)
longFuelTrim2Changed(float value)Long Fuel Trim 2 — Mode 1 PID 0x09 (%)
o2SensorB1S2Changed(float value)O2 B1S2 — Mode 1 PID 0x15
o2SensorB2S1Changed(float value)O2 B2S1 — Mode 1 PID 0x18 (V)
o2SensorB2S2Changed(float value)O2 B2S2 — Mode 1 PID 0x19 (V)
distanceSinceCodesCleared(float value)Distance Since Codes Cleared — Mode 1 PID 0x31 (km)
warmupsSinceCodesCleared(float value)Warmups Since Codes Cleared — Mode 1 PID 0x30
absoluteLoadChanged(float value)Absolute Load — Mode 1 PID 0x43 (%)
commandedEGRChanged(float value)Commanded EGR — Mode 1 PID 0x2C (%)
egrErrorChanged(float value)EGR Error — Mode 1 PID 0x2D
ethanoPercentChanged(float value)Ethanol Percent — Mode 1 PID 0x52
o2SensorB1S3Changed(float value)O2 B1S3 — Mode 1 PID 0x16 (V)
o2SensorB1S4Changed(float value)O2 B1S4 — Mode 1 PID 0x17 (V)
o2SensorB2S3Changed(float value)O2 B2S3 — Mode 1 PID 0x1A (V)
o2SensorB2S4Changed(float value)O2 B2S4 — Mode 1 PID 0x1B (V)
o2S1WRVoltageChanged(float value)Wide-range O2 sensor 1 voltage — Mode 1 PID 0x24 (bytes C/D × 8 / 65535 V)
o2S2WRVoltageChanged(float value)Wide-range O2 sensor 2 voltage — Mode 1 PID 0x25 (bytes C/D × 8 / 65535 V)
o2S3WRVoltageChanged(float value)Wide-range O2 sensor 3 voltage — Mode 1 PID 0x26 (bytes C/D × 8 / 65535 V)
o2S4WRVoltageChanged(float value)Wide-range O2 sensor 4 voltage — Mode 1 PID 0x27 (bytes C/D × 8 / 65535 V)
o2S5WRVoltageChanged(float value)Wide-range O2 sensor 5 voltage — Mode 1 PID 0x28 (bytes C/D × 8 / 65535 V)
o2S6WRVoltageChanged(float value)Wide-range O2 sensor 6 voltage — Mode 1 PID 0x29 (bytes C/D × 8 / 65535 V)
o2S7WRVoltageChanged(float value)Wide-range O2 sensor 7 voltage — Mode 1 PID 0x2A (bytes C/D × 8 / 65535 V)
o2S8WRVoltageChanged(float value)Wide-range O2 sensor 8 voltage — Mode 1 PID 0x2B (bytes C/D × 8 / 65535 V)
o2S1WRCurrentChanged(float value)Wide-range O2 sensor 1 current — Mode 1 PID 0x34 (bytes C/D / 256 − 128 mA)
o2S2WRCurrentChanged(float value)Wide-range O2 sensor 2 current — Mode 1 PID 0x35 (bytes C/D / 256 − 128 mA)
o2S3WRCurrentChanged(float value)Wide-range O2 sensor 3 current — Mode 1 PID 0x36 (bytes C/D / 256 − 128 mA)
o2S4WRCurrentChanged(float value)Wide-range O2 sensor 4 current — Mode 1 PID 0x37 (bytes C/D / 256 − 128 mA)
o2S5WRCurrentChanged(float value)Wide-range O2 sensor 5 current — Mode 1 PID 0x38 (bytes C/D / 256 − 128 mA)
o2S6WRCurrentChanged(float value)Wide-range O2 sensor 6 current — Mode 1 PID 0x39 (bytes C/D / 256 − 128 mA)
o2S7WRCurrentChanged(float value)Wide-range O2 sensor 7 current — Mode 1 PID 0x3A (bytes C/D / 256 − 128 mA)
o2S8WRCurrentChanged(float value)Wide-range O2 sensor 8 current — Mode 1 PID 0x3B (bytes C/D / 256 − 128 mA)
catalystTempB2S1Changed(float value)Catalyst Temp B2S1 — Mode 1 PID 0x3D (°C)
catalystTempB2S2Changed(float value)Catalyst Temp B2S2 — Mode 1 PID 0x3F (°C)
throttlePosCChanged(float value)Throttle Pos C — Mode 1 PID 0x48 (%)
acceleratorPosEChanged(float value)Accelerator Pos E — Mode 1 PID 0x4A (%)
acceleratorPosFChanged(float value)Accelerator Pos F — Mode 1 PID 0x4B (%)
throttleActuatorChanged(float value)Throttle Actuator — Mode 1 PID 0x4C (%)
evaporativePurgeChanged(float value)Evaporative Purge — Mode 1 PID 0x2E (%)
fuelRailPressureAbsChanged(float value)Fuel Rail Pressure Abs — Mode 1 PID 0x59 (kPa)
fuelInjectTimingChanged(float value)Fuel Inject Timing — Mode 1 PID 0x5D
fuelRateChanged(float value)Fuel Rate — Mode 1 PID 0x5E (L/h)
runTimeMILChanged(float value)Run Time MIL — Mode 1 PID 0x4D (min)
timeSinceDTCClearedChanged(float value)Time Since DTC Cleared — Mode 1 PID 0x4E (min)
maxMAFChanged(float value)Max MAF — Mode 1 PID 0x50
fuelTypeChanged(float value)Fuel Type — Mode 1 PID 0x51
evapVaporPressureAbsChanged(float value)Evap Vapor Pressure Abs — Mode 1 PID 0x53
evapVaporPressureAltChanged(float value)Evap Vapor Pressure Alt — Mode 1 PID 0x54
shortO2TrimB1Changed(float value)Short O2 Trim B1 — Mode 1 PID 0x55 (%)
longO2TrimB1Changed(float value)Long O2 Trim B1 — Mode 1 PID 0x56 (%)
shortO2TrimB2Changed(float value)Short O2 Trim B2 — Mode 1 PID 0x57 (%)
longO2TrimB2Changed(float value)Long O2 Trim B2 — Mode 1 PID 0x58 (%)
relativeAccelPosChanged(float value)Relative Accel Pos — Mode 1 PID 0x5A (%)
hybridBatteryRemainingChanged(float value)Hybrid Battery — Mode 1 PID 0x5B
elmVoltageChanged(float value)ELM327 adapter supply voltage (V) from the adapter's own ATRV command (text reply such as 12.6V); polled like a PID
connectionStatusChanged(QString status)Status text changed
connectionStatusDetailChanged(QString detail)Detailed status message
connectionLostUnexpectedly(QString reason)A live link dropped on its own (not a user disconnect, port change, diagnostic-mode switch or shutdown); shown as the app-wide ErrorToast
connectionProgressChanged(int progress)Connection progress percent
devicePresenceChanged(bool present)Configured adapter detected / lost on the port scan
availablePortsChanged(QVariantList ports)Plain port-name list from the discovery sweep
availableAdaptersChanged(QVariantList adapters)Same sweep, rich {name, identifier, kind} shape
supportedCommandsChanged(QVariantList commands)PID names the vehicle answered during the scan
scanProgressChanged(int progress, QString message)Vehicle scan progress percent and message
scanCompleteChanged(QVariantList supportedParams)Vehicle scan finished; list of supported PID names
vehicleSupportedParametersChanged()vehicleSupportedParameters / vehicleScanComplete changed (scan finished, or reset on disconnect)
scanOutputChanged(QString output)Terminal-style scan output line
dtcCodesChanged(QVariantList codes)Stored DTCs read ([{code, description}, …])
dtcCountChanged(int count)Number of stored DTCs
milStatusChanged(bool status)Check-engine lamp state
dtcClearResult(bool success, QString message)Clear-codes result (success, message)
freezeFrameChanged(QVariantList data)Freeze frame read: [{code, description, values: {paramId: value}}]
obdParameterChanged(QString paramId, float value)One value from a multi-value PID (0x61 and up: torque, boost, odometer, …); OBDParameterModel routes it by id
parameterSampled(QString paramId, float value)Every decoded reading, base or multi-value, by parameter id, on desktop and Android; the black box and the value store (paramStore) tap this
vinChanged(QString vin)VIN read at connect or by read_vin()
connectionLogLineAppended(QString line)One connection log line (kept in connectionLog)
connectionLogChanged()Notify for connectionLog

ParameterCatalog — parameterCatalog

src/managers/parametercatalog.h — QML context property parameterCatalog

The one table of display metadata for the 129 values a gauge can show: 120 OBD ids (the python-obd command names OBDManager emits on parameterSampled, which settings and dashboard files store), one alias (IGNITION_TIMING carries TIMING_ADVANCE) and the 8 BerryIMU readings. Decoders stay in ELM327Protocol; tests/cpp/tst_parametercatalog.cpp keeps the catalog's OBD ids equal to the decoders' and checks that frontend/OBDParameterModel.qml serves it unchanged (it has no table of its own; this one was generated from it and compared field by field before the switch). C++ reads it through the static ParameterCatalog::all() / find(id) / imuIds() / obdIds().

Properties

PropertyTypeAccessNotify signalDescription
parametersQVariantListconstant—Every parameter, in display order, as {id, title, shortTitle, unit, min, max, kind, decimals, source, aliasOf, group}; group is the system it belongs to (one of groups). kind is percentage | temperature | voltage | pressure | bidirectional | numeric (what WidgetCatalog matches widgets on); decimals is 0 or 1 for text readouts; source is "obd" or "imu"; shortTitle may be empty
displayParametersQVariantListread-onlydisplayParametersChangedThe same rows in the gauges' units (setDisplayUnits): unit, min and max converted, plus displayScale / displayOffset (value = raw × scale + offset; 1 / 0 when unchanged). Temperatures (every kind temperature row) by gaugeTempUnit, SPEED by gaugeSpeedUnit, ALTITUDE by sensorAltitudeUnit; OBDParameterModel serves gauges from it. parameters stays in each parameter's own unit
groupsQStringListconstant—The group values in the order pickers list them: Engine, Fuel & air, Temperatures, Electrical, Speed & motion, Emissions, Diagnostics, Sensors (the IMU)

Invokables & Slots

SignatureReturnsDescription
info(QString id)QVariantMapOne entry as in parameters (hash lookup); empty map for an unknown id
contains(QString id)boolWhether the id is in the catalog
toDisplay(QString id, QVariant value)QVariantA value in the gauges' units (the reference OBDParameterModel's scale/offset follow); invalid or non-numeric values and unknown ids pass through
setDisplayUnits(QString temp, QString speed, QString altitude)voidC++ only: src/appcore.cpp feeds SettingsManager's units; emits displayParametersChanged on a change

ParameterStore — paramStore

src/managers/parameterstore.h — QML context property paramStore, a QQmlPropertyMap

The latest value of every catalog id, one notifying key per id: bind paramStore.RPM or paramStore[id] and the binding re-evaluates only when that id changes; an id with no reading yet is undefined. src/main.cpp feeds it from obdManager.parameterSampled and the eight berryIMU signals; QML writes are rejected. Writes are coalesced: values land together every 33 ms (kFlushMs). A catalog alias (IGNITION_TIMING) is written whenever its target arrives. OBDParameterModel.liveValue(id) reads it for every gauge and card. Tests: tests/cpp/tst_parameterstore.cpp.

Invokables & Slots

SignatureReturnsDescription
get(QString id)QVariantCurrent value, or invalid / undefined if none yet
snapshot()QVariantMapEvery id that has a value → its value
ingest(QString id, float value)voidRecord a reading (lands at the next fold). Wired in src/appcore.cpp; tests and simulators call it too

Signals

SignalDescription
changed(QStringList ids)After each fold: the ids whose values were written. Per-key bindings do not need it; it is for consumers that want the batch

NowPlaying — nowPlaying

src/managers/nowplaying.h — QML context property nowPlaying

What is playing right now and the controls for it, whichever source owns OCTAVE's music: the phone (while mirroring, once phoneMirrorManager.mediaActive), Android Auto (built-in receiver) or OCTAVE's own player. It is also the arbiter: one source at a time, and only a user action changes it (Which source plays the music). Frontends bind to this instead of choosing between mediaManager and phoneMirrorManager themselves. The phone reports its position only now and then, so this owns the one clock that extrapolates it (every 500 ms, only while the phone plays). Values are raw: placeholder text such as "Nothing playing" is the frontend's choice (hasTrack). It also holds the hand-off (the phone taking the controls pauses local playback; a local track starting hands them back with releaseMedia(true), pausing the phone) and the Album Art Capture rule (the theme follows the live source's art). Tests: tests/cpp/tst_nowplaying.cpp.

Properties

PropertyTypeAccessNotify signalDescription
sourceQStringread-onlysourceChanged"local", "phone" or "androidauto"
playingboolread-onlyplayingChangedThe live source is playing
hasTrack, title, artist, albumbool, QStringread-onlytrackInfoChangedLocal: display name, artist, album of the current file. Phone: the media session's metadata (hasTrack false with no media app)
artUrlQStringread-onlyartUrlChangedAlbum art URL, "" when none (a file on the head unit; service clients fetch GET /art)
artRevisionintread-onlyartUrlChangedGoes up by one on every art change: the cache key for GET /art
durationMs, positionMsintread-onlydurationChanged, positionChangedLocal: the player's 10 Hz reports. Phone: each report, extrapolated every 500 ms while playing. 0 duration = unknown
canSeek, canShuffleboolread-onlycapabilitiesChangedcanShuffle is false on the phone (its shuffle belongs to its app)
shuffledboolread-onlyshuffledChangedLocal shuffle state

Invokables & Slots

SignatureReturnsDescription
togglePlay(), next(), previous()voidRouted to the live source (the gesture sensor uses these too)
seek(int positionMs)voidWhen canSeek; the position shows at once and the source confirms it
toggleShuffle()voidLocal only; does nothing while the phone or Android Auto is the source
useLocal()voidHand the music back to OCTAVE's own player (the Media Room's source pill); the phone or Android Auto pauses, nothing plays until asked
extractArtColors()voidTheme colours from the live source's art now (Media Room's "Save as Theme"). The Album Art Capture rule calls it on its own: while that theme is selected, whenever artUrl changes or the theme is chosen

Signals

SignalDescription
trackChanged()Another track or another source (for track-change animations); not emitted for play/pause, seeks or position

ShiftLightManager — shiftLightManager

src/managers/shiftlightmanager.h — QML context property shiftLightManager

The RPM shift light's rules, fed by OBDManager::rpmChanged (wired in src/appcore.cpp). A flag is an RPM band (rpmLow..rpmHigh, both inclusive) with a colour and effects, stored in the rpm_flags setting as a JSON string. When bands overlap the last matching flag wins. A legacy flag ({rpm} with no band) is migrated once on load to rpmLow = rpm, rpmHigh = rpm_max_rpm and written back. The flash timer runs here, so every frontend sees the same phase: a UI binds to active, activeFlag and lit and draws. All rpm_* settings are re-read when any of them changes. Tests: tests/cpp/tst_shiftlightmanager.cpp.

Properties

PropertyTypeAccessNotify signalDescription
enabledboolread-onlysettingsChangedrpm_shift_light_enabled (default true). Off means active is always false
showOnHomeCardboolread-onlysettingsChangedrpm_show_on_home_card (default true)
maxRpmintread-onlysettingsChangedrpm_max_rpm (default 8000): the redline, and the high bound given to migrated legacy flags
fullScreenFlashOpacitydoubleread-onlysettingsChangedrpm_fullscreen_flash_opacity (default 0.5): the fallback for flags without their own opacity
lampSize, glowSize, glowIntensitydoubleread-onlysettingsChangedrpm_shift_light_size (0.5), rpm_glow_size (0.6), rpm_glow_intensity (0.6)
colorTransitionSpeedintread-onlysettingsChangedrpm_color_transition_speed in ms (default 100)
pulseEnabledboolread-onlysettingsChangedrpm_pulse_enabled (default false)
flagsQVariantListread-onlyflagsChangedThe flags as stored, already migrated to bands. Write with setFlags()
rpmdoubleread-onlyrpmChangedLast RPM seen
activeboolread-onlyactiveFlagChangedA flag's band contains the RPM, and the light is enabled and not suppressed
activeIndexintread-onlyactiveFlagChangedIndex into flags, or -1
activeFlagQVariantMapread-onlyactiveFlagChangedThe active flag with every field filled in: color (#FF0000), flash (false), flashSpeed (100 ms), fullScreenFlash (false), fullScreenFlashOpacity (the global one), auraFlash (false), auraFlashOpacity (0.6), auraSpread (0.18). Empty when not active
litboolread-onlylitChangedThe light is on right now: active, and in the on phase if the flag flashes. A new flag always starts lit
suppressedboolread/writesuppressedChangedIn-memory override that forces the light dark without touching the saved setting (the dev screenshot stories use it)

Invokables & Slots

SignatureReturnsDescription
setRpm(double rpm)voidFeed a reading; re-matches the band. Connected to obdManager.rpmChanged in main.cpp
setFlags(QVariantList flags)voidSave the flags to rpm_flags (the RPM editor on OBDMenu calls this); applied live

Signals

SignalDescription
settingsChanged()Any rpm_* setting was re-read
flagsChanged()The stored flags changed
activeFlagChanged()Another flag (or none) became active, or the active one was edited. Not emitted while the RPM stays inside the same band
litChanged()On/off, including every flash toggle
rpmChanged(), suppressedChanged()Property notifies

TripRecorder — tripRecorder

src/managers/triprecorder.h — QML context property tripRecorder

The black box: every OBD reading of every drive into <config>/history/blackbox.sqlite, one CSV + JSON per trip under history/trips/. Trip detection and coalescing on the GUI thread, SQLite (TripStore) on its own thread; results come back as signals. See OBD Manager → Black Box and TripHistory.qml.

Properties

NameTypeNotifyDescription
enabledboolenabledChangedMirrors blackBoxEnabled
storeReadyboolstoreReadyChangedThe database opened; while false nothing is recorded and lastError says why
recordingboolrecordingChangedA trip is open
currentTripIdqint64recordingChangedId (= start time in ms) of the open trip, 0 when idle
currentTripStartMsqint64recordingChangedStart of the open trip
currentSampleCountintcurrentSampleCountChangedSamples stored this trip (updated on each flush)
currentTripElapsedSintcurrentTripElapsedSChangedSeconds since the trip being recorded started, 0 when none; moves once a second (the recorder's 1 s tick)
tripsQVariantListtripsChangedSummaries newest first: {id, startMs, endMs, startIso, endIso, durationS, open, clean, vin, make, modelYear, sampleCount, paramCount, distanceMiles, maxSpeed, maxRpm, maxCoolant, maxOilTemp, minVoltage, maxVoltage, fuelStart, fuelEnd, fuelUsedPct, eventCount, file, summaryFile} (no per-parameter list)
historyDir / tripsDirQStringhistoryDirChanged<config>/history and its trips/
storageBytesqint64storageBytesChangedDatabase (+ WAL) plus trip files
canOpenFolderboolconstantFalse on Android / iOS
lastExportPathQStringlastExportPathChangedCSV path of the last successful export
lastErrorQStringlastErrorChangedLast store error (database could not be opened, write failed)

Invokables & Slots

MethodReturnsDescription
recordSample(QString paramId, float value)voidOne reading (wired from obdManager.parameterSampled); starts a trip on RPM > 0, otherwise dropped until a trip is open
setConnected(bool), setVehicleParameters(QStringList), setVehicleIdentity(QString vin, QString make, int year), noteEvent(QString kind, QString detail), setEnabled(bool)voidInputs attach(OBDManager*) wires from the OBD manager and the settings
endTripNow()voidClose the open trip here (trip_end event "ended by user"); a new one starts on the next RPM > 0
refresh()voidRe-list trips and storage
requestDetail(qint64 id)void→ detailReady with the full summary (params, events); live for the open trip
requestSeries(qint64 id, QString paramId, int maxPoints = 400, double fromS = -1, double toS = -1)void→ seriesReady with [{t, v, lo, hi}]: seconds since start, bucket average, min, max. fromS / toS (seconds since start, negative = whole trip) window the query so a zoomed chart gets maxPoints buckets over just that span
requestHealthTrends(int days = 30)void→ healthTrendsReady: the closed trips that started in the last days days (0 = all), oldest first, as {days, fromMs, toMs, tripCount, metrics, params}. Each of metrics is a health number (warmupMin, settledCoolant, idleVoltage, chargingVoltage, idleRpm, ltft1, ltft2; see Health across drives) with title, unit, decimals, description, the usual range bandLo / bandHi (absent: none), rows [{id, startMs, v}], latest, recent (last three drives), baseline (the drives before, when there are three), status (ok / watch / none) and a note for a person. params: every parameter recorded in the window, {id, title, unit, trips}, most trips first
requestParamTrend(QString paramId, int days = 30)void→ paramTrendReady with [{id, startMs, v, lo, hi}]: one parameter's average, min and max per trip over the same window, from the stored summaries
deleteTrip(qint64 id)voidRows and files; the open trip is ended first
clearHistory()voidEverything but the trip being recorded
exportTrip(qint64 id)voidCopy the CSV + JSON into Downloads/OCTAVE-trips/ → exportFinished
openHistoryFolder()boolDesktop: open tripsDir in the file manager

Signals

SignalDescription
tripStarted(qint64 id)A trip opened
tripEnded(qint64 id, QVariantMap summary)Closed, summarised and written out
detailReady(qint64 id, QVariantMap detail), seriesReady(qint64 id, QString paramId, QVariantList points), exportFinished(qint64 id, QString path), healthTrendsReady(int days, QVariantMap result), paramTrendReady(QString paramId, int days, QVariantList rows)Answers to the requests above (path empty on failure)
enabledChanged(bool), storeReadyChanged(), recordingChanged(), currentSampleCountChanged(), tripsChanged(), historyDirChanged(), storageBytesChanged(), lastExportPathChanged(), lastErrorChanged(), currentTripElapsedSChanged()Property notifiers
liveTripChanged(qint64 id)New samples of the trip being recorded reached the store, at most once per 5 s: a view showing that trip re-requests its detail and series (the requests queue behind the write)

OBDAdapterFinder — obdAdapterFinder

src/managers/obdadapterfinder.h — QML context property obdAdapterFinder

Finds, pairs (answering the PIN itself through a BlueZ agent), trusts and connects a Bluetooth OBD-II adapter for frontend/OBDAdapterSheet.qml. See OBD Manager → Adapter Finder.

Properties

NameTypeNotifyDescription
supportedboolconstantDiscovery + pairing + connect work here (desktop Linux). False elsewhere; the sheet then falls back to obdManager.availableAdapters
canScanboolconstantstartScan() can look for adapters: supported on desktop; in the browser demo, whether the browser has Web Bluetooth (false in Firefox, Safari and Linux Chromium without its flag, where the sheet hides "Pick Bluetooth Adapter" and offers only the simulated car)
bluetoothOnboolbluetoothOnChangedA controller exists and is powered
scanningboolscanningChangedDiscovery running (15 s)
devicesQVariantListdevicesChanged[{address, name, rssi, kind: "classic"|"ble"|"dual", likelyObd, paired, connectable, note}]; likely adapters first, then by signal (rssi 0 = cached, not heard this scan)
busyAddressQStringbusyChangedAdapter being paired / connected, "" when idle
statusQStringstatusChangedHuman-readable progress or outcome
statusIsErrorboolstatusChangedstatus describes a failure

Invokables & Slots

SignatureReturnsDescription
startScan()voidClear the list and run Classic + LE discovery; no-op while pairing
stopScan()voidStop discovery (the sheet calls it on close; a pairing under way continues)
connectAdapter(QString address)voidPair with PINs 1234 / 0000 / 6789 / 1111, trust, look up the SPP channel, then obdManager.connect_direct() and a named saved-adapter chip
cancel()voidCancel pairing / channel lookup / scan and clear the status
powerOn()voidPower the Bluetooth controller on

Signals

SignatureDescription
bluetoothOnChanged()Controller powered on/off
scanningChanged()Discovery started or stopped
devicesChanged()The list changed (device found, signal updated, paired)
busyChanged()busyAddress changed
statusChanged()status / statusIsError changed

ESP32VolumeManager — esp32VolumeManager

src/managers/esp32volumemanager.h — QML context property esp32VolumeManager

Wireless rotary encoder over USB serial (115200 baud). Encoder ticks and button presses arrive as signals; src/appcore.cpp routes them through VolumeController, and pushes volume (send_volume_update), mute (send_mute_state) and the LED ring colour (send_theme_color: album-art accent in "theme" mode, esp32LedStaticColor in "static" mode, cyan fallback) back to the knob — including a full push 500 ms after the knob connects. ResourceError, DeviceNotFoundError, PermissionError, ReadError, WriteError and a rejected keepalive write are treated as a lost link and trigger auto-reconnect.

Mobile / build-variant differences
Mobile builds compile a no-op stub with the same signatures as desktop: all four properties, every slot below (get_available_ports() returns an empty list, get_connection_status() "Disconnected", get_connection_detail() "Not available on mobile", is_connected() false) and the five signals. QML still guards with typeof esp32VolumeManager.

Properties

PropertyTypeAccessNotify signalDescription
connectedboolread-onlyconnectionStatusChangedSerial link to the knob is open
connectionStatusQStringread-onlyconnectionStatusChanged"Connected" / "Disconnected" / "Connecting" / "Error"
connectionDetailQStringread-onlyconnectionDetailChangedHuman-readable detail (port, last error)
availablePortsQVariantListread-onlyavailablePortsChangedSerial ports found by the last scan, one {port, label, description, isEsp32S3} map each, ESP32-S3 first then by port, the OBD port left out; the Accessories page's picker binds it

Invokables & Slots

SignatureReturnsDescription
connect_device()voidOpen the configured (or auto-detected VID 303A) port at 115200 baud
disconnect_device()voidClose the serial port
get_available_ports()QVariantListScan and return availablePorts
is_connected()boolLink verified: an ESP32-S3 port is open, or another port has sent a knob command (only then does the manager write)
get_connection_status()QStringStatus text
get_connection_detail()QStringDetail text
refresh_ports()voidRescan ports now
reset_reconnect_attempts()voidZero the auto-reconnect attempt counter so reconnects resume
cleanup()voidStop timers and disconnect at exit

Signals

SignalDescription
connectionStatusChanged(QString status)Status text changed
connectionDetailChanged(QString detail)Detail message changed
availablePortsChanged(QVariantList ports)Port scan finished
volumeChangeRequested(float delta)Encoder turned: ± esp32VolumeStepSize × ticks; main routes it through VolumeController
muteToggleRequested()Encoder button pressed

BerryIMUManager — berryIMU

src/managers/berryimumanager.h — QML context property berryIMU

BerryIMU v3 (LSM6DSL accel/gyro, LIS3MDL mag, BMP388 baro) over I2C with a Madgwick AHRS on a worker thread (accel + gyro fusion only; the magnetometer feeds the heading readout). The Android build reads Qt Sensors instead. Five consecutive failed I2C block reads mark the bus dead: status "Error", then the usual retry / back-off. A permission-denied bus (EACCES / EPERM) logs a warning once (permission denied on /dev/i2c-N - add the user to the i2c group; not retrying), emits "Disconnected" and does not retry.

Mobile / build-variant differences
The Android build is a full QtSensors implementation with the identical API: setEnabled() follows imuEnabled like desktop (a persisted “off” stops the sensors when the SettingsManager is attached), connectionStatusChanged reports "Connected", "Unavailable" or "Disabled", setEmitRate() clamps to the same 10–120 Hz, and orientationChanged is synthesised as a yaw-stripped quaternion from the tared pitch / roll so CarMenu sees one convention.

Properties

PropertyTypeAccessNotify signalDescription
connectedboolread-onlyconnectionStatusChangedThe sensor read loop is running
hasTemperatureboolread-onlyhasTemperatureChangedA barometric temperature reading is available: always true on desktop; on Android it flips once Qt Sensors reports a value

Invokables & Slots

SignatureReturnsDescription
getConnectionStatus()QStringStatus text
setEnabled(bool enabled)voidStart/stop the sensor (runtime only, not saved). The manager calls it on settingsManager.imuEnabledChanged: QML saves with save_imu_enabled instead
isEnabled()boolEnabled flag
setEmitRate(int hz)voidSignal rate in Hz (clamped 10–120); the value is kept and applied to every worker the manager creates, so a call before start or across a retry is not lost. Driven by settingsManager.sensorEmitRate from startup
emitRate()intThe rate in Hz currently requested (C++ only)
setActive(bool active)voidDriven by setDemand: true while any consumer wants the IMU; false drops the worker to a 5 Hz idle rate
setDemand(QString consumer, bool wanted)voidA page showing IMU readings registers while on screen (frontend/ImuDemand.qml, consumer = its objectName); full rate while any consumer wants it
calibrateTare()voidTake the current orientation as the zero reference (CarMenu ZERO). Raises a request that the read thread services on its next pass; ignored with a log line when the loop is not running
resetTare()voidClear the tare (CarMenu RESET); serviced on the read thread while running, applied immediately otherwise
cleanup()voidStop the worker thread and close the I2C bus

Signals

SignalDescription
orientationChanged(float w, float x, float y, float z)Tared, yaw-stripped quaternion (w, x, y, z) from the Madgwick AHRS for the 3D vehicle model (Android: built from the tared pitch / roll)
pitchChanged(float pitch)Pitch in degrees
rollChanged(float roll)Roll in degrees
headingChanged(float heading)Compass heading 0–360
altitudeChanged(float altitude)Barometric altitude in metres
accelMagnitudeChanged(float mag)Total acceleration in g
lateralGChanged(float g)Side-to-side g
longitudinalGChanged(float g)Front-to-back g
baroTempChanged(float temp)Barometer temperature
connectionStatusChanged(QString status)"Connected" / "Disconnected" / "Error" (Android: "Connected" / "Unavailable" / "Disabled")
hasTemperatureChanged(bool has)Notify for hasTemperature

GestureManager — gestureSensor

src/managers/gesturemanager.h — QML context property gestureSensor

PAJ7620U2 I2C gesture sensor on a worker thread; gestures map to media actions. Directional / rotation / wave gestures are confirmed by a second register read 20 ms later: the sample is accepted when the re-read agrees or is empty (the sensor clears its flags on read) and discarded when it shows a different gesture. Five consecutive failed register reads mark the bus dead: status "Error", then retry / back-off. A permission-denied bus (EACCES / EPERM) logs a warning once (permission denied on /dev/i2c-N - add the user to the i2c group; not retrying), emits "Disconnected" and does not retry.

Mobile / build-variant differences
The mobile stub keeps the desktop signatures: connectionStatus property, every slot below (getConnectionStatus() returns "Disabled on mobile", getGestureAction() "none", isEnabled() false, setCooldown(int)) and the three signals including gestureDetected and connectionStatusChanged(QString).

Properties

PropertyTypeAccessNotify signalDescription
connectionStatusQStringread-onlyconnectionStatusChanged"Connected" / "Disconnected" (mobile stub: "Disabled on mobile"); read by the Accessories widget
gesturesQStringListconstant—The nine gestures the sensor reports, in settings-page order (gesturevocabulary.h)
actionsQVariantListconstant—{key, label} per action a gesture can trigger, none ("Disabled") last; the mobile stub has both

Invokables & Slots

SignatureReturnsDescription
getConnectionStatus()QStringStatus text
setGestureAction(QString gesture, QString action)voidMap a gesture to an action and persist it
getGestureAction(QString gesture)QStringAction mapped to a gesture
resetMappingToDefaults()voidRestore the default map (RIGHT→next_track, UP/CLOCKWISE→volume_up, FORWARD/WAVE→play_pause, BACKWARD→mute_toggle, …)
setEnabled(bool enabled)voidStart/stop the sensor (runtime only, not saved). The manager calls it on settingsManager.gestureSensorEnabledChanged: QML saves with save_gesture_sensor_enabled instead
setCooldown(int ms)voidMinimum ms between accepted gestures (runtime; follows gestureCooldownChanged). cooldownMs() reads it back (C++ only)
isEnabled()boolEnabled flag
cleanup()voidStop the worker thread and close the I2C bus

Signals

SignalDescription
gestureDetected(QString gesture)Raw gesture: RIGHT, LEFT, UP, DOWN, FORWARD, BACKWARD, CLOCKWISE, COUNTER-CLOCKWISE, WAVE
actionTriggered(QString action)Mapped action: next_track, previous_track, volume_up, volume_down, play_pause, mute_toggle (handled in main)
connectionStatusChanged(QString status)Sensor connection state changed

AndroidAutoManager — androidAutoManager

src/managers/androidautomanager.h — QML context property androidAutoManager

Android Auto with two backends, picked by the androidAutoBackend setting. Built-in ("native", implemented in src/managers/androidautomanager_native.cpp over src/android_auto/): OCTAVE is the head unit and speaks the Android Auto Protocol to the phone's head unit server through an adb forward; see Built-in Android Auto. Google DHU ("dhu", the default): the window/capture integration is incomplete (no window handle is discovered and click forwarding is a stub), and no current QML consumes image://dhuframe/; see platform status. adb is found by the same discovery as Phone Mirror (bundled platform-tools → PATH → SDK locations; PhoneMirrorManager::findAdb()), and only its own tcp:5277 forward is removed on setup / cleanup so a live mirror tunnel survives.

Experimental members
Every built-in backend member below (backend, nativeAvailable, nativeState, nativeStatus, phoneName, videoStreaming, certificateDir, videoSink, startNative, stopNative, injectTouch, setViewVisible, backendChanged, nativeStateChanged, videoStreamingChanged, videoSinkChanged) is marked Q_CLASSINFO("octave.experimental", ...): it is published in docs/api/androidAutoManager.json but may change without a protocol version bump.
Mobile / build-variant differences
The mobile stub exposes only isDhuInstalled / isDhuEmbedded (constant false), launchDhuSeamless() (false), closeDhu(), the dhuEmbeddedChanged, error, dhuWindowReady signals, and the built-in backend's names with inert constant values (backend "dhu", nativeAvailable false, nativeState "idle", empty nativeStatus / phoneName, videoStreaming false, videoSink null; startNative() returns false, the other invokables do nothing). A desktop build without OpenSSL or FFmpeg has the full class with nativeAvailable false, backend always "dhu", and startNative() setting error ("This build has no native Android Auto").

Properties

PropertyTypeAccessNotify signalDescription
isDhuInstalledboolread-only, constant—Google Desktop Head Unit binary found in the Android SDK
dhuPathQStringread-only, constant—Path of the DHU binary
isDhuEmbeddedboolread-onlydhuEmbeddedChangedManager considers the DHU running/embedded; this alone does not prove its window is displayed
dhuWindowHandleintread-onlydhuWindowReadyCurrently a process ID or 0 rather than a discovered native window handle
dhuCaptureQObject*read-only, constant—The DhuCapture object streaming frames to image://dhuframe/
backendQStringread-onlybackendChangedExperimental. "native" or "dhu" from the androidAutoBackend setting; "dhu" whenever nativeAvailable is false
nativeAvailableboolread-only, constant—Experimental. Built with the native receiver (OCTAVE_HAVE_NATIVE_AA: OpenSSL + FFmpeg, desktop)
nativeStateQStringread-onlynativeStateChangedExperimental. idle | connecting | waitingForPhone | waitingForServer | needsCertificate | running | error (what each means)
nativeStatusQStringread-onlynativeStateChangedExperimental. The state as a sentence for a person, including what to do
phoneNameQStringread-onlynativeStateChangedExperimental. Device name the phone reported in service discovery
videoStreamingboolread-onlyvideoStreamingChangedExperimental. The phone is sending video
certificateDirQStringread-only, constant—Experimental. <config dir>/android-auto: where headunit.crt + headunit.key are looked for when androidAutoCertPath is empty
videoSinkQObject*read/writevideoSinkChangedExperimental. The QVideoSink decoded frames go to; AndroidAutoView.qml sets its VideoOutput's sink

Invokables & Slots

SignatureReturnsDescription
getDhuInstallInstructions()QStringUser-facing SDK Manager instructions
launchDhuSeamless()boolPrepare the headunit server and adb forward, then launch DHU; embedding is incomplete (see above)
sendDhuClick(int x, int y)voidForward a click through DhuCapture (currently a logged stub)
closeDhu()voidStop capture and kill the DHU process
cleanup()voidAt exit: end a built-in session with a bye-bye (waits up to 3 s), close the DHU, remove its tcp:5277 forward
startNative()boolExperimental. Connect to the phone's head unit server and keep retrying (3 s while waiting for the phone, server or certificate; 8 s after an error) until stopNative(). False when it can't begin (nativeState says why); true when already connecting or running
stopNative()voidExperimental. Stop retrying; a running session ends with a bye-bye, the adb forward is removed, state returns to idle
injectTouch(int pointerId, int action, double x, double y)voidExperimental. A touch on the picture: pointerId from the touch area, action 0 down / 1 up / 2 move, x / y in 0..1 of the video. Only while running
setViewVisible(bool visible)voidExperimental. The view is on screen; false tells the phone to stop sending video (audio continues)

Signals

SignalDescription
connectionProgress(QString message)Launch progress text
error(QString message)Error message (DHU launch errors; also every failed built-in session)
dhuWindowReady(int windowHandle)DHU window found; carries the handle
dhuEmbeddedChanged(bool embedded)Embedding state changed
backendChanged()Experimental. androidAutoBackend was saved
nativeStateChanged()Experimental. nativeState, nativeStatus or phoneName changed
videoStreamingChanged()Experimental. videoStreaming changed
videoSinkChanged()Experimental. videoSink was set

DhuCapture — dhuCapture

src/managers/androidautomanager.h — sub-object androidAutoManager.dhuCapture

Sub-object reached through androidAutoManager.dhuCapture; grabs the DHU window at 30 fps into the image provider. Not a context property of its own.

Properties

PropertyTypeAccessNotify signalDescription
isCapturingboolread-onlycaptureStartedFrame capture timer running
windowHandleintread/write—Window being captured

Invokables & Slots

SignatureReturnsDescription
setWindowHandle(int hwnd)voidSet the window to capture
startCapture()voidStart grabbing frames (30 fps) into the dhuframe image provider
stopCapture()voidStop grabbing
sendMouseClick(int x, int y)voidForward a click (currently a logged stub)

Signals

SignalDescription
frameReady()A new provider frame is available; the current QML does not display this provider
captureStarted()Capture started
captureStopped()Capture stopped
error(QString message)Capture error

AirPlayManager — airPlayManager

src/managers/airplaymanager.h — QML context property airPlayManager

An iPhone over AirPlay: its mirrored screen and audio, and touch back through OCTAVE as a Bluetooth LE mouse. See iPhone (AirPlay). Settings: airPlayEnabled, airPlayName, airPlayRequirePin, airPlayResolution, airPlayTouchEnabled, airPlayTouchScale (generic keys).

Experimental
Every member is marked Q_CLASSINFO("octave.experimental", ...): published in docs/api/airPlayManager.json but may change without a protocol version bump. Scope phone.
Build variants
Without OCTAVE_HAVE_AIRPLAY (libplist + OpenSSL + libavcodec, Linux) the class is the same with available false and state "unavailable". Without BlueZ, touchAvailable is false and touchState is "unavailable".

Properties

PropertyTypeAccessNotify signalDescription
availableboolread-only, constant—Built with the AirPlay receiver
enabledboolread-onlyenabledChangedairPlayEnabled (and available)
stateQStringread-onlystateChangedoff | unavailable | error | waiting | pin | connected | mirroring | audio
statusQStringread-onlystateChangedThe state as a sentence for a person
receiverNameQStringread-onlystateChangedWhat the iPhone lists (airPlayName)
deviceName / deviceModelQStringread-onlystateChangedThe connecting iPhone's name and model
pinQStringread-onlystateChangedThe PIN to show while a new iPhone pairs; empty otherwise
mirroring / audioStreamingboolread-onlystateChangedScreen mirroring / AirPlay audio is running
frameWidth / frameHeightintread-onlyframeSizeChangedSize of the mirrored picture
title / artist / albumQStringread-onlymediaChangedTrack info sent with AirPlay audio
addressesQStringListread-onlystateChangedThis machine's IPv4 addresses on real interfaces (no container bridges or VPN tunnels)
videoSinkQObject*read/writevideoSinkChangedThe QVideoSink the mirrored picture goes to (AirPlayView.qml sets it)
touchAvailableboolread-only, constant—Built with the Bluetooth mouse (BlueZ)
touchEnabledboolread-onlytouchChangedairPlayTouchEnabled
touchStateQStringread-onlytouchChangedunavailable | off | waiting | connected
touchStatus / touchDeviceQStringread-onlytouchChangedThe mouse's state as a sentence; the connected iPhone's name
touchPairingboolread-onlytouchChangedThe pairing window is open
touchCalibratingboolread-onlytouchChangedWaiting for the calibration tap

Invokables & Slots

SignatureReturnsDescription
setEnabled(bool enabled)voidSaves airPlayEnabled: start or stop advertising
setTouchEnabled(bool enabled)voidSaves airPlayTouchEnabled: start or stop the Bluetooth mouse
pairTouch(bool open = true)voidAccept a new Bluetooth pairing for three minutes (closes once an iPhone connects); false closes it
injectTouch(int pointerId, int action, double x, double y)voidA touch on the mirrored picture: action 0 down / 1 up / 2 move, x / y in 0..1. The first finger moves the pointer; only while the mouse is connected
scroll(int dx, int dy)voidWheel steps (positive dy scrolls down)
calibrateTouch() / cancelCalibration()voidHome the pointer and move it 240 counts right and down; the next tap marks where it shows and sets airPlayTouchScale
forgetDevices()voidForget every iPhone that paired with the PIN

Signals

SignalDescription
enabledChanged(), stateChanged(), mediaChanged(), frameSizeChanged(), videoSinkChanged(), touchChanged()Property notifications
mirroringStarted()An iPhone started mirroring (Main.qml opens the iPhone page)
audioStreamingChanged(bool streaming)AirPlay audio started or stopped

PhoneMirrorManager — phoneMirrorManager

src/managers/phonemirrormanager.h — QML context property phoneMirrorManager

Built-in scrcpy-protocol client (see Phone Mirror): pushes tools/phone-server/octave-phone-server over adb, decodes H.264 itself and injects touch. Desktop only; the mobile build registers a stub. adb discovery (the public static findAdb()) is shared with AndroidAutoManager; on Windows every adb / server process goes through ScrcpyClient::hideConsoleWindow() so no console flashes. Errors are reported through scrcpyError only — there is no separate error signal.

Mobile / build-variant differences
The mobile stub declares every property as CONSTANT except deviceState, deviceHint, devices and mirrorNotice, which it lacks; it omits the slots describeDeviceState, dismissNotice, refreshDeviceState, selectDevice and cleanup, and the signals audioPlayed, connectionTypeChanged, currentBitRateChanged, deviceStateChanged, mediaChanged, mediaArtChanged, mediaQueueChanged, mirrorNoticeChanged, phoneAsleepChanged, phoneInUseChanged, qrPairingChanged and wirelessBusyChanged.

Properties

PropertyTypeAccessNotify signalDescription
adbPathQStringread-only, constant—adb in use (bundled platform-tools preferred)
nativeAvailableboolread-only, constant—adb found, server jar present and libavcodec linked
serverVersionQStringread-only, constant—Phone-server version the client speaks; must match the jar
isRunningboolread-onlyisRunningChangedA mirror session is active
displaySizeQStringread-onlydisplaySizeChangedRequested virtual display "WxH" or "auto" (fit the view, Android 11+); "" = phone screen
activeDisplaySizeQStringread-onlyframeSizeChanged"WxH" of the virtual display in use, "" when mirroring the phone screen
videoSinkQObject*read/writevideoSinkChangedQML binds VideoOutput.videoSink here; decoded frames go straight to it
frameWidthintread-onlyframeSizeChangedDecoded frame width
frameHeightintread-onlyframeSizeChangedDecoded frame height
audioActiveboolread-onlyaudioActiveChangedPhone audio is being played through OCTAVE
audioPlayingboolread-onlyaudioPlayingChangedThe phone is producing sound right now (drives ducking)
phoneAsleepboolread-onlyphoneAsleepChangedThe phone was locked / put to sleep during a session; OCTAVE is waking it
phoneInUseboolread-onlyphoneInUseChangedThe user unlocked the phone during a session; OCTAVE leaves its panel alone until resumeMirroring() or the phone is locked again
wirelessAddressQStringread-onlywirelessAddressChanged"ip:port" of the phone last connected over Wi-Fi (setting scrcpyWirelessAddress); reconnected automatically, "" = none
connectionTypeQStringread-onlyconnectionTypeChanged"usb" / "wifi" for the running session, "" when idle
wirelessBusyboolread-onlywirelessBusyChangedA QR pairing started from the UI is in progress
qrPairingRowsQStringListread-onlyqrPairingChangedModules of the QR code shown by startQrPairing(), one '0'/'1' string per row; empty when no pairing is waiting
qrPairingActiveboolread-onlyqrPairingChangedA QR pairing is waiting for the phone
currentBitRateintread-onlycurrentBitRateChangedVideo bit rate of the running session in bps (follows adaptive changes), 0 when idle
mediaAvailable, mediaPlaying, mediaCanSeekboolread-onlymediaChangedThe phone reports a media session / it is playing / it can seek
mediaTitle, mediaArtist, mediaAlbum, mediaAppQStringread-onlymediaChangedWhat the phone is playing; mediaApp is the package name
mediaDurationintread-onlymediaChangedTrack length in ms, 0 = unknown
mediaArtUrlQStringread-onlymediaArtChangedfile:// URL of the phone's album art, "" for none
mediaQueueQVariantListread-onlymediaQueueChangedPhone queue entries: {id, title, artist, art_uri, art}; art is a local JPEG URL, initially empty
mediaQueueActiveIdqint64read-onlymediaQueueChangedPlaying queue item ID; -1 when absent
mediaQueueTitleQStringread-onlymediaQueueChangedQueue title supplied by the phone app
sessionStateQStringread-onlysessionStateChanged"idle" | "starting" | "streaming" | "reconnecting" (a drop after streaming: retried every second, the view holds the last frame, up to 10 s) | "waitingForPhone" (a phone / link error: retried every 2 s, restarted the moment adb reports the phone) | "failed" (setup or fatal: not retried). Retries run only while setViewActive(true)
lastErrorKindQStringread-onlylastErrorKindChangedWhat the last scrcpyError was about: "noPhone" (no phone at all: the QR screen), "device" (the phone or its link: worth retrying), "setup" (OCTAVE's side: adb, the server, the decoder), "fatal" (the phone cannot do it: its encoder failed even in software); "" after a successful start. Decided by errorKindFor(message) next to the strings that make the messages
deviceStateQStringread-onlydeviceStateChangedLast adb devices probe (run off the GUI thread): "device" / "unauthorized" / "no-permissions" / "offline" / "none" / "no-adb"
deviceHintQStringread-onlydeviceStateChangediPhone on USB / adb server clash text, "" otherwise
devicesQVariantListread-onlydeviceStateChanged[{serial, state, wireless, model, selected}]; feeds the phone picker
mirrorNoticeQStringread-onlymirrorNoticeChangedNon-fatal notices for the running session (touch blocked, no audio, software encoder)
mediaActiveboolread-onlymediaActiveChanged(bool)The phone has OCTAVE's media controls from the first session report, even when paused or no app is playing. Cleared by releaseMedia() or disconnect; after release, resumed phone playback takes control again

Invokables & Slots

SignatureReturnsDescription
setVolume(float volume)voidCalled by VolumeController (0–1 linear); phone audio follows OCTAVE volume
setAudioGain(float gain)voidLinear gain on phone PCM before OCTAVE volume (setting scrcpyAudioGain)
setMuted(bool muted)voidOCTAVE's mute (volumeController.mutedChanged) silences phone audio too; phone audio always plays through OCTAVE while mirroring
setAudioDuckEnabled(bool enabled)voidSetting scrcpyAudioDuckEnabled
setAudioDuckLevel(float level)voidSetting scrcpyAudioDuckLevel (linear factor)
setAudioOutputDevice(QString id)voidSetting audioOutputDevice: phone audio plays to the same output as local music; called again whenever the outputs change, and an open sink moves when its device would change
setDisplaySize(QString size)voidVirtual display size (snapped to multiples of 8, or "auto"); restarts a running session
setViewSize(int width, int height)voidMirror view size in device pixels; drives "auto" and restarts a running auto session when it changes (debounced 1.5 s)
setDisplayDpi(int dpi)voidSetting scrcpyDisplayDpi (0 = phone's scaled density); restarts a running session
setBitRateUsb(int mbps), setBitRateWifi(int mbps)voidSettings scrcpyBitRateUsb / scrcpyBitRateWifi; restart a running session on that link
setBitRateAuto(bool enabled)voidSetting scrcpyBitRateAuto: adaptive bit rate with the per-link rates as ceiling; restarts a running session
setAutoWifi(bool enabled)voidSetting scrcpyAutoWifi: adb tcpip 5555 before USB sessions and remember the phone's Wi-Fi address
setPhoneScreenOff(bool off)voidSetting scrcpyPhoneScreenOff: keep the handset panel dark while mirroring (applied live)
wakePhone()voidWake a sleeping phone (KEYCODE_WAKEUP); the overlay tap-to-retry
resumeMirroring()voidLeave the in-use state: wake the phone if needed and re-apply screen-off
environmentOk()boolEverything OCTAVE needs is present (same as nativeAvailable); a failure is then about the phone
getInstallInstructions()QStringUser-facing setup help text
getDeviceState()QStringThe cached deviceState; schedules a refresh, never blocks
refreshDeviceState()voidProbe adb devices off the GUI thread; deviceStateChanged follows
setViewActive(bool active)voidThe mirror page is on screen; the automatic restarts and their adb probes run only then (the page calls it from its StackView status)
selectDevice(QString serial)voidMirror this phone; restarts a session running on another one
dismissNotice()voidHide mirrorNotice
describeDeviceState(QString state)QStringHuman-readable explanation of a device state
hasConnectedDevice()boolThe cached state is "device"
injectTouch(int pointerId, int action, float relX, float relY)voidMultitouch on the mirrored display: action 0 down / 1 up / 2 move; coordinates relative 0–1
injectKey(int keycode)voidSend an Android keycode
pressHome()voidHOME; on a virtual display launches the launcher there via am start --display because HOME is routed to the default display
pressBack()voidBACK
pressAppSwitch()voidAPP_SWITCH (recents)
startScrcpy()voidPush the server jar, start a session and begin decoding
stopScrcpy()voidEnd the session
cleanup()voidStop the session at exit
setWirelessAddress(QString address)voidRemembered Wi-Fi phone (primed from settings at startup); tries to reach it at once
forgetWireless()voidStop a Wi-Fi session, adb disconnect and clear wirelessAddress
startQrPairing()voidShow a QR code for the phone's “Pair device with QR code” scanner, wait up to 2 min for its mDNS pairing service, then adb pair and connect; result via wirelessResult
cancelQrPairing()voidDrop the shown code; the waiting job gives up within a second
mediaPlayPause(), mediaPlay(), mediaPause(), mediaNext(), mediaPrevious()voidDrive the phone's media session
mediaSkipToQueueItem(qint64 id)voidAsk the phone app to skip to an item from mediaQueue
mediaSeek(int positionMs)voidSeek the phone's media session
mediaPosition()intPhone media position in ms, extrapolated while playing
releaseMedia(bool pausePhone)voidAn OCTAVE source took over: the controls leave the phone, optionally pausing it

Signals

SignalDescription
audioPlayed(QByteArray pcm, int bufferedMs)PCM handed to the audio sink and buffered delay. Connected to AudioAnalyzer for the live waveform
mediaQueueChanged()Phone queue, current item, title or loaded queue artwork changed
scrcpyStarted(int handle)Session started (the handle is always 1 with the built-in client)
scrcpyStopped()Session ended
scrcpyError(QString message)Session failed to start / died; carries describeDeviceState()-style text for showing. lastErrorKind is set just before it
lastErrorKindChanged()Notify for lastErrorKind
sessionStateChanged()Notify for sessionState; set before the scrcpyError that caused it
isRunningChanged()Notify for isRunning
displaySizeChanged()Notify for displaySize
frameSizeChanged(int width, int height)Decoded size changed (also notifies activeDisplaySize, frameWidth, frameHeight)
frameReady()A frame reached the video sink
videoSinkChanged()Notify for videoSink
audioActiveChanged(bool active)Audio stream started / stopped
audioPlayingChanged(bool playing)Sound detected / silence
phoneAsleepChanged(bool asleep)Phone went to sleep / woke up while mirrored
phoneInUseChanged(bool inUse)Phone taken in hand / handed back
mediaChanged() / mediaArtChanged()Notify for the phone media properties (every state report) / mediaArtUrl
mediaTrackChanged()The track itself changed (title, artist or app), or went away on reset; nowPlaying turns it into trackChanged
mediaActiveChanged(bool active)The phone took / gave back the media controls; nowPlaying pauses local media when it takes over
duckingChanged(float factor)Duck factor while the phone makes sound and ducking is on, 1.0 otherwise; main routes it to mediaManager.setDucking
wirelessAddressChanged(QString address)Remembered Wi-Fi phone changed (paired, moved to a new port, forgotten); main saves it with save_scrcpy_wireless_address
connectionTypeChanged() / wirelessBusyChanged()Property notifications
wirelessResult(bool ok, QString message)Outcome of QR pairing, message ready to show
deviceStateChanged()A probe changed deviceState, deviceHint or devices (also emitted when a session starts, for selected)
mirrorNoticeChanged()mirrorNotice changed
qrPairingChanged()Notify for qrPairingRows / qrPairingActive
currentBitRateChanged()Notify for currentBitRate

DashboardManager — dashboardManager

src/managers/dashboardmanager.h — QML context property dashboardManager

Built-in dashboard presets plus user-authored dashboards in <app data>/dashboards, with hot reload of the user dir (see Gauges & Dashboards).

Properties

PropertyTypeAccessNotify signalDescription
dashboardsQVariantListread-onlydashboardsChangedMerged headers [{id, label, builtIn, path}, …], built-ins first
lastShareErrorQStringread-onlylastShareErrorChangedReason the last export/import failed; "" after a success
lastErrorQStringread-onlylastErrorChangedWhy the last loadDashboard / saveDashboard failed (unknown id, unreadable file, newer schema, no name, a built-in id...); "" after one that worked. The calls' return values are unchanged
hiddenBuiltInCountintread-onlydashboardsChangedBuilt-in presets the user deleted (hidden); shows the chooser's "Restore defaults" button
lastImportReportQVariantMapread-onlylastImportReportChangedExperimental. What the last successful import kept and left out: {id, label, cells, droppedCells, droppedProps, movedCells, portraitDropped, unknownTypes, paramIds}
previewQVariantMapread-onlypreviewChangedExperimental. A dashboard being edited on another device, {id, spec}, shown on the dashboard page; {} when none
widgetPresetsQVariantListread-onlywidgetPresetsChangedExperimental. My widgets: [{id, label, baseType, paramId, props}] from <config>/widgets/
templatesQVariantListconstant—Experimental. The starting points for a new dashboard (frontend/dashboards/templates/*.json, in their order): [{id, label, description, order, gridColumns, gridRows, cells}], each cell's data a slot {prefer, kinds} that fromTemplate() fills
supportedSchemaintconstant—Highest dashboard schema this build reads (kSupportedSchema, 2: the portrait layout); DashboardRenderer shows a "needs a newer OCTAVE" message for newer specs

Invokables & Slots

SignatureReturnsDescription
loadDashboard(QString id)QVariantThe spec for an id, normalised by the same rules as a save (in the grid, no overlaps, known keys; see Gauges & Dashboards); a newer-schema file untouched; empty object if unknown or unparsable
isBuiltIn(QString id)boolTrue for a read-only preset
saveDashboard(QVariantMap spec)QStringNormalise and write a user dashboard JSON (needs a label; a missing id becomes uniqueIdForLabel(label), a given one must be file-safe); returns the id, "" on failure, a newer schema or collision with a built-in
deleteDashboard(QString id)boolDelete a user dashboard file, or hide a built-in (persisted in .hidden-builtins)
restoreBuiltInDashboards()boolUn-hide every deleted built-in; false if none were hidden
uniqueIdForLabel(QString label)QStringFree id for a new dashboard named label (slug, then -2, -3, ...); never a built-in id, hidden or not, or the Parameter Cards id "grid". The editor calls it before saveDashboard
normalizedSpec(QVariantMap spec)QVariantMapA spec as save / load would leave it, for one that isn't a file (the editor's rescued draft); empty if unusable; an absent id stays absent
canPlace(QVariantList cells, int gridColumns, int gridRows, int col, int row, int colSpan, int rowSpan, int exceptIndex)boolThe rectangle is inside the grid and covers no cell but exceptIndex (-1 for none); the editor's drag / resize check
fitAt(QVariantList cells, int gridColumns, int gridRows, int col, int row, int colSpan, int rowSpan)QVariantMap{col, row, colSpan, rowSpan}: the wanted span cut to the grid edge, then shrunk toward 1×1 (wider side first) until it fits; the editor's tap-to-place
nearestFree(QVariantList cells, int gridColumns, int gridRows, int col, int row, int colSpan, int rowSpan, int exceptIndex)QVariantMapExperimental. {ok, col, row, colSpan, rowSpan}: the free spot of that span nearest (col, row), cell exceptIndex ignored; the editor's + Add and Duplicate
arrange(QVariantList cells, int gridColumns, int gridRows, int index, int col, int row, int colSpan, int rowSpan)QVariantMapExperimental. {ok, cells, moved, swapped, reason}: cell index moved / resized there, the cells it covers swapped with it or pushed to the nearest free spot of their size; the editor's drag, resize and swap
rescale(QVariantList cells, int fromColumns, int fromRows, int toColumns, int toRows)QVariantMapExperimental. {ok, cells, reason}: the layout on another grid size (edges scaled and rounded, collisions moved to the nearest free spot or a step smaller); the editor's grid density
derivePortrait(QVariantList cells, int gridColumns, int gridRows)QVariantMapExperimental. {gridColumns, gridRows, cells}: a portrait layout for landscape cells, one placement each in order (the grid turned, every widget its on-screen shape on a 16:9 screen, reading order, made smaller in steps until they fit); the same for the same input
orientedSpec(QVariantMap spec, bool portrait)QVariantMapExperimental. The spec as laid out on a portrait (true) screen: layouts.portrait, or one derived, as its grid and the cells' positions, without layouts; landscape returns the spec unchanged. DashboardRenderer uses it when taller than wide
thumbnailFromImage(QVariant image)QStringExperimental. A QImage as a 320 × 180 JPEG data URL (the editor's dashboard thumbnail); "" for anything else
widgetPresetText(QString id)QStringExperimental. A widget preset as shared JSON text; "" for an unknown id
fromTemplate(QString id, QStringList supported)QVariantMapExperimental. A new dashboard from a template in templates (property, frontend/dashboards/templates/*.json): each cell's slot takes its first prefer id the car reports (supported; empty = no car, the first preferred), else a reported id of one of its kinds, never one already taken; no id; empty for an unknown template
minSpan(QString type, int gridColumns, int gridRows, double cellWidth, double cellHeight, double spacing)QVariantMapExperimental. {colSpan, rowSpan}: the smallest span reaching the catalog's minSize for cells of that size (dp)
sizeOptions(QString type, int gridColumns, int gridRows, double cellWidth, double cellHeight, double spacing)QVariantListExperimental. [{label, colSpan, rowSpan}]: S / M / L, about 1/12, 1/6 and 1/3 of the grid nearest the widget's aspect, never below minSpan; the editor's size chips
duplicateDashboard(QString sourceId, QString newLabel)QStringClone any dashboard into a new user dashboard with a unique id derived from the label; returns the new id
refresh()voidRescan both directories and emit dashboardsChanged
exportDashboard(QString id)QStringWrite the spec to <Downloads>/OCTAVE-dashboards/<id>.json; returns the path, "" on failure
copyDashboardToClipboard(QString id)boolCopy the spec to the clipboard as compact JSON
importDashboard(QString fileOrUrl)QStringImport a shared dashboard from a path, file:// or content:// URL as a new user dashboard (fresh id from the label, sanitized to schema 1); returns the new id, "" with lastShareError set on failure
importDashboardFromClipboard()QStringSame, from clipboard text
importDashboardFromText(QString json)QStringSame, from a JSON string
previewDashboard(QVariantMap spec)boolExperimental. Show spec on the car's dashboard page as preview (load rules; false and no preview for an unusable one); ends 60 s after the last call
endPreview()voidExperimental. End the preview
saveWidgetPreset(QVariantMap preset)QStringExperimental. Save {label, baseType, paramId, props} (an existing id overwrites); the id, or "" with lastError
deleteWidgetPreset(QString id)boolExperimental. Delete one of My widgets
copyWidgetPresetToClipboard(QString id)boolExperimental. A preset as text on the clipboard
importWidgetPresetFromText(QString json), importWidgetPresetFromClipboard()QStringExperimental. A shared preset as a new one (never overwrites); "" with lastShareError

Signals

SignalDescription
dashboardsChanged()After any rescan (save, delete, duplicate, import, refresh(), or the user dir changing on disk)
lastShareErrorChanged()When lastShareError changes
lastImportReportChanged(), previewChanged(), widgetPresetsChanged()When those properties change

FrontendManager — frontendManager

src/managers/frontendmanager.h, src/managers/frontendmanifest.h — QML context property and service object frontendManager (changes need the system permission)

Installed frontends in <app data>/frontends/<id>/, each with an octave-frontend.json, and which one is the screen from the next start (see Writing a Frontend).

Properties

PropertyTypeAccessNotify signalDescription
frontendsQVariantListread-onlyfrontendsChanged[{id, name, version, description, kind, protocol, scopes, command, active, compatible, problem, path}]; a broken folder is listed with its problem
activeIdQStringread-onlyactiveChangedThe frontend used from the next start; "" for the built-in QML UI
runningIdQStringconstant—What this run shows, decided at start ("" = the QML UI)
forcedQml, forcedQmlReasonbool, QStringread-onlyactiveChangedUSE_QML is present (an exec frontend is not started) and its text
lastErrorQStringread-onlylastErrorChangedWhy the last install / remove / setActive failed; "" after a success

Invokables & Slots

SignatureReturnsDescription
installFromFolder(QString path)QStringCopy a frontend folder in after checking it (manifest, protocol, a program for this platform, no links, at most 10000 files and 256 MB); nothing in it runs. The id, or "" with lastError
installFromZip(QString path)QStringSame from a .zip of the folder or of its contents; an entry naming a path outside the folder, a link or a size that doesn't match refuses the whole zip
remove(QString id)boolDelete an installed frontend (not the one running)
setActive(QString id)boolThe screen from the next start; "" = the QML UI. Refuses one that can't run here
clearForcedQml()voidDelete USE_QML
manifestOf(QString id)QVariantMapOne row of frontends, {} if none

Signals

SignalDescription
frontendsChanged(), activeChanged(), lastErrorChanged()As the properties change
installed(QString id)An install finished

PerfMonitor — perfMonitor

src/dev/perfmonitor.{h,cpp} — QML context property perfMonitor developer only

Event-loop / thread-jitter / CPU profiler, registered only with --profile (the class exists only in OCTAVE_DEV_TOOLS builds). Production QML never references it.

Properties

PropertyTypeAccessNotify signalDescription
loopLatencyMsdoubleread-onlymetricsUpdatedRolling average event-loop latency in ms
loopP99Msdoubleread-onlymetricsUpdated99th percentile loop latency (stutter indicator)
gilJitterMsdoubleread-onlymetricsUpdatedAverage wake-up lateness of a probe thread that sleeps 10 ms (CPU contention)
cpuPercentdoubleread-onlymetricsUpdatedProcess CPU usage, per core
memMbdoubleread-onlymetricsUpdatedProcess RSS in MB
threadCountintread-onlymetricsUpdatedProcess thread count (Linux; read from /proc/self/status)
summaryTextQStringread-onlymetricsUpdatedOne-line status for the on-screen HUD

Invokables & Slots

SignatureReturnsDescription
getDetailedReport()QStringMulti-line report with loop / jitter / CPU stats and per-slot timings (p95 > 1 ms)

Signals

SignalDescription
metricsUpdated()Every 1 s reporting cycle (notify for every property)