#include #include #include #include #include #include #include #include /* ===================== 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; }