Здравствуйте, коллеги в этом руководстве расскажу как при помощи Google Assistant и протокола mqtt управлять датчиками умного дома, на примере платы ESP8266 и светодиода. Также создадим свое приложение для Assistant с блэкджеком и php скриптами. Всех желающих прошу под кат.
Для этого всего нам понадобится контроллер ESP8266, либо другие контроллеры с подключением к интернету а также сервер c валидным ssl сертификатом (вместо валидного ssl можно использовать обратный proxy у которого таковой уже имеется) и MQTT сервер (broker).
Для интеграции с google assistant будем использовать сервис Google Actions и Dialogflow. Итак начнем.
Создание и настройка проекта
Google Action Console
Для начала нужно авторизоваться на сервисе и создать проект, выбрать язык и регион.
После нужно выбрать сферу применения. Я выбрал Kids&Family. Из чужого опыта скажу, что логически напрашивающаяся категория Smart Home работает корректно только с устройствами от Google, для проектов со своими датчиками для корректной работы лучше выбрать другую категорию.
Читаем и принимаем соглашения. В категории Quick setup переходим к пункту Decide how your Action is invoked. Придумываем как будут звать нашего бота и выбираем голос из доступных, сохраняем.
Переходим в вкладку Actions, добавляем действие Custom Intent
Dialogflow
После нажатия кнопки Build нас перенаправляет на ресурс Dialogflow, тоже авторизируемся и переходим к созданию проекта:
1.Выбираем язык по умолчанию и часовой пояс.
2.Переходим в вкладку Fulfillment включаем пункт Webhook. Здесь вы должны указать адрес скрипта (о том что это за скрипт, читайте далее) на который Dialogflow будет отсылаться POST запрос.
3. Настройка команд и ответов
Вкладка intets имеет несколько стандартных заготовленых команд и ответов на них. В нашем случае нужно создать новую команду. Для этого нужно нажать на + во вкладке Intents. Придумать отображаемое имя команды и нажать сохранить.
Саму страницу можно условно разделить на три категории:
Training phrases — это слова, на которые assistant реагирует командой. Они могут быть разными для одной команды. Например слова посвети, вруби свет, включи лампу и т. п.
Action — само действие, или слово, которое будет понимать датчик, оно одно и конкретное.
Responses это ответы assistant после выполнения команды. Здесь просто поле для творчества.
Настройка хостинга
В качестве сервера приобрел самый дешевый (5$) дроплет и установил на него Debian 10.2. Какой вы
Настройка обратного proxy и DNS
Эту часть можно пропустить, если у вас есть
Сам сервис Cloudflare предлагает множество имен нижних уровней, потому если вы испытываете проблемы с выполнением пункта 4, возможно стоит в колонке content возле www***, https//www*** указать свой ip вместо дефолтного (*** это ваш домен).
Для взаимодействия с Dialogflow нужен SSL сертификат. Я не стал устанавливать его на сервер, вместо этого я использовал DNS proxy Cloudflare (бесплатный — basic). Для этого при настройке Cloudflare я добавил свое ранее приобретенное доменное имя и добавил к нему ip адрес своего сервера (колонка Content). Также добавил две A записи (на картинке это Value) в настройках провайдера имен. Стоит отметить, что добавление записи это не секундное дело и может занять до нескольких рабочих дней.
Установка программ
1.Первым делом после первого запуска сервера не забудьте обновить базу данных пакетов
apt update
, а потом обновить установленные пакеты
apt upgrade
2. После установим LAMP
Apache
apt install apache2
PHP/Mysql
apt-get install php libapache2-mod-php php-mcrypt php-mysql
.Добавьте адрес сервера в apache2.conf. Это можно выполнить командой nano /etc/apache2/apache2.conf указав в конце файла ServerName *** в конце вашего файла, где вместо звездочек нужно подставить ip сервера. Проверьте синтаксис и перезапустите службу Apach Подробнее тут.
После успешного выполнения действий описанных выше при вводе вашего доменного имени в строку браузера вы получите страницу приветствия Apache2.
Если этого не случилось проверьте корректно ли выполнялись команды, а также работает ли страница при не защищенном http соединении. Если все же работает возможно сервер слушает 80, а не 443 порт. Или на нем уже запущена какая то служба. Подробнее тут.
4.Установка Библиотеки Mosquitto для PHP
Устройства интернета вещей могут использовать разные протоколы для взаимодействия. Один из таких MQTT (https://habr.com/ru/post/463669/), который работает по принципу издатель-подписчик. В таком случае подписчики могут получать информацию от многих издателей. Но поскольку протокол понимает только определенные типы сообщений, для него нужен преобразователь (broker). на Вот его мы и настраиваем.
5.Если у вас не установлен PECL, установите его
apt install pecl
После становим брокер
pecl install Mosquitto-alpha
Затем добавьте extension = mosquitto.so к вашему php.ini. И не забудьте клиент
apt install mosquitto mosquitto-clients
Подробнее тут
Настройка php скрипта, подписка на topic
Собственно сам скрипт. Его назначение принимать post запрос от Dialogflow, вычленять из него action и передавать его как сообщение на брокер в тему, название которой указано в конце скрипта. Как вы назовете скрипт значения не имеет. Кстати это и есть скрипт, который мы указывали в вкладке Fulfillment. Поместите скрипт по адресу /var/www/html
Топики создаются подписчиками.Чтобы создать топик воспользуйтесь командой:
mosquitto_sub -h localhost - t /test/light
Вместо localhost вы можете задать любой другой адрес, или домен, где вы хотите создать издателя (pub)
Вместо /test/light вы можете задать любую тему. В нашем случае главное, чтобы она была указана в скрипте.
Сообщения создаются издателями. Чтобы создать сообщение можно воспользоваться командой.
mosquitto_pub -h localhost - t /test/light -m “light”
Но она нам не понадобится, поскольку нашим издателем (pub) будет наше приложение. Схема такая, когда наше приложение получает команду, оно отправляет запрос на наш скрипт. Скрипт на брокера, а брокер на подписчика (esp8266).
Проверять отправку сообщений мы будем через вкладку Test Action Console.
<?php
//Make sure that it is a POST request.
if(strcasecmp($_SERVER['REQUEST_METHOD'], 'POST') != 0){
throw new Exception('Request method must be POST!');
}
//Make sure that the content type of the POST request has been set to application/json
$contentType = isset($_SERVER["CONTENT_TYPE"]) ? trim($_SERVER["CONTENT_TYPE"]) : '';
if(strcasecmp($contentType, 'application/json') != 0){
throw new Exception('Content type must be: application/json');
}
//Receive the RAW post data.
$content = trim(file_get_contents("php://input"));
//Attempt to decode the incoming RAW post data from JSON.
$decoded = json_decode($content);
//file_put_contents($filename, $data);
var_dump($decoded);
echo $decoded->queryResult->action;
define('BROKER', 'localhost');
define('PORT', 1883);
define('CLIENT_ID', getmypid());
ити
$client = new MosquittoClient(CLIENT_ID);
$client->connect(BROKER, PORT, 60);
$message = $decoded->queryResult->action;
$client->publish('/test/light', $message, 0, false);
$client->loop();
?>
Прошивка ESP8266
Для прошивки будем использовать Arduino IDE. Если кто то будет устанавливать IDE впервые не забудьте про драйвер ch340. По дефолту в arduino єтой платі нет. В Файл>>Настройки вам нужно указать адрес дополнительніх плат: arduino.esp8266.com/stable/package_esp8266com_index.json. В Инструменты>>плата>>менеджер плат вам нужно установить пакет esp8266.
В скетче после const char* ssid вы должны указать название своей wi-fi сети. После const char* password ее пароль. После const char* mqtt_server указать ip адрес своего сервера.
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
const char* ssid = "***";
const char* password = "********";
const char* mqtt_server = "**.**.*.*";
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
int led = D5;
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) {
String msg="";
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
msg+=(char)payload[i];
}
Serial.println();
// Switch on the LED if an 1 was received as first character
// if ((char)payload[0] == '1') {
if (msg == "light") {
digitalWrite(led, HIGH); // Turn the LED on
} else {
digitalWrite(led, LOW); // Turn the LED off
}
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// ... and resubscribe
client.subscribe("/test/light");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup() {
pinMode(led, OUTPUT); // Initialize the led pin as an output
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
}
Результат
В результате, после компиляции скетча мы получаем приложение, которе интегрировано в google асистент и управляет датчиками. Вместо смартфона я использовал web приложение, но тестировал на Android — результат одинаковый. Главное, если вы тестируете с смартфона не забудь сказать: “Говорить с приложением ***”
Автор: Свердлюк Богдан