commit
b42e66e495
4 changed files with 295 additions and 0 deletions
@ -0,0 +1,5 @@ |
||||
## Lazy Light |
||||
|
||||
Simple Flipper App for controlling lights/fans in my apartment. |
||||
|
||||
Plz do not judge the C code, it was written quickly and without desire for beauty. |
||||
@ -0,0 +1,18 @@ |
||||
App( |
||||
appid="lazylight", |
||||
name="Lazy Light", |
||||
apptype=FlipperAppType.EXTERNAL, |
||||
entry_point="lazylight_main", |
||||
stack_size=4 * 1024, |
||||
requires=[ |
||||
"subghz", |
||||
"gui", |
||||
], |
||||
order=10, |
||||
fap_icon="app.png", |
||||
fap_category="Sub-GHz", |
||||
fap_icon_assets="assets", |
||||
fap_description="Control lights/fans in Jerry's apartment", |
||||
fap_author="@jerryaldrichiii", |
||||
fap_version="0.1", |
||||
) |
||||
@ -0,0 +1,272 @@ |
||||
#include <gui/gui.h> |
||||
#include <gui/view_dispatcher.h> |
||||
#include <gui/modules/submenu.h> |
||||
|
||||
#include <devices/cc1101_int/cc1101_int_interconnect.h> |
||||
#include <devices/devices.h> |
||||
#include <flipper_format_i.h> |
||||
#include <lib/subghz/transmitter.h> |
||||
#include <subghz_protocol_registry.h> |
||||
|
||||
/* ===================== Views ===================== */ |
||||
|
||||
typedef enum { |
||||
ViewIndexMainMenu, |
||||
ViewIndexMasterBedroom, |
||||
ViewIndexGuestBedroom, |
||||
ViewIndexOffice, |
||||
ViewIndexCount, |
||||
} ViewIndex; |
||||
|
||||
/* ===================== Menu Indexes ===================== */ |
||||
|
||||
typedef enum { |
||||
MainMenuMasterBedroom, |
||||
MainMenuGuestBedroom, |
||||
MainMenuOffice, |
||||
} MainMenuIndex; |
||||
|
||||
typedef enum { |
||||
RoomActionToggleLight, |
||||
RoomActionFanOff, |
||||
RoomActionFanLow, |
||||
RoomActionFanMedium, |
||||
RoomActionFanHigh, |
||||
} RoomActionIndex; |
||||
|
||||
/* ===================== App Struct ===================== */ |
||||
|
||||
typedef struct { |
||||
ViewDispatcher* view_dispatcher; |
||||
Submenu* main_menu; |
||||
Submenu* master_menu; |
||||
Submenu* guest_menu; |
||||
Submenu* office_menu; |
||||
ViewIndex current_view; |
||||
} LazyLightApp; |
||||
|
||||
/* ===================== RF Transmit Helper ===================== */ |
||||
|
||||
static void lazylight_tx(uint32_t key) { |
||||
char* protocol = "CAME"; |
||||
|
||||
SubGhzEnvironment* env = subghz_environment_alloc(); |
||||
subghz_environment_set_protocol_registry( |
||||
env, (void*)&subghz_protocol_registry); |
||||
|
||||
SubGhzTransmitter* tx = subghz_transmitter_alloc_init(env, protocol); |
||||
|
||||
FlipperFormat* ff = flipper_format_string_alloc(); |
||||
|
||||
uint32_t bits = 12; |
||||
|
||||
uint8_t data[8] = {0}; |
||||
|
||||
data[7] = (uint8_t)(key & 0xFFU); |
||||
data[6] = (uint8_t)((key >> 8) & 0x0FU); |
||||
|
||||
flipper_format_insert_or_update_string_cstr(ff, "Protocol", "CAME"); |
||||
flipper_format_insert_or_update_uint32(ff, "Bit", &bits, 1); |
||||
flipper_format_insert_or_update_hex(ff, "Key", data, COUNT_OF(data)); |
||||
flipper_format_rewind(ff); |
||||
|
||||
furi_check( |
||||
subghz_transmitter_deserialize(tx, ff) == |
||||
SubGhzProtocolStatusOk); |
||||
|
||||
subghz_devices_init(); |
||||
const SubGhzDevice* dev = |
||||
subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME); |
||||
|
||||
subghz_devices_begin(dev); |
||||
subghz_devices_reset(dev); |
||||
subghz_devices_load_preset( |
||||
dev, FuriHalSubGhzPresetOok650Async, NULL); |
||||
subghz_devices_set_frequency(dev, 303900000); |
||||
|
||||
furi_hal_power_suppress_charge_enter(); |
||||
|
||||
if(subghz_devices_start_async_tx( |
||||
dev, subghz_transmitter_yield, tx)) { |
||||
while(!subghz_devices_is_async_complete_tx(dev)) { |
||||
furi_delay_ms(50); |
||||
} |
||||
subghz_devices_stop_async_tx(dev); |
||||
} |
||||
|
||||
furi_hal_power_suppress_charge_exit(); |
||||
|
||||
subghz_devices_sleep(dev); |
||||
subghz_devices_end(dev); |
||||
subghz_devices_deinit(); |
||||
|
||||
flipper_format_free(ff); |
||||
subghz_transmitter_free(tx); |
||||
subghz_environment_free(env); |
||||
} |
||||
|
||||
/* ===================== Navigation ===================== */ |
||||
|
||||
static bool navigation_callback(void* ctx) { |
||||
furi_check(ctx); |
||||
|
||||
LazyLightApp* app = ctx; |
||||
|
||||
if(app->current_view == ViewIndexMainMenu) { |
||||
view_dispatcher_stop(app->view_dispatcher); |
||||
} else { |
||||
app->current_view = ViewIndexMainMenu; |
||||
view_dispatcher_switch_to_view( |
||||
app->view_dispatcher, ViewIndexMainMenu); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/* ===================== Menu Callbacks ===================== */ |
||||
|
||||
static void main_menu_cb(void* ctx, uint32_t index) { |
||||
LazyLightApp* app = ctx; |
||||
app->current_view = index + 1; |
||||
view_dispatcher_switch_to_view( |
||||
app->view_dispatcher, app->current_view); |
||||
} |
||||
|
||||
static void master_cb(void* ctx, uint32_t index) { |
||||
UNUSED(ctx); |
||||
if(index == RoomActionToggleLight) lazylight_tx(0x1F6); |
||||
if(index == RoomActionFanOff) lazylight_tx(0x1F5); |
||||
if(index == RoomActionFanLow) lazylight_tx(0x1FD); |
||||
if(index == RoomActionFanMedium) lazylight_tx(0x1FB); |
||||
if(index == RoomActionFanHigh) lazylight_tx(0x1F7); |
||||
} |
||||
|
||||
static void guest_cb(void* ctx, uint32_t index) { |
||||
UNUSED(ctx); |
||||
if(index == RoomActionToggleLight) lazylight_tx(0x66); |
||||
if(index == RoomActionFanOff) lazylight_tx(0x65); |
||||
if(index == RoomActionFanLow) lazylight_tx(0x6D); |
||||
if(index == RoomActionFanMedium) lazylight_tx(0x6B); |
||||
if(index == RoomActionFanHigh) lazylight_tx(0x67); |
||||
} |
||||
|
||||
static void office_cb(void* ctx, uint32_t index) { |
||||
UNUSED(ctx); |
||||
if(index == RoomActionToggleLight) lazylight_tx(0xE6); |
||||
if(index == RoomActionFanOff) lazylight_tx(0xE5); |
||||
if(index == RoomActionFanLow) lazylight_tx(0xED); |
||||
if(index == RoomActionFanMedium) lazylight_tx(0xEB); |
||||
if(index == RoomActionFanHigh) lazylight_tx(0xE7); |
||||
} |
||||
|
||||
/* ===================== App Setup ===================== */ |
||||
|
||||
static LazyLightApp* app_alloc() { |
||||
LazyLightApp* app = malloc(sizeof(LazyLightApp)); |
||||
Gui* gui = furi_record_open(RECORD_GUI); |
||||
|
||||
app->view_dispatcher = view_dispatcher_alloc(); |
||||
view_dispatcher_attach_to_gui( |
||||
app->view_dispatcher, gui, ViewDispatcherTypeFullscreen); |
||||
view_dispatcher_set_navigation_event_callback( |
||||
app->view_dispatcher, navigation_callback); |
||||
view_dispatcher_set_event_callback_context( |
||||
app->view_dispatcher, app); |
||||
|
||||
/* Main Menu */ |
||||
app->main_menu = submenu_alloc(); |
||||
submenu_add_item(app->main_menu, "Master Bedroom", |
||||
MainMenuMasterBedroom, main_menu_cb, app); |
||||
submenu_add_item(app->main_menu, "Guest Bedroom", |
||||
MainMenuGuestBedroom, main_menu_cb, app); |
||||
submenu_add_item(app->main_menu, "Office", |
||||
MainMenuOffice, main_menu_cb, app); |
||||
|
||||
/* Master Bedroom */ |
||||
app->master_menu = submenu_alloc(); |
||||
submenu_add_item(app->master_menu, "Toggle Light", |
||||
RoomActionToggleLight, master_cb, app); |
||||
submenu_add_item(app->master_menu, "Turn Fan Off", |
||||
RoomActionFanOff, master_cb, app); |
||||
submenu_add_item(app->master_menu, "Set Fan Low", |
||||
RoomActionFanLow, master_cb, app); |
||||
submenu_add_item(app->master_menu, "Set Fan Medium", |
||||
RoomActionFanMedium, master_cb, app); |
||||
submenu_add_item(app->master_menu, "Set Fan High", |
||||
RoomActionFanHigh, master_cb, app); |
||||
|
||||
/* Guest Bedroom */ |
||||
app->guest_menu = submenu_alloc(); |
||||
submenu_add_item(app->guest_menu, "Toggle Light", |
||||
RoomActionToggleLight, guest_cb, app); |
||||
submenu_add_item(app->guest_menu, "Turn Fan Off", |
||||
RoomActionFanOff, guest_cb, app); |
||||
submenu_add_item(app->guest_menu, "Set Fan Low", |
||||
RoomActionFanLow, guest_cb, app); |
||||
submenu_add_item(app->guest_menu, "Set Fan Medium", |
||||
RoomActionFanMedium, guest_cb, app); |
||||
submenu_add_item(app->guest_menu, "Set Fan High", |
||||
RoomActionFanHigh, guest_cb, app); |
||||
|
||||
/* Office */ |
||||
app->office_menu = submenu_alloc(); |
||||
submenu_add_item(app->office_menu, "Toggle Light", |
||||
RoomActionToggleLight, office_cb, app); |
||||
submenu_add_item(app->office_menu, "Turn Fan Off", |
||||
RoomActionFanOff, office_cb, app); |
||||
submenu_add_item(app->office_menu, "Set Fan Low", |
||||
RoomActionFanLow, office_cb, app); |
||||
submenu_add_item(app->office_menu, "Set Fan Medium", |
||||
RoomActionFanMedium, office_cb, app); |
||||
submenu_add_item(app->office_menu, "Set Fan High", |
||||
RoomActionFanHigh, office_cb, app); |
||||
|
||||
view_dispatcher_add_view( |
||||
app->view_dispatcher, |
||||
ViewIndexMainMenu, |
||||
submenu_get_view(app->main_menu)); |
||||
view_dispatcher_add_view( |
||||
app->view_dispatcher, |
||||
ViewIndexMasterBedroom, |
||||
submenu_get_view(app->master_menu)); |
||||
view_dispatcher_add_view( |
||||
app->view_dispatcher, |
||||
ViewIndexGuestBedroom, |
||||
submenu_get_view(app->guest_menu)); |
||||
view_dispatcher_add_view( |
||||
app->view_dispatcher, |
||||
ViewIndexOffice, |
||||
submenu_get_view(app->office_menu)); |
||||
|
||||
app->current_view = ViewIndexMainMenu; |
||||
return app; |
||||
} |
||||
|
||||
static void app_free(LazyLightApp* app) { |
||||
view_dispatcher_remove_view(app->view_dispatcher, ViewIndexMainMenu); |
||||
view_dispatcher_remove_view(app->view_dispatcher, ViewIndexMasterBedroom); |
||||
view_dispatcher_remove_view(app->view_dispatcher, ViewIndexGuestBedroom); |
||||
view_dispatcher_remove_view(app->view_dispatcher, ViewIndexOffice); |
||||
|
||||
view_dispatcher_free(app->view_dispatcher); |
||||
submenu_free(app->main_menu); |
||||
submenu_free(app->master_menu); |
||||
submenu_free(app->guest_menu); |
||||
submenu_free(app->office_menu); |
||||
furi_record_close(RECORD_GUI); |
||||
free(app); |
||||
} |
||||
|
||||
/* ===================== Entry ===================== */ |
||||
|
||||
int32_t lazylight_main(void* arg) { |
||||
UNUSED(arg); |
||||
|
||||
LazyLightApp* app = app_alloc(); |
||||
view_dispatcher_switch_to_view( |
||||
app->view_dispatcher, ViewIndexMainMenu); |
||||
view_dispatcher_run(app->view_dispatcher); |
||||
app_free(app); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
Loading…
Reference in new issue