{"id":7127,"date":"2024-07-28T06:38:31","date_gmt":"2024-07-28T06:38:31","guid":{"rendered":"http:\/\/172.30.70.55\/?p=7127"},"modified":"2024-08-10T01:54:46","modified_gmt":"2024-08-10T01:54:46","slug":"fire-remote-remap-script","status":"publish","type":"post","link":"https:\/\/phixd.us\/?p=7127","title":{"rendered":"Fire Remote Remap Script"},"content":{"rendered":"\n<p class=\"has-medium-font-size\">I&#8217;ve put together a helpful little script that let me take full control of my Fire TV remote by remapping the keys. Before this, several buttons were just sitting useless, especially when I tried using them with Kodi. I gave Kodi&#8217;s key remapper addon a shot, but it didn\u2019t quite cut it. That\u2019s when I decided to roll up my sleeves and make something myself.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">This script has been a game changer for me. It might not be the textbook way to handle things, but guess what? It works great for what I need. If you\u2019ve been in the same boat, wanting all your remote&#8217;s keys to actually do something, you might want to give this a try.<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading has-medium-font-size\"><strong>What\u2019s the Deal?<\/strong><\/h3>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-medium-font-size\"><strong>Device Discovery<\/strong>: Automatically finds your remote by name. No manual setup required.<\/li>\n\n\n\n<li class=\"has-medium-font-size\"><strong>Key Remapping<\/strong>: Converts unused or unsupported remote buttons into functional keys for your system.<\/li>\n\n\n\n<li class=\"has-medium-font-size\"><strong>MQTT Integration:<\/strong> This allows some remote to integrate with MQTT to allow you to trigger other automations. <\/li>\n\n\n\n<li class=\"has-medium-font-size\"><strong>Prevent Accidental Repeats<\/strong>: Adds a simple mechanism to stop the same button from sending multiple commands too quickly.<\/li>\n\n\n\n<li class=\"has-medium-font-size\"><strong>Debug Insights<\/strong>: If you like to see what\u2019s happening under the hood, switch on the debug mode for detailed logs.<\/li>\n<\/ul>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading has-medium-font-size\"><strong>Getting Started<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-medium-font-size\">Python 3.x<\/li>\n\n\n\n<li class=\"has-medium-font-size\">The <code>evdev<\/code> library<\/li>\n\n\n\n<li class=\"has-medium-font-size\"><code>xdotool<\/code> for simulating keypresses on Linux<\/li>\n<\/ul>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>How to Set It Up<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-medium-font-size\"><strong>Install the Essentials:<\/strong><\/li>\n<\/ul>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"pip install evdev \nsudo apt-get install xdotool\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #9CDCFE\">pip<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">install<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">evdev<\/span><span style=\"color: #D4D4D4\"> <\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">sudo<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">apt<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #9CDCFE\">get<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">install<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">xdotool<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-medium-font-size\"><strong>Download and Prep the Script<\/strong>:\n<ul class=\"wp-block-list\">\n<li class=\"has-medium-font-size\">Grab the script and save it where you prefer.<\/li>\n\n\n\n<li class=\"has-medium-font-size\">Make it executable with<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"chmod +x &lt;script_name&gt;.py\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #9CDCFE\">chmod<\/span><span style=\"color: #D4D4D4\"> +<\/span><span style=\"color: #9CDCFE\">x<\/span><span style=\"color: #D4D4D4\"> &lt;<\/span><span style=\"color: #9CDCFE\">script_name<\/span><span style=\"color: #D4D4D4\">&gt;.<\/span><span style=\"color: #9CDCFE\">py<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-medium-font-size\"><strong>Customize Your Controls<\/strong>:\n<ul class=\"wp-block-list\">\n<li>Open up the script and tweak the <code>key_mapping<\/code> to set up what each button should do.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-medium-font-size\"><strong>Run It and Enjoy<\/strong>:\n<ul class=\"wp-block-list\">\n<li>Fire up the script and see your remote come to life.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\" python &lt;script_name&gt;.py\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">python<\/span><span style=\"color: #D4D4D4\"> &lt;<\/span><span style=\"color: #9CDCFE\">script_name<\/span><span style=\"color: #D4D4D4\">&gt;.<\/span><span style=\"color: #9CDCFE\">py<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading has-medium-font-size\"><strong>How It Works<\/strong><\/h3>\n\n\n\n<p class=\"has-medium-font-size\">Once you kick things off, the script:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-medium-font-size\">Sets up the environment.<\/li>\n\n\n\n<li class=\"has-medium-font-size\">Searches for the remote and adjusts permissions if needed.<\/li>\n\n\n\n<li class=\"has-medium-font-size\">Listens for button presses and maps them to the corresponding actions you&#8217;ve set up.<\/li>\n<\/ul>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading has-medium-font-size\"><strong>A Little Troubleshooting<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-medium-font-size\"><strong>Can&#8217;t Find the Remote?<\/strong> Make sure the remote&#8217;s name in the script matches its system name exactly. You can use the command below to check for your remote. <\/li>\n<\/ul>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"sudo evtest\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #9CDCFE\">sudo<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">evtest<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-medium-font-size\"><strong>Permissions Issues?<\/strong> You might need to run the script with more privileges or adjust the device file permissions.<\/li>\n\n\n\n<li class=\"has-medium-font-size\"><strong>Keys Not Behaving?<\/strong> Double-check your <code>key_mapping<\/code> to make sure the commands are set up right.<\/li>\n<\/ul>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"has-medium-font-size\">If you&#8217;d like to remap your keys, you can use the <code>sudo evtest<\/code> command. Start by selecting the input device from the list presented. When you press a key, <code>evtest<\/code> will output information similar to the example below. The value provided is your key code, which you&#8217;ll need to define in your script. For instance, in this example, <code>c008d<\/code> is the key code. In the script, you should refer to it as <code>x0c008d<\/code>.<\/p>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"Event: time 1722150873.677004, type 4 (EV_MSC), code 4 (MSC_SCAN), value c008d\nEvent: time 1722150873.677004, type 1 (EV_KEY), code 362 (KEY_PROGRAM), value 1\nEvent: time 1722150873.677004, -------------- SYN_REPORT ------------\n\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C8C8C8\">Event<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">time<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #B5CEA8\">1722150873.677004<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">type<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #B5CEA8\">4<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #4FC1FF\">EV_MSC<\/span><span style=\"color: #D4D4D4\">), <\/span><span style=\"color: #9CDCFE\">code<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #B5CEA8\">4<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #4FC1FF\">MSC_SCAN<\/span><span style=\"color: #D4D4D4\">), <\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">c008d<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C8C8C8\">Event<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">time<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #B5CEA8\">1722150873.677004<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">type<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #B5CEA8\">1<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #4FC1FF\">EV_KEY<\/span><span style=\"color: #D4D4D4\">), <\/span><span style=\"color: #9CDCFE\">code<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #B5CEA8\">362<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #4FC1FF\">KEY_PROGRAM<\/span><span style=\"color: #D4D4D4\">), <\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #B5CEA8\">1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C8C8C8\">Event<\/span><span style=\"color: #D4D4D4\">: <\/span><span style=\"color: #9CDCFE\">time<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #B5CEA8\">1722150873.677004<\/span><span style=\"color: #D4D4D4\">, -------------- <\/span><span style=\"color: #4FC1FF\">SYN_REPORT<\/span><span style=\"color: #D4D4D4\"> ------------<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"has-medium-font-size\">In my setup, I\u2019ve configured the MQTT buttons to interface with Home Assistant, allowing for seamless control of my TV and voice assistant. When I press the &#8220;Power&#8221; button, an MQTT message (<code>power_pressed<\/code>) is sent, which is picked up Home Assistant then send a command to my Broadlink RM Pro to power my TV on or off. On the other hand, the &#8220;Voice&#8221; button is integrated with another script that enables voice control functionality. When this button is pressed, an MQTT message (<code>voice_pressed<\/code>) triggers the script, allowing me to use voice commands to control various smart home devices or perform specific actions. To ensure accurate feedback, both buttons also send an <code>idle<\/code> message after a brief period, indicating that they are no longer active. This setup not only simplifies the control of my TV and voice assistant but also ensures that every action is precisely tracked through MQTT messaging.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">That\u2019s about it! This setup has been rock solid for me, especially for my Kodi setup. If you\u2019re looking to get more out of your remote, why not give this a shot? Maybe it\u2019ll be just what you need. Cheers! \ud83d\ude80<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p class=\"has-medium-font-size\"><strong>Script:<\/strong><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#D4D4D4;--cbp-line-number-width:calc(3 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span role=\"button\" tabindex=\"0\" data-code=\"import evdev\nfrom evdev import InputDevice, categorize, ecodes\nimport subprocess\nimport os\nimport logging\nimport threading\nimport time\nimport paho.mqtt.client as mqtt\n\n# Ensure the DISPLAY environment variable is set\nos.environ['DISPLAY'] = ':0'\n\n# Debug toggle\ndebug = True\n\n# Set up logging to console\nlogging.basicConfig(level=logging.DEBUG if debug else logging.INFO, format='%(asctime)s %(message)s')\n\n# MQTT settings\nmqtt_broker = &quot;192.168.1.110&quot;\nmqtt_port = 1883\nmqtt_topic_voice = &quot;minipc\/fireremote\/voice&quot;\nmqtt_topic_power = &quot;minipc\/fireremote\/power&quot;\nmqtt_username = &quot;user&quot;\nmqtt_password = &quot;password&quot;\n\n# Idle times for voice and power buttons (in seconds)\nvoice_idle_timeout = 1  # User-configurable idle time for voice button\npower_idle_timeout = 1  # User-configurable idle time for power button\n\n# Initialize MQTT client\nmqtt_client = mqtt.Client()\n\n# Set username and password\nmqtt_client.username_pw_set(mqtt_username, mqtt_password)\n\n# Define on_connect callback\ndef on_connect(client, userdata, flags, rc):\n    if rc == 0:\n        logging.info(&quot;Connected to MQTT Broker!&quot;)\n    else:\n        logging.error(f&quot;Failed to connect, return code {rc}&quot;)\n\n# Define on_publish callback\ndef on_publish(client, userdata, mid):\n    logging.info(&quot;Message Published!&quot;)\n\nmqtt_client.on_connect = on_connect\nmqtt_client.on_publish = on_publish\n\n# Connect to the broker\nmqtt_client.connect(mqtt_broker, mqtt_port, 60)\n\n# Start the loop\nmqtt_client.loop_start()\n\n# Function to find the device path by name\ndef find_device_by_name(name):\n    devices = [evdev.InputDevice(path) for path in evdev.list_devices()]\n    for device in devices:\n        if device.name == name:\n            return device.path\n    return None\n\n# Path to the input device\ndevice_name = 'Amazon Remote Keyboard'\ndevice_path = find_device_by_name(device_name)\nif device_path is None:\n    logging.error(f'Device with name {device_name} not found.')\n    exit(1)\n\n# Function to set permissions to the input device\ndef set_device_permissions(device_path):\n    try:\n        subprocess.run(['sudo', 'chmod', 'a+rw', device_path], check=True)\n    except subprocess.CalledProcessError as e:\n        logging.error(f'Error setting permissions: {e}')\n        exit(1)\n\nset_device_permissions(device_path)\n\ndevice = InputDevice(device_path)\nlogging.info(f'Listening on {device_path}')\n\nkey_mapping = {\n    0xc0040: 'm',  # Menu Key\n    0xc008d: 'h',  # Guide Key mapped to 'h'\n    0xc009c: 'Up',  # Channel Up\n    0xc009d: 'Down',  # Channel Down\n    0xc00b4: 'r',  # Rewind\n    0xc00b3: 'f',  # Fast Forward\n    0xc0033: 'c',  # Settings Key\n    0xc027e: 'i',  # Button 1\n    0xc027f: 't',  # Button 2\n    0xc0221: 'MQTT_POWER',  # Power button mapped to MQTT &quot;power_pressed&quot;\n    0xc00cd: 'space',  # Play\/Pause\n    0xc0280: 'MQTT_VOICE'  # Voice button mapped to MQTT &quot;voice_pressed&quot;\n}\n\nlast_key = None  # To track the last processed key\ntimeout = 0.5  # Timeout in seconds (same as original script)\nlock = threading.Lock()\n\n# Keys for which we want to bypass the last_key logic\nbypass_keys = {0xc00b4, 0xc00b3, 0xc00cd}  # Rewind, Fast Forward, Play\/Pause\n\ndef send_idle_message(topic):\n    logging.debug(f&quot;Sending idle message to {topic}&quot;)\n    result = mqtt_client.publish(topic, &quot;idle&quot;)\n    if result.rc != mqtt.MQTT_ERR_SUCCESS:\n        logging.error(f&quot;Failed to send MQTT idle message: {result.rc}&quot;)\n    else:\n        logging.debug(&quot;MQTT idle message sent successfully&quot;)\n\ndef reset_last_key():\n    global last_key\n    with lock:\n        if debug:\n            logging.debug(f'Resetting last_key from {last_key} to None')\n        last_key = None\n\ndef remap_key(scan_code):\n    global last_key\n    if debug:\n        logging.debug(f'Attempting to remap scan code: {scan_code}')\n    with lock:\n        if scan_code in key_mapping:\n            new_key = key_mapping[scan_code]\n            if debug:\n                logging.debug(f'Scan code {scan_code} maps to {new_key}')\n            if scan_code in bypass_keys or last_key != scan_code:\n                if new_key == 'MQTT_VOICE':\n                    logging.debug(&quot;MQTT_VOICE action triggered&quot;)\n                    result = mqtt_client.publish(mqtt_topic_voice, &quot;voice_pressed&quot;)\n                    if result.rc != mqtt.MQTT_ERR_SUCCESS:\n                        logging.error(f&quot;Failed to send MQTT voice pressed message: {result.rc}&quot;)\n                    else:\n                        logging.debug(&quot;MQTT voice pressed message sent successfully&quot;)\n                    threading.Timer(voice_idle_timeout, send_idle_message, args=[mqtt_topic_voice]).start()\n\n                elif new_key == 'MQTT_POWER':\n                    logging.debug(&quot;MQTT_POWER action triggered&quot;)\n                    result = mqtt_client.publish(mqtt_topic_power, &quot;power_pressed&quot;)\n                    if result.rc != mqtt.MQTT_ERR_SUCCESS:\n                        logging.error(f&quot;Failed to send MQTT power pressed message: {result.rc}&quot;)\n                    else:\n                        logging.debug(&quot;MQTT power pressed message sent successfully&quot;)\n                    threading.Timer(power_idle_timeout, send_idle_message, args=[mqtt_topic_power]).start()\n\n                else:\n                    if debug:\n                        logging.debug(f'Executing xdotool for key: {new_key}')\n                    subprocess.run(['xdotool', 'key', new_key])\n\n                if scan_code not in bypass_keys:\n                    last_key = scan_code  # Update the last processed key only for non-bypass keys\n                    threading.Timer(timeout, reset_last_key).start()\n            else:\n                if debug:\n                    logging.debug(f'Scan code {scan_code} is the same as the last key processed. Skipping.')\n        else:\n            if debug:\n                logging.warning(f'No mapping found for scan code: {scan_code}')\n\ntry:\n    for event in device.read_loop():\n        if event.type == evdev.ecodes.EV_MSC and event.code == evdev.ecodes.MSC_SCAN:\n            if debug:\n                logging.debug(f'Detected MSC event: {event}')\n            remap_key(event.value)\n        elif event.type == evdev.ecodes.EV_KEY and event.value == 1:  # Only key press events\n            key_event = categorize(event)\n            if debug:\n                logging.debug(f'Detected key down: {key_event.scancode}, key code: {key_event.keycode}')\n        time.sleep(0.01)  # Add a small delay to ensure events are processed properly\nexcept KeyboardInterrupt:\n    logging.info('Exiting...')\n    mqtt_client.loop_stop()\nexcept Exception as e:\n    logging.error(f'Unexpected error: {e}', exc_info=True)\n    mqtt_client.loop_stop()\n    exit(1)\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">evdev<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">from<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">evdev<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">InputDevice<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">categorize<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">ecodes<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">subprocess<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">os<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">logging<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">threading<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">time<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">paho<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">mqtt<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">as<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">mqtt<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Ensure<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">DISPLAY<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">environment<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">variable<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">is<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">set<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">os<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">environ<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #CE9178\">&#39;DISPLAY&#39;<\/span><span style=\"color: #D4D4D4\">] = <\/span><span style=\"color: #CE9178\">&#39;:0&#39;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Debug<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">toggle<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">True<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Set<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">up<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">console<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">basicConfig<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">level<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">DEBUG<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">INFO<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">format<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #CE9178\">&#39;%(asctime)s %(message)s&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">MQTT<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">settings<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">mqtt_broker<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;192.168.1.110&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">mqtt_port<\/span><span style=\"color: #D4D4D4\"> = 1883<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">mqtt_topic_voice<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;minipc\/fireremote\/voice&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">mqtt_topic_power<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;minipc\/fireremote\/power&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">mqtt_username<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;user&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">mqtt_password<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&quot;password&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Idle<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">times<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">voice<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">and<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">power<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">buttons<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #9CDCFE\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">seconds<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">voice_idle_timeout<\/span><span style=\"color: #D4D4D4\"> = 1  # <\/span><span style=\"color: #9CDCFE\">User<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #9CDCFE\">configurable<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">idle<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">time<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">voice<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">button<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">power_idle_timeout<\/span><span style=\"color: #D4D4D4\"> = 1  # <\/span><span style=\"color: #9CDCFE\">User<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #9CDCFE\">configurable<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">idle<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">time<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">power<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">button<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Initialize<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">MQTT<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">client<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">mqtt_client<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">mqtt<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Client<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Set<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">username<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">and<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">password<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">mqtt_client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">username_pw_set<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">mqtt_username<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">mqtt_password<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Define<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">on_connect<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">callback<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">on_connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">userdata<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">flags<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">rc<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">rc<\/span><span style=\"color: #D4D4D4\"> == 0:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">info<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Connected to MQTT Broker!&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">error<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Failed to connect, return code {rc}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Define<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">on_publish<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">callback<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">on_publish<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">client<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">userdata<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">mid<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">info<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Message Published!&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">mqtt_client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">on_connect<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">on_connect<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">mqtt_client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">on_publish<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">on_publish<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Connect<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">broker<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">mqtt_client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">mqtt_broker<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">mqtt_port<\/span><span style=\"color: #D4D4D4\">, 60)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Start<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">loop<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">mqtt_client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">loop_start<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">find<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">device<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">path<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">by<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">name<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">find_device_by_name<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">devices<\/span><span style=\"color: #D4D4D4\"> = [<\/span><span style=\"color: #9CDCFE\">evdev<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">InputDevice<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">path<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">path<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">evdev<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">list_devices<\/span><span style=\"color: #D4D4D4\">()]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">device<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">devices<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">device<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\"> == <\/span><span style=\"color: #9CDCFE\">name<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">device<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">path<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">None<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Path<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">input<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">device<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">device_name<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #CE9178\">&#39;Amazon Remote Keyboard&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">device_path<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">find_device_by_name<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">device_name<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">device_path<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">is<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">None<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">error<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&#39;Device with name {device_name} not found.&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">exit<\/span><span style=\"color: #D4D4D4\">(1)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">set<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">permissions<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">input<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">device<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">set_device_permissions<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">device_path<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">try<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">subprocess<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">run<\/span><span style=\"color: #D4D4D4\">([<\/span><span style=\"color: #CE9178\">&#39;sudo&#39;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&#39;chmod&#39;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&#39;a+rw&#39;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">device_path<\/span><span style=\"color: #D4D4D4\">], <\/span><span style=\"color: #9CDCFE\">check<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">True<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">except<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">subprocess<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">CalledProcessError<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">as<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">e<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">error<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&#39;Error setting permissions: {e}&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">exit<\/span><span style=\"color: #D4D4D4\">(1)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">set_device_permissions<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">device_path<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">device<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">InputDevice<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">device_path<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">info<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&#39;Listening on {device_path}&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">key_mapping<\/span><span style=\"color: #D4D4D4\"> = {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    0<\/span><span style=\"color: #9CDCFE\">xc0040<\/span><span style=\"color: #D4D4D4\">: &#39;<\/span><span style=\"color: #9CDCFE\">m<\/span><span style=\"color: #D4D4D4\">&#39;,  # <\/span><span style=\"color: #9CDCFE\">Menu<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Key<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    0<\/span><span style=\"color: #9CDCFE\">xc008d<\/span><span style=\"color: #D4D4D4\">: &#39;<\/span><span style=\"color: #9CDCFE\">h<\/span><span style=\"color: #D4D4D4\">&#39;,  # <\/span><span style=\"color: #9CDCFE\">Guide<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Key<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">mapped<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\"> &#39;<\/span><span style=\"color: #9CDCFE\">h<\/span><span style=\"color: #D4D4D4\">&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    0<\/span><span style=\"color: #9CDCFE\">xc009c<\/span><span style=\"color: #D4D4D4\">: &#39;<\/span><span style=\"color: #9CDCFE\">Up<\/span><span style=\"color: #D4D4D4\">&#39;,  # <\/span><span style=\"color: #9CDCFE\">Channel<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Up<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    0<\/span><span style=\"color: #9CDCFE\">xc009d<\/span><span style=\"color: #D4D4D4\">: &#39;<\/span><span style=\"color: #9CDCFE\">Down<\/span><span style=\"color: #D4D4D4\">&#39;,  # <\/span><span style=\"color: #9CDCFE\">Channel<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Down<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    0<\/span><span style=\"color: #9CDCFE\">xc00b4<\/span><span style=\"color: #D4D4D4\">: &#39;<\/span><span style=\"color: #9CDCFE\">r<\/span><span style=\"color: #D4D4D4\">&#39;,  # <\/span><span style=\"color: #9CDCFE\">Rewind<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    0<\/span><span style=\"color: #9CDCFE\">xc00b3<\/span><span style=\"color: #D4D4D4\">: &#39;<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #D4D4D4\">&#39;,  # <\/span><span style=\"color: #9CDCFE\">Fast<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Forward<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    0<\/span><span style=\"color: #9CDCFE\">xc0033<\/span><span style=\"color: #D4D4D4\">: &#39;<\/span><span style=\"color: #9CDCFE\">c<\/span><span style=\"color: #D4D4D4\">&#39;,  # <\/span><span style=\"color: #9CDCFE\">Settings<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Key<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    0<\/span><span style=\"color: #9CDCFE\">xc027e<\/span><span style=\"color: #D4D4D4\">: &#39;<\/span><span style=\"color: #9CDCFE\">i<\/span><span style=\"color: #D4D4D4\">&#39;,  # <\/span><span style=\"color: #9CDCFE\">Button<\/span><span style=\"color: #D4D4D4\"> 1<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    0<\/span><span style=\"color: #9CDCFE\">xc027f<\/span><span style=\"color: #D4D4D4\">: &#39;<\/span><span style=\"color: #9CDCFE\">t<\/span><span style=\"color: #D4D4D4\">&#39;,  # <\/span><span style=\"color: #9CDCFE\">Button<\/span><span style=\"color: #D4D4D4\"> 2<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    0<\/span><span style=\"color: #9CDCFE\">xc0221<\/span><span style=\"color: #D4D4D4\">: &#39;<\/span><span style=\"color: #9CDCFE\">MQTT_POWER<\/span><span style=\"color: #D4D4D4\">&#39;,  # <\/span><span style=\"color: #9CDCFE\">Power<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">button<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">mapped<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">MQTT<\/span><span style=\"color: #D4D4D4\"> &quot;<\/span><span style=\"color: #9CDCFE\">power_pressed<\/span><span style=\"color: #D4D4D4\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    0<\/span><span style=\"color: #9CDCFE\">xc00cd<\/span><span style=\"color: #D4D4D4\">: &#39;<\/span><span style=\"color: #9CDCFE\">space<\/span><span style=\"color: #D4D4D4\">&#39;,  # <\/span><span style=\"color: #9CDCFE\">Play<\/span><span style=\"color: #D4D4D4\">\/<\/span><span style=\"color: #9CDCFE\">Pause<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    0<\/span><span style=\"color: #9CDCFE\">xc0280<\/span><span style=\"color: #D4D4D4\">: &#39;<\/span><span style=\"color: #9CDCFE\">MQTT_VOICE<\/span><span style=\"color: #D4D4D4\">&#39;  # <\/span><span style=\"color: #9CDCFE\">Voice<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">button<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">mapped<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">MQTT<\/span><span style=\"color: #D4D4D4\"> &quot;<\/span><span style=\"color: #9CDCFE\">voice_pressed<\/span><span style=\"color: #D4D4D4\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">last_key<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">None<\/span><span style=\"color: #D4D4D4\">  # <\/span><span style=\"color: #9CDCFE\">To<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">track<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">last<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">processed<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">key<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">timeout<\/span><span style=\"color: #D4D4D4\"> = 0.5  # <\/span><span style=\"color: #9CDCFE\">Timeout<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">seconds<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #9CDCFE\">same<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">as<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">original<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">script<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">lock<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">threading<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Lock<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\"># <\/span><span style=\"color: #9CDCFE\">Keys<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">which<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">we<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">want<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">bypass<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">last_key<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">logic<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">bypass_keys<\/span><span style=\"color: #D4D4D4\"> = {0<\/span><span style=\"color: #9CDCFE\">xc00b4<\/span><span style=\"color: #D4D4D4\">, 0<\/span><span style=\"color: #9CDCFE\">xc00b3<\/span><span style=\"color: #D4D4D4\">, 0<\/span><span style=\"color: #9CDCFE\">xc00cd<\/span><span style=\"color: #D4D4D4\">}  # <\/span><span style=\"color: #9CDCFE\">Rewind<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">Fast<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Forward<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">Play<\/span><span style=\"color: #D4D4D4\">\/<\/span><span style=\"color: #9CDCFE\">Pause<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">send_idle_message<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">topic<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Sending idle message to {topic}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">mqtt_client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">topic<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&quot;idle&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">rc<\/span><span style=\"color: #D4D4D4\"> != <\/span><span style=\"color: #9CDCFE\">mqtt<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">MQTT_ERR_SUCCESS<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">error<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Failed to send MQTT idle message: {result.rc}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;MQTT idle message sent successfully&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">reset_last_key<\/span><span style=\"color: #D4D4D4\">():<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">global<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">last_key<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">with<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">lock<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&#39;Resetting last_key from {last_key} to None&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">last_key<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">None<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">def<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">remap_key<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">scan_code<\/span><span style=\"color: #D4D4D4\">):<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">global<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">last_key<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&#39;Attempting to remap scan code: {scan_code}&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">with<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">lock<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">scan_code<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">key_mapping<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">new_key<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">key_mapping<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">scan_code<\/span><span style=\"color: #D4D4D4\">]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&#39;Scan code {scan_code} maps to {new_key}&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">scan_code<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">bypass_keys<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">or<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">last_key<\/span><span style=\"color: #D4D4D4\"> != <\/span><span style=\"color: #9CDCFE\">scan_code<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">new_key<\/span><span style=\"color: #D4D4D4\"> == <\/span><span style=\"color: #CE9178\">&#39;MQTT_VOICE&#39;<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;MQTT_VOICE action triggered&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">mqtt_client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">mqtt_topic_voice<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&quot;voice_pressed&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">rc<\/span><span style=\"color: #D4D4D4\"> != <\/span><span style=\"color: #9CDCFE\">mqtt<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">MQTT_ERR_SUCCESS<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                        <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">error<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Failed to send MQTT voice pressed message: {result.rc}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                        <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;MQTT voice pressed message sent successfully&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">threading<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Timer<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">voice_idle_timeout<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">send_idle_message<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">args<\/span><span style=\"color: #D4D4D4\">=[<\/span><span style=\"color: #9CDCFE\">mqtt_topic_voice<\/span><span style=\"color: #D4D4D4\">]).<\/span><span style=\"color: #9CDCFE\">start<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">elif<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">new_key<\/span><span style=\"color: #D4D4D4\"> == <\/span><span style=\"color: #CE9178\">&#39;MQTT_POWER&#39;<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;MQTT_POWER action triggered&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">mqtt_client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">publish<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">mqtt_topic_power<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&quot;power_pressed&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">result<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">rc<\/span><span style=\"color: #D4D4D4\"> != <\/span><span style=\"color: #9CDCFE\">mqtt<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">MQTT_ERR_SUCCESS<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                        <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">error<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&quot;Failed to send MQTT power pressed message: {result.rc}&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                        <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;MQTT power pressed message sent successfully&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">threading<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Timer<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">power_idle_timeout<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">send_idle_message<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">args<\/span><span style=\"color: #D4D4D4\">=[<\/span><span style=\"color: #9CDCFE\">mqtt_topic_power<\/span><span style=\"color: #D4D4D4\">]).<\/span><span style=\"color: #9CDCFE\">start<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                        <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&#39;Executing xdotool for key: {new_key}&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">subprocess<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">run<\/span><span style=\"color: #D4D4D4\">([<\/span><span style=\"color: #CE9178\">&#39;xdotool&#39;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&#39;key&#39;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">new_key<\/span><span style=\"color: #D4D4D4\">])<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">scan_code<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">not<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">bypass_keys<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">last_key<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">scan_code<\/span><span style=\"color: #D4D4D4\">  # <\/span><span style=\"color: #9CDCFE\">Update<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">the<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">last<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">processed<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">key<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">only<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">non<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #9CDCFE\">bypass<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">keys<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">threading<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">Timer<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">timeout<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">reset_last_key<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #9CDCFE\">start<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                    <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&#39;Scan code {scan_code} is the same as the last key processed. Skipping.&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">else<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">warning<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&#39;No mapping found for scan code: {scan_code}&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">try<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">for<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">event<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">in<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">device<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">read_loop<\/span><span style=\"color: #D4D4D4\">():<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">event<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">type<\/span><span style=\"color: #D4D4D4\"> == <\/span><span style=\"color: #9CDCFE\">evdev<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">ecodes<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">EV_MSC<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">and<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">event<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">code<\/span><span style=\"color: #D4D4D4\"> == <\/span><span style=\"color: #9CDCFE\">evdev<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">ecodes<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">MSC_SCAN<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&#39;Detected MSC event: {event}&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">remap_key<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">event<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">elif<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">event<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">type<\/span><span style=\"color: #D4D4D4\"> == <\/span><span style=\"color: #9CDCFE\">evdev<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">ecodes<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">EV_KEY<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">and<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">event<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">value<\/span><span style=\"color: #D4D4D4\"> == 1:  # <\/span><span style=\"color: #9CDCFE\">Only<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">key<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">press<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">events<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">key_event<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">categorize<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">event<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">if<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">                <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">debug<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&#39;Detected key down: {key_event.scancode}, key code: {key_event.keycode}&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">time<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sleep<\/span><span style=\"color: #D4D4D4\">(0.01)  # <\/span><span style=\"color: #9CDCFE\">Add<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">a<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">small<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">delay<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">ensure<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">events<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">are<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">processed<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">properly<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">except<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">KeyboardInterrupt<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">info<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&#39;Exiting...&#39;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">mqtt_client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">loop_stop<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">except<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Exception<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #C586C0\">as<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">e<\/span><span style=\"color: #D4D4D4\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">logging<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">error<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">f<\/span><span style=\"color: #CE9178\">&#39;Unexpected error: {e}&#39;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">exc_info<\/span><span style=\"color: #D4D4D4\">=<\/span><span style=\"color: #9CDCFE\">True<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">mqtt_client<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">loop_stop<\/span><span style=\"color: #D4D4D4\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">exit<\/span><span style=\"color: #D4D4D4\">(1)<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<div class=\"post-views content-post post-7127 entry-meta load-static\">\r\n\t\t\t\t<span class=\"post-views-icon dashicons dashicons-chart-bar\"><\/span> <span class=\"post-views-label\">Post Views:<\/span> <span class=\"post-views-count\">17<\/span>\r\n\t\t\t<\/div>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve put together a helpful little script that let me take full control of my Fire TV remote by remapping the keys. Before this, several buttons were just sitting useless, &#8230;<\/p>\n","protected":false},"author":1,"featured_media":7128,"comment_status":"open","ping_status":"open","sticky":true,"template":"","format":"standard","meta":{"footnotes":""},"categories":[352,356,354,353],"tags":[],"class_list":["post-7127","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-coding","category-kodi","category-linux","category-python"],"_links":{"self":[{"href":"https:\/\/phixd.us\/index.php?rest_route=\/wp\/v2\/posts\/7127","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/phixd.us\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/phixd.us\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/phixd.us\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/phixd.us\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=7127"}],"version-history":[{"count":46,"href":"https:\/\/phixd.us\/index.php?rest_route=\/wp\/v2\/posts\/7127\/revisions"}],"predecessor-version":[{"id":7258,"href":"https:\/\/phixd.us\/index.php?rest_route=\/wp\/v2\/posts\/7127\/revisions\/7258"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/phixd.us\/index.php?rest_route=\/wp\/v2\/media\/7128"}],"wp:attachment":[{"href":"https:\/\/phixd.us\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7127"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/phixd.us\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7127"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/phixd.us\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7127"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}