Нам понадобится:
- 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, не на котлине, а на джаве?
Всем добра, как сделать так что бы температура постоянно обновлялась, а не по кнопке?
Да! У меня тот же вопрос. Как постоянным потоком сделать температуру?