В настоящее время WhatsApp является одним из самых популярных кросс-платформенных мессенджеров, используемых человечеством. По самым скромным оценкам его используют более 2 миллиардов людей во всем мире. Такая широкая популярность этого приложения приковывает к нему и повышенное внимание со стороны бизнеса. Но бизнес версия этого приложения под названием “WhatsApp Business” недостаточно хорошо подходит для автоматизации большого числа различных процессов. К примеру, для этих целей гораздо лучше подходит бот от Telegram. Ранее на нашем сайте мы уже рассматривали взаимодействие платы Raspberry Pi с ботом Telegram и управляли контактами платы с его помощью.
В данной статье мы рассмотрим создание WhatsApp бота на Raspberry Pi с использованием пакета pyautogui, написанного на Python. Мы будем запускать WhatsApp web на нашей плате Raspberry Pi, с помощью которого мы будем читать сообщения из нашего чата и давать соответствующие ответы на эти сообщения. В демонстрационных целях мы запрограммировали плату Raspberry Pi на управление светодиодом из данного чата. Но при небольшой доработке (добавив реле и цепи управления) вы можете использовать данный проект для управления любыми домашними электронными устройствами в своем доме.
Также на нашем сайте вы можете посмотреть ставшим весьма популярным проект автоматизации дома на Raspberry Pi с управлением с веб-страницы и все рассмотренные нами проекты автоматизации дома.
Использование WhatsApp на Raspberry Pi
Ранее на нашем сайте мы уже рассматривали использование WhatsApp на Raspberry Pi с помощью библиотеки Yowsup. Но этот метод имеет много ограничений и страдает от различных багов. Поэтому в данной статье мы рассмотрим другой способ использования WhatsApp на Raspberry Pi.
Почему мы не будем использовать WhatsApp Business API
Я думаю, многие знают о том, что у WhatsApp есть свое собственное API для использования в различных бизнес процессах. С помощью данного API и языка python можно автоматизировать обработку сообщений WhatsApp. Примерами подобных приложений являются OYO, MakeMyTrip и т.д. Но использование этого API для такого маленького процесса как автоматизация дома, является дорогим удовольствием (лицензия на него стоит достаточно дорого).
Чтобы обойти данное ограничение мы в данном проекте будем использовать небольшой лайфхак чтобы получить доступ к содержимому WhatsApp – это позволит нам бесплатно читать и отвечать на сообщения. Для этого нам понадобится всего лишь плата Raspberry Pi и соединение с интернетом.
Selenium или pyautogui – что лучше для автоматизации WhatsApp на Raspberry Pi
Теперь, когда мы выбрали низкобюджетный способ автоматизации WhatsApp, нам необходимо решить какой инструмент лучше использовать – selenium или Pyautogui.
Selenium представляет собой инструмент для автоматизации браузера, который изначально создавался для тестирования веб-приложений. Но его также можно использовать для автоматизации практически любых процессов в сети интернет, например, чтения и постинга сообщений в социальной сети Facebook. В общем, с помощью selenium можно автоматизировать практически все, что можно делать с помощью браузера.
Альтернативой selenium для автоматизации WhatsApp являются pyautoGUI и OpenCV. Этот пакет помогает нам читать содержимое экрана и производить навигацию по экрану чтобы выполнить любое необходимое нам действие. То есть большинство вещей, которые мы можем делать на Raspberry Pi с помощью мышки и клавиатуры, можно делать с помощью пакетов pyautogui и paperclip. Далее мы более детально рассмотрим как это можно сделать.
Автор проекта (ссылка на оригинал приведена в конце статьи) тестировал возможности pyautogui и selenium для задач, решаемых в проекте, и пришел к выводу что selenium достаточно сложно использовать на Raspberry Pi из-за его веб-драйвера. Поэтому он решил использовать pyautogui. Но вы можете попробовать использовать и selenium, если хотите.
Установка пакетов на Raspberry Pi для автоматизации WhatsApp
Прежде чем идти дальше, нам необходимо установить ряд пакетов на плату Raspberry Pi. Как было указано раньше, нам будет необходима библиотека OpenCV. Вы можете установить ее с помощью Cmake или с помощью установщика pip. Автор проекта рекомендует использовать pip поскольку это намного проще и быстрее.
В данном случае для простой установки OpenCV для Python 3 на Raspberry Pi выполните следующую последовательность команд:
1 2 3 4 5 6 7 8 |
pip3 install opencv-python sudo apt-get install libcblas-dev sudo apt-get install libhdf5-dev sudo apt-get install libhdf5-serial-dev sudo apt-get install libatlas-base-dev sudo apt-get install libqt4-test sudo apt-get install libqtgui4 sudo apt-get install libjasper-dev |
Далее нам необходимо установить пакеты Pyperclip и pyautogui для автоматизации наших WhatsApp сообщений. Pyautogui используется для чтения элементов на экране и для создания событий клавиатуры и мыши, а pyperclip используется для копирования и вставки информации между экраном и программой на python.
1 2 |
pip3 install pyperclip pip3 install pyautogui |
Схема проекта
Схема автоматизации дома с помощью Raspberry Pi и WhatsApp представлена на следующем рисунке.
Как видите, схема проекта очень проста. Нам необходимо всего лишь подключить светодиод к контакту GPIO 40 платы Raspberry Pi. Когда пользователь будет передавать WhatsApp сообщение “turn on the light” (включить свет) плата Raspberry Pi будет включать этот светодиод, а когда плата будет получать сообщение на выключение этого светодиода, она будет выключать его.
Внешний вид собранной конструкции проекта показан на следующем рисунке.
Объяснение программы для Raspberry Pi
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Все необходимые коды на Python для данного проекта можно скачать по следующей ссылке – Raspberry pi WhatsApp Automation Python code files.
Внутри этого скачанного каталога вы найдете код основной программы проекта на Python и пять изображений. Эти изображения будут помогать нам идентифицировать различные части (элементы) на странице WhatsApp. Убедитесь в том, что вы запускаете программу на Python на исполнение в том же самом каталоге, в котором находятся данные изображения. Также, если вы будете добавлять в этот каталог другие изображения, убедитесь в том, что они в формате .JPG, потому что плата Raspberry Pi не очень хорошо работает с другими форматами изображений.
Первым делом нам в программе необходимо подключить (импортировать) используемые библиотеки. Назначение части из них уже было рассмотрено раньше в статье. Библиотека time будет использоваться для организации временных задержек в программе, а библиотека webbrowser будет использоваться для автоматического открытия веб-браузера и запуска WhatsApp.
1 2 3 4 5 6 |
import pyautogui as pygu #To move mouse cursor and make click and keyboard strokes from time import sleep #for delay import pyperclip #to copy and past data import webbrowser #to open webbrowser import RPi.GPIO as IO # calling header file for GPIO’s of PI import time # calling for time to provide delays in program |
Далее сконфигурируем используемые контакты и откроем WhatsApp браузер. Контакт GPIO 40 будет использоваться для управления светодиодом, поэтому мы сконфигурируем его в качестве цифрового выхода. Также мы запустим веб-браузер, которым по умолчанию в Raspberry Pi является Chromium. Далее мы откроем web.whatsapp.com – с его помощью мы и будем производить нашу автоматизацию WhatsApp. Убедитесь в том, что в сервисе web.whatsapp.com вы уже сканировали QR код и поставили в нем галочку “always login”.
1 2 3 4 |
IO.setmode (IO.BOARD) # programming the GPIO by BOARD pin numbers, GPIO21 is called as PIN40 IO.setup(40,IO.OUT) # initialize digital pin40 as an output. #Open the default webbrowser and open web.whatsapp webbrowser.open_new('https://web.whatsapp.com/') |
Затем мы подготовим шаблоны сообщений, которые мы будем передавать пользователю в чат в качестве ответов. Вы можете создать такое количество этих сообщений, какое захотите. В шаблонах этих сообщений можно использовать форматирование текста, например, *bold* будет обозначать выделение жирным шрифтом, также можно использовать смайлики с помощью команды :smiley.
1 2 3 4 5 6 7 8 9 10 |
default_message = [ "Hi I am your Whatsapp Bot :robot \n from RaspberryPi. I can help you with basic home automation. You can try any of the following :notes \n commands", "*turn on light* - _Turns on the led connected to pi_", "*turn off light* - _Turns off the led connected to pi_"] turn_on_light = [ "Sure, your :bulb \n Light is now turned on" ] turn_off_light = [ "Okay, Your LED is not turned off" ] |
Далее мы будем производить проверку успешного открытия WhatsApp в веб-браузере. Представленная ниже функция будет проверять успешно ли открылась страница чата WhatsApp в веб-браузере. Она будет использовать картинку под названием whatsapp_header.jpg (находится в скачанном вами ранее каталоге) чтобы проверить что это действительно так. Мы будем переходить к дальнейшему исполнению программы только если эта страница открылась успешно.
В коде этой функции мы будем производить поиск изображения “whatsapp_header.jpg” на нашем экране. Если мы найдем это сообщение на экране мы можем подтвердить что страница открылась успешно.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#Wait for whatsapp page to def open_whatsapp(): # check if whatsapp opened successfully find_whatsapp_header = None while find_whatsapp_header is None: find_whatsapp_header = pygu.locateOnScreen("Whatsapp_header.JPG", confidence=.8) use_here_button_pos = pygu.locateOnScreen("use_here_button.JPG", confidence=.8) if (use_here_button_pos): print("Whatsapp is being used somewhere else, clicking on use here") sleep(2) pygu.moveTo(use_here_button_pos[0], use_here_button_pos[1], duration=0.5) pygu.click() print(".") sleep(2) return 1 |
После этого мы будем производить проверку доступности чата. Аналогично, в этой функции мы будем искать на экране изображение “green_circle.jpg”. Если это изображение найдено на экране, мы будем перемещаться к этому зеленому кругу и производить клик на нем. Если пользователь использует чат в первый раз нам необходимо будет нажать на кнопку "ok" перед тем как продолжить, в ином случае мы можем просто продолжить.
Эта функция будет возвращать 1 если новый чат доступен и будет возвращать 0 если он не доступен. Она будет также открывать чат и быть готовым к чтению или передаче сообщений.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#checks for new message and opens it def new_chat_available(): # Check for new messages green_circle_pos = pygu.locateOnScreen("green_circle.JPG", confidence=.8) if (green_circle_pos): sleep(2) pygu.moveTo(green_circle_pos[0], green_circle_pos[1], duration=0.5) pygu.click() sleep(1) ok_button_pos = pygu.locateOnScreen("ok_button.JPG", confidence=.8) if (ok_button_pos): pygu.moveTo(ok_button_pos[0], ok_button_pos[1], duration=0.5) pygu.click() return 1 else: sleep(1) return 0 |
Далее мы будем читать последнее сообщение, переданное пользователем. Данная функция будет считывать последнее сообщение при помощи поиска изображения “smily_paperclip.jpg” на экране. После этого она будет перемещаться в текстовое поле с помощью функции py.mpveTo(). Обратите внимание на то, что значения 50 и 35 жестко запрограммированы внутри этой функции. Возможно, вам их придется немного изменить для более корректной работы программы.
Затем мы будем читать последнее сообщение при помощи тройного клика (triple-clicking) на белом прямоугольнике – при помощи этого мы будем выделять все сообщение, затем мы можем копировать все сообщение при помощи ctrl+C и затем использовать pyperclip чтобы получить это значение (прочитать это сообщение). Как вы можете видеть, представленная функция возвращает скопированную информацию при помощи pyperclip.paste().
1 2 3 4 5 6 7 8 9 |
def read_last_message(): smily_paperclip_pos = pygu.locateOnScreen("smily_paperclip.JPG", confidence=.6) pygu.moveTo(smily_paperclip_pos[0], smily_paperclip_pos[1]) pygu.moveTo(smily_paperclip_pos[0] + 50, smily_paperclip_pos[1] - 35, duration=0.5) sleep(1) pygu.tripleClick() pygu.hotkey('ctrl', 'c') sleep(0.1) return (pyperclip.paste()) |
Затем нам необходимо сформировать правильный ответ на последнее принятое сообщение. И следующая функция используется для поиска соответствующего ответа на последнее сообщение, переданное пользователем. Данная функция сравнивает это сообщение с заранее определенными ответами, которые мы ожидаем увидеть. В нашем случае мы ожидаем увидеть сообщения “CD_bot”, “turn on light” или “turn off light”. Если пользователь передал одно из этих сообщений, мы будем отвечать ему заранее подготовленным текстом. Также мы будем включать/выключать светодиод в зависимости от принятой команды.
1 2 3 4 5 6 7 8 9 10 11 |
def get_response(incoming_message): if "CD_bot" in incoming_message: return default_message if "turn on light" in incoming_message: IO.output(40,1) # turn the LED on return turn_on_light if "turn off light" in incoming_message: IO.output(40,0) # turn the LED off return turn_off_light else: return "" |
Теперь, когда мы знаем последнее сообщение, переданное пользователем, и подготовили сообщение для ответа, нам необходимо всего лишь передать этот ответ пользователю. Для этого мы запрограммируем функцию send_message(). В качестве параметра в эту функцию будет передаваться сообщение для ответа, а она будет передавать его в окно чата с помощью метода typewrite, доступного в pyautogui. Затем мы будем использовать shift+enter чтобы перейти на новую строку и затем нажимать enter чтобы передать сообщение.
1 2 3 4 5 |
def send_message(message_content): for content in message_content: pygu.typewrite(content, interval=.02) pygu.hotkey('shift', 'enter') pygu.hotkey('enter') #Enter key to send the message |
Затем мы будем проверять появилось ли новое сообщение в текущем чате. Для того чтобы проверить открыт чат или нет, мы использовали поиск изображения green_circle. Если же пользователь в текущем открытом чате передает новое сообщение нам необходимо обнаружить его при помощи проверки цвета пиксела под курсором. Принятые сообщения WhatsApp всегда отображаются на белом фоне. Поэтому мы будем проверять цвет пиксела под курсором – если он белый, мы будем продолжать чтение этого сообщения как рассматривалось ранее.
1 2 3 4 5 6 7 |
def new_message_available(): current_mouse_pos = pygu.position() pointer_color = pygu.pixel(current_mouse_pos[0], current_mouse_pos[1]) if (pointer_color == (255, 255, 255)): return 1 else: return 0 |
Теперь, когда у нас запрограммированы функции на все необходимые нам действия, нам необходимо всего лишь правильно их использовать внутри бесконечного цикла while. Внутри этого цикла мы будем проверять чат на наличие новых сообщений и соответствующим образом на них отвечать.
1 2 3 4 5 6 7 8 |
if (open_whatsapp()): #if whatsapp page is opened successfully print("##Whatsapp page ready for automation##") while(1): if (new_chat_available() or new_message_available()): print("New chat or message is available") incoming_message = read_last_message() #read the last message that we received message_content = get_response(incoming_message) #decide what to respond to that message send_message(message_content) #send the message to person |
Теперь, основываясь на материалах данной статьи, вы можете создать проект, в котором вы сможете управлять любым домашним электронным устройством или, к примеру, измерять температуру и влажность в комнате и передавать эту информацию в чат WhatsApp. Также замечательной частью описанного проекта является то, что вы можете расшарить (предоставить доступ) этого бота для своих знакомых и они тоже будут иметь к нему доступ. В этом случае им необходимо будет знать имя этого бота – в нашем случае это “CD_bot”. Также вы можете добавить этого бота в группу WhatsApp и тогда все, кто состоит в этой группе, смогут давать команды боту и получать от него на них ответы.
Более подробно работу этого проекта вы можете посмотреть на видео, приведенном в конце статьи.
Исходный код программы на Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
import pyautogui as pygu # библиотека для перемещения курсора мыши и имитации нажатия кнопок клавиатуры from time import sleep # for delay import pyperclip # для копирования и вставки данных import webbrowser # для открытия веб-браузера import os # для закрытия веб-браузера import RPi.GPIO as IO # calling header file for GPIO’s of PI import time # для организации временных задержек в программе IO.setmode (IO.BOARD) # programming the GPIO by BOARD pin numbers, GPIO21 is called as PIN40 IO.setup(40,IO.OUT) # инициализируем pin40 в качестве цифрового выхода # открываем веб-браузер по умолчанию и открываем web.whastapp webbrowser.open_new('https://web.whatsapp.com/') default_message = [ "Hi I am your Whatsapp Bot :robot \n from RaspberryPi. I can help you with basic home automation. You can try any of the following :notes \n commands", "*turn on light* - _Turns on the led connected to pi_", "*turn off light* - _Turns off the led connected to pi_"] turn_on_light = [ "Sure, your :bulb \n Light is now turned on" ] turn_off_light = [ "Okay, Your LED is not turned off" ] #Wait for whatsapp page to def open_whatsapp(): # проверяем успешно ли открылся whatsapp find_whatsapp_header = None while find_whatsapp_header is None: find_whatsapp_header = pygu.locateOnScreen("Whatsapp_header.JPG", confidence=.8) use_here_button_pos = pygu.locateOnScreen("use_here_button.JPG", confidence=.8) if (use_here_button_pos): print("Whatsapp is being used somewhere else, clicking on use here") sleep(2) pygu.moveTo(use_here_button_pos[0], use_here_button_pos[1], duration=0.5) pygu.click() print(".") sleep(2) return 1 # проверяем наличие новых сообщений и открываем их def new_chat_available(): # проверяем наличие новых сообщений green_circle_pos = pygu.locateOnScreen("green_circle.JPG", confidence=.8) if (green_circle_pos): sleep(2) pygu.moveTo(green_circle_pos[0], green_circle_pos[1], duration=0.5) pygu.click() sleep(1) ok_button_pos = pygu.locateOnScreen("ok_button.JPG", confidence=.8) if (ok_button_pos): pygu.moveTo(ok_button_pos[0], ok_button_pos[1], duration=0.5) pygu.click() return 1 else: sleep(1) return 0 def read_last_message(): smily_paperclip_pos = pygu.locateOnScreen("smily_paperclip.JPG", confidence=.6) pygu.moveTo(smily_paperclip_pos[0], smily_paperclip_pos[1]) pygu.moveTo(smily_paperclip_pos[0] + 50, smily_paperclip_pos[1] - 35, duration=0.5) sleep(1) pygu.tripleClick() pygu.hotkey('ctrl', 'c') sleep(0.1) return (pyperclip.paste()) def get_response(incoming_message): if "CD_bot" in incoming_message: return default_message if "turn on light" in incoming_message: IO.output(40,1) # включаем светодиод return turn_on_light if "turn off light" in incoming_message: IO.output(40,0) # выключаем светодиод return turn_off_light else: return "" def send_message(message_content): for content in message_content: pygu.typewrite(content, interval=.02) pygu.hotkey('shift', 'enter') sleep(1) pygu.hotkey('enter') # клавиша Enter чтобы передать сообщение def new_message_available(): current_mouse_pos = pygu.position() pointer_color = pygu.pixel(current_mouse_pos[0], current_mouse_pos[1]) if (pointer_color == (255, 255, 255)): return 1 else: return 0 if (open_whatsapp()): # если страница whatsapp успешно открылась print("##Whatsapp page ready for automation##") while(1): if (new_chat_available() or new_message_available()): print("New chat or message is available") incoming_message = read_last_message() # считываем последнее принятое сообщение message_content = get_response(incoming_message) # решаем что ответить на это сообщение send_message(message_content) # передаем сообщение пользователю |