[FL-2911] IR Universal Audio Remote (#1942)
* Add Audio universal remote * Add signal library for Audio Universal Remote * Update UniversalRemotes.md * Added IR profile for Samsung K450 soundbar (#1892) * Add symbols to API file * Rearrange Audio remote buttons * Add new icons, remove old ones * Remove old signals, add new ones * Add universal audio remote to CLI, refactor code * Improve help text * Correct formatting * Update UniversalRemotes.md * Furi: restore correct api_symbols.csv version Co-authored-by: Alexei Humeniy <yo@ahumeniy.net> Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
|
@ -5,25 +5,21 @@
|
||||||
#include <furi_hal_infrared.h>
|
#include <furi_hal_infrared.h>
|
||||||
#include <flipper_format.h>
|
#include <flipper_format.h>
|
||||||
#include <toolbox/args.h>
|
#include <toolbox/args.h>
|
||||||
|
#include <m-dict.h>
|
||||||
|
|
||||||
#include "infrared_signal.h"
|
#include "infrared_signal.h"
|
||||||
#include "infrared_brute_force.h"
|
#include "infrared_brute_force.h"
|
||||||
|
|
||||||
#include <m-dict.h>
|
|
||||||
|
|
||||||
#define INFRARED_CLI_BUF_SIZE 10
|
#define INFRARED_CLI_BUF_SIZE 10
|
||||||
|
#define INFRARED_ASSETS_FOLDER "infrared/assets"
|
||||||
|
#define INFRARED_BRUTE_FORCE_DUMMY_INDEX 0
|
||||||
|
|
||||||
DICT_DEF2(dict_signals, FuriString*, FURI_STRING_OPLIST, int, M_DEFAULT_OPLIST)
|
DICT_DEF2(dict_signals, FuriString*, FURI_STRING_OPLIST, int, M_DEFAULT_OPLIST)
|
||||||
|
|
||||||
enum RemoteTypes { TV = 0, AC = 1 };
|
|
||||||
|
|
||||||
static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args);
|
static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args);
|
||||||
static void infrared_cli_start_ir_tx(Cli* cli, FuriString* args);
|
static void infrared_cli_start_ir_tx(Cli* cli, FuriString* args);
|
||||||
static void infrared_cli_process_decode(Cli* cli, FuriString* args);
|
static void infrared_cli_process_decode(Cli* cli, FuriString* args);
|
||||||
static void infrared_cli_process_universal(Cli* cli, FuriString* args);
|
static void infrared_cli_process_universal(Cli* cli, FuriString* args);
|
||||||
static void infrared_cli_list_remote_signals(enum RemoteTypes remote_type);
|
|
||||||
static void
|
|
||||||
infrared_cli_brute_force_signals(Cli* cli, enum RemoteTypes remote_type, FuriString* signal);
|
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
const char* cmd;
|
const char* cmd;
|
||||||
|
@ -87,8 +83,10 @@ static void infrared_cli_print_usage(void) {
|
||||||
INFRARED_MIN_FREQUENCY,
|
INFRARED_MIN_FREQUENCY,
|
||||||
INFRARED_MAX_FREQUENCY);
|
INFRARED_MAX_FREQUENCY);
|
||||||
printf("\tir decode <input_file> [<output_file>]\r\n");
|
printf("\tir decode <input_file> [<output_file>]\r\n");
|
||||||
printf("\tir universal <tv, ac> <signal name>\r\n");
|
printf("\tir universal <remote_name> <signal_name>\r\n");
|
||||||
printf("\tir universal list <tv, ac>\r\n");
|
printf("\tir universal list <remote_name>\r\n");
|
||||||
|
// TODO: Do not hardcode universal remote names
|
||||||
|
printf("\tAvailable universal remotes: tv audio ac\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args) {
|
static void infrared_cli_start_ir_rx(Cli* cli, FuriString* args) {
|
||||||
|
@ -356,89 +354,31 @@ static void infrared_cli_process_decode(Cli* cli, FuriString* args) {
|
||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void infrared_cli_process_universal(Cli* cli, FuriString* args) {
|
static void infrared_cli_list_remote_signals(FuriString* remote_name) {
|
||||||
enum RemoteTypes Remote;
|
if(furi_string_empty(remote_name)) {
|
||||||
|
printf("Missing remote name.\r\n");
|
||||||
FuriString* command;
|
return;
|
||||||
FuriString* remote;
|
|
||||||
FuriString* signal;
|
|
||||||
command = furi_string_alloc();
|
|
||||||
remote = furi_string_alloc();
|
|
||||||
signal = furi_string_alloc();
|
|
||||||
|
|
||||||
do {
|
|
||||||
if(!args_read_string_and_trim(args, command)) {
|
|
||||||
infrared_cli_print_usage();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(furi_string_cmp_str(command, "list") == 0) {
|
|
||||||
args_read_string_and_trim(args, remote);
|
|
||||||
if(furi_string_cmp_str(remote, "tv") == 0) {
|
|
||||||
Remote = TV;
|
|
||||||
} else if(furi_string_cmp_str(remote, "ac") == 0) {
|
|
||||||
Remote = AC;
|
|
||||||
} else {
|
|
||||||
printf("Invalid remote type.\r\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
infrared_cli_list_remote_signals(Remote);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(furi_string_cmp_str(command, "tv") == 0) {
|
|
||||||
Remote = TV;
|
|
||||||
} else if(furi_string_cmp_str(command, "ac") == 0) {
|
|
||||||
Remote = AC;
|
|
||||||
} else {
|
|
||||||
printf("Invalid remote type.\r\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
args_read_string_and_trim(args, signal);
|
|
||||||
if(furi_string_empty(signal)) {
|
|
||||||
printf("Must supply a valid signal for type of remote selected.\r\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
infrared_cli_brute_force_signals(cli, Remote, signal);
|
|
||||||
break;
|
|
||||||
|
|
||||||
} while(false);
|
|
||||||
|
|
||||||
furi_string_free(command);
|
|
||||||
furi_string_free(remote);
|
|
||||||
furi_string_free(signal);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void infrared_cli_list_remote_signals(enum RemoteTypes remote_type) {
|
|
||||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
FlipperFormat* ff = flipper_format_buffered_file_alloc(storage);
|
FlipperFormat* ff = flipper_format_buffered_file_alloc(storage);
|
||||||
dict_signals_t signals_dict;
|
FuriString* remote_path = furi_string_alloc_printf(
|
||||||
FuriString* key;
|
"%s/%s.ir", EXT_PATH(INFRARED_ASSETS_FOLDER), furi_string_get_cstr(remote_name));
|
||||||
const char* remote_file = NULL;
|
|
||||||
bool success = false;
|
|
||||||
int max = 1;
|
|
||||||
|
|
||||||
switch(remote_type) {
|
do {
|
||||||
case TV:
|
if(!flipper_format_buffered_file_open_existing(ff, furi_string_get_cstr(remote_path))) {
|
||||||
remote_file = EXT_PATH("infrared/assets/tv.ir");
|
printf("Invalid remote name.\r\n");
|
||||||
break;
|
|
||||||
case AC:
|
|
||||||
remote_file = EXT_PATH("infrared/assets/ac.ir");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dict_signals_t signals_dict;
|
||||||
dict_signals_init(signals_dict);
|
dict_signals_init(signals_dict);
|
||||||
key = furi_string_alloc();
|
|
||||||
|
|
||||||
success = flipper_format_buffered_file_open_existing(ff, remote_file);
|
FuriString* key = furi_string_alloc();
|
||||||
if(success) {
|
FuriString* signal_name = furi_string_alloc();
|
||||||
FuriString* signal_name;
|
|
||||||
signal_name = furi_string_alloc();
|
|
||||||
printf("Valid signals:\r\n");
|
printf("Valid signals:\r\n");
|
||||||
|
int max = 1;
|
||||||
while(flipper_format_read_string(ff, "name", signal_name)) {
|
while(flipper_format_read_string(ff, "name", signal_name)) {
|
||||||
furi_string_set_str(key, furi_string_get_cstr(signal_name));
|
furi_string_set_str(key, furi_string_get_cstr(signal_name));
|
||||||
int* v = dict_signals_get(signals_dict, key);
|
int* v = dict_signals_get(signals_dict, key);
|
||||||
|
@ -449,57 +389,57 @@ static void infrared_cli_list_remote_signals(enum RemoteTypes remote_type) {
|
||||||
dict_signals_set_at(signals_dict, key, 1);
|
dict_signals_set_at(signals_dict, key, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dict_signals_it_t it;
|
dict_signals_it_t it;
|
||||||
for(dict_signals_it(it, signals_dict); !dict_signals_end_p(it); dict_signals_next(it)) {
|
for(dict_signals_it(it, signals_dict); !dict_signals_end_p(it); dict_signals_next(it)) {
|
||||||
const struct dict_signals_pair_s* pair = dict_signals_cref(it);
|
const struct dict_signals_pair_s* pair = dict_signals_cref(it);
|
||||||
printf("\t%s\r\n", furi_string_get_cstr(pair->key));
|
printf("\t%s\r\n", furi_string_get_cstr(pair->key));
|
||||||
}
|
}
|
||||||
furi_string_free(signal_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
furi_string_free(key);
|
furi_string_free(key);
|
||||||
|
furi_string_free(signal_name);
|
||||||
dict_signals_clear(signals_dict);
|
dict_signals_clear(signals_dict);
|
||||||
|
|
||||||
|
} while(false);
|
||||||
|
|
||||||
flipper_format_free(ff);
|
flipper_format_free(ff);
|
||||||
|
furi_string_free(remote_path);
|
||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
infrared_cli_brute_force_signals(Cli* cli, enum RemoteTypes remote_type, FuriString* signal) {
|
infrared_cli_brute_force_signals(Cli* cli, FuriString* remote_name, FuriString* signal_name) {
|
||||||
InfraredBruteForce* brute_force = infrared_brute_force_alloc();
|
InfraredBruteForce* brute_force = infrared_brute_force_alloc();
|
||||||
const char* remote_file = NULL;
|
FuriString* remote_path = furi_string_alloc_printf(
|
||||||
uint32_t i = 0;
|
"%s/%s.ir", EXT_PATH(INFRARED_ASSETS_FOLDER), furi_string_get_cstr(remote_name));
|
||||||
bool success = false;
|
|
||||||
|
|
||||||
switch(remote_type) {
|
infrared_brute_force_set_db_filename(brute_force, furi_string_get_cstr(remote_path));
|
||||||
case TV:
|
infrared_brute_force_add_record(
|
||||||
remote_file = EXT_PATH("infrared/assets/tv.ir");
|
brute_force, INFRARED_BRUTE_FORCE_DUMMY_INDEX, furi_string_get_cstr(signal_name));
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(furi_string_empty(signal_name)) {
|
||||||
|
printf("Missing signal name.\r\n");
|
||||||
break;
|
break;
|
||||||
case AC:
|
}
|
||||||
remote_file = EXT_PATH("infrared/assets/ac.ir");
|
if(!infrared_brute_force_calculate_messages(brute_force)) {
|
||||||
break;
|
printf("Invalid remote name.\r\n");
|
||||||
default:
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
infrared_brute_force_set_db_filename(brute_force, remote_file);
|
|
||||||
infrared_brute_force_add_record(brute_force, i++, furi_string_get_cstr(signal));
|
|
||||||
|
|
||||||
success = infrared_brute_force_calculate_messages(brute_force);
|
|
||||||
if(success) {
|
|
||||||
uint32_t record_count;
|
uint32_t record_count;
|
||||||
uint32_t index = 0;
|
bool running = infrared_brute_force_start(
|
||||||
int records_sent = 0;
|
brute_force, INFRARED_BRUTE_FORCE_DUMMY_INDEX, &record_count);
|
||||||
bool running = false;
|
|
||||||
|
|
||||||
running = infrared_brute_force_start(brute_force, index, &record_count);
|
|
||||||
if(record_count <= 0) {
|
if(record_count <= 0) {
|
||||||
printf("Invalid signal.\n");
|
printf("Invalid signal name.\r\n");
|
||||||
infrared_brute_force_reset(brute_force);
|
break;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Sending %ld codes to the tv.\r\n", record_count);
|
printf("Sending %ld signal(s)...\r\n", record_count);
|
||||||
printf("Press Ctrl-C to stop.\r\n");
|
printf("Press Ctrl-C to stop.\r\n");
|
||||||
|
|
||||||
|
int records_sent = 0;
|
||||||
while(running) {
|
while(running) {
|
||||||
running = infrared_brute_force_send_next(brute_force);
|
running = infrared_brute_force_send_next(brute_force);
|
||||||
|
|
||||||
|
@ -510,14 +450,35 @@ static void
|
||||||
}
|
}
|
||||||
|
|
||||||
infrared_brute_force_stop(brute_force);
|
infrared_brute_force_stop(brute_force);
|
||||||
} else {
|
} while(false);
|
||||||
printf("Invalid signal.\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
furi_string_free(remote_path);
|
||||||
infrared_brute_force_reset(brute_force);
|
infrared_brute_force_reset(brute_force);
|
||||||
infrared_brute_force_free(brute_force);
|
infrared_brute_force_free(brute_force);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void infrared_cli_process_universal(Cli* cli, FuriString* args) {
|
||||||
|
FuriString* arg1 = furi_string_alloc();
|
||||||
|
FuriString* arg2 = furi_string_alloc();
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!args_read_string_and_trim(args, arg1)) break;
|
||||||
|
if(!args_read_string_and_trim(args, arg2)) break;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
if(furi_string_empty(arg1)) {
|
||||||
|
printf("Wrong arguments.\r\n");
|
||||||
|
infrared_cli_print_usage();
|
||||||
|
} else if(furi_string_equal_str(arg1, "list")) {
|
||||||
|
infrared_cli_list_remote_signals(arg2);
|
||||||
|
} else {
|
||||||
|
infrared_cli_brute_force_signals(cli, arg1, arg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_string_free(arg1);
|
||||||
|
furi_string_free(arg2);
|
||||||
|
}
|
||||||
|
|
||||||
static void infrared_cli_start_ir(Cli* cli, FuriString* args, void* context) {
|
static void infrared_cli_start_ir(Cli* cli, FuriString* args, void* context) {
|
||||||
UNUSED(context);
|
UNUSED(context);
|
||||||
if(furi_hal_infrared_is_busy()) {
|
if(furi_hal_infrared_is_busy()) {
|
||||||
|
|
|
@ -16,6 +16,7 @@ ADD_SCENE(infrared, remote_list, RemoteList)
|
||||||
ADD_SCENE(infrared, universal, Universal)
|
ADD_SCENE(infrared, universal, Universal)
|
||||||
ADD_SCENE(infrared, universal_tv, UniversalTV)
|
ADD_SCENE(infrared, universal_tv, UniversalTV)
|
||||||
ADD_SCENE(infrared, universal_ac, UniversalAC)
|
ADD_SCENE(infrared, universal_ac, UniversalAC)
|
||||||
|
ADD_SCENE(infrared, universal_audio, UniversalAudio)
|
||||||
ADD_SCENE(infrared, debug, Debug)
|
ADD_SCENE(infrared, debug, Debug)
|
||||||
ADD_SCENE(infrared, error_databases, ErrorDatabases)
|
ADD_SCENE(infrared, error_databases, ErrorDatabases)
|
||||||
ADD_SCENE(infrared, rpc, Rpc)
|
ADD_SCENE(infrared, rpc, Rpc)
|
||||||
|
|
|
@ -21,6 +21,12 @@ void infrared_scene_universal_on_enter(void* context) {
|
||||||
SubmenuIndexUniversalTV,
|
SubmenuIndexUniversalTV,
|
||||||
infrared_scene_universal_submenu_callback,
|
infrared_scene_universal_submenu_callback,
|
||||||
context);
|
context);
|
||||||
|
submenu_add_item(
|
||||||
|
submenu,
|
||||||
|
"Audio Players",
|
||||||
|
SubmenuIndexUniversalAudio,
|
||||||
|
infrared_scene_universal_submenu_callback,
|
||||||
|
context);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu,
|
submenu,
|
||||||
"Air Conditioners",
|
"Air Conditioners",
|
||||||
|
@ -45,7 +51,7 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) {
|
||||||
scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC);
|
scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexUniversalAudio) {
|
} else if(event.event == SubmenuIndexUniversalAudio) {
|
||||||
//TODO Implement Audio universal remote
|
scene_manager_next_scene(scene_manager, InfraredSceneUniversalAudio);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
#include "../infrared_i.h"
|
||||||
|
|
||||||
|
#include "common/infrared_scene_universal_common.h"
|
||||||
|
|
||||||
|
void infrared_scene_universal_audio_on_enter(void* context) {
|
||||||
|
infrared_scene_universal_common_on_enter(context);
|
||||||
|
|
||||||
|
Infrared* infrared = context;
|
||||||
|
ButtonPanel* button_panel = infrared->button_panel;
|
||||||
|
InfraredBruteForce* brute_force = infrared->brute_force;
|
||||||
|
|
||||||
|
infrared_brute_force_set_db_filename(brute_force, EXT_PATH("infrared/assets/audio.ir"));
|
||||||
|
|
||||||
|
button_panel_reserve(button_panel, 2, 4);
|
||||||
|
uint32_t i = 0;
|
||||||
|
button_panel_add_item(
|
||||||
|
button_panel,
|
||||||
|
i,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
3,
|
||||||
|
11,
|
||||||
|
&I_Power_25x27,
|
||||||
|
&I_Power_hvr_25x27,
|
||||||
|
infrared_scene_universal_common_item_callback,
|
||||||
|
context);
|
||||||
|
infrared_brute_force_add_record(brute_force, i++, "Power");
|
||||||
|
button_panel_add_item(
|
||||||
|
button_panel,
|
||||||
|
i,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
36,
|
||||||
|
11,
|
||||||
|
&I_Mute_25x27,
|
||||||
|
&I_Mute_hvr_25x27,
|
||||||
|
infrared_scene_universal_common_item_callback,
|
||||||
|
context);
|
||||||
|
infrared_brute_force_add_record(brute_force, i++, "Mute");
|
||||||
|
button_panel_add_item(
|
||||||
|
button_panel,
|
||||||
|
i,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
41,
|
||||||
|
&I_Play_25x27,
|
||||||
|
&I_Play_hvr_25x27,
|
||||||
|
infrared_scene_universal_common_item_callback,
|
||||||
|
context);
|
||||||
|
infrared_brute_force_add_record(brute_force, i++, "Play");
|
||||||
|
button_panel_add_item(
|
||||||
|
button_panel,
|
||||||
|
i,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
36,
|
||||||
|
41,
|
||||||
|
&I_Pause_25x27,
|
||||||
|
&I_Pause_hvr_25x27,
|
||||||
|
infrared_scene_universal_common_item_callback,
|
||||||
|
context);
|
||||||
|
infrared_brute_force_add_record(brute_force, i++, "Pause");
|
||||||
|
button_panel_add_item(
|
||||||
|
button_panel,
|
||||||
|
i,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
71,
|
||||||
|
&I_TrackPrev_25x27,
|
||||||
|
&I_TrackPrev_hvr_25x27,
|
||||||
|
infrared_scene_universal_common_item_callback,
|
||||||
|
context);
|
||||||
|
infrared_brute_force_add_record(brute_force, i++, "Prev");
|
||||||
|
button_panel_add_item(
|
||||||
|
button_panel,
|
||||||
|
i,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
36,
|
||||||
|
71,
|
||||||
|
&I_TrackNext_25x27,
|
||||||
|
&I_TrackNext_hvr_25x27,
|
||||||
|
infrared_scene_universal_common_item_callback,
|
||||||
|
context);
|
||||||
|
infrared_brute_force_add_record(brute_force, i++, "Next");
|
||||||
|
button_panel_add_item(
|
||||||
|
button_panel,
|
||||||
|
i,
|
||||||
|
0,
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
101,
|
||||||
|
&I_Vol_down_25x27,
|
||||||
|
&I_Vol_down_hvr_25x27,
|
||||||
|
infrared_scene_universal_common_item_callback,
|
||||||
|
context);
|
||||||
|
infrared_brute_force_add_record(brute_force, i++, "Vol_dn");
|
||||||
|
button_panel_add_item(
|
||||||
|
button_panel,
|
||||||
|
i,
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
36,
|
||||||
|
101,
|
||||||
|
&I_Vol_up_25x27,
|
||||||
|
&I_Vol_up_hvr_25x27,
|
||||||
|
infrared_scene_universal_common_item_callback,
|
||||||
|
context);
|
||||||
|
infrared_brute_force_add_record(brute_force, i++, "Vol_up");
|
||||||
|
|
||||||
|
button_panel_add_label(button_panel, 1, 8, FontPrimary, "Mus. remote");
|
||||||
|
|
||||||
|
view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical);
|
||||||
|
view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewStack);
|
||||||
|
|
||||||
|
infrared_show_loading_popup(infrared, true);
|
||||||
|
bool success = infrared_brute_force_calculate_messages(brute_force);
|
||||||
|
infrared_show_loading_popup(infrared, false);
|
||||||
|
|
||||||
|
if(!success) {
|
||||||
|
scene_manager_next_scene(infrared->scene_manager, InfraredSceneErrorDatabases);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool infrared_scene_universal_audio_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
return infrared_scene_universal_common_on_event(context, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void infrared_scene_universal_audio_on_exit(void* context) {
|
||||||
|
infrared_scene_universal_common_on_exit(context);
|
||||||
|
}
|
BIN
assets/icons/Infrared/Pause_25x27.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
assets/icons/Infrared/Pause_hvr_25x27.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
assets/icons/Infrared/Play_25x27.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
assets/icons/Infrared/Play_hvr_25x27.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
assets/icons/Infrared/TrackNext_25x27.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
assets/icons/Infrared/TrackNext_hvr_25x27.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
assets/icons/Infrared/TrackPrev_25x27.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
assets/icons/Infrared/TrackPrev_hvr_25x27.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
244
assets/resources/infrared/assets/audio.ir
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
Filetype: IR library file
|
||||||
|
Version: 1
|
||||||
|
#
|
||||||
|
# Model: NoName Unknown Audio remote
|
||||||
|
name: Play
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 00 00 00 00
|
||||||
|
command: 43 00 00 00
|
||||||
|
#
|
||||||
|
name: Vol_up
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 00 00 00 00
|
||||||
|
command: 15 00 00 00
|
||||||
|
#
|
||||||
|
name: Vol_dn
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 00 00 00 00
|
||||||
|
command: 07 00 00 00
|
||||||
|
#
|
||||||
|
name: Next
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 00 00 00 00
|
||||||
|
command: 40 00 00 00
|
||||||
|
#
|
||||||
|
name: Prev
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 00 00 00 00
|
||||||
|
command: 44 00 00 00
|
||||||
|
#
|
||||||
|
# Model: Western Digital Unknown
|
||||||
|
name: Power
|
||||||
|
type: parsed
|
||||||
|
protocol: NECext
|
||||||
|
address: 84 79 00 00
|
||||||
|
command: 12 ED 00 00
|
||||||
|
#
|
||||||
|
name: Play
|
||||||
|
type: parsed
|
||||||
|
protocol: NECext
|
||||||
|
address: 84 79 00 00
|
||||||
|
command: 0A F5 00 00
|
||||||
|
#
|
||||||
|
name: Vol_up
|
||||||
|
type: parsed
|
||||||
|
protocol: NECext
|
||||||
|
address: 84 79 00 00
|
||||||
|
command: 05 FA 00 00
|
||||||
|
#
|
||||||
|
name: Vol_dn
|
||||||
|
type: parsed
|
||||||
|
protocol: NECext
|
||||||
|
address: 84 79 00 00
|
||||||
|
command: 00 FF 00 00
|
||||||
|
#
|
||||||
|
name: Next
|
||||||
|
type: parsed
|
||||||
|
protocol: NECext
|
||||||
|
address: 84 79 00 00
|
||||||
|
command: 01 FE 00 00
|
||||||
|
#
|
||||||
|
name: Prev
|
||||||
|
type: parsed
|
||||||
|
protocol: NECext
|
||||||
|
address: 84 79 00 00
|
||||||
|
command: 02 FD 00 00
|
||||||
|
#
|
||||||
|
# Model: Yamaha RAV15
|
||||||
|
name: Play
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 00 00 00 00
|
||||||
|
command: 43 00 00 00
|
||||||
|
#
|
||||||
|
name: Vol_up
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 00 00 00 00
|
||||||
|
command: 15 00 00 00
|
||||||
|
#
|
||||||
|
name: Vol_dn
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 00 00 00 00
|
||||||
|
command: 07 00 00 00
|
||||||
|
#
|
||||||
|
name: Next
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 00 00 00 00
|
||||||
|
command: 40 00 00 00
|
||||||
|
#
|
||||||
|
name: Prev
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 00 00 00 00
|
||||||
|
command: 44 00 00 00
|
||||||
|
#
|
||||||
|
# Model: Yamaha RX-V375
|
||||||
|
name: Power
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 7E 00 00 00
|
||||||
|
command: 2A 00 00 00
|
||||||
|
#
|
||||||
|
name: Vol_up
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 7A 00 00 00
|
||||||
|
command: 1A 00 00 00
|
||||||
|
#
|
||||||
|
name: Mute
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 7A 00 00 00
|
||||||
|
command: 1C 00 00 00
|
||||||
|
#
|
||||||
|
name: Vol_dn
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 7A 00 00 00
|
||||||
|
command: 1B 00 00 00
|
||||||
|
#
|
||||||
|
# Model: SVEN HT-415
|
||||||
|
name: Power
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 41 00 00 00
|
||||||
|
command: 42 00 00 00
|
||||||
|
#
|
||||||
|
name: Vol_up
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 41 00 00 00
|
||||||
|
command: 0B 00 00 00
|
||||||
|
#
|
||||||
|
name: Vol_dn
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 41 00 00 00
|
||||||
|
command: 1B 00 00 00
|
||||||
|
#
|
||||||
|
name: Mute
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 41 00 00 00
|
||||||
|
command: 56 00 00 00
|
||||||
|
#
|
||||||
|
# Model: HUAYU AKB74475490
|
||||||
|
name: Power
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 04 00 00 00
|
||||||
|
command: 08 00 00 00
|
||||||
|
#
|
||||||
|
name: Play
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 04 00 00 00
|
||||||
|
command: B0 00 00 00
|
||||||
|
#
|
||||||
|
name: Pause
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 04 00 00 00
|
||||||
|
command: BA 00 00 00
|
||||||
|
#
|
||||||
|
name: Vol_up
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 04 00 00 00
|
||||||
|
command: 02 00 00 00
|
||||||
|
#
|
||||||
|
name: Vol_dn
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 04 00 00 00
|
||||||
|
command: 03 00 00 00
|
||||||
|
#
|
||||||
|
name: Prev
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 04 00 00 00
|
||||||
|
command: 8F 00 00 00
|
||||||
|
#
|
||||||
|
name: Next
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 04 00 00 00
|
||||||
|
command: 8E 00 00 00
|
||||||
|
#
|
||||||
|
name: Mute
|
||||||
|
type: parsed
|
||||||
|
protocol: NEC
|
||||||
|
address: 04 00 00 00
|
||||||
|
command: 09 00 00 00
|
||||||
|
#
|
||||||
|
# Model: Samsung HW-K450 Soundbar
|
||||||
|
#
|
||||||
|
name: Power
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.330000
|
||||||
|
data: 4637 4376 612 419 584 420 584 420 583 421 582 1427 531 1477 531 472 532 472 557 1452 556 1451 557 1451 557 1452 556 447 557 448 556 449 555 449 555 4453 554 450 554 450 554 451 553 450 554 451 553 451 553 451 553 450 554 1455 553 1454 554 1454 554 451 553 1454 554 1454 554 1455 553 1454 554 451 553 450 554 450 554 1455 553 55439 4554 4458 555 449 555 449 555 450 554 450 554 1455 553 1454 554 451 553 450 554 1454 554 1454 554 1454 554 1455 553 450 554 451 553 451 553 451 553 4453 554 451 553 451 552 451 553 451 553 451 553 451 553 451 553 451 553 1455 553 1455 553 1455 553 451 553 1455 553 1455 553 1455 553 1455 553 451 553 451 552 451 553 1455 553
|
||||||
|
#
|
||||||
|
name: Play
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.330000
|
||||||
|
data: 4636 4380 612 392 612 394 610 394 610 419 583 1399 557 1452 556 473 556 448 556 1428 581 1453 555 1453 555 1453 555 449 555 450 554 451 553 452 552 4457 551 452 552 452 552 452 552 452 552 452 552 1457 551 452 552 1457 551 452 552 452 552 453 551 1457 552 1457 551 452 552 1457 551 452 552 1457 551 1457 551 1457 552 452 552 55450 4551 4461 553 451 553 452 552 452 552 452 552 1456 552 1456 552 452 552 452 552 1456 552 1456 552 1456 552 1456 552 452 552 452 552 453 551 453 551 4456 551 453 551 453 551 453 551 453 551 453 551 1457 551 453 551 1457 552 453 551 454 550 454 550 1457 552 1457 551 454 550 1457 551 454 550 1458 551 1457 551 1458 550 454 550
|
||||||
|
#
|
||||||
|
name: Vol_up
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.330000
|
||||||
|
data: 4640 4405 583 420 583 421 582 421 583 422 581 1427 531 1478 530 473 531 472 557 1452 557 1452 556 1452 556 1452 556 448 556 448 556 449 555 450 554 4454 554 451 553 451 553 451 553 451 553 1455 554 1455 553 1455 553 451 553 1455 553 1456 553 1456 553 451 553 451 553 451 553 451 554 1455 554 451 553 452 553 451 553 1456 553 55447 4556 4458 555 449 555 450 554 450 554 450 554 1455 553 1455 553 451 553 451 553 1455 553 1455 553 1455 553 1455 553 451 553 451 553 451 553 451 553 4454 553 451 553 450 554 451 553 450 554 1455 553 1455 553 1455 553 451 553 1455 553 1455 553 1455 553 451 553 451 553 451 553 450 554 1455 553 451 553 451 553 451 553 1455 553
|
||||||
|
#
|
||||||
|
name: Vol_dn
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.330000
|
||||||
|
data: 4636 4378 613 393 611 392 612 393 611 393 557 1451 558 1450 610 420 583 421 557 1427 581 1452 556 1452 556 1452 556 448 555 449 555 450 554 450 554 4455 553 451 553 451 553 451 553 451 553 451 553 451 553 452 552 1456 553 1456 552 1456 553 1456 552 451 553 1456 553 1456 552 1456 553 451 553 451 553 452 552 451 553 1456 552 55452 4553 4461 553 450 554 451 553 451 553 451 553 1456 553 1456 552 451 553 451 553 1456 552 1455 553 1455 553 1455 553 451 553 451 553 451 553 451 553 4456 552 451 553 451 553 451 553 451 553 451 553 451 553 451 553 1456 552 1455 553 1455 553 1455 553 451 553 1455 553 1456 552 1456 552 451 553 451 553 451 553 451 553 1456 552
|
||||||
|
#
|
||||||
|
name: Prev
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.330000
|
||||||
|
data: 255 113623 4638 4378 613 391 612 392 559 446 558 446 558 1477 531 1477 532 472 532 472 532 1476 532 1476 532 1476 532 1477 531 473 555 449 555 449 555 450 554 4455 554 450 554 450 554 450 554 450 554 1455 554 1455 554 450 554 1455 554 450 555 450 554 450 554 1455 554 451 553 451 553 1455 554 450 554 1455 554 1456 553 1455 554 450 554
|
||||||
|
#
|
||||||
|
name: Next
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.330000
|
||||||
|
data: 4557 4430 611 392 610 394 559 445 559 446 558 1451 558 1477 531 448 556 472 532 1476 532 1477 532 1477 531 1477 531 473 556 449 555 449 555 450 554 4454 554 450 554 450 554 450 554 450 555 450 554 450 554 1455 554 1455 554 450 554 450 554 450 554 1455 554 1455 554 1455 553 451 553 450 554 1455 554 1455 554 1455 554 450 554 55458 4555 4459 554 450 554 450 554 450 554 450 554 1455 553 1455 553 450 554 450 554 1455 553 1455 553 1455 553 1455 553 450 554 450 554 450 554 450 554 4454 554 450 554 450 554 450 554 451 553 450 554 450 554 1455 553 1455 553 451 553 450 554 450 554 1455 553 1455 553 1455 553 450 554 451 553 1455 554 1455 553 1455 553 450 554
|
||||||
|
#
|
||||||
|
name: Mute
|
||||||
|
type: raw
|
||||||
|
frequency: 38000
|
||||||
|
duty_cycle: 0.330000
|
||||||
|
data: 4639 4406 586 418 585 393 559 447 557 447 557 1477 532 1477 532 472 532 472 532 1476 533 1476 532 1476 532 1476 532 473 555 449 555 449 555 449 555 4455 554 450 554 450 554 450 554 450 554 1455 554 450 554 450 554 450 554 1455 554 1455 553 1455 553 450 554 450 554 1455 554 1455 554 1455 554 450 554 450 554 450 554 1455 554 55454 4557 4458 555 449 555 449 555 450 554 450 554 1455 554 1455 553 450 554 450 554 1455 554 1455 554 1454 554 1455 554 450 554 450 554 450 555 450 554 4455 553 450 554 450 554 450 554 450 554 1455 554 450 554 450 554 450 554 1455 554 1455 554 1455 553 450 554 450 554 1455 554 1455 553 1455 554 450 554 450 554 450 554 1455 554
|
|
@ -1,4 +1,18 @@
|
||||||
# Universal Remotes
|
# Universal Remotes
|
||||||
|
## Audio Players
|
||||||
|
### Recording signals
|
||||||
|
Adding your audio player to the universal remote is quite straightforward. 8 signals can be recorded: `Power`, `Play`, `Pause`, `Vol_up`, `Vol_dn`, `Next`, `Prev`, `Mute`. Any of them can be omitted if it is not supported by the device.
|
||||||
|
|
||||||
|
The signal names are self-explanatory.
|
||||||
|
On many remotes, the `Play` button doubles as `Pause`. In this case record it as `Play` omitting the `Pause`.
|
||||||
|
Make sure that every signal does what it's supposed to.
|
||||||
|
|
||||||
|
If everything checks out, append these signals **to the end** of the [Audio players universal remote file](/assets/resources/infrared/assets/audio.ir).
|
||||||
|
|
||||||
|
The order of signals is not important, but they must be preceded by a following comment: `# Model: <Your model name>` in order to keep the library organised.
|
||||||
|
|
||||||
|
When done, open a pull request containing the changed file.
|
||||||
|
|
||||||
## Air Conditioners
|
## Air Conditioners
|
||||||
### Recording signals
|
### Recording signals
|
||||||
Air conditioners differ from most other infrared-controlled devices because their state is tracked by the remote.
|
Air conditioners differ from most other infrared-controlled devices because their state is tracked by the remote.
|
||||||
|
@ -31,7 +45,7 @@ Finally, record the `Off` signal:
|
||||||
4. Save the resulting signal under the name `Off`.
|
4. Save the resulting signal under the name `Off`.
|
||||||
|
|
||||||
The resulting remote file should now contain 6 signals. Any of them can be omitted, but that will mean that this functionality will not be used.
|
The resulting remote file should now contain 6 signals. Any of them can be omitted, but that will mean that this functionality will not be used.
|
||||||
Test the file against the actual device. Every signal must do what it's supposed to.
|
Test the file against the actual device. Make sure that every signal does what it's supposed to.
|
||||||
|
|
||||||
If everything checks out, append these signals **to the end** of the [A/C universal remote file](/assets/resources/infrared/assets/ac.ir).
|
If everything checks out, append these signals **to the end** of the [A/C universal remote file](/assets/resources/infrared/assets/ac.ir).
|
||||||
|
|
||||||
|
|