Skip to content

Latest commit

 

History

History
690 lines (567 loc) · 18.3 KB

File metadata and controls

690 lines (567 loc) · 18.3 KB

Technical Implementation Document

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

Issue Solution
Device not found Ensure BLE is enabled, device is in range
Connection drops Implement auto-reconnect with backoff
Commands not working Verify packet structure, check model compatibility
High battery drain Optimize 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

10.3 Related Projects

  • govee_btled (Python implementation)
  • Govee-Reverse-Engineering repositories
  • homebridge-govee plugin

Appendix A: Complete Command Reference

Command Packet Structure Description
Power On 33 01 01 00...00 33 Turn device on
Power Off 33 01 00 00...00 32 Turn device off
Set Color 33 05 02 RR GG BB 00...00 XX Set RGB color
Set Brightness 33 04 LL 00...00 XX Set brightness (0x00-0xFE)
Keep Alive AA 01 00...00 AB Maintain connection
Set White 33 05 01 00 00 00 WW...00 XX Set white level
Scene Mode 33 05 04 SS...00 XX Activate scene

Appendix B: Model Compatibility Matrix

Model Type RGB White Segments Effects Tested
H6006 Bulb
H6160 Strip
H6163 Strip
H6104 TV Light
H6110 Bulb
H6159 Panels

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