Статьи

Пульт дистанционного управления Mac с Node.js и Arduino

Сочетание Arduinos и Node.js позволяет нам делать много неожиданных вещей. В этой статье я покажу, как создать пульт дистанционного управления для Mac с помощью Arduinos, Node.js и AppleScript.

Если вы новичок в объединении Arduinos и Node.js, я ранее уже рассказывал о включении светодиодных индикаторов и отображении данных веб-API на ЖК-дисплее .

Наш пульт дистанционного управления Arduino будет увеличивать и уменьшать громкость нашего Mac, указывать нашему Mac воспроизводить плейлист iTunes по нашему выбору и настраивать его на прекращение воспроизведения на iTunes (что, вероятно, будет этим плейлистом!).

Имейте в виду, что эта демонстрация предоставляет доступ к командам непосредственно на вашем Mac — есть вероятность, что это может быть использовано неправильно или вредно, если вы предоставите слишком большой доступ! Храните его для личного использования, а не для крупных корпоративных проектов.

Настройка нашего Arduino

Убедитесь, что на вашей плате Arduino установлен эскиз StandardFirmata, так как мы будем использовать библиотеку johnny-Five для отправки инструкций нашему Arduino. Это будет работать, только если у вас есть StandardFirmata:

Установка стандартных Firmata на Arduino

Наш макет Arduino, созданный для этой демонстрации, выглядит так:

Эскиз для нашего Arduino Mac Remote Control

Наш серверный код

Наш серверный код Node.js относительно короткий и приятный для этой демонстрации:

var five = require('johnny-five'), board = new five.Board(), exec = require('child_process').exec, btn1, btn2, btn3, btn4, btn5, currentVolLevels = {}; board.on('ready', function() { console.log('Arduino board is ready!'); btn1 = new five.Button(7); btn2 = new five.Button(6); btn3 = new five.Button(5); btn4 = new five.Button(4); btn5 = new five.Button(3); btn1.on('down', function(value) { askiTunes('play playlist \"Top 25 Most Played\"'); }); btn2.on('down', function(value) { askiTunes('stop'); }); btn3.on('down', function(value) { setVolumeLevel(currentVolLevels['output volume'] + 5); }); btn4.on('down', function(value) { setVolumeLevel(currentVolLevels['output volume'] - 5); }); btn5.on('down', function(value) { toggleMute(); }); getVolumeLevels(); }); function getVolumeLevels() { exec("osascript -e 'get volume settings'", function(err, stdout, stderr) { if (!err) { var levels = stdout.split(', '); levels.forEach(function(val,ind) { var vals = val.split(':'); if (vals[1].indexOf('true') > -1) currentVolLevels[vals[0]] = true; else if (vals[1].indexOf('false') > -1) currentVolLevels[vals[0]] = false; else currentVolLevels[vals[0]] = parseInt(vals[1]); }); console.log(currentVolLevels); } }); } function setVolumeLevel(level) { console.log('Setting volume level to ' + level); exec("osascript -e 'set volume output volume " + level + "'", function() { getVolumeLevels(); }); } function toggleMute() { var muteRequest = currentVolLevels['output muted'] ? 'without' : 'with'; console.log('Toggling mute to ' + muteRequest + ' muted'); exec("osascript -e 'set volume " + muteRequest + " output muted'", function() { getVolumeLevels(); }); } function askiTunes(event, callback) { exec("osascript -e 'tell application \"iTunes\" to "+event+"'", function(err, stdout, stderr) { console.log('iTunes was just asked to ' + event + '.'); }); } 

Этот код объяснил

Теперь важная часть статьи — что означает весь этот код! Давайте рассмотрим, как все сочетается.

Для взаимодействия с нашей платой Arduino мы используем johnny-Five. Мы начнем с настройки нашего модуля Johnny-Five и нашей платы Arduino. Затем мы определяем переменные для хранения наших пяти кнопок.

 var five = require('johnny-five'), board = new five.Board(), btn1, btn2, btn3, btn4, btn5, 

Мы также настроили нашу функцию exec() которая позволяет нам запускать команды AppleScript из Node.js.

 exec = require('child_process').exec, 

Когда johnny-5 сообщает нам, что наша плата готова к использованию, мы запускаем быстрый console.log и определяем наши пять кнопок и контакты Arduino, к которым они подключены (7, 6, 5, 4 и 3).

 board.on('ready', function() { console.log('Arduino board is ready!'); btn1 = new five.Button(7); btn2 = new five.Button(6); btn3 = new five.Button(5); btn4 = new five.Button(4); btn5 = new five.Button(3); 

При каждом событии нажатия кнопки мы запускаем разные функции. На нашей первой кнопке мы запускаем askiTunes() которая отправляет iTunes запрос. В нашем случае он запрашивает наш «25 самых популярных» плейлистов.

 btn1.on('down', function(value) { askiTunes('play playlist \"Top 25 Most Played\"'); }); 

Функция askiTunes() выполняет наш первый бит AppleScript, используя функцию exec() . Все наши команды AppleScript выполняются в Node.js с помощью команды osascript .

Наша askiTunes() запускает команду osascript -e 'tell application \"iTunes\" to "+event+"' . Это дает нам общую команду, указывающую iTunes сделать что-то. Мы можем настроить что-то через переменную event .

Когда мы закончим, мы запустим console.log чтобы знать, что событие было распознано.

 function askiTunes(event, callback) { exec("osascript -e 'tell application \"iTunes\" to "+event+"'", function(err, stdout, stderr) { console.log('iTunes was just asked to ' + event + '.'); }); } 

Наша вторая кнопка запускает ту же askiTunes() но мы передаем ей событие stop чтобы остановить все, что в данный момент воспроизводится.

 btn2.on('down', function(value) { askiTunes('stop'); }); 

Если бы у нас было больше кнопок для игры, мы могли бы добавить кнопки для pause и общее событие play которое возобновит то, что в данный момент находится в очереди.

Наши третья и четвертая кнопки увеличивают громкость нашего Mac с помощью функции, которую мы будем называть setVolumeLevel() .

 btn3.on('down', function(value) { setVolumeLevel(currentVolLevels['output volume'] + 5); }); btn4.on('down', function(value) { setVolumeLevel(currentVolLevels['output volume'] - 5); }); 

setVolumeLevel() использует объект, который мы определяем в начале нашего кода, называемый currentVolLevels . Этот объект хранит четыре различных значения, которые AppleScript возвращает с нашего Mac. Образец этих данных выглядит так:

 { 'output volume': 5, 'input volume': 83, 'alert volume': 100, 'output muted': false } 

Как вы можете видеть, у нас есть значение в этом объекте JSON, называемое 'output volume' . Мы добавляем пять к уровню громкости на нашей третьей кнопке (увеличивая его) и уменьшая его на пять на нашей четвертой кнопке (уменьшая его), а затем передаем это значение в функцию, чтобы изменения произошли.

Наша setVolumeLevel() использует команду AppleScript для set volume output volume чтобы изменить set volume output volume нашего Mac до уровня, который мы передали. Мы также запускаем консольный журнал, чтобы отслеживать запросы на уровне громкости.

 function setVolumeLevel(level) { console.log('Setting volume level to ' + level); exec("osascript -e 'set volume output volume " + level + "'", function() { getVolumeLevels(); }); } 

Когда наш код AppleScript был запущен, мы вызываем getVolumeLevels() который является нашей функцией, которая устанавливает все наши значения currentVolLevels и отслеживает объем нашего Mac. Я объясню это подробно после того, как мы рассмотрели нашу последнюю кнопку.

Эта вышеупомянутая последняя кнопка запускает toggleMute() которая toggleMute() и включает наш Mac.

 btn5.on('down', function(value) { toggleMute(); }); 

Наша toggleMute() просматривает currentVolLevels['output muted'] и использует либо osascript -e 'set volume without output muted' чтобы отключить osascript -e 'set volume with output muted' либо osascript -e 'set volume with output muted' чтобы включить его. Если currentVolLevels['output muted'] равен true , тогда мы устанавливаем ключевое слово на 'without' чтобы убрать приглушение. Если значение равно false , мы устанавливаем ключевое слово на 'with' чтобы включить звук.

 function toggleMute() { var muteRequest = currentVolLevels['output muted'] ? 'without' : 'with'; console.log('Toggling mute to ' + muteRequest + ' muted'); exec("osascript -e 'set volume " + muteRequest + " output muted'", function() { getVolumeLevels(); }); } 

Этот вызов AppleScript также запускает getVolumeLevels() после ее завершения. В этой функции мы запускаем osascript -e 'get volume settings' чтобы получить текущий объем нашего Mac. Возвращает эти значения в формате:

 "output volume:5, input volume:83, alert volume:100, output muted:false" 

В нашем getVolumeLevels() мы берем значение, возвращенное в переменной stdout и форматируем его в объект JSON, хранящийся в currentVolLevels используя код, который выглядит следующим образом:

 function getVolumeLevels() { exec("osascript -e 'get volume settings'", function(err, stdout, stderr) { if (!err) { var levels = stdout.split(', '); levels.forEach(function(val,ind) { var vals = val.split(':'); if (vals[1].indexOf('true') > -1) currentVolLevels[vals[0]] = true; else if (vals[1].indexOf('false') > -1) currentVolLevels[vals[0]] = false; else currentVolLevels[vals[0]] = parseInt(vals[1]); }); console.log(currentVolLevels); } }); } 

Преобразование JSON специально разработано для строки, которую мы получили выше. Сначала мы разбиваем каждую пару ключ / значение на массив, называемый levels , разделяя его между запятыми, чтобы создать массив следующим образом:

 ['output volume:5', 'input volume:83', 'alert volume:100', 'output muted:false'] 

Затем мы перебираем каждую строку в массиве, аккуратно переставляя ее в наш объект JSON currentVolLevels . Для этого мы разбиваем каждую пару ключ / значение на массив с именем vals используя символ : качестве нашего сплиттера. vals[0] будет каждой клавишей, такой как output volume , тогда как vals[1] содержит фактические значения уровня громкости. В качестве ключа объекта JSON мы используем vals[0] , например currentVolLevels[vals[0]] = something .

Есть один фактор, который мы должны помнить и учитывать при возврате уровней громкости. Одним из этих значений является значение true / false (наше состояние приглушения / включения звука), а остальные — числа. Все они представлены в виде строк и должны быть преобразованы. Мы сделаем это с помощью простого оператора if, который смотрит на значение vals[1] . Мы проверяем строку "true" и строку "false" . Если мы найдем что-либо из этого, мы установим соответствующее значение внутри currentVolLevels как соответствующее логическое значение. Если это ни то, ни другое, мы анализируем строку в целое число, которое будет представлять числовой уровень громкости, и сохраняем его внутри currentVolLevels .

Конечный результат выглядит так:

 { 'output volume': 5, 'input volume': 83, 'alert volume': 100, 'output muted': false } 

Наш файл Package.json

В этом случае наш файл package.json довольно прост и в основном должен гарантировать, что у нас установлены модули johnny-Five и serialport npm.

 { "name": "nodemaccontroller", "version": "1.0.0", "description": "Code to control your Mac via Node", "main": "index.js", "dependencies": { "johnny-five": "^0.8.76", "serialport": "^1.7.1" }, "author": } 

Наш пульт дистанционного управления в действии

Установите все вышеперечисленные зависимости, используя npm install , убедитесь, что ваш Arduino подключен и работает эскиз StandardFirmata, затем запустите node index.js . После запуска нажмите несколько кнопок, и вы сможете управлять своим Mac! Пока он работает, он будет выглядеть так в консоли:

Наш Arduino пульт дистанционного управления в действии

Наш Arduino пульт дистанционного управления в действии

Другие возможности

Если вы не большой поклонник музыки или вы не используете свой Mac для своей музыки, есть множество других ярлыков AppleScript, к которым вы можете подключить свой сервер Node.js. Вот несколько идей.

Запустить приложения

 function openCalculator() { exec("osascript -e 'tell application \"Calculator\" to launch'"); } 

Откройте новое окно Finder

 function openFinderWindow() { exec("osascript -e 'tell app \"Finder\" to make new Finder window'"); } 

Заставь Mac говорить!

 function tellMacToSpeak() { exec("osascript -e 'say \"I am completely operational, and all my circuits are functioning perfectly.\"'"); } 

Вывод

Теперь у вас есть отличный способ сделать свой собственный Mac периферийным устройством! Если вы хотите, чтобы оно работало как переносное устройство, вы можете настроить websockets, socket.io или базовый HTTP-сервер, предоставить Arduino Wi-Fi или другой способ удаленного доступа к серверу Node.js (или использовать что-то другое). как микроконтроллер Particle Photon или Particle Electron , а затем выполните эти вызовы exec() на основе удаленных команд (хотя, будьте осторожны, exec() может быть использован неправильно!). Здесь есть много возможностей для некоторых очень забавных проектов! Как всегда, если вы делаете что-то аккуратно, оставляете заметку в комментариях или связываетесь со мной в Твиттере ( @thatpatrickguy ), я хотел бы проверить это!