{"id":460964,"date":"2025-05-25T21:00:13","date_gmt":"2025-05-25T21:00:13","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=460964"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=460964","title":{"rendered":"<span>ESP32-S3 BLE Keyboard<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a9f\/6c6\/012\/a9f6c6012335685ef9dcbd22470f70d9.jpg\" alt=\"USB-\u0441\u0432\u0438\u0441\u0442\u043e\u043a \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 \u0438\u0437 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430\" title=\"USB-\u0441\u0432\u0438\u0441\u0442\u043e\u043a \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 \u0438\u0437 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430\" width=\"4080\" height=\"3072\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/a9f\/6c6\/012\/a9f6c6012335685ef9dcbd22470f70d9.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a9f\/6c6\/012\/a9f6c6012335685ef9dcbd22470f70d9.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>USB-\u0441\u0432\u0438\u0441\u0442\u043e\u043a \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 \u0438\u0437 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u0418\u0434\u0435\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u0443 \u043c\u0435\u043d\u044f \u0434\u0430\u0432\u043d\u043e. \u0417\u0430\u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430 \u043f\u0430\u0440\u043e\u043b\u0435\u0439. \u041d\u0430\u0434\u043e\u0435\u043b\u043e \u043f\u0435\u0440\u0435\u043f\u0435\u0447\u0430\u0442\u044b\u0432\u0430\u0442\u044c 20-\u0441\u0438\u043c\u0432\u043e\u043b\u044c\u043d\u044b\u0435 \u043f\u0430\u0440\u043e\u043b\u0438 \u0438\u0437 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u043d\u043e\u0433\u043e KeyPass, \u0430 \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440, \u0433\u0434\u0435 \u043d\u0443\u0436\u043d\u043e \u0447\u0442\u043e-\u0442\u043e \u0432\u0432\u043e\u0434\u0438\u0442\u044c, \u0443\u0441\u0442\u0430\u043d\u0435\u0448\u044c \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c. \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043b, \u0447\u0442\u043e \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e\u0442, \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043b, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u044e\u0442. \u0412 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c, \u043d\u0435 \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u043b\u0438\u0441\u044c \u0440\u0430\u0437\u043c\u0435\u0440\u044b. \u0418\u043d\u043e\u0433\u0434\u0430 \u0446\u0435\u043d\u0430. \u0421 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u0442\u0435\u043b\u0435\u0444\u043e\u043d \u0441 \u043f\u0430\u0440\u043e\u043b\u044f\u043c\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u0441 \u0441\u043e\u0431\u043e\u0439. \u0410 \u0442\u0443\u0442 \u0435\u0449\u0451 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 DeepSeek.<br \/>TL;DR \u041f\u0440\u043e\u0441\u0442\u043e \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u043c\u0443\u0447\u0435\u043d\u0438\u0439. \u0412 \u043a\u043e\u043d\u0446\u0435 \u043f\u0440\u043e\u0448\u0438\u0432\u043a\u0430 \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 + Android-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u0425\u043e\u0442\u044f \u0438 \u043d\u0430 \u0441\u0442\u0430\u0434\u0438\u0438 \u00ab\u043a\u043e\u043d\u0446\u0435\u043f\u0442\u00bb.<\/p>\n<p>\u041e\u0434\u043d\u0430\u0436\u0434\u044b \u044f \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043b, \u0447\u0442\u043e \u0435\u0441\u0442\u044c \u0442\u0430\u043a\u0438\u0435 ESP32, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u043c\u0435\u044e\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 USB \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0438 \u044d\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c HID-\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430. \u0423 \u043d\u0438\u0445 \u0435\u0441\u0442\u044c bluetooth, \u0442\u043e \u0435\u0441\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0442\u043a\u043d\u0443\u0442\u044c \u0432 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440, \u043f\u0440\u0438\u043a\u0438\u043d\u0443\u0442\u044c\u0441\u044f \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u043e\u0439, \u0438 \u0441 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0442\u0435\u043a\u0441\u0442. \u0420\u0430\u0437\u043c\u0435\u0440 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0441\u043e\u0432\u0441\u0435\u043c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439, \u043f\u043e\u0432\u0435\u0441\u0438\u043b \u043d\u0430 \u043a\u043b\u044e\u0447\u0438, \u2014 \u0438 \u043e\u043d \u0432\u0441\u0435\u0433\u0434\u0430 \u0441 \u0442\u043e\u0431\u043e\u0439.<br \/>\u041a\u0443\u043f\u0438\u043b \u0443 \u043a\u0438\u0442\u0430\u0439\u0446\u0435\u0432 ESP32-C3. \u041f\u043e\u043a\u0430 \u043e\u043d\u043e \u0435\u0445\u0430\u043b\u043e, \u0443\u0437\u043d\u0430\u043b, \u0447\u0442\u043e USB HID \u0442\u0430\u043c \u043d\u0435\u0442. \u041a\u0443\u043f\u0438\u043b ESP32-S3 zero mini micro nano (\u0438\u0445 \u043f\u043e-\u0440\u0430\u0437\u043d\u043e\u043c\u0443 \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442) \u2014 \u044d\u0442\u043e \u0434\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u0440\u0435\u0448\u0438\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u043c\u043e\u0439 \u043f\u0443\u0442\u044c.<br \/>\u0412 \u043e\u0431\u0449\u0435\u043c, \u0438\u0437 \u0436\u0435\u043b\u0435\u0437\u0430 \u044d\u0442\u043e \u0432\u0441\u0451. \u0414\u0430\u043b\u044c\u0448\u0435 \u043f\u0440\u043e\u0448\u0438\u0432\u043a\u0430 \u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<br \/>\u0412\u0430\u0439\u0431-\u043a\u043e\u0434\u0438\u043d\u0433 \u044d\u0442\u043e \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043c\u043e\u0436\u0435\u0448\u044c, \u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u2014 \u043d\u0435\u0442. \u0423\u0434\u043e\u0431\u043d\u043e, \u0447\u0442\u043e \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0438\u0437\u0443\u0447\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440,  BLE (\u044f \u0441 \u043d\u0438\u043c \u0434\u043e \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u043b\u0441\u044f), Kotlin &#8212; \u043d\u0438 \u0440\u0430\u0437\u0443 \u043d\u0435 \u043f\u0438\u0441\u0430\u043b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430, \u0438 \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u043d\u0435 \u0443\u043c\u0435\u044e. \u042f \u043d\u0435 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442.<br \/>\u042f \u043f\u043e\u0447\u0435\u043c\u0443-\u0442\u043e \u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0432 \u0432 \u0447\u0430\u0442 DeepSeek \u00ab\u041d\u0430\u043f\u0438\u0448\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u0434\u043b\u044f ESP32-S3 \u0434\u043b\u044f \u044d\u043c\u0443\u043b\u044f\u0446\u0438\u0438 USB HID \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b. ESP32-S3 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0442\u0435\u043a\u0441\u0442 \u0447\u0435\u0440\u0435\u0437 BLE \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 USB. \u041d\u0430\u043f\u0438\u0448\u0438 Android-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0442\u0435\u043a\u0441\u0442 \u043f\u043e BLE \u0438\u0437 \u0431\u0443\u0444\u0435\u0440\u0430 \u043e\u0431\u043c\u0435\u043d\u0430\u00bb \u043f\u043e\u043b\u0443\u0447\u0443 \u0432\u0441\u0451 \u0438 \u0441\u0440\u0430\u0437\u0443. \u0421\u0440\u0430\u0437\u0443 \u043d\u0435 \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e \u043d\u0438\u0447\u0435\u0433\u043e \ud83d\ude41<br \/>\u041f\u043e\u043a\u0430 \u0435\u0445\u0430\u043b \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440, \u044f \u0437\u0430\u043d\u044f\u043b\u0441\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0434\u043b\u044f \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430.<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/345\/0b8\/4d3\/3450b84d33baf16eed96224304a7064a.png\" width=\"1554\" height=\"234\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/345\/0b8\/4d3\/3450b84d33baf16eed96224304a7064a.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/345\/0b8\/4d3\/3450b84d33baf16eed96224304a7064a.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u0412\u043e\u0442 \u043f\u0435\u0440\u0435\u0447\u0435\u043d\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u0448\u0438\u0431\u043e\u043a:<br \/><code>Unresolved reference \u2018R'<br \/>unable to instantiate activity componentinfo didnt find class mainactivivty<br \/>resource style\/AppTheme not found<br \/>Attempt to invoke virtual method 'java.lang.String android.provider.MiuiSettings$SettingsCloudData$CloudData.getString(java.lang.String, java.lang.String)' on a null object reference<\/code><br \/>\u041f\u043e \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0447\u0430\u0441\u0442\u0438, \u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043b \u0442\u0435\u043a\u0441\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 \u0438\u0437 IDE \u0432 \u0447\u0430\u0442 DeepSeek. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u043b \u00ab\u0438\u0441\u043f\u0440\u0430\u0432\u044c \u043e\u0448\u0438\u0431\u043a\u0443\u00bb \u0438\u043b\u0438 \u00ab\u043d\u0430\u0439\u0434\u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u00bb, \u043f\u043e\u0442\u043e\u043c \u0437\u0430\u0431\u0438\u043b \u0434\u0430\u0436\u0435 \u043d\u0430 \u044d\u0442\u043e. \u041d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u044c \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0430, \u043a\u0430\u043a \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043d\u0430 \u0436\u0435 \u0438 \u0441\u0434\u0435\u043b\u0430\u043b\u0430. \u0421\u0442\u0440\u0430\u043d\u043d\u043e\u0435 \u043e\u0449\u0443\u0449\u0435\u043d\u0438\u0435. \u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e, \u044f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0442\u0451\u043c\u043d\u0443\u044e \u0442\u0435\u043c\u0443 \u0438 \u043f\u0435\u0440\u0435\u0434\u0432\u0438\u043d\u0443\u043b \u043a\u043d\u043e\u043f\u043e\u0447\u043a\u0443:<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u043a\u0440\u044b\u0442\u044b\u0439 \u0442\u0435\u043a\u0441\u0442<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/19d\/d56\/460\/19dd564600e51dbe84a48e0b175fc767.jpg\" width=\"1080\" height=\"2316\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/19d\/d56\/460\/19dd564600e51dbe84a48e0b175fc767.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/19d\/d56\/460\/19dd564600e51dbe84a48e0b175fc767.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>MainActivity.kt<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>package com.mc.bleapp  import android.annotation.SuppressLint import android.bluetooth.* import android.bluetooth.le.ScanCallback import android.bluetooth.le.ScanResult import android.content.ClipboardManager import android.content.Context import android.content.pm.PackageManager import android.os.Bundle import android.os.Handler import android.os.Looper import android.util.Log import android.widget.Button import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import java.util.*  class MainActivity : AppCompatActivity() {      private lateinit var statusText: TextView     private lateinit var logText: TextView     private lateinit var sendButton: Button     private lateinit var reconnectButton: Button      private val DEVICE_NAME = \"Secure BLE Keyboard\"     private val SERVICE_UUID = UUID.fromString(\"4fafc201-1fb5-459e-8fcc-c5c9c331914b\")     private val INPUT_CHAR_UUID = UUID.fromString(\"beb5483e-36e1-4688-b7f5-ea07361b26a8\")      private var bluetoothAdapter: BluetoothAdapter? = null     private var bluetoothGatt: BluetoothGatt? = null     private var inputCharacteristic: BluetoothGattCharacteristic? = null     private var isConnected = false      private val handler = Handler(Looper.getMainLooper())     private val PERMISSIONS = arrayOf(         android.Manifest.permission.ACCESS_FINE_LOCATION,         android.Manifest.permission.BLUETOOTH,         android.Manifest.permission.BLUETOOTH_ADMIN,         android.Manifest.permission.BLUETOOTH_CONNECT,         android.Manifest.permission.BLUETOOTH_SCAN     )      override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContentView(R.layout.activity_main)          statusText = findViewById(R.id.statusText)         logText = findViewById(R.id.logText)         sendButton = findViewById(R.id.sendButton)         reconnectButton = findViewById(R.id.reconnectButton)          reconnectButton.setOnClickListener { reconnect() }         sendButton.setOnClickListener { sendClipboardContent() }         checkPermissions()     }      private fun checkPermissions() {         if (PERMISSIONS.any { ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED }) {             ActivityCompat.requestPermissions(this, PERMISSIONS, 0)         } else {             initializeBluetooth()         }     }      @SuppressLint(\"MissingPermission\")     private fun initializeBluetooth() {         bluetoothAdapter = BluetoothAdapter.getDefaultAdapter().takeIf { it.isEnabled }             ?: run {                 Toast.makeText(this, \"Enable Bluetooth\", Toast.LENGTH_LONG).show()                 return             }         startDeviceScan()     }      @SuppressLint(\"MissingPermission\")     private fun startDeviceScan() {         statusText.text = \"Scanning...\"         bluetoothAdapter?.bluetoothLeScanner?.startScan(scanCallback)         handler.postDelayed({ stopScan() }, 10000)     }      private fun stopScan() {         bluetoothAdapter?.bluetoothLeScanner?.stopScan(scanCallback)     }      private val scanCallback = object : ScanCallback() {         @SuppressLint(\"MissingPermission\")         override fun onScanResult(callbackType: Int, result: ScanResult) {             if (result.device.name == DEVICE_NAME) {                 stopScan()                 connectToDevice(result.device)             }         }     }      @SuppressLint(\"MissingPermission\")     private fun connectToDevice(device: BluetoothDevice) {         statusText.text = \"Connecting...\"         bluetoothGatt = device.connectGatt(this, false, gattCallback)     }      private val gattCallback = object : BluetoothGattCallback() {         @SuppressLint(\"MissingPermission\")         override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {             when (newState) {                 BluetoothProfile.STATE_CONNECTED -&gt; {                     isConnected = true                     handler.post {                         statusText.text = \"Connected\"                         log(\"Connected\")                     }                     gatt.discoverServices()                 }                 BluetoothProfile.STATE_DISCONNECTED -&gt; {                     isConnected = false                     handler.post {                         statusText.text = \"Disconnected\"                         log(\"Connection lost\")                     }                 }             }         }          override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {             if (status == BluetoothGatt.GATT_SUCCESS) {                 inputCharacteristic = gatt.getService(SERVICE_UUID)                     ?.getCharacteristic(INPUT_CHAR_UUID)                  handler.post {                     if (inputCharacteristic != null) {                         log(\"Service found\")                         sendButton.isEnabled = true                     } else {                         log(\"Service not found\")                     }                 }             }         }     }      private fun sendClipboardContent() {         if (!isConnected) {             Toast.makeText(this, \"Not connected\", Toast.LENGTH_SHORT).show()             return         }          val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager         clipboard.primaryClip?.getItemAt(0)?.text?.toString()?.let { text -&gt;             if (text.isNotEmpty()) sendData(text)         } ?: Toast.makeText(this, \"Clipboard empty\", Toast.LENGTH_SHORT).show()     }      @SuppressLint(\"MissingPermission\")     private fun sendData(text: String) {         inputCharacteristic?.let {             it.value = text.toByteArray()             bluetoothGatt?.writeCharacteristic(it)             log(\"Sent: ${text.take(20)}...\")         } ?: log(\"Characteristic null\")     }      private fun log(message: String) {         logText.append(\"\\n$message\")     }      @SuppressLint(\"MissingPermission\")     private fun reconnect() {         log(\"Reconnect...\")         bluetoothGatt?.disconnect()         bluetoothGatt?.close()         bluetoothGatt = null         inputCharacteristic = null         sendButton.isEnabled = false         startDeviceScan()     }      override fun onDestroy() {         super.onDestroy()         bluetoothGatt?.disconnect()         bluetoothGatt?.close()     } }<\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>activity_main.xml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>&lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt; &lt;LinearLayout     xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"     android:layout_width=\"match_parent\"     android:layout_height=\"match_parent\"     android:orientation=\"vertical\"     android:padding=\"16dp\"&gt;      &lt;TextView         android:id=\"@+id\/statusText\"         android:layout_marginTop=\"20dp\"         android:layout_width=\"match_parent\"         android:layout_height=\"wrap_content\"         android:text=\"Status: Disconnected\"         android:textSize=\"18sp\"\/&gt;      &lt;TextView         android:layout_width=\"match_parent\"         android:layout_height=\"wrap_content\"         android:text=\"Log:\"         android:textSize=\"16sp\"\/&gt;      &lt;ScrollView         android:layout_width=\"match_parent\"         android:layout_height=\"0dp\"         android:layout_weight=\"1\"&gt;          &lt;TextView             android:id=\"@+id\/logText\"             android:layout_width=\"match_parent\"             android:layout_height=\"wrap_content\"             android:textSize=\"14sp\"\/&gt;     &lt;\/ScrollView&gt;      &lt;Button         android:id=\"@+id\/reconnectButton\"         android:layout_width=\"match_parent\"         android:layout_height=\"wrap_content\"         android:text=\"\u041f\u0435\u0440\u0435\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f\"\/&gt;      &lt;Button         android:id=\"@+id\/sendButton\"         android:layout_width=\"match_parent\"         android:layout_height=\"87dp\"         android:enabled=\"false\"         android:text=\"\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c\"\/&gt; &lt;\/LinearLayout&gt;<\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>AndroidManifest.xml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>&lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt; &lt;manifest xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"     package=\"com.mc.bleapp\"&gt;      &lt;uses-permission android:name=\"android.permission.BLUETOOTH\"\/&gt;     &lt;uses-permission android:name=\"android.permission.BLUETOOTH_CONNECT\"\/&gt;     &lt;uses-permission android:name=\"android.permission.BLUETOOTH_SCAN\"\/&gt;     &lt;uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"\/&gt;     &lt;uses-permission android:name=\"android.permission.BLUETOOTH_PRIVILEGED\"\/&gt;     &lt;uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"\/&gt;      &lt;application         android:theme=\"@style\/Theme.AppCompat.DayNight.DarkActionBar\"         android:allowBackup=\"true\"         android:icon=\"@mipmap\/ic_launcher\"         android:label=\"BLE Keyboard\"&gt;          &lt;activity             android:name=\".MainActivity\"             android:exported=\"true\"&gt;             &lt;intent-filter&gt;                 &lt;action android:name=\"android.intent.action.MAIN\" \/&gt;                 &lt;category android:name=\"android.intent.category.LAUNCHER\" \/&gt;             &lt;\/intent-filter&gt;         &lt;\/activity&gt;      &lt;\/application&gt; &lt;\/manifest&gt;<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u043f\u0440\u0438\u0435\u0445\u0430\u043b \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440, \u0438 \u0432\u043e\u0442 \u0441 \u043d\u0438\u043c \u044f \u0431\u0438\u043b\u0441\u044f \u0434\u0432\u0435 \u043d\u0435\u0434\u0435\u043b\u0438.<br \/>\u041f\u043e\u0441\u043b\u0435 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043e\u043a \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u043e\u043d\u043e \u043f\u0440\u043e\u0448\u0438\u043b\u043e\u0441\u044c, \u043d\u043e \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e.<br \/>\u041f\u0435\u0440\u0432\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 &#8212;<br \/><code>BT_GATT: gatts_write_attr_perm_check - GATT_INSUF_AUTHENTICATION,handle 002a, perm 0020<\/code><br \/>\u041e\u043d\u0430 \u0441\u044b\u043f\u0430\u043b\u0430\u0441\u044c \u0432 \u043b\u043e\u0433 \u043f\u0440\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0442\u0435\u043a\u0441\u0442 \u0441 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430. \u042f \u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u0440\u0430\u0437 \u043f\u0440\u043e \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e &#8212; \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0438\u043d-\u043a\u043e\u0434 \u043f\u0440\u0438 bluetooth-\u0441\u043f\u0430\u0440\u0438\u0432\u0430\u043d\u0438\u0438. \u041a \u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u043c\u0435\u043d\u0442\u0443 \u044f \u0443\u0436\u0435 \u043f\u043e\u043d\u044f\u043b, \u0447\u0442\u043e, \u0445\u043e\u0442\u044c \u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u044c \u0438 \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u0442 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442, \u043b\u0443\u0447\u0448\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u0447\u0430\u0442 \u0434\u043b\u044f \u043d\u043e\u0432\u043e\u0439 \u0438\u0434\u0435\u0438.<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/29b\/b12\/4f4\/29bb124f4853140316063c68a64ce45e.png\" width=\"1512\" height=\"122\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/29b\/b12\/4f4\/29bb124f4853140316063c68a64ce45e.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/29b\/b12\/4f4\/29bb124f4853140316063c68a64ce45e.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u0431\u044b\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0438 \u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u044f:<br \/><code>error: lvalue required as unary '&amp;' operand -&gt; \u0417\u0430\u043c\u0435\u043d\u0438\u043b\u0438 #define PIN_CODE \u043d\u0430 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u043d\u0443\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e const uint32_t PIN_CODE<br \/>error: conversion from 'String' to non-scalar type 'std::string' {aka 'std::_<em>cxx11::basic_string'} requested -&gt; std::string value = pCharacteristic-&gt;getValue().c_str(); <\/em><\/code><\/p>\n<p>\u0418 \u0435\u0449\u0451 \u0448\u0442\u0443\u043a \u043f\u044f\u0442\u043e\u043a. <\/p>\n<p>\u041f\u0440\u0438\u0447\u0451\u043c, \u044d\u0442\u0438 \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u044e\u0442\u0441\u044f \u0438\u0437 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438 \u0432 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044e. \u0418\u0441\u043f\u0440\u0430\u0432\u0438\u043b \u043e\u0434\u043d\u0443 &#8212; \u0432\u0435\u0440\u043d\u0443\u043b \u0434\u0440\u0443\u0433\u0443\u044e. \u0418\u0441\u043f\u0440\u0430\u0432\u0438\u043b \u0434\u0440\u0443\u0433\u0443\u044e, \u043d\u043e\u0432\u0430\u044f \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044f &#8212; \u043e\u043f\u0430, \u0432\u0435\u0440\u043d\u0443\u043b\u0430\u0441\u044c \u043f\u0435\u0440\u0432\u0430\u044f. \u042f \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043b \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u043a\u0441\u0442 \u043e\u0448\u0438\u0431\u043a\u0438, \u0437\u0430\u0442\u0435\u043c \u043f\u0435\u0440\u0435\u0448\u0451\u043b \u043a \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0443 \u0442\u0435\u043a\u0441\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 + \u0441\u0442\u0440\u043e\u043a\u0430 \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439 &#8212; \u043e\u0442\u0432\u0435\u0442\u044b \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u043b\u0438\u0441\u044c. \u0412 \u043b\u044e\u0431\u043e\u043c \u043a\u043e\u0434\u0438\u043d\u0433\u0435 \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u043e\u043f\u044b\u0442 =) <\/p>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435, \u043a\u043e\u0433\u0434\u0430 \u0441\u043f\u0430\u0440\u0438\u0432\u0430\u043d\u0438\u0435 \u0441 \u043f\u0438\u043d-\u043a\u043e\u0434\u043e\u043c \u0441\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c, \u044f \u043f\u0435\u0440\u0435\u0448\u0451\u043b \u043a \u0438\u043c\u0438\u0442\u0430\u0446\u0438\u0438 HID-\u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b. \u0422\u0443\u0442 \u0432\u0440\u043e\u0434\u0435 \u043a\u0430\u043a \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u043d\u0435 \u0441\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c. \u041d\u0443 \u044d\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430. <\/p>\n<p><code>error: 'BLEProperties' has not been declared BLEProperties::PROPERTY_NOTIFY -&gt; \u041e\u0448\u0438\u0431\u043a\u0430 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u0438\u0437-\u0437\u0430 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0435\u0433\u043e \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430. \u041d\u0443\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c BLECharacteristic::PROPERTY* \u0432\u043c\u0435\u0441\u0442\u043e BLEProperties::.<\/code><br \/>\u0422\u0430\u043a \u0437\u0430\u0447\u0435\u043c \u0442\u044b, \u0441\u043e\u0431\u0430\u043a\u0430, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0448\u044c \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0439 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441???<br \/><code>error: 'class BLEAdvertising' has no member named \u2018setMinSecurity' -&gt; \u0423\u0434\u0430\u043b\u0435\u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0430 pAdvertising-&gt;setMinSecurity() - \u044d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438<\/code><br \/>\u041d\u0443 \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435. \u041f\u043e\u0447\u0435\u043c\u0443 \u0441\u0440\u0430\u0437\u0443 \u043d\u0435 \u043f\u0438\u0441\u0430\u0442\u044c \u0431\u0435\u0437 \u043e\u0448\u0438\u0431\u043e\u043a? \u042d\u0442\u043e \u0447\u0442\u043e, \u0438\u043c\u0438\u0442\u0430\u0446\u0438\u044f \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u0430?<br \/>\u041a \u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u043c\u0435\u043d\u0442\u0443 \u044f \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u044e \u043f\u0440\u043e \u0442\u043e, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0432 \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b \u0441 \u043a\u043e\u0434\u043e\u043c. \u0421\u043e\u0445\u0440\u0430\u043d\u0438\u043b \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043a\u043e\u0434, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0431\u044b\u043b \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0440\u043e\u0441 \u043f\u0438\u043d-\u043a\u043e\u0434\u0430, \u0438 \u043c\u044b \u043d\u0430\u0447\u0430\u043b\u0438 \u0441\u043d\u0430\u0447\u0430\u043b\u0430:<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8c2\/b82\/f01\/8c2b82f01b80d6263ee4d302eeb8405d.png\" width=\"1524\" height=\"244\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/8c2\/b82\/f01\/8c2b82f01b80d6263ee4d302eeb8405d.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8c2\/b82\/f01\/8c2b82f01b80d6263ee4d302eeb8405d.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u041d\u0443 \u0438 \u0441\u043d\u043e\u0432\u0430 \u0437\u0430\u043d\u043e\u0432\u043e:<br \/><code>error: conversion from 'String' to non-scalar type \u2018std::string'<\/code><br \/>\u0412\u0440\u0435\u043c\u0435\u043d\u0430\u043c\u0438 \u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u043f\u0440\u0438\u0434\u0443\u043c\u044b\u0432\u0430\u043b\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043c\u0435\u0442\u043e\u0434 <code>asciiToHID<\/code> \u2014 \u0435\u0439 \u0442\u0430\u043a \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u043a\u043e\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442 \u0432 HID-\u0441\u0438\u043c\u0432\u043e\u043b\u044b. \u041e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u00ab\u0432 \u043a\u043b\u0430\u0441\u0441\u0435 SecurityCallbacks \u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b \u0432\u0441\u0435 \u0447\u0438\u0441\u0442\u043e \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0438\u0437 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 BLESecurityCallbacks\u00bb. \u0418 \u043c\u043d\u043e\u0433\u043e \u0435\u0449\u0451 \u0432\u0441\u044f\u043a\u043e\u0433\u043e, \u0447\u0435\u0440\u0435\u0437 \u0447\u0442\u043e \u043c\u044b \u0441 \u043d\u0435\u0439 \u043f\u0440\u043e\u0448\u043b\u0438.<\/p>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435, \u044f \u043d\u0435 \u0434\u043e\u0431\u0438\u043b\u0441\u044f \u0447\u0435\u0433\u043e \u0445\u043e\u0442\u0435\u043b \u0432 \u0447\u0438\u0441\u0442\u043e\u043c \u0432\u0438\u0434\u0435. \u0412 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430\u0445 \u044f\u0434\u0440\u043e ESP \u043f\u0430\u0434\u0430\u043b\u043e \u0432 \u043f\u0430\u043d\u0438\u043a\u0435, \u0447\u0430\u0441\u0442\u043e \u043f\u043e\u0441\u043b\u0435 \u0432\u043d\u0435\u0441\u0435\u043d\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043d\u0435 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u043b\u043e \u043f\u0438\u043d-\u043a\u043e\u0434 \u0438 \u043d\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u044f\u043b\u043e\u0441\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e. \u0423 \u043c\u0435\u043d\u044f \u0431\u044b\u043b\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0438\u0437 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430 \u0442\u0435\u043a\u0441\u0442 \u0438 \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b, \u043d\u043e \u043d\u0438\u043a\u0430\u043a \u043d\u0435 \u0445\u043e\u0447\u0435\u0442 \u0432 USB HID. \u042f \u0432\u0437\u044f\u043b \u043a\u043e\u0434 \u0438\u0437 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0434\u043b\u044f \u0438\u043c\u0438\u0442\u0430\u0446\u0438\u0438 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b \u043e\u0442 DeepSeek \u0438 \u043f\u043e\u043f\u0440\u043e\u0441\u0438\u043b \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0432\u043e\u0434 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <a href=\"http:\/\/Keyboard.press\" rel=\"noopener noreferrer nofollow\">Keyboard.press<\/a>:<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0438\u043c\u0435\u0440<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>#include &lt;USB.h&gt; #include &lt;USBHIDKeyboard.h&gt;  USBHIDKeyboard Keyboard;  void setup() {   USB.begin();   Keyboard.begin();   delay(2000); \/\/ \u0414\u0430\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f USB   Keyboard.press(KEY_LEFT_CTRL);   Keyboard.press(KEY_ALT);   Keyboard.press('t');   Keyboard.releaseAll(); \/\/ \u041e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 Ctrl+Alt+T (\u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b \u0432 Linux) }  void loop() {}<\/code><\/pre>\n<\/div>\n<\/details>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2f9\/c99\/f24\/2f9c99f2471bab438cba095693d4beb0.png\" width=\"1524\" height=\"288\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/2f9\/c99\/f24\/2f9c99f2471bab438cba095693d4beb0.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/2f9\/c99\/f24\/2f9c99f2471bab438cba095693d4beb0.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u0422\u0443\u0442 \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e \u0441 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0440\u0430\u0437\u0430. \u041d\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043b\u0430\u0442\u0438\u043d\u0438\u0446\u0430, \u0446\u0438\u0444\u0440\u044b \u0438 \u0441\u043f\u0435\u0446\u0441\u0438\u043c\u0432\u043e\u043b\u044b. \u0412\u043f\u0440\u043e\u0447\u0435\u043c, \u043c\u043d\u0435 \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e.<\/p>\n<details class=\"spoiler\">\n<summary>worked_hid_keyboard.ino<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>#include &lt;BLEDevice.h&gt; #include &lt;BLEUtils.h&gt; #include &lt;BLEServer.h&gt; #include &lt;BLE2902.h&gt; #include &lt;USB.h&gt; #include &lt;USBHIDKeyboard.h&gt;  USBHIDKeyboard Keyboard;  #define DEVICE_NAME \"Secure BLE Keyboard\" #define SERVICE_UUID        \"4fafc201-1fb5-459e-8fcc-c5c9c331914b\" #define CHARACTERISTIC_UUID \"beb5483e-36e1-4688-b7f5-ea07361b26a8\" const uint32_t PIN_CODE = 123456;  bool deviceConnected = false;  class CharacteristicCallbacks : public BLECharacteristicCallbacks {     void onWrite(BLECharacteristic *pCharacteristic) override {         String arduinoString = pCharacteristic-&gt;getValue().c_str();          std::string value(arduinoString.c_str());                  if (!value.empty()) {             Serial.print(\"Received: \");             Serial.println(value.c_str());                          \/\/ \u041e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u0442\u0435\u043a\u0441\u0442\u0430 \u0447\u0435\u0440\u0435\u0437 USB HID             for (char c : value) {                 Keyboard.press(c); \/\/ \u041d\u0430\u0436\u0430\u0442\u044c \u043a\u043b\u0430\u0432\u0438\u0448\u0443                 delay(10);         \/\/ \u041a\u043e\u0440\u043e\u0442\u043a\u0430\u044f \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0430                 Keyboard.release(c); \/\/ \u041e\u0442\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043a\u043b\u0430\u0432\u0438\u0448\u0443             }         }     } };  class ServerCallbacks: public BLEServerCallbacks {     void onConnect(BLEServer* pServer) override {         deviceConnected = true;         Serial.println(\"Device connected\");     };      void onDisconnect(BLEServer* pServer) override {         deviceConnected = false;         Serial.println(\"Device disconnected\");         pServer-&gt;startAdvertising();     } };  class SecurityCallbacks: public BLESecurityCallbacks {     bool onConfirmPIN(uint32_t pass_key) override {         Serial.print(\"Confirm PIN: \");         Serial.println(pass_key);         return (pass_key == PIN_CODE);     }      void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl) override {         if(cmpl.success) {             Serial.println(\"Authentication success\");         } else {             Serial.println(\"Authentication failed\");         }     }      uint32_t onPassKeyRequest() override {         return PIN_CODE;     }      void onPassKeyNotify(uint32_t pass_key) override {         Serial.print(\"PassKey Notify: \");         Serial.println(pass_key);     }      bool onSecurityRequest() override {         return true;     } };  void setup() {     Serial.begin(115200);     USB.begin();     Keyboard.begin();     delay(2000); \/\/ \u0414\u0430\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u0434\u043b\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f USB     BLEDevice::init(DEVICE_NAME);     BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT);          BLEServer *pServer = BLEDevice::createServer();     pServer-&gt;setCallbacks(new ServerCallbacks());          BLESecurity *pSecurity = new BLESecurity();     pSecurity-&gt;setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND);     pSecurity-&gt;setCapability(ESP_IO_CAP_OUT);     pSecurity-&gt;setInitEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);     BLEDevice::setSecurityCallbacks(new SecurityCallbacks());      esp_ble_gap_set_security_param(         ESP_BLE_SM_SET_STATIC_PASSKEY,         const_cast&lt;uint32_t*&gt;(reinterpret_cast&lt;const uint32_t*&gt;(&amp;PIN_CODE)),         sizeof(PIN_CODE)     );      BLEService *pService = pServer-&gt;createService(SERVICE_UUID);     BLECharacteristic *pCharacteristic = pService-&gt;createCharacteristic(         CHARACTERISTIC_UUID,         BLECharacteristic::PROPERTY_READ |         BLECharacteristic::PROPERTY_WRITE     );      \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445     pCharacteristic-&gt;setCallbacks(new CharacteristicCallbacks());          pCharacteristic-&gt;setValue(\"Hello World\");     pCharacteristic-&gt;addDescriptor(new BLE2902());     pService-&gt;start();      BLEAdvertising *pAdvertising = pServer-&gt;getAdvertising();     pAdvertising-&gt;addServiceUUID(SERVICE_UUID);     pAdvertising-&gt;start(); }  void loop() {     delay(1000); }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043c\u0438\u0433\u0430\u043d\u0438\u0435 \u0441\u0432\u0435\u0442\u043e\u0434\u0438\u043e\u0434\u043e\u043c \u0438 \u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0440\u043f\u0443\u0441 (\u044f \u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0449\u0438\u043a \u043d\u0435 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439, \u0443\u043c\u0435\u044e \u0442\u043e\u043b\u044c\u043a\u043e \u0432 SketchUp).<br \/>\u0418\u0442\u043e\u0433\u043e:<\/p>\n<ul>\n<li>\n<p>\u0432\u0430\u0439\u0431-\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u0443 \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043f\u043e\u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u043e\u043c. \u041f\u0440\u0430\u0432\u0438\u043b \u043a\u043e\u0434, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u043b \u043d\u0443\u0436\u043d\u043e\u0435, \u0443\u0431\u0438\u0440\u0430\u043b \u043b\u0438\u0448\u043d\u0435\u0435. \u0415\u0441\u043b\u0438 \u0431 \u044f \u0431\u044b\u043b \u0443\u0441\u043b\u043e\u0432\u043d\u044b\u043c \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u0449\u0438\u043a\u043e\u043c, \u0438 DeepSeek \u0431\u044b \u0434\u0435\u043b\u0430\u043b \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u0438 \u0441\u0445\u0435\u043c &#8212; \u044f \u0431\u044b \u043d\u0435 \u0441\u043c\u043e\u0433 \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c;<\/p>\n<\/li>\n<li>\n<p>\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e, \u043b\u0443\u0447\u0448\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0448\u0430\u0436\u043e\u0447\u043a\u0430\u043c\u0438, \u0430 \u043d\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0446\u0435\u043b\u0438\u043a\u043e\u043c. \u041e\u0434\u0438\u043d \u0448\u0430\u0436\u043e\u0447\u0435\u043a &#8212; \u043e\u0434\u0438\u043d \u0437\u0430\u043f\u0440\u043e\u0441;<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0438\u0439 \u043a\u043e\u0434 \u0432 \u0444\u0430\u0439\u043b \u0438 \u043f\u0440\u0438\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u044c \u043a \u0437\u0430\u043f\u0440\u043e\u0441\u0443 &#8212; \u044d\u0442\u043e \u043f\u0440\u044f\u043c \u0437\u0434\u043e\u0440\u043e\u0432\u043e, \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u0431\u044b\u043b\u043e \u043f\u0440\u043e\u0440\u044b\u0432\u043e\u043c;<\/p>\n<\/li>\n<li>\n<p>\u0441 Android-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u0445\u043e\u0440\u043e\u0448\u043e, \u044f \u0432 \u044d\u0442\u043e\u043c \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u043e\u043b\u044c \u0431\u044b\u043b. \u0422\u0435\u043f\u0435\u0440\u044c \u0443\u043c\u0435\u044e \u043a\u043d\u043e\u043f\u043a\u0443 \u043f\u043e \u044d\u043a\u0440\u0430\u043d\u0443 \u0434\u0432\u0438\u0433\u0430\u0442\u044c.<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u0430 \u0432\u0435\u0441\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0443\u0448\u043b\u043e 2 \u043d\u0435\u0434\u0435\u043b\u0438 \u043c\u0435\u0436\u0434\u0443 \u0434\u0435\u043b\u043e\u043c. \u0427\u0438\u0441\u0442\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0447\u0430\u0441\u0430 2-3. \u042d\u0442\u043e, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0431\u044b\u0441\u0442\u0440\u0435\u0435, \u043d\u0435\u0436\u0435\u043b\u0438 \u044f \u0431\u044b \u0447\u0438\u0442\u0430\u043b \u0434\u043e\u043a\u0438 \u0438 \u043f\u0438\u0441\u0430\u043b \u043a\u043e\u0434 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7aa\/4d6\/4c2\/7aa4d64c2c615b610bf8f12774d4405c.jpg\" width=\"4080\" height=\"3072\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/7aa\/4d6\/4c2\/7aa4d64c2c615b610bf8f12774d4405c.jpg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7aa\/4d6\/4c2\/7aa4d64c2c615b610bf8f12774d4405c.jpg 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p><a href=\"https:\/\/drive.google.com\/drive\/folders\/1zFxzrz0QtOuRhmeJQWPL4AHrEKBH6fUr?usp=drive_link\" rel=\"noopener noreferrer nofollow\">\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 Google Drive \u0441 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0430\u043c\u0438, apk \u0438 stl \u0434\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u0445\u043e\u0447\u0435\u0442 \u0442\u0430\u043a \u0436\u0435, \u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043b\u0435\u043d\u044c.<\/a><\/p>\n<p>\u0412 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 \u043d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u0438 \u0443\u0447\u0430\u0441\u0442\u0438\u044f \u043d\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u043b\u0438, \u0432\u0441\u0451 \u0441\u0430\u043c =)<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/912690\/\"> https:\/\/habr.com\/ru\/articles\/912690\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\">\n<div><figcaption>USB-\u0441\u0432\u0438\u0441\u0442\u043e\u043a \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 \u0438\u0437 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u0418\u0434\u0435\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u0443 \u043c\u0435\u043d\u044f \u0434\u0430\u0432\u043d\u043e. \u0417\u0430\u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430 \u043f\u0430\u0440\u043e\u043b\u0435\u0439. \u041d\u0430\u0434\u043e\u0435\u043b\u043e \u043f\u0435\u0440\u0435\u043f\u0435\u0447\u0430\u0442\u044b\u0432\u0430\u0442\u044c 20-\u0441\u0438\u043c\u0432\u043e\u043b\u044c\u043d\u044b\u0435 \u043f\u0430\u0440\u043e\u043b\u0438 \u0438\u0437 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u043d\u043e\u0433\u043e KeyPass, \u0430 \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440, \u0433\u0434\u0435 \u043d\u0443\u0436\u043d\u043e \u0447\u0442\u043e-\u0442\u043e \u0432\u0432\u043e\u0434\u0438\u0442\u044c, \u0443\u0441\u0442\u0430\u043d\u0435\u0448\u044c \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c. \u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043b, \u0447\u0442\u043e \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e\u0442, \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043b, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u044e\u0442. \u0412 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c, \u043d\u0435 \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u043b\u0438\u0441\u044c \u0440\u0430\u0437\u043c\u0435\u0440\u044b. \u0418\u043d\u043e\u0433\u0434\u0430 \u0446\u0435\u043d\u0430. \u0421 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b, \u0442\u0435\u043b\u0435\u0444\u043e\u043d \u0441 \u043f\u0430\u0440\u043e\u043b\u044f\u043c\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u0441 \u0441\u043e\u0431\u043e\u0439. \u0410 \u0442\u0443\u0442 \u0435\u0449\u0451 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u044b\u0439 DeepSeek.<br \/>TL;DR \u041f\u0440\u043e\u0441\u0442\u043e \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u043c\u0443\u0447\u0435\u043d\u0438\u0439. \u0412 \u043a\u043e\u043d\u0446\u0435 \u043f\u0440\u043e\u0448\u0438\u0432\u043a\u0430 \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 + Android-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u0425\u043e\u0442\u044f \u0438 \u043d\u0430 \u0441\u0442\u0430\u0434\u0438\u0438 \u00ab\u043a\u043e\u043d\u0446\u0435\u043f\u0442\u00bb.<\/p>\n<p>\u041e\u0434\u043d\u0430\u0436\u0434\u044b \u044f \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043b, \u0447\u0442\u043e \u0435\u0441\u0442\u044c \u0442\u0430\u043a\u0438\u0435 ESP32, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u043c\u0435\u044e\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 USB \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0438 \u044d\u043c\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c HID-\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430. \u0423 \u043d\u0438\u0445 \u0435\u0441\u0442\u044c bluetooth, \u0442\u043e \u0435\u0441\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0442\u043a\u043d\u0443\u0442\u044c \u0432 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440, \u043f\u0440\u0438\u043a\u0438\u043d\u0443\u0442\u044c\u0441\u044f \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u043e\u0439, \u0438 \u0441 \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0442\u0435\u043a\u0441\u0442. \u0420\u0430\u0437\u043c\u0435\u0440 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0441\u043e\u0432\u0441\u0435\u043c \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0439, \u043f\u043e\u0432\u0435\u0441\u0438\u043b \u043d\u0430 \u043a\u043b\u044e\u0447\u0438, \u2014 \u0438 \u043e\u043d \u0432\u0441\u0435\u0433\u0434\u0430 \u0441 \u0442\u043e\u0431\u043e\u0439.<br \/>\u041a\u0443\u043f\u0438\u043b \u0443 \u043a\u0438\u0442\u0430\u0439\u0446\u0435\u0432 ESP32-C3. \u041f\u043e\u043a\u0430 \u043e\u043d\u043e \u0435\u0445\u0430\u043b\u043e, \u0443\u0437\u043d\u0430\u043b, \u0447\u0442\u043e USB HID \u0442\u0430\u043c \u043d\u0435\u0442. \u041a\u0443\u043f\u0438\u043b ESP32-S3 zero mini micro nano (\u0438\u0445 \u043f\u043e-\u0440\u0430\u0437\u043d\u043e\u043c\u0443 \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442) \u2014 \u044d\u0442\u043e \u0434\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u0440\u0435\u0448\u0438\u0442 \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u043c\u043e\u0439 \u043f\u0443\u0442\u044c.<br \/>\u0412 \u043e\u0431\u0449\u0435\u043c, \u0438\u0437 \u0436\u0435\u043b\u0435\u0437\u0430 \u044d\u0442\u043e \u0432\u0441\u0451. \u0414\u0430\u043b\u044c\u0448\u0435 \u043f\u0440\u043e\u0448\u0438\u0432\u043a\u0430 \u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<br \/>\u0412\u0430\u0439\u0431-\u043a\u043e\u0434\u0438\u043d\u0433 \u044d\u0442\u043e \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043c\u043e\u0436\u0435\u0448\u044c, \u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u2014 \u043d\u0435\u0442. \u0423\u0434\u043e\u0431\u043d\u043e, \u0447\u0442\u043e \u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0438\u0437\u0443\u0447\u0430\u0442\u044c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440,  BLE (\u044f \u0441 \u043d\u0438\u043c \u0434\u043e \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u043b\u0441\u044f), Kotlin &#8212; \u043d\u0438 \u0440\u0430\u0437\u0443 \u043d\u0435 \u043f\u0438\u0441\u0430\u043b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430, \u0438 \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u043d\u0435 \u0443\u043c\u0435\u044e. \u042f \u043d\u0435 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442.<br \/>\u042f \u043f\u043e\u0447\u0435\u043c\u0443-\u0442\u043e \u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0432 \u0432 \u0447\u0430\u0442 DeepSeek \u00ab\u041d\u0430\u043f\u0438\u0448\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u0434\u043b\u044f ESP32-S3 \u0434\u043b\u044f \u044d\u043c\u0443\u043b\u044f\u0446\u0438\u0438 USB HID \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b. ESP32-S3 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0442\u0435\u043a\u0441\u0442 \u0447\u0435\u0440\u0435\u0437 BLE \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 USB. \u041d\u0430\u043f\u0438\u0448\u0438 Android-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0442\u0435\u043a\u0441\u0442 \u043f\u043e BLE \u0438\u0437 \u0431\u0443\u0444\u0435\u0440\u0430 \u043e\u0431\u043c\u0435\u043d\u0430\u00bb \u043f\u043e\u043b\u0443\u0447\u0443 \u0432\u0441\u0451 \u0438 \u0441\u0440\u0430\u0437\u0443. \u0421\u0440\u0430\u0437\u0443 \u043d\u0435 \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e \u043d\u0438\u0447\u0435\u0433\u043e \ud83d\ude41<br \/>\u041f\u043e\u043a\u0430 \u0435\u0445\u0430\u043b \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440, \u044f \u0437\u0430\u043d\u044f\u043b\u0441\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0434\u043b\u044f \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0430.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u0412\u043e\u0442 \u043f\u0435\u0440\u0435\u0447\u0435\u043d\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u0448\u0438\u0431\u043e\u043a:<br \/><code>Unresolved reference \u2018R'<br \/>unable to instantiate activity componentinfo didnt find class mainactivivty<br \/>resource style\/AppTheme not found<br \/>Attempt to invoke virtual method 'java.lang.String android.provider.MiuiSettings$SettingsCloudData$CloudData.getString(java.lang.String, java.lang.String)' on a null object reference<\/code><br \/>\u041f\u043e \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0447\u0430\u0441\u0442\u0438, \u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043b \u0442\u0435\u043a\u0441\u0442 \u043e\u0448\u0438\u0431\u043a\u0438 \u0438\u0437 IDE \u0432 \u0447\u0430\u0442 DeepSeek. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u043b \u00ab\u0438\u0441\u043f\u0440\u0430\u0432\u044c \u043e\u0448\u0438\u0431\u043a\u0443\u00bb \u0438\u043b\u0438 \u00ab\u043d\u0430\u0439\u0434\u0438 \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u00bb, \u043f\u043e\u0442\u043e\u043c \u0437\u0430\u0431\u0438\u043b \u0434\u0430\u0436\u0435 \u043d\u0430 \u044d\u0442\u043e. \u041d\u0435\u0439\u0440\u043e\u0441\u0435\u0442\u044c \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0430, \u043a\u0430\u043a \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043e\u0448\u0438\u0431\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043d\u0430 \u0436\u0435 \u0438 \u0441\u0434\u0435\u043b\u0430\u043b\u0430. \u0421\u0442\u0440\u0430\u043d\u043d\u043e\u0435 \u043e\u0449\u0443\u0449\u0435\u043d\u0438\u0435. \u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e, \u044f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0442\u0451\u043c\u043d\u0443\u044e \u0442\u0435\u043c\u0443 \u0438 \u043f\u0435\u0440\u0435\u0434\u0432\u0438\u043d\u0443\u043b \u043a\u043d\u043e\u043f\u043e\u0447\u043a\u0443:<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u043a\u0440\u044b\u0442\u044b\u0439 \u0442\u0435\u043a\u0441\u0442<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><\/figure>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>MainActivity.kt<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>package com.mc.bleapp  import android.annotation.SuppressLint import android.bluetooth.* import android.bluetooth.le.ScanCallback import android.bluetooth.le.ScanResult import android.content.ClipboardManager import android.content.Context import android.content.pm.PackageManager import android.os.Bundle import android.os.Handler import android.os.Looper import android.util.Log import android.widget.Button import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import java.util.*  class MainActivity : AppCompatActivity() {      private lateinit var statusText: TextView     private lateinit var logText: TextView     private lateinit var sendButton: Button     private lateinit var reconnectButton: Button      private val DEVICE_NAME = \"Secure BLE Keyboard\"     private val SERVICE_UUID = UUID.fromString(\"4fafc201-1fb5-459e-8fcc-c5c9c331914b\")     private val INPUT_CHAR_UUID = UUID.fromString(\"beb5483e-36e1-4688-b7f5-ea07361b26a8\")      private var bluetoothAdapter: BluetoothAdapter? = null     private var bluetoothGatt: BluetoothGatt? = null     private var inputCharacteristic: BluetoothGattCharacteristic? = null     private var isConnected = false      private val handler = Handler(Looper.getMainLooper())     private val PERMISSIONS = arrayOf(         android.Manifest.permission.ACCESS_FINE_LOCATION,         android.Manifest.permission.BLUETOOTH,         android.Manifest.permission.BLUETOOTH_ADMIN,         android.Manifest.permission.BLUETOOTH_CONNECT,         android.Manifest.permission.BLUETOOTH_SCAN     )      override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContentView(R.layout.activity_main)          statusText = findViewById(R.id.statusText)         logText = findViewById(R.id.logText)         sendButton = findViewById(R.id.sendButton)         reconnectButton = findViewById(R.id.reconnectButton)          reconnectButton.setOnClickListener { reconnect() }         sendButton.setOnClickListener { sendClipboardContent() }         checkPermissions()     }      private fun checkPermissions() {         if (PERMISSIONS.any { ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED }) {             ActivityCompat.requestPermissions(this, PERMISSIONS, 0)         } else {             initializeBluetooth()         }     }      @SuppressLint(\"MissingPermission\")     private fun initializeBluetooth() {         bluetoothAdapter = BluetoothAdapter.getDefaultAdapter().takeIf { it.isEnabled }             ?: run {                 Toast.makeText(this, \"Enable Bluetooth\", Toast.LENGTH_LONG).show()                 return             }         startDeviceScan()     }      @SuppressLint(\"MissingPermission\")     private fun startDeviceScan() {         statusText.text = \"Scanning...\"         bluetoothAdapter?.bluetoothLeScanner?.startScan(scanCallback)         handler.postDelayed({ stopScan() }, 10000)     }      private fun stopScan() {         bluetoothAdapter?.bluetoothLeScanner?.stopScan(scanCallback)     }      private val scanCallback = object : ScanCallback() {         @SuppressLint(\"MissingPermission\")         override fun onScanResult(callbackType: Int, result: ScanResult) {             if (result.device.name == DEVICE_NAME) {                 stopScan()                 connectToDevice(result.device)             }         }     }      @SuppressLint(\"MissingPermission\")     private fun connectToDevice(device: BluetoothDevice) {         statusText.text = \"Connecting...\"         bluetoothGatt = device.connectGatt(this, false, gattCallback)     }      private val gattCallback = object : BluetoothGattCallback() {         @SuppressLint(\"MissingPermission\")         override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {             when (newState) {                 BluetoothProfile.STATE_CONNECTED -&gt; {                     isConnected = true                     handler.post {                         statusText.text = \"Connected\"                         log(\"Connected\")                     }                     gatt.discoverServices()                 }                 BluetoothProfile.STATE_DISCONNECTED -&gt; {                     isConnected = false                     handler.post {                         statusText.text = \"Disconnected\"                         log(\"Connection lost\")                     }                 }             }         }          override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {             if (status == BluetoothGatt.GATT_SUCCESS) {                 inputCharacteristic = gatt.getService(SERVICE_UUID)                     ?.getCharacteristic(INPUT_CHAR_UUID)                  handler.post {                     if (inputCharacteristic != null) {                         log(\"Service found\")                         sendButton.isEnabled = true                     } else {                         log(\"Service not found\")                     }                 }             }         }     }      private fun sendClipboardContent() {         if (!isConnected) {             Toast.makeText(this, \"Not connected\", Toast.LENGTH_SHORT).show()             return         }          val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager         clipboard.primaryClip?.getItemAt(0)?.text?.toString()?.let { text -&gt;             if (text.isNotEmpty()) sendData(text)         } ?: Toast.makeText(this, \"Clipboard empty\", Toast.LENGTH_SHORT).show()     }      @SuppressLint(\"MissingPermission\")     private fun sendData(text: String) {         inputCharacteristic?.let {             it.value = text.toByteArray()             bluetoothGatt?.writeCharacteristic(it)             log(\"Sent: ${text.take(20)}...\")         } ?: log(\"Characteristic null\")     }      private fun log(message: String) {         logText.append(\"\\n$message\")     }      @SuppressLint(\"MissingPermission\")     private fun reconnect() {         log(\"Reconnect...\")         bluetoothGatt?.disconnect()         bluetoothGatt?.close()         bluetoothGatt = null         inputCharacteristic = null         sendButton.isEnabled = false         startDeviceScan()     }      override fun onDestroy() {         super.onDestroy()         bluetoothGatt?.disconnect()         bluetoothGatt?.close()     } }<\/code><\/pre>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>activity_main.xml<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>&lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt; &lt;LinearLayout     xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"     android:layout_width=\"match_parent\"     android:layout_height=\"match_parent\"     android:orientation=\"vertical\"     android:padding=\"16dp\"&gt;      &lt;TextView         android:id=\"@+id\/statusText\"         android:layout_marginTop=\"20dp\"         android:layout_width=\"match_parent\"         android:layout_height=\"wrap_content\"         android:text=\"Status: Disconnected\"         android:textSize=\"18sp\"\/&gt;      &lt;TextView         android:layout_width=\"match_parent\"         android:layout_height=\"wrap_content\"         android:text=\"Log:\"         android:textSize=\"16sp\"\/&gt;      &lt;ScrollView         android:layout_width=\"match_parent\"         android:layout_height=\"0dp\"         android:layout_weight=\"1\"&gt;          &lt;TextView             android:id=\"@+id\/logText\"             android:layout_width=\"match_parent\"             android:layout_height=\"wrap_content\"             android:textSize=\"14sp\"\/&gt;     &lt;\/ScrollView&gt;      &lt;Button         android:id=\"@+id\/reconnectButton\"         android:layout_width=\"match_parent\"        <\/code><\/pre>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-460964","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/460964","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=460964"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/460964\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=460964"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=460964"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=460964"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}