Здравствуйте, коллеги в этом руководстве расскажу как при помощи Google Assistant и протокола mqtt управлять датчиками умного дома, на примере платы ESP8266 и светодиода. Также создадим свое приложение для Assistant с блэкджеком и php скриптами. Всех желающих прошу под кат.

Для этого всего нам понадобится контроллер ESP8266, либо другие контроллеры с подключением к интернету а также сервер c валидным ssl сертификатом (вместо валидного ssl можно использовать обратный proxy у которого таковой уже имеется) и MQTT сервер (broker).

Для интеграции с google assistant будем использовать сервис Google Actions и Dialogflow. Итак начнем.

image

Создание и настройка проекта


Google Action Console


Для начала нужно авторизоваться на сервисе и создать проект, выбрать язык и регион.

image

После нужно выбрать сферу применения. Я выбрал Kids&Family. Из чужого опыта скажу, что логически напрашивающаяся категория Smart Home работает корректно только с устройствами от Google, для проектов со своими датчиками для корректной работы лучше выбрать другую категорию.

image

Читаем и принимаем соглашения. В категории Quick setup переходим к пункту Decide how your Action is invoked. Придумываем как будут звать нашего бота и выбираем голос из доступных, сохраняем.

image

Переходим в вкладку Actions, добавляем действие Custom Intent

image

Dialogflow


После нажатия кнопки Build нас перенаправляет на ресурс Dialogflow, тоже авторизируемся и переходим к созданию проекта:

  1. Выбираем язык по умолчанию и часовой пояс.
  2. Переходим в вкладку Fulfillment включаем пункт Webhook. Здесь вы должны указать адрес скрипта (о том что это за скрипт, читайте далее) на который Dialogflow будет отсылаться POST запрос.

    image
  3. 3. Настройка команд и ответов.

    Вкладка intets имеет несколько стандартных заготовленных команд и ответов на них. В нашем случае нужно создать новую команду. Для этого нужно нажать на + во вкладке Intents. Придумать отображаемое имя команды и нажать сохранить.

image

Саму страницу можно условно разделить на три категории:

Training phrases — это слова, на которые assistant реагирует командой. Они могут быть разными для одной команды. Например слова посвети, вруби свет, включи лампу и т. п.

image

Action — само действие, или слово, которое будет понимать датчик, оно одно и конкретное.

Responses это ответы assistant после выполнения команды. Здесь просто поле для творчества.

image

Настройка хостинга


В качестве сервера приобрел самый дешевый (5$) дроплет и установил на него Debian 10.2. Какой вы хостинг выберете значение не имеет.

Настройка обратного proxy и DNS


Эту часть можно пропустить, если у вас есть хостинг с валидным сертификатом.

Сам сервис Cloudflare предлагает множество имен нижних уровней, потому если вы испытываете проблемы с выполнением пункта 4, возможно стоит в колонке content возле www***, https//www*** указать свой ip вместо дефолтного (*** это ваш домен).

Для взаимодействия с Dialogflow нужен SSL сертификат. Я не стал устанавливать его на сервер, вместо этого я использовал DNS proxy Cloudflare (бесплатный — basic). Для этого при настройке Cloudflare я добавил свое ранее приобретенное доменное имя и добавил к нему ip адрес своего сервера (колонка Content). Также добавил две A записи (на картинке это Value) в настройках провайдера имен. Стоит отметить, что добавление записи это не секундное дело и может занять до нескольких рабочих дней.

image

Установка программ


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.

image

Если этого не случилось проверьте корректно ли выполнялись команды, а также работает ли страница при не защищенном http соединении. Если все же работает возможно сервер слушает 80, а не 443 порт. Или на нем уже запущена какая то служба. Подробнее тут.

4. Установка Библиотеки Mosquitto для PHP

Устройства интернета вещей могут использовать разные протоколы для взаимодействия. Один из таких MQTT, который работает по принципу издатель-подписчик. В таком случае подписчики могут получать информацию от многих издателей. Но поскольку протокол понимает только определенные типы сообщений, для него нужен преобразователь (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.

image

image

Скрипт php
<?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 Mosquitto\Client(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 адрес своего сервера.

Скетч Arduino IDE
#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 — результат одинаковый. Главное, если вы тестируете с смартфона не забудь сказать: “Говорить с приложением ***”.

image

image