Нам понадобится:
- ESP8266
- 3 Сопротивления по 220 ом
- Сопротивление 4.7К
- 3 светодиода
- Dallas 18B20 сенсор температуры
- Arduino IDE установленное на ПК
- Android Studio установленное на ПК
Шаг 1 (настройка Arduino IDE):
Самое первое что нам нужно сделать это установить в Arduino IDE две библиотеки:
- OneWire
- DallasTemperature
На видео я показал где это можно сделать. После того как это сделано убедитесь что у вас также установлена поддержка плат ESP8266 и выбрана в разделе “Инструменты – Платы“. Если все выбрано то подключаем к ПК микроконтроллер ESP8266 и выбираем в “Инструменты – Порт” порт к которому подключен ESP8266.
Шаг 2 (копируем скетч в Arduino IDE):
#include <ESP8266WiFi.h>
#include <OneWire.h>
#include <DallasTemperature.h>
bool led1IsOn = false;
bool led2IsOn = false;
bool led3IsOn = false;
const int LED_0 = 16;
const int LED_1 = 5;
const int LED_2 = 2;
const int oneWireBus = 4;
const char* ssid = "";
const char* password = "";
float temperatureC = 0.0f;
// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(80);
OneWire oneWire(oneWireBus);
DallasTemperature sensors(&oneWire);
void setup() {
Serial.begin(115200);
pinMode(LED_0, OUTPUT);
pinMode(LED_1, OUTPUT);
pinMode(LED_2, OUTPUT);
delay(1000);
digitalWrite(LED_0, HIGH);
digitalWrite(LED_1, HIGH);
digitalWrite(LED_2, HIGH);
delay(1000);
digitalWrite(LED_0, LOW);
digitalWrite(LED_1, LOW);
digitalWrite(LED_2, LOW);
delay(10);
sensors.begin();
// Connect to WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
// Start the server
server.begin();
Serial.println("Server started");
// Print the IP address
Serial.println(WiFi.localIP());
}
void loop() {
// Check if a client has connected
sensors.requestTemperatures();
WiFiClient client = server.available();
if (!client) {
return;
}
// Wait until the client sends some data
Serial.println("new client");
while(!client.available()){
delay(1);
}
// Read the first line of the request
String req = client.readStringUntil('\r');
Serial.println(req);
// Match the request
controller(req, client);
client.flush();
// Prepare the response
String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
s += temperatureC;
// Send the response to the client
client.print(s);
delay(1);
Serial.println("Client disonnected");
// The client will actually be disconnected
// when the function returns and 'client' object is detroyed
}
void controller(String req, WiFiClient client){
if (req.indexOf("/temperature") != -1){
temperatureC = sensors.getTempCByIndex(0);
Serial.println("Showing temperature");
} else if(req.indexOf("/led1") != -1){
setLedState(LED_0, led1IsOn);
led1IsOn = !led1IsOn;
} else if(req.indexOf("/led2") != -1){
setLedState(LED_1, led2IsOn);
led2IsOn = !led2IsOn;
} else if(req.indexOf("/led3") != -1){
setLedState(LED_2, led3IsOn);
led3IsOn = !led3IsOn;
} else {
Serial.println("invalid request");
client.stop();
return;
}
}
void setLedState(int led, bool state){
if(!state){
digitalWrite(led, HIGH);
} else {
digitalWrite(led, LOW);}
}
Шаг 3 (Указываем ssid и password сети):
В самом начале скетча есть две переменные это ssid и password. В них нужно указать название вашей сети WiFi и пароль сети чтобы ESP8266 мог к ней подключится.
Шаг 4 (Загружаем скетч на ESP8266):
Загружаем скетч на микроконтроллер. Если все сделали правильно то после загрузки все 3 светодиода должны загореться и потухнуть.
Шаг 5 (Загружаем скетч на ESP8266):
Загружаем скетч на микроконтроллер. Если все сделали правильно то после загрузки все 3 светодиода должны загореться и потухнуть. А также открываем в Arduino IDE “Инструменты – Монитор порта” там увидим сообщение удалось подключится к сети или нет. Если удалось значит мы готовы для сборки схемы.
Шаг 7 (Создаем приложение):
MainActivity:
import android.content.SharedPreferences
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import com.neco_desarrollo.esp8266controller2.databinding.ActivityMainBinding
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.IOException
class MainActivity : AppCompatActivity() {
private lateinit var request: Request
private lateinit var binding: ActivityMainBinding
private lateinit var pref: SharedPreferences
private val client = OkHttpClient()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
pref = getSharedPreferences("MyPref", MODE_PRIVATE)
onClickSaveIp()
getIp()
binding.apply {
bLed1.setOnClickListener(onClickListener())
bLed2.setOnClickListener(onClickListener())
bLed3.setOnClickListener(onClickListener())
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.main_menu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if(item.itemId == R.id.sync) post("temperature")
return true
}
private fun onClickListener(): View.OnClickListener{
return View.OnClickListener {
when(it.id){
R.id.bLed1 -> { post("led1") }
R.id.bLed2 -> { post("led2") }
R.id.bLed3 -> { post("led3") }
}
}
}
private fun getIp() = with(binding){
val ip = pref.getString("ip", "")
if(ip != null){
if(ip.isNotEmpty()) edIp.setText(ip)
}
}
private fun onClickSaveIp() = with(binding){
bSave.setOnClickListener {
if(edIp.text.isNotEmpty())saveIp(edIp.text.toString())
}
}
private fun saveIp(ip: String){
val editor = pref.edit()
editor.putString("ip", ip)
editor.apply()
}
private fun post(post: String){
Thread{
request = Request.Builder().url("http://${binding.edIp.text}/$post").build()
try {
var response = client.newCall(request).execute()
if(response.isSuccessful){
val resultText = response.body()?.string()
runOnUiThread {
val temp = resultText + "Cº"
binding.tvTemp.text = temp
}
}
} catch (i: IOException){
}
}.start()
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/tvTemp"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:fontFamily="sans-serif-condensed-medium"
android:gravity="center"
android:text="0Cº"
android:textColor="@color/teal_700"
android:textSize="80sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/bLed3"
app:layout_constraintEnd_toEndOf="@+id/bSave"
app:layout_constraintHorizontal_bias="0.332"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintStart_toStartOf="@+id/bSave"
app:layout_constraintTop_toBottomOf="@+id/bSave" />
<EditText
android:id="@+id/edIp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:ems="10"
android:hint="Ip address"
android:inputType="textPersonName"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/bSave"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Save Ip"
app:layout_constraintEnd_toEndOf="@+id/edIp"
app:layout_constraintStart_toStartOf="@+id/edIp"
app:layout_constraintTop_toBottomOf="@+id/edIp" />
<Button
android:id="@+id/bLed1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:text="Led 1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/bLed2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="led 2"
app:layout_constraintBottom_toTopOf="@+id/bLed1"
app:layout_constraintEnd_toEndOf="@+id/bLed1"
app:layout_constraintStart_toStartOf="@+id/bLed1" />
<Button
android:id="@+id/bLed3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Led 3"
app:layout_constraintBottom_toTopOf="@+id/bLed2"
app:layout_constraintEnd_toEndOf="@+id/bLed2"
app:layout_constraintStart_toStartOf="@+id/bLed2" />
</androidx.constraintlayout.widget.ConstraintLayout>
main_menu.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/sync"
android:title="Sync"
android:icon="@drawable/ic_sync"
app:showAsAction="ifRoom"/>
</menu>
Библиотека OkHttp(добавить в build.gradle):
implementation 'com.squareup.okhttp3:okhttp:3.10.0' Permission(добавить в AndroidManifest.xml):
<uses-permission android:name="android.permission.INTERNET"/>
Доброго времнни суток Сергей,
Подскажите как отойти от локальной wi-fi сети, т.е. развернуть сервачок который будет через интернет принимать и отправлять статусы и команды из/в андроид приложение?
Подскажите как это гуглить?
Всё что я нахожу это статьи про mqtt серверы, но они платные и дорогие.
Вам нужен серый или белый IP адрес у провайдера, на роутере пробросить какой-нибудь нестандартный порт с внешнего адреса, который выдает провайдер, на внутренний адрес вашей платы wifi
Например яндекс пишет что у вас адрес 8.8.8.8, а у платы адрес 192.168.0.51
В роутере вам нужно пробросить порт скажем 85 на внутренний адрес 192.168.0.51 на уже стандарный порт http 80
При этом с внешнего адреса обращаться как http:\\8.8.8.8\led1:85
Провайдеры не всегда выдают серые адреса – который при каждом подключении новый, но по которому можно обратиться к вашему роутеру из интернета, часто сеть провайдера со своими адресами и тогда точно придется арендовать белый ip.
Есть ещё сервисы в которых можно прикрутить имя к вашему внешнему серому динамическому ip гуглить freeDns. Ну или купить доменное имя и прикрутить к своему арендованному белому ip, но это уже другая история.
Единственное, что не получится, так это простое копирование кода. Андроид Студио требует местами синхронизации, импортирования. B месте добавления иконки в файле main_menu.xml пришлось вручную указывать рисунок. Приложение запустилось, а вот скетч ещё не собирал.
Заработало на ESP32! Кроме датчика температуры, которого просто у меня нет. А светодиодики включает. Только нужно заменить первую строку счетча с #include на #include . И конечно установить требующиеся библиотеки.
ничего не получается почемуто, первый раз в андроидстудио.
как окно с рисованием меню достать? нажимаю на ActivityMainBinding(как в видео), и ничего не происходит.
Надо вам посмотреть видеоурок про работу с Binding. Сначала надо добавить в файл buildgradle(app) такую строку buildFeatures{viewBinding true}. Потом нажать справа вверху кнопку Sync Now. Так он включается. Это всё есть и в этом видео. Короче разбираться надо досконально.
Заработало не сразу в части ESP32.
Библиотеку пришлось поменять на WiFi.h
И не получался нормальный ответ ESP32 на запрос, т.е. светодиоды включались, а температура в ответ не приходила. При этом если браузером зайти на ESP по адресу скажем 192.168.0.51/led1 то пишет что сервер внезапно разорвал соединение(светодиод включается). Ну и в студии если в блоке catch выводить ошибку, тоже самое показывает.
Победить удалось убрав client.flush(); и строку ответа поменял на раздельные строки
client.println(“HTTP/1.1 200 OK”);
client.println(“Content-Type: text/html”);
client.println();
client.println(“25.4”);
почему то символы переноса /r/n не срабатывают Arduino IDE версии 2.0.1
Спасибо бро!!!
спасибо за подсказку
Просто убрал client.flush(); и показ температуры заработал.
До этого код try {} не запускался.
Здравствуйте! А есть возможность управления ESP через Android исключив роутер?
Есть, нужно создать точку доступа непосредственно на ESP и телефон будет подключен на прямую к МК.
Через блютус, вроде можно подключаться
Здравствуйте, возникла проблема при private lateinit var binding: ActivityMainBinding
выделяет красным, bilding включил
Пожалуйста помогите, возникла проблема при private lateinit var binding: ActivityMainBinding
выделяет красным, binding включил
Замените часть neco_desarrollo на свою в import com.neco_desarrollo.esp8266controller2.databinding.ActivityMainBinding
А где взять neco_desarrollo ?
А есть код Android studio, не на котлине, а на джаве?
Всем добра, как сделать так что бы температура постоянно обновлялась, а не по кнопке?
Да! У меня тот же вопрос. Как постоянным потоком сделать температуру?