Prometheus metrics¶
Prometheus is an open-source time-series monitoring and alerting platform. Rather than waiting for systems to push events, Prometheus periodically scrapes metrics over HTTP from instrumented endpoints, storing timestamped samples that can be queried with PromQL and visualized in dashboards like Grafana.
In Native Tv, the Prometheus metrics endpoint exposes your TV's system, panel, and HDMI telemetry directly to Prometheus-compatible scrapers (including VictoriaMetrics and Grafana Agent). Common use-cases include:
- Long-term OLED panel and storage health: Graphing panel run-time against automatic pixel refresher cycles in Grafana to monitor panel aging, verify that compensation cycles run after prolonged sessions, and track eMMC flash wear over the life of the TV.
- Thermal and hardware observability: Recording SoC temperatures, processor clocks, and memory utilization over time to identify thermal throttling, background spikes, or resource constraints during high-bitrate 4K HDR playback and gaming.
- Proactive home lab alerting: Setting Alertmanager alert rules to trigger notifications when Magic Remote battery levels drop below 15%, when internal storage approaches capacity, when eMMC enters pre-EOL warning states, or if panel maintenance errors occur.
- Infrastructure monitoring without Home Assistant: Collecting rich telemetry directly into an existing monitoring and observability stack without requiring an MQTT broker or Home Assistant instance.
The server answers scrapes at /api/prometheus/metrics in the standard Prometheus text exposition format. It is off by default, and while it is off the path does not exist: a request receives a 404 Not Found.
Switching it on¶
The Prometheus switch on the Server tab turns it on and off, at once and without a restart. It is read-only where controls are turned off in config.json.
The same setting can be configured in /var/lib/tvweb/config.json on the TV, followed by a restart of the server:
"prometheus": { "enabled": true }
Scraping¶
The endpoint is under /api/, so a token, where one is set, is needed as for the rest of the API. Prometheus sends it as an Authorization: Bearer header, which keeps it out of URLs and logs:
scrape_configs:
- job_name: nativetv
metrics_path: /api/prometheus/metrics
scrape_interval: 15s
authorization:
credentials_file: /etc/prometheus/nativetv-token
static_configs:
- targets: ["192.168.1.20:8080"]
Each scrape runs the same stats collection as the dashboard, behind its 1.5 s cache, so 15 s is the recommended minimum scrape interval. The MQTT bridge publishes every 30 s by default.
Testing locally¶
To spin up a local Prometheus instance against your TV without manual setup:
./scripts/run-prometheus.sh <tv-ip> [<tv-ip2> ...]
It downloads a standalone Prometheus binary into ~/.cache/nativetv-prometheus/ if one is not in PATH, starts a server targeting your TV(s) at http://localhost:9090, and cleans up its temporary state when stopped.
Metrics¶
These names are stable: one is not renamed or removed, so dashboards and alerts built on them keep working. Labels carry only values that rarely change. Values are in base units: bytes, hertz, seconds, and ratios from 0 to 1 rather than percentages. A family the TV gives no reading for, such as the panel figures on an LCD or the remote's battery with no remote paired, is left out of the scrape, HELP and TYPE too, rather than given a 0.
The OLED protections are asbl, the Automatic Static Brightness Limiter (Temporal Peak Control on the TV), which lowers brightness while a bright image is held, and gsr, Global Stress Reduction, which dims the screen when it detects a stationary element. They come from the TV's panel service, or from its panel maintenance records where it has none; a TV that reports neither has no sample for them.
nativetv_signal_info labels the picture settings in use: dynamic_range is sdr, hdr, dolby_vision or technicolor, and picture_mode is the mode within it: personalized, vivid, standard, eco, cinema, cinema_bright, sports, game, photo, filmmaker, expert_bright, expert_dark or hdr_effect. A value the TV adds later keeps its own name in snake case.
nativetv_sound_info labels the sound settings, the output and mode the dashboard's and Home Assistant's selects show, rather than the audio path in use at the moment. output is the output's key, such as tv_speaker, external_arc, external_optical, bt_soundbar, headphone, or tv_external_speaker, and mode is standard, ai_sound, ai_sound_plus, movie, news, sports, music, or game. A value the TV adds later keeps its own name in snake case. nativetv_sound_input_info labels the format of the sound being played, from an app or an input: codec is the TV's name for it, such as pcm, opus, aac, ac3, eac3, or truehd, and immersive is dolby_atmos, dts_x, or none. It has a sample only while something plays, and not at all on webOS 4, which does not report it. nativetv_volume_ratio has a sample only while the TV sets the volume level: with an output whose volume it only steps, such as an ARC soundbar, or does not control, such as optical, it has no level to report.
nativetv_power_on_info labels the reason the TV's power service gives for the TV last powering on, read at Native Tv's start and after each power transition. reason is the service's own name in snake case, as in its PowerOnReason log lines, such as remote_key, wake_on_wifi, always_on, or reboot_by_on_regular, and the family has no sample on a TV that gives none. nativetv_power_on_time_seconds is when the TV last powered on, from the time on its power service reports, and has no sample in standby; the time it has been on is time() - nativetv_power_on_time_seconds.
The signal gauges describe the HDMI source on screen and have no sample otherwise. The refresh rate is the rate the source sends, not the content's frame rate. nativetv_signal_frame_rate_hertz is the rate the game is running at while VRR is in use, and the same as the refresh rate otherwise. Its vrr_type label is the kind of VRR, such as gsync, or off.
nativetv_signal_format_info and the HDR families describe the source on the TV's connected video sink and have no sample without one. type is the source's HDR type, such as sdr or hdr10, with player-led (low-latency) Dolby Vision as dolby_vision_low_latency; eotf is sdr, hdr, pq, or hlg, from the source's HDR static metadata, and empty without it; colorimetry is the colorimetry the source signals, such as bt2020_rgb_or_ycbcr; and encoding is rgb_444, ycbcr_444, ycbcr_422, or ycbcr_420, named as the HDMI link's chroma is. A value the TV adds later keeps its own name in snake case. The HDR luminance gauges are in nits (cd/m²), from HDR10 static metadata, and the content and frame-average light levels have no sample while the source gives none.
nativetv_signal_low_latency is ALLM, the flag an HDMI source sets to ask for the TV's low-latency picture processing, in any format. Low-latency Dolby Vision is separate: the source does the Dolby Vision mapping and sends a BT.2020 signal, and type is dolby_vision_low_latency, where Dolby Vision the TV maps is dolby_vision. dynamic_range is dolby_vision in both, so only type tells them apart, and neither implies ALLM.
The HDMI link families describe every input with a source linked to it, whichever input is on screen, and have no sample for an input without one; nativetv_hdmi_source_powered has a sample for every input, linked or not. input is hdmi1 to hdmi4, as the TV numbers its inputs. phy_mode is frl_48, frl_40, frl_32, frl_24, frl_18, frl_9, tmds_6g, or tmds_3g, and other for a mode outside these, which has no rate; chroma is rgb_444, ycbcr_444, ycbcr_422, or ycbcr_420; and hdcp is 2_3, 2_2, 1_4, or none. A chroma format or HDCP version outside these keeps its own name in snake case.
nativetv_foreground_app_info has a sample while an app is in the foreground, including with the screen off, and none in standby: app_id is the app's id, such as com.webos.app.hdmi4 or netflix, and app_name is the name given an input in the TV's settings, an app's title, or the short id. nativetv_hdmi_input_info has a sample for every HDMI input, labelled with input, its app_id, and the name given it in the TV's settings, so the foreground app joins it on app_id and the input then joins the HDMI link families on input.
The syslog counters count since the server started and have samples only while syslog forwarding is on. source is system, nativetv, or kernel, one for each source forwarded. Compared with what the receiver counts per source as MSGID, they show lines lost on the way.
The NTP families have samples only while setting the clock from NTP is on, and the offset, round trip, stratum, and last answer only once the server has answered. The counters count since the server started. The offset is the server's time less the TV's at that answer, before the clock was set from it. How long since the last answer is time() - nativetv_ntp_last_answer_timestamp_seconds.
nativetv_watch_seconds_total has samples only while watch time is on, one for each app the history has: the app's id, the input's, such as hdmi2, screen_off for the TV on with its panel off, or screen_saver for LG's screen saver showing. Clearing the history resets it.
version is the Native Tv version. A label the TV does not report is present with an empty value. The panel usage since the last compensation cycle is nativetv_oled_panel_usage_seconds_total - nativetv_oled_last_compensation_usage_seconds, the uptime is time() - nativetv_boot_time_seconds, and the processor's busy share is 1 - avg without (cpu, mode) (rate(nativetv_cpu_seconds_total{mode="idle"}[5m])).
| Metric | Type | Labels | Value |
|---|---|---|---|
nativetv_info |
gauge | model, firmware, webos, version |
1 |
nativetv_boot_time_seconds |
gauge | When the TV last booted, as a Unix time; later than the real boot on a TV that suspends in standby | |
nativetv_system_on |
gauge | 1 when on, including with the screen off | |
nativetv_screen_on |
gauge | 1 when the screen is on, including a screen saver | |
nativetv_power_on_info |
gauge | reason |
1 |
nativetv_power_on_time_seconds |
gauge | When the TV last powered on, as a Unix time; none in standby | |
nativetv_soc_temperature_celsius |
gauge | SoC temperature | |
nativetv_cpu_seconds_total |
counter | cpu, mode |
Time each online core has spent in each mode |
nativetv_cpu_frequency_hertz |
gauge | Processor clock | |
nativetv_gpu_frequency_hertz |
gauge | GPU clock | |
nativetv_memory_total_bytes |
gauge | MemTotal |
|
nativetv_memory_available_bytes |
gauge | MemAvailable |
|
nativetv_swap_total_bytes |
gauge | SwapTotal |
|
nativetv_swap_free_bytes |
gauge | SwapFree |
|
nativetv_network_receive_bytes_total |
counter | interface |
Bytes received on the interface in use |
nativetv_network_transmit_bytes_total |
counter | interface |
Bytes sent on the interface in use |
nativetv_wifi_signal_dbm |
gauge | Wi-Fi signal level | |
nativetv_wifi_link_quality |
gauge | Wi-Fi link quality, on the driver's own scale | |
nativetv_emmc_pre_eol_state |
gauge | state |
1 for the current eMMC state: normal, warning, urgent |
nativetv_emmc_life_used_ratio |
gauge | type |
eMMC estimated life used, in steps of 0.1 |
nativetv_app_storage_size_bytes |
gauge | Size of the app storage filesystem | |
nativetv_app_storage_available_bytes |
gauge | Space available there for new apps | |
nativetv_remote_battery_ratio |
gauge | Magic Remote battery, read over Bluetooth on webOS 9 and 10 and from LG's remote service on webOS 4 | |
nativetv_adblock_enabled |
gauge | 1 when ad blocking is in place | |
nativetv_oled_panel_usage_seconds_total |
counter | Time the panel has been in use | |
nativetv_oled_last_compensation_usage_seconds |
gauge | Panel usage at the last short compensation cycle | |
nativetv_oled_compensation_interval_seconds |
gauge | Panel usage between short compensation cycles | |
nativetv_oled_compensation_running |
gauge | 1 while a short compensation cycle runs | |
nativetv_oled_compensation_runs_total |
counter | Short compensation cycles completed | |
nativetv_oled_last_refresher_usage_seconds |
gauge | Panel usage at the last Pixel Refresher run | |
nativetv_oled_refresher_interval_seconds |
gauge | Panel usage between automatic Pixel Refresher runs | |
nativetv_oled_refresher_runs_total |
counter | Pixel Refresher runs completed | |
nativetv_oled_refresher_running |
gauge | 1 while a Pixel Refresher run is in progress | |
nativetv_oled_refresher_scheduled |
gauge | 1 while a Pixel Refresher run waits for the next standby | |
nativetv_oled_failure_alerts_total |
counter | Panel maintenance failure alerts recorded | |
nativetv_oled_gsr_stress_events_total |
counter | Stress events Global Stress Reduction has counted | |
nativetv_oled_protection_enabled |
gauge | protection |
1 when the protection is on: asbl, gsr |
nativetv_picture_backlight_ratio |
gauge | Backlight of the picture mode in use, OLED light on an OLED | |
nativetv_sound_info |
gauge | output, mode |
1 |
nativetv_sound_input_info |
gauge | codec, immersive |
1 while something plays |
nativetv_volume_ratio |
gauge | Volume, while the TV sets the level | |
nativetv_muted |
gauge | 1 while the sound is muted | |
nativetv_foreground_app_info |
gauge | app_id, app_name |
1 |
nativetv_signal_info |
gauge | dynamic_range, picture_mode |
1 |
nativetv_signal_low_latency |
gauge | 1 while the picture is in low-latency mode (ALLM) | |
nativetv_signal_vrr |
gauge | 1 while the HDMI source uses VRR | |
nativetv_signal_width_pixels |
gauge | Width of the HDMI source's picture | |
nativetv_signal_height_pixels |
gauge | Height of the HDMI source's picture | |
nativetv_signal_refresh_hertz |
gauge | Refresh rate of the HDMI signal | |
nativetv_signal_frame_rate_hertz |
gauge | vrr_type |
Frame rate the HDMI source presents |
nativetv_signal_format_info |
gauge | type, eotf, colorimetry, encoding |
1 |
nativetv_signal_hdr_mastering_luminance_max_nits |
gauge | Peak luminance of the mastering display | |
nativetv_signal_hdr_mastering_luminance_min_nits |
gauge | Black level of the mastering display | |
nativetv_signal_hdr_content_light_level_max_nits |
gauge | Brightest pixel in the content (MaxCLL) | |
nativetv_signal_hdr_frame_average_light_level_max_nits |
gauge | Brightest frame average in the content (MaxFALL) | |
nativetv_signal_game_mode |
gauge | 1 while the source is in game mode | |
nativetv_hdmi_input_info |
gauge | input, app_id, name |
1 |
nativetv_hdmi_link_info |
gauge | input, phy_mode, chroma, hdcp |
1 |
nativetv_hdmi_link_bits_per_second |
gauge | input |
Rate of the input's link |
nativetv_hdmi_qms |
gauge | input |
1 while Quick Media Switching is active on the link |
nativetv_hdmi_source_powered |
gauge | input |
1 while a powered source is on the input's cable |
nativetv_syslog_messages_total |
counter | source |
Log lines sent to the syslog server |
nativetv_syslog_errors_total |
counter | Log lines that could not be sent, and were dropped | |
nativetv_ntp_clock_sets_total |
counter | Times the clock was set from the NTP server | |
nativetv_ntp_errors_total |
counter | NTP syncs that set no clock | |
nativetv_ntp_offset_seconds |
gauge | The server's time less the TV's at the last answer | |
nativetv_ntp_round_trip_seconds |
gauge | Round trip to the server for the last answer | |
nativetv_ntp_stratum |
gauge | The server's stratum in the last answer | |
nativetv_ntp_last_answer_timestamp_seconds |
gauge | When the last answer came, as a Unix time | |
nativetv_watch_seconds_total |
counter | app |
Time the TV was on with the app or input in front |