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