[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>
This commit is contained in:
Georgii Surkov 2022-10-28 19:43:54 +03:00 committed by GitHub
parent 93a6e17ce5
commit d5f791b1fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 486 additions and 127 deletions

View File

@ -5,25 +5,21 @@
#include <furi_hal_infrared.h>
#include <flipper_format.h>
#include <toolbox/args.h>
#include <m-dict.h>
#include "infrared_signal.h"
#include "infrared_brute_force.h"
#include <m-dict.h>
#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)
enum RemoteTypes { TV = 0, AC = 1 };
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_process_decode(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 {
const char* cmd;
@ -87,8 +83,10 @@ static void infrared_cli_print_usage(void) {
INFRARED_MIN_FREQUENCY,
INFRARED_MAX_FREQUENCY);
printf("\tir decode <input_file> [<output_file>]\r\n");
printf("\tir universal <tv, ac> <signal name>\r\n");
printf("\tir universal list <tv, ac>\r\n");
printf("\tir universal <remote_name> <signal_name>\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) {
@ -356,89 +354,31 @@ static void infrared_cli_process_decode(Cli* cli, FuriString* args) {
furi_record_close(RECORD_STORAGE);
}
static void infrared_cli_process_universal(Cli* cli, FuriString* args) {
enum RemoteTypes Remote;
FuriString* command;
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;
static void infrared_cli_list_remote_signals(FuriString* remote_name) {
if(furi_string_empty(remote_name)) {
printf("Missing remote name.\r\n");
return;
}
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);
FlipperFormat* ff = flipper_format_buffered_file_alloc(storage);
dict_signals_t signals_dict;
FuriString* key;
const char* remote_file = NULL;
bool success = false;
int max = 1;
FuriString* remote_path = furi_string_alloc_printf(
"%s/%s.ir", EXT_PATH(INFRARED_ASSETS_FOLDER), furi_string_get_cstr(remote_name));
switch(remote_type) {
case TV:
remote_file = EXT_PATH("infrared/assets/tv.ir");
break;
case AC:
remote_file = EXT_PATH("infrared/assets/ac.ir");
break;
default:
do {
if(!flipper_format_buffered_file_open_existing(ff, furi_string_get_cstr(remote_path))) {
printf("Invalid remote name.\r\n");
break;
}
dict_signals_t signals_dict;
dict_signals_init(signals_dict);
key = furi_string_alloc();
success = flipper_format_buffered_file_open_existing(ff, remote_file);
if(success) {
FuriString* signal_name;
signal_name = furi_string_alloc();
FuriString* key = furi_string_alloc();
FuriString* signal_name = furi_string_alloc();
printf("Valid signals:\r\n");
int max = 1;
while(flipper_format_read_string(ff, "name", signal_name)) {
furi_string_set_str(key, furi_string_get_cstr(signal_name));
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_it_t 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);
printf("\t%s\r\n", furi_string_get_cstr(pair->key));
}
furi_string_free(signal_name);
}
furi_string_free(key);
furi_string_free(signal_name);
dict_signals_clear(signals_dict);
} while(false);
flipper_format_free(ff);
furi_string_free(remote_path);
furi_record_close(RECORD_STORAGE);
}
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();
const char* remote_file = NULL;
uint32_t i = 0;
bool success = false;
FuriString* remote_path = furi_string_alloc_printf(
"%s/%s.ir", EXT_PATH(INFRARED_ASSETS_FOLDER), furi_string_get_cstr(remote_name));
switch(remote_type) {
case TV:
remote_file = EXT_PATH("infrared/assets/tv.ir");
infrared_brute_force_set_db_filename(brute_force, furi_string_get_cstr(remote_path));
infrared_brute_force_add_record(
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;
case AC:
remote_file = EXT_PATH("infrared/assets/ac.ir");
break;
default:
}
if(!infrared_brute_force_calculate_messages(brute_force)) {
printf("Invalid remote name.\r\n");
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 index = 0;
int records_sent = 0;
bool running = false;
bool running = infrared_brute_force_start(
brute_force, INFRARED_BRUTE_FORCE_DUMMY_INDEX, &record_count);
running = infrared_brute_force_start(brute_force, index, &record_count);
if(record_count <= 0) {
printf("Invalid signal.\n");
infrared_brute_force_reset(brute_force);
return;
printf("Invalid signal name.\r\n");
break;
}
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");
int records_sent = 0;
while(running) {
running = infrared_brute_force_send_next(brute_force);
@ -510,14 +450,35 @@ static void
}
infrared_brute_force_stop(brute_force);
} else {
printf("Invalid signal.\r\n");
}
} while(false);
furi_string_free(remote_path);
infrared_brute_force_reset(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) {
UNUSED(context);
if(furi_hal_infrared_is_busy()) {

View File

@ -16,6 +16,7 @@ ADD_SCENE(infrared, remote_list, RemoteList)
ADD_SCENE(infrared, universal, Universal)
ADD_SCENE(infrared, universal_tv, UniversalTV)
ADD_SCENE(infrared, universal_ac, UniversalAC)
ADD_SCENE(infrared, universal_audio, UniversalAudio)
ADD_SCENE(infrared, debug, Debug)
ADD_SCENE(infrared, error_databases, ErrorDatabases)
ADD_SCENE(infrared, rpc, Rpc)

View File

@ -21,6 +21,12 @@ void infrared_scene_universal_on_enter(void* context) {
SubmenuIndexUniversalTV,
infrared_scene_universal_submenu_callback,
context);
submenu_add_item(
submenu,
"Audio Players",
SubmenuIndexUniversalAudio,
infrared_scene_universal_submenu_callback,
context);
submenu_add_item(
submenu,
"Air Conditioners",
@ -45,7 +51,7 @@ bool infrared_scene_universal_on_event(void* context, SceneManagerEvent event) {
scene_manager_next_scene(scene_manager, InfraredSceneUniversalAC);
consumed = true;
} else if(event.event == SubmenuIndexUniversalAudio) {
//TODO Implement Audio universal remote
scene_manager_next_scene(scene_manager, InfraredSceneUniversalAudio);
consumed = true;
}
}

View File

@ -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);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View 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

View File

@ -1,4 +1,18 @@
# 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
### Recording signals
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`.
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).