From c4f084a99168f7ee01062c5a6fd3da130cb4225e Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Thu, 1 Jul 2021 00:17:07 +0200 Subject: [PATCH] Merge JSON ircodes (#2048) * add decodeIRJson and JSON remote option * handle JSON API commands also * removed code that forced IR codes in a certain range to be decoded by decodeIR24. Generate default ir.json files for currently supported remotes. * comment out printing API commands in IR handling * refactor decodeIRJson to change how ir.json is loaded add support for calling several c functions * Handle setting palette when effect is still on default solid and will not display it * remove colorUpdated notifier that was pasted in accidentally * Update to handle both 24-key and 24-key old remotes (#1969) * Update readme.md * Update ir.cpp Handle both 24-key and 24-key old in decodeIR switch statement * Re-add JSON remote option Co-authored-by: Scott Bailey Co-authored-by: Artacus <40248830+scottrbailey@users.noreply.github.com> --- usermods/JSON_IR_remote/21-key_ir.json | 119 +++++++++ usermods/JSON_IR_remote/24-key_ir.json | 147 +++++++++++ usermods/JSON_IR_remote/32-key_ir.json | 185 ++++++++++++++ usermods/JSON_IR_remote/40-key-black_ir.json | 233 ++++++++++++++++++ usermods/JSON_IR_remote/40-key-blue_ir.json | 217 +++++++++++++++++ usermods/JSON_IR_remote/44-key_ir.json | 241 +++++++++++++++++++ usermods/JSON_IR_remote/6-key_ir.json | 38 +++ usermods/JSON_IR_remote/9-key_ir.json | 47 ++++ usermods/JSON_IR_remote/IR_Remote_Codes.xlsx | Bin 0 -> 25093 bytes usermods/JSON_IR_remote/ir_json_maker.py | 108 +++++++++ usermods/JSON_IR_remote/readme.md | 33 +++ wled00/data/settings_leds.htm | 17 +- wled00/fcn_declare.h | 1 + wled00/html_settings.h | 58 ++--- wled00/ir.cpp | 133 ++++++++-- 15 files changed, 1519 insertions(+), 58 deletions(-) create mode 100644 usermods/JSON_IR_remote/21-key_ir.json create mode 100644 usermods/JSON_IR_remote/24-key_ir.json create mode 100644 usermods/JSON_IR_remote/32-key_ir.json create mode 100644 usermods/JSON_IR_remote/40-key-black_ir.json create mode 100644 usermods/JSON_IR_remote/40-key-blue_ir.json create mode 100644 usermods/JSON_IR_remote/44-key_ir.json create mode 100644 usermods/JSON_IR_remote/6-key_ir.json create mode 100644 usermods/JSON_IR_remote/9-key_ir.json create mode 100644 usermods/JSON_IR_remote/IR_Remote_Codes.xlsx create mode 100644 usermods/JSON_IR_remote/ir_json_maker.py create mode 100644 usermods/JSON_IR_remote/readme.md diff --git a/usermods/JSON_IR_remote/21-key_ir.json b/usermods/JSON_IR_remote/21-key_ir.json new file mode 100644 index 00000000..cc71b14d --- /dev/null +++ b/usermods/JSON_IR_remote/21-key_ir.json @@ -0,0 +1,119 @@ +{ + "desc": "21-key", + "0xFFA25D": { + "label": "On", + "pos": "1x1", + "cmd": "T=1" + }, + "0xFF629D": { + "label": "Off", + "pos": "1x2", + "cmd": "T=0" + }, + "0xFFE21D": { + "label": "Flash", + "pos": "1x3", + "cmnt": "Cycle Effects", + "cmd": "CY=0&FX=~" + }, + "0xFF22DD": { + "label": "Strobe", + "pos": "2x1", + "cmnt": "Sinelon Dual", + "cmd": "CY=0&FX=93" + }, + "0xFF02FD": { + "label": "Fade", + "pos": "2x2", + "cmnt": "Rain", + "cmd": "CY=0&FX=43" + }, + "0xFFC23D": { + "label": "Smooth", + "pos": "2x3", + "cmnt": "Aurora", + "cmd": "CY=0&FX=38" + }, + "0xFFE01F": { + "label": "Bright +", + "pos": "3x1", + "cmd": "A=~16" + }, + "0xFFA857": { + "label": "Bright -", + "pos": "3x2", + "cmd": "A=~-16" + }, + "0xFF906F": { + "label": "White", + "pos": "3x3", + "cmd": "FP=5&CL=hFFFFFF&C2=hFFFFFF&C3=hA8A8A8" + }, + "0xFF6897": { + "label": "Red", + "pos": "4x1", + "cmnt": "Lava", + "cmd": "FP=8" + }, + "0xFF9867": { + "label": "Green", + "pos": "4x2", + "cmnt": "Forest", + "cmd": "FP=10" + }, + "0xFFB04F": { + "label": "Blue", + "pos": "4x3", + "cmnt": "Breeze", + "cmd": "FP=15" + }, + "0xFF30CF": { + "label": "Tomato", + "pos": "5x1", + "cmd": "FP=5&CL=hFF6347&C2=hFFBF47&C3=hA85859" + }, + "0xFF18E7": { + "label": "LightGreen", + "pos": "5x2", + "cmnt": "Rivendale", + "cmd": "FP=14" + }, + "0xFF7A85": { + "label": "SkyBlue", + "pos": "5x3", + "cmnt": "Ocean", + "cmd": "FP=9" + }, + "0xFF10EF": { + "label": "Orange", + "pos": "6x1", + "cmnt": "Orangery", + "cmd": "FP=47" + }, + "0xFF38C7": { + "label": "Aqua", + "pos": "6x2", + "cmd": "FP=5&CL=hFFFF&C2=h7FFF&C3=h39A895" + }, + "0xFF5AA5": { + "label": "Purple", + "pos": "6x3", + "cmd": "FP=5&CL=h663399&C2=h993399&C3=h473864" + }, + "0xFF42BD": { + "label": "Yellow", + "pos": "7x1", + "cmd": "FP=5&CL=hFFFF00&C2=hFFC800&C3=hFDFFDE" + }, + "0xFF4AB5": { + "label": "Cyan", + "pos": "7x2", + "cmnt": "Beech", + "cmd": "FP=22" + }, + "0xFF52AD": { + "label": "Pink", + "pos": "7x3", + "cmd": "FP=5&CL=hFFC0CB&C2=hFFD4C0&C3=hA88C96" + } +} \ No newline at end of file diff --git a/usermods/JSON_IR_remote/24-key_ir.json b/usermods/JSON_IR_remote/24-key_ir.json new file mode 100644 index 00000000..48be10b9 --- /dev/null +++ b/usermods/JSON_IR_remote/24-key_ir.json @@ -0,0 +1,147 @@ +{ + "desc": "24-key", + "0xF700FF": { + "label": "+", + "pos": "1x1", + "cmnt": "Speed +", + "cmd": "SX=~16" + }, + "0xF7807F": { + "label": "-", + "pos": "1x2", + "cmnt": "Speed -", + "cmd": "SX=~-16" + }, + "0xF740BF": { + "label": "On/Off", + "pos": "1x3", + "cmnt": "Toggle On/Off", + "cmd": "T=2" + }, + "0xF7C03F": { + "label": "W", + "pos": "1x4", + "cmnt": "Cycle color palette", + "cmd": "FP=~" + }, + "0xF720DF": { + "label": "R", + "pos": "2x1", + "cmnt": "Lava", + "cmd": "FP=8" + }, + "0xF7A05F": { + "label": "G", + "pos": "2x2", + "cmnt": "Forest", + "cmd": "FP=10" + }, + "0xF7609F": { + "label": "B", + "pos": "2x3", + "cmnt": "Breeze", + "cmd": "FP=15" + }, + "0xF7E01F": { + "label": "Bright -", + "pos": "2x4", + "cmnt": "Bright -", + "cmd": "A=~-16" + }, + "0xF710EF": { + "label": "Timer1H", + "pos": "3x1", + "cmnt": "Timer 60 min", + "cmd": "NL=60&NT=0" + }, + "0xF7906F": { + "label": "Timer4H", + "pos": "3x2", + "cmnt": "Timer 30 min", + "cmd": "NL=30&NT=0" + }, + "0xF750AF": { + "label": "Timer8H", + "pos": "3x3", + "cmnt": "Timer 15 min", + "cmd": "NL=15&NT=0" + }, + "0xF7D02F": { + "label": "Bright128", + "pos": "3x4", + "cmnt": "Bright 128", + "cmd": "A=128" + }, + "0xF730CF": { + "label": "Music1", + "pos": "4x1", + "cmnt": "Cycle FX +", + "cmd": "FX=~" + }, + "0xF7B04F": { + "label": "Music2", + "pos": "4x2", + "cmnt": "Cycle FX -", + "cmd": "FX=~-1" + }, + "0xF7708F": { + "label": "Music3", + "pos": "4x3", + "cmnt": "Reset FX and FP", + "cmd": "FX=1&PF=6" + }, + "0xF7F00F": { + "label": "Bright +", + "pos": "4x4", + "cmnt": "Bright +", + "cmd": "A=~16" + }, + "0xF708F7": { + "label": "Mode1", + "pos": "5x1", + "cmnt": "Preset 1", + "cmd": "PL=1" + }, + "0xF78877": { + "label": "Mode2", + "pos": "5x2", + "cmnt": "Preset 2", + "cmd": "PL=2" + }, + "0xF748B7": { + "label": "Mode3", + "pos": "5x3", + "cmnt": "Preset 3", + "cmd": "PL=3" + }, + "0xF7C837": { + "label": "Up", + "pos": "5x4", + "cmnt": "Intensity +", + "cmd": "IX=~16" + }, + "0xF728D7": { + "label": "Mode4", + "pos": "6x1", + "cmnt": "Preset 4", + "cmd": "PL=4" + }, + "0xF7A857": { + "label": "Mode5", + "pos": "6x2", + "cmnt": "Preset 5", + "cmd": "PL=5" + }, + "0xF76897": { + "label": "Cycle", + "pos": "6x3", + "cmnt": "Toggle preset cycle", + "cmd": "CY=1&PT=60000" + }, + "0xF7E817": { + "label": "Down", + "pos": "6x4", + "cmnt": "Intensity -", + "cmd": "IX=~-16" + } +} \ No newline at end of file diff --git a/usermods/JSON_IR_remote/32-key_ir.json b/usermods/JSON_IR_remote/32-key_ir.json new file mode 100644 index 00000000..f58c7795 --- /dev/null +++ b/usermods/JSON_IR_remote/32-key_ir.json @@ -0,0 +1,185 @@ +{ + "desc": "32-key", + "0xFF08F7": { + "label": "On", + "pos": "1x1", + "cmd": "T=1" + }, + "0xFFC03F": { + "label": "Off", + "pos": "1x2", + "cmd": "T=0" + }, + "0xFF807F": { + "label": "Auto", + "pos": "1x3", + "cmnt": "Toggle preset cycle", + "cmd": "CY=2" + }, + "0xFF609F": { + "label": "Mode", + "pos": "1x4", + "cmnt": "Cycle effects", + "cmd": "FX=~&CY=0" + }, + "0xFF906F": { + "label": "4H", + "pos": "2x1", + "cmnt": "Timer 60min", + "cmd": "NL=60&NT=0" + }, + "0xFFB847": { + "label": "6H", + "pos": "2x2", + "cmnt": "Timer 90min", + "cmd": "NL=90&NT=0" + }, + "0xFFF807": { + "label": "8H", + "pos": "2x3", + "cmnt": "Timer 120min", + "cmd": "NL=120&NT=0" + }, + "0xFFB04F": { + "label": "Timer Off", + "pos": "2x4", + "cmd": "NL=0" + }, + "0xFF9867": { + "label": "Red", + "pos": "3x1", + "cmnt": "Lava", + "cmd": "FP=8" + }, + "0xFFD827": { + "label": "Green", + "pos": "3x2", + "cmnt": "Forest", + "cmd": "FP=10" + }, + "0xFF8877": { + "label": "Blue", + "pos": "3x3", + "cmnt": "Breeze", + "cmd": "FP=15" + }, + "0xFFA857": { + "label": "White", + "pos": "3x4", + "cmd": "FP=5&CL=hFFFFFF&C2=hFFE4CD&C3=hE4E4FF" + }, + "0xFFE817": { + "label": "OrangeRed", + "pos": "4x1", + "cmnt": "Sakura", + "cmd": "FP=49" + }, + "0xFF48B7": { + "label": "SeaGreen", + "pos": "4x2", + "cmnt": "Rivendale", + "cmd": "FP=14" + }, + "0xFF6897": { + "label": "RoyalBlue", + "pos": "4x3", + "cmnt": "Ocean", + "cmd": "FP=9" + }, + "0xFFB24D": { + "label": "DarkBlue", + "pos": "4x4", + "cmnt": "Breeze", + "cmd": "FP=15" + }, + "0xFF02FD": { + "label": "Orange", + "pos": "5x1", + "cmnt": "Orangery", + "cmd": "FP=47" + }, + "0xFF32CD": { + "label": "YellowGreen", + "pos": "5x2", + "cmnt": "Aurora", + "cmd": "FP=37" + }, + "0xFF20DF": { + "label": "SkyBlue", + "pos": "5x3", + "cmnt": "Beech", + "cmd": "FP=22" + }, + "0xFF00FF": { + "label": "Orchid", + "pos": "5x4", + "cmd": "FP=5&CL=hDA70D6&C2=hDA70A0&C3=h89618F" + }, + "0xFF50AF": { + "label": "Yellow", + "pos": "6x1", + "cmd": "FP=5&CL=hFFFF00&C2=hFFC800&C3=hFDFFDE" + }, + "0xFF7887": { + "label": "DarkGreen", + "pos": "6x2", + "cmnt": "Orange and Teal", + "cmd": "FP=44" + }, + "0xFF708F": { + "label": "RebeccaPurple", + "pos": "6x3", + "cmd": "FP=5&CL=h800080&C2=h800040&C3=h4B1C54" + }, + "0xFF58A7": { + "label": "Plum", + "pos": "6x4", + "cmd": "FP=5&CL=hDDA0DD&C2=hDDA0BE&C3=h8D7791" + }, + "0xFF38C7": { + "label": "Strobe", + "pos": "7x1", + "cmnt": "Dancing Shadows", + "cmd": "FX=112&CY=0" + }, + "0xFF28D7": { + "label": "In Waves", + "pos": "7x2", + "cmnt": "Noise 1", + "cmd": "FX=70&CY=0" + }, + "0xFFF00F": { + "label": "Speed +", + "pos": "7x3", + "cmd": "SX=~16" + }, + "0xFF30CF": { + "label": "Speed -", + "pos": "7x4", + "cmd": "SX=~-16" + }, + "0xFF40BF": { + "label": "Jump", + "pos": "8x1", + "cmnt": "Colortwinkles", + "cmd": "FX=74&CY=0" + }, + "0xFF12ED": { + "label": "Fade", + "pos": "8x2", + "cmnt": "Sunrise", + "cmd": "FX=104&CY=0" + }, + "0xFF2AD5": { + "label": "Flash", + "pos": "8x3", + "cmnt": "Railway", + "cmd": "FX=78&CY=0" + }, + "0xFFA05F": { + "label": "Chase Flash", + "pos": "8x4", + "cmnt": "Washing Machine", + "cmd": "FX=113&CY=0" + } +} \ No newline at end of file diff --git a/usermods/JSON_IR_remote/40-key-black_ir.json b/usermods/JSON_IR_remote/40-key-black_ir.json new file mode 100644 index 00000000..71262b12 --- /dev/null +++ b/usermods/JSON_IR_remote/40-key-black_ir.json @@ -0,0 +1,233 @@ +{ + "desc": "40-key-black", + "0xFF3AC5": { + "label": "Bright +", + "pos": "1x1", + "cmd": "A=~16" + }, + "0xFFBA45": { + "label": "Bright -", + "pos": "1x2", + "cmd": "A=~-16" + }, + "0xFF827D": { + "label": "Off", + "pos": "1x3", + "cmd": "T=0" + }, + "0xFF02FD": { + "label": "On", + "pos": "1x4", + "cmd": "T=1" + }, + "0xFF1AE5": { + "label": "Red", + "pos": "2x1", + "cmnt": "Lava", + "cmd": "FP=8" + }, + "0xFF9A65": { + "label": "Green", + "pos": "2x2", + "cmnt": "Forest", + "cmd": "FP=10" + }, + "0xFFA25D": { + "label": "Blue", + "pos": "2x3", + "cmnt": "Breeze", + "cmd": "FP=15" + }, + "0xFF22DD": { + "label": "White", + "pos": "2x4", + "cmd": "FP=5&CL=hFFFFFF&C2=hFFFFFF&C3=hA8A8A8" + }, + "0xFF2AD5": { + "label": "Tomato", + "pos": "3x1", + "cmnt": "Yelmag", + "cmd": "FP=5&CL=hFF6347&C2=hFFBF47&C3=hA85859" + }, + "0xFFAA55": { + "label": "LightGreen", + "pos": "3x2", + "cmnt": "Rivendale", + "cmd": "FP=14" + }, + "0xFF926D": { + "label": "SkyBlue", + "pos": "3x3", + "cmnt": "Ocean", + "cmd": "FP=9" + }, + "0xFF12ED": { + "label": "WarmWhite", + "pos": "3x4", + "cmnt": "Warm White", + "cmd": "FP=5&CL=hFFE4CD&C2=hFFFCCD&C3=hA89892" + }, + "0xFF0AF5": { + "label": "OrangeRed", + "pos": "4x1", + "cmnt": "Sakura", + "cmd": "FP=49" + }, + "0xFF8A75": { + "label": "Cyan", + "pos": "4x2", + "cmnt": "Beech", + "cmd": "FP=22" + }, + "0xFFB24D": { + "label": "RebeccaPurple", + "pos": "4x3", + "cmd": "FP=5&CL=h663399&C2=h993399&C3=h473864" + }, + "0xFF32CD": { + "label": "CoolWhite", + "pos": "4x4", + "cmnt": "Cool White", + "cmd": "FP=5&CL=hE4E4FF&C2=hF1E4FF&C3=h9C9EA8" + }, + "0xFF38C7": { + "label": "Orange", + "pos": "5x1", + "cmnt": "Orangery", + "cmd": "FP=47" + }, + "0xFFB847": { + "label": "Turquoise", + "pos": "5x2", + "cmd": "FP=5&CL=h40E0D0&C2=h40A0E0&C3=h4E9381" + }, + "0xFF7887": { + "label": "Purple", + "pos": "5x3", + "cmd": "FP=5&CL=h800080&C2=h800040&C3=h4B1C54" + }, + "0xFFF807": { + "label": "MedGray", + "pos": "5x4", + "cmnt": "Cycle palette +", + "cmd": "FP=~" + }, + "0xFF18E7": { + "label": "Yellow", + "pos": "6x1", + "cmd": "FP=5&CL=hFFFF00&C2=h7FFF00&C3=hA89539" + }, + "0xFF9867": { + "label": "DarkCyan", + "pos": "6x2", + "cmd": "FP=5&CL=h8B8B&C2=h458B&C3=h1F5B51" + }, + "0xFF58A7": { + "label": "Plum", + "pos": "6x3", + "cmnt": "Magenta", + "cmd": "FP=40" + }, + "0xFFD827": { + "label": "DarkGray", + "pos": "6x4", + "cmnt": "Cycle palette -", + "cmd": "FP=~-" + }, + "0xFF28D7": { + "label": "Jump3", + "pos": "7x1", + "cmnt": "Colortwinkles", + "cmd": "CY=0&FX=74" + }, + "0xFFA857": { + "label": "Fade3", + "pos": "7x2", + "cmnt": "Rain", + "cmd": "CY=0&FX=43" + }, + "0xFF6897": { + "label": "Flash", + "pos": "7x3", + "cmnt": "Cycle Effects", + "cmd": "CY=0&FX=~" + }, + "0xFFE817": { + "label": "Quick", + "pos": "7x4", + "cmnt": "Fx speed +16", + "cmd": "SX=~16" + }, + "0xFF08F7": { + "label": "Jump7", + "pos": "8x1", + "cmnt": "Sinelon Dual", + "cmd": "CY=0&FX=93" + }, + "0xFF8877": { + "label": "Fade7", + "pos": "8x2", + "cmnt": "Lighthouse", + "cmd": "CY=0&FX=41" + }, + "0xFF48B7": { + "label": "Auto", + "pos": "8x3", + "cmnt": "Toggle preset cycle", + "cmd": "CY=2" + }, + "0xFFC837": { + "label": "Slow", + "pos": "8x4", + "cmnt": "FX speed -16", + "cmd": "SX=~-16" + }, + "0xFF30CF": { + "label": "Custom1", + "pos": "9x1", + "cmnt": "Noise 1", + "cmd": "CY=0&FX=70" + }, + "0xFFB04F": { + "label": "Custom2", + "pos": "9x2", + "cmnt": "Dancing Shadows", + "cmd": "CY=0&FX=112" + }, + "0xFF708F": { + "label": "Music +", + "pos": "9x3", + "cmnt": "FX Intensity +16", + "cmd": "IX=~16" + }, + "0xFFF00F": { + "label": "Timer60", + "pos": "9x4", + "cmnt": "Timer 60 min", + "cmd": "NL=60&NT=0" + }, + "0xFF10EF": { + "label": "Custom3", + "pos": "10x1", + "cmnt": "Twinklefox", + "cmd": "CY=0&FX=80" + }, + "0xFF906F": { + "label": "Custom4", + "pos": "10x2", + "cmnt": "Twinklecat", + "cmd": "CY=0&FX=81" + }, + "0xFF50AF": { + "label": "Music -", + "pos": "10x3", + "cmnt": "FX Intesity -16", + "cmd": "IX=~-16" + }, + "0xFFD02F": { + "label": "Timer120", + "pos": "10x4", + "cmnt": "Timer 120 min", + "cmd": "NL=120&NT=0" + } +} \ No newline at end of file diff --git a/usermods/JSON_IR_remote/40-key-blue_ir.json b/usermods/JSON_IR_remote/40-key-blue_ir.json new file mode 100644 index 00000000..ed25d778 --- /dev/null +++ b/usermods/JSON_IR_remote/40-key-blue_ir.json @@ -0,0 +1,217 @@ +{ + "desc": "40-key-blue", + "0xFF3AC5": { + "label": "Bright +", + "pos": "1x1", + "cmd": "A=~16" + }, + "0xFFBA45": { + "label": "Bright -", + "pos": "1x2", + "cmd": "A=~-16" + }, + "0xFF827D": { + "label": "Off", + "pos": "1x3", + "cmd": "T=0" + }, + "0xFF02FD": { + "label": "On", + "pos": "1x4", + "cmd": "T=1" + }, + "0xFF1AE5": { + "label": "Red", + "pos": "2x1", + "cmnt": "Lava", + "cmd": "FP=8" + }, + "0xFF9A65": { + "label": "Green", + "pos": "2x2", + "cmnt": "Forest", + "cmd": "FP=10" + }, + "0xFFA25D": { + "label": "Blue", + "pos": "2x3", + "cmnt": "Breeze", + "cmd": "FP=15" + }, + "0xFF22DD": { + "label": "White", + "pos": "2x4", + "cmd": "FP=5&CL=hFFFFFF&C2=hFFFFFF&C3=hA8A8A8" + }, + "0xFF2AD5": { + "label": "Tomato", + "pos": "3x1", + "cmnt": "Yelmag", + "cmd": "FP=5&CL=hFF6347&C2=hFFBF47&C3=hA85859" + }, + "0xFFAA55": { + "label": "LightGreen", + "pos": "3x2", + "cmnt": "Rivendale", + "cmd": "FP=14" + }, + "0xFF926D": { + "label": "SkyBlue", + "pos": "3x3", + "cmnt": "Ocean", + "cmd": "FP=9" + }, + "0xFF12ED": { + "label": "WarmWhite", + "pos": "3x4", + "cmnt": "Warm White", + "cmd": "FP=5&CL=hFFE4CD&C2=hFFFCCD&C3=hA89892" + }, + "0xFF0AF5": { + "label": "OrangeRed", + "pos": "4x1", + "cmnt": "Sakura", + "cmd": "FP=49" + }, + "0xFF8A75": { + "label": "Cyan", + "pos": "4x2", + "cmnt": "Beech", + "cmd": "FP=22" + }, + "0xFFB24D": { + "label": "RebeccaPurple", + "pos": "4x3", + "cmd": "FP=5&CL=h663399&C2=h993399&C3=h473864" + }, + "0xFF32CD": { + "label": "CoolWhite", + "pos": "4x4", + "cmnt": "Cool White", + "cmd": "FP=5&CL=hE4E4FF&C2=hF1E4FF&C3=h9C9EA8" + }, + "0xFF38C7": { + "label": "Orange", + "pos": "5x1", + "cmnt": "Orangery", + "cmd": "FP=47" + }, + "0xFFB847": { + "label": "Turquoise", + "pos": "5x2", + "cmd": "FP=5&CL=h40E0D0&C2=h40A0E0&C3=h4E9381" + }, + "0xFF7887": { + "label": "Purple", + "pos": "5x3", + "cmd": "FP=5&CL=h800080&C2=h800040&C3=h4B1C54" + }, + "0xFFF807": { + "label": "MedGray", + "pos": "5x4", + "cmnt": "Cycle palette +", + "cmd": "FP=~" + }, + "0xFF18E7": { + "label": "Yellow", + "pos": "6x1", + "cmd": "FP=5&CL=hFFFF00&C2=h7FFF00&C3=hA89539" + }, + "0xFF9867": { + "label": "DarkCyan", + "pos": "6x2", + "cmd": "FP=5&CL=h8B8B&C2=h458B&C3=h1F5B51" + }, + "0xFF58A7": { + "label": "Plum", + "pos": "6x3", + "cmnt": "Magenta", + "cmd": "FP=40" + }, + "0xFFD827": { + "label": "DarkGray", + "pos": "6x4", + "cmnt": "Cycle palette -", + "cmd": "FP=~-" + }, + "0xFF28D7": { + "label": "W +", + "pos": "7x1" + }, + "0xFFA857": { + "label": "W -", + "pos": "7x2" + }, + "0xFF6897": { + "label": "W On", + "pos": "7x3" + }, + "0xFFE817": { + "label": "W Off", + "pos": "7x4" + }, + "0xFF08F7": { + "label": "W25", + "pos": "8x1" + }, + "0xFF8877": { + "label": "W50", + "pos": "8x2" + }, + "0xFF48B7": { + "label": "W75", + "pos": "8x3" + }, + "0xFFC837": { + "label": "W100", + "pos": "8x4" + }, + "0xFF30CF": { + "label": "Jump3", + "pos": "9x1", + "cmnt": "Colortwinkles", + "cmd": "CY=0&FX=74" + }, + "0xFFB04F": { + "label": "Fade3", + "pos": "9x2", + "cmnt": "Rain", + "cmd": "CY=0&FX=43" + }, + "0xFF708F": { + "label": "Jump7", + "pos": "9x3", + "cmnt": "Sinelon Dual", + "cmd": "CY=0&FX=93" + }, + "0xFFF00F": { + "label": "Quick", + "pos": "9x4", + "cmnt": "Fx speed +16", + "cmd": "SX=~16" + }, + "0xFF10EF": { + "label": "Fade", + "pos": "10x1", + "cmnt": "Lighthouse", + "cmd": "CY=0&FX=41" + }, + "0xFF906F": { + "label": "Flash", + "pos": "10x2", + "cmnt": "Cycle Effects", + "cmd": "CY=0&FX=~" + }, + "0xFF50AF": { + "label": "Auto", + "pos": "10x3", + "cmnt": "Toggle preset cycle", + "cmd": "CY=2" + }, + "0xFFD02F": { + "label": "Slow", + "pos": "10x4", + "cmnt": "Sinelon Dual", + "cmd": "CY=0&FX=93" + } +} \ No newline at end of file diff --git a/usermods/JSON_IR_remote/44-key_ir.json b/usermods/JSON_IR_remote/44-key_ir.json new file mode 100644 index 00000000..bd78e766 --- /dev/null +++ b/usermods/JSON_IR_remote/44-key_ir.json @@ -0,0 +1,241 @@ +{ + "desc": "44-key", + "0xFF3AC5": { + "label": "Bright +", + "pos": "1x1", + "cmd": "A=~16" + }, + "0xFFBA45": { + "label": "Bright -", + "pos": "1x2", + "cmd": "A=~-16" + }, + "0xFF827D": { + "label": "Off", + "pos": "1x3", + "cmd": "T=0" + }, + "0xFF02FD": { + "label": "On", + "pos": "1x4", + "cmd": "T=1" + }, + "0xFF1AE5": { + "label": "Red", + "pos": "2x1", + "cmnt": "Lava", + "cmd": "FP=8" + }, + "0xFF9A65": { + "label": "Green", + "pos": "2x2", + "cmnt": "Forest", + "cmd": "FP=10" + }, + "0xFFA25D": { + "label": "Blue", + "pos": "2x3", + "cmnt": "Breeze", + "cmd": "FP=15" + }, + "0xFF22DD": { + "label": "White", + "pos": "2x4", + "cmd": "FP=5&CL=hFFFFFF&C2=hFFFFFF&C3=hA8A8A8" + }, + "0xFF2AD5": { + "label": "Tomato", + "pos": "3x1", + "cmd": "FP=5&CL=hFF6347&C2=hFFBF47&C3=hA85859" + }, + "0xFFAA55": { + "label": "LightGreen", + "pos": "3x2", + "cmnt": "Rivendale", + "cmd": "FP=14" + }, + "0xFF926D": { + "label": "DeepBlue", + "pos": "3x3", + "cmnt": "Ocean", + "cmd": "FP=9" + }, + "0xFF12ED": { + "label": "Warmwhite2", + "pos": "3x4", + "cmnt": "Warm White", + "cmd": "FP=5&CL=hFFE4CD&C2=hFFFCCD&C3=hA89892" + }, + "0xFF0AF5": { + "label": "Orange", + "pos": "4x1", + "cmnt": "Sakura", + "cmd": "FP=49" + }, + "0xFF8A75": { + "label": "Turquoise", + "pos": "4x2", + "cmnt": "Beech", + "cmd": "FP=22" + }, + "0xFFB24D": { + "label": "Purple", + "pos": "4x3", + "cmd": "FP=5&CL=h663399&C2=h993399&C3=h473864" + }, + "0xFF32CD": { + "label": "WarmWhite", + "pos": "4x4", + "cmd": "FP=5&CL=hE4E4FF&C2=hF1E4FF&C3=h9C9EA8" + }, + "0xFF38C7": { + "label": "Yellowish", + "pos": "5x1", + "cmnt": "Orangery", + "cmd": "FP=47" + }, + "0xFFB847": { + "label": "Cyan", + "pos": "5x2", + "cmnt": "Beech", + "cmd": "FP=22" + }, + "0xFF7887": { + "label": "Magenta", + "pos": "5x3", + "cmd": "FP=5&CL=hFF00FF&C2=hFF007F&C3=h9539A8" + }, + "0xFFF807": { + "label": "ColdWhite", + "pos": "5x4", + "cmd": "FP=5&CL=hE4E4FF&C2=hF1E4FF&C3=h9C9EA8" + }, + "0xFF18E7": { + "label": "Yellow", + "pos": "6x1", + "cmd": "FP=5&CL=hFFFF00&C2=hFFC800&C3=hFDFFDE" + }, + "0xFF9867": { + "label": "Aqua", + "pos": "6x2", + "cmd": "FP=5&CL=hFFFF&C2=h7FFF&C3=h39A895" + }, + "0xFF58A7": { + "label": "Pink", + "pos": "6x3", + "cmd": "FP=5&CL=hFFC0CB&C2=hFFD4C0&C3=hA88C96" + }, + "0xFFD827": { + "label": "ColdWhite2", + "pos": "6x4", + "cmd": "FP=5&CL=hE4E4FF&C2=hF1E4FF&C3=h9C9EA8" + }, + "0xFF28D7": { + "label": "Red +", + "pos": "7x1", + "cmd": "FP=5&R=~16" + }, + "0xFFA857": { + "label": "Green +", + "pos": "7x2", + "cmd": "FP=5&G=~16" + }, + "0xFF6897": { + "label": "Blue +", + "pos": "7x3", + "cmd": "FP=5&B=~16" + }, + "0xFFE817": { + "label": "Quick", + "pos": "7x4", + "cmnt": "Fx speed +16", + "cmd": "SX=~16" + }, + "0xFF08F7": { + "label": "Red -", + "pos": "8x1", + "cmd": "FP=5&R=~-16" + }, + "0xFF8877": { + "label": "Green -", + "pos": "8x2", + "cmd": "FP=5&G=~-16" + }, + "0xFF48B7": { + "label": "Blue -", + "pos": "8x3", + "cmd": "FP=5&B=~-16" + }, + "0xFFC837": { + "label": "Slow", + "pos": "8x4", + "cmnt": "FX speed -16", + "cmd": "SX=~-16" + }, + "0xFF30CF": { + "label": "Diy1", + "pos": "9x1", + "cmd": "CY=0&PL=1" + }, + "0xFFB04F": { + "label": "Diy2", + "pos": "9x2", + "cmd": "CY=0&PL=2" + }, + "0xFF708F": { + "label": "Diy3", + "pos": "9x3", + "cmd": "CY=0&PL=3" + }, + "0xFFF00F": { + "label": "Auto", + "pos": "9x4", + "cmnt": "Toggle preset cycle", + "cmd": "CY=2" + }, + "0xFF10EF": { + "label": "Diy4", + "pos": "10x1", + "cmd": "CY=0&PL=4" + }, + "0xFF906F": { + "label": "Diy5", + "pos": "10x2", + "cmd": "CY=0&PL=5" + }, + "0xFF50AF": { + "label": "Diy6", + "pos": "10x3", + "cmd": "CY=0&PL=6" + }, + "0xFFD02F": { + "label": "Flash", + "pos": "10x4", + "cmnt": "Cycle Effects", + "cmd": "CY=0&FX=~" + }, + "0xFF20DF": { + "label": "Jump3", + "pos": "11x1", + "cmnt": "Colortwinkles", + "cmd": "CY=0&FX=74" + }, + "0xFFA05F": { + "label": "Jump7", + "pos": "11x2", + "cmnt": "Sinelon Dual", + "cmd": "CY=0&FX=93" + }, + "0xFF609F": { + "label": "Fade3", + "pos": "11x3", + "cmnt": "Rain", + "cmd": "CY=0&FX=43" + }, + "0xFFE01F": { + "label": "Fade7", + "pos": "11x4", + "cmnt": "Lighthouse", + "cmd": "CY=0&FX=41" + } +} \ No newline at end of file diff --git a/usermods/JSON_IR_remote/6-key_ir.json b/usermods/JSON_IR_remote/6-key_ir.json new file mode 100644 index 00000000..d4960a4b --- /dev/null +++ b/usermods/JSON_IR_remote/6-key_ir.json @@ -0,0 +1,38 @@ +{ + "desc": "6-key", + "0xFF0FF0": { + "label": "Power", + "pos": "1x1", + "cmd": "T=2" + }, + "0xFF8F70": { + "label": "Channel +", + "pos": "2x1", + "cmnt": "Cycle palette up", + "cmd": "FP=~" + }, + "0xFF4FB0": { + "label": "Channel -", + "pos": "3x1", + "cmnt": "Cycle palette down", + "cmd": "FP=~-" + }, + "0xFFCF30": { + "label": "Volume +", + "pos": "4x1", + "cmnt": "Brighten", + "cmd": "A=~16" + }, + "0xFF2FD0": { + "label": "Volume -", + "pos": "5x1", + "cmnt": "Dim", + "cmd": "A=~-16" + }, + "0xFFAF50": { + "label": "Mute", + "pos": "6x1", + "cmnt": "Cycle effects", + "cmd": "CY=0&FX=~" + } +} \ No newline at end of file diff --git a/usermods/JSON_IR_remote/9-key_ir.json b/usermods/JSON_IR_remote/9-key_ir.json new file mode 100644 index 00000000..f0bdd8f3 --- /dev/null +++ b/usermods/JSON_IR_remote/9-key_ir.json @@ -0,0 +1,47 @@ +{ + "desc": "9-key", + "0xFF629D": { + "label": "Power", + "cmd": "T=2" + }, + "0xFF22DD": { + "label": "A", + "cmnt": "Preset 1", + "cmd": "PL=1" + }, + "0xFF02FD": { + "label": "B", + "cmnt": "Preset 2", + "cmd": "PL=2" + }, + "0xFFC23D": { + "label": "C", + "cmnt": "Preset 3", + "cmd": "PL=3" + }, + "0xFF30CF": { + "label": "Left", + "cmnt": "Speed -", + "cmd": "SI=~-16" + }, + "0xFF7A85": { + "label": "Right", + "cmnt": "Speed +", + "cmd": "SI=~16" + }, + "0xFF9867": { + "label": "Up", + "cmnt": "Bright +", + "cmd": "A=~16" + }, + "0xFF38C7": { + "label": "Down", + "cmnt": "Bright -", + "cmd": "A=~-16" + }, + "0xFF18E7": { + "label": "Select", + "cmnt": "Cycle effects", + "cmd": "CY=0&FX=~" + } +} \ No newline at end of file diff --git a/usermods/JSON_IR_remote/IR_Remote_Codes.xlsx b/usermods/JSON_IR_remote/IR_Remote_Codes.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b1f99d3ac8d21e57b4da63d32b29d26cc4271005 GIT binary patch literal 25093 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 QBl9 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 literal 0 HcmV?d00001 diff --git a/usermods/JSON_IR_remote/ir_json_maker.py b/usermods/JSON_IR_remote/ir_json_maker.py new file mode 100644 index 00000000..a6adcc8c --- /dev/null +++ b/usermods/JSON_IR_remote/ir_json_maker.py @@ -0,0 +1,108 @@ +import colorsys +import json +import openpyxl + +named_colors = {'AliceBlue': '0xF0F8FF', 'AntiqueWhite': '0xFAEBD7', 'Aqua': '0x00FFFF', + 'Aquamarine': '0x7FFFD4', 'Azure': '0xF0FFFF', 'Beige': '0xF5F5DC', 'Bisque': '0xFFE4C4', + 'Black': '0x000000', 'BlanchedAlmond': '0xFFEBCD', 'Blue': '0x0000FF', + 'BlueViolet': '0x8A2BE2', 'Brown': '0xA52A2A', 'BurlyWood': '0xDEB887', + 'CadetBlue': '0x5F9EA0', 'Chartreuse': '0x7FFF00', 'Chocolate': '0xD2691E', + 'Coral': '0xFF7F50', 'CornflowerBlue': '0x6495ED', 'Cornsilk': '0xFFF8DC', + 'Crimson': '0xDC143C', 'Cyan': '0x00FFFF', 'DarkBlue': '0x00008B', 'DarkCyan': '0x008B8B', + 'DarkGoldenRod': '0xB8860B', 'DarkGray': '0xA9A9A9', 'DarkGrey': '0xA9A9A9', + 'DarkGreen': '0x006400', 'DarkKhaki': '0xBDB76B', 'DarkMagenta': '0x8B008B', + 'DarkOliveGreen': '0x556B2F', 'DarkOrange': '0xFF8C00', 'DarkOrchid': '0x9932CC', + 'DarkRed': '0x8B0000', 'DarkSalmon': '0xE9967A', 'DarkSeaGreen': '0x8FBC8F', + 'DarkSlateBlue': '0x483D8B', 'DarkSlateGray': '0x2F4F4F', 'DarkSlateGrey': '0x2F4F4F', + 'DarkTurquoise': '0x00CED1', 'DarkViolet': '0x9400D3', 'DeepPink': '0xFF1493', + 'DeepSkyBlue': '0x00BFFF', 'DimGray': '0x696969', 'DimGrey': '0x696969', + 'DodgerBlue': '0x1E90FF', 'FireBrick': '0xB22222', 'FloralWhite': '0xFFFAF0', + 'ForestGreen': '0x228B22', 'Fuchsia': '0xFF00FF', 'Gainsboro': '0xDCDCDC', + 'GhostWhite': '0xF8F8FF', 'Gold': '0xFFD700', 'GoldenRod': '0xDAA520', 'Gray': '0x808080', + 'Grey': '0x808080', 'Green': '0x008000', 'GreenYellow': '0xADFF2F', 'HoneyDew': '0xF0FFF0', + 'HotPink': '0xFF69B4', 'IndianRed': '0xCD5C5C', 'Indigo': '0x4B0082', 'Ivory': '0xFFFFF0', + 'Khaki': '0xF0E68C', 'Lavender': '0xE6E6FA', 'LavenderBlush': '0xFFF0F5', + 'LawnGreen': '0x7CFC00', 'LemonChiffon': '0xFFFACD', 'LightBlue': '0xADD8E6', + 'LightCoral': '0xF08080', 'LightCyan': '0xE0FFFF', 'LightGoldenRodYellow': '0xFAFAD2', + 'LightGray': '0xD3D3D3', 'LightGrey': '0xD3D3D3', 'LightGreen': '0x90EE90', + 'LightPink': '0xFFB6C1', 'LightSalmon': '0xFFA07A', 'LightSeaGreen': '0x20B2AA', + 'LightSkyBlue': '0x87CEFA', 'LightSlateGray': '0x778899', 'LightSlateGrey': '0x778899', + 'LightSteelBlue': '0xB0C4DE', 'LightYellow': '0xFFFFE0', 'Lime': '0x00FF00', + 'LimeGreen': '0x32CD32', 'Linen': '0xFAF0E6', 'Magenta': '0xFF00FF', 'Maroon': '0x800000', + 'MediumAquaMarine': '0x66CDAA', 'MediumBlue': '0x0000CD', 'MediumOrchid': '0xBA55D3', + 'MediumPurple': '0x9370DB', 'MediumSeaGreen': '0x3CB371', 'MediumSlateBlue': '0x7B68EE', + 'MediumSpringGreen': '0x00FA9A', 'MediumTurquoise': '0x48D1CC', 'MediumVioletRed': '0xC71585', + 'MidnightBlue': '0x191970', 'MintCream': '0xF5FFFA', 'MistyRose': '0xFFE4E1', + 'Moccasin': '0xFFE4B5', 'NavajoWhite': '0xFFDEAD', 'Navy': '0x000080', 'OldLace': '0xFDF5E6', + 'Olive': '0x808000', 'OliveDrab': '0x6B8E23', 'Orange': '0xFFA500', 'OrangeRed': '0xFF4500', + 'Orchid': '0xDA70D6', 'PaleGoldenRod': '0xEEE8AA', 'PaleGreen': '0x98FB98', + 'PaleTurquoise': '0xAFEEEE', 'PaleVioletRed': '0xDB7093', 'PapayaWhip': '0xFFEFD5', + 'PeachPuff': '0xFFDAB9', 'Peru': '0xCD853F', 'Pink': '0xFFC0CB', 'Plum': '0xDDA0DD', + 'PowderBlue': '0xB0E0E6', 'Purple': '0x800080', 'RebeccaPurple': '0x663399', 'Red': '0xFF0000', + 'RosyBrown': '0xBC8F8F', 'RoyalBlue': '0x4169E1', 'SaddleBrown': '0x8B4513', 'Salmon': '0xFA8072', + 'SandyBrown': '0xF4A460', 'SeaGreen': '0x2E8B57', 'SeaShell': '0xFFF5EE', 'Sienna': '0xA0522D', + 'Silver': '0xC0C0C0', 'SkyBlue': '0x87CEEB', 'SlateBlue': '0x6A5ACD', 'SlateGray': '0x708090', + 'SlateGrey': '0x708090', 'Snow': '0xFFFAFA', 'SpringGreen': '0x00FF7F', 'SteelBlue': '0x4682B4', + 'Tan': '0xD2B48C', 'Teal': '0x008080', 'Thistle': '0xD8BFD8', 'Tomato': '0xFF6347', + 'Turquoise': '0x40E0D0', 'Violet': '0xEE82EE', 'Wheat': '0xF5DEB3', 'White': '0xFFFFFF', + 'WhiteSmoke': '0xF5F5F5', 'Yellow': '0xFFFF00', 'YellowGreen': '0x9ACD32'} + +def shift_color(col, shift=30, sat=1.0, val=1.0): + r = (col & (255 << 16)) >> 16 + g = (col & (255 << 8)) >> 8 + b = col & 255 + hsv = colorsys.rgb_to_hsv(r, g, b) + h = (((hsv[0] * 360) + shift) % 360) / 360 + rgb = colorsys.hsv_to_rgb(h, hsv[1] * sat, hsv[2] * val) + return (int(rgb[0]) << 16) + (int(rgb[1]) << 8) + int(rgb[2]) + +def parse_sheet(ws): + print(f'Parsing worksheet {ws.title}') + ir = {"desc": ws.title} + rows = ws.rows + keys = [col.value.lower() for col in next(rows)] + for row in rows: + rec = dict(zip(keys, [col.value for col in row])) + if rec.get('code') is None: + continue + cd = {"label": rec.get('label')} + if rec.get('row'): + cd['pos'] = f'{rec["row"]}x{rec["col"]}' + if rec.get('comment'): + cd['cmnt'] = rec.get('comment') + if rec.get('rpt'): + cd['rpt'] = bool(rec['rpt']) + + if rec.get('cmd'): + cd['cmd'] = rec['cmd'] + elif all((rec.get('primary'), rec.get('secondary'), rec.get('tertiary'))): + c1 = int(rec.get('primary'), 16) + c2 = int(rec.get('secondary'), 16) + c3 = int(rec.get('tertiary'), 16) + cd['cmd'] = f'FP=5&CL=h{c1:X}&C2=h{c2:X}&C3=h{c3:X}' + elif all((rec.get('primary'), rec.get('secondary'))): + c1 = int(rec.get('primary'), 16) + c2 = int(rec.get('secondary'), 16) + c3 = shift_color(c1, -1, sat=0.66, val=0.66) + cd['cmd'] = f'FP=5&CL=h{c1:X}&C2=h{c2:X}&C3=h{c3:X}' + elif rec.get('primary'): + c1 = int(rec.get('primary'), 16) + c2 = shift_color(c1, 30) + c3 = shift_color(c1, -10, sat=0.66, val=0.66) + cd['cmd'] = f'FP=5&CL=h{c1:X}&C2=h{c2:X}&C3=h{c3:X}' + elif rec.get('label') in named_colors: + c1 = int(named_colors[rec.get('label')], 16) + c2 = shift_color(c1, 30) + c3 = shift_color(c1, -10, sat=0.66, val=0.66) + cd['cmd'] = f'FP=5&CL=h{c1:X}&C2=h{c2:X}&C3=h{c3:X}' + else: + print(f'Did not find a command or color for {rec["label"]}. Hint use named CSS colors as labels') + ir[rec['code']] = cd + + with open(f'{ws.title}_ir.json', 'w') as fp: + json.dump(ir, fp, indent=2) + +if __name__ == '__main__': + wb = openpyxl.load_workbook('IR_Remote_Codes.xlsx') + for ws in wb.worksheets: + parse_sheet(ws) diff --git a/usermods/JSON_IR_remote/readme.md b/usermods/JSON_IR_remote/readme.md new file mode 100644 index 00000000..ee18aa94 --- /dev/null +++ b/usermods/JSON_IR_remote/readme.md @@ -0,0 +1,33 @@ +# JSON IR remote + +## Purpose + +The JSON IR remote allows users to customize IR remote behavior without writing custom code and compiling. +It also enables using any remote that is compatible with your IR receiver. Using the JSON IR remote, you can +map buttons from any remote to any HTTP request API or JSON API command. + +## Usage + +* Upload the IR config file, named _ir.json_ to your board using the [ip address]/edit url. Pick from one of the included files or create your own. +* On the config > LED settings page, set the correct IR pin. +* On the config > Sync Interfaces page, select "JSON Remote" as the Infrared remote. + +## Modification + +* See if there is a json file with the same number of buttons as your remote. Many remotes will have the same internals and emit the same codes but have different labels. +* In the ir.json file, each key will be the hex encoded IR code. +* The "cmd" property will be the HTTP Request API or JSON API to execute when that button is pressed. +* A limited number of c functions are supported (!incBrightness, !decBrightness, !presetFallback) +* When using !presetFallback, include properties PL (preset to load), FX (effect to fall back to) and FP (palette to fall back to) +* If the command is _repeatable_ and does not contain the "~" character, add a "rpt": true property. +* Other properties are ignored, but having a label property may help when editing. + + +Sample: +{ + "0xFF629D": {"cmd": "T=2", "rpt": true, "label": "Toggle on/off"}, // HTTP command + "0xFF9867": {"cmd": "A=~16", "label": "Inc brightness"}, // HTTP command with incrementing + "0xFF38C7": {"cmd": {"bri": 10}, "label": "Dim to 10"}, // JSON command + "0xFF22DD": {"cmd": "!presetFallback", "PL": 1, "FX": 16, "FP": 6, + "label": "Preset 1 or fallback to Saw - Party"}, // c function +} diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index e771a605..bac853b4 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -350,14 +350,15 @@ Reverse (rotated 180°):
Touch threshold:
IR pin:   ×
IR info
Relay pin: Invert  ×
diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 405c14f2..ff3fa0e1 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -87,6 +87,7 @@ void decodeIR44(uint32_t code); void decodeIR21(uint32_t code); void decodeIR6(uint32_t code); void decodeIR9(uint32_t code); +void decodeIRJson(uint32_t code); void initIR(); void handleIR(); diff --git a/wled00/html_settings.h b/wled00/html_settings.h index 1b6bede1..5a94c336 100644 --- a/wled00/html_settings.h +++ b/wled00/html_settings.h @@ -121,36 +121,36 @@ class="xs" min="-1" max="40" name="IR" onchange="UI()">  × -
IR info
Relay pin: Invert  × -

Defaults

Turn LEDs on after power up/reset: -
Default brightness: (0-255)

Apply preset - - at boot (0 uses defaults)

Use Gamma correction for color: (strongly recommended)
-Use Gamma correction for brightness: - (not recommended)

Brightness factor: %

Transitions

Crossfade:
Transition Time: ms
Enable Palette transitions: JSON remote ×
+IR info
Relay pin: Invert + ×

Defaults

Turn LEDs on after power up/reset:
Default brightness: (0-255)

Apply preset at boot (0 uses defaults) +

Use Gamma correction for color: + (strongly recommended)
Use Gamma correction for brightness: (not recommended)

Brightness factor: %

Transitions

+Crossfade:
Transition Time: ms
Enable Palette transitions:

Timed light

Default Duration: min
-Default Target brightness:
Mode:

Advanced

Palette blending: -
Auto-calculate white channel from RGB:


)====="; +name="TL" type="number" min="1" max="255" required> min
+Default Target brightness:
Mode:

Advanced

Palette blending:
+Auto-calculate white channel from RGB:


)====="; #ifdef WLED_ENABLE_DMX diff --git a/wled00/ir.cpp b/wled00/ir.cpp index 0f0a77ee..ac921fb4 100644 --- a/wled00/ir.cpp +++ b/wled00/ir.cpp @@ -68,6 +68,14 @@ void decBrightness() } } +// apply preset or fallback to a effect and palette if it doesn't exist +void presetFallback(int8_t presetID, int8_t effectID, int8_t paletteID) +{ + if (!applyPreset(presetID)) { + effectCurrent = effectID; + effectPalette = paletteID; + } +} //Add what your custom IR codes should trigger here. Guide: https://github.com/Aircoookie/WLED/wiki/Infrared-Control //IR codes themselves can be defined directly after "case" or in "ir_codes.h" @@ -85,8 +93,6 @@ bool decodeIRCustom(uint32_t code) return true; } - - void relativeChange(byte* property, int8_t amount, byte lowerBoundary, byte higherBoundary) { int16_t new_val = (int16_t) *property + amount; @@ -156,24 +162,28 @@ void decodeIR(uint32_t code) lastValidCode = 0; irTimesRepeated = 0; if (decodeIRCustom(code)) return; if (code > 0xFFFFFF) return; //invalid code - else if (code > 0xF70000 && code < 0xF80000) decodeIR24(code); //is in 24-key remote range - else if (code > 0xFF0000) { - switch (irEnabled) { - case 1: decodeIR24OLD(code); break; // white 24-key remote (old) - it sends 0xFF0000 values - case 2: decodeIR24CT(code); break; // white 24-key remote with CW, WW, CT+ and CT- keys - case 3: decodeIR40(code); break; // blue 40-key remote with 25%, 50%, 75% and 100% keys - case 4: decodeIR44(code); break; // white 44-key remote with color-up/down keys and DIY1 to 6 keys - case 5: decodeIR21(code); break; // white 21-key remote - case 6: decodeIR6(code); break; // black 6-key learning remote defaults: "CH" controls brightness, - // "VOL +" controls effect, "VOL -" controls colour/palette, "MUTE" - // sets bright plain white - case 7: decodeIR9(code); break; - default: return; - } + switch (irEnabled) { + case 1: + if (code > 0xF80000) { + decodeIR24OLD(code); // white 24-key remote (old) - it sends 0xFF0000 values + } else { + decodeIR24(code); // 24-key remote - 0xF70000 to 0xF80000 + } + break; + case 2: decodeIR24CT(code); break; // white 24-key remote with CW, WW, CT+ and CT- keys + case 3: decodeIR40(code); break; // blue 40-key remote with 25%, 50%, 75% and 100% keys + case 4: decodeIR44(code); break; // white 44-key remote with color-up/down keys and DIY1 to 6 keys + case 5: decodeIR21(code); break; // white 21-key remote + case 6: decodeIR6(code); break; // black 6-key learning remote defaults: "CH" controls brightness, + // "VOL +" controls effect, "VOL -" controls colour/palette, "MUTE" + // sets bright plain white + case 7: decodeIR9(code); break; + case 8: decodeIRJson(code); break; // any remote configurable with ir.json file + default: return; } + if (nightlightActive && bri == 0) nightlightActive = false; colorUpdated(NOTIFIER_CALL_MODE_BUTTON); //for notifier, IR is considered a button input - //code <= 0xF70000 also invalid } void applyRepeatActions(){ @@ -219,9 +229,12 @@ void applyRepeatActions(){ nightlightStartTime = millis(); colorUpdated(NOTIFIER_CALL_MODE_BUTTON); } + else if (irEnabled == 8) + { + decodeIRJson(lastValidCode); + } } - void decodeIR24(uint32_t code) { switch (code) { @@ -286,7 +299,6 @@ void decodeIR24OLD(uint32_t code) lastValidCode = code; } - void decodeIR24CT(uint32_t code) { switch (code) { @@ -321,7 +333,6 @@ void decodeIR24CT(uint32_t code) lastValidCode = code; } - void decodeIR40(uint32_t code) { switch (code) { @@ -522,6 +533,87 @@ void decodeIR9(uint32_t code) lastValidCode = code; } + +/* +This allows users to customize IR actions without the need to edit C code and compile. +From the https://github.com/Aircoookie/WLED/wiki/Infrared-Control page, download the starter +ir.json file that corresponds to the number of buttons on your remote. +Many of the remotes with the same number of buttons emit the same codes, but will have +different labels or colors. Once you edit the ir.json file, upload it to your controller +using the /edit page. + +Each key should be the hex encoded IR code. The "cmd" property should be the HTTP API +or JSON API command to execute on button press. If the command contains a relative change (SI=~16), +it will register as a repeatable command. If the command doesn't contain a "~" but is repeatable, add "rpt" property +set to true. Other properties are ignored but having labels and positions can assist with editing +the json file. + +Sample: +{ + "0xFF629D": {"cmd": "T=2", "rpt": true, "label": "Toggle on/off"}, // HTTP command + "0xFF9867": {"cmd": "A=~16", "label": "Inc brightness"}, // HTTP command with incrementing + "0xFF38C7": {"cmd": {"bri": 10}, "label": "Dim to 10"}, // JSON command + "0xFF22DD": {"cmd": "!presetFallback", "PL": 1, "FX": 16, "FP": 6, // Custom command + "label": "Preset 1, fallback to Saw - Party if not found"}, +} +*/ +void decodeIRJson(uint32_t code) +{ + char objKey[10]; + const char* cmd; + String cmdStr; + DynamicJsonDocument irDoc(JSON_BUFFER_SIZE); + JsonObject fdo; + JsonObject jsonCmdObj; + + sprintf(objKey, "\"0x%X\":", code); + + errorFlag = readObjectFromFile("/ir.json", objKey, &irDoc) ? ERR_NONE : ERR_FS_PLOAD; + fdo = irDoc.as(); + lastValidCode = 0; + if (!errorFlag) + { + cmd = fdo["cmd"]; + cmdStr = String(cmd); + jsonCmdObj = fdo["cmd"]; + if (!cmdStr.isEmpty()) + { + if (cmdStr.startsWith("!")) { + // call limited set of C functions + if (cmdStr == "!incBrightness") { + lastValidCode = code; + incBrightness(); + } else if (cmdStr == "!decBrightness") { + lastValidCode = code; + decBrightness(); + } else if (cmdStr == "!presetFallback") { + uint8_t p1 = fdo["PL"] ? fdo["PL"] : 1; + uint8_t p2 = fdo["FX"] ? fdo["FX"] : random8(100); + uint8_t p3 = fdo["FP"] ? fdo["FP"] : 0; + presetFallback(p1, p2, p3); + } + } else { + // HTTP API command + if (cmdStr.indexOf("~") || fdo["rpt"]) + { + // repeatable action + lastValidCode = code; + } if (effectCurrent == 0 && cmdStr.indexOf("FP=") > -1) { + // setting palette but it wont show because effect is solid + effectCurrent = FX_MODE_GRADIENT; + } + if (!cmdStr.startsWith("win&")) { + cmdStr = "win&" + cmdStr; + } + handleSet(nullptr, cmdStr, false); + } + } else if (!jsonCmdObj.isNull()) { + // command is JSON object + deserializeState(jsonCmdObj); + } + } +} + void initIR() { if (irEnabled > 0) @@ -531,7 +623,6 @@ void initIR() } } - void handleIR() { if (irEnabled > 0 && millis() - irCheckedTime > 120)