Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make blink colors configurable #4

Merged
merged 2 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 65 additions & 11 deletions Kconfig
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# Color definitions to use with color settings
COLOR_BLACK := 0 # no blink
COLOR_RED := 1
COLOR_GREEN := 2
COLOR_YELLOW := 3
COLOR_BLUE := 4
COLOR_MAGENTA := 5
COLOR_CYAN := 6
COLOR_WHITE := 7

config RGBLED_WIDGET
bool "Enable RGB LED widget for showing battery and output status"

Expand All @@ -6,18 +16,16 @@ if RGBLED_WIDGET
config LED
default y

config RGBLED_WIDGET_BATTERY_BLINK_MS
int "Duration of battery level blink in ms"
default 2000

config RGBLED_WIDGET_OUTPUT_BLINK_MS
int "Duration of BLE connection status blink in ms"
default 1000

config RGBLED_WIDGET_INTERVAL_MS
int "Minimum wait duration between two blinks in ms"
default 500

# Battery level settings

config RGBLED_WIDGET_BATTERY_BLINK_MS
int "Duration of battery level blink in ms"
default 2000

config RGBLED_WIDGET_BATTERY_LEVEL_HIGH
int "High battery level percentage"
default 80
Expand All @@ -30,21 +38,67 @@ config RGBLED_WIDGET_BATTERY_LEVEL_CRITICAL
int "Critical battery level percentage"
default 5

config RGBLED_WIDGET_BATTERY_COLOR_HIGH
int "Color for high battery level (above LEVEL_HIGH)"
range 0 7
default $(COLOR_GREEN)

config RGBLED_WIDGET_BATTERY_COLOR_MEDIUM
int "Color for medium battery level (between LEVEL_LOW and LEVEL_HIGH)"
range 0 7
default $(COLOR_YELLOW)

config RGBLED_WIDGET_BATTERY_COLOR_LOW
int "Color for low battery level (below LEVEL_LOW)"
range 0 7
default $(COLOR_RED)

config RGBLED_WIDGET_BATTERY_COLOR_CRITICAL
int "Color for critical battery level (below LEVEL_CRITICAL)"
range 0 7
default $(COLOR_RED)

# Connectivity indicator settings
config RGBLED_WIDGET_CONN_BLINK_MS
int "Duration of BLE connection status blink in ms"
default RGBLED_WIDGET_OUTPUT_BLINK_MS

config RGBLED_WIDGET_OUTPUT_BLINK_MS # DEPRECATED, do not use
int
default 1000

config RGBLED_WIDGET_CONN_COLOR_CONNECTED
int "Color for connected BLE connection status"
range 0 7
default $(COLOR_BLUE)

config RGBLED_WIDGET_CONN_COLOR_ADVERTISING
int "Color for advertising BLE connection status"
range 0 7
default $(COLOR_YELLOW)

config RGBLED_WIDGET_CONN_COLOR_DISCONNECTED
int "Color for disconnected BLE connection status"
range 0 7
default $(COLOR_RED)

# Layer indicator settings
config RGBLED_WIDGET_SHOW_LAYER_CHANGE
bool "Indicate highest active layer on each layer change with a sequence of blinks"

config RGBLED_WIDGET_LAYER_BLINK_MS
int "Blink and wait duration for layer indicator"
default 100

if RGBLED_WIDGET_SHOW_LAYER_CHANGE
config RGBLED_WIDGET_LAYER_COLOR
int "Color to use for layer indicator"
range 0 7
default $(COLOR_CYAN)

config RGBLED_WIDGET_LAYER_DEBOUNCE_MS
int "Wait duration after a layer change before showing the highest active layer"
default 100

endif # RGBLED_WIDGET_SHOW_LAYER_CHANGE

endif # RGBLED_WIDGET

DT_COMPAT_ZMK_BEHAVIOR_RGBLED_WIDGET := zmk,behavior-rgbled-widget
Expand Down
39 changes: 38 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,44 @@ This will happen on all keyboard parts for split keyboards, so make sure to flas

## Configuration

Blink durations can also be adjusted, see the [Kconfig file](Kconfig) for available config properties.
<details>
<summary>Expand to see available configuration options</summary>

| Name | Description | Default |
| ---------------------------------------------- | ---------------------------------------------------------------------------- | ------------ |
| `CONFIG_RGBLED_WIDGET_INTERVAL_MS` | Minimum wait duration between two blinks in ms | 500 |
| `CONFIG_RGBLED_WIDGET_BATTERY_BLINK_MS` | Duration of battery level blink in ms | 2000 |
| `CONFIG_RGBLED_WIDGET_BATTERY_LEVEL_HIGH` | High battery level percentage | 80 |
| `CONFIG_RGBLED_WIDGET_BATTERY_LEVEL_LOW` | Low battery level percentage | 20 |
| `CONFIG_RGBLED_WIDGET_BATTERY_LEVEL_CRITICAL` | Critical battery level percentage, blink periodically if under | 5 |
| `CONFIG_RGBLED_WIDGET_BATTERY_COLOR_HIGH` | Color for high battery level (above `LEVEL_HIGH`) | Green (`2`) |
| `CONFIG_RGBLED_WIDGET_BATTERY_COLOR_MEDIUM` | Color for medium battery level (between `LEVEL_LOW` and `LEVEL_HIGH`) | Yellow (`3`) |
| `CONFIG_RGBLED_WIDGET_BATTERY_COLOR_LOW` | Color for low battery level (below `LEVEL_LOW`) | Red (`1`) |
| `CONFIG_RGBLED_WIDGET_BATTERY_COLOR_CRITICAL` | Color for critical battery level (below `LEVEL_CRITICAL`) | Red (`1`) |
| `CONFIG_RGBLED_WIDGET_CONN_BLINK_MS` | Duration of BLE connection status blink in ms | 1000 |
| `CONFIG_RGBLED_WIDGET_CONN_COLOR_CONNECTED` | Color for connected BLE connection status | Blue (`4`) |
| `CONFIG_RGBLED_WIDGET_CONN_COLOR_ADVERTISING` | Color for advertising BLE connection status | Yellow (`3`) |
| `CONFIG_RGBLED_WIDGET_CONN_COLOR_DISCONNECTED` | Color for disconnected BLE connection status | Red (`1`) |
| `CONFIG_RGBLED_WIDGET_SHOW_LAYER_CHANGE` | Indicate highest active layer on each layer change with a sequence of blinks | `n` |
| `CONFIG_RGBLED_WIDGET_LAYER_BLINK_MS` | Blink and wait duration for layer indicator | 100 |
| `CONFIG_RGBLED_WIDGET_LAYER_COLOR` | Color to use for layer indicator | Cyan (`6`) |
| `CONFIG_RGBLED_WIDGET_LAYER_DEBOUNCE_MS` | Wait duration after a layer change before showing the highest active layer | 100 |

Color settings use the following integer values:

| Color | Value |
| ------------ | ----- |
| Black (none) | `0` |
| Red | `1` |
| Green | `2` |
| Yellow | `3` |
| Blue | `4` |
| Magenta | `5` |
| Cyan | `6` |
| White | `7` |

</details>

You can add these settings to your keyboard conf file to modify the config values, e.g. in `config/hummingbird.conf`:

```ini
Expand Down
71 changes: 38 additions & 33 deletions src/widget.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,23 @@ static const uint8_t rgb_idx[] = {DT_NODE_CHILD_IDX(DT_ALIAS(led_red)),
DT_NODE_CHILD_IDX(DT_ALIAS(led_green)),
DT_NODE_CHILD_IDX(DT_ALIAS(led_blue))};

// color values as specified by an RGB bitfield
enum led_color_t {
LED_BLACK, // 0b000
LED_RED, // 0b001
LED_GREEN, // 0b010
LED_YELLOW, // 0b011
LED_BLUE, // 0b100
LED_MAGENTA, // 0b101
LED_CYAN, // 0b110
LED_WHITE // 0b111
};
// map from color values to names, for logging
static const char *color_names[] = {"black", "red", "green", "yellow",
"blue", "magenta", "cyan", "white"};
// log shorthands
#define LOG_CONN_CENTRAL(index, status, color_label) \
LOG_INF("Profile %d %s, blinking %s", index, status, \
color_names[CONFIG_RGBLED_WIDGET_CONN_COLOR_##color_label])
#define LOG_CONN_PERIPHERAL(status, color_label) \
LOG_INF("Peripheral %s, blinking %s", status, \
color_names[CONFIG_RGBLED_WIDGET_CONN_COLOR_##color_label])
#define LOG_BATTERY(battery_level, color_label) \
LOG_INF("Battery level %d, blinking %s", battery_level, \
color_names[CONFIG_RGBLED_WIDGET_BATTERY_COLOR_##color_label])

// a blink work item as specified by the color and duration
struct blink_item {
enum led_color_t color;
uint8_t color;
uint16_t duration_ms;
bool first_item;
uint16_t sleep_ms;
Expand All @@ -69,22 +71,22 @@ void indicate_connectivity(void) {
#if !IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
uint8_t profile_index = zmk_ble_active_profile_index();
if (zmk_ble_active_profile_is_connected()) {
LOG_INF("Profile %d connected, blinking blue", profile_index);
blink.color = LED_BLUE;
LOG_CONN_CENTRAL(profile_index, "connected", CONNECTED);
blink.color = CONFIG_RGBLED_WIDGET_CONN_COLOR_CONNECTED;
} else if (zmk_ble_active_profile_is_open()) {
LOG_INF("Profile %d open, blinking yellow", profile_index);
blink.color = LED_YELLOW;
LOG_CONN_CENTRAL(profile_index, "open", ADVERTISING);
blink.color = CONFIG_RGBLED_WIDGET_CONN_COLOR_ADVERTISING;
} else {
LOG_INF("Profile %d not connected, blinking red", profile_index);
blink.color = LED_RED;
LOG_CONN_CENTRAL(profile_index, "not connected", DISCONNECTED);
blink.color = CONFIG_RGBLED_WIDGET_CONN_COLOR_DISCONNECTED;
}
#else
if (zmk_split_bt_peripheral_is_connected()) {
LOG_INF("Peripheral connected, blinking blue");
blink.color = LED_BLUE;
LOG_CONN_PERIPHERAL("connected", CONNECTED);
blink.color = CONFIG_RGBLED_WIDGET_CONN_COLOR_CONNECTED;
} else {
LOG_INF("Peripheral not connected, blinking red");
blink.color = LED_RED;
LOG_CONN_PERIPHERAL("not connected", DISCONNECTED);
blink.color = CONFIG_RGBLED_WIDGET_CONN_COLOR_DISCONNECTED;
}
#endif

Expand Down Expand Up @@ -121,16 +123,16 @@ void indicate_battery(void) {

if (battery_level == 0) {
LOG_INF("Battery level undetermined (zero), blinking magenta");
blink.color = LED_MAGENTA;
blink.color = 5;
} else if (battery_level >= CONFIG_RGBLED_WIDGET_BATTERY_LEVEL_HIGH) {
LOG_INF("Battery level %d, blinking green", battery_level);
blink.color = LED_GREEN;
LOG_BATTERY(battery_level, HIGH);
blink.color = CONFIG_RGBLED_WIDGET_BATTERY_COLOR_HIGH;
} else if (battery_level >= CONFIG_RGBLED_WIDGET_BATTERY_LEVEL_LOW) {
LOG_INF("Battery level %d, blinking yellow", battery_level);
blink.color = LED_YELLOW;
LOG_BATTERY(battery_level, MEDIUM);
blink.color = CONFIG_RGBLED_WIDGET_BATTERY_COLOR_MEDIUM;
} else {
LOG_INF("Battery level %d, blinking red", battery_level);
blink.color = LED_RED;
LOG_BATTERY(battery_level, LOW);
blink.color = CONFIG_RGBLED_WIDGET_BATTERY_COLOR_LOW;
}

k_msgq_put(&led_msgq, &blink, K_NO_WAIT);
Expand All @@ -145,10 +147,10 @@ static int led_battery_listener_cb(const zmk_event_t *eh) {
uint8_t battery_level = as_zmk_battery_state_changed(eh)->state_of_charge;

if (battery_level > 0 && battery_level <= CONFIG_RGBLED_WIDGET_BATTERY_LEVEL_CRITICAL) {
LOG_INF("Battery level %d, blinking red for critical", battery_level);
LOG_BATTERY(battery_level, CRITICAL);

struct blink_item blink = {.duration_ms = CONFIG_RGBLED_WIDGET_BATTERY_BLINK_MS,
.color = LED_RED};
.color = CONFIG_RGBLED_WIDGET_BATTERY_COLOR_CRITICAL};
k_msgq_put(&led_msgq, &blink, K_NO_WAIT);
}
return 0;
Expand All @@ -163,10 +165,13 @@ ZMK_SUBSCRIPTION(led_battery_listener, zmk_battery_state_changed);
void indicate_layer(void) {
uint8_t index = zmk_keymap_highest_layer_active();
static const struct blink_item blink = {.duration_ms = CONFIG_RGBLED_WIDGET_LAYER_BLINK_MS,
.color = LED_CYAN,
.color = CONFIG_RGBLED_WIDGET_LAYER_COLOR,
.sleep_ms = CONFIG_RGBLED_WIDGET_LAYER_BLINK_MS};
static const struct blink_item last_blink = {.duration_ms = CONFIG_RGBLED_WIDGET_LAYER_BLINK_MS,
.color = LED_CYAN};
.color = CONFIG_RGBLED_WIDGET_LAYER_COLOR};
LOG_INF("Blinking %d times %s for layer change", index,
color_names[CONFIG_RGBLED_WIDGET_LAYER_COLOR]);

for (int i = 0; i < index; i++) {
if (i < index - 1) {
k_msgq_put(&led_msgq, &blink, K_NO_WAIT);
Expand Down