{"id":360434,"date":"2024-05-21T00:53:12","date_gmt":"2024-05-21T00:53:12","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=360434"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-05-21T00:53:12","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=360434","title":{"rendered":"<span>\u041a\u0430\u043a \u044f \u0440\u0435\u0432\u0435\u0440\u0441-\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u0438\u043b \u043a\u0438\u0442\u0430\u0439\u0441\u043a\u0438\u0439 \u0431\u043b\u044e\u0442\u0443\u0437 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440<\/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<h2>\u0421 \u0447\u0435\u0433\u043e \u0432\u0441\u0435 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c<\/h2>\n<p>\u041c\u044b \u0441 \u0434\u0440\u0443\u0437\u044c\u044f\u043c\u0438 \u043a\u0443\u043f\u0438\u043b\u0438 \u043b\u0435\u0434 \u043b\u0435\u043d\u0442\u0443 \u0441 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u043f\u043e \u0431\u043b\u044e\u0442\u0443\u0437\u0443 \u0438 \u043f\u043e\u0432\u0435\u0441\u0438\u043b\u0438 \u0435\u0451 \u0432 \u0437\u0430\u043b\u0435. \u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0431\u044b\u043b\u0430 \u043f\u0440\u0438\u043a\u043e\u043b\u044c\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0446\u0432\u0435\u0442\u043e\u043c\u0443\u0437\u044b\u043a\u0438, \u043d\u043e \u043e\u043d\u0430 \u0431\u044b\u043b\u0430 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u0430. \u0422\u0430\u043a \u0447\u0442\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0451 \u0441\u0430\u043c\u043e\u043c\u0443.<\/p>\n<h2>\u0428\u0430\u0433\u0438 \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/h2>\n<ul>\n<li>\n<p>\u041d\u0430\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u0432\u043e\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0431\u043b\u044e\u0442\u0443\u0437 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440<\/p>\n<\/li>\n<li>\n<p>\u0410\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0430\u0443\u0434\u0438\u043e\u043f\u043e\u0442\u043e\u043a, \u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u0440\u0435\u0437\u043a\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0431\u0438\u0442\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043a\u0440\u0435\u0441\u0442\u0438\u0442\u044c \u0434\u0432\u0430 \u0441\u043a\u0440\u0438\u043f\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0431\u0435\u0440\u0442\u043a\u0443 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b<\/p>\n<\/li>\n<\/ul>\n<h2>\u041a\u0430\u043a \u043f\u043e\u043d\u044f\u0442\u044c \u0447\u0442\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u0430 \u0431\u043b\u044e\u0442\u0443\u0437 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440?<\/h2>\n<p>\u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u043b\u0435\u0434 \u043b\u0435\u043d\u0442\u044b \u0447\u0435\u0440\u0435\u0437 \u0431\u043b\u044e\u0442\u0443\u0437. \u041d\u0430 \u043a\u0430\u0436\u0434\u0443\u044e \u043a\u043d\u043e\u043f\u043a\u0443 \u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0435\u043a\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441. \u041d\u0430\u043c \u043d\u0430\u0434\u043e &#171;\u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0438\u0442\u044c&#187; \u0435\u0433\u043e \u0438 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u0442\u044c.<\/p>\n<figure class=\"float bordered full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/982\/534\/825\/982534825b6445ef67a5c70bbc07cf56.png\" alt=\"\u0421\u043a\u0440\u0438\u043d\u0448\u043e\u0442 \u0438\u0437 MohuanLED\" title=\"\u0421\u043a\u0440\u0438\u043d\u0448\u043e\u0442 \u0438\u0437 MohuanLED\" width=\"606\" height=\"1280\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/982\/534\/825\/982534825b6445ef67a5c70bbc07cf56.png\"\/><\/p>\n<div><figcaption>\u0421\u043a\u0440\u0438\u043d\u0448\u043e\u0442 \u0438\u0437 MohuanLED<\/figcaption><\/div>\n<\/figure>\n<\/p>\n<h2>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435<\/h2>\n<p>\u0427\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u043b\u043e\u0433\u0430\u0445 &#8212; \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u0432\u044b\u0442\u0430\u0449\u0438\u0442\u044c \u043c\u0430\u043a \u0430\u0434\u0440\u0435\u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430. <br \/>\u0418\u0434\u0435\u043c \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0431\u043b\u044e\u0442\u0443\u0437\u0430, \u0438\u0449\u0435\u043c \u043b\u0435\u0434 \u043b\u0435\u043d\u0442\u0443 \u0438 \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u043c\u0430\u043a \u0430\u0434\u0440\u0435\u0441:<\/p>\n<figure class=\"float full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/dab\/b6a\/792\/dabb6a792cbff711fcfb277d2346a437.png\" width=\"606\" height=\"1280\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/dab\/b6a\/792\/dabb6a792cbff711fcfb277d2346a437.png\"\/><\/figure>\n<\/p>\n<p>\u041f\u043e\u0440\u0430 \u0434\u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c \u043b\u043e\u0433\u0438! <br \/>\u0412 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0445 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u043c \u043f\u0443\u043d\u043a\u0442 &#171;Enable Bluetooth HCI snoop log&#187;<\/p>\n<figure class=\"float full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7c6\/f8f\/cf9\/7c6f8fcf9064981c92e4cbdc03e792de.png\" width=\"606\" height=\"1280\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/7c6\/f8f\/cf9\/7c6f8fcf9064981c92e4cbdc03e792de.png\"\/><\/figure>\n<\/p>\n<p>\u041f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0431\u043b\u044e\u0442\u0443\u0437, \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0435 \u0431\u043b\u044e\u0442\u0443\u0437 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0431\u0443\u0434\u0443\u0442 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f.<\/p>\n<h2>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043b\u043e\u0433\u043e\u0432<\/h2>\n<p>\u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e \u0432\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u044c \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0444\u0430\u0439\u043b \u0441 \u043b\u043e\u0433\u0430\u043c\u0438, \u044d\u0442\u043e \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u0434\u0435\u043b\u0430\u0442\u044c \u043e\u043a\u043e\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u0443\u0442\u044f\u043c\u0438.<\/p>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u0442\u0435\u043b\u0435\u0444\u043e\u043d \u043a \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0443, \u043f\u043e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 adb \u043d\u0430 \u043f\u043a \u0438 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u043e\u0442\u043b\u0430\u0434\u043a\u0443 \u043f\u043e \u044e\u0441\u0431 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0434\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u00ab\u0431\u0430\u0433\u0440\u0435\u043f\u043e\u0440\u0442\u00bb\u00a0\u2014 \u044d\u0442\u043e \u0437\u0438\u043f \u0430\u0440\u0445\u0438\u0432 \u0441\u00a0\u043b\u043e\u0433\u0430\u043c\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b. \u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u0434\u043b\u044f\u00a0\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438: adb bugreport btsnoop_hci.log. <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0437\u0438\u043f \u0430\u0440\u0445\u0438\u0432 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043e \u043b\u043e\u0433\u0430\u0445, \u0432\u044b\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u043c \u0435\u0433\u043e \u043f\u043e \u0438\u043c\u0435\u043d\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c \u0432 \u0432\u044b\u0432\u043e\u0434\u0435:<\/p>\n<p>adb pull \/data\/user_de\/0\/com.android.shell\/files\/bugreports\/bugreport-flame-TP1A.221005.002.B2-2023-11-02-19-00-13.zip<\/p>\n<p>\u0412 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0439 \u043f\u0430\u043f\u043a\u0435 \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u0437\u0438\u043f \u0430\u0440\u0445\u0438\u0432. \u041f\u043e \u043f\u0443\u0442\u0438 \/FS\/data\/misc\/bluetooth\/logs\/ \u0432\u043d\u0443\u0442\u0440\u0438 \u0430\u0440\u0445\u0438\u0432\u0430 \u0431\u0443\u0434\u0443\u0442 \u043b\u043e\u0433\u0438. \u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0438\u0445 \u0447\u0435\u0440\u0435\u0437 WireShark(<a href=\"https:\/\/www.wireshark.org\/\" rel=\"noopener noreferrer nofollow\">https:\/\/www.wireshark.org\/<\/a>) \u0438 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c \u0430\u043d\u0430\u043b\u0438\u0437.<\/p>\n<h2>\u0427\u0442\u043e \u0438 \u043a\u0430\u043a \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c?<\/h2>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u0434\u043e \u043e\u0442\u0441\u0435\u044f\u0442\u044c \u043d\u0435\u043d\u0443\u0436\u043d\u044b\u0435 \u043b\u043e\u0433\u0438, \u0432\u0432\u043e\u0434\u0438\u043c <br \/>bluetooth.addr==&lt;MAC \u0430\u0434\u0440\u0435\u0441\u0441 \u0432\u0430\u0448\u0435\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u043b\u0438 \u043d\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440.<\/p>\n<p>\u0412 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u0441\u0435 \u0431\u044b\u043b\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e. \u041e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0431\u044b\u043b\u043e \u0432\u0441\u0435\u0433\u0434\u0430 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c &#8212; 6996060101, \u0430 \u043f\u043e\u0441\u043b\u0435 &#8212; \u0448\u0435\u043b \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u043e\u0434, \u043e\u0447\u0435\u043d\u044c \u0441\u0438\u043b\u044c\u043d\u043e \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0432\u0448\u0438\u0439 16-\u0440\u0438\u0447\u043d\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0446\u0432\u0435\u0442\u0430. \u0422\u043e \u0435\u0441\u0442\u044c 69960501ffffffff &#8212; \u0432\u043a\u043b\u044e\u0447\u0438\u0442 \u0431\u0435\u043b\u044b\u0439 \u0446\u0432\u0435\u0442, \u0430 69960501fff000 &#8212; \u0436\u0435\u043b\u0442\u044b\u0439.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/cf0\/ef6\/e30\/cf0ef6e30218a55e5547d10ae842f99b.png\" width=\"1256\" height=\"901\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/cf0\/ef6\/e30\/cf0ef6e30218a55e5547d10ae842f99b.png\"\/><\/figure>\n<h2>\u041f\u0438\u0442\u043e\u043d \u0441\u043a\u0440\u0438\u043f\u0442 <\/h2>\n<p>\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0443 \u0447\u0435\u0440\u0435\u0437 \u043f\u0438\u0442\u043e\u043d.<\/p>\n<p>\u042f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u0441\u043a\u0440\u0438\u043f\u0442:<\/p>\n<pre><code class=\"python\">import sounddevice as sd import numpy as np from bluepy import btle import sys  class LEDController(btle.Peripheral):     def __init__(self, device_addr):         print(\"Connecting to:\", device_addr)         super().__init__(device_addr)         self.characteristic = self.getCharacteristics(uuid='0000ee01-0000-1000-8000-00805f9b34fb')[0]          def send_command(self, command):         self.characteristic.write(bytes.fromhex(command), withResponse=True)  def list_devices():     scanner = btle.Scanner()     devices = scanner.scan(5.0)     device_dict = {}     for i, device in enumerate(devices):         print(f\"{i}. {device.addr} ({device.getValueText(9)})\")         device_dict[i] = device     return device_dict   def main():     devices = list_devices()     device_list = list(devices.values())  # Convert values to a list     device_choice = int(input(\"Choose a device (number): \"))     device_addr = device_list[device_choice].addr     print(f\"Connecting to {device_addr}...\")     device = LEDController(device_addr)          color_code = input(\"Enter the 16-hex digit color code: \")      try:         device.send_command(f'6996060101{color_code}')     finally:         device.disconnect()  # \u041e\u0442\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043f\u0440\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b   if __name__ == \"__main__\":     main() <\/code><\/pre>\n<p>\u041e\u043d \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0431\u043b\u044e\u0442\u0443\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0438 \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c\u0443 \u0438 , \u0430 \u0437\u0430\u0442\u0435\u043c &#8212; \u043f\u0440\u043e\u0431\u0443\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u043e \u0441\u043c\u0435\u043d\u043e\u0439 \u0446\u0432\u0435\u0442\u0430 \u043d\u0430 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c.<\/p>\n<h2>\u0410\u043d\u0430\u043b\u0438\u0437 \u0430\u0443\u0434\u0438\u043e\u043f\u043e\u0442\u043e\u043a\u0430<\/h2>\n<p>\u0414\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0430\u0443\u0434\u0438\u043e \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 sounddevice \u0434\u043b\u044f \u043f\u0438\u0442\u043e\u043d\u0430.<\/p>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0447\u0438\u0442\u0430\u0442\u044c \u0430\u0443\u0434\u0438\u043e\u043f\u043e\u0442\u043e\u043a \u0441\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e \u0432\u044b\u0432\u043e\u0434\u0430 \u0438 \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c ON, \u0432 \u043f\u0438\u043a\u043e\u0432\u044b\u0445 \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u0445, \u0430 OFF \u0432 \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u0445 \u0441\u043e \u0441\u0440\u0435\u0434\u043d\u0435\u0439 \u0430\u043c\u043f\u043b\u0438\u0442\u0443\u0434\u043e\u0439 \u0437\u0432\u0443\u043a\u0430:<\/p>\n<pre><code class=\"python\">import sounddevice as sd import numpy as np import json previous_volume = None minVol = 0 maxVol = 0 count_of_zeros = 0 def callback(indata, frames, time, status):     global minVol     global maxVol     global previous_volume     global count_of_zeros     if status:         print(status, file=sys.stderr)     volume_norm = np.linalg.norm(indata) * 10          if volume_norm == 0:         return     if previous_volume is not None and volume_norm &lt; previous_volume \/ 7:         count_of_zeros += 1         if(count_of_zeros > 20):             minVol = 0             maxVol = 0             count_of_zeros = 0             previous_volume = None         return     if maxVol &lt; volume_norm:         maxVol = volume_norm     minVol = maxVol - 45     if minVol &lt; 0:         minVol = 0     if volume_norm*10 &lt; minVol:         minVol = volume_norm*10         maxVol = minVol + 45     if volume_norm &lt; minVol:         print(\"OFF\", volume_norm)         return     string_to_print = \"ON \" * 20     if count_of_zeros > 0:         count_of_zeros -= 1            previous_volume = volume_norm  stream = sd.InputStream(callback=callback) with stream:     input(\"Press Enter to stop recording\") <\/code><\/pre>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0448\u0430\u0433\u043e\u043c \u0431\u044b\u043b\u043e \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0434\u0432\u0430 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0432 \u043e\u0434\u0438\u043d, \u043d\u043e \u044d\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u043b\u043e \u043a \u0432\u044b\u0441\u043e\u043a\u043e\u0439 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0435(\u043e\u043a\u043e\u043b\u043e 5 \u0441\u0435\u043a\u0443\u043d\u0434), \u0441\u0442\u0430\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u043f\u0438\u0442\u043e\u043d &#8212; \u043d\u0435 \u0441\u0430\u043c\u044b\u0439 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0434\u043b\u044f \u0440\u0438\u0430\u043b\u0442\u0430\u0439\u043c \u0430\u043d\u0430\u043b\u0438\u0437\u0430.<\/p>\n<p>\u042f \u0440\u0435\u0448\u0438\u043b \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 \u0433\u043e, \u0432\u043e\u0442 \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c:<\/p>\n<pre><code class=\"go\">package main  import ( \"fmt\" \"log\" \"math\" \"strings\" \"time\"  \"github.com\/gordonklaus\/portaudio\" \"encoding\/hex\" \"flag\" \"tinygo.org\/x\/bluetooth\" )  \/\/ \u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0430\u0443\u0434\u0438\u043e \u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 Bluetooth var ( SampleRate      float64 = 44100 Threshold       float64 = 800 BufferSize      int     = 512 CutoffFrequency float64 = 250 delay           int     = 3 color           string  = \"ff0000\" )  \/\/ \u041a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0430\u0443\u0434\u0438\u043e \u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c const ( NumInputChannels = 1 StateOff         = \"off\" StateOn          = \"on\" )  \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u043b\u0430\u0433\u043e\u0432 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b func init() { flag.Float64Var(&amp;SampleRate, \"sampleRate\", 44100, \"Sample rate of the audio\") flag.Float64Var(&amp;Threshold, \"threshold\", 800, \"Volume threshold for triggering an action\") flag.IntVar(&amp;BufferSize, \"bufferSize\", 256, \"Size of the audio buffer\") flag.Float64Var(&amp;CutoffFrequency, \"cutoffFrequency\", 250, \"Cutoff frequency for the low-pass filter\") flag.IntVar(&amp;delay, \"delay\", 3, \"Delay between audio buffer reads\") flag.StringVar(&amp;color, \"color\", \"ff0000\", \"Color for the LED\") }  \/\/ \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043f\u0438\u043a\u043e\u0432 \u0437\u0432\u0443\u043a\u0430 type PeakTracker struct { state          string isRising       bool peakStartLevel float64 peakEndLevel   float64 lastState      string }  \/\/ \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f Bluetooth type data struct { off   []byte on    []byte color []byte }  \/\/ \u0417\u0430\u0440\u0430\u043d\u0435\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f Bluetooth var sampleData = data{ off: []byte{0x69, 0x96, 0x02, 0x01, 0x00}, on:  []byte{0x69, 0x96, 0x02, 0x01, 0x01}, \/\/6996060101ffff to color red color: []byte{0x69, 0x96, 0x06, 0x01, 0x01, 0xff, 0xff}, }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 PeakTracker func NewPeakTracker() *PeakTracker { return &amp;PeakTracker{ state:    StateOff, isRising: false, } }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 func (pt *PeakTracker) CheckStateChange() { if pt.state != pt.lastState { pt.lastState = pt.state \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c lastState \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0447\u0430\u0442\u0438 switch pt.state { case StateOff: fmt.Println(\"off\") _, err := bluetoothChar.WriteWithoutResponse(sampleData.off) if err != nil { log.Fatalf(\"can't write characteristic: %s\", err) } case StateOn: fmt.Println(\"on\") _, err := bluetoothChar.WriteWithoutResponse(getColor(color)) if err != nil { log.Fatalf(\"can't write characteristic: %s\", err) } } } }  \/\/ \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u0440\u043e\u0433\u0430 \u0430\u043c\u043f\u043b\u0438\u0442\u0443\u0434\u044b \u0437\u0432\u0443\u043a\u0430 type ThresholdTracker struct { maxMovingAverage *MovingAverage minMovingAverage *MovingAverage threshold        float64 }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 ThresholdTracker func NewThresholdTracker(size int) *ThresholdTracker { return &amp;ThresholdTracker{ maxMovingAverage: NewMovingAverage(size), minMovingAverage: NewMovingAverage(size), } }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0440\u043e\u0433\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0434\u0432\u0438\u0436\u0443\u0449\u0435\u0433\u043e\u0441\u044f \u0441\u0440\u0435\u0434\u043d\u0435\u0433\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c\u0430 \u0438 \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u0430 func (tt *ThresholdTracker) Update(value float64) { \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c maxMovingAverage, \u0435\u0441\u043b\u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432\u044b\u0448\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u0440\u0435\u0434\u043d\u0435\u0433\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c\u0430 \u0438\u043b\u0438 \u043e\u043a\u043d\u043e \u0435\u0449\u0435 \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0435. if value > tt.maxMovingAverage.Average() || !tt.maxMovingAverage.full { tt.maxMovingAverage.Add(value) }  \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c minMovingAverage, \u0435\u0441\u043b\u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043d\u0438\u0436\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u0440\u0435\u0434\u043d\u0435\u0433\u043e \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u0430 \u0438\u043b\u0438 \u043e\u043a\u043d\u043e \u0435\u0449\u0435 \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0435. if value &lt; tt.minMovingAverage.Average() || !tt.minMovingAverage.full { tt.minMovingAverage.Add(value) }  \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u043f\u043e\u0440\u043e\u0433 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043d\u043e\u0432\u044b\u0445 \u0441\u0440\u0435\u0434\u043d\u0438\u0445 \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c\u0430 \u0438 \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u0430. tt.threshold = (tt.maxMovingAverage.Average() + tt.minMovingAverage.Average()) \/ 2 }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0441\u0440\u0435\u0434\u043d\u0435\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u043e\u043a\u043d\u0435 func (ma *MovingAverage) Average() float64 { if ma.full { return ma.sum \/ float64(ma.size) } \/\/ \u0415\u0441\u043b\u0438 \u043e\u043a\u043d\u043e \u0435\u0449\u0435 \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0435, \u0434\u0435\u043b\u0438\u043c \u043d\u0430 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432. return ma.sum \/ float64(ma.index) }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f PeakTracker \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u043e\u0440\u043e\u0433\u0430 func (pt *PeakTracker) UpdateWithThreshold(amplitude, threshold float64) { switch pt.state { case StateOff: if amplitude > threshold { pt.isRising = true pt.peakStartLevel = amplitude } if pt.isRising &amp;&amp; amplitude &lt; pt.peakStartLevel-threshold { pt.state = StateOn pt.peakEndLevel = amplitude pt.isRising = false } case StateOn: if amplitude &lt; threshold { pt.state = StateOff pt.isRising = false } } pt.CheckStateChange() }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f PeakTracker \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043f\u043e\u0440\u043e\u0433\u0430 func (pt *PeakTracker) UpdateWithDynamicThreshold(amplitude, threshold float64) { switch pt.state { case StateOff: if amplitude > threshold { pt.state = StateOn } case StateOn: if amplitude &lt; threshold { pt.state = StateOff } } pt.CheckStateChange() }  \/\/ \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043d\u0438\u0437\u043a\u043e\u0447\u0430\u0441\u0442\u043e\u0442\u043d\u043e\u0433\u043e \u0444\u0438\u043b\u044c\u0442\u0440\u0430 type LowPassFilter struct { a        float64 y, yPrev float64 }  \/\/ \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 LowPassFilter func NewLowPassFilter(sampleRate, cutoffFrequency float64) *LowPassFilter { dt := 1.0 \/ <\/code><\/pre>\n<\/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\/774588\/\"> https:\/\/habr.com\/ru\/articles\/774588\/<\/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<h2>\u0421 \u0447\u0435\u0433\u043e \u0432\u0441\u0435 \u043d\u0430\u0447\u0430\u043b\u043e\u0441\u044c<\/h2>\n<p>\u041c\u044b \u0441 \u0434\u0440\u0443\u0437\u044c\u044f\u043c\u0438 \u043a\u0443\u043f\u0438\u043b\u0438 \u043b\u0435\u0434 \u043b\u0435\u043d\u0442\u0443 \u0441 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u043f\u043e \u0431\u043b\u044e\u0442\u0443\u0437\u0443 \u0438 \u043f\u043e\u0432\u0435\u0441\u0438\u043b\u0438 \u0435\u0451 \u0432 \u0437\u0430\u043b\u0435. \u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0431\u044b\u043b\u0430 \u043f\u0440\u0438\u043a\u043e\u043b\u044c\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0446\u0432\u0435\u0442\u043e\u043c\u0443\u0437\u044b\u043a\u0438, \u043d\u043e \u043e\u043d\u0430 \u0431\u044b\u043b\u0430 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u0430. \u0422\u0430\u043a \u0447\u0442\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0451 \u0441\u0430\u043c\u043e\u043c\u0443.<\/p>\n<h2>\u0428\u0430\u0433\u0438 \u043a \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438<\/h2>\n<ul>\n<li>\n<p>\u041d\u0430\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u0432\u043e\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0431\u043b\u044e\u0442\u0443\u0437 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440<\/p>\n<\/li>\n<li>\n<p>\u0410\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0430\u0443\u0434\u0438\u043e\u043f\u043e\u0442\u043e\u043a, \u043d\u0430\u0445\u043e\u0434\u0438\u0442 \u0440\u0435\u0437\u043a\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0431\u0438\u0442\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0421\u043a\u0440\u0435\u0441\u0442\u0438\u0442\u044c \u0434\u0432\u0430 \u0441\u043a\u0440\u0438\u043f\u0442\u0430<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043e\u0431\u0435\u0440\u0442\u043a\u0443 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u0440\u0430\u0431\u043e\u0442\u044b<\/p>\n<\/li>\n<\/ul>\n<h2>\u041a\u0430\u043a \u043f\u043e\u043d\u044f\u0442\u044c \u0447\u0442\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u0430 \u0431\u043b\u044e\u0442\u0443\u0437 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440?<\/h2>\n<p>\u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0447\u0435\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u043b\u0435\u0434 \u043b\u0435\u043d\u0442\u044b \u0447\u0435\u0440\u0435\u0437 \u0431\u043b\u044e\u0442\u0443\u0437. \u041d\u0430 \u043a\u0430\u0436\u0434\u0443\u044e \u043a\u043d\u043e\u043f\u043a\u0443 \u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0435\u043a\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441. \u041d\u0430\u043c \u043d\u0430\u0434\u043e &#171;\u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u0438\u0442\u044c&#187; \u0435\u0433\u043e \u0438 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u0442\u044c.<\/p>\n<figure class=\"float bordered full-width\">\n<div><figcaption>\u0421\u043a\u0440\u0438\u043d\u0448\u043e\u0442 \u0438\u0437 MohuanLED<\/figcaption><\/div>\n<\/figure>\n<\/p>\n<h2>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435<\/h2>\n<p>\u0427\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0432 \u043b\u043e\u0433\u0430\u0445 &#8212; \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u0432\u044b\u0442\u0430\u0449\u0438\u0442\u044c \u043c\u0430\u043a \u0430\u0434\u0440\u0435\u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430. <br \/>\u0418\u0434\u0435\u043c \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0431\u043b\u044e\u0442\u0443\u0437\u0430, \u0438\u0449\u0435\u043c \u043b\u0435\u0434 \u043b\u0435\u043d\u0442\u0443 \u0438 \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u043c\u0430\u043a \u0430\u0434\u0440\u0435\u0441:<\/p>\n<figure class=\"float full-width\"><\/figure>\n<\/p>\n<p>\u041f\u043e\u0440\u0430 \u0434\u043e\u0441\u0442\u0430\u0432\u0430\u0442\u044c \u043b\u043e\u0433\u0438! <br \/>\u0412 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0445 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u043c \u043f\u0443\u043d\u043a\u0442 &#171;Enable Bluetooth HCI snoop log&#187;<\/p>\n<figure class=\"float full-width\"><\/figure>\n<\/p>\n<p>\u041f\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0431\u043b\u044e\u0442\u0443\u0437, \u0442\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0435 \u0431\u043b\u044e\u0442\u0443\u0437 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0431\u0443\u0434\u0443\u0442 \u043b\u043e\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f.<\/p>\n<h2>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043b\u043e\u0433\u043e\u0432<\/h2>\n<p>\u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e \u0432\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u044c \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0444\u0430\u0439\u043b \u0441 \u043b\u043e\u0433\u0430\u043c\u0438, \u044d\u0442\u043e \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u0434\u0435\u043b\u0430\u0442\u044c \u043e\u043a\u043e\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u0443\u0442\u044f\u043c\u0438.<\/p>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u0442\u0435\u043b\u0435\u0444\u043e\u043d \u043a \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0443, \u043f\u043e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 adb \u043d\u0430 \u043f\u043a \u0438 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u043e\u0442\u043b\u0430\u0434\u043a\u0443 \u043f\u043e \u044e\u0441\u0431 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0434\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u00ab\u0431\u0430\u0433\u0440\u0435\u043f\u043e\u0440\u0442\u00bb\u00a0\u2014 \u044d\u0442\u043e \u0437\u0438\u043f \u0430\u0440\u0445\u0438\u0432 \u0441\u00a0\u043b\u043e\u0433\u0430\u043c\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b. \u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u0434\u043b\u044f\u00a0\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438: adb bugreport btsnoop_hci.log. <\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435 \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u0437\u0438\u043f \u0430\u0440\u0445\u0438\u0432 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043e \u043b\u043e\u0433\u0430\u0445, \u0432\u044b\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u043c \u0435\u0433\u043e \u043f\u043e \u0438\u043c\u0435\u043d\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c \u0432 \u0432\u044b\u0432\u043e\u0434\u0435:<\/p>\n<p>adb pull \/data\/user_de\/0\/com.android.shell\/files\/bugreports\/bugreport-flame-TP1A.221005.002.B2-2023-11-02-19-00-13.zip<\/p>\n<p>\u0412 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0439 \u043f\u0430\u043f\u043a\u0435 \u043f\u043e\u044f\u0432\u0438\u043b\u0441\u044f \u0437\u0438\u043f \u0430\u0440\u0445\u0438\u0432. \u041f\u043e \u043f\u0443\u0442\u0438 \/FS\/data\/misc\/bluetooth\/logs\/ \u0432\u043d\u0443\u0442\u0440\u0438 \u0430\u0440\u0445\u0438\u0432\u0430 \u0431\u0443\u0434\u0443\u0442 \u043b\u043e\u0433\u0438. \u041e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0438\u0445 \u0447\u0435\u0440\u0435\u0437 WireShark(<a href=\"https:\/\/www.wireshark.org\/\" rel=\"noopener noreferrer nofollow\">https:\/\/www.wireshark.org\/<\/a>) \u0438 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c \u0430\u043d\u0430\u043b\u0438\u0437.<\/p>\n<h2>\u0427\u0442\u043e \u0438 \u043a\u0430\u043a \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c?<\/h2>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043d\u0430\u0434\u043e \u043e\u0442\u0441\u0435\u044f\u0442\u044c \u043d\u0435\u043d\u0443\u0436\u043d\u044b\u0435 \u043b\u043e\u0433\u0438, \u0432\u0432\u043e\u0434\u0438\u043c <br \/>bluetooth.addr==&lt;MAC \u0430\u0434\u0440\u0435\u0441\u0441 \u0432\u0430\u0448\u0435\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u043b\u0438 \u043d\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440.<\/p>\n<p>\u0412 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0432\u0441\u0435 \u0431\u044b\u043b\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e. \u041e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0431\u044b\u043b\u043e \u0432\u0441\u0435\u0433\u0434\u0430 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c &#8212; 6996060101, \u0430 \u043f\u043e\u0441\u043b\u0435 &#8212; \u0448\u0435\u043b \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u043e\u0434, \u043e\u0447\u0435\u043d\u044c \u0441\u0438\u043b\u044c\u043d\u043e \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0432\u0448\u0438\u0439 16-\u0440\u0438\u0447\u043d\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0446\u0432\u0435\u0442\u0430. \u0422\u043e \u0435\u0441\u0442\u044c 69960501ffffffff &#8212; \u0432\u043a\u043b\u044e\u0447\u0438\u0442 \u0431\u0435\u043b\u044b\u0439 \u0446\u0432\u0435\u0442, \u0430 69960501fff000 &#8212; \u0436\u0435\u043b\u0442\u044b\u0439.<\/p>\n<figure class=\"full-width\"><\/figure>\n<h2>\u041f\u0438\u0442\u043e\u043d \u0441\u043a\u0440\u0438\u043f\u0442 <\/h2>\n<p>\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0443 \u0447\u0435\u0440\u0435\u0437 \u043f\u0438\u0442\u043e\u043d.<\/p>\n<p>\u042f \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u0441\u043a\u0440\u0438\u043f\u0442:<\/p>\n<pre><code class=\"python\">import sounddevice as sd import numpy as np from bluepy import btle import sys  class LEDController(btle.Peripheral):     def __init__(self, device_addr):         print(\"Connecting to:\", device_addr)         super().__init__(device_addr)         self.characteristic = self.getCharacteristics(uuid='0000ee01-0000-1000-8000-00805f9b34fb')[0]          def send_command(self, command):         self.characteristic.write(bytes.fromhex(command), withResponse=True)  def list_devices():     scanner = btle.Scanner()     devices = scanner.scan(5.0)     device_dict = {}     for i, device in enumerate(devices):         print(f\"{i}. {device.addr} ({device.getValueText(9)})\")         device_dict[i] = device     return device_dict   def main():     devices = list_devices()     device_list = list(devices.values())  # Convert values to a list     device_choice = int(input(\"Choose a device (number): \"))     device_addr = device_list[device_choice].addr     print(f\"Connecting to {device_addr}...\")     device = LEDController(device_addr)          color_code = input(\"Enter the 16-hex digit color code: \")      try:         device.send_command(f'6996060101{color_code}')     finally:         device.disconnect()  # \u041e\u0442\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043f\u0440\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b   if __name__ == \"__main__\":     main() <\/code><\/pre>\n<p>\u041e\u043d \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0431\u043b\u044e\u0442\u0443\u0437 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 \u0438 \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c\u0443 \u0438 , \u0430 \u0437\u0430\u0442\u0435\u043c &#8212; \u043f\u0440\u043e\u0431\u0443\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u043e \u0441\u043c\u0435\u043d\u043e\u0439 \u0446\u0432\u0435\u0442\u0430 \u043d\u0430 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c.<\/p>\n<h2>\u0410\u043d\u0430\u043b\u0438\u0437 \u0430\u0443\u0434\u0438\u043e\u043f\u043e\u0442\u043e\u043a\u0430<\/h2>\n<p>\u0414\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u0430\u0443\u0434\u0438\u043e \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 sounddevice \u0434\u043b\u044f \u043f\u0438\u0442\u043e\u043d\u0430.<\/p>\n<p>\u041d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u043a\u0440\u0438\u043f\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0447\u0438\u0442\u0430\u0442\u044c \u0430\u0443\u0434\u0438\u043e\u043f\u043e\u0442\u043e\u043a \u0441\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e \u0432\u044b\u0432\u043e\u0434\u0430 \u0438 \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c ON, \u0432 \u043f\u0438\u043a\u043e\u0432\u044b\u0445 \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u0445, \u0430 OFF \u0432 \u043c\u043e\u043c\u0435\u043d\u0442\u0430\u0445 \u0441\u043e \u0441\u0440\u0435\u0434\u043d\u0435\u0439 \u0430\u043c\u043f\u043b\u0438\u0442\u0443\u0434\u043e\u0439 \u0437\u0432\u0443\u043a\u0430:<\/p>\n<pre><code class=\"python\">import sounddevice as sd import numpy as np import json previous_volume = None minVol = 0 maxVol = 0 count_of_zeros = 0 def callback(indata, frames, time, status):     global minVol     global maxVol     global previous_volume     global count_of_zeros     if status:         print(status, file=sys.stderr)     volume_norm = np.linalg.norm(indata) * 10          if volume_norm == 0:         return     if previous_volume is not None and volume_norm &lt; previous_volume \/ 7:         count_of_zeros += 1         if(count_of_zeros > 20):             minVol = 0             maxVol = 0             count_of_zeros = 0             previous_volume = None         return     if maxVol &lt; volume_norm:         maxVol = volume_norm     minVol = maxVol - 45     if minVol &lt; 0:         minVol = 0     if volume_norm*10 &lt; minVol:         minVol = volume_norm*10         maxVol = minVol + 45     if volume_norm &lt; minVol:         print(\"OFF\", volume_norm)         return     string_to_print = \"ON \" * 20     if count_of_zeros > 0:         count_of_zeros -= 1            previous_volume = volume_norm  stream = sd.InputStream(callback=callback) with stream:     input(\"Press Enter to stop recording\") <\/code><\/pre>\n<p>\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0448\u0430\u0433\u043e\u043c \u0431\u044b\u043b\u043e \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0434\u0432\u0430 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u0432 \u043e\u0434\u0438\u043d, \u043d\u043e \u044d\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u043b\u043e \u043a \u0432\u044b\u0441\u043e\u043a\u043e\u0439 \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0435(\u043e\u043a\u043e\u043b\u043e 5 \u0441\u0435\u043a\u0443\u043d\u0434), \u0441\u0442\u0430\u043b\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e \u043f\u0438\u0442\u043e\u043d &#8212; \u043d\u0435 \u0441\u0430\u043c\u044b\u0439 \u043e\u043f\u0442\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0434\u043b\u044f \u0440\u0438\u0430\u043b\u0442\u0430\u0439\u043c \u0430\u043d\u0430\u043b\u0438\u0437\u0430.<\/p>\n<p>\u042f \u0440\u0435\u0448\u0438\u043b \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 \u0433\u043e, \u0432\u043e\u0442 \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c:<\/p>\n<pre><code class=\"go\">package main  import ( \"fmt\" \"log\" \"math\" \"strings\" \"time\"  \"github.com\/gordonklaus\/portaudio\" \"encoding\/hex\" \"flag\" \"tinygo.org\/x\/bluetooth\" )  \/\/ \u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0430\u0443\u0434\u0438\u043e \u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 Bluetooth var ( SampleRate      float64 = 44100 Threshold       float64 = 800 BufferSize      int     = 512 CutoffFrequency float64 = 250 delay           int     = 3 color           string  = \"ff0000\" )  \/\/ \u041a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u044b \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0430\u0443\u0434\u0438\u043e \u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c const ( NumInputChannels = 1 StateOff         = \"off\" StateOn          = \"on\" )  \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0444\u043b\u0430\u0433\u043e\u0432 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b func init() { flag.Float64Var(&amp;SampleRate, \"sampleRate\", 44100, \"Sample rate of the audio\") flag.Float64Var(&amp;Threshold, \"threshold\", 800, \"Volume threshold for triggering an action\") flag.IntVar(&amp;BufferSize, \"bufferSize\", 256, \"Size of the audio buffer\") flag.Float64Var(&amp;CutoffFrequency, \"cutoffFrequency\", 250, \"Cutoff frequency for the low-pass filter\") flag.IntVar(&amp;delay, \"delay\", 3, \"Delay between audio buffer reads\") flag.StringVar(&amp;color, \"color\", \"ff0000\", \"Color for the LED\") }  \/\/ \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043f\u0438\u043a\u043e\u0432 \u0437\u0432\u0443\u043a\u0430 type PeakTracker struct { state          string isRising       bool peakStartLevel float64 peakEndLevel   float64 lastState      string }  \/\/ \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f Bluetooth type data struct { off   []byte on    []byte color []byte }  \/\/ \u0417\u0430\u0440\u0430\u043d\u0435\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f Bluetooth var sampleData = data{ off: []byte{0x69, 0x96, 0x02, 0x01, 0x00}, on:  []byte{0x69, 0x96, 0x02, 0x01, 0x01}, \/\/6996060101ffff to color red color: []byte{0x69, 0x96, 0x06, 0x01, 0x01, 0xff, 0xff}, }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 PeakTracker func NewPeakTracker() *PeakTracker { return &amp;PeakTracker{ state:    StateOff, isRising: false, } }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 func (pt *PeakTracker) CheckStateChange() { if pt.state != pt.lastState { pt.lastState = pt.state \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c lastState \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0447\u0430\u0442\u0438 switch pt.state { case StateOff: fmt.Println(\"off\") _, err := bluetoothChar.WriteWithoutResponse(sampleData.off) if err != nil { log.Fatalf(\"can't write characteristic: %s\", err) } case StateOn: fmt.Println(\"on\") _, err := bluetoothChar.WriteWithoutResponse(getColor(color)) if err != nil { log.Fatalf(\"can't write characteristic: %s\", err) } } } }  \/\/ \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u0440\u043e\u0433\u0430 \u0430\u043c\u043f\u043b\u0438\u0442\u0443\u0434\u044b \u0437\u0432\u0443\u043a\u0430 type ThresholdTracker struct { maxMovingAverage *MovingAverage minMovingAverage *MovingAverage threshold        float64 }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 ThresholdTracker func NewThresholdTracker(size int) *ThresholdTracker { return &amp;ThresholdTracker{ maxMovingAverage: NewMovingAverage(size), minMovingAverage: NewMovingAverage(size), } }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0440\u043e\u0433\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0434\u0432\u0438\u0436\u0443\u0449\u0435\u0433\u043e\u0441\u044f \u0441\u0440\u0435\u0434\u043d\u0435\u0433\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c\u0430 \u0438 \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u0430 func (tt *ThresholdTracker) Update(value float64) { \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c maxMovingAverage, \u0435\u0441\u043b\u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0432\u044b\u0448\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u0440\u0435\u0434\u043d\u0435\u0433\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c\u0430 \u0438\u043b\u0438 \u043e\u043a\u043d\u043e \u0435\u0449\u0435 \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0435. if value > tt.maxMovingAverage.Average() || !tt.maxMovingAverage.full { tt.maxMovingAverage.Add(value) }  \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c minMovingAverage, \u0435\u0441\u043b\u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043d\u0438\u0436\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0441\u0440\u0435\u0434\u043d\u0435\u0433\u043e \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u0430 \u0438\u043b\u0438 \u043e\u043a\u043d\u043e \u0435\u0449\u0435 \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0435. if value &lt; tt.minMovingAverage.Average() || !tt.minMovingAverage.full { tt.minMovingAverage.Add(value) }  \/\/ \u041e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u043f\u043e\u0440\u043e\u0433 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043d\u043e\u0432\u044b\u0445 \u0441\u0440\u0435\u0434\u043d\u0438\u0445 \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c\u0430 \u0438 \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u0430. tt.threshold = (tt.maxMovingAverage.Average() + tt.minMovingAverage.Average()) \/ 2 }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0441\u0440\u0435\u0434\u043d\u0435\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u043e\u043a\u043d\u0435 func (ma *MovingAverage) Average() float64 { if ma.full { return ma.sum \/ float64(ma.size) } \/\/ \u0415\u0441\u043b\u0438 \u043e\u043a\u043d\u043e \u0435\u0449\u0435 \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0435, \u0434\u0435\u043b\u0438\u043c \u043d\u0430 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432. return ma.sum \/ float64(ma.index) }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f PeakTracker \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u043e\u0440\u043e\u0433\u0430 func (pt *PeakTracker) UpdateWithThreshold(amplitude, threshold float64) { switch pt.state { case StateOff: if amplitude > threshold { pt.isRising = true pt.peakStartLevel = amplitude } if pt.isRising &amp;&amp; amplitude &lt; pt.peakStartLevel-threshold { pt.state = StateOn pt.peakEndLevel = amplitude pt.isRising = false } case StateOn: if amplitude &lt; threshold { pt.state = StateOff pt.isRising = false } } pt.CheckStateChange() }  \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f PeakTracker \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043f\u043e\u0440\u043e\u0433\u0430 func (pt *PeakTracker) UpdateWithDynamicThreshold(amplitude, threshold float64) { switch pt.state { case StateOff: if amplitude > threshold { pt.state = StateOn } case StateOn: if amplitude &lt; threshold { pt.state = StateOff } } pt.CheckStateChange() }  \/\/ \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043d\u0438\u0437\u043a\u043e\u0447\u0430\u0441\u0442\u043e\u0442\u043d\u043e\u0433\u043e<\/code><\/pre>\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-360434","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/360434","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=360434"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/360434\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=360434"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=360434"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=360434"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}