OpenLogi

0x4301 · solarKeyboardDashboard

Battery and ambient-light monitoring for solar keyboards — schedule periodic light-measure reports, override the CheckLight LED color, and receive battery and lux broadcast events.

Battery and ambient-light monitoring for Logitech solar keyboards such as the K750. set_light_measure schedules periodic light reports by specifying the number of reports and their interval in seconds; passing 0 for either value cancels an in-progress schedule. set_led overrides the firmware's CheckLight LED to a chosen color for a firmware-defined duration; call it within the 250 ms window after a CheckLightButton event to intercept before the firmware renders its own status.

All three broadcast events carry a SolarStatus payload with battery_level (percentage) and light_level (lux, 0511):

  • Battery — spontaneous report fired roughly every 90 s, at power-up, and on reconnect; light_level is always 0.
  • LightMeasure — one report per period set by set_light_measure.
  • CheckLightButton — fired when the user presses the CheckLight button, carrying the latest battery and light readings.

set_led accepts a LedId variant: Off, Red, Orange, or Green.

Spec: Logitech HID++ 2.0 — solarKeyboardDashboard. Used by: Typed wrapper in openlogi-hidpp.

Function reference

The SolarDashboardFeature wrapper (0x4301) exposes:

Methods

FunctionHID++ fnSignatureReturns
set_light_measure0(max_reports: u8, report_period: u8)()
set_led1(led: LedId)()
listenevent()async_channel::Receiver<SolarEvent>

set_light_measure and set_led are async and return Result<(), Hidpp20Error>. listen is synchronous and returns an async_channel::Receiver<SolarEvent> that yields decoded broadcast events.

Types

LedId

A CheckLight LED color passed to set_led.

VariantValueDescription
Off0All LEDs off.
Red1Red.
Orange2Orange.
Green3Green.

SolarStatus

Battery and light readings shared by every solar-dashboard event.

FieldTypeDescription
battery_levelu8Remaining battery capacity, as a percentage.
light_levelu16Current light measure in lux (0..=511).

Events

SolarDashboardFeature implements EmittingFeature<SolarEvent>; call listen() to subscribe. Each variant wraps a SolarStatus payload.

VariantDescription
Battery(SolarStatus)Spontaneous battery report (every ~90 s, at power-up, and on reconnect). light_level is always 0 for this variant.
LightMeasure(SolarStatus)Battery and light report sent per the set_light_measure schedule.
CheckLightButton(SolarStatus)The CheckLight button was pressed; carries the latest battery and light readings.

Wire format

set_light_measure and set_led each carry a 3-byte short request payload with no meaningful response bytes; both functions are fire-and-acknowledge. Broadcast events arrive as 16-byte long payloads decoded by SolarStatus::from_payload.

set_light_measure (fn 0)

Request: [max_reports, report_period, 0x00]

ByteFieldNotes
0max_reportsNumber of LightMeasure reports to send. 0 cancels scheduling.
1report_periodInterval between reports in seconds. 0 cancels scheduling.
2Padding, always 0x00.

Response: acknowledged only; no response fields are read.

set_led (fn 1)

Request: [led, 0x00, 0x00]

ByteFieldNotes
0ledLedId as u8: Off=0, Red=1, Orange=2, Green=3.
1–2Padding, always 0x00.

Response: acknowledged only; no response fields are read.

Events (fn 0–2)

All three event variants share the same 16-byte payload layout decoded by SolarStatus::from_payload.

ByteFieldNotes
0battery_levelRemaining battery capacity as a percentage (u8).
1–2light_levelAmbient light in lux, big-endian u16 (0..=511).
3–15Unused.

Event sub-id (the function nibble on the broadcast message) selects the variant:

Sub-idVariant
0SolarEvent::Battery
1SolarEvent::LightMeasure
2SolarEvent::CheckLightButton

Usage (Rust)

use hidpp::{device::Device, feature::solar_dashboard::{LedId, SolarDashboardFeature, SolarEvent}};

// device: mut Device, already created via Device::new(channel, index).await?
device.enumerate_features().await?;
if let Some(feat) = device.get_feature::<SolarDashboardFeature>() {
    // Schedule 10 light-measure reports every 30 seconds.
    feat.set_light_measure(10, 30).await?;

    // Subscribe to broadcast events.
    let rx = feat.listen();
    while let Ok(event) = rx.recv().await {
        match event {
            SolarEvent::Battery(s) => println!("battery: {}%", s.battery_level),
            SolarEvent::LightMeasure(s) => println!("battery: {}%, lux: {}", s.battery_level, s.light_level),
            SolarEvent::CheckLightButton(s) => {
                println!("check-light pressed: battery {}%, lux {}", s.battery_level, s.light_level);
                // Override the firmware LED within the 250 ms window.
                feat.set_led(LedId::Green).await?;
            }
        }
    }
}

On this page