ContrÎlez un ordinateur via la télécommande d'un amplificateur à l'aide d'Arduino et de Node.js

Préface


L'histoire commence avec le fait qu'il y a six mois, j'ai acheté un amplificateur Yamaha A-S501.


Yamaha A-S501


Inclus Ă©tait une tĂ©lĂ©commande qui pouvait contrĂŽler Ă  la fois l'amplificateur et le lecteur CD Yamaha, que je n'avais naturellement pas. Par consĂ©quent, la plupart des boutons de la tĂ©lĂ©commande n'Ă©taient tout simplement pas utilisĂ©s. Et en gĂ©nĂ©ral, la console elle-mĂȘme n'Ă©tait pas nĂ©cessaire, et elle reposait toujours sur une Ă©tagĂšre.


Cependant, en le regardant, j'étais hanté par l'idée d'utiliser au maximum la télécommande. Par exemple, il serait pratique de s'allonger sur le canapé et de regarder un film, de rembobiner avec un mouvement rapide de la main, de le mettre en pause, etc. Bien sûr, à ces fins, j'avais l'habitude d'utiliser des applications sur mon smartphone pour contrÎler les programmes MPC-HC, Foobar2000, mais la télécommande serait plus rapide et plus pratique.


Comme on dit, les yeux ont peur, mais les mains aussi. Avec le choix de la technologie, tout était immédiatement clair. Arduino - Je voulais depuis longtemps jouer avec elle, et c'est juste une grande chance. Pour le gestionnaire de boutons, Node.js, car Je me spécialise dans javascript et je ne voulais pas changer de contexte.


Et donc, allons-y ...


Solutions prĂȘtes Ă  l'emploi


Un des analogues existants que j'ai pu trouver est Flirc . En l'utilisant, vous pouvez émuler des frappes sur le clavier physique d'un ordinateur.



Un tel rĂ©cepteur infrarouge coĂ»te 100 zlotys (≈ 28 $). Pour l'avenir, c'est deux fois plus cher que ce que j'ai obtenu. De plus, en termes de fonctionnalitĂ©, cela s'est avĂ©rĂ© encore meilleur (subjectivement).


Achat de piĂšces



J'avais besoin de:


  • En fait, la carte Arduino Uno elle-mĂȘme. Il convient de noter qu'il ne s'agit pas de la carte d'origine, mais d'une sorte de clone polonais. Selon la description - il est complĂštement similaire Ă  l'original. (27,90 zƂ)
  • RĂ©cepteur infrarouge VS1838B HX1838 (tension: 3,3–5 V, frĂ©quence: 38 kHz, angle: 90 °) (1,30 zƂ)
  • Carte de prototypage + fils (13.90 zƂ)
  • Un plateau vide pour tout souder (2.10 zƂ)
  • Connecteurs pour cartes de connexion (2,51 zƂ)

Total: 47,71 zƂ (≈ 14 $)


Logiciels


En attendant la livraison, j'ai commencé à écrire un «pilote», qui devrait lire les données du port série d'Arduino et effectuer certaines actions pour le bouton pressé de la télécommande.


L'idĂ©e Ă©tait de pouvoir tout personnaliser et tout. Chaque bouton de la tĂ©lĂ©commande peut ĂȘtre affectĂ© Ă  certaines actions de plusieurs types:



{ "key": "space" } 

  • ExĂ©cution d'un programme arbitraire avec des paramĂštres:

 { "exec": ["c:\\Program Files (x86)\\foobar2000\\foobar2000.exe", "/play"] } 


 { "if": { "running": "mpc-hc.exe" }, "then": [ ... ], "else": [ ... ] } 

Chaque type a son propre gestionnaire, qui a la mĂȘme API, et il Ă©tait donc possible de tout rĂ©duire en une boucle simple qui dĂ©marre tous les gestionnaires en sĂ©quence.


 const runHandlers = require('./handlers') module.exports = async function run(actions) { if (!Array.isArray(actions)) { actions = [actions] } for (const act of actions) { await runHandlers(act) } } 

Au lieu de mille mots de documentation, les tests vous disent tout:


 run when "exec" action √ executes the specified file without args (as array) (4ms) √ executes the specified file without args (as string) (1ms) √ executes the specified file with args √ rejects if "exec" has wrong type (5ms) when "key" action √ sends the specified key press if passed string (1ms) √ sends the specified key combination if passed array √ rejects if "key" has wrong type (1ms) when "if" action √ rejects if no "then" (1ms) √ rejects if operator is not supported when operator if "running" √ runs "then" actions if the condition is true (1ms) √ runs "else" actions if the condition is false √ does not run anything if the condition is false and no "else" statement (1ms) when multiple actions √ executes all actions (1ms) when multiple actions are mixed into one √ runs only first one alphabetically 

Il reste à attendre les détails chéris.


Le fer


J'avoue, je n'ai rien inventĂ© de nouveau, tout a dĂ©jĂ  Ă©tĂ© fait avant moi. Je viens d'utiliser le diagramme prĂȘt Ă  l'emploi de l'article Comment configurer une tĂ©lĂ©commande infrarouge et un rĂ©cepteur sur un Arduino .


Le schéma est assez simple:



En pratique:




Firmware


J'ai Ă©galement honnĂȘtement empruntĂ© le firmware de l' article , pour son travail, j'aurai besoin de la bibliothĂšque IRremote Arduino .


J'ai remplacé les codes des boutons par ceux de ma télécommande:


 void loop() { if (irrecv.decode(&results)) { if (results.value == 0xFFFFFFFF) { results.value = key_value; } switch (results.value) { case 0x9E6140BF: Serial.println("play"); break; case 0x9E61AA55: Serial.println("pause"); break; /* ...*/ case 0x5EA1A857: Serial.println("cd"); break; default: Serial.println(results.value, HEX); break; } key_value = results.value; irrecv.resume(); } } 


DĂšs que les noms des boutons pressĂ©s sont apparus dans la fenĂȘtre du moniteur de port dans l'IDE Arduino, il a Ă©tĂ© nĂ©cessaire d'ajouter un composant pour travailler avec le port sĂ©rie au pilote.


Le résultat a été un wrapper sur la bibliothÚque serialport et, en fait, le flux de données du port:


 const SerialPort = require('serialport') module.exports = class SerialPortReader { constructor(port) { const serialPort = new SerialPort(port) this.lineStream = serialPort.pipe(new SerialPort.parsers.Readline()) } start(handler) { this.lineStream.on('readable', () => { const data = this.lineStream.read().trim() handler(data) }) } } 

Plus tard, il a fallu transformer les gestionnaires en fonction "anti-rebond", car la tĂ©lĂ©commande reçoit un signal Ă  rĂ©pĂ©tition rapide qui, mĂȘme en appuyant briĂšvement sur le bouton, parvient Ă  s'Ă©teindre plusieurs fois. Cependant, la suppression d'une telle option pour tous les boutons n'est pas non plus tout Ă  fait appropriĂ©e, par exemple pour le volume.


Le code final ressemble Ă  ceci:


 const debounce = require('debounce') const settings = require('./lib/settings') const run = require('./lib/run') const SerialPortReader = require('./lib/SerialPortReader') const simpleHandle = async button => { const actions = settings.mappings[button] if (!actions) { console.warn(`Action not found for remote control button "${button}"`) return } try { await run(actions) } catch (e) { console.error(e.message) process.exit(1) } } const debouncedHandle = debounce(simpleHandle, settings.debounceDelay, true) const callHandleFn = button => { return (settings.noDebounce.includes(button) ? simpleHandle : debouncedHandle)(button) } const reader = new SerialPortReader(settings.serialPort) reader.start(callHandleFn) 

Création d'un conseil d'administration indépendant


AprĂšs m'ĂȘtre assurĂ© que le prototype fonctionne, j'ai procĂ©dĂ© Ă  la crĂ©ation d'une planche. Il convient de le noter, pour moi, c'est la premiĂšre expĂ©rience dans ce domaine. Je n'avais pas de fer Ă  souder appropriĂ© avec une petite aiguille - seulement l'ancien gros soviĂ©tique avec un fil tendu.


Avec un chagrin en deux, j'ai réussi à souder les "jambes" (sur les deux gros connecteurs de 8 broches, seulement 2 broches ont survécu). Tout le reste était plus facile.



(Crooked. TrÚs probablement en raison du clone Arduino. Les nids sont inégaux les uns par rapport aux autres.)



J'ai intentionnellement placé le récepteur infrarouge entre les cartes. Ainsi, l'appareil se glisse facilement sous l'amplificateur. J'ai décidé de faire les pistes en connectant les trous sur la planche avec de l'étain, au lieu de les connecter avec des fils. Et enfin, j'ai collé la bande pour que la carte ne se referme pas sur le boßtier métallique de l'amplificateur.




Résultat: un appareil et un logiciel pleinement opérationnels pour 14 $. L'expérience acquise et la joie du travail accompli et le résultat sont inestimables! :-)


Merci de votre attention!




Démo:



Sources chez Github .




PS Merci ramanchik 'u pour la consultation :)

Source: https://habr.com/ru/post/fr453474/


All Articles