Raspberry Pi публикует MQTT-сообщения на ESP8266
В этом проекте вы создадите автономный веб-сервер на Raspberry Pi, который может переключать два светодиода на ESP8266 с помощью протокола MQTT. Вы можете заменить эти светодиоды любым выходом (например, реле, управляющим лампой).
Для создания веб-сервера вы будете использовать Python-микрофреймворк Flask. Вот общая схема системы:
Сначала посмотрите видеодемонстрацию
Рекомендуемые ресурсы:
Вам понадобится плата Raspberry Pi – прочитайте Лучшие стартовые наборы Raspberry Pi
Если вам нравится домашняя автоматизация и вы хотите построить полноценную систему домашней автоматизации, я рекомендую скачать мой курс по домашней автоматизации.
Базовая настройка Raspberry Pi
Прежде чем продолжить чтение этого проекта, убедитесь, что на вашем Raspberry Pi установлена операционная система Raspbian.
Вы можете прочитать мое руководство Начало работы с Raspberry Pi для установки Raspbian и выполнения базовой настройки.
Запуск и установка брокера Mosquitto
Raspberry Pi будет взаимодействовать с ESP8266 по протоколу MQTT. Если брокер Mosquitto установлен, вам нужно запустить брокер Mosquitto в фоновом режиме:
pi@raspberry:~ $ mosquitto -d
Веб-сервер на Python с Flask
Мы будем использовать Python-микрофреймворк Flask для превращения Raspberry Pi в веб-сервер.
Для установки Flask вам нужно установить pip. Выполните следующие команды для обновления вашего Pi и установки pip:
pi@raspberrypi ~ $ sudo apt-get update
pi@raspberrypi ~ $ sudo apt-get upgrade
pi@raspberrypi ~ $ sudo apt-get install python-pip python-flask
Затем используйте pip для установки Flask и его зависимостей:
pi@raspberrypi ~ $ sudo pip install flask
Установка Python Paho-MQTT
Пакет Paho-MQTT предоставляет клиентский класс, который позволяет приложениям подключаться к MQTT-брокеру для публикации сообщений, а также подписываться на топики и получать опубликованные сообщения. В этом примере веб-сервер на Python будет публиковать сообщения на ESP8266 для включения и выключения GPIO.
Для установки paho-mqtt выполните следующую команду:
pi@raspberrypi ~ $ sudo pip install paho-mqtt
Создание Python-скрипта
Это основной скрипт нашего приложения. Он настраивает веб-сервер, и при нажатии кнопок публикует MQTT-сообщение на ESP8266.
Чтобы все было организовано, начните с создания новой папки:
pi@raspberrypi ~ $ mkdir web-server
pi@raspberrypi ~ $ cd web-server
pi@raspberrypi:~/web-server $
Создайте новый файл с именем app.py.
pi@raspberrypi:~/web-server $ nano app.py
Скопируйте и вставьте следующий скрипт на ваш Raspberry Pi:
#
# Created by Rui Santos
# Complete project details: https://randomnerdtutorials.com
#
import paho.mqtt.client as mqtt
from flask import Flask, render_template, request
app = Flask(__name__)
mqttc=mqtt.Client()
mqttc.connect("localhost",1883,60)
mqttc.loop_start()
# Create a dictionary called pins to store the pin number, name, and pin state:
pins = {
4 : {'name' : 'GPIO 4', 'board' : 'esp8266', 'topic' : 'esp8266/4', 'state' : 'False'},
5 : {'name' : 'GPIO 5', 'board' : 'esp8266', 'topic' : 'esp8266/5', 'state' : 'False'}
}
# Put the pin dictionary into the template data dictionary:
templateData = {
'pins' : pins
}
@app.route("/")
def main():
# Pass the template data into the template main.html and return it to the user
return render_template('main.html', **templateData)
# The function below is executed when someone requests a URL with the pin number and action in it:
@app.route("/<board>/<changePin>/<action>")
def action(board, changePin, action):
# Convert the pin from the URL into an integer:
changePin = int(changePin)
# Get the device name for the pin being changed:
devicePin = pins[changePin]['name']
# If the action part of the URL is "on," execute the code indented below:
if action == "1" and board == 'esp8266':
mqttc.publish(pins[changePin]['topic'],"1")
pins[changePin]['state'] = 'True'
if action == "0" and board == 'esp8266':
mqttc.publish(pins[changePin]['topic'],"0")
pins[changePin]['state'] = 'False'
# Along with the pin dictionary, put the message into the template data dictionary:
templateData = {
'pins' : pins
}
return render_template('main.html', **templateData)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8181, debug=True)
Создание HTML-файла
Разделение HTML-тегов и вашего Python-скрипта – это способ поддерживать организованность вашего проекта.
Flask использует шаблонизатор Jinja2, который вы можете использовать для отправки динамических данных из вашего Python-скрипта в HTML-файл.
Создайте новую папку templates:
pi@raspberrypi:~/web-server $ mkdir templates
pi@raspberrypi:~/web-server $ cd templates
pi@raspberrypi:~/web-server/templates $
Создайте новый файл с именем main.html.
pi@raspberrypi:~/web-server/templates $ nano main.html
Скопируйте и вставьте следующий шаблон на ваш Pi:
<!DOCTYPE html>
<head>
<title>RPi Web Server</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>RPi Web Server - ESP8266 MQTT</h1>
{% for pin in pins %}
<h2>{{ pins[pin].name }}
{% if pins[pin].state == 'True' %}
is currently <strong>on</strong></h2><div class="row"><div class="col-md-2">
<a href="/esp8266/{{pin}}/0" class="btn btn-block btn-lg btn-default" role="button">Turn off</a></div></div>
{% else %}
is currently <strong>off</strong></h2><div class="row"><div class="col-md-2">
<a href="/esp8266/{{pin}}/1" class="btn btn-block btn-lg btn-primary" role="button">Turn on</a></div></div>
{% endif %}
{% endfor %}
</body>
</html>
Программирование ESP8266
Для взаимодействия ESP8266 с веб-сервером Raspberry Pi вам нужно установить библиотеку PubSubClient. Эта библиотека предоставляет клиент для простого обмена сообщениями publish/subscribe с сервером, поддерживающим MQTT (по сути, позволяет вашему ESP8266 общаться с веб-сервером на Python).
Установка библиотеки
1) Нажмите сюда, чтобы скачать библиотеку PubSubClient. У вас должна появиться папка .zip в папке Загрузки
2) Распакуйте папку .zip, и у вас должна получиться папка pubsubclient-master
3) Переименуйте папку из pubsubclient-master в pubsubclient
4) Переместите папку pubsubclient в папку libraries вашей установки Arduino IDE
5) Затем перезапустите Arduino IDE
Библиотека поставляется с рядом примеров скетчей. Смотрите File > Examples > PubSubClient в Arduino IDE.
Загрузка скетча
Наконец, вы можете загрузить полный скетч на ваш ESP8266 (замените на ваш SSID, пароль и IP-адрес RPi):
/*****
All the resources for this project:
https://randomnerdtutorials.com/
*****/
// Loading the ESP8266WiFi library and the PubSubClient library
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// Change the credentials below, so your ESP8266 connects to your router
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";
// Change the variable to your Raspberry Pi IP address, so it connects to your MQTT broker
const char* mqtt_server = "YOUR_RPi_IP_Address";
// Initializes the espClient
WiFiClient espClient;
PubSubClient client(espClient);
// Connect an LED to each GPIO of your ESP8266
const int ledGPIO5 = 5;
const int ledGPIO4 = 4;
// Don't change the function below. This functions connects your ESP8266 to your router
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(".");
}
Serial.println("");
Serial.print("WiFi connected - ESP IP address: ");
Serial.println(WiFi.localIP());
}
// This functions is executed when some device publishes a message to a topic that your ESP8266 is subscribed to
// Change the function below to add logic to your program, so when a device publishes a message to a topic that
// your ESP8266 is subscribed you can actually do something
void callback(String topic, byte* message, unsigned int length) {
Serial.print("Message arrived on topic: ");
Serial.print(topic);
Serial.print(". Message: ");
String messageTemp;
for (int i = 0; i < length; i++) {
Serial.print((char)message[i]);
messageTemp += (char)message[i];
}
Serial.println();
// Feel free to add more if statements to control more GPIOs with MQTT
// If a message is received on the topic home/office/esp1/gpio2, you check if the message is either 1 or 0. Turns the ESP GPIO according to the message
if(topic=="esp8266/4"){
Serial.print("Changing GPIO 4 to ");
if(messageTemp == "1"){
digitalWrite(ledGPIO4, HIGH);
Serial.print("On");
}
else if(messageTemp == "0"){
digitalWrite(ledGPIO4, LOW);
Serial.print("Off");
}
}
if(topic=="esp8266/5"){
Serial.print("Changing GPIO 5 to ");
if(messageTemp == "1"){
digitalWrite(ledGPIO5, HIGH);
Serial.print("On");
}
else if(messageTemp == "0"){
digitalWrite(ledGPIO5, LOW);
Serial.print("Off");
}
}
Serial.println();
}
// This functions reconnects your ESP8266 to your MQTT broker
// Change the function below if you want to subscribe to more topics with your ESP8266
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
/*
YOU NEED TO CHANGE THIS NEXT LINE, IF YOU'RE HAVING PROBLEMS WITH MQTT MULTIPLE CONNECTIONS
To change the ESP device ID, you will have to give a unique name to the ESP8266.
Here's how it looks like now:
if (client.connect("ESP8266Client")) {
If you want more devices connected to the MQTT broker, you can do it like this:
if (client.connect("ESPOffice")) {
Then, for the other ESP:
if (client.connect("ESPGarage")) {
That should solve your MQTT multiple connections problem
THE SECTION IN loop() function should match your device name
*/
if (client.connect("ESP8266Client")) {
Serial.println("connected");
// Subscribe or resubscribe to a topic
// You can subscribe to more topics (to control more LEDs in this example)
client.subscribe("esp8266/4");
client.subscribe("esp8266/5");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
// The setup function sets your ESP GPIOs to Outputs, starts the serial communication at a baud rate of 115200
// Sets your mqtt broker and sets the callback function
// The callback function is what receives messages and actually controls the LEDs
void setup() {
pinMode(ledGPIO4, OUTPUT);
pinMode(ledGPIO5, OUTPUT);
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
// For this project, you don't need to change anything in the loop function.
// Basically it ensures that you ESP is connected to your broker
void loop() {
if (!client.connected()) {
reconnect();
}
if(!client.loop())
/*
YOU NEED TO CHANGE THIS NEXT LINE, IF YOU'RE HAVING PROBLEMS WITH MQTT MULTIPLE CONNECTIONS
To change the ESP device ID, you will have to give a unique name to the ESP8266.
Here's how it looks like now:
client.connect("ESP8266Client");
If you want more devices connected to the MQTT broker, you can do it like this:
client.connect("ESPOffice");
Then, for the other ESP:
client.connect("ESPGarage");
That should solve your MQTT multiple connections problem
THE SECTION IN recionnect() function should match your device name
*/
client.connect("ESP8266Client");
}
Схема подключения
Схема подключения для этого проекта очень простая. Просто подключите два светодиода с двумя резисторами к вашему ESP8266, как показано на рисунке ниже.
Вы можете использовать ссылки выше или перейти непосредственно на MakerAdvisor.com/tools, чтобы найти все компоненты для ваших проектов по лучшей цене!
Запуск веб-сервера
Для запуска веб-сервера Raspberry Pi перейдите в папку, содержащую файл app.py:
pi@raspberrypi:~/web-server/templates $ cd ..
Затем выполните следующую команду:
pi@raspberrypi:~/web-server $ sudo python app.py
Ваш веб-сервер должен запуститься немедленно на порту :8181!
Демонстрация
Откройте адрес вашего Raspberry Pi в браузере, введя его IP-адрес, в моем случае: http://192.168.1.98:8181
Примечание: вы должны ввести ваш IP-адрес, за которым следует :8181
Вот видеодемонстрация работы веб-сервера:
Заключение
В следующей статье мы будем публиковать показания датчиков с ESP8266 на веб-сервер Python.
Нравится домашняя автоматизация? Узнайте больше о Node-RED, Raspberry Pi, ESP8266 и Arduino с моим курсом: Постройте систему домашней автоматизации за $100.
У вас есть вопросы? Оставьте комментарий ниже!
Спасибо за чтение. Если вам понравилась эта статья, возможно, вам понравятся и следующие, поэтому, пожалуйста, поддержите меня, подписавшись на мой блог.