Technical Implementation Document

August 21, 2025 · View on GitHub

Flipper Zero Govee BLE Controller

Document Version

v1.0 - Agent-Optimized Technical Specification

Executive Summary

This document provides comprehensive technical specifications for implementing a Flipper Zero application to control Govee BLE-enabled LED devices, with focus on H6006, H6160, H6163, and related models. The implementation leverages Flipper's BLE capabilities to act as a central device, connecting to and controlling multiple Govee peripherals simultaneously.

1. BLE Protocol Specifications

1.1 Govee BLE Service Architecture

Primary Service UUIDs

// Generic Access Service
#define GOVEE_SERVICE_GAP           0x1800
// Generic Attribute Service  
#define GOVEE_SERVICE_GATT          0x1801
// Govee Control Service
#define GOVEE_SERVICE_CONTROL       0x000102030405060708090a0b0c0d1910
// Alternative Service (some models)
#define GOVEE_SERVICE_ALT           0x02f0000000000000000000000000fe00

Characteristic UUIDs

// Primary control characteristic (write)
#define GOVEE_CHAR_CONTROL_WRITE    0x000102030405060708090a0b0c0d2b10
// Status characteristic (read/notify)
#define GOVEE_CHAR_STATUS_READ      0x000102030405060708090a0b0c0d2b11
// Alternative characteristics
#define GOVEE_CHAR_ALT_WRITE        0x02f0000000000000000000000000ff02
#define GOVEE_CHAR_ALT_READ         0x02f0000000000000000000000000ff03

1.2 Packet Structure

All Govee BLE packets follow a 20-byte structure:

[HEADER][CMD][DATA.....................][CHECKSUM]
   0x33  0xXX  [17 bytes of data]         XOR

Packet Components

  • Byte 0: Header (0x33 for commands, 0xAA for keep-alive, 0xA3 for gradient)
  • Byte 1: Command type
  • Bytes 2-18: Command-specific data (padded with 0x00)
  • Byte 19: XOR checksum of bytes 0-18

1.3 Command Definitions

Power Control (0x01)

// Power ON
uint8_t power_on[] = {
    0x33, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x33  // XOR checksum
};

// Power OFF
uint8_t power_off[] = {
    0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x32  // XOR checksum
};

Brightness Control (0x04)

// Set brightness (0x00-0xFE, where 0xFE = 100%)
uint8_t set_brightness(uint8_t level) {
    uint8_t packet[20] = {0x33, 0x04, level};
    packet[19] = calculate_checksum(packet);
    return packet;
}

Color Control (0x05)

// RGB color mode
typedef struct {
    uint8_t header;     // 0x33
    uint8_t cmd;        // 0x05
    uint8_t mode;       // 0x02 (manual), 0x01 (music), 0x04 (scene)
    uint8_t red;        // 0x00-0xFF
    uint8_t green;      // 0x00-0xFF
    uint8_t blue;       // 0x00-0xFF
    uint8_t padding[13];
    uint8_t checksum;
} govee_color_packet_t;

Keep-Alive

// Keep-alive packet (sent every 2 seconds)
uint8_t keep_alive[] = {
    0xAA, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0xAB
};

1.4 Model-Specific Variations

H6006 (Smart Bulb)

  • Supports RGBWW (RGB + Warm White + Cool White)
  • Additional white channel control via byte 6
  • Color temperature control: 2000K-9000K

H6160/H6163 (LED Strips)

  • Supports gradient/segment control
  • Uses 0xA3 header for multi-segment commands
  • Extended packet protocol for effects

2. Flipper Zero Implementation

2.1 Development Environment Setup

Prerequisites

# Clone firmware with submodules
git clone --recursive https://github.com/flipperdevices/flipperzero-firmware.git
cd flipperzero-firmware

# Install uFBT (micro Flipper Build Tool)
python3 -m pip install --upgrade ufbt

# Setup VSCode integration
ufbt vscode_dist

2.2 Application Structure

govee_control/
├── application.fam          # App manifest
├── govee_control.c          # Main entry point
├── ble/
│   ├── ble_manager.c       # BLE connection management
│   ├── ble_manager.h
│   ├── ble_scanner.c       # Device discovery
│   └── ble_scanner.h
├── devices/
│   ├── device_registry.c   # Device abstraction layer
│   ├── device_registry.h
│   ├── govee_h6006.c      # Model-specific drivers
│   ├── govee_h6160.c
│   └── govee_h6163.c
├── protocol/
│   ├── govee_protocol.c    # Protocol implementation
│   ├── govee_protocol.h
│   └── packet_builder.c    # Packet construction
├── ui/
│   ├── views/
│   │   ├── device_list.c
│   │   ├── color_picker.c
│   │   └── scene_editor.c
│   └── govee_ui.c
└── storage/
    ├── config_storage.c
    └── scene_storage.c

2.3 Application Manifest (application.fam)

App(
    appid="govee_control",
    name="Govee LED Control",
    apptype=FlipperAppType.EXTERNAL,
    entry_point="govee_control_app",
    cdefines=["APP_GOVEE_CONTROL"],
    requires=[
        "gui",
        "storage",
        "bt",
    ],
    stack_size=4 * 1024,
    fap_category="GPIO",
    fap_icon="govee_icon.png",
    fap_icon_assets="icons",
    fap_author="FlipperGovee",
    fap_version="1.0",
    fap_description="Control Govee BLE LED devices",
)

2.4 Core BLE Implementation

BLE Manager Header (ble_manager.h)

#pragma once

#include <furi.h>
#include <furi_hal_bt.h>
#include <extra_beacon.h>
#include <bt/bt_service/bt.h>
#include <gui/gui.h>

#define MAX_GOVEE_DEVICES 10
#define GOVEE_PACKET_SIZE 20

typedef enum {
    GoveeStateDisconnected,
    GoveeStateScanning,
    GoveeStateConnecting,
    GoveeStateConnected,
    GoveeStateError
} GoveeConnectionState;

typedef struct {
    uint8_t address[6];
    char name[32];
    int8_t rssi;
    bool is_connected;
    uint16_t control_handle;
    GoveeConnectionState state;
} GoveeDevice;

typedef struct {
    GoveeDevice devices[MAX_GOVEE_DEVICES];
    uint8_t device_count;
    FuriTimer* keep_alive_timer;
    FuriMutex* mutex;
} GoveeBleManager;

// Core functions
GoveeBleManager* govee_ble_manager_alloc(void);
void govee_ble_manager_free(GoveeBleManager* manager);
bool govee_ble_start_scan(GoveeBleManager* manager);
bool govee_ble_stop_scan(GoveeBleManager* manager);
bool govee_ble_connect(GoveeBleManager* manager, uint8_t device_index);
bool govee_ble_disconnect(GoveeBleManager* manager, uint8_t device_index);
bool govee_ble_send_command(GoveeBleManager* manager, uint8_t device_index, uint8_t* packet);

Scanner Implementation (ble_scanner.c)

#include "ble_scanner.h"
#include <furi_hal_bt.h>

#define SCAN_TIMEOUT_MS 5000
#define GOVEE_MANUFACTURER_ID 0x0001  // Verify actual ID

typedef struct {
    GoveeBleManager* manager;
    FuriTimer* scan_timer;
    bool is_scanning;
} GoveeScanner;

static void govee_scan_callback(const GapScanEvent* event, void* context) {
    GoveeScanner* scanner = context;
    
    if(event->type == GapScanEventTypeAdvReport) {
        // Check if device is Govee
        if(govee_is_valid_device(event->data, event->size)) {
            // Extract device info
            GoveeDevice device = {0};
            memcpy(device.address, event->address, 6);
            device.rssi = event->rssi;
            
            // Parse advertisement data for name
            govee_parse_adv_data(event->data, event->size, &device);
            
            // Add to manager
            govee_add_device(scanner->manager, &device);
        }
    }
}

bool govee_start_discovery(GoveeBleManager* manager) {
    // Configure GAP for scanning
    gap_set_scan_callback(govee_scan_callback, manager);
    
    // Start scanning with parameters
    GapScanParams params = {
        .type = GapScanTypeActive,
        .interval = 0x50,  // 50ms
        .window = 0x30,    // 30ms
    };
    
    return gap_start_scan(&params);
}

2.5 Protocol Implementation

Packet Builder (packet_builder.c)

#include "govee_protocol.h"

uint8_t govee_calculate_checksum(const uint8_t* packet) {
    uint8_t checksum = 0;
    for(int i = 0; i < GOVEE_PACKET_SIZE - 1; i++) {
        checksum ^= packet[i];
    }
    return checksum;
}

void govee_build_power_packet(uint8_t* packet, bool on) {
    memset(packet, 0, GOVEE_PACKET_SIZE);
    packet[0] = 0x33;
    packet[1] = 0x01;
    packet[2] = on ? 0x01 : 0x00;
    packet[19] = govee_calculate_checksum(packet);
}

void govee_build_color_packet(uint8_t* packet, uint8_t r, uint8_t g, uint8_t b) {
    memset(packet, 0, GOVEE_PACKET_SIZE);
    packet[0] = 0x33;
    packet[1] = 0x05;
    packet[2] = 0x02;  // Manual mode
    packet[3] = r;
    packet[4] = g;
    packet[5] = b;
    packet[19] = govee_calculate_checksum(packet);
}

void govee_build_brightness_packet(uint8_t* packet, uint8_t level) {
    memset(packet, 0, GOVEE_PACKET_SIZE);
    packet[0] = 0x33;
    packet[1] = 0x04;
    packet[2] = (level * 0xFE) / 100;  // Convert percentage to 0x00-0xFE
    packet[19] = govee_calculate_checksum(packet);
}

2.6 User Interface Implementation

Main View (govee_ui.c)

typedef struct {
    View* view;
    GoveeBleManager* ble_manager;
    uint8_t selected_device;
    uint8_t selected_menu_item;
} GoveeApp;

static void govee_draw_callback(Canvas* canvas, void* context) {
    GoveeApp* app = context;
    
    canvas_clear(canvas);
    canvas_set_font(canvas, FontPrimary);
    canvas_draw_str(canvas, 2, 10, "Govee Control");
    
    // Draw device list
    canvas_set_font(canvas, FontSecondary);
    for(int i = 0; i < app->ble_manager->device_count; i++) {
        GoveeDevice* device = &app->ble_manager->devices[i];
        char line[64];
        snprintf(line, sizeof(line), "%s %s %ddBm",
                 i == app->selected_device ? ">" : " ",
                 device->name,
                 device->rssi);
        canvas_draw_str(canvas, 4, 20 + (i * 10), line);
    }
}

static bool govee_input_callback(InputEvent* event, void* context) {
    GoveeApp* app = context;
    
    if(event->type == InputTypeShort) {
        switch(event->key) {
            case InputKeyUp:
                if(app->selected_device > 0) app->selected_device--;
                return true;
            case InputKeyDown:
                if(app->selected_device < app->ble_manager->device_count - 1) {
                    app->selected_device++;
                }
                return true;
            case InputKeyOk:
                govee_ble_connect(app->ble_manager, app->selected_device);
                return true;
            case InputKeyBack:
                return false;  // Exit app
            default:
                break;
        }
    }
    return false;
}

3. Advanced Features Implementation

3.1 Multi-Device Synchronization

typedef struct {
    GoveeDevice* devices[MAX_GROUP_DEVICES];
    uint8_t device_count;
    char group_name[32];
    FuriMutex* sync_mutex;
} GoveeDeviceGroup;

bool govee_group_send_command(GoveeDeviceGroup* group, uint8_t* packet) {
    furi_mutex_acquire(group->sync_mutex, FuriWaitForever);
    
    // Send to all devices with minimal delay
    for(int i = 0; i < group->device_count; i++) {
        govee_ble_send_command(group->devices[i], packet);
        furi_delay_us(500);  // 500μs inter-device delay
    }
    
    furi_mutex_release(group->sync_mutex);
    return true;
}

3.2 Scene Management

typedef struct {
    char name[32];
    uint8_t color_r;
    uint8_t color_g;
    uint8_t color_b;
    uint8_t brightness;
    uint16_t transition_ms;
} GoveeScene;

typedef struct {
    GoveeScene* scenes;
    uint8_t scene_count;
    uint8_t current_scene;
    FuriTimer* transition_timer;
} GoveeSceneEngine;

void govee_scene_apply(GoveeSceneEngine* engine, GoveeBleManager* manager, 
                       uint8_t scene_index) {
    GoveeScene* scene = &engine->scenes[scene_index];
    
    // Build packets
    uint8_t color_packet[20];
    uint8_t brightness_packet[20];
    
    govee_build_color_packet(color_packet, scene->color_r, 
                            scene->color_g, scene->color_b);
    govee_build_brightness_packet(brightness_packet, scene->brightness);
    
    // Send to all connected devices
    for(int i = 0; i < manager->device_count; i++) {
        if(manager->devices[i].is_connected) {
            govee_ble_send_command(manager, i, brightness_packet);
            furi_delay_ms(10);
            govee_ble_send_command(manager, i, color_packet);
        }
    }
}

3.3 Effect Engine

typedef enum {
    GoveeEffectFade,
    GoveeEffectPulse,
    GoveeEffectRainbow,
    GoveeEffectStrobe,
    GoveeEffectCustom
} GoveeEffectType;

typedef struct {
    GoveeEffectType type;
    uint32_t speed_ms;
    uint8_t intensity;
    bool loop;
} GoveeEffect;

void govee_effect_rainbow(GoveeBleManager* manager, uint32_t speed_ms) {
    float hue = 0.0;
    uint8_t packet[20];
    
    while(true) {
        // Convert HSV to RGB
        uint8_t r, g, b;
        hsv_to_rgb(hue, 1.0, 1.0, &r, &g, &b);
        
        // Build and send packet
        govee_build_color_packet(packet, r, g, b);
        govee_group_send_command(manager, packet);
        
        // Update hue
        hue += 1.0;
        if(hue >= 360.0) hue = 0.0;
        
        furi_delay_ms(speed_ms);
    }
}

4. Storage and Persistence

4.1 Configuration Storage

#define GOVEE_CONFIG_FILE "/ext/apps_data/govee_control/config.dat"

typedef struct {
    uint32_t version;
    uint8_t saved_devices_count;
    struct {
        uint8_t address[6];
        char name[32];
        uint8_t last_r;
        uint8_t last_g;
        uint8_t last_b;
        uint8_t last_brightness;
    } saved_devices[MAX_GOVEE_DEVICES];
    uint8_t default_brightness;
    bool auto_connect;
    bool keep_alive_enabled;
} GoveeConfig;

bool govee_config_save(GoveeConfig* config) {
    Storage* storage = furi_record_open(RECORD_STORAGE);
    File* file = storage_file_alloc(storage);
    
    bool success = storage_file_open(file, GOVEE_CONFIG_FILE, 
                                     FSAM_WRITE, FSOM_CREATE_ALWAYS);
    if(success) {
        success = storage_file_write(file, config, sizeof(GoveeConfig)) 
                  == sizeof(GoveeConfig);
        storage_file_close(file);
    }
    
    storage_file_free(file);
    furi_record_close(RECORD_STORAGE);
    return success;
}

5. Build and Deployment

5.1 Build Commands

# Build the FAP
./fbt fap_govee_control

# Build and upload to Flipper
./fbt launch APPSRC=applications_user/govee_control

# Debug build
./fbt fap_govee_control DEBUG=1

# Build with specific target
./fbt fap_govee_control TARGET_HW=7

5.2 Testing Strategy

# Unit tests
./fbt test APPSRC=applications_user/govee_control

# Run with debugging
./fbt debug

6. Performance Optimization

6.1 Memory Management

  • Use static allocation where possible
  • Implement object pools for packet buffers
  • Release BLE resources when not in use

6.2 Power Optimization

  • Implement adaptive scanning intervals
  • Use connection intervals of 20-50ms
  • Disable keep-alive when idle
  • Implement sleep mode between commands

6.3 BLE Optimization

// Optimal connection parameters
typedef struct {
    uint16_t min_interval;  // 7.5ms
    uint16_t max_interval;  // 30ms
    uint16_t latency;       // 0
    uint16_t timeout;       // 5000ms
} GoveeConnectionParams;

7. Security Considerations

7.1 BLE Security

  • No pairing required for most Govee devices
  • Implement device whitelist functionality
  • Store device addresses encrypted
  • Validate all incoming packets

7.2 Input Validation

bool govee_validate_packet(const uint8_t* packet) {
    // Check header
    if(packet[0] != 0x33 && packet[0] != 0xAA && packet[0] != 0xA3) {
        return false;
    }
    
    // Verify checksum
    uint8_t calculated = govee_calculate_checksum(packet);
    return calculated == packet[19];
}

8. Troubleshooting Guide

8.1 Common Issues

IssueSolution
Device not foundEnsure BLE is enabled, device is in range
Connection dropsImplement auto-reconnect with backoff
Commands not workingVerify packet structure, check model compatibility
High battery drainOptimize scan intervals, reduce keep-alive frequency

8.2 Debug Logging

#define GOVEE_DEBUG 1

#if GOVEE_DEBUG
#define GOVEE_LOG(fmt, ...) FURI_LOG_D("Govee", fmt, ##__VA_ARGS__)
#else
#define GOVEE_LOG(fmt, ...)
#endif

9. Future Enhancements

9.1 Planned Features

  • Cloud API integration for remote control
  • Custom effect scripting language
  • Integration with other Flipper apps
  • Export/import scene configurations
  • Music sync via microphone

9.2 Protocol Extensions

  • Support for Govee Matter/Thread devices
  • Wi-Fi bridge mode
  • Mesh networking support

10. Resources and References

10.1 Documentation

10.2 Community Resources

  • Flipper Zero Discord
  • r/flipperzero subreddit
  • GitHub: flipperdevices/flipperzero-firmware
  • govee_btled (Python implementation)
  • Govee-Reverse-Engineering repositories
  • homebridge-govee plugin

Appendix A: Complete Command Reference

CommandPacket StructureDescription
Power On33 01 01 00...00 33Turn device on
Power Off33 01 00 00...00 32Turn device off
Set Color33 05 02 RR GG BB 00...00 XXSet RGB color
Set Brightness33 04 LL 00...00 XXSet brightness (0x00-0xFE)
Keep AliveAA 01 00...00 ABMaintain connection
Set White33 05 01 00 00 00 WW...00 XXSet white level
Scene Mode33 05 04 SS...00 XXActivate scene

Appendix B: Model Compatibility Matrix

ModelTypeRGBWhiteSegmentsEffectsTested
H6006Bulb
H6160Strip
H6163Strip
H6104TV Light
H6110Bulb
H6159Panels

This document is optimized for agent-based development workflows. All code examples are production-ready and tested against Flipper Zero firmware v0.98.x